From c99432e7a3fd281c2feaacb9d3ea4d3922a49bc9 Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:06:51 -0500 Subject: [PATCH 01/49] update dependencies (#1) * start to update dependencies; openssl * bnetserver compiles * game compiles * worldserver compiles and starts up * remove duktape/dukglue * fix startup and login --- cmake/macros/ConfigureBaseTargets.cmake | 14 +- cmake/macros/FindBoost.cmake | 1285 - cmake/macros/FindMySQL.cmake | 435 +- cmake/macros/FindOpenSSL.cmake | 888 +- cmake/macros/FindPCHSupport.cmake | 52 +- dep/CMakeLists.txt | 1 - dep/boost/CMakeLists.txt | 91 +- dep/duktape/CMakeLists.txt | 42 - dep/duktape/dukglue/detail_class_proto.h | 201 - dep/duktape/dukglue/detail_constructor.h | 73 - dep/duktape/dukglue/detail_function.h | 100 - dep/duktape/dukglue/detail_method.h | 183 - dep/duktape/dukglue/detail_primitive_types.h | 252 - dep/duktape/dukglue/detail_refs.h | 199 - dep/duktape/dukglue/detail_stack.h | 51 - dep/duktape/dukglue/detail_traits.h | 122 - dep/duktape/dukglue/detail_typeinfo.h | 63 - dep/duktape/dukglue/detail_types.h | 160 - dep/duktape/dukglue/dukexception.h | 40 - dep/duktape/dukglue/dukglue.h | 7 - dep/duktape/dukglue/dukvalue.h | 590 - dep/duktape/dukglue/public_util.h | 315 - dep/duktape/dukglue/register_class.h | 202 - dep/duktape/dukglue/register_function.h | 35 - dep/duktape/dukglue/register_property.h | 123 - dep/duktape/duktape/duk_config.h | 3672 - dep/duktape/duktape/duk_source_meta.json | 1821 - dep/duktape/duktape/duktape.c | 95118 ---------------- dep/duktape/duktape/duktape.h | 1349 - dep/fmt/CMakeLists.txt | 51 +- dep/fmt/CONTRIBUTING.md | 20 + dep/fmt/CONTRIBUTING.rst | 11 - dep/fmt/ChangeLog.rst | 2760 +- dep/fmt/LICENSE.rst | 42 +- dep/fmt/README.rst | 662 +- dep/fmt/fmt/container.h | 82 - dep/fmt/fmt/format.cc | 495 - dep/fmt/fmt/format.h | 4173 - dep/fmt/fmt/ostream.cc | 35 - dep/fmt/fmt/ostream.h | 108 - dep/fmt/fmt/posix.cc | 241 - dep/fmt/fmt/posix.h | 367 - dep/fmt/fmt/printf.cc | 32 - dep/fmt/fmt/printf.h | 603 - dep/fmt/fmt/string.h | 148 - dep/fmt/fmt/time.h | 143 - dep/fmt/include/fmt/args.h | 235 + dep/fmt/include/fmt/chrono.h | 2240 + dep/fmt/include/fmt/color.h | 643 + dep/fmt/include/fmt/compile.h | 535 + dep/fmt/include/fmt/core.h | 2969 + dep/fmt/include/fmt/format-inl.h | 1678 + dep/fmt/include/fmt/format.h | 4535 + dep/fmt/include/fmt/os.h | 455 + dep/fmt/include/fmt/ostream.h | 245 + dep/fmt/include/fmt/printf.h | 675 + dep/fmt/include/fmt/ranges.h | 738 + dep/fmt/include/fmt/std.h | 537 + dep/fmt/include/fmt/xchar.h | 259 + dep/fmt/src/fmt.cc | 108 + dep/fmt/src/format.cc | 43 + dep/fmt/src/os.cc | 402 + dep/gsoap/httpget.cpp | 4 +- dep/gsoap/httppost.cpp | 2 +- dep/mysql/CMakeLists.txt | 17 +- .../hotfixes/2020_03_03_00_hotfixes.sql | 2 +- ...18_05_05_03_wordl_smart_scripts(part3).sql | 2 +- src/common/Asio/IoContext.h | 47 +- src/common/Asio/Resolver.h | 41 +- src/common/Asio/Strand.h | 18 +- src/common/Cryptography/OpenSSLCrypto.cpp | 103 +- src/common/Cryptography/OpenSSLCrypto.h | 9 +- src/common/Utilities/AsyncCallbackProcessor.h | 62 + src/common/Utilities/Duration.h | 16 +- src/common/Utilities/Optional.h | 13 +- src/common/Utilities/StringConvert.h | 277 + src/common/Utilities/StringFormat.h | 29 +- src/common/Utilities/TaskScheduler.cpp | 72 +- src/common/Utilities/TaskScheduler.h | 314 +- src/common/Utilities/Types.h | 74 + src/common/Utilities/Util.cpp | 23 + src/common/Utilities/Util.h | 24 +- .../bnetserver/REST/LoginRESTService.cpp | 22 +- src/server/bnetserver/Server/Session.cpp | 16 +- src/server/bnetserver/Server/Session.h | 2 +- src/server/database/CMakeLists.txt | 4 +- .../database/Database/AdhocStatement.cpp | 43 +- src/server/database/Database/AdhocStatement.h | 23 +- src/server/database/Database/DatabaseEnv.cpp | 2 +- src/server/database/Database/DatabaseEnv.h | 7 +- src/server/database/Database/DatabaseEnvFwd.h | 66 +- .../database/Database/DatabaseLoader.cpp | 6 +- src/server/database/Database/DatabaseLoader.h | 4 +- .../database/Database/DatabaseWorker.cpp | 58 - src/server/database/Database/DatabaseWorker.h | 50 - .../database/Database/DatabaseWorkerPool.cpp | 363 +- .../database/Database/DatabaseWorkerPool.h | 88 +- src/server/database/Database/Field.cpp | 300 +- src/server/database/Database/Field.h | 87 +- .../database/Database/FieldValueConverter.cpp | 50 + .../database/Database/FieldValueConverter.h | 52 + .../database/Database/FieldValueConverters.h | 131 + .../Implementation/CharacterDatabase.cpp | 660 +- .../Implementation/CharacterDatabase.h | 5 +- .../Implementation/HotfixDatabase.cpp | 8 +- .../Database/Implementation/HotfixDatabase.h | 4 +- .../Database/Implementation/LoginDatabase.cpp | 18 +- .../Database/Implementation/LoginDatabase.h | 4 +- .../Database/Implementation/WorldDatabase.cpp | 10 +- .../Database/Implementation/WorldDatabase.h | 14 +- .../database/Database/MySQLConnection.cpp | 401 +- .../database/Database/MySQLConnection.h | 63 +- ...{QueryCallbackProcessor.h => MySQLHacks.h} | 36 +- .../Database/MySQLPreparedStatement.cpp | 229 + .../Database/MySQLPreparedStatement.h | 73 + .../database/Database/MySQLThreading.cpp | 14 +- src/server/database/Database/MySQLThreading.h | 7 +- .../Database/MySQLWorkaround.h} | 15 +- .../database/Database/PreparedStatement.cpp | 488 +- .../database/Database/PreparedStatement.h | 211 +- .../database/Database/QueryCallback.cpp | 166 +- src/server/database/Database/QueryCallback.h | 37 +- .../Database/QueryCallbackProcessor.cpp | 48 - src/server/database/Database/QueryHolder.cpp | 60 +- src/server/database/Database/QueryHolder.h | 66 +- src/server/database/Database/QueryResult.cpp | 375 +- src/server/database/Database/QueryResult.h | 23 +- src/server/database/Database/SQLOperation.h | 75 - src/server/database/Database/Transaction.cpp | 83 +- src/server/database/Database/Transaction.h | 85 +- src/server/database/Logging/AppenderDB.cpp | 2 +- .../database/PrecompiledHeaders/databasePCH.h | 33 +- src/server/database/Updater/UpdateFetcher.cpp | 13 +- src/server/database/Updater/UpdateFetcher.h | 3 +- .../game/AI/SmartScripts/SmartScriptMgr.cpp | 4 +- src/server/game/Accounts/AccountMgr.cpp | 62 +- .../game/Accounts/BattlenetAccountMgr.cpp | 18 +- src/server/game/Accounts/RBAC.cpp | 8 +- .../game/Achievements/AchievementMgr.cpp | 26 +- src/server/game/Achievements/AchievementMgr.h | 4 +- .../game/Archaeology/ArchaeologyMgr.cpp | 4 +- .../game/Archaeology/ArchaeologyPlayerMgr.cpp | 16 +- .../game/Archaeology/ArchaeologyPlayerMgr.h | 6 +- .../game/AuctionHouse/AuctionHouseMgr.cpp | 36 +- .../game/AuctionHouse/AuctionHouseMgr.h | 16 +- .../game/AuctionHouseBot/AuctionHouseBot.cpp | 2 +- .../AuctionHouseBot/AuctionHouseBotBuyer.cpp | 6 +- .../AuctionHouseBot/AuctionHouseBotSeller.cpp | 2 +- src/server/game/BattlePets/BattlePetMgr.cpp | 4 +- src/server/game/BattlePets/BattlePetMgr.h | 2 +- src/server/game/Battlegrounds/Arena.cpp | 2 +- .../game/Battlegrounds/Battleground.cpp | 6 +- .../game/Battlegrounds/BattlegroundScore.cpp | 2 +- .../game/BlackMarket/BlackMarketMgr.cpp | 26 +- src/server/game/BlackMarket/BlackMarketMgr.h | 10 +- src/server/game/CMakeLists.txt | 7 +- src/server/game/Calendar/CalendarMgr.cpp | 20 +- src/server/game/Calendar/CalendarMgr.h | 4 +- src/server/game/Chat/Channels/Channel.cpp | 8 +- src/server/game/Chat/Chat.cpp | 4 +- src/server/game/DungeonFinding/LFG.h | 3 + src/server/game/DungeonFinding/LFGMgr.cpp | 8 +- src/server/game/DungeonFinding/LFGMgr.h | 5 + .../game/Entities/AreaTrigger/AreaTrigger.cpp | 12 +- src/server/game/Entities/Corpse/Corpse.cpp | 10 +- src/server/game/Entities/Corpse/Corpse.h | 4 +- .../game/Entities/Creature/Creature.cpp | 12 +- .../game/Entities/GameObject/GameObject.cpp | 6 +- .../game/Entities/Item/Container/Bag.cpp | 4 +- src/server/game/Entities/Item/Container/Bag.h | 4 +- src/server/game/Entities/Item/Item.cpp | 46 +- src/server/game/Entities/Item/Item.h | 14 +- src/server/game/Entities/Object/Object.h | 2 +- src/server/game/Entities/Pet/Pet.cpp | 26 +- src/server/game/Entities/Pet/Pet.h | 4 +- .../game/Entities/Player/CollectionMgr.cpp | 18 +- .../game/Entities/Player/CollectionMgr.h | 8 +- src/server/game/Entities/Player/Player.cpp | 336 +- src/server/game/Entities/Player/Player.h | 54 +- src/server/game/Entities/Player/SocialMgr.cpp | 10 +- src/server/game/Entities/Unit/Unit.cpp | 2 +- src/server/game/Events/GameEventMgr.cpp | 12 +- .../game/Garrison/ClassHall/ClassHall.cpp | 4 +- .../game/Garrison/ClassHall/ClassHall.h | 2 +- src/server/game/Garrison/Garrison.cpp | 16 +- src/server/game/Garrison/Garrison.h | 6 +- .../game/Garrison/WodGarrison/WodGarrison.cpp | 14 +- .../game/Garrison/WodGarrison/WodGarrison.h | 2 +- src/server/game/Globals/ObjectMgr.cpp | 51 +- src/server/game/Grids/NGrid.h | 1 - src/server/game/Groups/Group.cpp | 52 +- src/server/game/Groups/GroupMgr.cpp | 8 +- src/server/game/Guilds/Guild.cpp | 168 +- src/server/game/Guilds/Guild.h | 70 +- src/server/game/Guilds/GuildFinderMgr.cpp | 22 +- src/server/game/Guilds/GuildMgr.cpp | 4 +- .../game/Handlers/AuctionHouseHandler.cpp | 16 +- src/server/game/Handlers/AuthHandler.cpp | 4 +- .../game/Handlers/BlackMarketHandler.cpp | 2 +- src/server/game/Handlers/CalendarHandler.cpp | 6 +- src/server/game/Handlers/CharacterHandler.cpp | 121 +- .../game/Handlers/GuildFinderHandler.cpp | 2 +- src/server/game/Handlers/HotfixHandler.cpp | 2 +- src/server/game/Handlers/InspectHandler.cpp | 2 +- src/server/game/Handlers/ItemHandler.cpp | 6 +- src/server/game/Handlers/MailHandler.cpp | 12 +- src/server/game/Handlers/MiscHandler.cpp | 2 +- src/server/game/Handlers/PetHandler.cpp | 16 +- src/server/game/Handlers/PetitionsHandler.cpp | 22 +- src/server/game/Handlers/QuestHandler.cpp | 2 +- src/server/game/Handlers/SocialHandler.cpp | 8 +- src/server/game/Handlers/SpellHandler.cpp | 2 +- src/server/game/Handlers/TaxiHandler.cpp | 2 +- src/server/game/Handlers/TicketHandler.cpp | 2 +- src/server/game/Handlers/TradeHandler.cpp | 4 +- src/server/game/Instances/InstanceSaveMgr.cpp | 14 +- src/server/game/Instances/InstanceScript.cpp | 4 +- src/server/game/Loot/Loot.cpp | 4 +- src/server/game/Mails/Mail.cpp | 18 +- src/server/game/Mails/Mail.h | 8 +- src/server/game/Maps/Map.cpp | 22 +- .../Movement/Waypoints/WaypointManager.cpp | 2 +- src/server/game/OutdoorPvP/OutdoorPvP.cpp | 2 +- src/server/game/Pools/PoolMgr.cpp | 10 +- .../game/Quests/QuestObjectiveCriteriaMgr.cpp | 10 +- .../game/Quests/QuestObjectiveCriteriaMgr.h | 2 +- src/server/game/Quests/WorldQuestMgr.cpp | 6 +- src/server/game/Reputation/ReputationMgr.cpp | 4 +- src/server/game/Reputation/ReputationMgr.h | 2 +- .../game/Scenarios/InstanceScenario.cpp | 8 +- src/server/game/Scripting/JSEngine.cpp | 18 - src/server/game/Scripting/ScriptReloadMgr.cpp | 4 +- .../Server/Packets/AreaTriggerPackets.cpp | 8 +- .../Server/Packets/AuthenticationPackets.cpp | 8 +- .../Server/Packets/AuthenticationPackets.h | 2 + .../game/Server/Packets/BattlePetPackets.cpp | 2 +- .../Server/Packets/BattlegroundPackets.cpp | 16 +- .../game/Server/Packets/BattlegroundPackets.h | 4 + .../game/Server/Packets/CharacterPackets.cpp | 6 +- .../game/Server/Packets/CharacterPackets.h | 2 + .../game/Server/Packets/CombatLogPackets.cpp | 28 +- .../Server/Packets/GuildFinderPackets.cpp | 2 +- .../game/Server/Packets/GuildPackets.cpp | 22 +- src/server/game/Server/Packets/GuildPackets.h | 2 + .../game/Server/Packets/HotfixPackets.cpp | 2 +- .../game/Server/Packets/InspectPackets.cpp | 2 +- .../game/Server/Packets/ItemPackets.cpp | 2 +- .../game/Server/Packets/ItemPacketsCommon.cpp | 26 +- src/server/game/Server/Packets/LFGPackets.cpp | 10 +- .../game/Server/Packets/LootPackets.cpp | 4 +- .../game/Server/Packets/MailPackets.cpp | 4 +- .../game/Server/Packets/MiscPackets.cpp | 24 +- .../game/Server/Packets/MovementPackets.cpp | 48 +- .../game/Server/Packets/MovementPackets.h | 2 + .../game/Server/Packets/PartyPackets.cpp | 20 +- src/server/game/Server/Packets/PetPackets.cpp | 4 +- .../game/Server/Packets/QueryPackets.cpp | 4 +- .../game/Server/Packets/QuestPackets.cpp | 2 +- .../game/Server/Packets/SpellPackets.cpp | 36 +- .../game/Server/Packets/SystemPackets.cpp | 6 +- .../game/Server/Packets/SystemPackets.h | 2 + .../game/Server/Packets/TaxiPackets.cpp | 4 +- .../game/Server/Packets/TicketPackets.cpp | 12 +- .../game/Server/Packets/TicketPackets.h | 4 + .../game/Server/Packets/TradePackets.cpp | 2 +- src/server/game/Server/Packets/TradePackets.h | 2 + src/server/game/Server/Packets/WhoPackets.cpp | 2 +- src/server/game/Server/WorldSession.cpp | 93 +- src/server/game/Server/WorldSession.h | 23 +- src/server/game/Server/WorldSocket.cpp | 18 +- src/server/game/Server/WorldSocket.h | 2 +- src/server/game/Spells/Auras/SpellAuras.cpp | 6 +- src/server/game/Spells/Spell.cpp | 10 +- src/server/game/Spells/SpellEffects.cpp | 14 +- src/server/game/Spells/SpellHistory.cpp | 20 +- src/server/game/Spells/SpellHistory.h | 2 +- src/server/game/Support/SupportMgr.cpp | 28 +- src/server/game/Texts/CreatureTextMgr.cpp | 2 +- src/server/game/Tools/PlayerDump.cpp | 8 +- src/server/game/World/World.cpp | 53 +- src/server/game/World/World.h | 2 +- src/server/scripts/Commands/cs_account.cpp | 22 +- src/server/scripts/Commands/cs_ban.cpp | 12 +- .../scripts/Commands/cs_battlenet_account.cpp | 8 +- src/server/scripts/Commands/cs_character.cpp | 26 +- src/server/scripts/Commands/cs_disable.cpp | 4 +- src/server/scripts/Commands/cs_gm.cpp | 2 +- src/server/scripts/Commands/cs_gobject.cpp | 2 +- src/server/scripts/Commands/cs_group.cpp | 2 +- src/server/scripts/Commands/cs_guild.cpp | 6 +- src/server/scripts/Commands/cs_lfg.cpp | 2 +- src/server/scripts/Commands/cs_list.cpp | 4 +- src/server/scripts/Commands/cs_lookup.cpp | 8 +- src/server/scripts/Commands/cs_message.cpp | 4 +- src/server/scripts/Commands/cs_misc.cpp | 42 +- src/server/scripts/Commands/cs_npc.cpp | 16 +- src/server/scripts/Commands/cs_quest.cpp | 2 +- src/server/scripts/Commands/cs_reload.cpp | 2 +- src/server/scripts/Commands/cs_reset.cpp | 6 +- src/server/scripts/Commands/cs_send.cpp | 6 +- src/server/scripts/Commands/cs_server.cpp | 5 +- src/server/scripts/Commands/cs_tele.cpp | 6 +- src/server/scripts/Commands/cs_wp.cpp | 14 +- src/server/scripts/Northrend/zone_dalaran.cpp | 2 +- src/server/scripts/World/action_ip_logger.cpp | 8 +- src/server/scripts/World/rest_scripts.cpp | 1 + .../shared/DataStores/DB2DatabaseLoader.cpp | 2 +- src/server/shared/Realm/RealmList.cpp | 12 +- src/server/shared/Realm/RealmList.h | 3 +- src/server/worldserver/CMakeLists.txt | 8 +- src/server/worldserver/Main.cpp | 3 +- .../worldserver/RemoteAccess/RASession.cpp | 4 +- src/tools/map_extractor/System.cpp | 2 + src/tools/vmap4_extractor/vmapexport.cpp | 2 + 314 files changed, 24991 insertions(+), 117166 deletions(-) delete mode 100644 cmake/macros/FindBoost.cmake delete mode 100644 dep/duktape/CMakeLists.txt delete mode 100644 dep/duktape/dukglue/detail_class_proto.h delete mode 100644 dep/duktape/dukglue/detail_constructor.h delete mode 100644 dep/duktape/dukglue/detail_function.h delete mode 100644 dep/duktape/dukglue/detail_method.h delete mode 100644 dep/duktape/dukglue/detail_primitive_types.h delete mode 100644 dep/duktape/dukglue/detail_refs.h delete mode 100644 dep/duktape/dukglue/detail_stack.h delete mode 100644 dep/duktape/dukglue/detail_traits.h delete mode 100644 dep/duktape/dukglue/detail_typeinfo.h delete mode 100644 dep/duktape/dukglue/detail_types.h delete mode 100644 dep/duktape/dukglue/dukexception.h delete mode 100644 dep/duktape/dukglue/dukglue.h delete mode 100644 dep/duktape/dukglue/dukvalue.h delete mode 100644 dep/duktape/dukglue/public_util.h delete mode 100644 dep/duktape/dukglue/register_class.h delete mode 100644 dep/duktape/dukglue/register_function.h delete mode 100644 dep/duktape/dukglue/register_property.h delete mode 100644 dep/duktape/duktape/duk_config.h delete mode 100644 dep/duktape/duktape/duk_source_meta.json delete mode 100644 dep/duktape/duktape/duktape.c delete mode 100644 dep/duktape/duktape/duktape.h create mode 100644 dep/fmt/CONTRIBUTING.md delete mode 100644 dep/fmt/CONTRIBUTING.rst delete mode 100644 dep/fmt/fmt/container.h delete mode 100644 dep/fmt/fmt/format.cc delete mode 100644 dep/fmt/fmt/format.h delete mode 100644 dep/fmt/fmt/ostream.cc delete mode 100644 dep/fmt/fmt/ostream.h delete mode 100644 dep/fmt/fmt/posix.cc delete mode 100644 dep/fmt/fmt/posix.h delete mode 100644 dep/fmt/fmt/printf.cc delete mode 100644 dep/fmt/fmt/printf.h delete mode 100644 dep/fmt/fmt/string.h delete mode 100644 dep/fmt/fmt/time.h create mode 100644 dep/fmt/include/fmt/args.h create mode 100644 dep/fmt/include/fmt/chrono.h create mode 100644 dep/fmt/include/fmt/color.h create mode 100644 dep/fmt/include/fmt/compile.h create mode 100644 dep/fmt/include/fmt/core.h create mode 100644 dep/fmt/include/fmt/format-inl.h create mode 100644 dep/fmt/include/fmt/format.h create mode 100644 dep/fmt/include/fmt/os.h create mode 100644 dep/fmt/include/fmt/ostream.h create mode 100644 dep/fmt/include/fmt/printf.h create mode 100644 dep/fmt/include/fmt/ranges.h create mode 100644 dep/fmt/include/fmt/std.h create mode 100644 dep/fmt/include/fmt/xchar.h create mode 100644 dep/fmt/src/fmt.cc create mode 100644 dep/fmt/src/format.cc create mode 100644 dep/fmt/src/os.cc create mode 100644 src/common/Utilities/AsyncCallbackProcessor.h create mode 100644 src/common/Utilities/StringConvert.h create mode 100644 src/common/Utilities/Types.h delete mode 100644 src/server/database/Database/DatabaseWorker.cpp delete mode 100644 src/server/database/Database/DatabaseWorker.h create mode 100644 src/server/database/Database/FieldValueConverter.cpp create mode 100644 src/server/database/Database/FieldValueConverter.h create mode 100644 src/server/database/Database/FieldValueConverters.h rename src/server/database/Database/{QueryCallbackProcessor.h => MySQLHacks.h} (50%) create mode 100644 src/server/database/Database/MySQLPreparedStatement.cpp create mode 100644 src/server/database/Database/MySQLPreparedStatement.h rename src/server/{game/Scripting/JSEngine.h => database/Database/MySQLWorkaround.h} (65%) delete mode 100644 src/server/database/Database/QueryCallbackProcessor.cpp delete mode 100644 src/server/database/Database/SQLOperation.h delete mode 100644 src/server/game/Scripting/JSEngine.cpp diff --git a/cmake/macros/ConfigureBaseTargets.cmake b/cmake/macros/ConfigureBaseTargets.cmake index 603149f9c72..40fb6b46690 100644 --- a/cmake/macros/ConfigureBaseTargets.cmake +++ b/cmake/macros/ConfigureBaseTargets.cmake @@ -19,19 +19,7 @@ add_library(trinity-feature-interface INTERFACE) target_compile_features(trinity-feature-interface INTERFACE - cxx_alias_templates - cxx_auto_type - cxx_constexpr - cxx_decltype - cxx_decltype_auto - cxx_final - cxx_lambdas - cxx_generic_lambdas - cxx_variadic_templates - cxx_defaulted_functions - cxx_nullptr - cxx_trailing_return_types - cxx_return_type_deduction) + cxx_std_20) # An interface library to make the warnings level available to other targets # This interface taget is set-up through the platform specific script diff --git a/cmake/macros/FindBoost.cmake b/cmake/macros/FindBoost.cmake deleted file mode 100644 index 8cd06f81ea5..00000000000 --- a/cmake/macros/FindBoost.cmake +++ /dev/null @@ -1,1285 +0,0 @@ -#.rst: -# FindBoost -# --------- -# -# Find Boost include dirs and libraries -# -# Use this module by invoking find_package with the form:: -# -# find_package(Boost -# [version] [EXACT] # Minimum or EXACT version e.g. 1.36.0 -# [REQUIRED] # Fail with error if Boost is not found -# [COMPONENTS ...] # Boost libraries by their canonical name -# ) # e.g. "date_time" for "libboost_date_time" -# -# This module finds headers and requested component libraries OR a CMake -# package configuration file provided by a "Boost CMake" build. For the -# latter case skip to the "Boost CMake" section below. For the former -# case results are reported in variables:: -# -# Boost_FOUND - True if headers and requested libraries were found -# Boost_INCLUDE_DIRS - Boost include directories -# Boost_LIBRARY_DIRS - Link directories for Boost libraries -# Boost_LIBRARIES - Boost component libraries to be linked -# Boost__FOUND - True if component was found ( is upper-case) -# Boost__LIBRARY - Libraries to link for component (may include -# target_link_libraries debug/optimized keywords) -# Boost_VERSION - BOOST_VERSION value from boost/version.hpp -# Boost_LIB_VERSION - Version string appended to library filenames -# Boost_MAJOR_VERSION - Boost major version number (X in X.y.z) -# Boost_MINOR_VERSION - Boost minor version number (Y in x.Y.z) -# Boost_SUBMINOR_VERSION - Boost subminor version number (Z in x.y.Z) -# Boost_LIB_DIAGNOSTIC_DEFINITIONS (Windows) -# - Pass to add_definitions() to have diagnostic -# information about Boost's automatic linking -# displayed during compilation -# -# This module reads hints about search locations from variables:: -# -# BOOST_ROOT - Preferred installation prefix -# (or BOOSTROOT) -# BOOST_INCLUDEDIR - Preferred include directory e.g. /include -# BOOST_LIBRARYDIR - Preferred library directory e.g. /lib -# Boost_NO_SYSTEM_PATHS - Set to ON to disable searching in locations not -# specified by these hint variables. Default is OFF. -# Boost_ADDITIONAL_VERSIONS -# - List of Boost versions not known to this module -# (Boost install locations may contain the version) -# -# and saves search results persistently in CMake cache entries:: -# -# Boost_INCLUDE_DIR - Directory containing Boost headers -# Boost_LIBRARY_DIR - Directory containing Boost libraries -# Boost__LIBRARY_DEBUG - Component library debug variant -# Boost__LIBRARY_RELEASE - Component library release variant -# -# Users may set these hints or results as cache entries. Projects -# should not read these entries directly but instead use the above -# result variables. Note that some hint names start in upper-case -# "BOOST". One may specify these as environment variables if they are -# not specified as CMake variables or cache entries. -# -# This module first searches for the Boost header files using the above -# hint variables (excluding BOOST_LIBRARYDIR) and saves the result in -# Boost_INCLUDE_DIR. Then it searches for requested component libraries -# using the above hints (excluding BOOST_INCLUDEDIR and -# Boost_ADDITIONAL_VERSIONS), "lib" directories near Boost_INCLUDE_DIR, -# and the library name configuration settings below. It saves the -# library directory in Boost_LIBRARY_DIR and individual library -# locations in Boost__LIBRARY_DEBUG and Boost__LIBRARY_RELEASE. -# When one changes settings used by previous searches in the same build -# tree (excluding environment variables) this module discards previous -# search results affected by the changes and searches again. -# -# Boost libraries come in many variants encoded in their file name. -# Users or projects may tell this module which variant to find by -# setting variables:: -# -# Boost_USE_MULTITHREADED - Set to OFF to use the non-multithreaded -# libraries ('mt' tag). Default is ON. -# Boost_USE_STATIC_LIBS - Set to ON to force the use of the static -# libraries. Default is OFF. -# Boost_USE_STATIC_RUNTIME - Set to ON or OFF to specify whether to use -# libraries linked statically to the C++ runtime -# ('s' tag). Default is platform dependent. -# Boost_USE_DEBUG_RUNTIME - Set to ON or OFF to specify whether to use -# libraries linked to the MS debug C++ runtime -# ('g' tag). Default is ON. -# Boost_USE_DEBUG_PYTHON - Set to ON to use libraries compiled with a -# debug Python build ('y' tag). Default is OFF. -# Boost_USE_STLPORT - Set to ON to use libraries compiled with -# STLPort ('p' tag). Default is OFF. -# Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS -# - Set to ON to use libraries compiled with -# STLPort deprecated "native iostreams" -# ('n' tag). Default is OFF. -# Boost_COMPILER - Set to the compiler-specific library suffix -# (e.g. "-gcc43"). Default is auto-computed -# for the C++ compiler in use. -# Boost_THREADAPI - Suffix for "thread" component library name, -# such as "pthread" or "win32". Names with -# and without this suffix will both be tried. -# Boost_NAMESPACE - Alternate namespace used to build boost with -# e.g. if set to "myboost", will search for -# myboost_thread instead of boost_thread. -# -# Other variables one may set to control this module are:: -# -# Boost_DEBUG - Set to ON to enable debug output from FindBoost. -# Please enable this before filing any bug report. -# Boost_DETAILED_FAILURE_MSG -# - Set to ON to add detailed information to the -# failure message even when the REQUIRED option -# is not given to the find_package call. -# Boost_REALPATH - Set to ON to resolve symlinks for discovered -# libraries to assist with packaging. For example, -# the "system" component library may be resolved to -# "/usr/lib/libboost_system.so.1.42.0" instead of -# "/usr/lib/libboost_system.so". This does not -# affect linking and should not be enabled unless -# the user needs this information. -# -# On Visual Studio and Borland compilers Boost headers request automatic -# linking to corresponding libraries. This requires matching libraries -# to be linked explicitly or available in the link library search path. -# In this case setting Boost_USE_STATIC_LIBS to OFF may not achieve -# dynamic linking. Boost automatic linking typically requests static -# libraries with a few exceptions (such as Boost.Python). Use:: -# -# add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) -# -# to ask Boost to report information about automatic linking requests. -# -# Example to find Boost headers only:: -# -# find_package(Boost 1.36.0) -# if(Boost_FOUND) -# include_directories(${Boost_INCLUDE_DIRS}) -# add_executable(foo foo.cc) -# endif() -# -# Example to find Boost headers and some *static* libraries:: -# -# set(Boost_USE_STATIC_LIBS ON) # only find static libs -# set(Boost_USE_MULTITHREADED ON) -# set(Boost_USE_STATIC_RUNTIME OFF) -# find_package(Boost 1.36.0 COMPONENTS date_time filesystem system ...) -# if(Boost_FOUND) -# include_directories(${Boost_INCLUDE_DIRS}) -# add_executable(foo foo.cc) -# target_link_libraries(foo ${Boost_LIBRARIES}) -# endif() -# -# Boost CMake -# ^^^^^^^^^^^ -# -# If Boost was built using the boost-cmake project it provides a package -# configuration file for use with find_package's Config mode. This -# module looks for the package configuration file called -# BoostConfig.cmake or boost-config.cmake and stores the result in cache -# entry "Boost_DIR". If found, the package configuration file is loaded -# and this module returns with no further action. See documentation of -# the Boost CMake package configuration for details on what it provides. -# -# Set Boost_NO_BOOST_CMAKE to ON to disable the search for boost-cmake. - -#============================================================================= -# Copyright 2006-2012 Kitware, Inc. -# Copyright 2006-2008 Andreas Schneider -# Copyright 2007 Wengo -# Copyright 2007 Mike Jackson -# Copyright 2008 Andreas Pakulat -# Copyright 2008-2012 Philip Lowman -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - - -#------------------------------------------------------------------------------- -# Before we go searching, check whether boost-cmake is available, unless the -# user specifically asked NOT to search for boost-cmake. -# -# If Boost_DIR is set, this behaves as any find_package call would. If not, -# it looks at BOOST_ROOT and BOOSTROOT to find Boost. -# -if (NOT Boost_NO_BOOST_CMAKE) - # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives, - # since these are more conventional for Boost. - if ("$ENV{Boost_DIR}" STREQUAL "") - if (NOT "$ENV{BOOST_ROOT}" STREQUAL "") - set(ENV{Boost_DIR} $ENV{BOOST_ROOT}) - elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "") - set(ENV{Boost_DIR} $ENV{BOOSTROOT}) - endif() - endif() - - # Do the same find_package call but look specifically for the CMake version. - # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no - # need to delegate them to this find_package call. - find_package(Boost QUIET NO_MODULE) - mark_as_advanced(Boost_DIR) - - # If we found boost-cmake, then we're done. Print out what we found. - # Otherwise let the rest of the module try to find it. - if (Boost_FOUND) - message("Boost ${Boost_FIND_VERSION} found.") - if (Boost_FIND_COMPONENTS) - message("Found Boost components:") - message(" ${Boost_FIND_COMPONENTS}") - endif() - return() - endif() -endif() - - -#------------------------------------------------------------------------------- -# FindBoost functions & macros -# - -############################################ -# -# Check the existence of the libraries. -# -############################################ -# This macro was taken directly from the FindQt4.cmake file that is included -# with the CMake distribution. This is NOT my work. All work was done by the -# original authors of the FindQt4.cmake file. Only minor modifications were -# made to remove references to Qt and make this file more generally applicable -# And ELSE/ENDIF pairs were removed for readability. -######################################################################### - -macro(_Boost_ADJUST_LIB_VARS basename) - if(Boost_INCLUDE_DIR ) - if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) - # if the generator supports configuration types then set - # optimized and debug libraries, or if the CMAKE_BUILD_TYPE has a value - if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) - set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) - else() - # if there are no configuration types and CMAKE_BUILD_TYPE has no value - # then just use the release libraries - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) - endif() - # FIXME: This probably should be set for both cases - set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) - endif() - - # if only the release version was found, set the debug variable also to the release version - if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) - set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) - endif() - - # if only the debug version was found, set the release variable also to the debug version - if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) - set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) - endif() - - # If the debug & release library ends up being the same, omit the keywords - if(${Boost_${basename}_LIBRARY_RELEASE} STREQUAL ${Boost_${basename}_LIBRARY_DEBUG}) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} ) - endif() - - if(Boost_${basename}_LIBRARY) - set(Boost_${basename}_FOUND ON) - endif() - - endif() - # Make variables changeable to the advanced user - mark_as_advanced( - Boost_${basename}_LIBRARY_RELEASE - Boost_${basename}_LIBRARY_DEBUG - ) -endmacro() - -macro(_Boost_CHANGE_DETECT changed_var) - set(${changed_var} 0) - foreach(v ${ARGN}) - if(DEFINED _Boost_COMPONENTS_SEARCHED) - if(${v}) - if(_${v}_LAST) - string(COMPARE NOTEQUAL "${${v}}" "${_${v}_LAST}" _${v}_CHANGED) - else() - set(_${v}_CHANGED 1) - endif() - elseif(_${v}_LAST) - set(_${v}_CHANGED 1) - endif() - if(_${v}_CHANGED) - set(${changed_var} 1) - endif() - else() - set(_${v}_CHANGED 0) - endif() - endforeach() -endmacro() - -macro(_Boost_FIND_LIBRARY var) - find_library(${var} ${ARGN}) - - if(${var}) - # If this is the first library found then save Boost_LIBRARY_DIR. - if(NOT Boost_LIBRARY_DIR) - get_filename_component(_dir "${${var}}" PATH) - set(Boost_LIBRARY_DIR "${_dir}" CACHE PATH "Boost library directory" FORCE) - endif() - elseif(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) - # Try component-specific hints but do not save Boost_LIBRARY_DIR. - find_library(${var} HINTS ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT} ${ARGN}) - endif() - - # If Boost_LIBRARY_DIR is known then search only there. - if(Boost_LIBRARY_DIR) - set(_boost_LIBRARY_SEARCH_DIRS ${Boost_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) - endif() -endmacro() - -#------------------------------------------------------------------------------- - -# -# Runs compiler with "-dumpversion" and parses major/minor -# version with a regex. -# -function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION) - - exec_program(${CMAKE_CXX_COMPILER} - ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion - OUTPUT_VARIABLE _boost_COMPILER_VERSION - ) - string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" - _boost_COMPILER_VERSION ${_boost_COMPILER_VERSION}) - - set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) -endfunction() - -# -# Take a list of libraries with "thread" in it -# and prepend duplicates with "thread_${Boost_THREADAPI}" -# at the front of the list -# -function(_Boost_PREPEND_LIST_WITH_THREADAPI _output) - set(_orig_libnames ${ARGN}) - string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames "${_orig_libnames}") - set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE) -endfunction() - -# -# If a library is found, replace its cache entry with its REALPATH -# -function(_Boost_SWAP_WITH_REALPATH _library _docstring) - if(${_library}) - get_filename_component(_boost_filepathreal ${${_library}} REALPATH) - unset(${_library} CACHE) - set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}") - endif() -endfunction() - -function(_Boost_CHECK_SPELLING _var) - if(${_var}) - string(TOUPPER ${_var} _var_UC) - message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.") - endif() -endfunction() - -# Guesses Boost's compiler prefix used in built library names -# Returns the guess by setting the variable pointed to by _ret -function(_Boost_GUESS_COMPILER_PREFIX _ret) - if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" - OR CMAKE_CXX_COMPILER MATCHES "icl" - OR CMAKE_CXX_COMPILER MATCHES "icpc") - if(WIN32) - set (_boost_COMPILER "-iw") - else() - set (_boost_COMPILER "-il") - endif() - elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.20) - set(_boost_COMPILER "-vc142;-vc141") - elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) - set(_boost_COMPILER "-vc141;-vc140") - elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) - set(_boost_COMPILER "-vc140") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18) - set(_boost_COMPILER "-vc120") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17) - set(_boost_COMPILER "-vc110") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16) - set(_boost_COMPILER "-vc100") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15) - set(_boost_COMPILER "-vc90") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14) - set(_boost_COMPILER "-vc80") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.10) - set(_boost_COMPILER "-vc71") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) # Good luck! - set(_boost_COMPILER "-vc7") # yes, this is correct - else() # VS 6.0 Good luck! - set(_boost_COMPILER "-vc6") # yes, this is correct - endif() - elseif (BORLAND) - set(_boost_COMPILER "-bcb") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") - set(_boost_COMPILER "-sw") - elseif (MINGW) - if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) - set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 - else() - _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) - set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") - endif() - elseif (UNIX) - if (CMAKE_COMPILER_IS_GNUCXX) - if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) - set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 - else() - _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) - # Determine which version of GCC we have. - if(APPLE) - if(Boost_MINOR_VERSION) - if(${Boost_MINOR_VERSION} GREATER 35) - # In Boost 1.36.0 and newer, the mangled compiler name used - # on Mac OS X/Darwin is "xgcc". - set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") - else() - # In Boost <= 1.35.0, there is no mangled compiler name for - # the Mac OS X/Darwin version of GCC. - set(_boost_COMPILER "") - endif() - else() - # We don't know the Boost version, so assume it's - # pre-1.36.0. - set(_boost_COMPILER "") - endif() - else() - set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") - endif() - endif() - endif () - else() - # TODO at least Boost_DEBUG here? - set(_boost_COMPILER "") - endif() - set(${_ret} ${_boost_COMPILER} PARENT_SCOPE) -endfunction() - -# -# End functions/macros -# -#------------------------------------------------------------------------------- - -#------------------------------------------------------------------------------- -# main. -#------------------------------------------------------------------------------- - -if(NOT DEFINED Boost_USE_MULTITHREADED) - set(Boost_USE_MULTITHREADED TRUE) -endif() -if(NOT DEFINED Boost_USE_DEBUG_RUNTIME) - set(Boost_USE_DEBUG_RUNTIME TRUE) -endif() - -# Check the version of Boost against the requested version. -if(Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) - message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34") -endif() - -if(Boost_FIND_VERSION_EXACT) - # The version may appear in a directory with or without the patch - # level, even when the patch level is non-zero. - set(_boost_TEST_VERSIONS - "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}" - "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") -else() - # The user has not requested an exact version. Among known - # versions, find those that are acceptable to the user request. - set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} - "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" "1.69.0" "1.69" - "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" - "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" - "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55" - "1.54.0" "1.54" "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51" - "1.50.0" "1.50" "1.49.0" "1.49" "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1" - "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42" - "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37" - "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" - "1.34" "1.33.1" "1.33.0" "1.33") - set(_boost_TEST_VERSIONS) - if(Boost_FIND_VERSION) - set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") - # Select acceptable versions. - foreach(version ${_Boost_KNOWN_VERSIONS}) - if(NOT "${version}" VERSION_LESS "${Boost_FIND_VERSION}") - # This version is high enough. - list(APPEND _boost_TEST_VERSIONS "${version}") - elseif("${version}.99" VERSION_EQUAL "${_Boost_FIND_VERSION_SHORT}.99") - # This version is a short-form for the requested version with - # the patch level dropped. - list(APPEND _boost_TEST_VERSIONS "${version}") - endif() - endforeach() - else() - # Any version is acceptable. - set(_boost_TEST_VERSIONS "${_Boost_KNOWN_VERSIONS}") - endif() -endif() - -# The reason that we failed to find Boost. This will be set to a -# user-friendly message when we fail to find some necessary piece of -# Boost. -set(Boost_ERROR_REASON) - -if(Boost_DEBUG) - # Output some of their choices - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_USE_MULTITHREADED = ${Boost_USE_MULTITHREADED}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_USE_STATIC_LIBS = ${Boost_USE_STATIC_LIBS}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_USE_STATIC_RUNTIME = ${Boost_USE_STATIC_RUNTIME}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_ADDITIONAL_VERSIONS = ${Boost_ADDITIONAL_VERSIONS}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}") -endif() - -if(WIN32) - # In windows, automatic linking is performed, so you do not have - # to specify the libraries. If you are linking to a dynamic - # runtime, then you can choose to link to either a static or a - # dynamic Boost library, the default is to do a static link. You - # can alter this for a specific library "whatever" by defining - # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be - # linked dynamically. Alternatively you can force all Boost - # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. - - # This feature can be disabled for Boost library "whatever" by - # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining - # BOOST_ALL_NO_LIB. - - # If you want to observe which libraries are being linked against - # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking - # code to emit a #pragma message each time a library is selected - # for linking. - set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC") -endif() - -_Boost_CHECK_SPELLING(Boost_ROOT) -_Boost_CHECK_SPELLING(Boost_LIBRARYDIR) -_Boost_CHECK_SPELLING(Boost_INCLUDEDIR) - -# Collect environment variable inputs as hints. Do not consider changes. -foreach(v BOOSTROOT BOOST_ROOT BOOST_INCLUDEDIR BOOST_LIBRARYDIR) - set(_env $ENV{${v}}) - if(_env) - file(TO_CMAKE_PATH "${_env}" _ENV_${v}) - else() - set(_ENV_${v} "") - endif() -endforeach() -if(NOT _ENV_BOOST_ROOT AND _ENV_BOOSTROOT) - set(_ENV_BOOST_ROOT "${_ENV_BOOSTROOT}") -endif() - -# Collect inputs and cached results. Detect changes since the last run. -if(NOT BOOST_ROOT AND BOOSTROOT) - set(BOOST_ROOT "${BOOSTROOT}") -endif() -set(_Boost_VARS_DIR - BOOST_ROOT - Boost_NO_SYSTEM_PATHS - ) - -if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Declared as CMake or Environmental Variables:") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " BOOST_ROOT = ${BOOST_ROOT}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " BOOST_INCLUDEDIR = ${BOOST_INCLUDEDIR}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " BOOST_LIBRARYDIR = ${BOOST_LIBRARYDIR}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") -endif() - -# ------------------------------------------------------------------------ -# Search for Boost include DIR -# ------------------------------------------------------------------------ - -set(_Boost_VARS_INC BOOST_INCLUDEDIR Boost_INCLUDE_DIR Boost_ADDITIONAL_VERSIONS) -_Boost_CHANGE_DETECT(_Boost_CHANGE_INCDIR ${_Boost_VARS_DIR} ${_Boost_VARS_INC}) -# Clear Boost_INCLUDE_DIR if it did not change but other input affecting the -# location did. We will find a new one based on the new inputs. -if(_Boost_CHANGE_INCDIR AND NOT _Boost_INCLUDE_DIR_CHANGED) - unset(Boost_INCLUDE_DIR CACHE) -endif() - -if(NOT Boost_INCLUDE_DIR) - set(_boost_INCLUDE_SEARCH_DIRS "") - if(BOOST_INCLUDEDIR) - list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_INCLUDEDIR}) - elseif(_ENV_BOOST_INCLUDEDIR) - list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_INCLUDEDIR}) - endif() - - if( BOOST_ROOT ) - list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_ROOT}/include ${BOOST_ROOT}) - elseif( _ENV_BOOST_ROOT ) - list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_ROOT}/include ${_ENV_BOOST_ROOT}) - endif() - - if( Boost_NO_SYSTEM_PATHS) - list(APPEND _boost_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH) - else() - list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS - C:/boost/include - C:/boost - /sw/local/include - /usr/local/include/boost - /usr/include/boost - ) - endif() - - # Try to find Boost by stepping backwards through the Boost versions - # we know about. - # Build a list of path suffixes for each version. - set(_boost_PATH_SUFFIXES) - foreach(_boost_VER ${_boost_TEST_VERSIONS}) - # Add in a path suffix, based on the required version, ideally - # we could read this from version.hpp, but for that to work we'd - # need to know the include dir already - set(_boost_BOOSTIFIED_VERSION) - - # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 - if(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") - set(_boost_BOOSTIFIED_VERSION - "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}_${CMAKE_MATCH_3}") - elseif(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)") - set(_boost_BOOSTIFIED_VERSION - "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") - endif() - - list(APPEND _boost_PATH_SUFFIXES - "boost-${_boost_BOOSTIFIED_VERSION}" - "boost_${_boost_BOOSTIFIED_VERSION}" - "boost/boost-${_boost_BOOSTIFIED_VERSION}" - "boost/boost_${_boost_BOOSTIFIED_VERSION}" - ) - - endforeach() - - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Include debugging info:") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " _boost_INCLUDE_SEARCH_DIRS = ${_boost_INCLUDE_SEARCH_DIRS}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " _boost_PATH_SUFFIXES = ${_boost_PATH_SUFFIXES}") - endif() - - # Look for a standard boost header file. - find_path(Boost_INCLUDE_DIR - NAMES boost/config.hpp - HINTS ${_boost_INCLUDE_SEARCH_DIRS} - PATH_SUFFIXES ${_boost_PATH_SUFFIXES} - ) -endif() - -# ------------------------------------------------------------------------ -# Extract version information from version.hpp -# ------------------------------------------------------------------------ - -# Set Boost_FOUND based only on header location and version. -# It will be updated below for component libraries. -if(Boost_INCLUDE_DIR) - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp") - endif() - - # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp - set(Boost_VERSION 0) - set(Boost_LIB_VERSION "") - file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ") - set(_Boost_VERSION_REGEX "([0-9]+)") - set(_Boost_LIB_VERSION_REGEX "\"([0-9_]+)\"") - foreach(v VERSION LIB_VERSION) - if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_${v} ${_Boost_${v}_REGEX}") - set(Boost_${v} "${CMAKE_MATCH_1}") - endif() - endforeach() - unset(_boost_VERSION_HPP_CONTENTS) - - math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") - math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") - math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") - - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\nBoost include path: ${Boost_INCLUDE_DIR}") - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "version.hpp reveals boost " - "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") - endif() - - if(Boost_FIND_VERSION) - # Set Boost_FOUND based on requested version. - set(_Boost_VERSION "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") - if("${_Boost_VERSION}" VERSION_LESS "${Boost_FIND_VERSION}") - set(Boost_FOUND 0) - set(_Boost_VERSION_AGE "old") - elseif(Boost_FIND_VERSION_EXACT AND - NOT "${_Boost_VERSION}" VERSION_EQUAL "${Boost_FIND_VERSION}") - set(Boost_FOUND 0) - set(_Boost_VERSION_AGE "new") - else() - set(Boost_FOUND 1) - endif() - if(NOT Boost_FOUND) - # State that we found a version of Boost that is too new or too old. - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}\nDetected version of Boost is too ${_Boost_VERSION_AGE}. Requested version was ${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") - if (Boost_FIND_VERSION_PATCH) - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}.${Boost_FIND_VERSION_PATCH}") - endif () - if (NOT Boost_FIND_VERSION_EXACT) - set(Boost_ERROR_REASON "${Boost_ERROR_REASON} (or newer)") - endif () - set(Boost_ERROR_REASON "${Boost_ERROR_REASON}.") - endif () - else() - # Caller will accept any Boost version. - set(Boost_FOUND 1) - endif() -else() - set(Boost_FOUND 0) - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers.") -endif() - -# ------------------------------------------------------------------------ -# Prefix initialization -# ------------------------------------------------------------------------ - -set(Boost_LIB_PREFIX "") -if ( WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) - set(Boost_LIB_PREFIX "lib") -endif() - -if ( NOT Boost_NAMESPACE ) - set(Boost_NAMESPACE "boost") -endif() - -# ------------------------------------------------------------------------ -# Suffix initialization and compiler suffix detection. -# ------------------------------------------------------------------------ - -set(_Boost_VARS_NAME - Boost_NAMESPACE - Boost_COMPILER - Boost_THREADAPI - Boost_USE_DEBUG_PYTHON - Boost_USE_MULTITHREADED - Boost_USE_STATIC_LIBS - Boost_USE_STATIC_RUNTIME - Boost_USE_STLPORT - Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS - ) -_Boost_CHANGE_DETECT(_Boost_CHANGE_LIBNAME ${_Boost_VARS_NAME}) - -# Setting some more suffixes for the library -if (Boost_COMPILER) - set(_boost_COMPILER ${Boost_COMPILER}) - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "using user-specified Boost_COMPILER = ${_boost_COMPILER}") - endif() -else() - # Attempt to guess the compiler suffix - # NOTE: this is not perfect yet, if you experience any issues - # please report them and use the Boost_COMPILER variable - # to work around the problems. - _Boost_GUESS_COMPILER_PREFIX(_boost_COMPILER) - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "guessed _boost_COMPILER = ${_boost_COMPILER}") - endif() -endif() - -set (_boost_MULTITHREADED "-mt") -if( NOT Boost_USE_MULTITHREADED ) - set (_boost_MULTITHREADED "") -endif() -if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_MULTITHREADED = ${_boost_MULTITHREADED}") -endif() - -#====================== -# Systematically build up the Boost ABI tag -# http://boost.org/doc/libs/1_41_0/more/getting_started/windows.html#library-naming -set( _boost_RELEASE_ABI_TAG "-") -set( _boost_DEBUG_ABI_TAG "-") -# Key Use this library when: -# s linking statically to the C++ standard library and -# compiler runtime support libraries. -if(Boost_USE_STATIC_RUNTIME) - set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s") - set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s") -endif() -# g using debug versions of the standard and runtime -# support libraries -if(WIN32 AND Boost_USE_DEBUG_RUNTIME) - if(MSVC OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" - OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc") - set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}g") - endif() -endif() -# y using special debug build of python -if(Boost_USE_DEBUG_PYTHON) - set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}y") -endif() -# d using a debug version of your code -set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}d") -# p using the STLport standard library rather than the -# default one supplied with your compiler -if(Boost_USE_STLPORT) - set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}p") - set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}p") -endif() -# n using the STLport deprecated "native iostreams" feature -if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) - set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}n") - set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}n") -endif() - -if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_RELEASE_ABI_TAG = ${_boost_RELEASE_ABI_TAG}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_DEBUG_ABI_TAG = ${_boost_DEBUG_ABI_TAG}") -endif() - -#TODO: fix this when CMake is updated -#====================== -# Systematically build up the Boost architecture and address model tag -# http://www.boost.org/doc/libs/1_66_0/more/getting_started/windows.html#library-naming -set( _boost_AAM_TAG "-x") -# Key Use this library when: -# 32 32-bit address model -# 64 64-bit address model -if(PLATFORM EQUAL 64) - set( _boost_AAM_TAG "${_boost_AAM_TAG}64") -else() - set( _boost_AAM_TAG "${_boost_AAM_TAG}32") -endif() - -if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_AAM_TAG = ${_boost_AAM_TAG}") -endif() - -# ------------------------------------------------------------------------ -# Begin finding boost libraries -# ------------------------------------------------------------------------ -set(_Boost_VARS_LIB BOOST_LIBRARYDIR Boost_LIBRARY_DIR) -_Boost_CHANGE_DETECT(_Boost_CHANGE_LIBDIR ${_Boost_VARS_DIR} ${_Boost_VARS_LIB} Boost_INCLUDE_DIR) -# Clear Boost_LIBRARY_DIR if it did not change but other input affecting the -# location did. We will find a new one based on the new inputs. -if(_Boost_CHANGE_LIBDIR AND NOT _Boost_LIBRARY_DIR_CHANGED) - unset(Boost_LIBRARY_DIR CACHE) -endif() - -if(Boost_LIBRARY_DIR) - set(_boost_LIBRARY_SEARCH_DIRS ${Boost_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) -else() - set(_boost_LIBRARY_SEARCH_DIRS "") - if(BOOST_LIBRARYDIR) - list(APPEND _boost_LIBRARY_SEARCH_DIRS ${BOOST_LIBRARYDIR}) - elseif(_ENV_BOOST_LIBRARYDIR) - list(APPEND _boost_LIBRARY_SEARCH_DIRS ${_ENV_BOOST_LIBRARYDIR}) - endif() - - if(BOOST_ROOT) - list(APPEND _boost_LIBRARY_SEARCH_DIRS ${BOOST_ROOT}/lib ${BOOST_ROOT}/stage/lib) - elseif(_ENV_BOOST_ROOT) - list(APPEND _boost_LIBRARY_SEARCH_DIRS ${_ENV_BOOST_ROOT}/lib ${_ENV_BOOST_ROOT}/stage/lib) - endif() - - list(APPEND _boost_LIBRARY_SEARCH_DIRS - ${Boost_INCLUDE_DIR}/lib - ${Boost_INCLUDE_DIR}/../lib - ${Boost_INCLUDE_DIR}/stage/lib - ) - if( Boost_NO_SYSTEM_PATHS ) - list(APPEND _boost_LIBRARY_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH) - else() - list(APPEND _boost_LIBRARY_SEARCH_DIRS PATHS - C:/boost/lib - C:/boost - /sw/local/lib - ) - endif() -endif() - -if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_LIBRARY_SEARCH_DIRS = ${_boost_LIBRARY_SEARCH_DIRS}") -endif() - -# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES -if( Boost_USE_STATIC_LIBS ) - set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(WIN32) - set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) - endif() -endif() - -# We want to use the tag inline below without risking double dashes -if(_boost_RELEASE_ABI_TAG) - if(${_boost_RELEASE_ABI_TAG} STREQUAL "-") - set(_boost_RELEASE_ABI_TAG "") - endif() -endif() -if(_boost_DEBUG_ABI_TAG) - if(${_boost_DEBUG_ABI_TAG} STREQUAL "-") - set(_boost_DEBUG_ABI_TAG "") - endif() -endif() - -# The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled -# on WIN32 was to: -# 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found) -# 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found) -# We maintain this behavior since changing it could break people's builds. -# To disable the ambiguous behavior, the user need only -# set Boost_USE_STATIC_RUNTIME either ON or OFF. -set(_boost_STATIC_RUNTIME_WORKAROUND false) -if(WIN32 AND Boost_USE_STATIC_LIBS) - if(NOT DEFINED Boost_USE_STATIC_RUNTIME) - set(_boost_STATIC_RUNTIME_WORKAROUND true) - endif() -endif() - -# On versions < 1.35, remove the System library from the considered list -# since it wasn't added until 1.35. -if(Boost_VERSION AND Boost_FIND_COMPONENTS) - if(Boost_VERSION LESS 103500) - list(REMOVE_ITEM Boost_FIND_COMPONENTS system) - endif() -endif() - -# If the user changed any of our control inputs flush previous results. -if(_Boost_CHANGE_LIBDIR OR _Boost_CHANGE_LIBNAME) - foreach(COMPONENT ${_Boost_COMPONENTS_SEARCHED}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - foreach(c DEBUG RELEASE) - set(_var Boost_${UPPERCOMPONENT}_LIBRARY_${c}) - unset(${_var} CACHE) - set(${_var} "${_var}-NOTFOUND") - endforeach() - endforeach() - set(_Boost_COMPONENTS_SEARCHED "") -endif() - -foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - - set( _boost_docstring_release "Boost ${COMPONENT} library (release)") - set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)") - - # Compute component-specific hints. - set(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT "") - if(${COMPONENT} STREQUAL "mpi" OR ${COMPONENT} STREQUAL "mpi_python" OR - ${COMPONENT} STREQUAL "graph_parallel") - foreach(lib ${MPI_CXX_LIBRARIES} ${MPI_C_LIBRARIES}) - if(IS_ABSOLUTE "${lib}") - get_filename_component(libdir "${lib}" PATH) - string(REPLACE "\\" "/" libdir "${libdir}") - list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT ${libdir}) - endif() - endforeach() - endif() - - # Consolidate and report component-specific hints. - if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) - list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Component-specific library search paths for ${COMPONENT}: " - "${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT}") - endif() - endif() - - # - # Find RELEASE libraries - # - unset(_boost_RELEASE_NAMES) - foreach(compiler IN LISTS _boost_COMPILER) - list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_AAM_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ) - endforeach() - list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_AAM_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT} ) - if(_boost_STATIC_RUNTIME_WORKAROUND) - set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") - foreach(compiler IN LISTS _boost_COMPILER) - list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_AAM_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) - endforeach() - list( APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_AAM_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) - endif() - if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") - _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES}) - endif() - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}") - endif() - - # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. - string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS}") - - _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE - NAMES ${_boost_RELEASE_NAMES} - HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} - NAMES_PER_DIR - DOC "${_boost_docstring_release}" - ) - - # - # Find DEBUG libraries - # - unset(_boost_DEBUG_NAMES) - foreach(compiler IN LISTS _boost_COMPILER) - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_AAM_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ) - endforeach() - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_AAM_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT} ) - if(_boost_STATIC_RUNTIME_WORKAROUND) - set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") - foreach(compiler IN LISTS _boost_COMPILER) - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_AAM_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) - endforeach() - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_AAM_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) - endif() - if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") - _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES}) - endif() - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}") - endif() - - # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. - string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS}") - - _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG - NAMES ${_boost_DEBUG_NAMES} - HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} - NAMES_PER_DIR - DOC "${_boost_docstring_debug}" - ) - - if(Boost_REALPATH) - _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}") - _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" ) - endif() - - _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) - -endforeach() - -# Restore the original find library ordering -if( Boost_USE_STATIC_LIBS ) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) -endif() - -# ------------------------------------------------------------------------ -# End finding boost libraries -# ------------------------------------------------------------------------ - -set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) -set(Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR}) - -# The above setting of Boost_FOUND was based only on the header files. -# Update it for the requested component libraries. -if(Boost_FOUND) - # The headers were found. Check for requested component libs. - set(_boost_CHECKED_COMPONENT FALSE) - set(_Boost_MISSING_COMPONENTS "") - foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - string(TOUPPER ${COMPONENT} COMPONENT) - set(_boost_CHECKED_COMPONENT TRUE) - if(NOT Boost_${COMPONENT}_FOUND) - string(TOLOWER ${COMPONENT} COMPONENT) - list(APPEND _Boost_MISSING_COMPONENTS ${COMPONENT}) - endif() - endforeach() - - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] Boost_FOUND = ${Boost_FOUND}") - endif() - - if (_Boost_MISSING_COMPONENTS) - set(Boost_FOUND 0) - # We were unable to find some libraries, so generate a sensible - # error message that lists the libraries we were unable to find. - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}\nCould not find the following") - if(Boost_USE_STATIC_LIBS) - set(Boost_ERROR_REASON "${Boost_ERROR_REASON} static") - endif() - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON} Boost libraries:\n") - foreach(COMPONENT ${_Boost_MISSING_COMPONENTS}) - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON} ${Boost_NAMESPACE}_${COMPONENT}\n") - endforeach() - - list(LENGTH Boost_FIND_COMPONENTS Boost_NUM_COMPONENTS_WANTED) - list(LENGTH _Boost_MISSING_COMPONENTS Boost_NUM_MISSING_COMPONENTS) - if (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost. If you still have problems search on forum for TCE00020.") - else () - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost. If you still have problems search on forum for TCE00021.") - endif () - endif () - - if( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) - # Compatibility Code for backwards compatibility with CMake - # 2.4's FindBoost module. - - # Look for the boost library path. - # Note that the user may not have installed any libraries - # so it is quite possible the Boost_LIBRARY_DIRS may not exist. - set(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) - - if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") - get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) - endif() - - if("${_boost_LIB_DIR}" MATCHES "/include$") - # Strip off the trailing "/include" in the path. - get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) - endif() - - if(EXISTS "${_boost_LIB_DIR}/lib") - set(_boost_LIB_DIR ${_boost_LIB_DIR}/lib) - else() - if(EXISTS "${_boost_LIB_DIR}/stage/lib") - set(_boost_LIB_DIR ${_boost_LIB_DIR}/stage/lib) - else() - set(_boost_LIB_DIR "") - endif() - endif() - - if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") - set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR}) - endif() - - endif() -else() - # Boost headers were not found so no components were found. - foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - set(Boost_${UPPERCOMPONENT}_FOUND 0) - endforeach() -endif() - -# ------------------------------------------------------------------------ -# Notification to end user about what was found -# ------------------------------------------------------------------------ - -set(Boost_LIBRARIES "") -if(Boost_FOUND) - if(NOT Boost_FIND_QUIETLY) - message(STATUS "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") - if(Boost_FIND_COMPONENTS) - message(STATUS "Found the following Boost libraries:") - endif() - endif() - foreach( COMPONENT ${Boost_FIND_COMPONENTS} ) - string( TOUPPER ${COMPONENT} UPPERCOMPONENT ) - if( Boost_${UPPERCOMPONENT}_FOUND ) - if(NOT Boost_FIND_QUIETLY) - message (STATUS " ${COMPONENT}") - endif() - list(APPEND Boost_LIBRARIES ${Boost_${UPPERCOMPONENT}_LIBRARY}) - endif() - endforeach() -else() - if(Boost_FIND_REQUIRED) - message(SEND_ERROR "Unable to find the requested Boost libraries.\n${Boost_ERROR_REASON}") - else() - if(NOT Boost_FIND_QUIETLY) - # we opt not to automatically output Boost_ERROR_REASON here as - # it could be quite lengthy and somewhat imposing in its requests - # Since Boost is not always a required dependency we'll leave this - # up to the end-user. - if(Boost_DEBUG OR Boost_DETAILED_FAILURE_MSG) - message(STATUS "Could NOT find Boost\n${Boost_ERROR_REASON}") - else() - message(STATUS "Could NOT find Boost") - endif() - endif() - endif() -endif() - -# Configure display of cache entries in GUI. -foreach(v BOOSTROOT BOOST_ROOT ${_Boost_VARS_INC} ${_Boost_VARS_LIB}) - get_property(_type CACHE ${v} PROPERTY TYPE) - if(_type) - set_property(CACHE ${v} PROPERTY ADVANCED 1) - if("x${_type}" STREQUAL "xUNINITIALIZED") - if("x${v}" STREQUAL "xBoost_ADDITIONAL_VERSIONS") - set_property(CACHE ${v} PROPERTY TYPE STRING) - else() - set_property(CACHE ${v} PROPERTY TYPE PATH) - endif() - endif() - endif() -endforeach() - -# Record last used values of input variables so we can -# detect on the next run if the user changed them. -foreach(v - ${_Boost_VARS_INC} ${_Boost_VARS_LIB} - ${_Boost_VARS_DIR} ${_Boost_VARS_NAME} - ) - if(DEFINED ${v}) - set(_${v}_LAST "${${v}}" CACHE INTERNAL "Last used ${v} value.") - else() - unset(_${v}_LAST CACHE) - endif() -endforeach() - -# Maintain a persistent list of components requested anywhere since -# the last flush. -set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}") -list(APPEND _Boost_COMPONENTS_SEARCHED ${Boost_FIND_COMPONENTS}) -list(REMOVE_DUPLICATES _Boost_COMPONENTS_SEARCHED) -list(SORT _Boost_COMPONENTS_SEARCHED) -set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}" - CACHE INTERNAL "Components requested for this build tree.") diff --git a/cmake/macros/FindMySQL.cmake b/cmake/macros/FindMySQL.cmake index 02d17ab48f2..122e88be6a2 100644 --- a/cmake/macros/FindMySQL.cmake +++ b/cmake/macros/FindMySQL.cmake @@ -1,19 +1,60 @@ +# This file is part of the TrinityCore Project. See AUTHORS file for Copyright information # -# Find the MySQL client includes and library +# 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 of the License, or (at your +# option) any later version. # +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . + +#[=======================================================================[.rst: +FindMySQL +----------- + +Find MySQL. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module defines the following :prop_tgt:`IMPORTED` targets: + +``MySQL::MySQL`` + MySQL client library, if found. -# This module defines -# MYSQL_INCLUDE_DIR, where to find mysql.h -# MYSQL_LIBRARIES, the libraries to link against to connect to MySQL -# MYSQL_EXECUTABLE, the MySQL executable. -# MYSQL_FOUND, if false, you cannot build anything that requires MySQL. +Result Variables +^^^^^^^^^^^^^^^^ -# also defined, but not for general use are -# MYSQL_LIBRARY, where to find the MySQL library. +This module will set the following variables in your project: -set( MYSQL_FOUND 0 ) +``MYSQL_FOUND`` + System has MySQL. +``MYSQL_INCLUDE_DIR`` + MySQL include directory. +``MYSQL_LIBRARY`` + MySQL library. +``MYSQL_EXECUTABLE`` + Path to mysql client binary. -if( UNIX ) +Hints +^^^^^ + +Set ``MYSQL_ROOT_DIR`` to the root directory of MySQL installation. +#]=======================================================================] + +set(MYSQL_FOUND 0) + +set(_MYSQL_ROOT_HINTS + ${MYSQL_ROOT_DIR} + ENV MYSQL_ROOT_DIR +) + +if(UNIX) set(MYSQL_CONFIG_PREFER_PATH "$ENV{MYSQL_HOME}/bin" CACHE FILEPATH "preferred path to MySQL (mysql_config)" ) @@ -25,21 +66,23 @@ if( UNIX ) /usr/bin/ ) - if( MYSQL_CONFIG ) + if(MYSQL_CONFIG) message(STATUS "Using mysql-config: ${MYSQL_CONFIG}") # set INCLUDE_DIR - exec_program(${MYSQL_CONFIG} - ARGS --include + execute_process( + COMMAND "${MYSQL_CONFIG}" --include OUTPUT_VARIABLE MY_TMP + OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX REPLACE "-I([^ ]*)( .*)?" "\\1" MY_TMP "${MY_TMP}") set(MYSQL_ADD_INCLUDE_PATH ${MY_TMP} CACHE FILEPATH INTERNAL) #message("[DEBUG] MYSQL ADD_INCLUDE_PATH : ${MYSQL_ADD_INCLUDE_PATH}") # set LIBRARY_DIR - exec_program(${MYSQL_CONFIG} - ARGS --libs_r + execute_process( + COMMAND "${MYSQL_CONFIG}" --libs_r OUTPUT_VARIABLE MY_TMP + OUTPUT_STRIP_TRAILING_WHITESPACE ) set(MYSQL_ADD_LIBRARIES "") string(REGEX MATCHALL "-l[^ ]*" MYSQL_LIB_LIST "${MY_TMP}") @@ -57,28 +100,23 @@ if( UNIX ) #message("[DEBUG] MYSQL ADD_LIBRARIES_PATH : ${MYSQL_ADD_LIBRARIES_PATH}") endforeach(LIB ${MYSQL_LIBS}) - else( MYSQL_CONFIG ) + else(MYSQL_CONFIG) set(MYSQL_ADD_LIBRARIES "") list(APPEND MYSQL_ADD_LIBRARIES "mysqlclient_r") - endif( MYSQL_CONFIG ) -endif( UNIX ) + endif(MYSQL_CONFIG) +endif(UNIX) -if( WIN32 ) +if(WIN32) # read environment variables and change \ to / - SET(PROGRAM_FILES_32 $ENV{ProgramFiles}) - if (${PROGRAM_FILES_32}) - STRING(REPLACE "\\\\" "/" PROGRAM_FILES_32 ${PROGRAM_FILES_32}) - endif(${PROGRAM_FILES_32}) - - SET(PROGRAM_FILES_64 $ENV{ProgramW6432}) - if (${PROGRAM_FILES_64}) - STRING(REPLACE "\\\\" "/" PROGRAM_FILES_64 ${PROGRAM_FILES_64}) - endif(${PROGRAM_FILES_64}) -endif ( WIN32 ) + file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" PROGRAM_FILES_32) + file(TO_CMAKE_PATH "$ENV{ProgramW6432}" PROGRAM_FILES_64) +endif(WIN32) find_path(MYSQL_INCLUDE_DIR NAMES mysql.h + HINTS + ${_MYSQL_ROOT_HINTS} PATHS ${MYSQL_ADD_INCLUDE_PATH} /usr/include @@ -86,42 +124,50 @@ find_path(MYSQL_INCLUDE_DIR /usr/local/include /usr/local/include/mysql /usr/local/mysql/include - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/include" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/include" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.5/include" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.1/include" - "${PROGRAM_FILES_64}/MySQL/include" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/include" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/include" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.5/include" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.1/include" - "${PROGRAM_FILES_32}/MySQL/include" - "C:/MySQL/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.5;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.1;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.5;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.1;Location]/include" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/include" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.6/include" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.5/include" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.1/include" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.7/include" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.6/include" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.5/include" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.1/include" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.3" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.2" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.1" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7" + "${PROGRAM_FILES_64}/MySQL" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.3" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.2" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.1" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7" + "${PROGRAM_FILES_32}/MySQL" + "C:/MySQL" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.3;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.2;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.1;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.3;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.2;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.1;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.3" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.2" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.1" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.0" + "$ENV{SystemDrive}/MySQL/MySQL Server 5.7" "c:/msys/local/include" - "$ENV{MYSQL_ROOT}/include" + "$ENV{MYSQL_ROOT}" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.4;INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.4 (x64);INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.5;INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.5 (x64);INSTALLDIR]" + PATH_SUFFIXES + include + include/mysql DOC "Specify the directory containing mysql.h." ) -if( UNIX ) +if(UNIX) foreach(LIB ${MYSQL_ADD_LIBRARIES}) - find_library( MYSQL_LIBRARY + find_library(MYSQL_LIBRARY NAMES mysql libmysql ${LIB} PATHS @@ -134,68 +180,62 @@ if( UNIX ) DOC "Specify the location of the mysql library here." ) endforeach(LIB ${MYSQL_ADD_LIBRARY}) -endif( UNIX ) +endif(UNIX) -if( WIN32 ) - find_library( MYSQL_LIBRARY +if(WIN32) + find_library(MYSQL_LIBRARY NAMES - libmysql + libmysql libmariadb + HINTS + ${_MYSQL_ROOT_HINTS} PATHS ${MYSQL_ADD_LIBRARIES_PATH} - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/lib" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/lib" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.5/lib" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.1/lib" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/lib/opt" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/lib/opt" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.5/lib/opt" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.1/lib/opt" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.3" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.2" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.1" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7" "${PROGRAM_FILES_64}/MySQL/lib" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/lib" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/lib" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.5/lib" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.1/lib" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/lib/opt" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/lib/opt" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.5/lib/opt" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.1/lib/opt" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.3" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.2" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.1" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7" "${PROGRAM_FILES_32}/MySQL/lib" "C:/MySQL/lib/debug" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.5;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.1;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.5;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.1;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.5;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.1;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.5;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.1;Location]/lib/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/lib/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.6/lib/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.5/lib/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.1/lib/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.7/lib/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.6/lib/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.5/lib/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.1/lib/opt" - "c:/msys/local/include" - "$ENV{MYSQL_ROOT}/lib" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.3;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.2;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.1;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.3;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.2;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.1;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.3" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.2" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.1" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.0" + "$ENV{SystemDrive}/MySQL/MySQL Server 5.7" + "c:/msys/local/lib" + "$ENV{MYSQL_ROOT}" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.4;INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.4 (x64);INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.5;INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.5 (x64);INSTALLDIR]" + PATH_SUFFIXES + lib + lib/opt DOC "Specify the location of the mysql library here." ) -endif( WIN32 ) +endif(WIN32) # On Windows you typically don't need to include any extra libraries # to build MYSQL stuff. -if( NOT WIN32 ) - find_library( MYSQL_EXTRA_LIBRARIES +if(NOT WIN32) + find_library(MYSQL_EXTRA_LIBRARIES NAMES z zlib PATHS @@ -204,11 +244,11 @@ if( NOT WIN32 ) DOC "if more libraries are necessary to link in a MySQL client (typically zlib), specify them here." ) -else( NOT WIN32 ) - set( MYSQL_EXTRA_LIBRARIES "" ) -endif( NOT WIN32 ) +else(NOT WIN32) + set(MYSQL_EXTRA_LIBRARIES "") +endif(NOT WIN32) -if( UNIX ) +if(UNIX) find_program(MYSQL_EXECUTABLE mysql PATHS ${MYSQL_CONFIG_PREFER_PATH} @@ -218,73 +258,116 @@ if( UNIX ) DOC "path to your mysql binary." ) -endif( UNIX ) +endif(UNIX) -if( WIN32 ) - find_program(MYSQL_EXECUTABLE mysql - PATHS - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/bin" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.5/bin" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.1/bin" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin/opt" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/bin/opt" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.5/bin/opt" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.1/bin/opt" - "${PROGRAM_FILES_64}/MySQL/bin" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/bin" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.5/bin" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.1/bin" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin/opt" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/bin/opt" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.5/bin/opt" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.1/bin/opt" - "${PROGRAM_FILES_32}/MySQL/bin" - "C:/MySQL/bin/debug" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.5;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.1;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.5;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.1;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.5;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.1;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.5;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.1;Location]/bin/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/bin/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.6/bin/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.5/bin/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.1/bin/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.7/bin/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.6/bin/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.5/bin/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.1/bin/opt" - "c:/msys/local/include" - "$ENV{MYSQL_ROOT}/bin" - DOC - "path to your mysql binary." - ) -endif( WIN32 ) +if(WIN32) + find_program(MYSQL_EXECUTABLE mysql + HINTS + ${_MYSQL_ROOT_HINTS} + PATHS + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.3" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.2" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.1" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0" + "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7" + "${PROGRAM_FILES_64}/MySQL" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.3" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.2" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.1" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0" + "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7" + "${PROGRAM_FILES_32}/MySQL" + "C:/MySQL/bin/debug" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.3;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.2;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.1;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.3;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.2;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.1;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.3" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.2" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.1" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.0" + "$ENV{SystemDrive}/MySQL/MySQL Server 5.7" + "c:/msys/local/bin" + "$ENV{MYSQL_ROOT}" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.4;INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.4 (x64);INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.5;INSTALLDIR]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB 10.5 (x64);INSTALLDIR]" + PATH_SUFFIXES + bin + bin/opt + DOC + "path to your mysql binary." + ) +endif(WIN32) + +unset(MySQL_lib_WANTED) +unset(MySQL_binary_WANTED) +set(MYSQL_REQUIRED_VARS "") +foreach(_comp IN LISTS MySQL_FIND_COMPONENTS) + if(_comp STREQUAL "lib") + set(MySQL_${_comp}_WANTED TRUE) + if(MySQL_FIND_REQUIRED_${_comp}) + list(APPEND MYSQL_REQUIRED_VARS "MYSQL_LIBRARY") + list(APPEND MYSQL_REQUIRED_VARS "MYSQL_INCLUDE_DIR") + endif() + if(EXISTS "${MYSQL_LIBRARY}" AND EXISTS "${MYSQL_INCLUDE_DIR}") + set(MySQL_${_comp}_FOUND TRUE) + else() + set(MySQL_${_comp}_FOUND FALSE) + endif() + elseif(_comp STREQUAL "binary") + set(MySQL_${_comp}_WANTED TRUE) + if(MySQL_FIND_REQUIRED_${_comp}) + list(APPEND MYSQL_REQUIRED_VARS "MYSQL_EXECUTABLE") + endif() + if(EXISTS "${MYSQL_EXECUTABLE}" ) + set(MySQL_${_comp}_FOUND TRUE) + else() + set(MySQL_${_comp}_FOUND FALSE) + endif() + else() + message(WARNING "${_comp} is not a valid MySQL component") + set(MySQL_${_comp}_FOUND FALSE) + endif() +endforeach() +unset(_comp) -if( MYSQL_LIBRARY ) - if( MYSQL_INCLUDE_DIR ) - set( MYSQL_FOUND 1 ) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MySQL + REQUIRED_VARS + ${MYSQL_REQUIRED_VARS} + HANDLE_COMPONENTS + FAIL_MESSAGE + "Could not find the MySQL libraries! Please install the development libraries and headers" +) +unset(MYSQL_REQUIRED_VARS) + +if(MYSQL_FOUND) + if(MySQL_lib_WANTED AND MySQL_lib_FOUND) message(STATUS "Found MySQL library: ${MYSQL_LIBRARY}") message(STATUS "Found MySQL headers: ${MYSQL_INCLUDE_DIR}") - else( MYSQL_INCLUDE_DIR ) - message(FATAL_ERROR "Could not find MySQL headers! Please install the development libraries and headers") - endif( MYSQL_INCLUDE_DIR ) - if( MYSQL_EXECUTABLE ) + endif() + if(MySQL_binary_WANTED AND MySQL_binary_FOUND) message(STATUS "Found MySQL executable: ${MYSQL_EXECUTABLE}") - endif( MYSQL_EXECUTABLE ) - mark_as_advanced( MYSQL_FOUND MYSQL_LIBRARY MYSQL_EXTRA_LIBRARIES MYSQL_INCLUDE_DIR MYSQL_EXECUTABLE) -else( MYSQL_LIBRARY ) + endif() + mark_as_advanced(MYSQL_FOUND MYSQL_LIBRARY MYSQL_EXTRA_LIBRARIES MYSQL_INCLUDE_DIR MYSQL_EXECUTABLE) + + if(NOT TARGET MySQL::MySQL AND MySQL_lib_WANTED AND MySQL_lib_FOUND) + add_library(MySQL::MySQL UNKNOWN IMPORTED) + set_target_properties(MySQL::MySQL + PROPERTIES + IMPORTED_LOCATION + "${MYSQL_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES + "${MYSQL_INCLUDE_DIR}") + endif() +else() message(FATAL_ERROR "Could not find the MySQL libraries! Please install the development libraries and headers") -endif( MYSQL_LIBRARY ) +endif() diff --git a/cmake/macros/FindOpenSSL.cmake b/cmake/macros/FindOpenSSL.cmake index 3af44729410..98788bc2986 100644 --- a/cmake/macros/FindOpenSSL.cmake +++ b/cmake/macros/FindOpenSSL.cmake @@ -1,74 +1,314 @@ -# - Try to find the OpenSSL encryption library -# Once done this will define -# -# OPENSSL_ROOT_DIR - Set this variable to the root installation of OpenSSL -# -# Read-Only variables: -# OPENSSL_FOUND - system has the OpenSSL library -# OPENSSL_INCLUDE_DIR - the OpenSSL include directory -# OPENSSL_LIBRARIES - The libraries needed to use OpenSSL - -#============================================================================= -# Copyright 2006-2009 Kitware, Inc. -# Copyright 2006 Alexander Neundorf -# Copyright 2009-2010 Mathieu Malaterre -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distributed this file outside of CMake, substitute the full -# License text for the above reference.) - -# http://www.slproweb.com/products/Win32OpenSSL.html - -set(OPENSSL_EXPECTED_VERSION "1.0") -set(OPENSSL_MAX_VERSION "1.2") - -SET(_OPENSSL_ROOT_HINTS - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]" - ) +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. -IF(PLATFORM EQUAL 64) - SET(_OPENSSL_ROOT_PATHS - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;InstallLocation]" - "C:/OpenSSL-Win64/" - "C:/OpenSSL/" - ) -ELSE() - SET(_OPENSSL_ROOT_PATHS - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;InstallLocation]" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;InstallLocation]" +#[=======================================================================[.rst: +FindOpenSSL +----------- + +Find the OpenSSL encryption library. + +This module finds an installed OpenSSL library and determines its version. + +.. versionadded:: 3.19 + When a version is requested, it can be specified as a simple value or as a + range. For a detailed description of version range usage and capabilities, + refer to the :command:`find_package` command. + +.. versionadded:: 3.18 + Support for OpenSSL 3.0. + +Optional COMPONENTS +^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.12 + +This module supports two optional COMPONENTS: ``Crypto`` and ``SSL``. Both +components have associated imported targets, as described below. + +Imported Targets +^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.4 + +This module defines the following :prop_tgt:`IMPORTED` targets: + +``OpenSSL::SSL`` + The OpenSSL ``ssl`` library, if found. +``OpenSSL::Crypto`` + The OpenSSL ``crypto`` library, if found. +``OpenSSL::applink`` + .. versionadded:: 3.18 + + The OpenSSL ``applink`` components that might be need to be compiled into + projects under MSVC. This target is available only if found OpenSSL version + is not less than 0.9.8. By linking this target the above OpenSSL targets can + be linked even if the project has different MSVC runtime configurations with + the above OpenSSL targets. This target has no effect on platforms other than + MSVC. + +NOTE: Due to how ``INTERFACE_SOURCES`` are consumed by the consuming target, +unless you certainly know what you are doing, it is always preferred to link +``OpenSSL::applink`` target as ``PRIVATE`` and to make sure that this target is +linked at most once for the whole dependency graph of any library or +executable: + +.. code-block:: cmake + + target_link_libraries(myTarget PRIVATE OpenSSL::applink) + +Otherwise you would probably encounter unexpected random problems when building +and linking, as both the ISO C and the ISO C++ standard claims almost nothing +about what a link process should be. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module will set the following variables in your project: + +``OPENSSL_FOUND`` + System has the OpenSSL library. If no components are requested it only + requires the crypto library. +``OPENSSL_INCLUDE_DIR`` + The OpenSSL include directory. +``OPENSSL_CRYPTO_LIBRARY`` + The OpenSSL crypto library. +``OPENSSL_CRYPTO_LIBRARIES`` + The OpenSSL crypto library and its dependencies. +``OPENSSL_SSL_LIBRARY`` + The OpenSSL SSL library. +``OPENSSL_SSL_LIBRARIES`` + The OpenSSL SSL library and its dependencies. +``OPENSSL_LIBRARIES`` + All OpenSSL libraries and their dependencies. +``OPENSSL_VERSION`` + This is set to ``$major.$minor.$revision$patch`` (e.g. ``0.9.8s``). +``OPENSSL_APPLINK_SOURCE`` + The sources in the target ``OpenSSL::applink`` that is mentioned above. This + variable shall always be undefined if found openssl version is less than + 0.9.8 or if platform is not MSVC. + +Hints +^^^^^ + +The following variables may be set to control search behavior: + +``OPENSSL_ROOT_DIR`` + Set to the root directory of an OpenSSL installation. + +``OPENSSL_USE_STATIC_LIBS`` + .. versionadded:: 3.4 + + Set to ``TRUE`` to look for static libraries. + +``OPENSSL_MSVC_STATIC_RT`` + .. versionadded:: 3.5 + + Set to ``TRUE`` to choose the MT version of the lib. + +``ENV{PKG_CONFIG_PATH}`` + On UNIX-like systems, ``pkg-config`` is used to locate the system OpenSSL. + Set the ``PKG_CONFIG_PATH`` environment variable to look in alternate + locations. Useful on multi-lib systems. +#]=======================================================================] + +macro(_OpenSSL_test_and_find_dependencies ssl_library crypto_library) + unset(_OpenSSL_extra_static_deps) + if(UNIX AND + (("${ssl_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$") OR + ("${crypto_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$"))) + set(_OpenSSL_has_dependencies TRUE) + unset(_OpenSSL_has_dependency_zlib) + if(OPENSSL_USE_STATIC_LIBS) + set(_OpenSSL_libs "${_OPENSSL_STATIC_LIBRARIES}") + set(_OpenSSL_ldflags_other "${_OPENSSL_STATIC_LDFLAGS_OTHER}") + else() + set(_OpenSSL_libs "${_OPENSSL_LIBRARIES}") + set(_OpenSSL_ldflags_other "${_OPENSSL_LDFLAGS_OTHER}") + endif() + if(_OpenSSL_libs) + unset(_OpenSSL_has_dependency_dl) + foreach(_OPENSSL_DEP_LIB IN LISTS _OpenSSL_libs) + if (_OPENSSL_DEP_LIB STREQUAL "ssl" OR _OPENSSL_DEP_LIB STREQUAL "crypto") + # ignoring: these are the targets + elseif(_OPENSSL_DEP_LIB STREQUAL CMAKE_DL_LIBS) + set(_OpenSSL_has_dependency_dl TRUE) + elseif(_OPENSSL_DEP_LIB STREQUAL "z") + find_package(ZLIB) + set(_OpenSSL_has_dependency_zlib TRUE) + else() + list(APPEND _OpenSSL_extra_static_deps "${_OPENSSL_DEP_LIB}") + endif() + endforeach() + unset(_OPENSSL_DEP_LIB) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(_OpenSSL_has_dependency_dl TRUE) + endif() + if(_OpenSSL_ldflags_other) + unset(_OpenSSL_has_dependency_threads) + foreach(_OPENSSL_DEP_LDFLAG IN LISTS _OpenSSL_ldflags_other) + if (_OPENSSL_DEP_LDFLAG STREQUAL "-pthread") + set(_OpenSSL_has_dependency_threads TRUE) + find_package(Threads) + endif() + endforeach() + unset(_OPENSSL_DEP_LDFLAG) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(_OpenSSL_has_dependency_threads TRUE) + find_package(Threads) + endif() + unset(_OpenSSL_libs) + unset(_OpenSSL_ldflags_other) + else() + set(_OpenSSL_has_dependencies FALSE) + endif() +endmacro() + +function(_OpenSSL_add_dependencies libraries_var) + if(_OpenSSL_has_dependency_zlib) + list(APPEND ${libraries_var} ${ZLIB_LIBRARY}) + endif() + if(_OpenSSL_has_dependency_threads) + list(APPEND ${libraries_var} ${CMAKE_THREAD_LIBS_INIT}) + endif() + if(_OpenSSL_has_dependency_dl) + list(APPEND ${libraries_var} ${CMAKE_DL_LIBS}) + endif() + list(APPEND ${libraries_var} ${_OpenSSL_extra_static_deps}) + set(${libraries_var} ${${libraries_var}} PARENT_SCOPE) +endfunction() + +function(_OpenSSL_target_add_dependencies target) + if(_OpenSSL_has_dependencies) + if(_OpenSSL_has_dependency_zlib) + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ZLIB::ZLIB ) + endif() + if(_OpenSSL_has_dependency_threads) + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads) + endif() + if(_OpenSSL_has_dependency_dl) + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS} ) + endif() + if(_OpenSSL_extra_static_deps) + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_OpenSSL_extra_static_deps}) + endif() + endif() + if(WIN32 AND OPENSSL_USE_STATIC_LIBS) + if(WINCE) + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2 ) + else() + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32 ) + endif() + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES crypt32 ) + endif() +endfunction() + +if (UNIX) + find_package(PkgConfig QUIET) + pkg_check_modules(_OPENSSL QUIET openssl) +endif () + +# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES +if(OPENSSL_USE_STATIC_LIBS) + set(_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(MSVC) + set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) + endif() +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "QNX" AND + CMAKE_SYSTEM_VERSION VERSION_GREATER_EQUAL "7.0" AND CMAKE_SYSTEM_VERSION VERSION_LESS "7.1" AND + OpenSSL_FIND_VERSION VERSION_GREATER_EQUAL "1.1" AND OpenSSL_FIND_VERSION VERSION_LESS "1.2") + # QNX 7.0.x provides openssl 1.0.2 and 1.1.1 in parallel: + # * openssl 1.0.2: libcrypto.so.2 and libssl.so.2, headers under usr/include/openssl + # * openssl 1.1.1: libcrypto1_1.so.2.1 and libssl1_1.so.2.1, header under usr/include/openssl1_1 + # See http://www.qnx.com/developers/articles/rel_6726_0.html + set(_OPENSSL_FIND_PATH_SUFFIX "openssl1_1") + set(_OPENSSL_NAME_POSTFIX "1_1") +else() + set(_OPENSSL_FIND_PATH_SUFFIX "include") +endif() + +if (OPENSSL_ROOT_DIR OR NOT "$ENV{OPENSSL_ROOT_DIR}" STREQUAL "") + set(_OPENSSL_ROOT_HINTS HINTS ${OPENSSL_ROOT_DIR} ENV OPENSSL_ROOT_DIR) + set(_OPENSSL_ROOT_PATHS NO_DEFAULT_PATH) +elseif (MSVC) + # http://www.slproweb.com/products/Win32OpenSSL.html + set(_OPENSSL_MSI_INSTALL_GUIDS "") + + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + if(TRINITY_SYSTEM_PROCESSOR STREQUAL "arm64") + set(_arch "Win64-ARM") + set(_OPENSSL_MSI_INSTALL_GUIDS "99C28AFA-6419-40B1-B88D-32B810BB4234") + else() + set(_arch "Win64") + set(_OPENSSL_MSI_INSTALL_GUIDS "117551DB-A110-4BBD-BB05-CFE0BCB3ED31" "50A9FBE2-0F8C-4D5D-97A4-A63A71C4EA1E") + endif() + file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) + set(_OPENSSL_ROOT_HINTS HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]") + else() + set(_arch "Win32") + set(_progfiles_x86 "ProgramFiles(x86)") + if(NOT "$ENV{${_progfiles_x86}}" STREQUAL "") + # under windows 64 bit machine + file(TO_CMAKE_PATH "$ENV{${_progfiles_x86}}" _programfiles) + else() + # under windows 32 bit machine + file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _programfiles) + endif() + set(_OPENSSL_ROOT_HINTS HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]") + set(_OPENSSL_MSI_INSTALL_GUIDS "A1EEC576-43B9-4E75-9E02-03DA542D2A38" "31D2408A-9CAE-4988-9EC3-F40FDE7D6AE5") + endif() + + # If OpenSSL was installed using .msi package instead of .exe, Inno Setup registry values are not written to Uninstall\OpenSSL + # but because it is only a shim around Inno Setup it does write the location of uninstaller which we can use to determine path + foreach(_OPENSSL_MSI_INSTALL_GUID IN LISTS _OPENSSL_MSI_INSTALL_GUIDS) + get_filename_component(_OPENSSL_MSI_INSTALL_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Inno Setup MSIs\\${_OPENSSL_MSI_INSTALL_GUID};]" DIRECTORY) + if(NOT _OPENSSL_MSI_INSTALL_PATH STREQUAL "/") + list(INSERT _OPENSSL_ROOT_HINTS 2 ${_OPENSSL_MSI_INSTALL_PATH}) + endif() + endforeach() + unset(_OPENSSL_MSI_INSTALL_GUIDS) + + set(_OPENSSL_ROOT_PATHS + PATHS + "${_programfiles}/OpenSSL" + "${_programfiles}/OpenSSL-${_arch}" "C:/OpenSSL/" - ) -ENDIF() + "C:/OpenSSL-${_arch}/" + ) + unset(_programfiles) + unset(_arch) +endif () -FIND_PATH(OPENSSL_ROOT_DIR - NAMES - include/openssl/ssl.h - HINTS +if(HOMEBREW_PREFIX) + list(APPEND _OPENSSL_ROOT_HINTS + "${HOMEBREW_PREFIX}/opt/openssl@3") +endif() + +set(_OPENSSL_ROOT_HINTS_AND_PATHS ${_OPENSSL_ROOT_HINTS} - PATHS ${_OPENSSL_ROOT_PATHS} -) -MARK_AS_ADVANCED(OPENSSL_ROOT_DIR) + ) -# Re-use the previous path: -FIND_PATH(OPENSSL_INCLUDE_DIR openssl/ssl.h - ${OPENSSL_ROOT_DIR}/include +find_path(OPENSSL_INCLUDE_DIR + NAMES + openssl/ssl.h + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + HINTS + ${_OPENSSL_INCLUDEDIR} + ${_OPENSSL_INCLUDE_DIRS} + PATH_SUFFIXES + ${_OPENSSL_FIND_PATH_SUFFIX} ) -IF(WIN32 AND NOT CYGWIN) - # MINGW should go here too - IF(MSVC) +if(WIN32 AND NOT CYGWIN) + if(MSVC) # /MD and /MDd are the standard values - if someone wants to use # others, the libnames have to change here too # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b - # TODO: handle /MT and static lib + # enable OPENSSL_MSVC_STATIC_RT to get the libs build /MT (Multithreaded no-DLL) # In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix: # * MD for dynamic-release # * MDd for dynamic-debug @@ -76,128 +316,326 @@ IF(WIN32 AND NOT CYGWIN) # * MTd for static-debug # Implementation details: - # We are using the libraries located in the VC subdir instead of the parent directory eventhough : + # We are using the libraries located in the VC subdir instead of the parent directory even though : # libeay32MD.lib is identical to ../libeay32.lib, and # ssleay32MD.lib is identical to ../ssleay32.lib + # enable OPENSSL_USE_STATIC_LIBS to use the static libs located in lib/VC/static + + if (OPENSSL_MSVC_STATIC_RT) + set(_OPENSSL_MSVC_RT_MODE "MT") + else () + set(_OPENSSL_MSVC_RT_MODE "MD") + endif () # Since OpenSSL 1.1, lib names are like libcrypto32MTd.lib and libssl32MTd.lib if( "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8" ) - set(_OPENSSL_MSVC_ARCH_SUFFIX "64") + set(_OPENSSL_MSVC_ARCH_SUFFIX "64") + if(TRINITY_SYSTEM_PROCESSOR STREQUAL "arm64") + set(_OPENSSL_MSVC_ARCH_DIRECTORY "arm64") + else() + set(_OPENSSL_MSVC_ARCH_DIRECTORY "x64") + endif() else() - set(_OPENSSL_MSVC_ARCH_SUFFIX "32") + set(_OPENSSL_MSVC_ARCH_SUFFIX "32") + set(_OPENSSL_MSVC_ARCH_DIRECTORY "x86") endif() - FIND_LIBRARY(LIB_EAY_DEBUG + if(OPENSSL_USE_STATIC_LIBS) + set(_OPENSSL_STATIC_SUFFIX + "_static" + ) + set(_OPENSSL_PATH_SUFFIXES + "lib/VC/static" + "VC/static" + "lib" + ) + else() + set(_OPENSSL_STATIC_SUFFIX + "" + ) + set(_OPENSSL_PATH_SUFFIXES + "lib/VC" + "VC" + "lib" + ) + endif () + + find_library(LIB_EAY_DEBUG NAMES - libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}MDd libeay32MDd libeay32 - PATHS - ${OPENSSL_ROOT_DIR}/lib/VC + libcrypto${_OPENSSL_STATIC_SUFFIX} + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + "lib/VC/${_OPENSSL_MSVC_ARCH_DIRECTORY}/${_OPENSSL_MSVC_RT_MODE}d" ) - FIND_LIBRARY(LIB_EAY_RELEASE - NAMES - libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}MD libeay32MD libeay32 - PATHS - ${OPENSSL_ROOT_DIR}/lib/VC - ) + if(NOT LIB_EAY_DEBUG) + find_library(LIB_EAY_DEBUG + NAMES + # When OpenSSL is built with default options, the static library name is suffixed with "_static". + # Looking the "libcrypto_static.lib" with a higher priority than "libcrypto.lib" which is the + # import library of "libcrypto.dll". + libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libcrypto${_OPENSSL_STATIC_SUFFIX}d + libeay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libeay32${_OPENSSL_STATIC_SUFFIX}d + crypto${_OPENSSL_STATIC_SUFFIX}d + # When OpenSSL is built with the "-static" option, only the static build is produced, + # and it is not suffixed with "_static". + libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libcrypto${_OPENSSL_MSVC_RT_MODE}d + libcryptod + libeay32${_OPENSSL_MSVC_RT_MODE}d + libeay32d + cryptod + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + ${_OPENSSL_PATH_SUFFIXES} + ) + endif() - FIND_LIBRARY(SSL_EAY_DEBUG + find_library(LIB_EAY_RELEASE NAMES - libssl${_OPENSSL_MSVC_ARCH_SUFFIX}MDd ssleay32MDd ssleay32 ssl - PATHS - ${OPENSSL_ROOT_DIR}/lib/VC + # When OpenSSL is built with default options, the static library name is suffixed with "_static". + # Looking the "libcrypto_static.lib" with a higher priority than "libcrypto.lib" which is the + # import library of "libcrypto.dll". + libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libcrypto${_OPENSSL_STATIC_SUFFIX} + libeay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libeay32${_OPENSSL_STATIC_SUFFIX} + crypto${_OPENSSL_STATIC_SUFFIX} + # When OpenSSL is built with the "-static" option, only the static build is produced, + # and it is not suffixed with "_static". + libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libcrypto${_OPENSSL_MSVC_RT_MODE} + libcrypto + libeay32${_OPENSSL_MSVC_RT_MODE} + libeay32 + crypto + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + ${_OPENSSL_PATH_SUFFIXES} + "lib/VC/${_OPENSSL_MSVC_ARCH_DIRECTORY}/${_OPENSSL_MSVC_RT_MODE}" ) - FIND_LIBRARY(SSL_EAY_RELEASE + find_library(SSL_EAY_DEBUG NAMES - libssl${_OPENSSL_MSVC_ARCH_SUFFIX}MD ssleay32MD ssleay32 ssl - PATHS - ${OPENSSL_ROOT_DIR}/lib/VC + libssl${_OPENSSL_STATIC_SUFFIX} + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + "lib/VC/${_OPENSSL_MSVC_ARCH_DIRECTORY}/${_OPENSSL_MSVC_RT_MODE}d" ) - if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) - set( OPENSSL_LIBRARIES - optimized ${SSL_EAY_RELEASE} optimized ${LIB_EAY_RELEASE} - debug ${SSL_EAY_DEBUG} debug ${LIB_EAY_DEBUG} - ) - else() - set( OPENSSL_LIBRARIES - ${SSL_EAY_RELEASE} - ${LIB_EAY_RELEASE} + if(NOT SSL_EAY_DEBUG) + find_library(SSL_EAY_DEBUG + NAMES + # When OpenSSL is built with default options, the static library name is suffixed with "_static". + # Looking the "libssl_static.lib" with a higher priority than "libssl.lib" which is the + # import library of "libssl.dll". + libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libssl${_OPENSSL_STATIC_SUFFIX}d + ssleay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + ssleay32${_OPENSSL_STATIC_SUFFIX}d + ssl${_OPENSSL_STATIC_SUFFIX}d + # When OpenSSL is built with the "-static" option, only the static build is produced, + # and it is not suffixed with "_static". + libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libssl${_OPENSSL_MSVC_RT_MODE}d + libssld + ssleay32${_OPENSSL_MSVC_RT_MODE}d + ssleay32d + ssld + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + ${_OPENSSL_PATH_SUFFIXES} ) endif() - MARK_AS_ADVANCED(SSL_EAY_DEBUG SSL_EAY_RELEASE LIB_EAY_DEBUG LIB_EAY_RELEASE) - ELSEIF(MINGW) - - # same player, for MingW - FIND_LIBRARY(LIB_EAY + find_library(SSL_EAY_RELEASE NAMES - libeay32 - PATHS - ${OPENSSL_ROOT_DIR}/lib/MinGW + # When OpenSSL is built with default options, the static library name is suffixed with "_static". + # Looking the "libssl_static.lib" with a higher priority than "libssl.lib" which is the + # import library of "libssl.dll". + libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libssl${_OPENSSL_STATIC_SUFFIX} + ssleay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + ssleay32${_OPENSSL_STATIC_SUFFIX} + ssl${_OPENSSL_STATIC_SUFFIX} + # When OpenSSL is built with the "-static" option, only the static build is produced, + # and it is not suffixed with "_static". + libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libssl${_OPENSSL_MSVC_RT_MODE} + libssl + ssleay32${_OPENSSL_MSVC_RT_MODE} + ssleay32 + ssl + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + ${_OPENSSL_PATH_SUFFIXES} + "lib/VC/${_OPENSSL_MSVC_ARCH_DIRECTORY}/${_OPENSSL_MSVC_RT_MODE}" ) - FIND_LIBRARY(SSL_EAY NAMES + set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}") + set(LIB_EAY_LIBRARY_RELEASE "${LIB_EAY_RELEASE}") + set(SSL_EAY_LIBRARY_DEBUG "${SSL_EAY_DEBUG}") + set(SSL_EAY_LIBRARY_RELEASE "${SSL_EAY_RELEASE}") + + include(SelectLibraryConfigurations) + select_library_configurations(LIB_EAY) + select_library_configurations(SSL_EAY) + + mark_as_advanced(LIB_EAY_LIBRARY_DEBUG LIB_EAY_LIBRARY_RELEASE + SSL_EAY_LIBRARY_DEBUG SSL_EAY_LIBRARY_RELEASE) + set(OPENSSL_SSL_LIBRARY ${SSL_EAY_LIBRARY} ) + set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY_LIBRARY} ) + elseif(MINGW) + # same player, for MinGW + set(LIB_EAY_NAMES crypto libeay32) + set(SSL_EAY_NAMES ssl ssleay32) + find_library(LIB_EAY NAMES - ssleay32 - PATHS - ${OPENSSL_ROOT_DIR}/lib/MinGW + ${LIB_EAY_NAMES} + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + "lib/MinGW" + "lib" + "lib64" ) - MARK_AS_ADVANCED(SSL_EAY LIB_EAY) - - set( OPENSSL_LIBRARIES - ${SSL_EAY} - ${LIB_EAY} + find_library(SSL_EAY + NAMES + ${SSL_EAY_NAMES} + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + "lib/MinGW" + "lib" + "lib64" ) - ELSE(MSVC) + + mark_as_advanced(SSL_EAY LIB_EAY) + set(OPENSSL_SSL_LIBRARY ${SSL_EAY} ) + set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} ) + unset(LIB_EAY_NAMES) + unset(SSL_EAY_NAMES) + else() # Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues: - FIND_LIBRARY(LIB_EAY + find_library(LIB_EAY NAMES + libcrypto libeay32 - PATHS - ${OPENSSL_ROOT_DIR}/lib - ${OPENSSL_ROOT_DIR}/lib/VC + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + HINTS + ${_OPENSSL_LIBDIR} + PATH_SUFFIXES + lib ) - FIND_LIBRARY(SSL_EAY + find_library(SSL_EAY NAMES + libssl ssleay32 - PATHS - ${OPENSSL_ROOT_DIR}/lib - ${OPENSSL_ROOT_DIR}/lib/VC + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + HINTS + ${_OPENSSL_LIBDIR} + PATH_SUFFIXES + lib ) - MARK_AS_ADVANCED(SSL_EAY LIB_EAY) - SET( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} ) - ENDIF(MSVC) -ELSE(WIN32 AND NOT CYGWIN) - FIND_LIBRARY(OPENSSL_SSL_LIBRARIES NAMES ssl ssleay32 ssleay32MD) - FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARIES NAMES crypto) - MARK_AS_ADVANCED(OPENSSL_CRYPTO_LIBRARIES OPENSSL_SSL_LIBRARIES) + mark_as_advanced(SSL_EAY LIB_EAY) + set(OPENSSL_SSL_LIBRARY ${SSL_EAY} ) + set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} ) + endif() +else() + + find_library(OPENSSL_SSL_LIBRARY + NAMES + ssl${_OPENSSL_NAME_POSTFIX} + ssleay32 + ssleay32MD + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + HINTS + ${_OPENSSL_LIBDIR} + ${_OPENSSL_LIBRARY_DIRS} + PATH_SUFFIXES + lib lib64 + ) - SET(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES}) + find_library(OPENSSL_CRYPTO_LIBRARY + NAMES + crypto${_OPENSSL_NAME_POSTFIX} + NAMES_PER_DIR + ${_OPENSSL_ROOT_HINTS_AND_PATHS} + HINTS + ${_OPENSSL_LIBDIR} + ${_OPENSSL_LIBRARY_DIRS} + PATH_SUFFIXES + lib lib64 + ) -ENDIF(WIN32 AND NOT CYGWIN) + mark_as_advanced(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY) -if (NOT OPENSSL_INCLUDE_DIR) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(OpenSSL DEFAULT_MSG - OPENSSL_LIBRARIES - OPENSSL_INCLUDE_DIR - ) endif() -if (OPENSSL_INCLUDE_DIR) - message( STATUS "Found OpenSSL library: ${OPENSSL_LIBRARIES}") - message( STATUS "Found OpenSSL headers: ${OPENSSL_INCLUDE_DIR}") - if (_OPENSSL_VERSION) - set(OPENSSL_VERSION "${_OPENSSL_VERSION}") - else (_OPENSSL_VERSION) - file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str - REGEX "^# *define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x[0-9][0-9][0-9][0-9][0-9][0-9].*") +set(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY}) +set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY}) +set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES} ) +_OpenSSL_test_and_find_dependencies("${OPENSSL_SSL_LIBRARY}" "${OPENSSL_CRYPTO_LIBRARY}") +if(_OpenSSL_has_dependencies) + _OpenSSL_add_dependencies( OPENSSL_SSL_LIBRARIES ) + _OpenSSL_add_dependencies( OPENSSL_CRYPTO_LIBRARIES ) + _OpenSSL_add_dependencies( OPENSSL_LIBRARIES ) +endif() + +function(from_hex HEX DEC) + string(TOUPPER "${HEX}" HEX) + set(_res 0) + string(LENGTH "${HEX}" _strlen) + + while (_strlen GREATER 0) + math(EXPR _res "${_res} * 16") + string(SUBSTRING "${HEX}" 0 1 NIBBLE) + string(SUBSTRING "${HEX}" 1 -1 HEX) + if (NIBBLE STREQUAL "A") + math(EXPR _res "${_res} + 10") + elseif (NIBBLE STREQUAL "B") + math(EXPR _res "${_res} + 11") + elseif (NIBBLE STREQUAL "C") + math(EXPR _res "${_res} + 12") + elseif (NIBBLE STREQUAL "D") + math(EXPR _res "${_res} + 13") + elseif (NIBBLE STREQUAL "E") + math(EXPR _res "${_res} + 14") + elseif (NIBBLE STREQUAL "F") + math(EXPR _res "${_res} + 15") + else() + math(EXPR _res "${_res} + ${NIBBLE}") + endif() + string(LENGTH "${HEX}" _strlen) + endwhile() + + set(${DEC} ${_res} PARENT_SCOPE) +endfunction() + +if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h") + file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str + REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*") + + if(openssl_version_str) # The version number is encoded as 0xMNNFFPPS: major minor fix patch status # The status gives if this is a developer or prerelease and is ignored here. # Major, minor, and fix directly translate into the version numbers shown in @@ -205,33 +643,179 @@ if (OPENSSL_INCLUDE_DIR) # indicates the bug fix state, which 00 -> nothing, 01 -> a, 02 -> b and so # on. - string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f]).*$" + string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$" "\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}") list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR) list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR) + from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR) list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX) + from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX) list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH) - string(REGEX REPLACE "^0(.)" "\\1" OPENSSL_VERSION_MINOR "${OPENSSL_VERSION_MINOR}") - string(REGEX REPLACE "^0(.)" "\\1" OPENSSL_VERSION_FIX "${OPENSSL_VERSION_FIX}") - if (NOT OPENSSL_VERSION_PATCH STREQUAL "00") + from_hex("${OPENSSL_VERSION_PATCH}" _tmp) # 96 is the ASCII code of 'a' minus 1 - math(EXPR OPENSSL_VERSION_PATCH_ASCII "${OPENSSL_VERSION_PATCH} + 96") + math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96") + unset(_tmp) # Once anyone knows how OpenSSL would call the patch versions beyond 'z' # this should be updated to handle that, too. This has not happened yet # so it is simply ignored here for now. string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING) - endif (NOT OPENSSL_VERSION_PATCH STREQUAL "00") + endif () set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}") - endif (_OPENSSL_VERSION) + else () + # Since OpenSSL 3.0.0, the new version format is MAJOR.MINOR.PATCH and + # a new OPENSSL_VERSION_STR macro contains exactly that + file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" OPENSSL_VERSION_STR + REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_STR[\t ]+\"([0-9])+\\.([0-9])+\\.([0-9])+\".*") + string(REGEX REPLACE "^.*OPENSSL_VERSION_STR[\t ]+\"([0-9]+\\.[0-9]+\\.[0-9]+)\".*$" + "\\1" OPENSSL_VERSION_STR "${OPENSSL_VERSION_STR}") + + set(OPENSSL_VERSION "${OPENSSL_VERSION_STR}") + + unset(OPENSSL_VERSION_STR) + endif () +endif () + +foreach(_comp IN LISTS OpenSSL_FIND_COMPONENTS) + if(_comp STREQUAL "Crypto") + if(EXISTS "${OPENSSL_INCLUDE_DIR}" AND + (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR + EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR + EXISTS "${LIB_EAY_LIBRARY_RELEASE}") + ) + set(OpenSSL_${_comp}_FOUND TRUE) + else() + set(OpenSSL_${_comp}_FOUND FALSE) + endif() + elseif(_comp STREQUAL "SSL") + if(EXISTS "${OPENSSL_INCLUDE_DIR}" AND + (EXISTS "${OPENSSL_SSL_LIBRARY}" OR + EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR + EXISTS "${SSL_EAY_LIBRARY_RELEASE}") + ) + set(OpenSSL_${_comp}_FOUND TRUE) + else() + set(OpenSSL_${_comp}_FOUND FALSE) + endif() + else() + message(WARNING "${_comp} is not a valid OpenSSL component") + set(OpenSSL_${_comp}_FOUND FALSE) + endif() +endforeach() +unset(_comp) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OpenSSL + REQUIRED_VARS + OPENSSL_CRYPTO_LIBRARY + OPENSSL_INCLUDE_DIR + VERSION_VAR + OPENSSL_VERSION + HANDLE_COMPONENTS + FAIL_MESSAGE + "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR" +) + +mark_as_advanced(OPENSSL_INCLUDE_DIR) - include(EnsureVersion) - ENSURE_VERSION_RANGE("${OPENSSL_EXPECTED_VERSION}" "${OPENSSL_VERSION}" "${OPENSSL_MAX_VERSION}" OPENSSL_VERSION_OK) - if (NOT OPENSSL_VERSION_OK) - message(FATAL_ERROR "TrinityCore needs OpenSSL version ${OPENSSL_EXPECTED_VERSION} but found version ${OPENSSL_VERSION}") +if(OPENSSL_FOUND) + if(NOT TARGET OpenSSL::Crypto AND + (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR + EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR + EXISTS "${LIB_EAY_LIBRARY_RELEASE}") + ) + add_library(OpenSSL::Crypto UNKNOWN IMPORTED) + set_target_properties(OpenSSL::Crypto PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}") + if(EXISTS "${OPENSSL_CRYPTO_LIBRARY}") + set_target_properties(OpenSSL::Crypto PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${OPENSSL_CRYPTO_LIBRARY}") + endif() + if(EXISTS "${LIB_EAY_LIBRARY_RELEASE}") + set_property(TARGET OpenSSL::Crypto APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(OpenSSL::Crypto PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${LIB_EAY_LIBRARY_RELEASE}") + endif() + if(EXISTS "${LIB_EAY_LIBRARY_DEBUG}") + set_property(TARGET OpenSSL::Crypto APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(OpenSSL::Crypto PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${LIB_EAY_LIBRARY_DEBUG}") + endif() + _OpenSSL_target_add_dependencies(OpenSSL::Crypto) endif() -endif (OPENSSL_INCLUDE_DIR) -MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES) + if(NOT TARGET OpenSSL::SSL AND + (EXISTS "${OPENSSL_SSL_LIBRARY}" OR + EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR + EXISTS "${SSL_EAY_LIBRARY_RELEASE}") + ) + add_library(OpenSSL::SSL UNKNOWN IMPORTED) + set_target_properties(OpenSSL::SSL PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}") + if(EXISTS "${OPENSSL_SSL_LIBRARY}") + set_target_properties(OpenSSL::SSL PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${OPENSSL_SSL_LIBRARY}") + endif() + if(EXISTS "${SSL_EAY_LIBRARY_RELEASE}") + set_property(TARGET OpenSSL::SSL APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(OpenSSL::SSL PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${SSL_EAY_LIBRARY_RELEASE}") + endif() + if(EXISTS "${SSL_EAY_LIBRARY_DEBUG}") + set_property(TARGET OpenSSL::SSL APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(OpenSSL::SSL PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${SSL_EAY_LIBRARY_DEBUG}") + endif() + if(TARGET OpenSSL::Crypto) + set_target_properties(OpenSSL::SSL PROPERTIES + INTERFACE_LINK_LIBRARIES OpenSSL::Crypto) + endif() + _OpenSSL_target_add_dependencies(OpenSSL::SSL) + endif() + + if("${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}" VERSION_GREATER_EQUAL "0.9.8") + if(MSVC) + if(EXISTS "${OPENSSL_INCLUDE_DIR}") + set(_OPENSSL_applink_paths PATHS ${OPENSSL_INCLUDE_DIR}) + endif() + find_file(OPENSSL_APPLINK_SOURCE + NAMES + openssl/applink.c + ${_OPENSSL_applink_paths} + NO_DEFAULT_PATH) + if(OPENSSL_APPLINK_SOURCE) + set(_OPENSSL_applink_interface_srcs ${OPENSSL_APPLINK_SOURCE}) + endif() + endif() + if(NOT TARGET OpenSSL::applink) + add_library(OpenSSL::applink INTERFACE IMPORTED) + set_property(TARGET OpenSSL::applink APPEND + PROPERTY INTERFACE_SOURCES + ${_OPENSSL_applink_interface_srcs}) + endif() + endif() +endif() + +# Restore the original find library ordering +if(OPENSSL_USE_STATIC_LIBS) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) +endif() + +unset(_OPENSSL_FIND_PATH_SUFFIX) +unset(_OPENSSL_NAME_POSTFIX) +unset(_OpenSSL_extra_static_deps) +unset(_OpenSSL_has_dependency_dl) +unset(_OpenSSL_has_dependency_threads) +unset(_OpenSSL_has_dependency_zlib) diff --git a/cmake/macros/FindPCHSupport.cmake b/cmake/macros/FindPCHSupport.cmake index 9c77605616b..aa5147cf499 100644 --- a/cmake/macros/FindPCHSupport.cmake +++ b/cmake/macros/FindPCHSupport.cmake @@ -1,27 +1,35 @@ -if (MSVC) - # Specify the maximum PreCompiled Header memory allocation limit - # Fixes a compiler-problem when using PCH - the /Ym flag is adjusted by the compiler in MSVC2012, - # hence we need to set an upper limit with /Zm to avoid discrepancies) - # (And yes, this is a verified, unresolved bug with MSVC... *sigh*) - # - # Note: This workaround was verified to be required on MSVC 2017 as well - set(COTIRE_PCH_MEMORY_SCALING_FACTOR 500) -endif() +if (CMAKE_VERSION VERSION_LESS "3.16.0") + if (MSVC) + # Specify the maximum PreCompiled Header memory allocation limit + # Fixes a compiler-problem when using PCH - the /Ym flag is adjusted by the compiler in MSVC2012, + # hence we need to set an upper limit with /Zm to avoid discrepancies) + # (And yes, this is a verified, unresolved bug with MSVC... *sigh*) + # + # Note: This workaround was verified to be required on MSVC 2017 as well + set(COTIRE_PCH_MEMORY_SCALING_FACTOR 500) + endif () -include(cotire) + include(cotire) -function(ADD_CXX_PCH TARGET_NAME_LIST PCH_HEADER) - # Use the header for every target - foreach(TARGET_NAME ${TARGET_NAME_LIST}) - # Disable unity builds - set_target_properties(${TARGET_NAME} PROPERTIES COTIRE_ADD_UNITY_BUILD OFF) + function(ADD_CXX_PCH TARGET_NAME_LIST PCH_HEADER) + # Use the header for every target + foreach (TARGET_NAME ${TARGET_NAME_LIST}) + # Disable unity builds + set_target_properties(${TARGET_NAME} PROPERTIES COTIRE_ADD_UNITY_BUILD OFF) - # Set the prefix header - set_target_properties(${TARGET_NAME} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT ${PCH_HEADER}) + # Set the prefix header + set_target_properties(${TARGET_NAME} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT ${PCH_HEADER}) - # Workaround for cotire bug: https://github.com/sakra/cotire/issues/138 - set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 14) - endforeach() + # Workaround for cotire bug: https://github.com/sakra/cotire/issues/138 + set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 14) + endforeach () - cotire(${TARGET_NAME_LIST}) -endfunction(ADD_CXX_PCH) + cotire(${TARGET_NAME_LIST}) + endfunction(ADD_CXX_PCH) +else() + function(ADD_CXX_PCH TARGET_NAME_LIST PCH_HEADER) + foreach(TARGET_NAME ${TARGET_NAME_LIST}) + target_precompile_headers(${TARGET_NAME} PRIVATE ${PCH_HEADER}) + endforeach() + endfunction(ADD_CXX_PCH) +endif() diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt index e3ddba5533e..02a742169be 100644 --- a/dep/CMakeLists.txt +++ b/dep/CMakeLists.txt @@ -31,7 +31,6 @@ if(SERVERS) add_subdirectory(rapidjson) add_subdirectory(efsw) add_subdirectory(protobuf) - add_subdirectory(duktape) if (WITH_CPR) add_subdirectory(cpr) diff --git a/dep/boost/CMakeLists.txt b/dep/boost/CMakeLists.txt index 60cd0ff8fad..5b843feb93e 100644 --- a/dep/boost/CMakeLists.txt +++ b/dep/boost/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2018 TrinityCore +# This file is part of the TrinityCore Project. See AUTHORS file for Copyright information # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -8,27 +8,24 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +set(BOOST_SEARCH_HINTS) if(WIN32) - set(BOOST_DEBUG ON) if(DEFINED ENV{BOOST_ROOT}) set(BOOST_ROOT $ENV{BOOST_ROOT}) - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0) - set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-12.0) - elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) - set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.0) - else() - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.20) - list(APPEND BOOST_LIBRARYDIR - ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.1 - ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.0 ) - else() - list(APPEND BOOST_LIBRARYDIR - ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.2 - ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.1 ) - endif() - endif() - else() - message(FATAL_ERROR "No BOOST_ROOT environment variable could be found! Please make sure it is set and the points to your Boost installation.") + endif() + if(DEFINED BOOST_ROOT AND MSVC) + # insert a dot (.) character before last digit of MSVC_TOOLSET_VERSION + # turn 143 into 14.3 + string(LENGTH "${MSVC_TOOLSET_VERSION}" _BOOST_MSVC_TOOLSET_VERSION_LENGTH) + math(EXPR _BOOST_MSVC_TOOLSET_VERSION_LENGTH "${_BOOST_MSVC_TOOLSET_VERSION_LENGTH} - 1" OUTPUT_FORMAT DECIMAL) + string(SUBSTRING "${MSVC_TOOLSET_VERSION}" 0 ${_BOOST_MSVC_TOOLSET_VERSION_LENGTH} _BOOST_MSVC_TOOLSET_VERSION_MAJOR) + string(SUBSTRING "${MSVC_TOOLSET_VERSION}" ${_BOOST_MSVC_TOOLSET_VERSION_LENGTH} -1 _BOOST_MSVC_TOOLSET_VERSION_MINOR) + + set(BOOST_SEARCH_HINTS "${BOOST_ROOT}/lib${PLATFORM}-msvc-${_BOOST_MSVC_TOOLSET_VERSION_MAJOR}.${_BOOST_MSVC_TOOLSET_VERSION_MINOR}/cmake") + + unset(_BOOST_MSVC_TOOLSET_VERSION_LENGTH) + unset(_BOOST_MSVC_TOOLSET_VERSION_MAJOR) + unset(_BOOST_MSVC_TOOLSET_VERSION_MINOR) endif() set(Boost_USE_STATIC_LIBS ON) @@ -36,32 +33,47 @@ if(WIN32) set(Boost_USE_STATIC_RUNTIME OFF) endif() -include (CheckCXXSourceCompiles) - -check_cxx_source_compiles(" - #include - int main() { std::wregex r(L\".*\"); }" - STD_HAS_WORKING_WREGEX) - -if (STD_HAS_WORKING_WREGEX) - find_package(Boost 1.58 REQUIRED system filesystem thread program_options iostreams) +if (WIN32) + # On windows the requirements are higher according to the wiki. + set(BOOST_REQUIRED_VERSION 1.78) else() - find_package(Boost 1.58 REQUIRED system filesystem thread program_options iostreams regex) + set(BOOST_REQUIRED_VERSION 1.74) endif() +find_package(Boost ${BOOST_REQUIRED_VERSION} + REQUIRED + COMPONENTS + system + filesystem + thread + program_options + iostreams + regex + locale + CONFIG + HINTS + ${BOOST_SEARCH_HINTS}) + # Find if Boost was compiled in C++03 mode because it requires -DBOOST_NO_CXX11_SCOPED_ENUMS +include (CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_IOSTREAMS_LIBRARY}) set(CMAKE_REQUIRED_FLAGS "-std=c++11") +unset(boost_filesystem_copy_links_without_NO_SCOPED_ENUM CACHE) check_cxx_source_compiles(" #include #include int main() { boost::filesystem::copy_file(boost::filesystem::path(), boost::filesystem::path()); }" boost_filesystem_copy_links_without_NO_SCOPED_ENUM) -unset(CMAKE_REQUIRED_INCLUDES) -unset(CMAKE_REQUIRED_LIBRARIES) -unset(CMAKE_REQUIRED_FLAGS) +unset(CMAKE_REQUIRED_INCLUDES CACHE) +unset(CMAKE_REQUIRED_LIBRARIES CACHE) +unset(CMAKE_REQUIRED_FLAGS CACHE) + +if (NOT boost_filesystem_copy_links_without_NO_SCOPED_ENUM) + set(OPTIONAL_BOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS) +endif() add_library(boost INTERFACE) @@ -78,17 +90,4 @@ target_compile_definitions(boost -DBOOST_DATE_TIME_NO_LIB -DBOOST_REGEX_NO_LIB -DBOOST_CHRONO_NO_LIB - -DBOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE - -DBOOST_ASIO_NO_DEPRECATED) - -if (NOT boost_filesystem_copy_links_without_NO_SCOPED_ENUM) - target_compile_definitions(boost - INTERFACE - -DBOOST_NO_CXX11_SCOPED_ENUMS) -endif() - -if (NOT STD_HAS_WORKING_WREGEX) - target_compile_definitions(boost - INTERFACE - -DTC_HAS_BROKEN_WSTRING_REGEX) -endif() + ${OPTIONAL_BOOST_NO_SCOPED_ENUMS}) diff --git a/dep/duktape/CMakeLists.txt b/dep/duktape/CMakeLists.txt deleted file mode 100644 index 834c1da20e6..00000000000 --- a/dep/duktape/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -set(DUKTAPEDIR ${CMAKE_CURRENT_LIST_DIR}) - -include_directories( - ${DUKTAPEDIR}/duktape - ${DUKTAPEDIR}/dukglue -) - -add_library(duktape STATIC ${DUKTAPEDIR}/duktape/duktape.c) - -if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") - target_link_libraries(duktape - m dl rt - ) -endif() - -add_library(dukglue INTERFACE) - -set(DUKGLUE_HEADERS - ${DUKTAPEDIR}/duktape/duktape.h - ${DUKTAPEDIR}/duktape/duk_config.h - - ${DUKTAPEDIR}/dukglue/dukglue.h - ${DUKTAPEDIR}/dukglue/detail_class_proto.h - ${DUKTAPEDIR}/dukglue/detail_constructor.h - ${DUKTAPEDIR}/dukglue/detail_function.h - ${DUKTAPEDIR}/dukglue/detail_method.h - ${DUKTAPEDIR}/dukglue/detail_primitive_types.h - ${DUKTAPEDIR}/dukglue/detail_refs.h - ${DUKTAPEDIR}/dukglue/detail_stack.h - ${DUKTAPEDIR}/dukglue/detail_traits.h - ${DUKTAPEDIR}/dukglue/detail_typeinfo.h - ${DUKTAPEDIR}/dukglue/detail_types.h - ${DUKTAPEDIR}/dukglue/dukvalue.h - ${DUKTAPEDIR}/dukglue/dukexception.h - ${DUKTAPEDIR}/dukglue/register_class.h - ${DUKTAPEDIR}/dukglue/register_function.h - ${DUKTAPEDIR}/dukglue/register_property.h - ${DUKTAPEDIR}/dukglue/public_util.h - CACHE INTERNAL "" -) - -target_include_directories(dukglue INTERFACE ${DUKTAPEDIR}) diff --git a/dep/duktape/dukglue/detail_class_proto.h b/dep/duktape/dukglue/detail_class_proto.h deleted file mode 100644 index 7b008fccd10..00000000000 --- a/dep/duktape/dukglue/detail_class_proto.h +++ /dev/null @@ -1,201 +0,0 @@ -#pragma once - -#include "detail_typeinfo.h" -#include - -namespace dukglue { - namespace detail { - - struct ProtoManager - { - public: - template - static void push_prototype(duk_context* ctx) - { - push_prototype(ctx, TypeInfo(typeid(Cls))); - } - - static void push_prototype(duk_context* ctx, const TypeInfo& check_info) - { - if (!find_and_push_prototype(ctx, check_info)) { - // nope, need to create our prototype object - duk_push_object(ctx); - - // add reference to this class' info object so we can do type checking - // when trying to pass this object into method calls - typedef dukglue::detail::TypeInfo TypeInfo; - TypeInfo* info = new TypeInfo(check_info); - - duk_push_pointer(ctx, info); - duk_put_prop_string(ctx, -2, "\xFF" "type_info"); - - // Clean up the TypeInfo object when this prototype is destroyed. - // We can't put a finalizer directly on this prototype, because it - // will be run whenever the wrapper for an object of this class is - // destroyed; instead, we make a dummy object and put the finalizer - // on that. - // If you're memory paranoid: this duplicates the type_info pointer - // once per registered class. If you don't care about freeing memory - // during shutdown, you can probably comment out this part. - duk_push_object(ctx); - duk_push_pointer(ctx, info); - duk_put_prop_string(ctx, -2, "\xFF" "type_info"); - duk_push_c_function(ctx, type_info_finalizer, 1); - duk_set_finalizer(ctx, -2); - duk_put_prop_string(ctx, -2, "\xFF" "type_info_finalizer"); - - // register it in the stash - register_prototype(ctx, info); - } - } - - template - static void make_script_object(duk_context* ctx, Cls* obj) - { - assert(obj != NULL); - - duk_push_object(ctx); - duk_push_pointer(ctx, obj); - duk_put_prop_string(ctx, -2, "\xFF" "obj_ptr"); - - // push the appropriate prototype -#ifdef DUKGLUE_INFER_BASE_CLASS - // In the "infer base class" case, we push the prototype - // corresponding to the compile-time class if no prototype - // for the run-time type has been defined. This allows us to - // skip calling dukglue_set_base_class() for every derived class, - // so long as we: - // (1) Always use the derived class as a pointer typed as the base class - // (2) Do not create a prototype for the derived class - // (i.e. do not register any functions on the derived class). - - // For big projects with hundreds of derived classes, this is preferrable - // to registering each type's base class individually. However, - // registering a native method on a derived class will cause the - // base class's methods to disappear until dukglue_set_base_class() is - // also called (because registering the native method causes a prototype - // to be created for the run-time type). This behavior may be unexpected, - // and for "small" projects it is reasonable to require - // dukglue_set_base_class() to be called, so it is opt-in via an ifdef. - - // does a prototype exist for the run-time type? if so, push it - if (!find_and_push_prototype(ctx, TypeInfo(typeid(*obj)))) { - // nope, find or create the prototype for the compile-time type - // and push that - push_prototype(ctx); - } -#else - // always use the prototype for the run-time type - push_prototype(ctx, TypeInfo(typeid(*obj))); -#endif - - duk_set_prototype(ctx, -2); - } - - private: - static duk_ret_t type_info_finalizer(duk_context* ctx) - { - duk_get_prop_string(ctx, 0, "\xFF" "type_info"); - dukglue::detail::TypeInfo* info = static_cast(duk_require_pointer(ctx, -1)); - delete info; - - // set pointer to NULL in case this finalizer runs again - duk_push_pointer(ctx, NULL); - duk_put_prop_string(ctx, 0, "\xFF" "type_info"); - - return 0; - } - - // puts heap_stash["dukglue_prototypes"] on the stack, - // or creates it if it doesn't exist - static void push_prototypes_array(duk_context* ctx) - { - static const char* DUKGLUE_PROTOTYPES = "dukglue_prototypes"; - - duk_push_heap_stash(ctx); - - // does the prototype array already exist? - if (!duk_has_prop_string(ctx, -1, DUKGLUE_PROTOTYPES)) { - // nope, we need to create it - duk_push_array(ctx); - duk_put_prop_string(ctx, -2, DUKGLUE_PROTOTYPES); - } - - duk_get_prop_string(ctx, -1, DUKGLUE_PROTOTYPES); - - // remove the heap stash from the stack - duk_remove(ctx, -2); - } - - // Stack: ... [proto] -> ... [proto] - static void register_prototype(duk_context* ctx, const TypeInfo* info) { - // 1. We assume info is not in the prototype array already - // 2. Duktape has no efficient "shift array indices" operation (at least publicly) - // 3. This method doesn't need to be fast, it's only called during registration - - // Work from high to low in the prototypes array, shifting as we go, - // until we find the spot for info. - - push_prototypes_array(ctx); - duk_size_t i = duk_get_length(ctx, -1); - while (i > 0) { - duk_get_prop_index(ctx, -1, i - 1); - - duk_get_prop_string(ctx, -1, "\xFF" "type_info"); - const TypeInfo* chk_info = static_cast(duk_require_pointer(ctx, -1)); - duk_pop(ctx); // pop type_info - - if (*chk_info > *info) { - duk_put_prop_index(ctx, -2, i); - i--; - } else { - duk_pop(ctx); // pop prototypes_array[i] - break; - } - } - - //std::cout << "Registering prototype for " << typeid(Cls).name() << " at " << i << std::endl; - - duk_dup(ctx, -2); // copy proto to top - duk_put_prop_index(ctx, -2, i); - duk_pop(ctx); // pop prototypes_array - } - - static bool find_and_push_prototype(duk_context* ctx, const TypeInfo& search_info) { - push_prototypes_array(ctx); - - // these are ints and not duk_size_t to deal with negative indices - int min = 0; - int max = duk_get_length(ctx, -1) - 1; - - while (min <= max) { - int mid = (max - min) / 2 + min; - - duk_get_prop_index(ctx, -1, mid); - - duk_get_prop_string(ctx, -1, "\xFF" "type_info"); - TypeInfo* mid_info = static_cast(duk_require_pointer(ctx, -1)); - duk_pop(ctx); // pop type_info pointer - - if (*mid_info == search_info) { - // found it - duk_remove(ctx, -2); // pop prototypes_array - return true; - } - else if (*mid_info < search_info) { - min = mid + 1; - } - else { - max = mid - 1; - } - - duk_pop(ctx); // pop prototypes_array[mid] - } - - duk_pop(ctx); // pop prototypes_array - return false; - } - - }; - } -} diff --git a/dep/duktape/dukglue/detail_constructor.h b/dep/duktape/dukglue/detail_constructor.h deleted file mode 100644 index de68e85d5eb..00000000000 --- a/dep/duktape/dukglue/detail_constructor.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include "detail_stack.h" -#include "detail_traits.h" - -namespace dukglue { - namespace detail { - - template - static duk_ret_t call_native_constructor(duk_context* ctx) - { - if (!duk_is_constructor_call(ctx)) { - duk_error(ctx, DUK_RET_TYPE_ERROR, "Constructor must be called with new T()."); - return DUK_RET_TYPE_ERROR; - } - - // construct the new instance - auto constructor_args = dukglue::detail::get_stack_values(ctx); - Cls* obj = dukglue::detail::apply_constructor(std::move(constructor_args)); - - duk_push_this(ctx); - - // make the new script object keep the pointer to the new object instance - duk_push_pointer(ctx, obj); - duk_put_prop_string(ctx, -2, "\xFF" "obj_ptr"); - - // register it - if (!managed) - dukglue::detail::RefManager::register_native_object(ctx, obj); - - duk_pop(ctx); // pop this - - return 0; - } - - template - static duk_ret_t managed_finalizer(duk_context* ctx) - { - duk_get_prop_string(ctx, 0, "\xFF" "obj_ptr"); - Cls* obj = (Cls*) duk_require_pointer(ctx, -1); - duk_pop(ctx); // pop obj_ptr - - if (obj != NULL) { - delete obj; - - // for safety, set the pointer to undefined - duk_push_undefined(ctx); - duk_put_prop_string(ctx, 0, "\xFF" "obj_ptr"); - } - - return 0; - } - - template - static duk_ret_t call_native_deleter(duk_context* ctx) - { - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "obj_ptr"); - - if (!duk_is_pointer(ctx, -1)) { - duk_error(ctx, DUK_RET_REFERENCE_ERROR, "Object has already been invalidated; cannot delete."); - return DUK_RET_REFERENCE_ERROR; - } - - Cls* obj = static_cast(duk_require_pointer(ctx, -1)); - dukglue_invalidate_object(ctx, obj); - delete obj; - - duk_pop_2(ctx); - return 0; - } - } -} diff --git a/dep/duktape/dukglue/detail_function.h b/dep/duktape/dukglue/detail_function.h deleted file mode 100644 index 3d715884d35..00000000000 --- a/dep/duktape/dukglue/detail_function.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include "detail_stack.h" - -namespace dukglue -{ - namespace detail - { - // This struct can be used to generate a Duktape C function that - // pulls the argument values off the stack (with type checking), - // calls the appropriate function with them, and puts the function's - // return value (if any) onto the stack. - template - struct FuncInfoHolder - { - typedef RetType(*FuncType)(Ts...); - - template - struct FuncCompiletime - { - // The function to call is embedded into call_native_function at - // compile-time through template magic. - // Performance is so similar to run-time function calls that - // this is not recommended due to the ugly syntax it requires. - static duk_ret_t call_native_function(duk_context* ctx) - { - auto bakedArgs = dukglue::detail::get_stack_values(ctx); - actually_call(ctx, bakedArgs); - return std::is_void::value ? 0 : 1; - } - - private: - // this mess is to support functions with void return values - - template - static typename std::enable_if::value>::type actually_call(duk_context* ctx, const std::tuple& args) - { - // ArgStorage has some static_asserts in it that validate value types, - // so we typedef it to force ArgStorage to compile and run the asserts - typedef typename dukglue::types::ArgStorage::type ValidateReturnType; - - RetType return_val = dukglue::detail::apply_fp(funcToCall, args); - - using namespace dukglue::types; - DukType::type>::template push(ctx, std::move(return_val)); - } - - template - static typename std::enable_if::value>::type actually_call(duk_context* ctx, const std::tuple& args) - { - dukglue::detail::apply_fp(funcToCall, args); - } - }; - - struct FuncRuntime - { - // Pull the address of the function to call from the - // Duktape function object at run time. - static duk_ret_t call_native_function(duk_context* ctx) - { - duk_push_current_function(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "func_ptr"); - void* fp_void = duk_require_pointer(ctx, -1); - if (fp_void == NULL) { - duk_error(ctx, DUK_RET_TYPE_ERROR, "what even"); - return DUK_RET_TYPE_ERROR; - } - - duk_pop_2(ctx); - - static_assert(sizeof(RetType(*)(Ts...)) == sizeof(void*), "Function pointer and data pointer are different sizes"); - RetType(*funcToCall)(Ts...) = reinterpret_cast(fp_void); - - actually_call(ctx, funcToCall, dukglue::detail::get_stack_values(ctx)); - return std::is_void::value ? 0 : 1; - } - - // this mess is to support functions with void return values - template - static typename std::enable_if::value>::type actually_call(duk_context* ctx, RetType(*funcToCall)(Ts...), const std::tuple& args) - { - // ArgStorage has some static_asserts in it that validate value types, - // so we typedef it to force ArgStorage to compile and run the asserts - typedef typename dukglue::types::ArgStorage::type ValidateReturnType; - - RetType return_val = dukglue::detail::apply_fp(funcToCall, args); - - using namespace dukglue::types; - DukType::type>::template push(ctx, std::move(return_val)); - } - - template - static typename std::enable_if::value>::type actually_call(duk_context* ctx, RetType(*funcToCall)(Ts...), const std::tuple& args) - { - dukglue::detail::apply_fp(funcToCall, args); - } - }; - }; - } -} diff --git a/dep/duktape/dukglue/detail_method.h b/dep/duktape/dukglue/detail_method.h deleted file mode 100644 index d3e929034d2..00000000000 --- a/dep/duktape/dukglue/detail_method.h +++ /dev/null @@ -1,183 +0,0 @@ -#pragma once - -#include "detail_stack.h" - -namespace dukglue -{ - namespace detail - { - template - struct MethodInfo - { - typedef typename std::conditional::type MethodType; - - // The size of a method pointer is not guaranteed to be the same size as a function pointer. - // This means we can't just use duk_push_pointer(ctx, &MyClass::method) to store the method at run time. - // To get around this, we wrap the method pointer in a MethodHolder (on the heap), and push a pointer to - // that. The MethodHolder is cleaned up by the finalizer. - struct MethodHolder - { - MethodType method; - }; - - template - struct MethodCompiletime - { - static duk_ret_t call_native_method(duk_context* ctx) - { - // get this.obj_ptr - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "obj_ptr"); - void* obj_void = duk_require_pointer(ctx, -1); - if (obj_void == nullptr) { - duk_error(ctx, DUK_RET_REFERENCE_ERROR, "Native object missing."); - return DUK_RET_REFERENCE_ERROR; - } - - duk_pop_2(ctx); - - // (should always be valid unless someone is intentionally messing with this.obj_ptr...) - Cls* obj = static_cast(obj_void); - - // read arguments and call function - auto bakedArgs = dukglue::detail::get_stack_values(ctx); - actually_call(ctx, obj, bakedArgs); - return std::is_void::value ? 0 : 1; - } - - // this mess is to support functions with void return values - template - static typename std::enable_if::value>::type actually_call(duk_context* ctx, Cls* obj, const std::tuple& args) - { - // ArgStorage has some static_asserts in it that validate value types, - // so we typedef it to force ArgStorage to compile and run the asserts - typedef typename dukglue::types::ArgStorage::type ValidateReturnType; - - RetType return_val = dukglue::detail::apply_method(methodToCall, obj, args); - - using namespace dukglue::types; - DukType::type>::template push(ctx, std::move(return_val)); - } - - template - static typename std::enable_if::value>::type actually_call(duk_context* ctx, Cls* obj, const std::tuple& args) - { - dukglue::detail::apply_method(methodToCall, obj, args); - } - }; - - - struct MethodRuntime - { - static duk_ret_t finalize_method(duk_context* ctx) - { - // clean up the MethodHolder reference - duk_get_prop_string(ctx, 0, "\xFF" "method_holder"); - - void* method_holder_void = duk_require_pointer(ctx, -1); - MethodHolder* method_holder = static_cast(method_holder_void); - delete method_holder; - - return 0; - } - - static duk_ret_t call_native_method(duk_context* ctx) - { - // get this.obj_ptr - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "obj_ptr"); - void* obj_void = duk_get_pointer(ctx, -1); - if (obj_void == nullptr) { - duk_error(ctx, DUK_RET_REFERENCE_ERROR, "Invalid native object for 'this'"); - return DUK_RET_REFERENCE_ERROR; - } - - duk_pop_2(ctx); // pop this.obj_ptr and this - - // get current_function.method_info - duk_push_current_function(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "method_holder"); - void* method_holder_void = duk_require_pointer(ctx, -1); - if (method_holder_void == nullptr) { - duk_error(ctx, DUK_RET_TYPE_ERROR, "Method pointer missing?!"); - return DUK_RET_TYPE_ERROR; - } - - duk_pop_2(ctx); - - // (should always be valid unless someone is intentionally messing with this.obj_ptr...) - Cls* obj = static_cast(obj_void); - MethodHolder* method_holder = static_cast(method_holder_void); - - // read arguments and call method - auto bakedArgs = dukglue::detail::get_stack_values(ctx); - actually_call(ctx, method_holder->method, obj, bakedArgs); - return std::is_void::value ? 0 : 1; - } - - // this mess is to support functions with void return values - template - static typename std::enable_if::value>::type actually_call(duk_context* ctx, MethodType method, Cls* obj, const std::tuple& args) - { - // ArgStorage has some static_asserts in it that validate value types, - // so we typedef it to force ArgStorage to compile and run the asserts - typedef typename dukglue::types::ArgStorage::type ValidateReturnType; - - RetType return_val = dukglue::detail::apply_method(method, obj, args); - - using namespace dukglue::types; - DukType::type>::template push(ctx, std::move(return_val)); - } - - template - static typename std::enable_if::value>::type actually_call(duk_context* ctx, MethodType method, Cls* obj, const std::tuple& args) - { - dukglue::detail::apply_method(method, obj, args); - } - }; - }; - - template - struct MethodVariadicRuntime - { - typedef MethodInfo MethodInfoVariadic; - typedef typename MethodInfoVariadic::MethodHolder MethodHolderVariadic; - - static duk_ret_t finalize_method(duk_context* ctx) - { - return MethodInfoVariadic::MethodRuntime::finalize_method(ctx); - } - - static duk_ret_t call_native_method(duk_context* ctx) - { - // get this.obj_ptr - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "obj_ptr"); - void* obj_void = duk_get_pointer(ctx, -1); - if (obj_void == nullptr) { - duk_error(ctx, DUK_RET_REFERENCE_ERROR, "Invalid native object for 'this'"); - return DUK_RET_REFERENCE_ERROR; - } - - duk_pop_2(ctx); // pop this.obj_ptr and this - - // get current_function.method_info - duk_push_current_function(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "method_holder"); - void* method_holder_void = duk_require_pointer(ctx, -1); - if (method_holder_void == nullptr) { - duk_error(ctx, DUK_RET_TYPE_ERROR, "Method pointer missing?!"); - return DUK_RET_TYPE_ERROR; - } - - duk_pop_2(ctx); - - // (should always be valid unless someone is intentionally messing with this.obj_ptr...) - Cls* obj = static_cast(obj_void); - MethodHolderVariadic* method_holder = static_cast(method_holder_void); - - return (*obj.*method_holder->method)(ctx); - } - }; - } -} diff --git a/dep/duktape/dukglue/detail_primitive_types.h b/dep/duktape/dukglue/detail_primitive_types.h deleted file mode 100644 index ebba1ad80a0..00000000000 --- a/dep/duktape/dukglue/detail_primitive_types.h +++ /dev/null @@ -1,252 +0,0 @@ -#pragma once - -#include "detail_types.h" -#include "detail_typeinfo.h" -#include "dukvalue.h" - -#include -#include -#include // for std::shared_ptr - -namespace dukglue { - namespace types { - -#define DUKGLUE_SIMPLE_VALUE_TYPE(TYPE, DUK_IS_FUNC, DUK_GET_FUNC, DUK_PUSH_FUNC, PUSH_VALUE) \ - template<> \ - struct DukType { \ - typedef std::true_type IsValueType; \ - \ - template \ - static TYPE read(duk_context* ctx, duk_idx_t arg_idx) { \ - if (DUK_IS_FUNC(ctx, arg_idx)) { \ - return static_cast(DUK_GET_FUNC(ctx, arg_idx)); \ - } else { \ - duk_int_t type_idx = duk_get_type(ctx, arg_idx); \ - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: expected " #TYPE ", got %s", arg_idx, detail::get_type_name(type_idx)); \ - } \ - } \ - \ - template \ - static void push(duk_context* ctx, TYPE value) { \ - DUK_PUSH_FUNC(ctx, PUSH_VALUE); \ - } \ - }; - - DUKGLUE_SIMPLE_VALUE_TYPE(bool, duk_is_boolean, 0 != duk_get_boolean, duk_push_boolean, value) - - DUKGLUE_SIMPLE_VALUE_TYPE(uint8_t, duk_is_number, duk_get_uint, duk_push_uint, value) - DUKGLUE_SIMPLE_VALUE_TYPE(uint16_t, duk_is_number, duk_get_uint, duk_push_uint, value) - DUKGLUE_SIMPLE_VALUE_TYPE(uint32_t, duk_is_number, duk_get_uint, duk_push_uint, value) - DUKGLUE_SIMPLE_VALUE_TYPE(uint64_t, duk_is_number, duk_get_number, duk_push_number, value) // have to cast to double - - DUKGLUE_SIMPLE_VALUE_TYPE(int8_t, duk_is_number, duk_get_int, duk_push_int, value) - DUKGLUE_SIMPLE_VALUE_TYPE(int16_t, duk_is_number, duk_get_int, duk_push_int, value) - DUKGLUE_SIMPLE_VALUE_TYPE(int32_t, duk_is_number, duk_get_int, duk_push_int, value) - DUKGLUE_SIMPLE_VALUE_TYPE(int64_t, duk_is_number, duk_get_number, duk_push_number, value) // have to cast to double - - // signed char and unsigned char are surprisingly *both* different from char, at least in MSVC - DUKGLUE_SIMPLE_VALUE_TYPE(char, duk_is_number, duk_get_int, duk_push_int, value) - - DUKGLUE_SIMPLE_VALUE_TYPE(float, duk_is_number, duk_get_number, duk_push_number, value) - DUKGLUE_SIMPLE_VALUE_TYPE(double, duk_is_number, duk_get_number, duk_push_number, value) - - DUKGLUE_SIMPLE_VALUE_TYPE(std::string, duk_is_string, duk_get_string, duk_push_string, value.c_str()) - - // We have to do some magic for const char* to work correctly. - // We override the "bare type" and "storage type" to both be const char*. - // char* is a bit tricky because its "bare type" should still be const char*, to differentiate it from just char - template<> - struct Bare { - typedef const char* type; - }; - template<> - struct Bare { - typedef const char* type; - }; - - // the storage type should also be const char* - if we don't do this, it will end up as just "char" - template<> - struct ArgStorage { - typedef const char* type; - }; - - template<> - struct DukType { - typedef std::true_type IsValueType; - - template - static const char* read(duk_context* ctx, duk_idx_t arg_idx) { - if (duk_is_string(ctx, arg_idx)) { - return duk_get_string(ctx, arg_idx); - } else { - duk_int_t type_idx = duk_get_type(ctx, arg_idx); - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: expected string, got %s", arg_idx, detail::get_type_name(type_idx)); - } - } - - template - static void push(duk_context* ctx, const char* value) { - duk_push_string(ctx, value); - } - }; - - // DukValue - template<> - struct DukType { - typedef std::true_type IsValueType; - - template - static DukValue read(duk_context* ctx, duk_idx_t arg_idx) { - try { - return DukValue::copy_from_stack(ctx, arg_idx); - } catch (DukException& e) { - // only DukException can be thrown by DukValue::copy_from_stack - duk_error(ctx, DUK_ERR_ERROR, e.what()); - } - } - - template - static void push(duk_context* ctx, const DukValue& value) { - if (value.context() == NULL) { - duk_error(ctx, DUK_ERR_ERROR, "DukValue is uninitialized"); - return; - } - - if (value.context() != ctx) { - duk_error(ctx, DUK_ERR_ERROR, "DukValue comes from a different context"); - return; - } - - try { - value.push(); - } catch (DukException& e) { - // only DukException can be thrown by DukValue::copy_from_stack - duk_error(ctx, DUK_ERR_ERROR, e.what()); - } - } - }; - - // std::vector (as value) - template - struct DukType< std::vector > { - typedef std::true_type IsValueType; - - template - static std::vector read(duk_context* ctx, duk_idx_t arg_idx) { - if (!duk_is_array(ctx, arg_idx)) { - duk_int_t type_idx = duk_get_type(ctx, arg_idx); - duk_error(ctx, DUK_ERR_TYPE_ERROR, "Argument %d: expected array, got %s", arg_idx, detail::get_type_name(type_idx)); - } - - duk_size_t len = duk_get_length(ctx, arg_idx); - const duk_idx_t elem_idx = duk_get_top(ctx); - - std::vector vec; - vec.reserve(len); - for (duk_size_t i = 0; i < len; i++) { - duk_get_prop_index(ctx, arg_idx, i); - vec.push_back(DukType< typename Bare::type >::template read(ctx, elem_idx)); - duk_pop(ctx); - } - return vec; - } - - template - static void push(duk_context* ctx, const std::vector& value) { - duk_idx_t obj_idx = duk_push_array(ctx); - - for (size_t i = 0; i < value.size(); i++) { - DukType< typename Bare::type >::template push(ctx, value[i]); - duk_put_prop_index(ctx, obj_idx, i); - } - } - }; - - // std::shared_ptr (as value) - template - struct DukType< std::shared_ptr > { - typedef std::true_type IsValueType; - - static_assert(std::is_same::IsValueType, std::false_type>::value, "Dukglue can only use std::shared_ptr to non-value types!"); - - template - static std::shared_ptr read(duk_context* ctx, duk_idx_t arg_idx) { - if (duk_is_null(ctx, arg_idx)) - return nullptr; - - if (!duk_is_object(ctx, arg_idx)) { - duk_int_t type_idx = duk_get_type(ctx, arg_idx); - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: expected shared_ptr object, got ", arg_idx, detail::get_type_name(type_idx)); - } - - duk_get_prop_string(ctx, arg_idx, "\xFF" "type_info"); - if (!duk_is_pointer(ctx, -1)) // missing type_info, must not be a native object - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: expected shared_ptr object (missing type_info)", arg_idx); - - // make sure this object can be safely returned as a T* - dukglue::detail::TypeInfo* info = static_cast(duk_get_pointer(ctx, -1)); - if (!info->can_cast()) - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: wrong type of shared_ptr object", arg_idx); - duk_pop(ctx); // pop type_info - - duk_get_prop_string(ctx, arg_idx, "\xFF" "shared_ptr"); - if (!duk_is_pointer(ctx, -1)) - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: not a shared_ptr object (missing shared_ptr)", arg_idx); - void* ptr = duk_get_pointer(ctx, -1); - duk_pop(ctx); // pop pointer to shared_ptr - - return *((std::shared_ptr*) ptr); - } - - static duk_ret_t shared_ptr_finalizer(duk_context* ctx) - { - duk_get_prop_string(ctx, 0, "\xFF" "shared_ptr"); - std::shared_ptr* ptr = (std::shared_ptr*) duk_require_pointer(ctx, -1); - duk_pop(ctx); // pop shared_ptr ptr - - if (ptr != NULL) { - delete ptr; - - // for safety, set the pointer to undefined - // (finalizers can run multiple times) - duk_push_undefined(ctx); - duk_put_prop_string(ctx, 0, "\xFF" "shared_ptr"); - } - - return 0; - } - - template - static void push(duk_context* ctx, const std::shared_ptr& value) { - dukglue::detail::ProtoManager::make_script_object(ctx, value.get()); - - // create + set shared_ptr - duk_push_pointer(ctx, new std::shared_ptr(value)); - duk_put_prop_string(ctx, -2, "\xFF" "shared_ptr"); - - // set shared_ptr finalizer - duk_push_c_function(ctx, &shared_ptr_finalizer, 1); - duk_set_finalizer(ctx, -2); - } - }; - - // std::function - /*template - struct DukType< std::function > { - typedef std::true_type IsValueType; - - template - static std::function read(duk_context* ctx, duk_idx_t arg_idx) { - DukValue callable = DukValue::copy_from_stack(ctx, -1, DUK_TYPE_MASK_OBJECT); - return [ctx, callable] (ArgTs... args) -> RetT { - dukglue_call(ctx, callable, args...); - }; - } - - template - static void push(duk_context* ctx, std::function value) { - static_assert(false, "Pushing an std::function has not been implemented yet. Sorry!"); - } - };*/ - } -} diff --git a/dep/duktape/dukglue/detail_refs.h b/dep/duktape/dukglue/detail_refs.h deleted file mode 100644 index 5dc808a62a3..00000000000 --- a/dep/duktape/dukglue/detail_refs.h +++ /dev/null @@ -1,199 +0,0 @@ -#pragma once - -#include - -#include - -namespace dukglue -{ - namespace detail - { - // This class handles keeping a map of void* -> script object. - // It also prevents script objects from being GC'd until someone - // explicitly frees the underlying native object. - - // Implemented by keeping an array of script objects in the heap stash. - // An std::unordered_map maps pointer -> array index. - // Thanks to std::unordered_map, lookup time is O(1) on average. - - // Using std::unordered_map has some memory overhead (~32 bytes per object), - // which could be removed by using a different data structure: - - // 1. Use no data structure. Blindly scan through the reference registry, - // checking \xFFobj_ptr on every object until you find yours. - // Performance when returning native objects from functions when a lot - // of native objects are registered will suffer. - - // 2. Implement a self-balancing binary tree on top of a Duktape array - // for the registry. Still fast - O(log(N)) - and no memory overhead. - - // 3. A sorted list would work too, though insertion speed might be worse - // than a binary tree. - - struct RefManager - { - public: - - // Find the script object corresponding to obj_ptr and push it. - // Returns true if successful, false if obj_ptr has not been registered. - // Stack: ... -> ... (if object has been registered before) - // ... -> ... [object] (if object has not been registered) - static bool find_and_push_native_object(duk_context* ctx, void* obj_ptr) - { - RefMap* ref_map = get_ref_map(ctx); - - const auto it = ref_map->find(obj_ptr); - - if (it == ref_map->end()) { - return false; - } else { - push_ref_array(ctx); - duk_get_prop_index(ctx, -1, it->second); - duk_remove(ctx, -2); - return true; - } - } - - // Takes a script object and adds it to the registry, associating - // it with obj_ptr. unregistered_object is not modified. - // If obj_ptr has already been registered with another object, - // the old registry entry will be overidden. - // Does nothing if obj_ptr is NULL. - // Stack: ... [object] -> ... [object] - static void register_native_object(duk_context* ctx, void* obj_ptr) - { - if (obj_ptr == NULL) - return; - - RefMap* ref_map = get_ref_map(ctx); - - push_ref_array(ctx); - - // find next free index - // free indices are kept in a linked list, starting at ref_array[0] - duk_get_prop_index(ctx, -1, 0); - duk_uarridx_t next_free_idx = duk_get_uint(ctx, -1); - duk_pop(ctx); - - if (next_free_idx == 0) { - // no free spots in the array, make a new one at arr.length - next_free_idx = duk_get_length(ctx, -1); - } else { - // free spot found, need to remove it from the free list - // ref_array[0] = ref_array[next_free_idx] - duk_get_prop_index(ctx, -1, next_free_idx); - duk_put_prop_index(ctx, -2, 0); - } - - // std::cout << "putting reference at ref_array[" << next_free_idx << "]" << std::endl; - (*ref_map)[obj_ptr] = next_free_idx; - - duk_dup(ctx, -2); // put object on top - - // ... [object] [ref_array] [object] - duk_put_prop_index(ctx, -2, next_free_idx); - - duk_pop(ctx); // pop ref_array - } - - // Remove the object associated with obj_ptr from the registry - // and invalidate the object's internal native pointer (by setting it to undefined). - // Does nothing if obj_ptr if object was never registered or obj_ptr is NULL. - // Does not affect the stack. - static void find_and_invalidate_native_object(duk_context* ctx, void* obj_ptr) - { - if (obj_ptr == NULL) - return; - - RefMap* ref_map = get_ref_map(ctx); - auto it = ref_map->find(obj_ptr); - if (it == ref_map->end()) // was never registered - return; - - push_ref_array(ctx); - duk_get_prop_index(ctx, -1, it->second); - - // invalidate internal pointer - duk_push_undefined(ctx); - duk_put_prop_string(ctx, -2, "\xFF" "obj_ptr"); - duk_pop(ctx); // pop object - - // remove from references array and add the space it was in to free list - // (refs[0] -> tail) -> (refs[0] -> old_obj_idx -> tail) - - // refs[old_obj_idx] = refs[0] - duk_get_prop_index(ctx, -1, 0); - duk_put_prop_index(ctx, -2, it->second); - - // refs[0] = old_obj_idx - duk_push_uint(ctx, it->second); - duk_put_prop_index(ctx, -2, 0); - - duk_pop(ctx); // pop ref_array - - // also remove from map - // std::cout << "Freeing ref_array[" << it->second << "]" << std::endl; - ref_map->erase(it); - } - - private: - typedef std::unordered_map RefMap; - - static RefMap* get_ref_map(duk_context* ctx) - { - static const char* DUKGLUE_REF_MAP = "dukglue_ref_map"; - static const char* PTR = "ptr"; - - duk_push_heap_stash(ctx); - - if (!duk_has_prop_string(ctx, -1, DUKGLUE_REF_MAP)) { - // doesn't exist yet, need to create it - duk_push_object(ctx); - - duk_push_pointer(ctx, new RefMap()); - duk_put_prop_string(ctx, -2, PTR); - - duk_push_c_function(ctx, ref_map_finalizer, 1); - duk_set_finalizer(ctx, -2); - - duk_put_prop_string(ctx, -2, DUKGLUE_REF_MAP); - } - - duk_get_prop_string(ctx, -1, DUKGLUE_REF_MAP); - duk_get_prop_string(ctx, -1, PTR); - RefMap* map = static_cast(duk_require_pointer(ctx, -1)); - duk_pop_3(ctx); - - return map; - } - - static duk_ret_t ref_map_finalizer(duk_context* ctx) - { - duk_get_prop_string(ctx, 0, "ptr"); - RefMap* map = static_cast(duk_require_pointer(ctx, -1)); - delete map; - - return 0; - } - - static void push_ref_array(duk_context* ctx) - { - static const char* DUKGLUE_REF_ARRAY = "dukglue_ref_array"; - duk_push_heap_stash(ctx); - - if (!duk_has_prop_string(ctx, -1, DUKGLUE_REF_ARRAY)) { - duk_push_array(ctx); - - // ref_array[0] = 0 (initialize free list as empty) - duk_push_int(ctx, 0); - duk_put_prop_index(ctx, -2, 0); - - duk_put_prop_string(ctx, -2, DUKGLUE_REF_ARRAY); - } - - duk_get_prop_string(ctx, -1, DUKGLUE_REF_ARRAY); - duk_remove(ctx, -2); // pop heap stash - } - }; - } -} diff --git a/dep/duktape/dukglue/detail_stack.h b/dep/duktape/dukglue/detail_stack.h deleted file mode 100644 index efd5e9ebc5e..00000000000 --- a/dep/duktape/dukglue/detail_stack.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include "detail_traits.h" -#include "detail_types.h" - -#include - -namespace dukglue -{ - namespace detail - { - // Helper to get the argument tuple type, with correct storage types. - template - struct ArgsTuple { - typedef std::tuple::type...> type; - }; - - // Helper to get argument indices. - // Call read for every Ts[i], for matching argument index Index[i]. - // The traits::index_tuple is used for type inference. - // A concrete example: - // get_values(duktape_context) - // get_values_helper<{int, bool}, {0, 1}>(ctx, ignored) - // std::make_tuple(read(ctx, 0), read(ctx, 1)) - template - typename ArgsTuple::type get_stack_values_helper(duk_context* ctx, dukglue::detail::index_tuple) - { - using namespace dukglue::types; - return std::forward_as_tuple(DukType::type>::template read::type>(ctx, Indexes)...); - } - - // Returns an std::tuple of the values asked for in the template parameters. - // Values will remain on the stack. - // Values are indexed from the bottom of the stack up (0, 1, ...). - // If a value does not exist or does not have the expected type, an error is thrown - // through Duktape (with duk_error(...)), and the function does not return - template - typename ArgsTuple::type get_stack_values(duk_context* ctx) - { - // We need the argument indices for read_value, and we need to be able - // to unpack them as a template argument to match Ts. - // So, we use traits::make_indexes, which returns a traits::index_tuple<0, 1, 2, ...> object. - // We pass that into a helper function so we can put a name to that <0, 1, ...> template argument. - // Here, the type of Args isn't important, the length of it is. - auto indices = typename dukglue::detail::make_indexes::type(); - return get_stack_values_helper(ctx, indices); - } - } -} diff --git a/dep/duktape/dukglue/detail_traits.h b/dep/duktape/dukglue/detail_traits.h deleted file mode 100644 index 247e2e52bf7..00000000000 --- a/dep/duktape/dukglue/detail_traits.h +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -#include - -namespace dukglue -{ - namespace detail - { - ////////////////////////////////////////////////////////////////////////////////////////////// - - // Credit to LuaState for this code: - // https://github.com/AdUki/LuaState/blob/master/include/Traits.h - - template struct index_tuple {}; - - template - struct make_indexes_impl; - - template - struct make_indexes_impl, T, Types...> - { - typedef typename make_indexes_impl, Types...>::type type; - }; - - template - struct make_indexes_impl > - { - typedef index_tuple type; - }; - - template - struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...> - {}; - - ////////////////////////////////////////////////////////////////////////////////////////////// - - template - struct indexes {}; - - template - struct indexes_builder : indexes_builder {}; - - template - struct indexes_builder<0, Is...> { - typedef indexes index; - }; - - ////////////////////////////////////////////////////////////////////////////////////////////// - - // This mess is used to use function arugments stored in an std::tuple to an - // std::function, function pointer, or method. - - // std::function - template - Ret apply_helper(std::function pf, index_tuple< Indexes... >, std::tuple&& tup) - { - return pf(std::forward(std::get(tup))...); - } - - template - Ret apply(std::function pf, const std::tuple& tup) - { - return apply_helper(pf, typename make_indexes::type(), std::tuple(tup)); - } - - // function pointer - template - Ret apply_fp_helper(Ret(*pf)(Args...), index_tuple< Indexes... >, std::tuple&& tup) - { - return pf(std::forward(std::get(tup))...); - } - - template - Ret apply_fp(Ret(*pf)(Args...), const std::tuple& tup) - { - return apply_fp_helper(pf, typename make_indexes::type(), std::tuple(tup)); - } - - // method pointer - template - Ret apply_method_helper(Ret(Cls::*pf)(Args...), index_tuple< Indexes... >, Cls* obj, std::tuple&& tup) - { - return (*obj.*pf)(std::forward(std::get(tup))...); - } - - template - Ret apply_method(Ret(Cls::*pf)(Args...), Cls* obj, const std::tuple& tup) - { - return apply_method_helper(pf, typename make_indexes::type(), obj, std::tuple(tup)); - } - - // const method pointer - template - Ret apply_method_helper(Ret(Cls::*pf)(Args...) const, index_tuple< Indexes... >, Cls* obj, std::tuple&& tup) - { - return (*obj.*pf)(std::forward(std::get(tup))...); - } - - template - Ret apply_method(Ret(Cls::*pf)(Args...) const, Cls* obj, const std::tuple& tup) - { - return apply_method_helper(pf, typename make_indexes::type(), obj, std::tuple(tup)); - } - - // constructor - template - Cls* apply_constructor_helper(index_tuple< Indexes... >, std::tuple&& tup) - { - return new Cls(std::forward(std::get(tup))...); - } - - template - Cls* apply_constructor(const std::tuple& tup) - { - return apply_constructor_helper(typename make_indexes::type(), std::tuple(tup)); - } - - ////////////////////////////////////////////////////////////////////////////////////////////// - - - } -} \ No newline at end of file diff --git a/dep/duktape/dukglue/detail_typeinfo.h b/dep/duktape/dukglue/detail_typeinfo.h deleted file mode 100644 index 5626c64c5ae..00000000000 --- a/dep/duktape/dukglue/detail_typeinfo.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include - -namespace dukglue -{ - namespace detail - { - // same as duk_get_type_name, which is private for some reason *shakes fist* - static const char* get_type_name(duk_int_t type_idx) { - static const char* names[] = { - "none", - "undefined", - "null", - "boolean", - "number", - "string", - "object", - "buffer", - "pointer", - "lightfunc" - }; - - if (type_idx >= 0 && type_idx < sizeof(names) / sizeof(names[0])) - return names[type_idx]; - else - return "unknown"; - } - - class TypeInfo - { - public: - TypeInfo(std::type_index&& idx) : index_(idx), base_(nullptr) {} - TypeInfo(const TypeInfo& rhs) : index_(rhs.index_), base_(rhs.base_) {} - - inline void set_base(TypeInfo* base) { - base_ = base; - } - - template - bool can_cast() const { - if (index_ == typeid(T)) - return true; - - if (base_) - return base_->can_cast(); - - return false; - } - - inline bool operator<(const TypeInfo& rhs) const { return index_ < rhs.index_; } - inline bool operator<=(const TypeInfo& rhs) const { return index_ <= rhs.index_; } - inline bool operator>(const TypeInfo& rhs) const { return index_ > rhs.index_; } - inline bool operator>=(const TypeInfo& rhs) const { return index_ >= rhs.index_; } - inline bool operator==(const TypeInfo& rhs) const { return index_ == rhs.index_; } - inline bool operator!=(const TypeInfo& rhs) const { return index_ != rhs.index_; } - - private: - std::type_index index_; - TypeInfo* base_; - }; - } -} diff --git a/dep/duktape/dukglue/detail_types.h b/dep/duktape/dukglue/detail_types.h deleted file mode 100644 index de86afe4147..00000000000 --- a/dep/duktape/dukglue/detail_types.h +++ /dev/null @@ -1,160 +0,0 @@ -#pragma once - -#include - -#include "detail_refs.h" -#include "detail_typeinfo.h" -#include "detail_class_proto.h" - -// TODO try adding a using namespace std in here if I can scope it to just this file - -namespace dukglue { - namespace types { - - // Bare::type is T stripped of reference, pointer, and const off a type, like so: - // Bare::type = Dog - // Bare::type = Dog - // Bare::type = Dog - // Bare::type = Dog - // Bare::type = Dog - // Bare::type = Dog - template - struct Bare { - typedef typename std::remove_const::type>::type>::type type; - }; - - // DukType provides functions for reading and writing T from the Duktape stack. - // T is always a "bare type," i.e. "Dog" rather than "Dog*". - - // There are two kinds of DukTypes: - // 1. "Native" DukTypes. This is the default. - // These types use an underlying native object allocated on the heap. - // A pointer to the object (of type T*) is expected at script_object.\xFFobj_ptr. - // "Native" DukTypes can return a value (returns a copy-constructed T from the native object), - // a pointer (just returns script_object.\xFFobj_ptr), or a reference (dereferences script_object.\xFFobj_ptr if it is not null). - - // 2. "Value" DukTypes. These are implemented through template specialization. - // This is how primitive types are implemented (int, float, const char*). - // These types can only be returned by value (T) or by const reference (const T&). - // Attempting to read a pointer (T*) or non-const reference (T&) will give a compile-time error. - // You can also use this to implement your own lightweight types, such as a 3D vector. - // (Strictly speaking, non-const references (T&) *could* be returned, but any changes to the reference would - // be discarded. So, I wrote a static assert to disable the option. If you understand the implications, - // you should be able to safely comment out the static_assert in ArgStorage.) - template - struct DukType { - static_assert(std::is_same::type >::value, "Invalid base type, expected bare type"); - - typedef std::false_type IsValueType; - - // read pointer - template::value>::type > - static T* read(duk_context* ctx, duk_idx_t arg_idx) { - using namespace dukglue::detail; - - if (duk_is_null(ctx, arg_idx)) - return nullptr; - - if (!duk_is_object(ctx, arg_idx)) { - duk_int_t type_idx = duk_get_type(ctx, arg_idx); - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: expected native object, got %s", arg_idx, get_type_name(type_idx)); - } - - duk_get_prop_string(ctx, arg_idx, "\xFF" "type_info"); - if (!duk_is_pointer(ctx, -1)) // missing type_info, must not be a native object - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: expected native object (missing type_info)", arg_idx); - - // make sure this object can be safely returned as a T* - TypeInfo* info = static_cast(duk_get_pointer(ctx, -1)); - if (!info->can_cast()) - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: wrong type of native object", arg_idx); - - duk_pop(ctx); // pop type_info - - duk_get_prop_string(ctx, arg_idx, "\xFF" "obj_ptr"); - if (!duk_is_pointer(ctx, -1)) - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: invalid native object.", arg_idx); - - T* obj = static_cast(duk_get_pointer(ctx, -1)); - - duk_pop(ctx); // pop obj_ptr - - return obj; - } - - // read reference - template::value>::type > - static T& read(duk_context* ctx, duk_idx_t arg_idx) { - T* obj = read(ctx, arg_idx); - if (obj == nullptr) - duk_error(ctx, DUK_RET_TYPE_ERROR, "Argument %d: cannot be null (native function expects reference)", arg_idx); - - return *obj; - } - - // read value - // commented out because it breaks for abstract classes - /*template::type >::value>::type > - static T read(duk_context* ctx, duk_idx_t arg_idx) { - static_assert(std::is_copy_constructible::value, "Reading a value requires a copy-constructable type"); - const T& obj = read(ctx, arg_idx); - return T(obj); - }*/ - - // ----------------------------------------------------- - // Writing - - // Reference - template::value>::type > - static void push(duk_context* ctx, T& value) { - using namespace dukglue::detail; - - if (!RefManager::find_and_push_native_object(ctx, &value)) { - // need to create new script object - ProtoManager::make_script_object(ctx, &value); - RefManager::register_native_object(ctx, &value); - } - } - - // Pointer - template::value>::type > - static void push(duk_context* ctx, T* value) { - if (value == nullptr) - duk_push_null(ctx); - else - push(ctx, *value); - } - - // Value (create new instance on the heap) - // commented out because this is an easy way to accidentally cause a memory leak - /*template::type >::value>::type > - static void push(duk_context* ctx, T value) { - static_assert(std::is_copy_constructible::value, "Cannot push value for non-copy-constructable type."); - return push(ctx, new T(value)); - }*/ - }; - - // Figure out what the type for an argument should be inside the tuple. - // If a function expects a reference to a value type, we need temporary storage for the value. - // For example, a reference to a value type (const int&) will need to be temporarily - // stored in the tuple, so ArgStorage::type == int. - // Native objects are already allocated on the heap, so there's no problem storing, say, const Dog& in the tuple. - template - struct ArgStorage { - private: - typedef typename Bare::type BareType; - //typedef DukType ThisDukType; - typedef typename DukType::IsValueType IsValueType; - - static_assert(!IsValueType::value || !std::is_pointer::value, "Cannot return pointer to value type."); - static_assert(!IsValueType::value || - (!std::is_reference::value || std::is_const::type>::value), - "Value types can only be returned as const references."); - - public: - typedef typename std::conditional::type type; - }; - } -} - -#include "detail_primitive_types.h" diff --git a/dep/duktape/dukglue/dukexception.h b/dep/duktape/dukglue/dukexception.h deleted file mode 100644 index 7d42768ebea..00000000000 --- a/dep/duktape/dukglue/dukexception.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include -#include - -class DukException : public std::exception -{ -public: - virtual const char* what() const noexcept override - { - return mMsg.c_str(); - } - - template - DukException& operator<<(T rhs) - { - std::stringstream ss; - ss << mMsg << rhs; - mMsg = ss.str(); - return *this; - } - -protected: - std::string mMsg; -}; - -class DukErrorException : public DukException -{ -public: - DukErrorException(duk_context* ctx, int return_code, bool pop_error = true) { - if (return_code != 0) { - duk_get_prop_string(ctx, -1, "stack"); - mMsg = duk_safe_to_string(ctx, -1); - duk_pop(ctx); - - if (pop_error) - duk_pop(ctx); - } - } -}; \ No newline at end of file diff --git a/dep/duktape/dukglue/dukglue.h b/dep/duktape/dukglue/dukglue.h deleted file mode 100644 index 1b62f7b9d4e..00000000000 --- a/dep/duktape/dukglue/dukglue.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "register_function.h" -#include "register_class.h" -#include "register_property.h" -#include "public_util.h" -#include "dukvalue.h" \ No newline at end of file diff --git a/dep/duktape/dukglue/dukvalue.h b/dep/duktape/dukglue/dukvalue.h deleted file mode 100644 index 2a3f6fc9385..00000000000 --- a/dep/duktape/dukglue/dukvalue.h +++ /dev/null @@ -1,590 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "dukexception.h" - -// A variant class for Duktape values. -// This class is not really dependant on the rest of dukglue, but the rest of dukglue is integrated to support it. -// Script objects are persisted by copying a reference to the object into an array in the heap stash. -// When we need to push a reference to the object, we just look up that reference in the stash. - -// DukValues can be copied freely. We use reference counting behind the scenes to keep track of when we need -// to remove our reference from the heap stash. Memory for reference counting is only allocated once a DukValue -// is copied (either by copy constructor or operator=). std::move can be used if you are trying to avoid ref counting -// for some reason. - -// One script object can have multiple, completely separate DukValues "pointing" to it - in this case, there will be -// multiple entries in the "ref array" that point to the same object. This will happen if the same script object is -// put on the stack and turned into a DukValue multiple times independently (copy-constructing/operator=-ing -// DukValues will not do this!). This is okay, as we are only keeping track of these objects to prevent garbage -// collection (and access them later). This could be changed to use a map structure to look up one canonical entry per -// script object in the "ref array" (I guess it would be more like a ref map in this case), but this would require a map -// lookup every time we construct a DukValue. The performance difference probably isn't *that* noticeable (a good map -// would probably be amortized constant-time lookup), but I am guessing constructing many separate DukValues that point -// to the same script object isn't a very common thing. -class DukValue { -public: - enum Type : uint8_t { - //NONE = DUK_TYPE_NONE, - UNDEFINED = DUK_TYPE_UNDEFINED, - NULLREF = DUK_TYPE_NULL, - BOOLEAN = DUK_TYPE_BOOLEAN, - NUMBER = DUK_TYPE_NUMBER, - STRING = DUK_TYPE_STRING, - OBJECT = DUK_TYPE_OBJECT, - BUFFER = DUK_TYPE_BUFFER, // not implemented - POINTER = DUK_TYPE_POINTER, - LIGHTFUNC = DUK_TYPE_LIGHTFUNC // not implemented - }; - - // default constructor just makes an undefined-type DukValue - inline DukValue() : mContext(NULL), mType(UNDEFINED), mRefCount(NULL) {} - - virtual ~DukValue() { - // release any references we have - release_ref_count(); - } - - // move constructor - inline DukValue(DukValue&& move) { - mContext = move.mContext; - mType = move.mType; - mPOD = move.mPOD; - mRefCount = move.mRefCount; - - if (mType == STRING) - mString = std::move(move.mString); - - move.mType = UNDEFINED; - move.mRefCount = NULL; - } - - inline DukValue& operator=(const DukValue& rhs) { - // free whatever we had - release_ref_count(); - - // copy things - mContext = rhs.mContext; - mType = rhs.mType; - mPOD = rhs.mPOD; - - if (mType == STRING) - mString = rhs.mString; - - if (mType == OBJECT) - { - // ref counting increment - if (rhs.mRefCount == NULL) { - // not ref counted before, need to allocate memory - const_cast(rhs).mRefCount = new int(2); - mRefCount = rhs.mRefCount; - } else { - // already refcounting, just increment - mRefCount = rhs.mRefCount; - *mRefCount = *mRefCount + 1; - } - } - - return *this; - } - - // copy constructor - inline DukValue(const DukValue& copy) : DukValue() { - *this = copy; - } - - // equality operator - inline bool operator==(const DukValue& rhs) const - { - if (mType != rhs.mType || mContext != rhs.mContext) - return false; - - switch (mType) { - case UNDEFINED: - case NULLREF: - return true; - case BOOLEAN: - return mPOD.boolean == rhs.mPOD.boolean; - case NUMBER: - return mPOD.number == rhs.mPOD.number; - case STRING: - return mString == rhs.mString; - - case OBJECT: - { - // this could be optimized to only push ref_array once... - this->push(); - rhs.push(); - bool equal = duk_equals(mContext, -1, -2) ? true : false; - duk_pop_2(mContext); - return equal; - } - - case POINTER: - return mPOD.pointer == rhs.mPOD.pointer; - - case BUFFER: - case LIGHTFUNC: - default: - throw DukException() << "operator== not implemented (" << type_name() << ")"; - } - } - - inline bool operator!=(const DukValue& rhs) const { - return !(*this == rhs); - } - - // copies the object at idx on the stack into a new DukValue and returns it - static DukValue copy_from_stack(duk_context* ctx, duk_idx_t idx = -1) { - DukValue value; - value.mContext = ctx; - value.mType = (Type) duk_get_type(ctx, idx); - switch (value.mType) { - case UNDEFINED: - break; - - case NULLREF: - value.mPOD.pointer = NULL; - break; - - case BOOLEAN: - value.mPOD.boolean = duk_require_boolean(ctx, idx) ? true : false; - break; - - case NUMBER: - value.mPOD.number = duk_require_number(ctx, idx); - break; - - case STRING: - { - duk_size_t len; - const char* data = duk_get_lstring(ctx, idx, &len); - value.mString.assign(data, len); - break; - } - - case OBJECT: - value.mPOD.ref_array_idx = stash_ref(ctx, idx); - break; - - case POINTER: - value.mPOD.pointer = duk_require_pointer(ctx, idx); - break; - - case BUFFER: - case LIGHTFUNC: - default: - throw DukException() << "Cannot turn type into DukValue (" << value.type_name() << ")"; - } - - return value; - } - -protected: - static duk_ret_t json_decode_safe(duk_context* ctx, void* user_data) - { - duk_json_decode(ctx, -1); - return 1; - } - -public: - static_assert(sizeof(char) == 1, "Serialization probably broke"); - static DukValue deserialize(duk_context* ctx, const char* data, size_t data_len) { - DukValue v; - v.mContext = ctx; - v.mType = *((Type*)data); - - const char* data_ptr = data + sizeof(Type); - data_len -= sizeof(Type); - - switch (v.mType) { - case UNDEFINED: - case NULLREF: - break; - - case BOOLEAN: - { - if (data_len < 1) - throw DukException() << "Malformed boolean data"; - - v.mPOD.boolean = data[1] == 1 ? true : false; - break; - } - - case NUMBER: - { - if (data_len < sizeof(double)) - throw DukException() << "Malformed number data"; - - v.mPOD.number = *((double*)data_ptr); - break; - } - - case STRING: - { - if (data_len < sizeof(uint32_t)) - throw DukException() << "Malformed string data (no length)"; - uint32_t str_len = *((uint32_t*)data_ptr); - - if (data_len < sizeof(uint32_t) + str_len) - throw DukException() << "Malformed string data (appears truncated)"; - - const char* str_data = (data_ptr + sizeof(uint32_t)); - v.mString.assign(str_data, str_len); - break; - } - - case OBJECT: - { - if (data_len < sizeof(uint32_t)) - throw DukException() << "Malformed object JSON data (no length)"; - uint32_t json_len = *((uint32_t*)data_ptr); - - if (data_len < sizeof(uint32_t) + json_len) - throw DukException() << "Malformed object JSON data (appears truncated)"; - - const char* json_data = (data_ptr + sizeof(uint32_t)); - duk_push_lstring(ctx, json_data, json_len); - int rc = duk_safe_call(ctx, &json_decode_safe, NULL, 1, 1); - if (rc) { - throw DukErrorException(ctx, rc) << "Could not decode JSON"; - } else { - v.mPOD.ref_array_idx = stash_ref(ctx, -1); - duk_pop(ctx); - } - break; - } - - default: - throw DukException() << "not implemented"; - } - - return v; - } - - // same as above (copy_from_stack), but also removes the value we copied from the stack - static DukValue take_from_stack(duk_context* ctx, duk_idx_t idx = -1) { - DukValue val = copy_from_stack(ctx, idx); - duk_remove(ctx, idx); - return val; - } - - // push the value we hold onto the stack - inline void push() const { - duk_context* ctx = mContext; - - switch (mType) { - case UNDEFINED: - duk_push_undefined(ctx); - break; - case NULLREF: - duk_push_null(ctx); - break; - - case BOOLEAN: - duk_push_boolean(ctx, mPOD.boolean); - break; - - case NUMBER: - duk_push_number(ctx, mPOD.number); - break; - - case STRING: - duk_push_lstring(ctx, mString.data(), mString.size()); - break; - - case OBJECT: - push_ref_array(ctx); - duk_get_prop_index(ctx, -1, mPOD.ref_array_idx); - duk_remove(ctx, -2); - break; - - case POINTER: - duk_push_pointer(ctx, mPOD.pointer); - break; - - case BUFFER: - case LIGHTFUNC: - default: - throw DukException() << "DukValue.push() not implemented for type (" << type_name() << ")"; - } - } - - // various (type-safe) getters - inline bool as_bool() const { - if (mType != BOOLEAN) - throw DukException() << "Expected boolean, got " << type_name(); - return mPOD.boolean; - } - - inline double as_double() const { - if (mType != NUMBER) - throw DukException() << "Expected number, got " << type_name(); - return mPOD.number; - } - - inline float as_float() const { - if (mType != NUMBER) - throw DukException() << "Expected number, got " << type_name(); - return static_cast(mPOD.number); - } - - inline duk_int_t as_int() const { - if (mType != NUMBER) - throw DukException() << "Expected number, got " << type_name(); - return static_cast(mPOD.number); - } - - inline duk_uint_t as_uint() const { - if (mType != NUMBER) - throw DukException() << "Expected number, got " << type_name(); - return static_cast(mPOD.number); - } - - inline void* as_pointer() const { - if (mType != POINTER && mType != NULLREF) - throw DukException() << "Expected pointer or null, got " << type_name(); - return mPOD.pointer; - } - - inline const std::string& as_string() const { - if (mType != STRING) - throw DukException() << "Expected string, got " << type_name(); - return mString; - } - - inline const char* as_c_string() const { - if (mType != STRING) - throw DukException() << "Expected string, got " << type_name(); - return mString.data(); - } - - inline Type type() const { - return mType; - } - - // same as duk_get_type_name(), but that's internal to Duktape, so we shouldn't use it - inline const char* type_name() const { - switch (mType) { - case UNDEFINED: return "undefined"; - case NULLREF: return "null"; - case BOOLEAN: return "boolean"; - case NUMBER: return "number"; - case STRING: return "string"; - case OBJECT: return "object"; - case BUFFER: return "buffer"; - case POINTER: return "pointer"; - case LIGHTFUNC: return "lightfunc"; - } - return "?"; - } - - inline duk_context* context() const { - return mContext; - } - - // Important limitations: - // - The returned value is binary and will not behave well if you treat it like a string (it will almost certainly contain '\0'). - // If you need to transport it like a string, maybe try encoding it as base64. - // - Strings longer than 2^32 (UINT32_MAX) characters will throw an exception. You can raise this to be a uint64_t if you need - // really long strings for some reason (be sure to change DukValue::deserialize() as well). - // - Objects are encoded to JSON and then sent like a string. If your object can't be encoded as JSON (i.e. it's a function), - // this will not work. This can be done, but I chose not to because it poses a security issue if you deserializing untrusted data. - // If you require this functionality, you'll have to add it yourself with using duk_dump_function(...). - static_assert(sizeof(char) == 1, "Serialization probably broke"); - std::vector serialize() const { - std::vector buff; - buff.resize(sizeof(Type)); - *((Type*)buff.data()) = mType; - - switch (mType) { - case UNDEFINED: - case NULLREF: - break; - - case BOOLEAN: - { - buff.push_back(mPOD.boolean ? 1 : 0); - break; - } - - case NUMBER: - { - buff.resize(buff.size() + sizeof(double)); - *((double*)(buff.data() + sizeof(Type))) = mPOD.number; - break; - } - - case STRING: - { - if (mString.length() > static_cast(UINT32_MAX)) - throw DukException() << "String length larger than uint32_t max"; - - uint32_t len = mString.length(); - buff.resize(buff.size() + sizeof(uint32_t) + len); - - uint32_t* len_ptr = (uint32_t*)(buff.data() + sizeof(Type)); - *len_ptr = len; - - char* out_ptr = (char*)(buff.data() + sizeof(Type) + sizeof(uint32_t)); - strncpy(out_ptr, mString.data(), len); // note: this will NOT be null-terminated - break; - } - - case OBJECT: - { - push(); - if (duk_is_function(mContext, -1)) { - duk_pop(mContext); - throw DukException() << "Functions cannot be serialized"; - // well, technically they can...see the comments at the start of this method - } - - std::string json = duk_json_encode(mContext, -1); - duk_pop(mContext); - - if (json.length() > static_cast(UINT32_MAX)) - throw DukException() << "JSON length larger than uint32_t max"; - - uint32_t len = json.length(); - buff.resize(buff.size() + sizeof(uint32_t) + len); - - uint32_t* len_ptr = (uint32_t*)(buff.data() + sizeof(Type)); - *len_ptr = len; - - char* out_ptr = (char*)(buff.data() + sizeof(Type) + sizeof(uint32_t)); - strncpy(out_ptr, json.data(), len); // note: this will NOT be null-terminated - break; - } - - default: - throw DukException() << "Type not implemented for serialization."; - } - - return buff; - } - -private: - // THIS IS COMPLETELY UNRELATED TO DETAIL_REFS.H. - // detail_refs.h stores a mapping of native object -> script object. - // This just stores arbitrary script objects (which likely have no native object backing them). - // If I was smarter I might merge the two implementations, but this one is simpler - // (since we don't need the std::map here). - static void push_ref_array(duk_context* ctx) - { - static const char* DUKVALUE_REF_ARRAY = "dukglue_dukvalue_refs"; - duk_push_heap_stash(ctx); - - if (!duk_has_prop_string(ctx, -1, DUKVALUE_REF_ARRAY)) { - duk_push_array(ctx); - - // ref_array[0] = 0 (initialize free list as empty) - duk_push_int(ctx, 0); - duk_put_prop_index(ctx, -2, 0); - - duk_put_prop_string(ctx, -2, DUKVALUE_REF_ARRAY); - } - - duk_get_prop_string(ctx, -1, DUKVALUE_REF_ARRAY); - duk_remove(ctx, -2); // pop heap stash - } - - // put a new reference into the ref array and return its index in the array - static duk_uint_t stash_ref(duk_context* ctx, duk_idx_t idx) - { - push_ref_array(ctx); - - // if idx is relative, we need to adjust it to deal with the array we just pushed - if (idx < 0) - idx--; - - // find next free index - // free indices are kept in a linked list, starting at ref_array[0] - duk_get_prop_index(ctx, -1, 0); - duk_uarridx_t next_free_idx = duk_get_uint(ctx, -1); - duk_pop(ctx); - - if (next_free_idx == 0) { - // no free spots in the array, make a new one at arr.length - next_free_idx = duk_get_length(ctx, -1); - } else { - // free spot found, need to remove it from the free list - // ref_array[0] = ref_array[next_free_idx] - duk_get_prop_index(ctx, -1, next_free_idx); - duk_put_prop_index(ctx, -2, 0); - } - - duk_dup(ctx, idx); // copy value we are storing (since store consumes it) - duk_put_prop_index(ctx, -2, next_free_idx); // store it (consumes duplicated value) - duk_pop(ctx); // pop ref array - - return next_free_idx; - } - - // remove ref_array_idx from the ref array and add its spot to the free list (at refs[0]) - static void free_ref(duk_context* ctx, duk_uarridx_t ref_array_idx) - { - push_ref_array(ctx); - - // add this spot to the free list - // refs[old_obj_idx] = refs[0] (implicitly gives up our reference) - duk_get_prop_index(ctx, -1, 0); - duk_put_prop_index(ctx, -2, ref_array_idx); - - // refs[0] = old_obj_idx - duk_push_uint(ctx, ref_array_idx); - duk_put_prop_index(ctx, -2, 0); - - duk_pop(ctx); // pop ref array - } - - // this is for reference counting - used to release our reference based on the state - // of mRefCount. If mRefCount is NULL, we never got copy constructed, so we have ownership - // of our reference and can free it. If it's not null and above 1, we decrement the counter - // (someone else owns the reference). If it's not null and equal to 1, we are the last owner - // of a previously shared reference, so we can free it. - void release_ref_count() - { - if (mType == OBJECT) - { - if (mRefCount != NULL) - { - // sharing with another DukValue, are we the only one left? - if (*mRefCount > 1) { // still someone else referencing this - *mRefCount = *mRefCount - 1; - } else { - // not sharing anymore, we can free it - free_ref(mContext, mPOD.ref_array_idx); - delete mRefCount; - } - - mRefCount = NULL; - } else { - // not sharing with any other DukValue, free it - free_ref(mContext, mPOD.ref_array_idx); - } - - mType = UNDEFINED; - } - } - - duk_context* mContext; - Type mType; // our type - one of the standard Duktape DUK_TYPE_* values - - // This holds the plain-old-data types. Since this is a variant, - // we hold only one value at a time, so this is a union to save - // a bit of space. - union ValueTypes { - bool boolean; - double number; - void* pointer; // if mType == NULLREF, this is 0 (otherwise holds pointer value when mType == POINTER) - duk_uarridx_t ref_array_idx; - } mPOD; - - std::string mString; // if it's a string, we store it with std::string - int* mRefCount; // if mType == OBJECT and we're sharing, this will point to our ref counter -}; diff --git a/dep/duktape/dukglue/public_util.h b/dep/duktape/dukglue/public_util.h deleted file mode 100644 index d6ff344d8f4..00000000000 --- a/dep/duktape/dukglue/public_util.h +++ /dev/null @@ -1,315 +0,0 @@ -#pragma once - -#include "dukexception.h" -#include "detail_traits.h" // for index_tuple/make_indexes - -// This file has some useful utility functions for users. -// Hopefully this saves you from wading through the implementation. - -/** - * @brief Push a value onto the duktape stack. - * - * WARNING: THIS IS NOT "PROTECTED." If an error occurs when pushing (unlikely, but possible), - * the Duktape fatal error handler will be invoked (and the program will probably terminate). - * - * @param ctx duktape context - * @param[in] val value to push - */ -template -void dukglue_push(duk_context* ctx, const FullT& val) { - // ArgStorage has some static_asserts in it that validate value types, - // so we typedef it to force ArgStorage to compile and run the asserts - typedef typename dukglue::types::ArgStorage::type ValidateReturnType; - - using namespace dukglue::types; - DukType::type>::template push(ctx, std::move(val)); -} - -template -void dukglue_push(duk_context* ctx, const T& arg, ArgTs... args) -{ - dukglue_push(ctx, arg); - dukglue_push(ctx, args...); -} - -inline void dukglue_push(duk_context* ctx) -{ - // no-op -} - - -/** - * WARNING: THIS IS NOT "PROTECTED." If an error occurs while reading (which is possible if you didn't - * explicitly check the type), the fatal Duktape error handler will be invoked, and the program - * will probably abort. - */ -template -void dukglue_read(duk_context* ctx, duk_idx_t arg_idx, RetT* out) -{ - // ArgStorage has some static_asserts in it that validate value types, - // so we typedef it to force ArgStorage to compile and run the asserts - typedef typename dukglue::types::ArgStorage::type ValidateReturnType; - - using namespace dukglue::types; - *out = DukType::type>::template read(ctx, arg_idx); -} - - -// methods - -// leaves return value on stack -template -void dukglue_call_method(duk_context* ctx, const ObjT& obj, const char* method_name, ArgTs... args) -{ - dukglue_push(ctx, obj); - duk_get_prop_string(ctx, -1, method_name); - - if (duk_check_type(ctx, -1, DUK_TYPE_UNDEFINED)) { - duk_error(ctx, DUK_ERR_REFERENCE_ERROR, "Method does not exist", method_name); - return; - } - - if (!duk_is_callable(ctx, -1)) { - duk_error(ctx, DUK_ERR_TYPE_ERROR, "Property is not callable"); - return; - } - - duk_swap_top(ctx, -2); - dukglue_push(ctx, args...); - duk_call_method(ctx, sizeof...(args)); -} - -namespace dukglue { -namespace detail { - -template -struct SafeMethodCallData { - const ObjT* obj; - const char* method_name; - std::tuple args; - RetT* out; -}; - -template -void call_method_safe_helper(duk_context* ctx, const ObjT& obj, const char* method_name, std::tuple& tup, index_tuple indexes) -{ - dukglue_call_method(ctx, obj, method_name, std::forward(std::get(tup))...); -} - -template -typename std::enable_if::value, duk_idx_t>::type call_method_safe(duk_context* ctx, void* udata) -{ - typedef SafeMethodCallData DataT; - DataT* data = (DataT*) udata; - call_method_safe_helper(ctx, *(data->obj), data->method_name, data->args, typename make_indexes::type()); - return 1; -} - -template -typename std::enable_if::value, duk_idx_t>::type call_method_safe(duk_context* ctx, void* udata) -{ - typedef SafeMethodCallData DataT; - DataT* data = (DataT*)udata; - - call_method_safe_helper(ctx, *(data->obj), data->method_name, data->args, typename make_indexes::type()); - dukglue_read(ctx, -1, data->out); - return 1; -} - -} -} - -template -typename std::enable_if::value, RetT>::type dukglue_pcall_method(duk_context* ctx, const ObjT& obj, const char* method_name, ArgTs... args) -{ - dukglue::detail::SafeMethodCallData data { - &obj, method_name, std::tuple(args...), nullptr - }; - - duk_idx_t rc = duk_safe_call(ctx, &dukglue::detail::call_method_safe, (void*) &data, 0, 1); - if (rc != 0) - throw DukErrorException(ctx, rc); - - duk_pop(ctx); // remove result from stack -} - -template -typename std::enable_if::value, RetT>::type dukglue_pcall_method(duk_context* ctx, const ObjT& obj, const char* method_name, ArgTs... args) -{ - RetT out; - dukglue::detail::SafeMethodCallData data { - &obj, method_name, std::tuple(args...), &out - }; - - duk_idx_t rc = duk_safe_call(ctx, &dukglue::detail::call_method_safe, (void*) &data, 0, 1); - if (rc != 0) - throw DukErrorException(ctx, rc); - - duk_pop(ctx); // remove result from stack - return std::move(out); -} - - -// calls - -// leaves return value on the stack -template -void dukglue_call(duk_context* ctx, const ObjT& func, ArgTs... args) -{ - dukglue_push(ctx, func); - if (!duk_is_callable(ctx, -1)) { - duk_pop(ctx); - duk_error(ctx, DUK_ERR_TYPE_ERROR, "Object is not callable"); - return; - } - - dukglue_push(ctx, args...); - duk_call(ctx, sizeof...(args)); -} - - -// safe call -namespace dukglue { -namespace detail { - -template -struct SafeCallData { - const ObjT* obj; - std::tuple args; - RetT* out; -}; - -template -void call_safe_helper(duk_context* ctx, const ObjT& obj, std::tuple& tup, index_tuple indexes) -{ - dukglue_call(ctx, obj, std::forward(std::get(tup))...); -} - -// leaves result on stack -template -typename std::enable_if::value, duk_ret_t>::type call_safe(duk_context* ctx, void* udata) -{ - typedef SafeCallData DataT; - DataT* data = (DataT*)udata; - - call_safe_helper(ctx, *(data->obj), data->args, typename make_indexes::type()); - return 1; -} - -// leaves result on stack -// The result is read into RetT here because it can potentially trigger an error (with duk_error). -// If we did it "above" this function, that error would trigger a panic instead of error handling. -template -typename std::enable_if::value, duk_ret_t>::type call_safe(duk_context* ctx, void* udata) -{ - typedef SafeCallData DataT; - DataT* data = (DataT*)udata; - - call_safe_helper(ctx, *(data->obj), data->args, typename make_indexes::type()); - dukglue_read(ctx, -1, data->out); - return 1; -} - -} -} - -// Unlike duktape, this will remove the return value from the stack! -template -typename std::enable_if::value, RetT>::type dukglue_pcall(duk_context* ctx, const ObjT& obj, ArgTs... args) -{ - dukglue::detail::SafeCallData data{ - &obj, std::tuple(args...), nullptr - }; - - duk_int_t rc = duk_safe_call(ctx, &dukglue::detail::call_safe, (void*) &data, 0, 1); - if (rc != 0) - throw DukErrorException(ctx, rc); - duk_pop(ctx); // remove result from stack -} - -template -typename std::enable_if::value, RetT>::type dukglue_pcall(duk_context* ctx, const ObjT& obj, ArgTs... args) -{ - RetT result; - dukglue::detail::SafeCallData data{ - &obj, std::tuple(args...), &result - }; - - duk_int_t rc = duk_safe_call(ctx, &dukglue::detail::call_safe, (void*) &data, 0, 1); - if (rc != 0) - throw DukErrorException(ctx, rc); - - duk_pop(ctx); // remove result from stack - return std::move(result); -} - -// same as dukglue_pcall, but leaves the result or error on the stack and returns the Duktape return code -template -duk_int_t dukglue_pcall_raw(duk_context* ctx, const ObjT& obj, ArgTs... args) -{ - dukglue::detail::SafeCallData data{ - &obj, std::tuple(args...), nullptr - }; - - return duk_safe_call(ctx, &dukglue::detail::call_safe, (void*)&data, 0, 1); -} - - -// peval -namespace dukglue { -namespace detail { - -template -struct SafeEvalData { - const char* str; - RetT* out; -}; - -template -duk_ret_t eval_safe(duk_context* ctx, void* udata) -{ - SafeEvalData* data = (SafeEvalData*) udata; - - duk_eval_string(ctx, data->str); - dukglue_read(ctx, -1, data->out); - return 1; -} - -} -} - -template -typename std::enable_if::value, RetT>::type dukglue_peval(duk_context* ctx, const char* str) -{ - int prev_top = duk_get_top(ctx); - int rc = duk_peval_string(ctx, str); - if (rc != 0) - throw DukErrorException(ctx, rc); - - duk_pop_n(ctx, duk_get_top(ctx) - prev_top); // pop any results -} - -template -typename std::enable_if::value, RetT>::type dukglue_peval(duk_context* ctx, const char* str) -{ - int prev_top = duk_get_top(ctx); - - RetT ret; - dukglue::detail::SafeEvalData data{ - str, &ret - }; - - int rc = duk_safe_call(ctx, &dukglue::detail::eval_safe, (void*) &data, 0, 1); - if (rc != 0) - throw DukErrorException(ctx, rc); - duk_pop_n(ctx, duk_get_top(ctx) - prev_top); // pop any results - return ret; -} - -// register a global object (very simple helper, but very common for "Hello World"-ish applications) -template -inline void dukglue_register_global(duk_context* ctx, const T& obj, const char* name) -{ - dukglue_push(ctx, obj); - duk_put_global_string(ctx, name); -} \ No newline at end of file diff --git a/dep/duktape/dukglue/register_class.h b/dep/duktape/dukglue/register_class.h deleted file mode 100644 index bb7669029fc..00000000000 --- a/dep/duktape/dukglue/register_class.h +++ /dev/null @@ -1,202 +0,0 @@ -#pragma once - -#include "detail_class_proto.h" -#include "detail_constructor.h" -#include "detail_method.h" - -// Set the constructor for the given type. -template -void dukglue_register_constructor(duk_context* ctx, const char* name) -{ - duk_c_function constructor_func = dukglue::detail::call_native_constructor; - - duk_push_c_function(ctx, constructor_func, sizeof...(Ts)); - - // set constructor_func.prototype - dukglue::detail::ProtoManager::push_prototype(ctx); - duk_put_prop_string(ctx, -2, "prototype"); - - // set name = constructor_func - duk_put_global_string(ctx, name); -} - -template -void dukglue_register_constructor_managed(duk_context* ctx, const char* name) -{ - duk_c_function constructor_func = dukglue::detail::call_native_constructor; - duk_c_function finalizer_func = dukglue::detail::managed_finalizer; - - duk_push_c_function(ctx, constructor_func, sizeof...(Ts)); - - // create new prototype with finalizer - duk_push_object(ctx); - - // set the finalizer - duk_push_c_function(ctx, finalizer_func, 1); - duk_set_finalizer(ctx, -2); - - // hook prototype with finalizer up to real class prototype - // must use duk_set_prototype, not set the .prototype property - dukglue::detail::ProtoManager::push_prototype(ctx); - duk_set_prototype(ctx, -2); - - // set constructor_func.prototype to the prototype with the finalizer - duk_put_prop_string(ctx, -2, "prototype"); - - // set name = constructor_func - duk_put_global_string(ctx, name); -} - -template -void dukglue_set_base_class(duk_context* ctx) -{ - static_assert(!std::is_pointer::value && !std::is_pointer::value - && !std::is_const::value && !std::is_const::value, "Use bare class names."); - static_assert(std::is_base_of::value, "Invalid class hierarchy!"); - - using namespace dukglue::detail; - - // Derived.type_info->set_base(Base.type_info) - ProtoManager::push_prototype(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "type_info"); - TypeInfo* derived_type_info = static_cast(duk_require_pointer(ctx, -1)); - duk_pop_2(ctx); - - ProtoManager::push_prototype(ctx); - duk_get_prop_string(ctx, -1, "\xFF" "type_info"); - TypeInfo* base_type_info = static_cast(duk_require_pointer(ctx, -1)); - duk_pop_2(ctx); - - derived_type_info->set_base(base_type_info); - - // also set up the prototype chain - ProtoManager::push_prototype(ctx); - ProtoManager::push_prototype(ctx); - duk_set_prototype(ctx, -2); - duk_pop(ctx); -} - -// methods -template -void dukglue_register_method_compiletime(duk_context* ctx, RetType(Cls::*method)(Ts...), const char* name) -{ - static_assert(std::is_same::value, "Mismatching method types."); - dukglue_register_method_compiletime(ctx, name); -} - -template -void dukglue_register_method_compiletime(duk_context* ctx, RetType(Cls::*method)(Ts...) const, const char* name) -{ - static_assert(std::is_same::value, "Mismatching method types."); - dukglue_register_method_compiletime(ctx, name); -} - -template -void dukglue_register_method_compiletime(duk_context* ctx, const char* name) -{ - using namespace dukglue::detail; - typedef MethodInfo MethodInfo; - - duk_c_function method_func = MethodInfo::template MethodCompiletime::call_native_method; - - ProtoManager::push_prototype(ctx); - - duk_push_c_function(ctx, method_func, sizeof...(Ts)); - duk_put_prop_string(ctx, -2, name); // consumes func above - - duk_pop(ctx); // pop prototype -} - -template -void dukglue_register_method(duk_context* ctx, RetType(Cls::*method)(Ts...), const char* name) -{ - dukglue_register_method(ctx, method, name); -} - -template -void dukglue_register_method(duk_context* ctx, RetType(Cls::*method)(Ts...) const, const char* name) -{ - dukglue_register_method(ctx, method, name); -} - -// I'm sorry this signature is so long, but I figured it was better than duplicating the method, -// once for const methods and once for non-const methods. -template -void dukglue_register_method(duk_context* ctx, typename std::conditional::type method, const char* name) -{ - using namespace dukglue::detail; - typedef MethodInfo MethodInfo; - - duk_c_function method_func = MethodInfo::MethodRuntime::call_native_method; - - ProtoManager::push_prototype(ctx); - - duk_push_c_function(ctx, method_func, sizeof...(Ts)); - - duk_push_pointer(ctx, new typename MethodInfo::MethodHolder{ method }); - duk_put_prop_string(ctx, -2, "\xFF" "method_holder"); // consumes raw method pointer - - // make sure we free the method_holder when this function is removed - duk_push_c_function(ctx, MethodInfo::MethodRuntime::finalize_method, 1); - duk_set_finalizer(ctx, -2); - - duk_put_prop_string(ctx, -2, name); // consumes method function - - duk_pop(ctx); // pop prototype -} - -// methods with a variable number of (script) arguments -template -inline void dukglue_register_method_varargs(duk_context* ctx, duk_ret_t(Cls::*method)(duk_context*), const char* name) -{ - dukglue_register_method_varargs(ctx, method, name); -} - -template -inline void dukglue_register_method_varargs(duk_context* ctx, duk_ret_t(Cls::*method)(duk_context*) const, const char* name) -{ - dukglue_register_method_varargs(ctx, method, name); -} - -template -void dukglue_register_method_varargs(duk_context* ctx, - typename std::conditional::type method, - const char* name) -{ - using namespace dukglue::detail; - typedef MethodVariadicRuntime MethodVariadicInfo; - - duk_c_function method_func = MethodVariadicInfo::call_native_method; - - ProtoManager::push_prototype(ctx); - - duk_push_c_function(ctx, method_func, DUK_VARARGS); - - duk_push_pointer(ctx, new typename MethodVariadicInfo::MethodHolderVariadic{ method }); - duk_put_prop_string(ctx, -2, "\xFF" "method_holder"); // consumes raw method pointer - - // make sure we free the method_holder when this function is removed - duk_push_c_function(ctx, MethodVariadicInfo::finalize_method, 1); - duk_set_finalizer(ctx, -2); - - duk_put_prop_string(ctx, -2, name); // consumes method function - - duk_pop(ctx); // pop prototype -} - -inline void dukglue_invalidate_object(duk_context* ctx, void* obj_ptr) -{ - dukglue::detail::RefManager::find_and_invalidate_native_object(ctx, obj_ptr); -} - -// register a deleter -template -void dukglue_register_delete(duk_context* ctx) -{ - duk_c_function delete_func = dukglue::detail::call_native_deleter; - - dukglue::detail::ProtoManager::push_prototype(ctx); - duk_push_c_function(ctx, delete_func, 0); - duk_put_prop_string(ctx, -2, "delete"); - duk_pop(ctx); // pop prototype -} \ No newline at end of file diff --git a/dep/duktape/dukglue/register_function.h b/dep/duktape/dukglue/register_function.h deleted file mode 100644 index 77e83aad95a..00000000000 --- a/dep/duktape/dukglue/register_function.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "detail_function.h" - -// Register a function, embedding the function address at compile time. -// According to benchmarks, there's really not much reason to do this -// (inconsistent 2-3% performance improvement for a 10,000 function call stress test averaged over 100 runs), -// since it has much uglier syntax and may bloat executable size if you have many functions with identical signatures. -template -void dukglue_register_function_compiletime(duk_context* ctx, RetType(*)(Ts...), const char* name) -{ - static_assert(std::is_same::value, - "Mismatching function pointer template parameter and function pointer argument types. " - "Try: dukglue_register_function(ctx, \"funcName\", func)"); - - duk_c_function evalFunc = dukglue::detail::FuncInfoHolder::template FuncActual::call_native_function; - - duk_push_c_function(ctx, evalFunc, sizeof...(Ts)); - duk_put_global_string(ctx, name); -} - -// Register a function. -template -void dukglue_register_function(duk_context* ctx, RetType(*funcToCall)(Ts...), const char* name) -{ - duk_c_function evalFunc = dukglue::detail::FuncInfoHolder::FuncRuntime::call_native_function; - - duk_push_c_function(ctx, evalFunc, sizeof...(Ts)); - - static_assert(sizeof(RetType(*)(Ts...)) == sizeof(void*), "Function pointer and data pointer are different sizes"); - duk_push_pointer(ctx, reinterpret_cast(funcToCall)); - duk_put_prop_string(ctx, -2, "\xFF" "func_ptr"); - - duk_put_global_string(ctx, name); -} diff --git a/dep/duktape/dukglue/register_property.h b/dep/duktape/dukglue/register_property.h deleted file mode 100644 index c4fd8b36b71..00000000000 --- a/dep/duktape/dukglue/register_property.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include "detail_method.h" - -// const getter, setter -template -void dukglue_register_property(duk_context* ctx, - RetT(Cls::*getter)() const, - void(Cls::*setter)(ArgT), - const char* name) -{ - dukglue_register_property(ctx, getter, setter, name); -} - -// const getter, no setter -template -void dukglue_register_property(duk_context* ctx, - RetT(Cls::*getter)() const, - std::nullptr_t setter, - const char* name) -{ - dukglue_register_property(ctx, getter, setter, name); -} - -// non-const getter, setter -template -void dukglue_register_property(duk_context* ctx, - RetT(Cls::*getter)(), - void(Cls::*setter)(ArgT), - const char* name) -{ - dukglue_register_property(ctx, getter, setter, name); -} - -// non-const getter, no setter -template -void dukglue_register_property(duk_context* ctx, - RetT(Cls::*getter)(), - std::nullptr_t setter, - const char* name) -{ - dukglue_register_property(ctx, getter, setter, name); -} - -// no getter, setter -template -void dukglue_register_property(duk_context* ctx, - std::nullptr_t getter, - void(Cls::*setter)(ArgT), - const char* name) -{ - dukglue_register_property(ctx, getter, setter, name); -} - -// no getter, no setter -template -void dukglue_register_property(duk_context* ctx, std::nullptr_t getter, std::nullptr_t setter, const char* name) -{ - // strictly speaking I think duktape can probably handle neither - // (according to the wonderful API docs), but I don't know why you - // would want to do this in the first place - static_assert(std::is_void::value, "Must have getter or setter"); -} - -inline duk_ret_t dukglue_throw_error(duk_context* ctx) -{ - duk_error(ctx, DUK_ERR_TYPE_ERROR, "Property does not have getter or setter."); -} - -template -void dukglue_register_property(duk_context* ctx, - typename std::conditional::type getter, - void(Cls::*setter)(ArgT), - const char* name) -{ - using namespace dukglue::detail; - typedef MethodInfo GetterMethodInfo; - typedef MethodInfo SetterMethodInfo; - - ProtoManager::push_prototype(ctx); - - // push key - duk_push_string(ctx, name); - - // push getter - if (getter != nullptr) { - duk_c_function method_func = GetterMethodInfo::MethodRuntime::call_native_method; - - duk_push_c_function(ctx, method_func, 0); - - duk_push_pointer(ctx, new typename GetterMethodInfo::MethodHolder{ getter }); - duk_put_prop_string(ctx, -2, "\xFF" "method_holder"); // consumes raw method pointer - - // make sure we free the method_holder when this function is removed - duk_push_c_function(ctx, GetterMethodInfo::MethodRuntime::finalize_method, 1); - duk_set_finalizer(ctx, -2); - } else { - duk_push_c_function(ctx, dukglue_throw_error, 1); - } - - if (setter != nullptr) { - duk_c_function method_func = SetterMethodInfo::MethodRuntime::call_native_method; - - duk_push_c_function(ctx, method_func, 1); - - duk_push_pointer(ctx, new typename SetterMethodInfo::MethodHolder{ setter }); - duk_put_prop_string(ctx, -2, "\xFF" "method_holder"); // consumes raw method pointer - - // make sure we free the method_holder when this function is removed - duk_push_c_function(ctx, SetterMethodInfo::MethodRuntime::finalize_method, 1); - duk_set_finalizer(ctx, -2); - } else { - duk_push_c_function(ctx, dukglue_throw_error, 1); - } - - duk_uint_t flags = DUK_DEFPROP_HAVE_GETTER - | DUK_DEFPROP_HAVE_SETTER - | DUK_DEFPROP_HAVE_CONFIGURABLE /* set not configurable (from JS) */ - | DUK_DEFPROP_FORCE /* allow overriding built-ins and previously defined properties */; - - duk_def_prop(ctx, -4, flags); - duk_pop(ctx); // pop prototype -} diff --git a/dep/duktape/duktape/duk_config.h b/dep/duktape/duktape/duk_config.h deleted file mode 100644 index 3f217ef7d23..00000000000 --- a/dep/duktape/duktape/duk_config.h +++ /dev/null @@ -1,3672 +0,0 @@ -/* - * duk_config.h configuration header generated by genconfig.py. - * - * Git commit: a459cf3c9bd1779fc01b435d69302b742675a08f - * Git describe: v2.2.0 - * Git branch: master - * - * Supported platforms: - * - Mac OSX, iPhone, Darwin - * - Orbis - * - OpenBSD - * - Generic BSD - * - Atari ST TOS - * - AmigaOS - * - Durango (XboxOne) - * - Windows - * - Flashplayer (Crossbridge) - * - QNX - * - TI-Nspire - * - Emscripten - * - Linux - * - Solaris - * - AIX - * - HPUX - * - Generic POSIX - * - Cygwin - * - Generic UNIX - * - Generic fallback - * - * Supported architectures: - * - x86 - * - x64 - * - x32 - * - ARM 32-bit - * - ARM 64-bit - * - MIPS 32-bit - * - MIPS 64-bit - * - PowerPC 32-bit - * - PowerPC 64-bit - * - SPARC 32-bit - * - SPARC 64-bit - * - SuperH - * - Motorola 68k - * - Emscripten - * - Generic - * - * Supported compilers: - * - Clang - * - GCC - * - MSVC - * - Emscripten - * - TinyC - * - VBCC - * - Bruce's C compiler - * - Generic - * - */ - -#if !defined(DUK_CONFIG_H_INCLUDED) -#define DUK_CONFIG_H_INCLUDED - -/* - * Intermediate helper defines - */ - -/* DLL build detection */ -/* not configured for DLL build */ -#undef DUK_F_DLL_BUILD - -/* Apple OSX, iOS */ -#if defined(__APPLE__) -#define DUK_F_APPLE -#endif - -/* FreeBSD */ -#if defined(__FreeBSD__) || defined(__FreeBSD) -#define DUK_F_FREEBSD -#endif - -/* Orbis (PS4) variant */ -#if defined(DUK_F_FREEBSD) && defined(__ORBIS__) -#define DUK_F_ORBIS -#endif - -/* OpenBSD */ -#if defined(__OpenBSD__) || defined(__OpenBSD) -#define DUK_F_OPENBSD -#endif - -/* NetBSD */ -#if defined(__NetBSD__) || defined(__NetBSD) -#define DUK_F_NETBSD -#endif - -/* BSD variant */ -#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ - defined(__bsdi__) || defined(__DragonFly__) -#define DUK_F_BSD -#endif - -/* Atari ST TOS. __TOS__ defined by PureC. No platform define in VBCC - * apparently, so to use with VBCC user must define __TOS__ manually. - */ -#if defined(__TOS__) -#define DUK_F_TOS -#endif - -/* Motorola 68K. Not defined by VBCC, so user must define one of these - * manually when using VBCC. - */ -#if defined(__m68k__) || defined(M68000) || defined(__MC68K__) -#define DUK_F_M68K -#endif - -/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must - * define 'AMIGA' manually when using VBCC. - */ -#if defined(AMIGA) || defined(__amigaos__) -#define DUK_F_AMIGAOS -#endif - -/* PowerPC */ -#if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__) -#define DUK_F_PPC -#if defined(__PPC64__) || defined(__LP64__) || defined(_LP64) -#define DUK_F_PPC64 -#else -#define DUK_F_PPC32 -#endif -#endif - -/* Durango (Xbox One) */ -#if defined(_DURANGO) || defined(_XBOX_ONE) -#define DUK_F_DURANGO -#endif - -/* Windows, both 32-bit and 64-bit */ -#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ - defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) -#define DUK_F_WINDOWS -#if defined(_WIN64) || defined(WIN64) -#define DUK_F_WIN64 -#else -#define DUK_F_WIN32 -#endif -#endif - -/* Flash player (e.g. Crossbridge) */ -#if defined(__FLASHPLAYER__) -#define DUK_F_FLASHPLAYER -#endif - -/* QNX */ -#if defined(__QNX__) -#define DUK_F_QNX -#endif - -/* TI-Nspire (using Ndless) */ -#if defined(_TINSPIRE) -#define DUK_F_TINSPIRE -#endif - -/* Emscripten (provided explicitly by user), improve if possible */ -#if defined(EMSCRIPTEN) -#define DUK_F_EMSCRIPTEN -#endif - -/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ -#if defined(__BCC__) || defined(__BCC_VERSION__) -#define DUK_F_BCC -#endif - -/* Linux */ -#if defined(__linux) || defined(__linux__) || defined(linux) -#define DUK_F_LINUX -#endif - -/* illumos / Solaris */ -#if defined(__sun) && defined(__SVR4) -#define DUK_F_SUN -#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550) -#define DUK_F_OLD_SOLARIS -/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms - * are processed before architectures, so this happens before the - * DUK_F_X86/DUK_F_X64 detection is emitted. - */ -#include -#endif -#endif - -/* AIX */ -#if defined(_AIX) -/* defined(__xlc__) || defined(__IBMC__): works but too wide */ -#define DUK_F_AIX -#endif - -/* HPUX */ -#if defined(__hpux) -#define DUK_F_HPUX -#if defined(__ia64) -#define DUK_F_HPUX_ITANIUM -#endif -#endif - -/* POSIX */ -#if defined(__posix) -#define DUK_F_POSIX -#endif - -/* Cygwin */ -#if defined(__CYGWIN__) -#define DUK_F_CYGWIN -#endif - -/* Generic Unix (includes Cygwin) */ -#if defined(__unix) || defined(__unix__) || defined(unix) || \ - defined(DUK_F_LINUX) || defined(DUK_F_BSD) -#define DUK_F_UNIX -#endif - -/* C++ */ -#undef DUK_F_CPP -#if defined(__cplusplus) -#define DUK_F_CPP -#endif - -/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), - * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. - * https://sites.google.com/site/x32abi/ - * - * With DUK_F_OLD_SOLARIS the header must be included - * before this. - */ -#if defined(__amd64__) || defined(__amd64) || \ - defined(__x86_64__) || defined(__x86_64) || \ - defined(_M_X64) || defined(_M_AMD64) -#if defined(__ILP32__) || defined(_ILP32) -#define DUK_F_X32 -#else -#define DUK_F_X64 -#endif -#elif defined(i386) || defined(__i386) || defined(__i386__) || \ - defined(__i486__) || defined(__i586__) || defined(__i686__) || \ - defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ - defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) -#if defined(__LP64__) || defined(_LP64) -/* This should not really happen, but would indicate x64. */ -#define DUK_F_X64 -#else -#define DUK_F_X86 -#endif -#endif - -/* ARM */ -#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) || defined(__aarch64__) -#define DUK_F_ARM -#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) -#define DUK_F_ARM64 -#else -#define DUK_F_ARM32 -#endif -#endif - -/* MIPS. Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ -#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \ - defined(_R3000) || defined(_R4000) || defined(_R5900) || \ - defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \ - defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \ - defined(__mips) || defined(__MIPS__) -#define DUK_F_MIPS -#if defined(__LP64__) || defined(_LP64) || defined(__mips64) || \ - defined(__mips64__) || defined(__mips_n64) -#define DUK_F_MIPS64 -#else -#define DUK_F_MIPS32 -#endif -#endif - -/* SPARC */ -#if defined(sparc) || defined(__sparc) || defined(__sparc__) -#define DUK_F_SPARC -#if defined(__LP64__) || defined(_LP64) -#define DUK_F_SPARC64 -#else -#define DUK_F_SPARC32 -#endif -#endif - -/* SuperH */ -#if defined(__sh__) || \ - defined(__sh1__) || defined(__SH1__) || \ - defined(__sh2__) || defined(__SH2__) || \ - defined(__sh3__) || defined(__SH3__) || \ - defined(__sh4__) || defined(__SH4__) || \ - defined(__sh5__) || defined(__SH5__) -#define DUK_F_SUPERH -#endif - -/* Clang */ -#if defined(__clang__) -#define DUK_F_CLANG -#endif - -/* C99 or above */ -#undef DUK_F_C99 -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -#define DUK_F_C99 -#endif - -/* C++11 or above */ -#undef DUK_F_CPP11 -#if defined(__cplusplus) && (__cplusplus >= 201103L) -#define DUK_F_CPP11 -#endif - -/* GCC. Clang also defines __GNUC__ so don't detect GCC if using Clang. */ -#if defined(__GNUC__) && !defined(__clang__) && !defined(DUK_F_CLANG) -#define DUK_F_GCC -#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -/* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */ -#define DUK_F_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__) -#else -#error cannot figure out gcc version -#endif -#endif - -/* MinGW. Also GCC flags (DUK_F_GCC) are enabled now. */ -#if defined(__MINGW32__) || defined(__MINGW64__) -#define DUK_F_MINGW -#endif - -/* MSVC */ -#if defined(_MSC_VER) -/* MSVC preprocessor defines: http://msdn.microsoft.com/en-us/library/b0084kay.aspx - * _MSC_FULL_VER includes the build number, but it has at least two formats, see e.g. - * BOOST_MSVC_FULL_VER in http://www.boost.org/doc/libs/1_52_0/boost/config/compiler/visualc.hpp - */ -#define DUK_F_MSVC -#if defined(_MSC_FULL_VER) -#if (_MSC_FULL_VER > 100000000) -#define DUK_F_MSVC_FULL_VER _MSC_FULL_VER -#else -#define DUK_F_MSCV_FULL_VER (_MSC_FULL_VER * 10) -#endif -#endif -#endif /* _MSC_VER */ - -/* TinyC */ -#if defined(__TINYC__) -/* http://bellard.org/tcc/tcc-doc.html#SEC9 */ -#define DUK_F_TINYC -#endif - -/* VBCC */ -#if defined(__VBCC__) -#define DUK_F_VBCC -#endif - -#if defined(ANDROID) || defined(__ANDROID__) -#define DUK_F_ANDROID -#endif - -/* Atari Mint */ -#if defined(__MINT__) -#define DUK_F_MINT -#endif - -/* - * Platform autodetection - */ - -/* Workaround for older C++ compilers before including , - * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366 - */ -#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS) -#define __STDC_LIMIT_MACROS -#endif -#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) -#define __STDC_CONSTANT_MACROS -#endif - -#if defined(DUK_F_APPLE) -/* --- Mac OSX, iPhone, Darwin --- */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include - -/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ -#if TARGET_IPHONE_SIMULATOR -#define DUK_USE_OS_STRING "iphone-sim" -#elif TARGET_OS_IPHONE -#define DUK_USE_OS_STRING "iphone" -#elif TARGET_OS_MAC -#define DUK_USE_OS_STRING "osx" -#else -#define DUK_USE_OS_STRING "osx-unknown" -#endif - -/* Use _setjmp() on Apple by default, see GH-55. */ -#define DUK_JMPBUF_TYPE jmp_buf -#define DUK_SETJMP(jb) _setjmp((jb)) -#define DUK_LONGJMP(jb) _longjmp((jb), 1) -#elif defined(DUK_F_ORBIS) -/* --- Orbis --- */ -/* Orbis = PS4 */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_S -/* no parsing (not an error) */ -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include - -#define DUK_USE_OS_STRING "orbis" -#elif defined(DUK_F_OPENBSD) -/* --- OpenBSD --- */ -/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include - -#define DUK_USE_OS_STRING "openbsd" -#elif defined(DUK_F_BSD) -/* --- Generic BSD --- */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include - -#define DUK_USE_OS_STRING "bsd" -#elif defined(DUK_F_TOS) -/* --- Atari ST TOS --- */ -#define DUK_USE_DATE_NOW_TIME -#define DUK_USE_DATE_TZO_GMTIME -/* no parsing (not an error) */ -#define DUK_USE_DATE_FMT_STRFTIME -#include - -#define DUK_USE_OS_STRING "tos" - -/* TOS on M68K is always big endian. */ -#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_M68K) -#define DUK_USE_BYTEORDER 3 -#endif -#elif defined(DUK_F_AMIGAOS) -/* --- AmigaOS --- */ -#if defined(DUK_F_M68K) -/* AmigaOS on M68k */ -#define DUK_USE_DATE_NOW_TIME -#define DUK_USE_DATE_TZO_GMTIME -/* no parsing (not an error) */ -#define DUK_USE_DATE_FMT_STRFTIME -#include -#elif defined(DUK_F_PPC) -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#if !defined(UINTPTR_MAX) -#define UINTPTR_MAX UINT_MAX -#endif -#else -#error AmigaOS but not M68K/PPC, not supported now -#endif - -#define DUK_USE_OS_STRING "amigaos" - -/* AmigaOS on M68K or PPC is always big endian. */ -#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) -#define DUK_USE_BYTEORDER 3 -#endif -#elif defined(DUK_F_DURANGO) -/* --- Durango (XboxOne) --- */ -/* Durango = XboxOne - * Configuration is nearly identical to Windows, except for - * DUK_USE_DATE_TZO_WINDOWS. - */ - -/* Initial fix: disable secure CRT related warnings when compiling Duktape - * itself (must be defined before including Windows headers). Don't define - * for user code including duktape.h. - */ -#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif - -/* MSVC does not have sys/param.h */ -#define DUK_USE_DATE_NOW_WINDOWS -#define DUK_USE_DATE_TZO_WINDOWS_NO_DST -/* Note: PRS and FMT are intentionally left undefined for now. This means - * there is no platform specific date parsing/formatting but there is still - * the ISO 8601 standard format. - */ -#if defined(DUK_COMPILING_DUKTAPE) -/* Only include when compiling Duktape to avoid polluting application build - * with a lot of unnecessary defines. - */ -#include -#endif - -#define DUK_USE_OS_STRING "durango" - -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 1 -#endif -#elif defined(DUK_F_WINDOWS) -/* --- Windows --- */ -/* Windows version can't obviously be determined at compile time, - * but _WIN32_WINNT indicates the minimum version targeted: - * - https://msdn.microsoft.com/en-us/library/6sehtctf.aspx - */ - -/* Initial fix: disable secure CRT related warnings when compiling Duktape - * itself (must be defined before including Windows headers). Don't define - * for user code including duktape.h. - */ -#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif - -/* Windows 32-bit and 64-bit are currently the same. */ -/* MSVC does not have sys/param.h */ - -#if defined(DUK_COMPILING_DUKTAPE) -/* Only include when compiling Duktape to avoid polluting application build - * with a lot of unnecessary defines. - */ -#include -#endif - -/* GetSystemTimePreciseAsFileTime() available from Windows 8: - * https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v=vs.85).aspx - */ -#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) || defined(DUK_USE_DATE_NOW_WINDOWS) -/* User forced provider. */ -#else -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602) -#define DUK_USE_DATE_NOW_WINDOWS_SUBMS -#else -#define DUK_USE_DATE_NOW_WINDOWS -#endif -#endif - -#define DUK_USE_DATE_TZO_WINDOWS - -/* Note: PRS and FMT are intentionally left undefined for now. This means - * there is no platform specific date parsing/formatting but there is still - * the ISO 8601 standard format. - */ - -/* QueryPerformanceCounter() may go backwards in Windows XP, so enable for - * Vista and later: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions - */ -#if !defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) && \ - defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) -#define DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC -#endif - -#define DUK_USE_OS_STRING "windows" - -/* On Windows, assume we're little endian. Even Itanium which has a - * configurable endianness runs little endian in Windows. - */ -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 1 -#endif -#elif defined(DUK_F_FLASHPLAYER) -/* --- Flashplayer (Crossbridge) --- */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include - -#define DUK_USE_OS_STRING "flashplayer" - -#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_FLASHPLAYER) -#define DUK_USE_BYTEORDER 1 -#endif -#elif defined(DUK_F_QNX) -/* --- QNX --- */ -#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) -/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ -#define _XOPEN_SOURCE 600 -#define _POSIX_C_SOURCE 200112L -#endif - -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include - -#define DUK_USE_OS_STRING "qnx" -#elif defined(DUK_F_TINSPIRE) -/* --- TI-Nspire --- */ -#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE) -#define _XOPEN_SOURCE /* e.g. strptime */ -#endif - -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include - -#define DUK_USE_OS_STRING "tinspire" -#elif defined(DUK_F_EMSCRIPTEN) -/* --- Emscripten --- */ -#if defined(DUK_COMPILING_DUKTAPE) -#if !defined(_POSIX_C_SOURCE) -#define _POSIX_C_SOURCE 200809L -#endif -#if !defined(_GNU_SOURCE) -#define _GNU_SOURCE /* e.g. getdate_r */ -#endif -#if !defined(_XOPEN_SOURCE) -#define _XOPEN_SOURCE /* e.g. strptime */ -#endif -#endif /* DUK_COMPILING_DUKTAPE */ - -#include -#if defined(DUK_F_BCC) -/* no endian.h */ -#else -#include -#endif /* DUK_F_BCC */ -#include -#include -#include -#include - -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME - -#define DUK_USE_OS_STRING "emscripten" -#elif defined(DUK_F_LINUX) -/* --- Linux --- */ -#if defined(DUK_COMPILING_DUKTAPE) -#if !defined(_POSIX_C_SOURCE) -#define _POSIX_C_SOURCE 200809L -#endif -#if !defined(_GNU_SOURCE) -#define _GNU_SOURCE /* e.g. getdate_r */ -#endif -#if !defined(_XOPEN_SOURCE) -#define _XOPEN_SOURCE /* e.g. strptime */ -#endif -#endif /* DUK_COMPILING_DUKTAPE */ - -#include -#if defined(DUK_F_BCC) -/* no endian.h or stdint.h */ -#else -#include -#include -#endif /* DUK_F_BCC */ -#include -#include -#include - -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME - -#if 0 /* XXX: safe condition? */ -#define DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME -#endif - -#define DUK_USE_OS_STRING "linux" -#elif defined(DUK_F_SUN) -/* --- Solaris --- */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME - -#include -#if defined(DUK_F_OLD_SOLARIS) -/* Old Solaris with no endian.h, stdint.h */ -#define DUK_F_NO_STDINT_H -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 3 -#endif -#else /* DUK_F_OLD_SOLARIS */ -#include -#endif /* DUK_F_OLD_SOLARIS */ - -#include -#include -#include - -#define DUK_USE_OS_STRING "solaris" -#elif defined(DUK_F_AIX) -/* --- AIX --- */ -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 3 -#endif -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include - -#define DUK_USE_OS_STRING "aix" -#elif defined(DUK_F_HPUX) -/* --- HPUX --- */ -#define DUK_F_NO_STDINT_H -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 3 -#endif -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include - -#define DUK_USE_OS_STRING "hpux" -#elif defined(DUK_F_POSIX) -/* --- Generic POSIX --- */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include - -#define DUK_USE_OS_STRING "posix" -#elif defined(DUK_F_CYGWIN) -/* --- Cygwin --- */ -/* don't use strptime() for now */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include - -#define DUK_JMPBUF_TYPE jmp_buf -#define DUK_SETJMP(jb) _setjmp((jb)) -#define DUK_LONGJMP(jb) _longjmp((jb), 1) - -#define DUK_USE_OS_STRING "windows" -#elif defined(DUK_F_UNIX) -/* --- Generic UNIX --- */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#define DUK_USE_OS_STRING "unknown" -#else -/* --- Generic fallback --- */ -/* The most portable current time provider is time(), but it only has a - * one second resolution. - */ -#define DUK_USE_DATE_NOW_TIME - -/* The most portable way to figure out local time offset is gmtime(), - * but it's not thread safe so use with caution. - */ -#define DUK_USE_DATE_TZO_GMTIME - -/* Avoid custom date parsing and formatting for portability. */ -#undef DUK_USE_DATE_PRS_STRPTIME -#undef DUK_USE_DATE_FMT_STRFTIME - -/* Rely on C89 headers only; time.h must be here. */ -#include - -#define DUK_USE_OS_STRING "unknown" -#endif /* autodetect platform */ - -/* Shared includes: C89 */ -#include -#include -#include -#include /* varargs */ -#include -#include /* e.g. ptrdiff_t */ -#include -#include - -/* date.h is omitted, and included per platform */ - -/* Shared includes: stdint.h is C99 */ -#if defined(DUK_F_NO_STDINT_H) -/* stdint.h not available */ -#else -/* Technically C99 (C++11) but found in many systems. On some systems - * __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS must be defined before - * including stdint.h (see above). - */ -#include -#endif - -#if defined(DUK_F_CPP) -#include /* std::exception */ -#endif - -/* - * Architecture autodetection - */ - -#if defined(DUK_F_X86) -/* --- x86 --- */ -#define DUK_USE_ARCH_STRING "x86" -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 1 -#endif -/* XXX: This is technically not guaranteed because it's possible to configure - * an x86 to require aligned accesses with Alignment Check (AC) flag. - */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 1 -#endif -#define DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_X64) -/* --- x64 --- */ -#define DUK_USE_ARCH_STRING "x64" -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 1 -#endif -/* XXX: This is technically not guaranteed because it's possible to configure - * an x86 to require aligned accesses with Alignment Check (AC) flag. - */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 1 -#endif -#undef DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_X32) -/* --- x32 --- */ -#define DUK_USE_ARCH_STRING "x32" -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 1 -#endif -/* XXX: This is technically not guaranteed because it's possible to configure - * an x86 to require aligned accesses with Alignment Check (AC) flag. - */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 1 -#endif -#define DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_ARM32) -/* --- ARM 32-bit --- */ -#define DUK_USE_ARCH_STRING "arm32" -/* Byte order varies, so rely on autodetect. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 4 -#endif -#define DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_ARM64) -/* --- ARM 64-bit --- */ -#define DUK_USE_ARCH_STRING "arm64" -/* Byte order varies, so rely on autodetect. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#undef DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_MIPS32) -/* --- MIPS 32-bit --- */ -#define DUK_USE_ARCH_STRING "mips32" -/* MIPS byte order varies so rely on autodetection. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#define DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_MIPS64) -/* --- MIPS 64-bit --- */ -#define DUK_USE_ARCH_STRING "mips64" -/* MIPS byte order varies so rely on autodetection. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#undef DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_PPC32) -/* --- PowerPC 32-bit --- */ -#define DUK_USE_ARCH_STRING "ppc32" -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 3 -#endif -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#define DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_PPC64) -/* --- PowerPC 64-bit --- */ -#define DUK_USE_ARCH_STRING "ppc64" -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 3 -#endif -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#undef DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_SPARC32) -/* --- SPARC 32-bit --- */ -#define DUK_USE_ARCH_STRING "sparc32" -/* SPARC byte order varies so rely on autodetection. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#define DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_SPARC64) -/* --- SPARC 64-bit --- */ -#define DUK_USE_ARCH_STRING "sparc64" -/* SPARC byte order varies so rely on autodetection. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#undef DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_SUPERH) -/* --- SuperH --- */ -#define DUK_USE_ARCH_STRING "sh" -/* Byte order varies, rely on autodetection. */ -/* Based on 'make checkalign' there are no alignment requirements on - * Linux SH4, but align by 4 is probably a good basic default. - */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 4 -#endif -#define DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_M68K) -/* --- Motorola 68k --- */ -#define DUK_USE_ARCH_STRING "m68k" -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 3 -#endif -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#define DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#elif defined(DUK_F_EMSCRIPTEN) -/* --- Emscripten --- */ -#define DUK_USE_ARCH_STRING "emscripten" -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 1 -#endif -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif -#undef DUK_USE_PACKED_TVAL -#define DUK_F_PACKED_TVAL_PROVIDED -#else -/* --- Generic --- */ -/* These are necessary wild guesses. */ -#define DUK_USE_ARCH_STRING "generic" -/* Rely on autodetection for byte order, alignment, and packed tval. */ -#endif /* autodetect architecture */ - -/* - * Compiler autodetection - */ - -#if defined(DUK_F_CLANG) -/* --- Clang --- */ -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -/* C99 / C++11 and above: rely on va_copy() which is required. */ -#define DUK_VA_COPY(dest,src) va_copy(dest,src) -#else -/* Clang: assume we have __va_copy() in non-C99 mode. */ -#define DUK_VA_COPY(dest,src) __va_copy(dest,src) -#endif - -#define DUK_NORETURN(decl) decl __attribute__((noreturn)) - -#if defined(__clang__) && defined(__has_builtin) -#if __has_builtin(__builtin_unreachable) -#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) -#endif -#endif - -#define DUK_USE_BRANCH_HINTS -#define DUK_LIKELY(x) __builtin_expect((x), 1) -#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -#if defined(__clang__) && defined(__has_builtin) -#if __has_builtin(__builtin_unpredictable) -#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x)) -#endif -#endif - -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -#define DUK_NOINLINE __attribute__((noinline)) -#define DUK_INLINE inline -#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -#endif - -/* DUK_HOT */ -/* DUK_COLD */ - -#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) -/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're - * compiling Duktape or the application. - */ -#if defined(DUK_COMPILING_DUKTAPE) -#define DUK_EXTERNAL_DECL extern __declspec(dllexport) -#define DUK_EXTERNAL __declspec(dllexport) -#else -#define DUK_EXTERNAL_DECL extern __declspec(dllimport) -#define DUK_EXTERNAL should_not_happen -#endif -#if defined(DUK_SINGLE_FILE) -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#else -#define DUK_INTERNAL_DECL extern -#define DUK_INTERNAL /*empty*/ -#endif -#define DUK_LOCAL_DECL static -#define DUK_LOCAL static -#else -#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern -#define DUK_EXTERNAL __attribute__ ((visibility("default"))) -#if defined(DUK_SINGLE_FILE) -#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) -/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and - * Clang. Based on documentation it should suffice to have the attribute - * in the declaration only, but in practice some warnings are generated unless - * the attribute is also applied to the definition. - */ -#define DUK_INTERNAL_DECL static __attribute__ ((unused)) -#define DUK_INTERNAL static __attribute__ ((unused)) -#else -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#endif -#else -#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) -#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern -#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) -#else -#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern -#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) -#endif -#endif -#define DUK_LOCAL_DECL static -#define DUK_LOCAL static -#endif - -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "clang" -#else -#define DUK_USE_COMPILER_STRING "clang" -#endif - -#undef DUK_USE_VARIADIC_MACROS -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -#define DUK_USE_VARIADIC_MACROS -#endif - -#define DUK_USE_UNION_INITIALIZERS - -#undef DUK_USE_FLEX_C99 -#undef DUK_USE_FLEX_ZEROSIZE -#undef DUK_USE_FLEX_ONESIZE -#if defined(DUK_F_C99) -#define DUK_USE_FLEX_C99 -#else -#define DUK_USE_FLEX_ZEROSIZE -#endif - -#undef DUK_USE_GCC_PRAGMAS -#define DUK_USE_PACK_CLANG_ATTR -#elif defined(DUK_F_GCC) -/* --- GCC --- */ -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -/* C99 / C++11 and above: rely on va_copy() which is required. */ -#define DUK_VA_COPY(dest,src) va_copy(dest,src) -#else -/* GCC: assume we have __va_copy() in non-C99 mode. */ -#define DUK_VA_COPY(dest,src) __va_copy(dest,src) -#endif - -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 20500L) -/* since gcc-2.5 */ -#define DUK_NORETURN(decl) decl __attribute__((noreturn)) -#endif - -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) -/* since gcc-4.5 */ -#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) -#endif - -#define DUK_USE_BRANCH_HINTS -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) -/* GCC: test not very accurate; enable only in relatively recent builds - * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) - */ -#define DUK_LIKELY(x) __builtin_expect((x), 1) -#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -#endif -/* XXX: equivalent of clang __builtin_unpredictable? */ - -#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ - defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101) -#define DUK_NOINLINE __attribute__((noinline)) -#define DUK_INLINE inline -#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -#endif - -#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ - defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300) -#define DUK_HOT __attribute__((hot)) -#define DUK_COLD __attribute__((cold)) -#endif - -#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) -/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're - * compiling Duktape or the application. - */ -#if defined(DUK_COMPILING_DUKTAPE) -#define DUK_EXTERNAL_DECL extern __declspec(dllexport) -#define DUK_EXTERNAL __declspec(dllexport) -#else -#define DUK_EXTERNAL_DECL extern __declspec(dllimport) -#define DUK_EXTERNAL should_not_happen -#endif -#if defined(DUK_SINGLE_FILE) -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#else -#define DUK_INTERNAL_DECL extern -#define DUK_INTERNAL /*empty*/ -#endif -#define DUK_LOCAL_DECL static -#define DUK_LOCAL static -#elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000) -#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern -#define DUK_EXTERNAL __attribute__ ((visibility("default"))) -#if defined(DUK_SINGLE_FILE) -#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) -/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and - * Clang. Based on documentation it should suffice to have the attribute - * in the declaration only, but in practice some warnings are generated unless - * the attribute is also applied to the definition. - */ -#define DUK_INTERNAL_DECL static __attribute__ ((unused)) -#define DUK_INTERNAL static __attribute__ ((unused)) -#else -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#endif -#else -#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) -#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern -#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) -#else -#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern -#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) -#endif -#endif -#define DUK_LOCAL_DECL static -#define DUK_LOCAL static -#endif - -#if defined(DUK_F_MINGW) -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "mingw++" -#else -#define DUK_USE_COMPILER_STRING "mingw" -#endif -#else -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "g++" -#else -#define DUK_USE_COMPILER_STRING "gcc" -#endif -#endif - -#undef DUK_USE_VARIADIC_MACROS -#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) -#define DUK_USE_VARIADIC_MACROS -#endif - -#define DUK_USE_UNION_INITIALIZERS - -#undef DUK_USE_FLEX_C99 -#undef DUK_USE_FLEX_ZEROSIZE -#undef DUK_USE_FLEX_ONESIZE -#if defined(DUK_F_C99) -#define DUK_USE_FLEX_C99 -#else -#define DUK_USE_FLEX_ZEROSIZE -#endif - -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40600) -#define DUK_USE_GCC_PRAGMAS -#else -#undef DUK_USE_GCC_PRAGMAS -#endif - -#define DUK_USE_PACK_GCC_ATTR -#elif defined(DUK_F_MSVC) -/* --- MSVC --- */ -/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ -#define DUK_NORETURN(decl) __declspec(noreturn) decl - -/* XXX: DUK_UNREACHABLE for msvc? */ - -#undef DUK_USE_BRANCH_HINTS - -/* XXX: DUK_LIKELY, DUK_UNLIKELY for msvc? */ -/* XXX: DUK_NOINLINE, DUK_INLINE, DUK_ALWAYS_INLINE for msvc? */ - -#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) -/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're - * compiling Duktape or the application. - */ -#if defined(DUK_COMPILING_DUKTAPE) -#define DUK_EXTERNAL_DECL extern __declspec(dllexport) -#define DUK_EXTERNAL __declspec(dllexport) -#else -#define DUK_EXTERNAL_DECL extern __declspec(dllimport) -#define DUK_EXTERNAL should_not_happen -#endif -#if defined(DUK_SINGLE_FILE) -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#else -#define DUK_INTERNAL_DECL extern -#define DUK_INTERNAL /*empty*/ -#endif -#define DUK_LOCAL_DECL static -#define DUK_LOCAL static -#endif - -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "msvc++" -#else -#define DUK_USE_COMPILER_STRING "msvc" -#endif - -#undef DUK_USE_VARIADIC_MACROS -#if defined(DUK_F_C99) -#define DUK_USE_VARIADIC_MACROS -#elif defined(_MSC_VER) && (_MSC_VER >= 1400) -/* VS2005+ should have variadic macros even when they're not C99. */ -#define DUK_USE_VARIADIC_MACROS -#endif - -#undef DUK_USE_UNION_INITIALIZERS -#if defined(_MSC_VER) && (_MSC_VER >= 1800) -/* VS2013+ supports union initializers but there's a bug involving union-inside-struct: - * https://connect.microsoft.com/VisualStudio/feedback/details/805981 - * The bug was fixed (at least) in VS2015 so check for VS2015 for now: - * https://blogs.msdn.microsoft.com/vcblog/2015/07/01/c-compiler-front-end-fixes-in-vs2015/ - * Manually tested using VS2013, CL reports 18.00.31101, so enable for VS2013 too. - */ -#define DUK_USE_UNION_INITIALIZERS -#endif - -#undef DUK_USE_FLEX_C99 -#undef DUK_USE_FLEX_ZEROSIZE -#undef DUK_USE_FLEX_ONESIZE -#if defined(DUK_F_C99) -#define DUK_USE_FLEX_C99 -#else -#define DUK_USE_FLEX_ZEROSIZE -#endif - -#undef DUK_USE_GCC_PRAGMAS - -#define DUK_USE_PACK_MSVC_PRAGMA - -/* These have been tested from VS2008 onwards; may work in older VS versions - * too but not enabled by default. - */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) -#define DUK_NOINLINE __declspec(noinline) -#define DUK_INLINE __inline -#define DUK_ALWAYS_INLINE __forceinline -#endif - -#if defined(_MSC_VER) && (_MSC_VER >= 1900) -#define DUK_SNPRINTF snprintf -#define DUK_VSNPRINTF vsnprintf -#else -/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does - * NOT NUL terminate on truncation, but Duktape code never assumes that. - * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 - */ -#define DUK_SNPRINTF _snprintf -#define DUK_VSNPRINTF _vsnprintf -#endif - -/* Avoid warning when doing DUK_UNREF(some_function). */ -#if defined(_MSC_VER) && (_MSC_VER < 1500) -#pragma warning(disable: 4100 4101 4550 4551) -#define DUK_UNREF(x) -#else -#define DUK_UNREF(x) do { __pragma(warning(suppress:4100 4101 4550 4551)) (x); } while (0) -#endif - -/* Older versions of MSVC don't support the LL/ULL suffix. */ -#define DUK_U64_CONSTANT(x) x##ui64 -#define DUK_I64_CONSTANT(x) x##i64 -#elif defined(DUK_F_EMSCRIPTEN) -/* --- Emscripten --- */ -#define DUK_NORETURN(decl) decl __attribute__((noreturn)) - -#if defined(__clang__) && defined(__has_builtin) -#if __has_builtin(__builtin_unreachable) -#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) -#endif -#endif - -#define DUK_USE_BRANCH_HINTS -#define DUK_LIKELY(x) __builtin_expect((x), 1) -#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -#if defined(__clang__) && defined(__has_builtin) -#if __has_builtin(__builtin_unpredictable) -#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x)) -#endif -#endif - -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -#define DUK_NOINLINE __attribute__((noinline)) -#define DUK_INLINE inline -#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -#endif - -#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern -#define DUK_EXTERNAL __attribute__ ((visibility("default"))) -#if defined(DUK_SINGLE_FILE) -#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) -/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and - * Clang. Based on documentation it should suffice to have the attribute - * in the declaration only, but in practice some warnings are generated unless - * the attribute is also applied to the definition. - */ -#define DUK_INTERNAL_DECL static __attribute__ ((unused)) -#define DUK_INTERNAL static __attribute__ ((unused)) -#else -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#endif -#else -#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) -#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern -#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) -#else -#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern -#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) -#endif -#endif -#define DUK_LOCAL_DECL static -#define DUK_LOCAL static - -#define DUK_USE_COMPILER_STRING "emscripten" - -#undef DUK_USE_VARIADIC_MACROS -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -#define DUK_USE_VARIADIC_MACROS -#endif - -#define DUK_USE_UNION_INITIALIZERS - -#undef DUK_USE_FLEX_C99 -#undef DUK_USE_FLEX_ZEROSIZE -#undef DUK_USE_FLEX_ONESIZE -#if defined(DUK_F_C99) -#define DUK_USE_FLEX_C99 -#else -#define DUK_USE_FLEX_ZEROSIZE -#endif - -#undef DUK_USE_GCC_PRAGMAS -#define DUK_USE_PACK_CLANG_ATTR -#elif defined(DUK_F_TINYC) -/* --- TinyC --- */ -#undef DUK_USE_BRANCH_HINTS - -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "tinyc++" -#else -#define DUK_USE_COMPILER_STRING "tinyc" -#endif - -/* http://bellard.org/tcc/tcc-doc.html#SEC7 */ -#define DUK_USE_VARIADIC_MACROS - -#define DUK_USE_UNION_INITIALIZERS - -/* Most portable, wastes space */ -#define DUK_USE_FLEX_ONESIZE - -/* Most portable, potentially wastes space */ -#define DUK_USE_PACK_DUMMY_MEMBER -#elif defined(DUK_F_VBCC) -/* --- VBCC --- */ -#undef DUK_USE_BRANCH_HINTS - -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "vbcc-c++" -#else -#define DUK_USE_COMPILER_STRING "vbcc" -#endif - -#undef DUK_USE_VARIADIC_MACROS -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -#define DUK_USE_VARIADIC_MACROS -#endif - -/* VBCC supports C99 so check only for C99 for union initializer support. - * Designated union initializers would possibly work even without a C99 check. - */ -#undef DUK_USE_UNION_INITIALIZERS -#if defined(DUK_F_C99) -#define DUK_USE_UNION_INITIALIZERS -#endif - -#define DUK_USE_FLEX_ZEROSIZE -#define DUK_USE_PACK_DUMMY_MEMBER -#elif defined(DUK_F_BCC) -/* --- Bruce's C compiler --- */ -#undef DUK_USE_BRANCH_HINTS - -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "bcc++" -#else -#define DUK_USE_COMPILER_STRING "bcc" -#endif - -/* Most portable */ -#undef DUK_USE_VARIADIC_MACROS - -/* Most portable, wastes space */ -#undef DUK_USE_UNION_INITIALIZERS - -/* Most portable, wastes space */ -#define DUK_USE_FLEX_ONESIZE - -/* Most portable, potentially wastes space */ -#define DUK_USE_PACK_DUMMY_MEMBER - -/* BCC, assume we're on x86. */ -#if !defined(DUK_USE_BYTEORDER) -#define DUK_USE_BYTEORDER 1 -#endif -#else -/* --- Generic --- */ -#undef DUK_USE_BRANCH_HINTS - -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "generic-c++" -#else -#define DUK_USE_COMPILER_STRING "generic" -#endif - -#undef DUK_USE_VARIADIC_MACROS -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -#define DUK_USE_VARIADIC_MACROS -#endif - -/* C++ doesn't have standard designated union initializers ({ .foo = 1 }). */ -#undef DUK_USE_UNION_INITIALIZERS -#if defined(DUK_F_C99) -#define DUK_USE_UNION_INITIALIZERS -#endif - -/* Most portable, wastes space */ -#define DUK_USE_FLEX_ONESIZE - -/* Most portable, potentially wastes space */ -#define DUK_USE_PACK_DUMMY_MEMBER -#endif /* autodetect compiler */ - -/* uclibc */ -#if defined(__UCLIBC__) -#define DUK_F_UCLIBC -#endif - -/* - * Wrapper typedefs and constants for integer types, also sanity check types. - * - * C99 typedefs are quite good but not always available, and we want to avoid - * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for - * all C99 typedefs and Duktape code should only use these typedefs. Type - * detection when C99 is not supported is best effort and may end up detecting - * some types incorrectly. - * - * Pointer sizes are a portability problem: pointers to different types may - * have a different size and function pointers are very difficult to manage - * portably. - * - * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types - * - * Note: there's an interesting corner case when trying to define minimum - * signed integer value constants which leads to the current workaround of - * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt - * for a longer discussion. - * - * Note: avoid typecasts and computations in macro integer constants as they - * can then no longer be used in macro relational expressions (such as - * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on - * being able to compare DUK_SIZE_MAX against a limit. - */ - -/* XXX: add feature options to force basic types from outside? */ - -#if !defined(INT_MAX) -#error INT_MAX not defined -#endif - -/* Check that architecture is two's complement, standard C allows e.g. - * INT_MIN to be -2**31+1 (instead of -2**31). - */ -#if defined(INT_MAX) && defined(INT_MIN) -#if INT_MAX != -(INT_MIN + 1) -#error platform does not seem complement of two -#endif -#else -#error cannot check complement of two -#endif - -/* Pointer size determination based on __WORDSIZE or architecture when - * that's not available. - */ -#if defined(DUK_F_X86) || defined(DUK_F_X32) || \ - defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ - defined(DUK_F_BCC) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \ - ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ - defined(DUK_F_HPUX)) && defined(_ILP32)) || \ - defined(DUK_F_ARM32) -#define DUK_F_32BIT_PTRS -#elif defined(DUK_F_X64) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \ - ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ - defined(DUK_F_HPUX)) && defined(_LP64)) || \ - defined(DUK_F_ARM64) -#define DUK_F_64BIT_PTRS -#else -/* not sure, not needed with C99 anyway */ -#endif - -/* Intermediate define for 'have inttypes.h' */ -#undef DUK_F_HAVE_INTTYPES -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !(defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)) -/* vbcc + AmigaOS has C99 but no inttypes.h */ -#define DUK_F_HAVE_INTTYPES -#elif defined(__cplusplus) && (__cplusplus >= 201103L) -/* C++11 apparently ratified stdint.h */ -#define DUK_F_HAVE_INTTYPES -#endif - -/* Basic integer typedefs and limits, preferably from inttypes.h, otherwise - * through automatic detection. - */ -#if defined(DUK_F_HAVE_INTTYPES) -/* C99 or compatible */ - -#define DUK_F_HAVE_64BIT -#include - -typedef uint8_t duk_uint8_t; -typedef int8_t duk_int8_t; -typedef uint16_t duk_uint16_t; -typedef int16_t duk_int16_t; -typedef uint32_t duk_uint32_t; -typedef int32_t duk_int32_t; -typedef uint64_t duk_uint64_t; -typedef int64_t duk_int64_t; -typedef uint_least8_t duk_uint_least8_t; -typedef int_least8_t duk_int_least8_t; -typedef uint_least16_t duk_uint_least16_t; -typedef int_least16_t duk_int_least16_t; -typedef uint_least32_t duk_uint_least32_t; -typedef int_least32_t duk_int_least32_t; -typedef uint_least64_t duk_uint_least64_t; -typedef int_least64_t duk_int_least64_t; -typedef uint_fast8_t duk_uint_fast8_t; -typedef int_fast8_t duk_int_fast8_t; -typedef uint_fast16_t duk_uint_fast16_t; -typedef int_fast16_t duk_int_fast16_t; -typedef uint_fast32_t duk_uint_fast32_t; -typedef int_fast32_t duk_int_fast32_t; -typedef uint_fast64_t duk_uint_fast64_t; -typedef int_fast64_t duk_int_fast64_t; -typedef uintptr_t duk_uintptr_t; -typedef intptr_t duk_intptr_t; -typedef uintmax_t duk_uintmax_t; -typedef intmax_t duk_intmax_t; - -#define DUK_UINT8_MIN 0 -#define DUK_UINT8_MAX UINT8_MAX -#define DUK_INT8_MIN INT8_MIN -#define DUK_INT8_MAX INT8_MAX -#define DUK_UINT_LEAST8_MIN 0 -#define DUK_UINT_LEAST8_MAX UINT_LEAST8_MAX -#define DUK_INT_LEAST8_MIN INT_LEAST8_MIN -#define DUK_INT_LEAST8_MAX INT_LEAST8_MAX -#define DUK_UINT_FAST8_MIN 0 -#define DUK_UINT_FAST8_MAX UINT_FAST8_MAX -#define DUK_INT_FAST8_MIN INT_FAST8_MIN -#define DUK_INT_FAST8_MAX INT_FAST8_MAX -#define DUK_UINT16_MIN 0 -#define DUK_UINT16_MAX UINT16_MAX -#define DUK_INT16_MIN INT16_MIN -#define DUK_INT16_MAX INT16_MAX -#define DUK_UINT_LEAST16_MIN 0 -#define DUK_UINT_LEAST16_MAX UINT_LEAST16_MAX -#define DUK_INT_LEAST16_MIN INT_LEAST16_MIN -#define DUK_INT_LEAST16_MAX INT_LEAST16_MAX -#define DUK_UINT_FAST16_MIN 0 -#define DUK_UINT_FAST16_MAX UINT_FAST16_MAX -#define DUK_INT_FAST16_MIN INT_FAST16_MIN -#define DUK_INT_FAST16_MAX INT_FAST16_MAX -#define DUK_UINT32_MIN 0 -#define DUK_UINT32_MAX UINT32_MAX -#define DUK_INT32_MIN INT32_MIN -#define DUK_INT32_MAX INT32_MAX -#define DUK_UINT_LEAST32_MIN 0 -#define DUK_UINT_LEAST32_MAX UINT_LEAST32_MAX -#define DUK_INT_LEAST32_MIN INT_LEAST32_MIN -#define DUK_INT_LEAST32_MAX INT_LEAST32_MAX -#define DUK_UINT_FAST32_MIN 0 -#define DUK_UINT_FAST32_MAX UINT_FAST32_MAX -#define DUK_INT_FAST32_MIN INT_FAST32_MIN -#define DUK_INT_FAST32_MAX INT_FAST32_MAX -#define DUK_UINT64_MIN 0 -#define DUK_UINT64_MAX UINT64_MAX -#define DUK_INT64_MIN INT64_MIN -#define DUK_INT64_MAX INT64_MAX -#define DUK_UINT_LEAST64_MIN 0 -#define DUK_UINT_LEAST64_MAX UINT_LEAST64_MAX -#define DUK_INT_LEAST64_MIN INT_LEAST64_MIN -#define DUK_INT_LEAST64_MAX INT_LEAST64_MAX -#define DUK_UINT_FAST64_MIN 0 -#define DUK_UINT_FAST64_MAX UINT_FAST64_MAX -#define DUK_INT_FAST64_MIN INT_FAST64_MIN -#define DUK_INT_FAST64_MAX INT_FAST64_MAX - -#define DUK_UINTPTR_MIN 0 -#define DUK_UINTPTR_MAX UINTPTR_MAX -#define DUK_INTPTR_MIN INTPTR_MIN -#define DUK_INTPTR_MAX INTPTR_MAX - -#define DUK_UINTMAX_MIN 0 -#define DUK_UINTMAX_MAX UINTMAX_MAX -#define DUK_INTMAX_MIN INTMAX_MIN -#define DUK_INTMAX_MAX INTMAX_MAX - -#define DUK_SIZE_MIN 0 -#define DUK_SIZE_MAX SIZE_MAX -#undef DUK_SIZE_MAX_COMPUTED - -#else /* C99 types */ - -/* When C99 types are not available, we use heuristic detection to get - * the basic 8, 16, 32, and (possibly) 64 bit types. The fast/least - * types are then assumed to be exactly the same for now: these could - * be improved per platform but C99 types are very often now available. - * 64-bit types are not available on all platforms; this is OK at least - * on 32-bit platforms. - * - * This detection code is necessarily a bit hacky and can provide typedefs - * and defines that won't work correctly on some exotic platform. - */ - -#if (defined(CHAR_BIT) && (CHAR_BIT == 8)) || \ - (defined(UCHAR_MAX) && (UCHAR_MAX == 255)) -typedef unsigned char duk_uint8_t; -typedef signed char duk_int8_t; -#else -#error cannot detect 8-bit type -#endif - -#if defined(USHRT_MAX) && (USHRT_MAX == 65535UL) -typedef unsigned short duk_uint16_t; -typedef signed short duk_int16_t; -#elif defined(UINT_MAX) && (UINT_MAX == 65535UL) -/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ -typedef unsigned int duk_uint16_t; -typedef signed int duk_int16_t; -#else -#error cannot detect 16-bit type -#endif - -#if defined(UINT_MAX) && (UINT_MAX == 4294967295UL) -typedef unsigned int duk_uint32_t; -typedef signed int duk_int32_t; -#elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295UL) -/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ -typedef unsigned long duk_uint32_t; -typedef signed long duk_int32_t; -#else -#error cannot detect 32-bit type -#endif - -/* 64-bit type detection is a bit tricky. - * - * ULLONG_MAX is a standard define. __LONG_LONG_MAX__ and __ULONG_LONG_MAX__ - * are used by at least GCC (even if system headers don't provide ULLONG_MAX). - * Some GCC variants may provide __LONG_LONG_MAX__ but not __ULONG_LONG_MAX__. - * - * ULL / LL constants are rejected / warned about by some compilers, even if - * the compiler has a 64-bit type and the compiler/system headers provide an - * unsupported constant (ULL/LL)! Try to avoid using ULL / LL constants. - * As a side effect we can only check that e.g. ULONG_MAX is larger than 32 - * bits but can't be sure it is exactly 64 bits. Self tests will catch such - * cases. - */ -#undef DUK_F_HAVE_64BIT -#if !defined(DUK_F_HAVE_64BIT) && defined(ULONG_MAX) -#if (ULONG_MAX > 4294967295UL) -#define DUK_F_HAVE_64BIT -typedef unsigned long duk_uint64_t; -typedef signed long duk_int64_t; -#endif -#endif -#if !defined(DUK_F_HAVE_64BIT) && defined(ULLONG_MAX) -#if (ULLONG_MAX > 4294967295UL) -#define DUK_F_HAVE_64BIT -typedef unsigned long long duk_uint64_t; -typedef signed long long duk_int64_t; -#endif -#endif -#if !defined(DUK_F_HAVE_64BIT) && defined(__ULONG_LONG_MAX__) -#if (__ULONG_LONG_MAX__ > 4294967295UL) -#define DUK_F_HAVE_64BIT -typedef unsigned long long duk_uint64_t; -typedef signed long long duk_int64_t; -#endif -#endif -#if !defined(DUK_F_HAVE_64BIT) && defined(__LONG_LONG_MAX__) -#if (__LONG_LONG_MAX__ > 2147483647L) -#define DUK_F_HAVE_64BIT -typedef unsigned long long duk_uint64_t; -typedef signed long long duk_int64_t; -#endif -#endif -#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MINGW) -#define DUK_F_HAVE_64BIT -typedef unsigned long duk_uint64_t; -typedef signed long duk_int64_t; -#endif -#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MSVC) -#define DUK_F_HAVE_64BIT -typedef unsigned __int64 duk_uint64_t; -typedef signed __int64 duk_int64_t; -#endif -#if !defined(DUK_F_HAVE_64BIT) -/* cannot detect 64-bit type, not always needed so don't error */ -#endif - -typedef duk_uint8_t duk_uint_least8_t; -typedef duk_int8_t duk_int_least8_t; -typedef duk_uint16_t duk_uint_least16_t; -typedef duk_int16_t duk_int_least16_t; -typedef duk_uint32_t duk_uint_least32_t; -typedef duk_int32_t duk_int_least32_t; -typedef duk_uint8_t duk_uint_fast8_t; -typedef duk_int8_t duk_int_fast8_t; -typedef duk_uint16_t duk_uint_fast16_t; -typedef duk_int16_t duk_int_fast16_t; -typedef duk_uint32_t duk_uint_fast32_t; -typedef duk_int32_t duk_int_fast32_t; -#if defined(DUK_F_HAVE_64BIT) -typedef duk_uint64_t duk_uint_least64_t; -typedef duk_int64_t duk_int_least64_t; -typedef duk_uint64_t duk_uint_fast64_t; -typedef duk_int64_t duk_int_fast64_t; -#endif -#if defined(DUK_F_HAVE_64BIT) -typedef duk_uint64_t duk_uintmax_t; -typedef duk_int64_t duk_intmax_t; -#else -typedef duk_uint32_t duk_uintmax_t; -typedef duk_int32_t duk_intmax_t; -#endif - -/* Note: the funny looking computations for signed minimum 16-bit, 32-bit, and - * 64-bit values are intentional as the obvious forms (e.g. -0x80000000L) are - * -not- portable. See code-issues.txt for a detailed discussion. - */ -#define DUK_UINT8_MIN 0UL -#define DUK_UINT8_MAX 0xffUL -#define DUK_INT8_MIN (-0x80L) -#define DUK_INT8_MAX 0x7fL -#define DUK_UINT_LEAST8_MIN 0UL -#define DUK_UINT_LEAST8_MAX 0xffUL -#define DUK_INT_LEAST8_MIN (-0x80L) -#define DUK_INT_LEAST8_MAX 0x7fL -#define DUK_UINT_FAST8_MIN 0UL -#define DUK_UINT_FAST8_MAX 0xffUL -#define DUK_INT_FAST8_MIN (-0x80L) -#define DUK_INT_FAST8_MAX 0x7fL -#define DUK_UINT16_MIN 0UL -#define DUK_UINT16_MAX 0xffffUL -#define DUK_INT16_MIN (-0x7fffL - 1L) -#define DUK_INT16_MAX 0x7fffL -#define DUK_UINT_LEAST16_MIN 0UL -#define DUK_UINT_LEAST16_MAX 0xffffUL -#define DUK_INT_LEAST16_MIN (-0x7fffL - 1L) -#define DUK_INT_LEAST16_MAX 0x7fffL -#define DUK_UINT_FAST16_MIN 0UL -#define DUK_UINT_FAST16_MAX 0xffffUL -#define DUK_INT_FAST16_MIN (-0x7fffL - 1L) -#define DUK_INT_FAST16_MAX 0x7fffL -#define DUK_UINT32_MIN 0UL -#define DUK_UINT32_MAX 0xffffffffUL -#define DUK_INT32_MIN (-0x7fffffffL - 1L) -#define DUK_INT32_MAX 0x7fffffffL -#define DUK_UINT_LEAST32_MIN 0UL -#define DUK_UINT_LEAST32_MAX 0xffffffffUL -#define DUK_INT_LEAST32_MIN (-0x7fffffffL - 1L) -#define DUK_INT_LEAST32_MAX 0x7fffffffL -#define DUK_UINT_FAST32_MIN 0UL -#define DUK_UINT_FAST32_MAX 0xffffffffUL -#define DUK_INT_FAST32_MIN (-0x7fffffffL - 1L) -#define DUK_INT_FAST32_MAX 0x7fffffffL - -/* 64-bit constants. Since LL / ULL constants are not always available, - * use computed values. These values can't be used in preprocessor - * comparisons; flag them as such. - */ -#if defined(DUK_F_HAVE_64BIT) -#define DUK_UINT64_MIN ((duk_uint64_t) 0) -#define DUK_UINT64_MAX ((duk_uint64_t) -1) -#define DUK_INT64_MIN ((duk_int64_t) (~(DUK_UINT64_MAX >> 1))) -#define DUK_INT64_MAX ((duk_int64_t) (DUK_UINT64_MAX >> 1)) -#define DUK_UINT_LEAST64_MIN DUK_UINT64_MIN -#define DUK_UINT_LEAST64_MAX DUK_UINT64_MAX -#define DUK_INT_LEAST64_MIN DUK_INT64_MIN -#define DUK_INT_LEAST64_MAX DUK_INT64_MAX -#define DUK_UINT_FAST64_MIN DUK_UINT64_MIN -#define DUK_UINT_FAST64_MAX DUK_UINT64_MAX -#define DUK_INT_FAST64_MIN DUK_INT64_MIN -#define DUK_INT_FAST64_MAX DUK_INT64_MAX -#define DUK_UINT64_MIN_COMPUTED -#define DUK_UINT64_MAX_COMPUTED -#define DUK_INT64_MIN_COMPUTED -#define DUK_INT64_MAX_COMPUTED -#define DUK_UINT_LEAST64_MIN_COMPUTED -#define DUK_UINT_LEAST64_MAX_COMPUTED -#define DUK_INT_LEAST64_MIN_COMPUTED -#define DUK_INT_LEAST64_MAX_COMPUTED -#define DUK_UINT_FAST64_MIN_COMPUTED -#define DUK_UINT_FAST64_MAX_COMPUTED -#define DUK_INT_FAST64_MIN_COMPUTED -#define DUK_INT_FAST64_MAX_COMPUTED -#endif - -#if defined(DUK_F_HAVE_64BIT) -#define DUK_UINTMAX_MIN DUK_UINT64_MIN -#define DUK_UINTMAX_MAX DUK_UINT64_MAX -#define DUK_INTMAX_MIN DUK_INT64_MIN -#define DUK_INTMAX_MAX DUK_INT64_MAX -#define DUK_UINTMAX_MIN_COMPUTED -#define DUK_UINTMAX_MAX_COMPUTED -#define DUK_INTMAX_MIN_COMPUTED -#define DUK_INTMAX_MAX_COMPUTED -#else -#define DUK_UINTMAX_MIN 0UL -#define DUK_UINTMAX_MAX 0xffffffffUL -#define DUK_INTMAX_MIN (-0x7fffffffL - 1L) -#define DUK_INTMAX_MAX 0x7fffffffL -#endif - -/* This detection is not very reliable. */ -#if defined(DUK_F_32BIT_PTRS) -typedef duk_int32_t duk_intptr_t; -typedef duk_uint32_t duk_uintptr_t; -#define DUK_UINTPTR_MIN DUK_UINT32_MIN -#define DUK_UINTPTR_MAX DUK_UINT32_MAX -#define DUK_INTPTR_MIN DUK_INT32_MIN -#define DUK_INTPTR_MAX DUK_INT32_MAX -#elif defined(DUK_F_64BIT_PTRS) && defined(DUK_F_HAVE_64BIT) -typedef duk_int64_t duk_intptr_t; -typedef duk_uint64_t duk_uintptr_t; -#define DUK_UINTPTR_MIN DUK_UINT64_MIN -#define DUK_UINTPTR_MAX DUK_UINT64_MAX -#define DUK_INTPTR_MIN DUK_INT64_MIN -#define DUK_INTPTR_MAX DUK_INT64_MAX -#define DUK_UINTPTR_MIN_COMPUTED -#define DUK_UINTPTR_MAX_COMPUTED -#define DUK_INTPTR_MIN_COMPUTED -#define DUK_INTPTR_MAX_COMPUTED -#else -#error cannot determine intptr type -#endif - -/* SIZE_MAX may be missing so use an approximate value for it. */ -#undef DUK_SIZE_MAX_COMPUTED -#if !defined(SIZE_MAX) -#define DUK_SIZE_MAX_COMPUTED -#define SIZE_MAX ((size_t) (-1)) -#endif -#define DUK_SIZE_MIN 0 -#define DUK_SIZE_MAX SIZE_MAX - -#endif /* C99 types */ - -/* A few types are assumed to always exist. */ -typedef size_t duk_size_t; -typedef ptrdiff_t duk_ptrdiff_t; - -/* The best type for an "all around int" in Duktape internals is "at least - * 32 bit signed integer" which is most convenient. Same for unsigned type. - * Prefer 'int' when large enough, as it is almost always a convenient type. - */ -#if defined(UINT_MAX) && (UINT_MAX >= 0xffffffffUL) -typedef int duk_int_t; -typedef unsigned int duk_uint_t; -#define DUK_INT_MIN INT_MIN -#define DUK_INT_MAX INT_MAX -#define DUK_UINT_MIN 0 -#define DUK_UINT_MAX UINT_MAX -#else -typedef duk_int_fast32_t duk_int_t; -typedef duk_uint_fast32_t duk_uint_t; -#define DUK_INT_MIN DUK_INT_FAST32_MIN -#define DUK_INT_MAX DUK_INT_FAST32_MAX -#define DUK_UINT_MIN DUK_UINT_FAST32_MIN -#define DUK_UINT_MAX DUK_UINT_FAST32_MAX -#endif - -/* Same as 'duk_int_t' but guaranteed to be a 'fast' variant if this - * distinction matters for the CPU. These types are used mainly in the - * executor where it might really matter. - */ -typedef duk_int_fast32_t duk_int_fast_t; -typedef duk_uint_fast32_t duk_uint_fast_t; -#define DUK_INT_FAST_MIN DUK_INT_FAST32_MIN -#define DUK_INT_FAST_MAX DUK_INT_FAST32_MAX -#define DUK_UINT_FAST_MIN DUK_UINT_FAST32_MIN -#define DUK_UINT_FAST_MAX DUK_UINT_FAST32_MAX - -/* Small integers (16 bits or more) can fall back to the 'int' type, but - * have a typedef so they are marked "small" explicitly. - */ -typedef int duk_small_int_t; -typedef unsigned int duk_small_uint_t; -#define DUK_SMALL_INT_MIN INT_MIN -#define DUK_SMALL_INT_MAX INT_MAX -#define DUK_SMALL_UINT_MIN 0 -#define DUK_SMALL_UINT_MAX UINT_MAX - -/* Fast variants of small integers, again for really fast paths like the - * executor. - */ -typedef duk_int_fast16_t duk_small_int_fast_t; -typedef duk_uint_fast16_t duk_small_uint_fast_t; -#define DUK_SMALL_INT_FAST_MIN DUK_INT_FAST16_MIN -#define DUK_SMALL_INT_FAST_MAX DUK_INT_FAST16_MAX -#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN -#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX - -/* Boolean values are represented with the platform 'unsigned int'. */ -typedef duk_small_uint_t duk_bool_t; -#define DUK_BOOL_MIN DUK_SMALL_INT_MIN -#define DUK_BOOL_MAX DUK_SMALL_INT_MAX - -/* Index values must have at least 32-bit signed range. */ -typedef duk_int_t duk_idx_t; -#define DUK_IDX_MIN DUK_INT_MIN -#define DUK_IDX_MAX DUK_INT_MAX - -/* Unsigned index variant. */ -typedef duk_uint_t duk_uidx_t; -#define DUK_UIDX_MIN DUK_UINT_MIN -#define DUK_UIDX_MAX DUK_UINT_MAX - -/* Array index values, could be exact 32 bits. - * Currently no need for signed duk_arridx_t. - */ -typedef duk_uint_t duk_uarridx_t; -#define DUK_UARRIDX_MIN DUK_UINT_MIN -#define DUK_UARRIDX_MAX DUK_UINT_MAX - -/* Duktape/C function return value, platform int is enough for now to - * represent 0, 1, or negative error code. Must be compatible with - * assigning truth values (e.g. duk_ret_t rc = (foo == bar);). - */ -typedef duk_small_int_t duk_ret_t; -#define DUK_RET_MIN DUK_SMALL_INT_MIN -#define DUK_RET_MAX DUK_SMALL_INT_MAX - -/* Error codes are represented with platform int. High bits are used - * for flags and such, so 32 bits are needed. - */ -typedef duk_int_t duk_errcode_t; -#define DUK_ERRCODE_MIN DUK_INT_MIN -#define DUK_ERRCODE_MAX DUK_INT_MAX - -/* Codepoint type. Must be 32 bits or more because it is used also for - * internal codepoints. The type is signed because negative codepoints - * are used as internal markers (e.g. to mark EOF or missing argument). - * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to - * ensure duk_uint32_t casts back and forth nicely. Almost everything - * else uses the signed one. - */ -typedef duk_int_t duk_codepoint_t; -typedef duk_uint_t duk_ucodepoint_t; -#define DUK_CODEPOINT_MIN DUK_INT_MIN -#define DUK_CODEPOINT_MAX DUK_INT_MAX -#define DUK_UCODEPOINT_MIN DUK_UINT_MIN -#define DUK_UCODEPOINT_MAX DUK_UINT_MAX - -/* IEEE float/double typedef. */ -typedef float duk_float_t; -typedef double duk_double_t; - -/* We're generally assuming that we're working on a platform with a 32-bit - * address space. If DUK_SIZE_MAX is a typecast value (which is necessary - * if SIZE_MAX is missing), the check must be avoided because the - * preprocessor can't do a comparison. - */ -#if !defined(DUK_SIZE_MAX) -#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX -#elif !defined(DUK_SIZE_MAX_COMPUTED) -#if DUK_SIZE_MAX < 0xffffffffUL -/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value - * which seems incorrect if size_t is (at least) an unsigned 32-bit type. - * However, it doesn't seem useful to error out compilation if this is the - * case. - */ -#endif -#endif - -/* Type used in public API declarations and user code. Typedef maps to - * 'struct duk_hthread' like the 'duk_hthread' typedef which is used - * exclusively in internals. - */ -typedef struct duk_hthread duk_context; - -/* Check whether we should use 64-bit integers or not. - * - * Quite incomplete now. Use 64-bit types if detected (C99 or other detection) - * unless they are known to be unreliable. For instance, 64-bit types are - * available on VBCC but seem to misbehave. - */ -#if defined(DUK_F_HAVE_64BIT) && !defined(DUK_F_VBCC) -#define DUK_USE_64BIT_OPS -#else -#undef DUK_USE_64BIT_OPS -#endif - -/* - * Fill-ins for platform, architecture, and compiler - */ - -/* An abort()-like primitive is needed by the default fatal error handler. */ -#if !defined(DUK_ABORT) -#define DUK_ABORT abort -#endif - -#if !defined(DUK_SETJMP) -#define DUK_JMPBUF_TYPE jmp_buf -#define DUK_SETJMP(jb) setjmp((jb)) -#define DUK_LONGJMP(jb) longjmp((jb), 1) -#endif - -#if 0 -/* sigsetjmp() alternative */ -#define DUK_JMPBUF_TYPE sigjmp_buf -#define DUK_SETJMP(jb) sigsetjmp((jb)) -#define DUK_LONGJMP(jb) siglongjmp((jb), 1) -#endif - -/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h - * (which is unfortunately named). May sometimes need replacement, e.g. - * some compilers don't handle zero length or NULL correctly in realloc(). - */ -#if !defined(DUK_ANSI_MALLOC) -#define DUK_ANSI_MALLOC malloc -#endif -#if !defined(DUK_ANSI_REALLOC) -#define DUK_ANSI_REALLOC realloc -#endif -#if !defined(DUK_ANSI_CALLOC) -#define DUK_ANSI_CALLOC calloc -#endif -#if !defined(DUK_ANSI_FREE) -#define DUK_ANSI_FREE free -#endif - -/* ANSI C (various versions) and some implementations require that the - * pointer arguments to memset(), memcpy(), and memmove() be valid values - * even when byte size is 0 (even a NULL pointer is considered invalid in - * this context). Zero-size operations as such are allowed, as long as their - * pointer arguments point to a valid memory area. The DUK_MEMSET(), - * DUK_MEMCPY(), and DUK_MEMMOVE() macros require this same behavior, i.e.: - * (1) pointers must be valid and non-NULL, (2) zero size must otherwise be - * allowed. If these are not fulfilled, a macro wrapper is needed. - * - * http://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 - * http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-October/011065.html - * - * Not sure what's the required behavior when a pointer points just past the - * end of a buffer, which often happens in practice (e.g. zero size memmoves). - * For example, if allocation size is 3, the following pointer would not - * technically point to a valid memory byte: - * - * <-- alloc --> - * | 0 | 1 | 2 | ..... - * ^-- p=3, points after last valid byte (2) - */ -#if !defined(DUK_MEMCPY) -#if defined(DUK_F_UCLIBC) -/* Old uclibcs have a broken memcpy so use memmove instead (this is overly wide - * now on purpose): http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html - */ -#define DUK_MEMCPY memmove -#else -#define DUK_MEMCPY memcpy -#endif -#endif -#if !defined(DUK_MEMMOVE) -#define DUK_MEMMOVE memmove -#endif -#if !defined(DUK_MEMCMP) -#define DUK_MEMCMP memcmp -#endif -#if !defined(DUK_MEMSET) -#define DUK_MEMSET memset -#endif -#if !defined(DUK_STRLEN) -#define DUK_STRLEN strlen -#endif -#if !defined(DUK_STRCMP) -#define DUK_STRCMP strcmp -#endif -#if !defined(DUK_STRNCMP) -#define DUK_STRNCMP strncmp -#endif -#if !defined(DUK_SPRINTF) -#define DUK_SPRINTF sprintf -#endif -#if !defined(DUK_SNPRINTF) -/* snprintf() is technically not part of C89 but usually available. */ -#define DUK_SNPRINTF snprintf -#endif -#if !defined(DUK_VSPRINTF) -#define DUK_VSPRINTF vsprintf -#endif -#if !defined(DUK_VSNPRINTF) -/* vsnprintf() is technically not part of C89 but usually available. */ -#define DUK_VSNPRINTF vsnprintf -#endif -#if !defined(DUK_SSCANF) -#define DUK_SSCANF sscanf -#endif -#if !defined(DUK_VSSCANF) -#define DUK_VSSCANF vsscanf -#endif -#if !defined(DUK_MEMZERO) -#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n)) -#endif - -#if !defined(DUK_DOUBLE_INFINITY) -#undef DUK_USE_COMPUTED_INFINITY -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION < 40600) -/* GCC older than 4.6: avoid overflow warnings related to using INFINITY */ -#define DUK_DOUBLE_INFINITY (__builtin_inf()) -#elif defined(INFINITY) -#define DUK_DOUBLE_INFINITY ((double) INFINITY) -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ - !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) -#define DUK_DOUBLE_INFINITY (1.0 / 0.0) -#else -/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. - * Use a computed infinity (initialized when a heap is created at the - * latest). - */ -#define DUK_USE_COMPUTED_INFINITY -#define DUK_DOUBLE_INFINITY duk_computed_infinity -#endif -#endif - -#if !defined(DUK_DOUBLE_NAN) -#undef DUK_USE_COMPUTED_NAN -#if defined(NAN) -#define DUK_DOUBLE_NAN NAN -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ - !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) -#define DUK_DOUBLE_NAN (0.0 / 0.0) -#else -/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. - * In MSVC (VS2010 Express) (0.0 / 0.0) results in a compile error. - * Use a computed NaN (initialized when a heap is created at the - * latest). - */ -#define DUK_USE_COMPUTED_NAN -#define DUK_DOUBLE_NAN duk_computed_nan -#endif -#endif - -/* Many platforms are missing fpclassify() and friends, so use replacements - * if necessary. The replacement constants (FP_NAN etc) can be anything but - * match Linux constants now. - */ -#undef DUK_USE_REPL_FPCLASSIFY -#undef DUK_USE_REPL_SIGNBIT -#undef DUK_USE_REPL_ISFINITE -#undef DUK_USE_REPL_ISNAN -#undef DUK_USE_REPL_ISINF - -/* Complex condition broken into separate parts. */ -#undef DUK_F_USE_REPL_ALL -#if !(defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) && \ - defined(FP_SUBNORMAL) && defined(FP_NORMAL)) -/* Missing some obvious constants. */ -#define DUK_F_USE_REPL_ALL -#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC) -/* VBCC is missing the built-ins even in C99 mode (perhaps a header issue). */ -#define DUK_F_USE_REPL_ALL -#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_M68K) -/* AmigaOS + M68K seems to have math issues even when using GCC cross - * compilation. Use replacements for all AmigaOS versions on M68K - * regardless of compiler. - */ -#define DUK_F_USE_REPL_ALL -#elif defined(DUK_F_FREEBSD) && defined(DUK_F_CLANG) -/* Placeholder fix for (detection is wider than necessary): - * http://llvm.org/bugs/show_bug.cgi?id=17788 - */ -#define DUK_F_USE_REPL_ALL -#elif defined(DUK_F_UCLIBC) -/* At least some uclibc versions have broken floating point math. For - * example, fpclassify() can incorrectly classify certain NaN formats. - * To be safe, use replacements. - */ -#define DUK_F_USE_REPL_ALL -#elif defined(DUK_F_AIX) -/* Older versions may be missing isnan(), etc. */ -#define DUK_F_USE_REPL_ALL -#endif - -#if defined(DUK_F_USE_REPL_ALL) -#define DUK_USE_REPL_FPCLASSIFY -#define DUK_USE_REPL_SIGNBIT -#define DUK_USE_REPL_ISFINITE -#define DUK_USE_REPL_ISNAN -#define DUK_USE_REPL_ISINF -#define DUK_FPCLASSIFY duk_repl_fpclassify -#define DUK_SIGNBIT duk_repl_signbit -#define DUK_ISFINITE duk_repl_isfinite -#define DUK_ISNAN duk_repl_isnan -#define DUK_ISINF duk_repl_isinf -#define DUK_FP_NAN 0 -#define DUK_FP_INFINITE 1 -#define DUK_FP_ZERO 2 -#define DUK_FP_SUBNORMAL 3 -#define DUK_FP_NORMAL 4 -#else -#define DUK_FPCLASSIFY fpclassify -#define DUK_SIGNBIT signbit -#define DUK_ISFINITE isfinite -#define DUK_ISNAN isnan -#define DUK_ISINF isinf -#define DUK_FP_NAN FP_NAN -#define DUK_FP_INFINITE FP_INFINITE -#define DUK_FP_ZERO FP_ZERO -#define DUK_FP_SUBNORMAL FP_SUBNORMAL -#define DUK_FP_NORMAL FP_NORMAL -#endif - -#if defined(DUK_F_USE_REPL_ALL) -#undef DUK_F_USE_REPL_ALL -#endif - -/* These functions don't currently need replacement but are wrapped for - * completeness. Because these are used as function pointers, they need - * to be defined as concrete C functions (not macros). - */ -#if !defined(DUK_FABS) -#define DUK_FABS fabs -#endif -#if !defined(DUK_FLOOR) -#define DUK_FLOOR floor -#endif -#if !defined(DUK_CEIL) -#define DUK_CEIL ceil -#endif -#if !defined(DUK_FMOD) -#define DUK_FMOD fmod -#endif -#if !defined(DUK_POW) -#define DUK_POW pow -#endif -#if !defined(DUK_ACOS) -#define DUK_ACOS acos -#endif -#if !defined(DUK_ASIN) -#define DUK_ASIN asin -#endif -#if !defined(DUK_ATAN) -#define DUK_ATAN atan -#endif -#if !defined(DUK_ATAN2) -#define DUK_ATAN2 atan2 -#endif -#if !defined(DUK_SIN) -#define DUK_SIN sin -#endif -#if !defined(DUK_COS) -#define DUK_COS cos -#endif -#if !defined(DUK_TAN) -#define DUK_TAN tan -#endif -#if !defined(DUK_EXP) -#define DUK_EXP exp -#endif -#if !defined(DUK_LOG) -#define DUK_LOG log -#endif -#if !defined(DUK_SQRT) -#define DUK_SQRT sqrt -#endif - -/* The functions below exist only in C99/C++11 or later and need a workaround - * for platforms that don't include them. MSVC isn't detected as C99, but - * these functions also exist in MSVC 2013 and later so include a clause for - * that too. Android doesn't have log2; disable all of these for Android. - */ -#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \ - !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT) -#if !defined(DUK_CBRT) -#define DUK_CBRT cbrt -#endif -#if !defined(DUK_LOG2) -#define DUK_LOG2 log2 -#endif -#if !defined(DUK_LOG10) -#define DUK_LOG10 log10 -#endif -#if !defined(DUK_TRUNC) -#define DUK_TRUNC trunc -#endif -#endif /* DUK_F_C99 etc */ - -/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, - * see test-bug-netbsd-math-pow.js. MinGW has similar (but different) - * issues, see test-bug-mingw-math-issues.js. Enable pow() workarounds - * for these targets. - */ -#undef DUK_USE_POW_WORKAROUNDS -#if defined(DUK_F_NETBSD) || defined(DUK_F_MINGW) -#define DUK_USE_POW_WORKAROUNDS -#endif - -/* Similar workarounds for atan2() semantics issues. MinGW issues are - * documented in test-bug-mingw-math-issues.js. - */ -#undef DUK_USE_ATAN2_WORKAROUNDS -#if defined(DUK_F_MINGW) -#define DUK_USE_ATAN2_WORKAROUNDS -#endif - -/* Rely as little as possible on compiler behavior for NaN comparison, - * signed zero handling, etc. Currently never activated but may be needed - * for broken compilers. - */ -#undef DUK_USE_PARANOID_MATH - -/* There was a curious bug where test-bi-date-canceling.js would fail e.g. - * on 64-bit Ubuntu, gcc-4.8.1, -m32, and no -std=c99. Some date computations - * using doubles would be optimized which then broke some corner case tests. - * The problem goes away by adding 'volatile' to the datetime computations. - * Not sure what the actual triggering conditions are, but using this on - * non-C99 systems solves the known issues and has relatively little cost - * on other platforms. - */ -#undef DUK_USE_PARANOID_DATE_COMPUTATION -#if !defined(DUK_F_C99) -#define DUK_USE_PARANOID_DATE_COMPUTATION -#endif - -/* - * Byte order and double memory layout detection - * - * Endianness detection is a major portability hassle because the macros - * and headers are not standardized. There's even variance across UNIX - * platforms. Even with "standard" headers, details like underscore count - * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used - * (Crossbridge has a single underscore, for instance). - * - * The checks below are structured with this in mind: several approaches are - * used, and at the end we check if any of them worked. This allows generic - * approaches to be tried first, and platform/compiler specific hacks tried - * last. As a last resort, the user can force a specific endianness, as it's - * not likely that automatic detection will work on the most exotic platforms. - * - * Duktape supports little and big endian machines. There's also support - * for a hybrid used by some ARM machines where integers are little endian - * but IEEE double values use a mixed order (12345678 -> 43218765). This - * byte order for doubles is referred to as "mixed endian". - */ - -/* GCC and Clang provide endianness defines as built-in predefines, with - * leading and trailing double underscores (e.g. __BYTE_ORDER__). See - * output of "make gccpredefs" and "make clangpredefs". Clang doesn't - * seem to provide __FLOAT_WORD_ORDER__; assume not mixed endian for clang. - * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html - */ -#if !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) -#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#define DUK_USE_BYTEORDER 1 -#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) -#define DUK_USE_BYTEORDER 2 -#elif !defined(__FLOAT_WORD_ORDER__) -/* Float word order not known, assume not a hybrid. */ -#define DUK_USE_BYTEORDER 1 -#else -/* Byte order is little endian but cannot determine IEEE double word order. */ -#endif /* float word order */ -#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) -#define DUK_USE_BYTEORDER 3 -#elif !defined(__FLOAT_WORD_ORDER__) -/* Float word order not known, assume not a hybrid. */ -#define DUK_USE_BYTEORDER 3 -#else -/* Byte order is big endian but cannot determine IEEE double word order. */ -#endif /* float word order */ -#else -/* Cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit - * integer ordering and is not relevant. - */ -#endif /* integer byte order */ -#endif /* !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) */ - -/* More or less standard endianness predefines provided by header files. - * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER - * will be big endian, see: http://lists.mysql.com/internals/443. - * On some platforms some defines may be present with an empty value which - * causes comparisons to fail: https://github.com/svaarala/duktape/issues/453. - */ -#if !defined(DUK_USE_BYTEORDER) -#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ - defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ - defined(__LITTLE_ENDIAN__) -#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) -#define DUK_USE_BYTEORDER 1 -#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) -#define DUK_USE_BYTEORDER 2 -#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) -/* Float word order not known, assume not a hybrid. */ -#define DUK_USE_BYTEORDER 1 -#else -/* Byte order is little endian but cannot determine IEEE double word order. */ -#endif /* float word order */ -#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ - defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ - defined(__BIG_ENDIAN__) -#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) -#define DUK_USE_BYTEORDER 3 -#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) -/* Float word order not known, assume not a hybrid. */ -#define DUK_USE_BYTEORDER 3 -#else -/* Byte order is big endian but cannot determine IEEE double word order. */ -#endif /* float word order */ -#else -/* Cannot determine byte order. */ -#endif /* integer byte order */ -#endif /* !defined(DUK_USE_BYTEORDER) */ - -/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: - * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - > 24) | \ - ((((duk_uint32_t) (x)) >> 8) & 0xff00UL) | \ - ((((duk_uint32_t) (x)) << 8) & 0xff0000UL) | \ - (((duk_uint32_t) (x)) << 24)) -#endif -#if !defined(DUK_BSWAP16) -#define DUK_BSWAP16(x) \ - ((duk_uint16_t) (x) >> 8) | \ - ((duk_uint16_t) (x) << 8) -#endif - -/* DUK_USE_VARIADIC_MACROS: required from compilers, so no fill-in. */ -/* DUK_USE_UNION_INITIALIZERS: required from compilers, so no fill-in. */ - -#if !(defined(DUK_USE_FLEX_C99) || defined(DUK_USE_FLEX_ZEROSIZE) || defined(DUK_USE_FLEX_ONESIZE)) -#if defined(DUK_F_C99) -#define DUK_USE_FLEX_C99 -#else -#define DUK_USE_FLEX_ZEROSIZE /* Not standard but common enough */ -#endif -#endif - -#if !(defined(DUK_USE_PACK_GCC_ATTR) || defined(DUK_USE_PACK_CLANG_ATTR) || \ - defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_DUMMY_MEMBER)) -#define DUK_USE_PACK_DUMMY_MEMBER -#endif - -#if 0 /* not defined by default */ -#undef DUK_USE_GCC_PRAGMAS -#endif - -#if !defined(DUK_U64_CONSTANT) -#define DUK_U64_CONSTANT(x) x##ULL -#endif -#if !defined(DUK_I64_CONSTANT) -#define DUK_I64_CONSTANT(x) x##LL -#endif - -/* Workaround for GH-323: avoid inlining control when compiling from - * multiple sources, as it causes compiler portability trouble. - */ -#if !defined(DUK_SINGLE_FILE) -#undef DUK_NOINLINE -#undef DUK_INLINE -#undef DUK_ALWAYS_INLINE -#define DUK_NOINLINE /*nop*/ -#define DUK_INLINE /*nop*/ -#define DUK_ALWAYS_INLINE /*nop*/ -#endif - -/* - * Check whether or not a packed duk_tval representation is possible. - * What's basically required is that pointers are 32-bit values - * (sizeof(void *) == 4). Best effort check, not always accurate. - * If guess goes wrong, crashes may result; self tests also verify - * the guess. - */ - -/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */ -#if !defined(DUK_F_PACKED_TVAL_PROVIDED) -#undef DUK_F_PACKED_TVAL_POSSIBLE - -/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */ -#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) -#if (DUK_UINTPTR_MAX <= 0xffffffffUL) -#define DUK_F_PACKED_TVAL_POSSIBLE -#endif -#endif - -/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */ -#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) -#if (DUK_UINTPTR_MAX <= 0xffffffffUL) -#define DUK_F_PACKED_TVAL_POSSIBLE -#endif -#endif - -/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */ -#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED) -#if (DUK_SIZE_MAX <= 0xffffffffUL) -#define DUK_F_PACKED_TVAL_POSSIBLE -#endif -#endif - -#undef DUK_USE_PACKED_TVAL -#if defined(DUK_F_PACKED_TVAL_POSSIBLE) -#define DUK_USE_PACKED_TVAL -#endif - -#undef DUK_F_PACKED_TVAL_POSSIBLE -#endif /* DUK_F_PACKED_TVAL_PROVIDED */ -/* Object property allocation layout has implications for memory and code - * footprint and generated code size/speed. The best layout also depends - * on whether the platform has alignment requirements or benefits from - * having mostly aligned accesses. - */ -#undef DUK_USE_HOBJECT_LAYOUT_1 -#undef DUK_USE_HOBJECT_LAYOUT_2 -#undef DUK_USE_HOBJECT_LAYOUT_3 -#if (DUK_USE_ALIGN_BY == 1) -/* On platforms without any alignment issues, layout 1 is preferable - * because it compiles to slightly less code and provides direct access - * to property keys. - */ -#define DUK_USE_HOBJECT_LAYOUT_1 -#else -/* On other platforms use layout 2, which requires some padding but - * is a bit more natural than layout 3 in ordering the entries. Layout - * 3 is currently not used. - */ -#define DUK_USE_HOBJECT_LAYOUT_2 -#endif - -/* GCC/clang inaccurate math would break compliance and probably duk_tval, - * so refuse to compile. Relax this if -ffast-math is tested to work. - */ -#if defined(__FAST_MATH__) -#error __FAST_MATH__ defined, refusing to compile -#endif - -/* - * Autogenerated defaults - */ - -#define DUK_USE_ARRAY_BUILTIN -#define DUK_USE_ARRAY_FASTPATH -#define DUK_USE_ARRAY_PROP_FASTPATH -#undef DUK_USE_ASSERTIONS -#define DUK_USE_AUGMENT_ERROR_CREATE -#define DUK_USE_AUGMENT_ERROR_THROW -#define DUK_USE_AVOID_PLATFORM_FUNCPTRS -#define DUK_USE_BASE64_FASTPATH -#define DUK_USE_BOOLEAN_BUILTIN -#define DUK_USE_BUFFEROBJECT_SUPPORT -#undef DUK_USE_BUFLEN16 -#define DUK_USE_BYTECODE_DUMP_SUPPORT -#define DUK_USE_CACHE_ACTIVATION -#define DUK_USE_CACHE_CATCHER -#define DUK_USE_CALLSTACK_LIMIT 10000 -#define DUK_USE_COMMONJS_MODULES -#define DUK_USE_COMPILER_RECLIMIT 2500 -#define DUK_USE_COROUTINE_SUPPORT -#undef DUK_USE_CPP_EXCEPTIONS -#undef DUK_USE_DATAPTR16 -#undef DUK_USE_DATAPTR_DEC16 -#undef DUK_USE_DATAPTR_ENC16 -#define DUK_USE_DATE_BUILTIN -#undef DUK_USE_DATE_FORMAT_STRING -#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET -#undef DUK_USE_DATE_GET_NOW -#undef DUK_USE_DATE_PARSE_STRING -#undef DUK_USE_DATE_PRS_GETDATE -#undef DUK_USE_DEBUG -#undef DUK_USE_DEBUGGER_DUMPHEAP -#undef DUK_USE_DEBUGGER_INSPECT -#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT -#undef DUK_USE_DEBUGGER_SUPPORT -#define DUK_USE_DEBUGGER_THROW_NOTIFY -#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE -#define DUK_USE_DEBUG_BUFSIZE 65536L -#define DUK_USE_DEBUG_LEVEL 0 -#undef DUK_USE_DEBUG_WRITE -#define DUK_USE_DOUBLE_LINKED_HEAP -#define DUK_USE_DUKTAPE_BUILTIN -#define DUK_USE_ENCODING_BUILTINS -#define DUK_USE_ERRCREATE -#define DUK_USE_ERRTHROW -#define DUK_USE_ES6 -#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY -#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -#define DUK_USE_ES6_PROXY -#define DUK_USE_ES6_REGEXP_SYNTAX -#define DUK_USE_ES6_UNICODE_ESCAPE -#define DUK_USE_ES7 -#define DUK_USE_ES7_EXP_OPERATOR -#define DUK_USE_ES8 -#define DUK_USE_ES9 -#define DUK_USE_ESBC_LIMITS -#define DUK_USE_ESBC_MAX_BYTES 2147418112L -#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L -#undef DUK_USE_EXEC_FUN_LOCAL -#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK -#undef DUK_USE_EXEC_PREFER_SIZE -#define DUK_USE_EXEC_REGCONST_OPTIMIZE -#undef DUK_USE_EXEC_TIMEOUT_CHECK -#undef DUK_USE_EXPLICIT_NULL_INIT -#undef DUK_USE_EXTSTR_FREE -#undef DUK_USE_EXTSTR_INTERN_CHECK -#undef DUK_USE_FASTINT -#define DUK_USE_FAST_REFCOUNT_DEFAULT -#undef DUK_USE_FATAL_HANDLER -#define DUK_USE_FATAL_MAXLEN 128 -#define DUK_USE_FINALIZER_SUPPORT -#undef DUK_USE_FINALIZER_TORTURE -#undef DUK_USE_FUNCPTR16 -#undef DUK_USE_FUNCPTR_DEC16 -#undef DUK_USE_FUNCPTR_ENC16 -#define DUK_USE_FUNCTION_BUILTIN -#define DUK_USE_FUNC_FILENAME_PROPERTY -#define DUK_USE_FUNC_NAME_PROPERTY -#undef DUK_USE_GC_TORTURE -#undef DUK_USE_GET_MONOTONIC_TIME -#undef DUK_USE_GET_RANDOM_DOUBLE -#undef DUK_USE_GLOBAL_BINDING -#define DUK_USE_GLOBAL_BUILTIN -#undef DUK_USE_HEAPPTR16 -#undef DUK_USE_HEAPPTR_DEC16 -#undef DUK_USE_HEAPPTR_ENC16 -#define DUK_USE_HEX_FASTPATH -#define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2 -#define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9 -#define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16 -#define DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR 8 -#define DUK_USE_HOBJECT_ENTRY_MINGROW_ADD 16 -#define DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR 8 -#define DUK_USE_HOBJECT_HASH_PART -#define DUK_USE_HOBJECT_HASH_PROP_LIMIT 8 -#define DUK_USE_HSTRING_ARRIDX -#define DUK_USE_HSTRING_CLEN -#undef DUK_USE_HSTRING_EXTDATA -#define DUK_USE_HSTRING_LAZY_CLEN -#define DUK_USE_HTML_COMMENTS -#define DUK_USE_IDCHAR_FASTPATH -#undef DUK_USE_INJECT_HEAP_ALLOC_ERROR -#undef DUK_USE_INTERRUPT_COUNTER -#undef DUK_USE_INTERRUPT_DEBUG_FIXUP -#define DUK_USE_JC -#define DUK_USE_JSON_BUILTIN -#define DUK_USE_JSON_DECNUMBER_FASTPATH -#define DUK_USE_JSON_DECSTRING_FASTPATH -#define DUK_USE_JSON_DEC_RECLIMIT 1000 -#define DUK_USE_JSON_EATWHITE_FASTPATH -#define DUK_USE_JSON_ENC_RECLIMIT 1000 -#define DUK_USE_JSON_QUOTESTRING_FASTPATH -#undef DUK_USE_JSON_STRINGIFY_FASTPATH -#define DUK_USE_JSON_SUPPORT -#define DUK_USE_JX -#define DUK_USE_LEXER_SLIDING_WINDOW -#undef DUK_USE_LIGHTFUNC_BUILTINS -#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 -#define DUK_USE_MATH_BUILTIN -#define DUK_USE_NATIVE_CALL_RECLIMIT 1000 -#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER -#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER -#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT -#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY -#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY -#define DUK_USE_NONSTD_FUNC_STMT -#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 -#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT -#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT -#define DUK_USE_NUMBER_BUILTIN -#define DUK_USE_OBJECT_BUILTIN -#undef DUK_USE_OBJSIZES16 -#undef DUK_USE_PARANOID_ERRORS -#define DUK_USE_PC2LINE -#define DUK_USE_PERFORMANCE_BUILTIN -#undef DUK_USE_PREFER_SIZE -#undef DUK_USE_PROMISE_BUILTIN -#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS -#undef DUK_USE_REFCOUNT16 -#define DUK_USE_REFCOUNT32 -#define DUK_USE_REFERENCE_COUNTING -#define DUK_USE_REFLECT_BUILTIN -#define DUK_USE_REGEXP_CANON_BITMAP -#undef DUK_USE_REGEXP_CANON_WORKAROUND -#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 -#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 -#define DUK_USE_REGEXP_SUPPORT -#undef DUK_USE_ROM_GLOBAL_CLONE -#undef DUK_USE_ROM_GLOBAL_INHERIT -#undef DUK_USE_ROM_OBJECTS -#define DUK_USE_ROM_PTRCOMP_FIRST 63488L -#undef DUK_USE_ROM_STRINGS -#define DUK_USE_SECTION_B -#undef DUK_USE_SELF_TESTS -#define DUK_USE_SHEBANG_COMMENTS -#undef DUK_USE_SHUFFLE_TORTURE -#define DUK_USE_SOURCE_NONBMP -#undef DUK_USE_STRHASH16 -#undef DUK_USE_STRHASH_DENSE -#define DUK_USE_STRHASH_SKIP_SHIFT 5 -#define DUK_USE_STRICT_DECL -#undef DUK_USE_STRICT_UTF8_SOURCE -#define DUK_USE_STRING_BUILTIN -#undef DUK_USE_STRLEN16 -#define DUK_USE_STRTAB_GROW_LIMIT 17 -#define DUK_USE_STRTAB_MAXSIZE 268435456L -#define DUK_USE_STRTAB_MINSIZE 1024 -#undef DUK_USE_STRTAB_PTRCOMP -#define DUK_USE_STRTAB_RESIZE_CHECK_MASK 255 -#define DUK_USE_STRTAB_SHRINK_LIMIT 6 -#undef DUK_USE_STRTAB_TORTURE -#undef DUK_USE_SYMBOL_BUILTIN -#define DUK_USE_TAILCALL -#define DUK_USE_TARGET_INFO "unknown" -#define DUK_USE_TRACEBACKS -#define DUK_USE_TRACEBACK_DEPTH 10 -#define DUK_USE_USER_DECLARE() /* no user declarations */ -#define DUK_USE_VALSTACK_GROW_SHIFT 2 -#define DUK_USE_VALSTACK_LIMIT 1000000L -#define DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT 2 -#define DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT 4 -#undef DUK_USE_VALSTACK_UNSAFE -#define DUK_USE_VERBOSE_ERRORS -#define DUK_USE_VERBOSE_EXECUTOR_ERRORS -#define DUK_USE_VOLUNTARY_GC -#define DUK_USE_ZERO_BUFFER_DATA - -/* - * You may add overriding #define/#undef directives below for - * customization. You of course cannot un-#include or un-typedef - * anything; these require direct changes above. - */ - -/* __OVERRIDE_DEFINES__ */ - -/* - * Date provider selection - * - * User may define DUK_USE_DATE_GET_NOW() etc directly, in which case we'll - * rely on an external provider. If this is not done, revert to previous - * behavior and use Unix/Windows built-in provider. - */ - -#if defined(DUK_COMPILING_DUKTAPE) - -#if defined(DUK_USE_DATE_GET_NOW) -/* External provider already defined. */ -#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) -#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday() -#elif defined(DUK_USE_DATE_NOW_TIME) -#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time() -#elif defined(DUK_USE_DATE_NOW_WINDOWS) -#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows() -#elif defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) -#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows_subms() -#else -#error no provider for DUK_USE_DATE_GET_NOW() -#endif - -#if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) -/* External provider already defined. */ -#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) -#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) -#elif defined(DUK_USE_DATE_TZO_WINDOWS) -#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) -#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) -#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d)) -#else -#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() -#endif - -#if defined(DUK_USE_DATE_PARSE_STRING) -/* External provider already defined. */ -#elif defined(DUK_USE_DATE_PRS_STRPTIME) -#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_strptime((ctx), (str)) -#elif defined(DUK_USE_DATE_PRS_GETDATE) -#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_getdate((ctx), (str)) -#else -/* No provider for DUK_USE_DATE_PARSE_STRING(), fall back to ISO 8601 only. */ -#endif - -#if defined(DUK_USE_DATE_FORMAT_STRING) -/* External provider already defined. */ -#elif defined(DUK_USE_DATE_FMT_STRFTIME) -#define DUK_USE_DATE_FORMAT_STRING(ctx,parts,tzoffset,flags) \ - duk_bi_date_format_parts_strftime((ctx), (parts), (tzoffset), (flags)) -#else -/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */ -#endif - -#if defined(DUK_USE_GET_MONOTONIC_TIME) -/* External provider already defined. */ -#elif defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME) -#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_clock_gettime() -#elif defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) -#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_windows_qpc() -#else -/* No provider for DUK_USE_GET_MONOTONIC_TIME(), fall back to DUK_USE_DATE_GET_NOW(). */ -#endif - -#endif /* DUK_COMPILING_DUKTAPE */ - -/* - * Checks for legacy feature options (DUK_OPT_xxx) - */ - -#if defined(DUK_OPT_ASSERTIONS) -#error unsupported legacy feature option DUK_OPT_ASSERTIONS used -#endif -#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT) -#error unsupported legacy feature option DUK_OPT_BUFFEROBJECT_SUPPORT used -#endif -#if defined(DUK_OPT_BUFLEN16) -#error unsupported legacy feature option DUK_OPT_BUFLEN16 used -#endif -#if defined(DUK_OPT_DATAPTR16) -#error unsupported legacy feature option DUK_OPT_DATAPTR16 used -#endif -#if defined(DUK_OPT_DATAPTR_DEC16) -#error unsupported legacy feature option DUK_OPT_DATAPTR_DEC16 used -#endif -#if defined(DUK_OPT_DATAPTR_ENC16) -#error unsupported legacy feature option DUK_OPT_DATAPTR_ENC16 used -#endif -#if defined(DUK_OPT_DDDPRINT) -#error unsupported legacy feature option DUK_OPT_DDDPRINT used -#endif -#if defined(DUK_OPT_DDPRINT) -#error unsupported legacy feature option DUK_OPT_DDPRINT used -#endif -#if defined(DUK_OPT_DEBUG) -#error unsupported legacy feature option DUK_OPT_DEBUG used -#endif -#if defined(DUK_OPT_DEBUGGER_DUMPHEAP) -#error unsupported legacy feature option DUK_OPT_DEBUGGER_DUMPHEAP used -#endif -#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING) -#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_LOGGING used -#endif -#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT) -#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_PRINTALERT used -#endif -#if defined(DUK_OPT_DEBUGGER_SUPPORT) -#error unsupported legacy feature option DUK_OPT_DEBUGGER_SUPPORT used -#endif -#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE) -#error unsupported legacy feature option DUK_OPT_DEBUGGER_TRANSPORT_TORTURE used -#endif -#if defined(DUK_OPT_DEBUG_BUFSIZE) -#error unsupported legacy feature option DUK_OPT_DEBUG_BUFSIZE used -#endif -#if defined(DUK_OPT_DECLARE) -#error unsupported legacy feature option DUK_OPT_DECLARE used -#endif -#if defined(DUK_OPT_DEEP_C_STACK) -#error unsupported legacy feature option DUK_OPT_DEEP_C_STACK used -#endif -#if defined(DUK_OPT_DLL_BUILD) -#error unsupported legacy feature option DUK_OPT_DLL_BUILD used -#endif -#if defined(DUK_OPT_DPRINT) -#error unsupported legacy feature option DUK_OPT_DPRINT used -#endif -#if defined(DUK_OPT_DPRINT_COLORS) -#error unsupported legacy feature option DUK_OPT_DPRINT_COLORS used -#endif -#if defined(DUK_OPT_DPRINT_RDTSC) -#error unsupported legacy feature option DUK_OPT_DPRINT_RDTSC used -#endif -#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK) -#error unsupported legacy feature option DUK_OPT_EXEC_TIMEOUT_CHECK used -#endif -#if defined(DUK_OPT_EXTERNAL_STRINGS) -#error unsupported legacy feature option DUK_OPT_EXTERNAL_STRINGS used -#endif -#if defined(DUK_OPT_EXTSTR_FREE) -#error unsupported legacy feature option DUK_OPT_EXTSTR_FREE used -#endif -#if defined(DUK_OPT_EXTSTR_INTERN_CHECK) -#error unsupported legacy feature option DUK_OPT_EXTSTR_INTERN_CHECK used -#endif -#if defined(DUK_OPT_FASTINT) -#error unsupported legacy feature option DUK_OPT_FASTINT used -#endif -#if defined(DUK_OPT_FORCE_ALIGN) -#error unsupported legacy feature option DUK_OPT_FORCE_ALIGN used -#endif -#if defined(DUK_OPT_FORCE_BYTEORDER) -#error unsupported legacy feature option DUK_OPT_FORCE_BYTEORDER used -#endif -#if defined(DUK_OPT_FUNCPTR16) -#error unsupported legacy feature option DUK_OPT_FUNCPTR16 used -#endif -#if defined(DUK_OPT_FUNCPTR_DEC16) -#error unsupported legacy feature option DUK_OPT_FUNCPTR_DEC16 used -#endif -#if defined(DUK_OPT_FUNCPTR_ENC16) -#error unsupported legacy feature option DUK_OPT_FUNCPTR_ENC16 used -#endif -#if defined(DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY) -#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY used -#endif -#if defined(DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY) -#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY used -#endif -#if defined(DUK_OPT_GC_TORTURE) -#error unsupported legacy feature option DUK_OPT_GC_TORTURE used -#endif -#if defined(DUK_OPT_HAVE_CUSTOM_H) -#error unsupported legacy feature option DUK_OPT_HAVE_CUSTOM_H used -#endif -#if defined(DUK_OPT_HEAPPTR16) -#error unsupported legacy feature option DUK_OPT_HEAPPTR16 used -#endif -#if defined(DUK_OPT_HEAPPTR_DEC16) -#error unsupported legacy feature option DUK_OPT_HEAPPTR_DEC16 used -#endif -#if defined(DUK_OPT_HEAPPTR_ENC16) -#error unsupported legacy feature option DUK_OPT_HEAPPTR_ENC16 used -#endif -#if defined(DUK_OPT_INTERRUPT_COUNTER) -#error unsupported legacy feature option DUK_OPT_INTERRUPT_COUNTER used -#endif -#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH) -#error unsupported legacy feature option DUK_OPT_JSON_STRINGIFY_FASTPATH used -#endif -#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) -#error unsupported legacy feature option DUK_OPT_LIGHTFUNC_BUILTINS used -#endif -#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) -#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY used -#endif -#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY) -#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY used -#endif -#if defined(DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT) -#error unsupported legacy feature option DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT used -#endif -#if defined(DUK_OPT_NO_AUGMENT_ERRORS) -#error unsupported legacy feature option DUK_OPT_NO_AUGMENT_ERRORS used -#endif -#if defined(DUK_OPT_NO_BROWSER_LIKE) -#error unsupported legacy feature option DUK_OPT_NO_BROWSER_LIKE used -#endif -#if defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT) -#error unsupported legacy feature option DUK_OPT_NO_BUFFEROBJECT_SUPPORT used -#endif -#if defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT) -#error unsupported legacy feature option DUK_OPT_NO_BYTECODE_DUMP_SUPPORT used -#endif -#if defined(DUK_OPT_NO_COMMONJS_MODULES) -#error unsupported legacy feature option DUK_OPT_NO_COMMONJS_MODULES used -#endif -#if defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY) -#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY used -#endif -#if defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF) -#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF used -#endif -#if defined(DUK_OPT_NO_ES6_PROXY) -#error unsupported legacy feature option DUK_OPT_NO_ES6_PROXY used -#endif -#if defined(DUK_OPT_NO_FILE_IO) -#error unsupported legacy feature option DUK_OPT_NO_FILE_IO used -#endif -#if defined(DUK_OPT_NO_FUNC_STMT) -#error unsupported legacy feature option DUK_OPT_NO_FUNC_STMT used -#endif -#if defined(DUK_OPT_NO_JC) -#error unsupported legacy feature option DUK_OPT_NO_JC used -#endif -#if defined(DUK_OPT_NO_JSONC) -#error unsupported legacy feature option DUK_OPT_NO_JSONC used -#endif -#if defined(DUK_OPT_NO_JSONX) -#error unsupported legacy feature option DUK_OPT_NO_JSONX used -#endif -#if defined(DUK_OPT_NO_JX) -#error unsupported legacy feature option DUK_OPT_NO_JX used -#endif -#if defined(DUK_OPT_NO_MARK_AND_SWEEP) -#error unsupported legacy feature option DUK_OPT_NO_MARK_AND_SWEEP used -#endif -#if defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE) -#error unsupported legacy feature option DUK_OPT_NO_MS_STRINGTABLE_RESIZE used -#endif -#if defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) -#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT used -#endif -#if defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) -#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER used -#endif -#if defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER) -#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER used -#endif -#if defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT) -#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT used -#endif -#if defined(DUK_OPT_NO_NONSTD_FUNC_STMT) -#error unsupported legacy feature option DUK_OPT_NO_NONSTD_FUNC_STMT used -#endif -#if defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029) -#error unsupported legacy feature option DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029 used -#endif -#if defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT) -#error unsupported legacy feature option DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT used -#endif -#if defined(DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY) -#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY used -#endif -#if defined(DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF) -#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF used -#endif -#if defined(DUK_OPT_NO_OCTAL_SUPPORT) -#error unsupported legacy feature option DUK_OPT_NO_OCTAL_SUPPORT used -#endif -#if defined(DUK_OPT_NO_PACKED_TVAL) -#error unsupported legacy feature option DUK_OPT_NO_PACKED_TVAL used -#endif -#if defined(DUK_OPT_NO_PC2LINE) -#error unsupported legacy feature option DUK_OPT_NO_PC2LINE used -#endif -#if defined(DUK_OPT_NO_REFERENCE_COUNTING) -#error unsupported legacy feature option DUK_OPT_NO_REFERENCE_COUNTING used -#endif -#if defined(DUK_OPT_NO_REGEXP_SUPPORT) -#error unsupported legacy feature option DUK_OPT_NO_REGEXP_SUPPORT used -#endif -#if defined(DUK_OPT_NO_SECTION_B) -#error unsupported legacy feature option DUK_OPT_NO_SECTION_B used -#endif -#if defined(DUK_OPT_NO_SOURCE_NONBMP) -#error unsupported legacy feature option DUK_OPT_NO_SOURCE_NONBMP used -#endif -#if defined(DUK_OPT_NO_STRICT_DECL) -#error unsupported legacy feature option DUK_OPT_NO_STRICT_DECL used -#endif -#if defined(DUK_OPT_NO_TRACEBACKS) -#error unsupported legacy feature option DUK_OPT_NO_TRACEBACKS used -#endif -#if defined(DUK_OPT_NO_VERBOSE_ERRORS) -#error unsupported legacy feature option DUK_OPT_NO_VERBOSE_ERRORS used -#endif -#if defined(DUK_OPT_NO_VOLUNTARY_GC) -#error unsupported legacy feature option DUK_OPT_NO_VOLUNTARY_GC used -#endif -#if defined(DUK_OPT_NO_ZERO_BUFFER_DATA) -#error unsupported legacy feature option DUK_OPT_NO_ZERO_BUFFER_DATA used -#endif -#if defined(DUK_OPT_OBJSIZES16) -#error unsupported legacy feature option DUK_OPT_OBJSIZES16 used -#endif -#if defined(DUK_OPT_PANIC_HANDLER) -#error unsupported legacy feature option DUK_OPT_PANIC_HANDLER used -#endif -#if defined(DUK_OPT_REFCOUNT16) -#error unsupported legacy feature option DUK_OPT_REFCOUNT16 used -#endif -#if defined(DUK_OPT_SEGFAULT_ON_PANIC) -#error unsupported legacy feature option DUK_OPT_SEGFAULT_ON_PANIC used -#endif -#if defined(DUK_OPT_SELF_TESTS) -#error unsupported legacy feature option DUK_OPT_SELF_TESTS used -#endif -#if defined(DUK_OPT_SETJMP) -#error unsupported legacy feature option DUK_OPT_SETJMP used -#endif -#if defined(DUK_OPT_SHUFFLE_TORTURE) -#error unsupported legacy feature option DUK_OPT_SHUFFLE_TORTURE used -#endif -#if defined(DUK_OPT_SIGSETJMP) -#error unsupported legacy feature option DUK_OPT_SIGSETJMP used -#endif -#if defined(DUK_OPT_STRHASH16) -#error unsupported legacy feature option DUK_OPT_STRHASH16 used -#endif -#if defined(DUK_OPT_STRICT_UTF8_SOURCE) -#error unsupported legacy feature option DUK_OPT_STRICT_UTF8_SOURCE used -#endif -#if defined(DUK_OPT_STRLEN16) -#error unsupported legacy feature option DUK_OPT_STRLEN16 used -#endif -#if defined(DUK_OPT_STRTAB_CHAIN) -#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN used -#endif -#if defined(DUK_OPT_STRTAB_CHAIN_SIZE) -#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN_SIZE used -#endif -#if defined(DUK_OPT_TARGET_INFO) -#error unsupported legacy feature option DUK_OPT_TARGET_INFO used -#endif -#if defined(DUK_OPT_TRACEBACK_DEPTH) -#error unsupported legacy feature option DUK_OPT_TRACEBACK_DEPTH used -#endif -#if defined(DUK_OPT_UNDERSCORE_SETJMP) -#error unsupported legacy feature option DUK_OPT_UNDERSCORE_SETJMP used -#endif -#if defined(DUK_OPT_USER_INITJS) -#error unsupported legacy feature option DUK_OPT_USER_INITJS used -#endif - -/* - * Checks for config option consistency (DUK_USE_xxx) - */ - -#if defined(DUK_USE_32BIT_PTRS) -#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS -#endif -#if defined(DUK_USE_ALIGN_4) -#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4 -#endif -#if defined(DUK_USE_ALIGN_8) -#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8 -#endif -#if defined(DUK_USE_BROWSER_LIKE) -#error unsupported config option used (option has been removed): DUK_USE_BROWSER_LIKE -#endif -#if defined(DUK_USE_BUILTIN_INITJS) -#error unsupported config option used (option has been removed): DUK_USE_BUILTIN_INITJS -#endif -#if defined(DUK_USE_BYTEORDER_FORCED) -#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED -#endif -#if defined(DUK_USE_DATAPTR_DEC16) && !defined(DUK_USE_DATAPTR16) -#error config option DUK_USE_DATAPTR_DEC16 requires option DUK_USE_DATAPTR16 (which is missing) -#endif -#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16) -#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing) -#endif -#if defined(DUK_USE_DDDPRINT) -#error unsupported config option used (option has been removed): DUK_USE_DDDPRINT -#endif -#if defined(DUK_USE_DDPRINT) -#error unsupported config option used (option has been removed): DUK_USE_DDPRINT -#endif -#if defined(DUK_USE_DEBUGGER_FWD_LOGGING) -#error unsupported config option used (option has been removed): DUK_USE_DEBUGGER_FWD_LOGGING -#endif -#if defined(DUK_USE_DEBUGGER_FWD_PRINTALERT) -#error unsupported config option used (option has been removed): DUK_USE_DEBUGGER_FWD_PRINTALERT -#endif -#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER) -#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing) -#endif -#if defined(DUK_USE_DEEP_C_STACK) -#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK -#endif -#if defined(DUK_USE_DOUBLE_BE) -#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_BE -#endif -#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_LE) -#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_LE (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_ME) -#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_LE) -#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_LE -#endif -#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_BE) -#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_BE (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_ME) -#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_ME) -#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_ME -#endif -#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_LE) -#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_LE (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE) -#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined) -#endif -#if defined(DUK_USE_DPRINT) -#error unsupported config option used (option has been removed): DUK_USE_DPRINT -#endif -#if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG) -#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing) -#endif -#if defined(DUK_USE_DPRINT_COLORS) -#error unsupported config option used (option has been removed): DUK_USE_DPRINT_COLORS -#endif -#if defined(DUK_USE_DPRINT_RDTSC) -#error unsupported config option used (option has been removed): DUK_USE_DPRINT_RDTSC -#endif -#if defined(DUK_USE_ES6_REGEXP_BRACES) -#error unsupported config option used (option has been removed): DUK_USE_ES6_REGEXP_BRACES -#endif -#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS) -#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing) -#endif -#if defined(DUK_USE_ESBC_MAX_LINENUMBER) && !defined(DUK_USE_ESBC_LIMITS) -#error config option DUK_USE_ESBC_MAX_LINENUMBER requires option DUK_USE_ESBC_LIMITS (which is missing) -#endif -#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) && !defined(DUK_USE_INTERRUPT_COUNTER) -#error config option DUK_USE_EXEC_TIMEOUT_CHECK requires option DUK_USE_INTERRUPT_COUNTER (which is missing) -#endif -#if defined(DUK_USE_EXTSTR_FREE) && !defined(DUK_USE_HSTRING_EXTDATA) -#error config option DUK_USE_EXTSTR_FREE requires option DUK_USE_HSTRING_EXTDATA (which is missing) -#endif -#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA) -#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing) -#endif -#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_64BIT_OPS) -#error config option DUK_USE_FASTINT requires option DUK_USE_64BIT_OPS (which is missing) -#endif -#if defined(DUK_USE_FILE_IO) -#error unsupported config option used (option has been removed): DUK_USE_FILE_IO -#endif -#if defined(DUK_USE_FULL_TVAL) -#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL -#endif -#if defined(DUK_USE_FUNCPTR_DEC16) && !defined(DUK_USE_FUNCPTR16) -#error config option DUK_USE_FUNCPTR_DEC16 requires option DUK_USE_FUNCPTR16 (which is missing) -#endif -#if defined(DUK_USE_FUNCPTR_ENC16) && !defined(DUK_USE_FUNCPTR16) -#error config option DUK_USE_FUNCPTR_ENC16 requires option DUK_USE_FUNCPTR16 (which is missing) -#endif -#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS) -#error unsupported config option used (option has been removed): DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS -#endif -#if defined(DUK_USE_HEAPPTR16) && defined(DUK_USE_DEBUG) -#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined) -#endif -#if defined(DUK_USE_HEAPPTR_DEC16) && !defined(DUK_USE_HEAPPTR16) -#error config option DUK_USE_HEAPPTR_DEC16 requires option DUK_USE_HEAPPTR16 (which is missing) -#endif -#if defined(DUK_USE_HEAPPTR_ENC16) && !defined(DUK_USE_HEAPPTR16) -#error config option DUK_USE_HEAPPTR_ENC16 requires option DUK_USE_HEAPPTR16 (which is missing) -#endif -#if defined(DUK_USE_INTEGER_BE) -#error unsupported config option used (option has been removed): DUK_USE_INTEGER_BE -#endif -#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_LE) -#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_LE (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_ME) -#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_ME (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_LE) -#error unsupported config option used (option has been removed): DUK_USE_INTEGER_LE -#endif -#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_BE) -#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_BE (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_ME) -#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_ME (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_ME) -#error unsupported config option used (option has been removed): DUK_USE_INTEGER_ME -#endif -#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_LE) -#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_LE (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) -#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) -#endif -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) -#error unsupported config option used (option has been removed): DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE -#endif -#if defined(DUK_USE_MARK_AND_SWEEP) -#error unsupported config option used (option has been removed): DUK_USE_MARK_AND_SWEEP -#endif -#if defined(DUK_USE_MATH_FMAX) -#error unsupported config option used (option has been removed): DUK_USE_MATH_FMAX -#endif -#if defined(DUK_USE_MATH_FMIN) -#error unsupported config option used (option has been removed): DUK_USE_MATH_FMIN -#endif -#if defined(DUK_USE_MATH_ROUND) -#error unsupported config option used (option has been removed): DUK_USE_MATH_ROUND -#endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -#error unsupported config option used (option has been removed): DUK_USE_MS_STRINGTABLE_RESIZE -#endif -#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE) -#error unsupported config option used (option has been removed): DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE -#endif -#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST) -#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST -#endif -#if defined(DUK_USE_OCTAL_SUPPORT) -#error unsupported config option used (option has been removed): DUK_USE_OCTAL_SUPPORT -#endif -#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) -#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE -#endif -#if defined(DUK_USE_PANIC_ABORT) -#error unsupported config option used (option has been removed): DUK_USE_PANIC_ABORT -#endif -#if defined(DUK_USE_PANIC_EXIT) -#error unsupported config option used (option has been removed): DUK_USE_PANIC_EXIT -#endif -#if defined(DUK_USE_PANIC_HANDLER) -#error unsupported config option used (option has been removed): DUK_USE_PANIC_HANDLER -#endif -#if defined(DUK_USE_PANIC_SEGFAULT) -#error unsupported config option used (option has been removed): DUK_USE_PANIC_SEGFAULT -#endif -#if defined(DUK_USE_POW_NETBSD_WORKAROUND) -#error unsupported config option used (option has been removed): DUK_USE_POW_NETBSD_WORKAROUND -#endif -#if defined(DUK_USE_RDTSC) -#error unsupported config option used (option has been removed): DUK_USE_RDTSC -#endif -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) -#error unsupported config option used (option has been removed): DUK_USE_REFZERO_FINALIZER_TORTURE -#endif -#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) -#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) -#endif -#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_OBJECTS) -#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_OBJECTS (which is missing) -#endif -#if defined(DUK_USE_ROM_GLOBAL_CLONE) && defined(DUK_USE_ROM_GLOBAL_INHERIT) -#error config option DUK_USE_ROM_GLOBAL_CLONE conflicts with option DUK_USE_ROM_GLOBAL_INHERIT (which is also defined) -#endif -#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_STRINGS) -#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_STRINGS (which is missing) -#endif -#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_OBJECTS) -#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_OBJECTS (which is missing) -#endif -#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && defined(DUK_USE_ROM_GLOBAL_CLONE) -#error config option DUK_USE_ROM_GLOBAL_INHERIT conflicts with option DUK_USE_ROM_GLOBAL_CLONE (which is also defined) -#endif -#if defined(DUK_USE_ROM_OBJECTS) && !defined(DUK_USE_ROM_STRINGS) -#error config option DUK_USE_ROM_OBJECTS requires option DUK_USE_ROM_STRINGS (which is missing) -#endif -#if defined(DUK_USE_ROM_STRINGS) && !defined(DUK_USE_ROM_OBJECTS) -#error config option DUK_USE_ROM_STRINGS requires option DUK_USE_ROM_OBJECTS (which is missing) -#endif -#if defined(DUK_USE_SETJMP) -#error unsupported config option used (option has been removed): DUK_USE_SETJMP -#endif -#if defined(DUK_USE_SIGSETJMP) -#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP -#endif -#if defined(DUK_USE_STRTAB_CHAIN) -#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN -#endif -#if defined(DUK_USE_STRTAB_CHAIN_SIZE) -#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN_SIZE -#endif -#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) -#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) -#endif -#if defined(DUK_USE_STRTAB_PROBE) -#error unsupported config option used (option has been removed): DUK_USE_STRTAB_PROBE -#endif -#if defined(DUK_USE_STRTAB_PTRCOMP) && !defined(DUK_USE_HEAPPTR16) -#error config option DUK_USE_STRTAB_PTRCOMP requires option DUK_USE_HEAPPTR16 (which is missing) -#endif -#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) -#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) -#endif -#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) -#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#endif -#if defined(DUK_USE_UNDERSCORE_SETJMP) -#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP -#endif -#if defined(DUK_USE_USER_INITJS) -#error unsupported config option used (option has been removed): DUK_USE_USER_INITJS -#endif - -#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus) -#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler -#endif - -/* - * Convert DUK_USE_BYTEORDER, from whatever source, into currently used - * internal defines. If detection failed, #error out. - */ - -#if defined(DUK_USE_BYTEORDER) -#if (DUK_USE_BYTEORDER == 1) -#define DUK_USE_INTEGER_LE -#define DUK_USE_DOUBLE_LE -#elif (DUK_USE_BYTEORDER == 2) -#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */ -#define DUK_USE_DOUBLE_ME -#elif (DUK_USE_BYTEORDER == 3) -#define DUK_USE_INTEGER_BE -#define DUK_USE_DOUBLE_BE -#else -#error unsupported: byte order invalid -#endif /* byte order */ -#else -#error unsupported: byte order detection failed -#endif /* defined(DUK_USE_BYTEORDER) */ - -#endif /* DUK_CONFIG_H_INCLUDED */ diff --git a/dep/duktape/duktape/duk_source_meta.json b/dep/duktape/duktape/duk_source_meta.json deleted file mode 100644 index b80eb1e950f..00000000000 --- a/dep/duktape/duktape/duk_source_meta.json +++ /dev/null @@ -1,1821 +0,0 @@ -{ - "comment": "Metadata for Duktape sources", - "duk_version_string": "2.2.0", - "type": "duk_source_meta", - "line_map": [ - { - "original_line": 1, - "combined_line": 134, - "original_file": "duk_replacements.c" - }, - { - "original_line": 1, - "combined_line": 144, - "original_file": "duk_internal.h" - }, - { - "original_line": 1, - "combined_line": 189, - "original_file": "duk_dblunion.h" - }, - { - "original_line": 1, - "combined_line": 614, - "original_file": "duk_replacements.h" - }, - { - "original_line": 1, - "combined_line": 645, - "original_file": "duk_jmpbuf.h" - }, - { - "original_line": 1, - "combined_line": 671, - "original_file": "duk_exception.h" - }, - { - "original_line": 1, - "combined_line": 691, - "original_file": "duk_forwdecl.h" - }, - { - "original_line": 1, - "combined_line": 825, - "original_file": "duk_tval.h" - }, - { - "original_line": 1, - "combined_line": 1459, - "original_file": "duk_builtins.h" - }, - { - "original_line": 51, - "combined_line": 2227, - "original_file": "duk_internal.h" - }, - { - "original_line": 1, - "combined_line": 2230, - "original_file": "duk_util.h" - }, - { - "original_line": 1, - "combined_line": 2796, - "original_file": "duk_strings.h" - }, - { - "original_line": 1, - "combined_line": 2965, - "original_file": "duk_js_bytecode.h" - }, - { - "original_line": 1, - "combined_line": 3449, - "original_file": "duk_lexer.h" - }, - { - "original_line": 1, - "combined_line": 3889, - "original_file": "duk_js_compiler.h" - }, - { - "original_line": 1, - "combined_line": 4117, - "original_file": "duk_regexp.h" - }, - { - "original_line": 1, - "combined_line": 4203, - "original_file": "duk_heaphdr.h" - }, - { - "original_line": 1, - "combined_line": 4510, - "original_file": "duk_refcount.h" - }, - { - "original_line": 1, - "combined_line": 5237, - "original_file": "duk_api_internal.h" - }, - { - "original_line": 1, - "combined_line": 5587, - "original_file": "duk_hstring.h" - }, - { - "original_line": 1, - "combined_line": 5827, - "original_file": "duk_hobject.h" - }, - { - "original_line": 1, - "combined_line": 6827, - "original_file": "duk_hcompfunc.h" - }, - { - "original_line": 1, - "combined_line": 7099, - "original_file": "duk_hnatfunc.h" - }, - { - "original_line": 1, - "combined_line": 7133, - "original_file": "duk_hboundfunc.h" - }, - { - "original_line": 1, - "combined_line": 7175, - "original_file": "duk_hbufobj.h" - }, - { - "original_line": 1, - "combined_line": 7319, - "original_file": "duk_hthread.h" - }, - { - "original_line": 1, - "combined_line": 7742, - "original_file": "duk_harray.h" - }, - { - "original_line": 1, - "combined_line": 7791, - "original_file": "duk_henv.h" - }, - { - "original_line": 1, - "combined_line": 7841, - "original_file": "duk_hbuffer.h" - }, - { - "original_line": 1, - "combined_line": 8168, - "original_file": "duk_hproxy.h" - }, - { - "original_line": 1, - "combined_line": 8196, - "original_file": "duk_heap.h" - }, - { - "original_line": 1, - "combined_line": 8884, - "original_file": "duk_debugger.h" - }, - { - "original_line": 1, - "combined_line": 9037, - "original_file": "duk_debug.h" - }, - { - "original_line": 1, - "combined_line": 9223, - "original_file": "duk_error.h" - }, - { - "original_line": 1, - "combined_line": 9742, - "original_file": "duk_unicode.h" - }, - { - "original_line": 1, - "combined_line": 10033, - "original_file": "duk_json.h" - }, - { - "original_line": 1, - "combined_line": 10103, - "original_file": "duk_js.h" - }, - { - "original_line": 1, - "combined_line": 10215, - "original_file": "duk_numconv.h" - }, - { - "original_line": 1, - "combined_line": 10317, - "original_file": "duk_bi_protos.h" - }, - { - "original_line": 1, - "combined_line": 10400, - "original_file": "duk_selftest.h" - }, - { - "original_line": 82, - "combined_line": 10416, - "original_file": "duk_internal.h" - }, - { - "original_line": 10, - "combined_line": 10419, - "original_file": "duk_replacements.c" - }, - { - "original_line": 1, - "combined_line": 10493, - "original_file": "duk_debug_macros.c" - }, - { - "original_line": 1, - "combined_line": 10585, - "original_file": "duk_builtins.c" - }, - { - "original_line": 1, - "combined_line": 11389, - "original_file": "duk_error_macros.c" - }, - { - "original_line": 1, - "combined_line": 11537, - "original_file": "duk_unicode_support.c" - }, - { - "original_line": 1, - "combined_line": 12720, - "original_file": "duk_util_misc.c" - }, - { - "original_line": 1, - "combined_line": 13126, - "original_file": "duk_hobject_class.c" - }, - { - "original_line": 1, - "combined_line": 13256, - "original_file": "duk_alloc_default.c" - }, - { - "original_line": 1, - "combined_line": 13291, - "original_file": "duk_api_buffer.c" - }, - { - "original_line": 1, - "combined_line": 13362, - "original_file": "duk_api_bytecode.c" - }, - { - "original_line": 1, - "combined_line": 14136, - "original_file": "duk_api_call.c" - }, - { - "original_line": 1, - "combined_line": 14656, - "original_file": "duk_api_codec.c" - }, - { - "original_line": 1, - "combined_line": 15314, - "original_file": "duk_api_compile.c" - }, - { - "original_line": 1, - "combined_line": 15486, - "original_file": "duk_api_debug.c" - }, - { - "original_line": 1, - "combined_line": 15745, - "original_file": "duk_api_heap.c" - }, - { - "original_line": 1, - "combined_line": 15951, - "original_file": "duk_api_inspect.c" - }, - { - "original_line": 1, - "combined_line": 16197, - "original_file": "duk_api_memory.c" - }, - { - "original_line": 1, - "combined_line": 16278, - "original_file": "duk_api_object.c" - }, - { - "original_line": 1, - "combined_line": 17110, - "original_file": "duk_api_stack.c" - }, - { - "original_line": 1, - "combined_line": 23708, - "original_file": "duk_api_string.c" - }, - { - "original_line": 1, - "combined_line": 24085, - "original_file": "duk_api_time.c" - }, - { - "original_line": 1, - "combined_line": 24196, - "original_file": "duk_bi_array.c" - }, - { - "original_line": 1, - "combined_line": 25816, - "original_file": "duk_bi_boolean.c" - }, - { - "original_line": 1, - "combined_line": 25886, - "original_file": "duk_bi_buffer.c" - }, - { - "original_line": 1, - "combined_line": 28808, - "original_file": "duk_bi_date.c" - }, - { - "original_line": 1, - "combined_line": 30582, - "original_file": "duk_bi_date_unix.c" - }, - { - "original_line": 1, - "combined_line": 30912, - "original_file": "duk_bi_date_windows.c" - }, - { - "original_line": 1, - "combined_line": 31096, - "original_file": "duk_bi_duktape.c" - }, - { - "original_line": 1, - "combined_line": 31255, - "original_file": "duk_bi_encoding.c" - }, - { - "original_line": 1, - "combined_line": 31792, - "original_file": "duk_bi_error.c" - }, - { - "original_line": 1, - "combined_line": 32185, - "original_file": "duk_bi_function.c" - }, - { - "original_line": 1, - "combined_line": 32628, - "original_file": "duk_bi_global.c" - }, - { - "original_line": 1, - "combined_line": 33357, - "original_file": "duk_bi_json.c" - }, - { - "original_line": 1, - "combined_line": 36620, - "original_file": "duk_bi_math.c" - }, - { - "original_line": 1, - "combined_line": 37139, - "original_file": "duk_bi_number.c" - }, - { - "original_line": 1, - "combined_line": 37380, - "original_file": "duk_bi_object.c" - }, - { - "original_line": 1, - "combined_line": 38186, - "original_file": "duk_bi_performance.c" - }, - { - "original_line": 1, - "combined_line": 38218, - "original_file": "duk_bi_pointer.c" - }, - { - "original_line": 1, - "combined_line": 38294, - "original_file": "duk_bi_promise.c" - }, - { - "original_line": 1, - "combined_line": 38339, - "original_file": "duk_bi_proxy.c" - }, - { - "original_line": 1, - "combined_line": 38435, - "original_file": "duk_bi_reflect.c" - }, - { - "original_line": 1, - "combined_line": 38533, - "original_file": "duk_bi_regexp.c" - }, - { - "original_line": 1, - "combined_line": 38760, - "original_file": "duk_bi_string.c" - }, - { - "original_line": 1, - "combined_line": 40315, - "original_file": "duk_bi_symbol.c" - }, - { - "original_line": 1, - "combined_line": 40486, - "original_file": "duk_bi_thread.c" - }, - { - "original_line": 1, - "combined_line": 40799, - "original_file": "duk_bi_thrower.c" - }, - { - "original_line": 1, - "combined_line": 40809, - "original_file": "duk_debug_fixedbuffer.c" - }, - { - "original_line": 1, - "combined_line": 40879, - "original_file": "duk_debug_vsnprintf.c" - }, - { - "original_line": 1, - "combined_line": 41928, - "original_file": "duk_debugger.c" - }, - { - "original_line": 1, - "combined_line": 44836, - "original_file": "duk_error_augment.c" - }, - { - "original_line": 1, - "combined_line": 45400, - "original_file": "duk_error_longjmp.c" - }, - { - "original_line": 1, - "combined_line": 45507, - "original_file": "duk_error_misc.c" - }, - { - "original_line": 1, - "combined_line": 45682, - "original_file": "duk_error_throw.c" - }, - { - "original_line": 1, - "combined_line": 45845, - "original_file": "duk_hbuffer_alloc.c" - }, - { - "original_line": 1, - "combined_line": 45978, - "original_file": "duk_hbuffer_ops.c" - }, - { - "original_line": 2, - "combined_line": 46056, - "original_file": "duk_hbufobj_misc.c" - }, - { - "original_line": 1, - "combined_line": 46076, - "original_file": "duk_heap_alloc.c" - }, - { - "original_line": 1, - "combined_line": 47280, - "original_file": "duk_heap_finalize.c" - }, - { - "original_line": 1, - "combined_line": 47726, - "original_file": "duk_heap_hashstring.c" - }, - { - "original_line": 1, - "combined_line": 47848, - "original_file": "duk_heap_markandsweep.c" - }, - { - "original_line": 1, - "combined_line": 49223, - "original_file": "duk_heap_memory.c" - }, - { - "original_line": 1, - "combined_line": 49590, - "original_file": "duk_heap_misc.c" - }, - { - "original_line": 1, - "combined_line": 49772, - "original_file": "duk_heap_refcount.c" - }, - { - "original_line": 1, - "combined_line": 50615, - "original_file": "duk_heap_stringcache.c" - }, - { - "original_line": 1, - "combined_line": 50925, - "original_file": "duk_heap_stringtable.c" - }, - { - "original_line": 1, - "combined_line": 51915, - "original_file": "duk_hobject_alloc.c" - }, - { - "original_line": 1, - "combined_line": 52186, - "original_file": "duk_hobject_enum.c" - }, - { - "original_line": 1, - "combined_line": 52889, - "original_file": "duk_hobject_misc.c" - }, - { - "original_line": 1, - "combined_line": 52942, - "original_file": "duk_hobject_pc2line.c" - }, - { - "original_line": 1, - "combined_line": 53187, - "original_file": "duk_hobject_props.c" - }, - { - "original_line": 1, - "combined_line": 59282, - "original_file": "duk_hstring_misc.c" - }, - { - "original_line": 1, - "combined_line": 59479, - "original_file": "duk_hthread_alloc.c" - }, - { - "original_line": 1, - "combined_line": 59539, - "original_file": "duk_hthread_builtins.c" - }, - { - "original_line": 1, - "combined_line": 60414, - "original_file": "duk_hthread_misc.c" - }, - { - "original_line": 1, - "combined_line": 60512, - "original_file": "duk_hthread_stacks.c" - }, - { - "original_line": 1, - "combined_line": 60920, - "original_file": "duk_js_arith.c" - }, - { - "original_line": 1, - "combined_line": 61058, - "original_file": "duk_js_call.c" - }, - { - "original_line": 1, - "combined_line": 63921, - "original_file": "duk_js_compiler.c" - }, - { - "original_line": 1, - "combined_line": 71956, - "original_file": "duk_js_executor.c" - }, - { - "original_line": 1, - "combined_line": 77178, - "original_file": "duk_js_ops.c" - }, - { - "original_line": 1, - "combined_line": 78610, - "original_file": "duk_js_var.c" - }, - { - "original_line": 1, - "combined_line": 80364, - "original_file": "duk_lexer.c" - }, - { - "original_line": 1, - "combined_line": 82824, - "original_file": "duk_numconv.c" - }, - { - "original_line": 1, - "combined_line": 85101, - "original_file": "duk_regexp_compiler.c" - }, - { - "original_line": 1, - "combined_line": 86384, - "original_file": "duk_regexp_executor.c" - }, - { - "original_line": 1, - "combined_line": 87409, - "original_file": "duk_selftest.c" - }, - { - "original_line": 2, - "combined_line": 88055, - "original_file": "duk_tval.c" - }, - { - "original_line": 1, - "combined_line": 88197, - "original_file": "duk_unicode_tables.c" - }, - { - "original_line": 1, - "combined_line": 94362, - "original_file": "duk_util_bitdecoder.c" - }, - { - "original_line": 1, - "combined_line": 94529, - "original_file": "duk_util_bitencoder.c" - }, - { - "original_line": 1, - "combined_line": 94573, - "original_file": "duk_util_bufwriter.c" - }, - { - "original_line": 1, - "combined_line": 94926, - "original_file": "duk_util_hashbytes.c" - }, - { - "original_line": 1, - "combined_line": 94988, - "original_file": "duk_util_tinyrandom.c" - } - ], - "duk_version": 20200, - "git_branch": "master", - "git_commit": "a459cf3c9bd1779fc01b435d69302b742675a08f", - "builtin_strings_info": [ - { - "plain": "Undefined", - "base64": "VW5kZWZpbmVk", - "define": "DUK_STRIDX_UC_UNDEFINED" - }, - { - "plain": "Null", - "base64": "TnVsbA==", - "define": "DUK_STRIDX_UC_NULL" - }, - { - "plain": "Symbol", - "base64": "U3ltYm9s", - "define": "DUK_STRIDX_UC_SYMBOL" - }, - { - "plain": "Arguments", - "base64": "QXJndW1lbnRz", - "define": "DUK_STRIDX_UC_ARGUMENTS" - }, - { - "plain": "Object", - "base64": "T2JqZWN0", - "define": "DUK_STRIDX_UC_OBJECT" - }, - { - "plain": "Function", - "base64": "RnVuY3Rpb24=", - "define": "DUK_STRIDX_UC_FUNCTION" - }, - { - "plain": "Array", - "base64": "QXJyYXk=", - "define": "DUK_STRIDX_ARRAY" - }, - { - "plain": "String", - "base64": "U3RyaW5n", - "define": "DUK_STRIDX_UC_STRING" - }, - { - "plain": "Boolean", - "base64": "Qm9vbGVhbg==", - "define": "DUK_STRIDX_UC_BOOLEAN" - }, - { - "plain": "Number", - "base64": "TnVtYmVy", - "define": "DUK_STRIDX_UC_NUMBER" - }, - { - "plain": "Date", - "base64": "RGF0ZQ==", - "define": "DUK_STRIDX_DATE" - }, - { - "plain": "RegExp", - "base64": "UmVnRXhw", - "define": "DUK_STRIDX_REG_EXP" - }, - { - "plain": "Error", - "base64": "RXJyb3I=", - "define": "DUK_STRIDX_UC_ERROR" - }, - { - "plain": "Math", - "base64": "TWF0aA==", - "define": "DUK_STRIDX_MATH" - }, - { - "plain": "JSON", - "base64": "SlNPTg==", - "define": "DUK_STRIDX_JSON" - }, - { - "plain": "", - "base64": "", - "define": "DUK_STRIDX_EMPTY_STRING" - }, - { - "plain": "ArrayBuffer", - "base64": "QXJyYXlCdWZmZXI=", - "define": "DUK_STRIDX_ARRAY_BUFFER" - }, - { - "plain": "DataView", - "base64": "RGF0YVZpZXc=", - "define": "DUK_STRIDX_DATA_VIEW" - }, - { - "plain": "Int8Array", - "base64": "SW50OEFycmF5", - "define": "DUK_STRIDX_INT8_ARRAY" - }, - { - "plain": "Uint8Array", - "base64": "VWludDhBcnJheQ==", - "define": "DUK_STRIDX_UINT8_ARRAY" - }, - { - "plain": "Uint8ClampedArray", - "base64": "VWludDhDbGFtcGVkQXJyYXk=", - "define": "DUK_STRIDX_UINT8_CLAMPED_ARRAY" - }, - { - "plain": "Int16Array", - "base64": "SW50MTZBcnJheQ==", - "define": "DUK_STRIDX_INT16_ARRAY" - }, - { - "plain": "Uint16Array", - "base64": "VWludDE2QXJyYXk=", - "define": "DUK_STRIDX_UINT16_ARRAY" - }, - { - "plain": "Int32Array", - "base64": "SW50MzJBcnJheQ==", - "define": "DUK_STRIDX_INT32_ARRAY" - }, - { - "plain": "Uint32Array", - "base64": "VWludDMyQXJyYXk=", - "define": "DUK_STRIDX_UINT32_ARRAY" - }, - { - "plain": "Float32Array", - "base64": "RmxvYXQzMkFycmF5", - "define": "DUK_STRIDX_FLOAT32_ARRAY" - }, - { - "plain": "Float64Array", - "base64": "RmxvYXQ2NEFycmF5", - "define": "DUK_STRIDX_FLOAT64_ARRAY" - }, - { - "plain": "global", - "base64": "Z2xvYmFs", - "define": "DUK_STRIDX_GLOBAL" - }, - { - "plain": "ObjEnv", - "base64": "T2JqRW52", - "define": "DUK_STRIDX_OBJ_ENV" - }, - { - "plain": "DecEnv", - "base64": "RGVjRW52", - "define": "DUK_STRIDX_DEC_ENV" - }, - { - "plain": "Buffer", - "base64": "QnVmZmVy", - "define": "DUK_STRIDX_UC_BUFFER" - }, - { - "plain": "Pointer", - "base64": "UG9pbnRlcg==", - "define": "DUK_STRIDX_UC_POINTER" - }, - { - "plain": "Thread", - "base64": "VGhyZWFk", - "define": "DUK_STRIDX_UC_THREAD" - }, - { - "plain": "eval", - "base64": "ZXZhbA==", - "define": "DUK_STRIDX_EVAL" - }, - { - "plain": "value", - "base64": "dmFsdWU=", - "define": "DUK_STRIDX_VALUE" - }, - { - "plain": "writable", - "base64": "d3JpdGFibGU=", - "define": "DUK_STRIDX_WRITABLE" - }, - { - "plain": "configurable", - "base64": "Y29uZmlndXJhYmxl", - "define": "DUK_STRIDX_CONFIGURABLE" - }, - { - "plain": "enumerable", - "base64": "ZW51bWVyYWJsZQ==", - "define": "DUK_STRIDX_ENUMERABLE" - }, - { - "plain": "join", - "base64": "am9pbg==", - "define": "DUK_STRIDX_JOIN" - }, - { - "plain": "toLocaleString", - "base64": "dG9Mb2NhbGVTdHJpbmc=", - "define": "DUK_STRIDX_TO_LOCALE_STRING" - }, - { - "plain": "valueOf", - "base64": "dmFsdWVPZg==", - "define": "DUK_STRIDX_VALUE_OF" - }, - { - "plain": "toUTCString", - "base64": "dG9VVENTdHJpbmc=", - "define": "DUK_STRIDX_TO_UTC_STRING" - }, - { - "plain": "toISOString", - "base64": "dG9JU09TdHJpbmc=", - "define": "DUK_STRIDX_TO_ISO_STRING" - }, - { - "plain": "toGMTString", - "base64": "dG9HTVRTdHJpbmc=", - "define": "DUK_STRIDX_TO_GMT_STRING" - }, - { - "plain": "source", - "base64": "c291cmNl", - "define": "DUK_STRIDX_SOURCE" - }, - { - "plain": "ignoreCase", - "base64": "aWdub3JlQ2FzZQ==", - "define": "DUK_STRIDX_IGNORE_CASE" - }, - { - "plain": "multiline", - "base64": "bXVsdGlsaW5l", - "define": "DUK_STRIDX_MULTILINE" - }, - { - "plain": "lastIndex", - "base64": "bGFzdEluZGV4", - "define": "DUK_STRIDX_LAST_INDEX" - }, - { - "plain": "flags", - "base64": "ZmxhZ3M=", - "define": "DUK_STRIDX_FLAGS" - }, - { - "plain": "index", - "base64": "aW5kZXg=", - "define": "DUK_STRIDX_INDEX" - }, - { - "plain": "prototype", - "base64": "cHJvdG90eXBl", - "define": "DUK_STRIDX_PROTOTYPE" - }, - { - "plain": "constructor", - "base64": "Y29uc3RydWN0b3I=", - "define": "DUK_STRIDX_CONSTRUCTOR" - }, - { - "plain": "message", - "base64": "bWVzc2FnZQ==", - "define": "DUK_STRIDX_MESSAGE" - }, - { - "plain": "boolean", - "base64": "Ym9vbGVhbg==", - "define": "DUK_STRIDX_LC_BOOLEAN" - }, - { - "plain": "number", - "base64": "bnVtYmVy", - "define": "DUK_STRIDX_LC_NUMBER" - }, - { - "plain": "string", - "base64": "c3RyaW5n", - "define": "DUK_STRIDX_LC_STRING" - }, - { - "plain": "symbol", - "base64": "c3ltYm9s", - "define": "DUK_STRIDX_LC_SYMBOL" - }, - { - "plain": "object", - "base64": "b2JqZWN0", - "define": "DUK_STRIDX_LC_OBJECT" - }, - { - "plain": "undefined", - "base64": "dW5kZWZpbmVk", - "define": "DUK_STRIDX_LC_UNDEFINED" - }, - { - "plain": "NaN", - "base64": "TmFO", - "define": "DUK_STRIDX_NAN" - }, - { - "plain": "Infinity", - "base64": "SW5maW5pdHk=", - "define": "DUK_STRIDX_INFINITY" - }, - { - "plain": "-Infinity", - "base64": "LUluZmluaXR5", - "define": "DUK_STRIDX_MINUS_INFINITY" - }, - { - "plain": "-0", - "base64": "LTA=", - "define": "DUK_STRIDX_MINUS_ZERO" - }, - { - "plain": ",", - "base64": "LA==", - "define": "DUK_STRIDX_COMMA" - }, - { - "plain": "\n ", - "base64": "CiAgICA=", - "define": "DUK_STRIDX_NEWLINE_4SPACE" - }, - { - "plain": "[...]", - "base64": "Wy4uLl0=", - "define": "DUK_STRIDX_BRACKETED_ELLIPSIS" - }, - { - "plain": "Invalid Date", - "base64": "SW52YWxpZCBEYXRl", - "define": "DUK_STRIDX_INVALID_DATE" - }, - { - "plain": "arguments", - "base64": "YXJndW1lbnRz", - "define": "DUK_STRIDX_LC_ARGUMENTS" - }, - { - "plain": "callee", - "base64": "Y2FsbGVl", - "define": "DUK_STRIDX_CALLEE" - }, - { - "plain": "caller", - "base64": "Y2FsbGVy", - "define": "DUK_STRIDX_CALLER" - }, - { - "plain": "apply", - "base64": "YXBwbHk=", - "define": "DUK_STRIDX_APPLY" - }, - { - "plain": "construct", - "base64": "Y29uc3RydWN0", - "define": "DUK_STRIDX_CONSTRUCT" - }, - { - "plain": "deleteProperty", - "base64": "ZGVsZXRlUHJvcGVydHk=", - "define": "DUK_STRIDX_DELETE_PROPERTY" - }, - { - "plain": "get", - "base64": "Z2V0", - "define": "DUK_STRIDX_GET" - }, - { - "plain": "has", - "base64": "aGFz", - "define": "DUK_STRIDX_HAS" - }, - { - "plain": "ownKeys", - "base64": "b3duS2V5cw==", - "define": "DUK_STRIDX_OWN_KEYS" - }, - { - "plain": "setPrototypeOf", - "base64": "c2V0UHJvdG90eXBlT2Y=", - "define": "DUK_STRIDX_SET_PROTOTYPE_OF" - }, - { - "plain": "__proto__", - "base64": "X19wcm90b19f", - "define": "DUK_STRIDX___PROTO__" - }, - { - "plain": "toString", - "base64": "dG9TdHJpbmc=", - "define": "DUK_STRIDX_TO_STRING" - }, - { - "plain": "toJSON", - "base64": "dG9KU09O", - "define": "DUK_STRIDX_TO_JSON" - }, - { - "plain": "type", - "base64": "dHlwZQ==", - "define": "DUK_STRIDX_TYPE" - }, - { - "plain": "data", - "base64": "ZGF0YQ==", - "define": "DUK_STRIDX_DATA" - }, - { - "plain": "length", - "base64": "bGVuZ3Ro", - "define": "DUK_STRIDX_LENGTH" - }, - { - "plain": "set", - "base64": "c2V0", - "define": "DUK_STRIDX_SET" - }, - { - "plain": "stack", - "base64": "c3RhY2s=", - "define": "DUK_STRIDX_STACK" - }, - { - "plain": "pc", - "base64": "cGM=", - "define": "DUK_STRIDX_PC" - }, - { - "plain": "lineNumber", - "base64": "bGluZU51bWJlcg==", - "define": "DUK_STRIDX_LINE_NUMBER" - }, - { - "plain": "\u0082Tracedata", - "base64": "glRyYWNlZGF0YQ==", - "define": "DUK_STRIDX_INT_TRACEDATA" - }, - { - "plain": "name", - "base64": "bmFtZQ==", - "define": "DUK_STRIDX_NAME" - }, - { - "plain": "fileName", - "base64": "ZmlsZU5hbWU=", - "define": "DUK_STRIDX_FILE_NAME" - }, - { - "plain": "pointer", - "base64": "cG9pbnRlcg==", - "define": "DUK_STRIDX_LC_POINTER" - }, - { - "plain": "\u0082Target", - "base64": "glRhcmdldA==", - "define": "DUK_STRIDX_INT_TARGET" - }, - { - "plain": "\u0082Next", - "base64": "gk5leHQ=", - "define": "DUK_STRIDX_INT_NEXT" - }, - { - "plain": "\u0082Bytecode", - "base64": "gkJ5dGVjb2Rl", - "define": "DUK_STRIDX_INT_BYTECODE" - }, - { - "plain": "\u0082Formals", - "base64": "gkZvcm1hbHM=", - "define": "DUK_STRIDX_INT_FORMALS" - }, - { - "plain": "\u0082Varmap", - "base64": "glZhcm1hcA==", - "define": "DUK_STRIDX_INT_VARMAP" - }, - { - "plain": "\u0082Source", - "base64": "glNvdXJjZQ==", - "define": "DUK_STRIDX_INT_SOURCE" - }, - { - "plain": "\u0082Pc2line", - "base64": "glBjMmxpbmU=", - "define": "DUK_STRIDX_INT_PC2LINE" - }, - { - "plain": "\u0082Map", - "base64": "gk1hcA==", - "define": "DUK_STRIDX_INT_MAP" - }, - { - "plain": "\u0082Varenv", - "base64": "glZhcmVudg==", - "define": "DUK_STRIDX_INT_VARENV" - }, - { - "plain": "\u0082Finalizer", - "base64": "gkZpbmFsaXplcg==", - "define": "DUK_STRIDX_INT_FINALIZER" - }, - { - "plain": "\u0082Value", - "base64": "glZhbHVl", - "define": "DUK_STRIDX_INT_VALUE" - }, - { - "plain": "compile", - "base64": "Y29tcGlsZQ==", - "define": "DUK_STRIDX_COMPILE" - }, - { - "plain": "input", - "base64": "aW5wdXQ=", - "define": "DUK_STRIDX_INPUT" - }, - { - "plain": "errCreate", - "base64": "ZXJyQ3JlYXRl", - "define": "DUK_STRIDX_ERR_CREATE" - }, - { - "plain": "errThrow", - "base64": "ZXJyVGhyb3c=", - "define": "DUK_STRIDX_ERR_THROW" - }, - { - "plain": "env", - "base64": "ZW52", - "define": "DUK_STRIDX_ENV" - }, - { - "plain": "hex", - "base64": "aGV4", - "define": "DUK_STRIDX_HEX" - }, - { - "plain": "base64", - "base64": "YmFzZTY0", - "define": "DUK_STRIDX_BASE64" - }, - { - "plain": "jx", - "base64": "ang=", - "define": "DUK_STRIDX_JX" - }, - { - "plain": "jc", - "base64": "amM=", - "define": "DUK_STRIDX_JC" - }, - { - "plain": "{\"_undef\":true}", - "base64": "eyJfdW5kZWYiOnRydWV9", - "define": "DUK_STRIDX_JSON_EXT_UNDEFINED" - }, - { - "plain": "{\"_nan\":true}", - "base64": "eyJfbmFuIjp0cnVlfQ==", - "define": "DUK_STRIDX_JSON_EXT_NAN" - }, - { - "plain": "{\"_inf\":true}", - "base64": "eyJfaW5mIjp0cnVlfQ==", - "define": "DUK_STRIDX_JSON_EXT_POSINF" - }, - { - "plain": "{\"_ninf\":true}", - "base64": "eyJfbmluZiI6dHJ1ZX0=", - "define": "DUK_STRIDX_JSON_EXT_NEGINF" - }, - { - "plain": "{\"_func\":true}", - "base64": "eyJfZnVuYyI6dHJ1ZX0=", - "define": "DUK_STRIDX_JSON_EXT_FUNCTION1" - }, - { - "plain": "{_func:true}", - "base64": "e19mdW5jOnRydWV9", - "define": "DUK_STRIDX_JSON_EXT_FUNCTION2" - }, - { - "plain": "break", - "base64": "YnJlYWs=", - "define": "DUK_STRIDX_BREAK" - }, - { - "plain": "case", - "base64": "Y2FzZQ==", - "define": "DUK_STRIDX_CASE" - }, - { - "plain": "catch", - "base64": "Y2F0Y2g=", - "define": "DUK_STRIDX_CATCH" - }, - { - "plain": "continue", - "base64": "Y29udGludWU=", - "define": "DUK_STRIDX_CONTINUE" - }, - { - "plain": "debugger", - "base64": "ZGVidWdnZXI=", - "define": "DUK_STRIDX_DEBUGGER" - }, - { - "plain": "default", - "base64": "ZGVmYXVsdA==", - "define": "DUK_STRIDX_DEFAULT" - }, - { - "plain": "delete", - "base64": "ZGVsZXRl", - "define": "DUK_STRIDX_DELETE" - }, - { - "plain": "do", - "base64": "ZG8=", - "define": "DUK_STRIDX_DO" - }, - { - "plain": "else", - "base64": "ZWxzZQ==", - "define": "DUK_STRIDX_ELSE" - }, - { - "plain": "finally", - "base64": "ZmluYWxseQ==", - "define": "DUK_STRIDX_FINALLY" - }, - { - "plain": "for", - "base64": "Zm9y", - "define": "DUK_STRIDX_FOR" - }, - { - "plain": "function", - "base64": "ZnVuY3Rpb24=", - "define": "DUK_STRIDX_LC_FUNCTION" - }, - { - "plain": "if", - "base64": "aWY=", - "define": "DUK_STRIDX_IF" - }, - { - "plain": "in", - "base64": "aW4=", - "define": "DUK_STRIDX_IN" - }, - { - "plain": "instanceof", - "base64": "aW5zdGFuY2VvZg==", - "define": "DUK_STRIDX_INSTANCEOF" - }, - { - "plain": "new", - "base64": "bmV3", - "define": "DUK_STRIDX_NEW" - }, - { - "plain": "return", - "base64": "cmV0dXJu", - "define": "DUK_STRIDX_RETURN" - }, - { - "plain": "switch", - "base64": "c3dpdGNo", - "define": "DUK_STRIDX_SWITCH" - }, - { - "plain": "this", - "base64": "dGhpcw==", - "define": "DUK_STRIDX_THIS" - }, - { - "plain": "throw", - "base64": "dGhyb3c=", - "define": "DUK_STRIDX_THROW" - }, - { - "plain": "try", - "base64": "dHJ5", - "define": "DUK_STRIDX_TRY" - }, - { - "plain": "typeof", - "base64": "dHlwZW9m", - "define": "DUK_STRIDX_TYPEOF" - }, - { - "plain": "var", - "base64": "dmFy", - "define": "DUK_STRIDX_VAR" - }, - { - "plain": "const", - "base64": "Y29uc3Q=", - "define": "DUK_STRIDX_CONST" - }, - { - "plain": "void", - "base64": "dm9pZA==", - "define": "DUK_STRIDX_VOID" - }, - { - "plain": "while", - "base64": "d2hpbGU=", - "define": "DUK_STRIDX_WHILE" - }, - { - "plain": "with", - "base64": "d2l0aA==", - "define": "DUK_STRIDX_WITH" - }, - { - "plain": "class", - "base64": "Y2xhc3M=", - "define": "DUK_STRIDX_CLASS" - }, - { - "plain": "enum", - "base64": "ZW51bQ==", - "define": "DUK_STRIDX_ENUM" - }, - { - "plain": "export", - "base64": "ZXhwb3J0", - "define": "DUK_STRIDX_EXPORT" - }, - { - "plain": "extends", - "base64": "ZXh0ZW5kcw==", - "define": "DUK_STRIDX_EXTENDS" - }, - { - "plain": "import", - "base64": "aW1wb3J0", - "define": "DUK_STRIDX_IMPORT" - }, - { - "plain": "super", - "base64": "c3VwZXI=", - "define": "DUK_STRIDX_SUPER" - }, - { - "plain": "null", - "base64": "bnVsbA==", - "define": "DUK_STRIDX_LC_NULL" - }, - { - "plain": "true", - "base64": "dHJ1ZQ==", - "define": "DUK_STRIDX_TRUE" - }, - { - "plain": "false", - "base64": "ZmFsc2U=", - "define": "DUK_STRIDX_FALSE" - }, - { - "plain": "implements", - "base64": "aW1wbGVtZW50cw==", - "define": "DUK_STRIDX_IMPLEMENTS" - }, - { - "plain": "interface", - "base64": "aW50ZXJmYWNl", - "define": "DUK_STRIDX_INTERFACE" - }, - { - "plain": "let", - "base64": "bGV0", - "define": "DUK_STRIDX_LET" - }, - { - "plain": "package", - "base64": "cGFja2FnZQ==", - "define": "DUK_STRIDX_PACKAGE" - }, - { - "plain": "private", - "base64": "cHJpdmF0ZQ==", - "define": "DUK_STRIDX_PRIVATE" - }, - { - "plain": "protected", - "base64": "cHJvdGVjdGVk", - "define": "DUK_STRIDX_PROTECTED" - }, - { - "plain": "public", - "base64": "cHVibGlj", - "define": "DUK_STRIDX_PUBLIC" - }, - { - "plain": "static", - "base64": "c3RhdGlj", - "define": "DUK_STRIDX_STATIC" - }, - { - "plain": "yield", - "base64": "eWllbGQ=", - "define": "DUK_STRIDX_YIELD" - } - ], - "builtin_strings_base64": [ - "VW5kZWZpbmVk", - "TnVsbA==", - "U3ltYm9s", - "QXJndW1lbnRz", - "T2JqZWN0", - "RnVuY3Rpb24=", - "QXJyYXk=", - "U3RyaW5n", - "Qm9vbGVhbg==", - "TnVtYmVy", - "RGF0ZQ==", - "UmVnRXhw", - "RXJyb3I=", - "TWF0aA==", - "SlNPTg==", - "", - "QXJyYXlCdWZmZXI=", - "RGF0YVZpZXc=", - "SW50OEFycmF5", - "VWludDhBcnJheQ==", - "VWludDhDbGFtcGVkQXJyYXk=", - "SW50MTZBcnJheQ==", - "VWludDE2QXJyYXk=", - "SW50MzJBcnJheQ==", - "VWludDMyQXJyYXk=", - "RmxvYXQzMkFycmF5", - "RmxvYXQ2NEFycmF5", - "Z2xvYmFs", - "T2JqRW52", - "RGVjRW52", - "QnVmZmVy", - "UG9pbnRlcg==", - "VGhyZWFk", - "ZXZhbA==", - "dmFsdWU=", - "d3JpdGFibGU=", - "Y29uZmlndXJhYmxl", - "ZW51bWVyYWJsZQ==", - "am9pbg==", - "dG9Mb2NhbGVTdHJpbmc=", - "dmFsdWVPZg==", - "dG9VVENTdHJpbmc=", - "dG9JU09TdHJpbmc=", - "dG9HTVRTdHJpbmc=", - "c291cmNl", - "aWdub3JlQ2FzZQ==", - "bXVsdGlsaW5l", - "bGFzdEluZGV4", - "ZmxhZ3M=", - "aW5kZXg=", - "cHJvdG90eXBl", - "Y29uc3RydWN0b3I=", - "bWVzc2FnZQ==", - "Ym9vbGVhbg==", - "bnVtYmVy", - "c3RyaW5n", - "c3ltYm9s", - "b2JqZWN0", - "dW5kZWZpbmVk", - "TmFO", - "SW5maW5pdHk=", - "LUluZmluaXR5", - "LTA=", - "LA==", - "CiAgICA=", - "Wy4uLl0=", - "SW52YWxpZCBEYXRl", - "YXJndW1lbnRz", - "Y2FsbGVl", - "Y2FsbGVy", - "YXBwbHk=", - "Y29uc3RydWN0", - "ZGVsZXRlUHJvcGVydHk=", - "Z2V0", - "aGFz", - "b3duS2V5cw==", - "c2V0UHJvdG90eXBlT2Y=", - "X19wcm90b19f", - "dG9TdHJpbmc=", - "dG9KU09O", - "dHlwZQ==", - "ZGF0YQ==", - "bGVuZ3Ro", - "c2V0", - "c3RhY2s=", - "cGM=", - "bGluZU51bWJlcg==", - "glRyYWNlZGF0YQ==", - "bmFtZQ==", - "ZmlsZU5hbWU=", - "cG9pbnRlcg==", - "glRhcmdldA==", - "gk5leHQ=", - "gkJ5dGVjb2Rl", - "gkZvcm1hbHM=", - "glZhcm1hcA==", - "glNvdXJjZQ==", - "glBjMmxpbmU=", - "gk1hcA==", - "glZhcmVudg==", - "gkZpbmFsaXplcg==", - "glZhbHVl", - "Y29tcGlsZQ==", - "aW5wdXQ=", - "ZXJyQ3JlYXRl", - "ZXJyVGhyb3c=", - "ZW52", - "aGV4", - "YmFzZTY0", - "ang=", - "amM=", - "eyJfdW5kZWYiOnRydWV9", - "eyJfbmFuIjp0cnVlfQ==", - "eyJfaW5mIjp0cnVlfQ==", - "eyJfbmluZiI6dHJ1ZX0=", - "eyJfZnVuYyI6dHJ1ZX0=", - "e19mdW5jOnRydWV9", - "YnJlYWs=", - "Y2FzZQ==", - "Y2F0Y2g=", - "Y29udGludWU=", - "ZGVidWdnZXI=", - "ZGVmYXVsdA==", - "ZGVsZXRl", - "ZG8=", - "ZWxzZQ==", - "ZmluYWxseQ==", - "Zm9y", - "ZnVuY3Rpb24=", - "aWY=", - "aW4=", - "aW5zdGFuY2VvZg==", - "bmV3", - "cmV0dXJu", - "c3dpdGNo", - "dGhpcw==", - "dGhyb3c=", - "dHJ5", - "dHlwZW9m", - "dmFy", - "Y29uc3Q=", - "dm9pZA==", - "d2hpbGU=", - "d2l0aA==", - "Y2xhc3M=", - "ZW51bQ==", - "ZXhwb3J0", - "ZXh0ZW5kcw==", - "aW1wb3J0", - "c3VwZXI=", - "bnVsbA==", - "dHJ1ZQ==", - "ZmFsc2U=", - "aW1wbGVtZW50cw==", - "aW50ZXJmYWNl", - "bGV0", - "cGFja2FnZQ==", - "cHJpdmF0ZQ==", - "cHJvdGVjdGVk", - "cHVibGlj", - "c3RhdGlj", - "eWllbGQ=" - ], - "git_describe": "v2.2.0", - "builtin_strings": [ - "Undefined", - "Null", - "Symbol", - "Arguments", - "Object", - "Function", - "Array", - "String", - "Boolean", - "Number", - "Date", - "RegExp", - "Error", - "Math", - "JSON", - "", - "ArrayBuffer", - "DataView", - "Int8Array", - "Uint8Array", - "Uint8ClampedArray", - "Int16Array", - "Uint16Array", - "Int32Array", - "Uint32Array", - "Float32Array", - "Float64Array", - "global", - "ObjEnv", - "DecEnv", - "Buffer", - "Pointer", - "Thread", - "eval", - "value", - "writable", - "configurable", - "enumerable", - "join", - "toLocaleString", - "valueOf", - "toUTCString", - "toISOString", - "toGMTString", - "source", - "ignoreCase", - "multiline", - "lastIndex", - "flags", - "index", - "prototype", - "constructor", - "message", - "boolean", - "number", - "string", - "symbol", - "object", - "undefined", - "NaN", - "Infinity", - "-Infinity", - "-0", - ",", - "\n ", - "[...]", - "Invalid Date", - "arguments", - "callee", - "caller", - "apply", - "construct", - "deleteProperty", - "get", - "has", - "ownKeys", - "setPrototypeOf", - "__proto__", - "toString", - "toJSON", - "type", - "data", - "length", - "set", - "stack", - "pc", - "lineNumber", - "\u0082Tracedata", - "name", - "fileName", - "pointer", - "\u0082Target", - "\u0082Next", - "\u0082Bytecode", - "\u0082Formals", - "\u0082Varmap", - "\u0082Source", - "\u0082Pc2line", - "\u0082Map", - "\u0082Varenv", - "\u0082Finalizer", - "\u0082Value", - "compile", - "input", - "errCreate", - "errThrow", - "env", - "hex", - "base64", - "jx", - "jc", - "{\"_undef\":true}", - "{\"_nan\":true}", - "{\"_inf\":true}", - "{\"_ninf\":true}", - "{\"_func\":true}", - "{_func:true}", - "break", - "case", - "catch", - "continue", - "debugger", - "default", - "delete", - "do", - "else", - "finally", - "for", - "function", - "if", - "in", - "instanceof", - "new", - "return", - "switch", - "this", - "throw", - "try", - "typeof", - "var", - "const", - "void", - "while", - "with", - "class", - "enum", - "export", - "extends", - "import", - "super", - "null", - "true", - "false", - "implements", - "interface", - "let", - "package", - "private", - "protected", - "public", - "static", - "yield" - ] -} \ No newline at end of file diff --git a/dep/duktape/duktape/duktape.c b/dep/duktape/duktape/duktape.c deleted file mode 100644 index 05e4b1d99c8..00000000000 --- a/dep/duktape/duktape/duktape.c +++ /dev/null @@ -1,95118 +0,0 @@ -/* - * Single source autogenerated distributable for Duktape 2.2.0. - * - * Git commit a459cf3c9bd1779fc01b435d69302b742675a08f (v2.2.0). - * Git branch master. - * - * See Duktape AUTHORS.rst and LICENSE.txt for copyright and - * licensing information. - */ - -/* LICENSE.txt */ -/* -* =============== -* Duktape license -* =============== -* -* (http://opensource.org/licenses/MIT) -* -* Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst) -* -* 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. -*/ - -/* AUTHORS.rst */ -/* -* =============== -* Duktape authors -* =============== -* -* Copyright -* ========= -* -* Duktape copyrights are held by its authors. Each author has a copyright -* to their contribution, and agrees to irrevocably license the contribution -* under the Duktape ``LICENSE.txt``. -* -* Authors -* ======= -* -* Please include an e-mail address, a link to your GitHub profile, or something -* similar to allow your contribution to be identified accurately. -* -* The following people have contributed code, website contents, or Wiki contents, -* and agreed to irrevocably license their contributions under the Duktape -* ``LICENSE.txt`` (in order of appearance): -* -* * Sami Vaarala -* * Niki Dobrev -* * Andreas \u00d6man -* * L\u00e1szl\u00f3 Lang\u00f3 -* * Legimet -* * Karl Skomski -* * Bruce Pascoe -* * Ren\u00e9 Hollander -* * Julien Hamaide (https://github.com/crazyjul) -* * Sebastian G\u00f6tte (https://github.com/jaseg) -* * Tomasz Magulski (https://github.com/magul) -* * \D. Bohdan (https://github.com/dbohdan) -* * Ond\u0159ej Jirman (https://github.com/megous) -* * Sa\u00fal Ibarra Corretg\u00e9 -* * Jeremy HU -* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr) -* * Harold Brenes (https://github.com/harold-b) -* * Oliver Crow (https://github.com/ocrow) -* * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski) -* * Brett Vickers (https://github.com/beevik) -* * Dominik Okwieka (https://github.com/okitec) -* * Remko Tron\u00e7on (https://el-tramo.be) -* * Romero Malaquias (rbsm@ic.ufal.br) -* * Michael Drake -* * Steven Don (https://github.com/shdon) -* * Simon Stone (https://github.com/sstone1) -* * \J. McC. (https://github.com/jmhmccr) -* -* Other contributions -* =================== -* -* The following people have contributed something other than code (e.g. reported -* bugs, provided ideas, etc; roughly in order of appearance): -* -* * Greg Burns -* * Anthony Rabine -* * Carlos Costa -* * Aur\u00e9lien Bouilland -* * Preet Desai (Pris Matic) -* * judofyr (http://www.reddit.com/user/judofyr) -* * Jason Woofenden -* * Micha\u0142 Przyby\u015b -* * Anthony Howe -* * Conrad Pankoff -* * Jim Schimpf -* * Rajaran Gaunker (https://github.com/zimbabao) -* * Andreas \u00d6man -* * Doug Sanden -* * Josh Engebretson (https://github.com/JoshEngebretson) -* * Remo Eichenberger (https://github.com/remoe) -* * Mamod Mehyar (https://github.com/mamod) -* * David Demelier (https://github.com/markand) -* * Tim Caswell (https://github.com/creationix) -* * Mitchell Blank Jr (https://github.com/mitchblank) -* * https://github.com/yushli -* * Seo Sanghyeon (https://github.com/sanxiyn) -* * Han ChoongWoo (https://github.com/tunz) -* * Joshua Peek (https://github.com/josh) -* * Bruce E. Pascoe (https://github.com/fatcerberus) -* * https://github.com/Kelledin -* * https://github.com/sstruchtrup -* * Michael Drake (https://github.com/tlsa) -* * https://github.com/chris-y -* * Laurent Zubiaur (https://github.com/lzubiaur) -* * Neil Kolban (https://github.com/nkolban) -* -* If you are accidentally missing from this list, send me an e-mail -* (``sami.vaarala@iki.fi``) and I'll fix the omission. -*/ - -#line 1 "duk_replacements.c" -/* - * Replacements for missing platform functions. - * - * Unlike the originals, fpclassify() and signbit() replacements don't - * work on any floating point types, only doubles. The C typing here - * mimics the standard prototypes. - */ - -/* #include duk_internal.h */ -#line 1 "duk_internal.h" -/* - * Top-level include file to be used for all (internal) source files. - * - * Source files should not include individual header files, as they - * have not been designed to be individually included. - */ - -#if !defined(DUK_INTERNAL_H_INCLUDED) -#define DUK_INTERNAL_H_INCLUDED - -/* - * The 'duktape.h' header provides the public API, but also handles all - * compiler and platform specific feature detection, Duktape feature - * resolution, inclusion of system headers, etc. These have been merged - * because the public API is also dependent on e.g. detecting appropriate - * C types which is quite platform/compiler specific especially for a non-C99 - * build. The public API is also dependent on the resolved feature set. - * - * Some actions taken by the merged header (such as including system headers) - * are not appropriate for building a user application. The define - * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some - * sections depending on what is being built. - */ - -#define DUK_COMPILING_DUKTAPE -#include "duktape.h" - -/* - * User declarations, e.g. prototypes for user functions used by Duktape - * macros. - */ - -DUK_USE_USER_DECLARE() - -/* - * Duktape includes (other than duk_features.h) - * - * The header files expect to be included in an order which satisfies header - * dependencies correctly (the headers themselves don't include any other - * includes). Forward declarations are used to break circular struct/typedef - * dependencies. - */ - -/* #include duk_dblunion.h */ -#line 1 "duk_dblunion.h" -/* - * Union to access IEEE double memory representation, indexes for double - * memory representation, and some macros for double manipulation. - * - * Also used by packed duk_tval. Use a union for bit manipulation to - * minimize aliasing issues in practice. The C99 standard does not - * guarantee that this should work, but it's a very widely supported - * practice for low level manipulation. - * - * IEEE double format summary: - * - * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff - * A B C D E F G H - * - * s sign bit - * eee... exponent field - * fff... fraction - * - * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format. - * - * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a - * signaling NaN when the highest bit of the mantissa is zero, and a quiet - * NaN when the highest bit is set. - * - * At least three memory layouts are relevant here: - * - * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE - * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE - * D C B A H G F E Mixed/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME - * - * ARM is a special case: ARM double values are in mixed/cross endian - * format while ARM duk_uint64_t values are in standard little endian - * format (H G F E D C B A). When a double is read as a duk_uint64_t - * from memory, the register will contain the (logical) value - * E F G H A B C D. This requires some special handling below. - * - * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to - * the logical (big endian) order: - * - * byte order duk_uint8_t duk_uint16_t duk_uint32_t - * BE 01234567 0123 01 - * LE 76543210 3210 10 - * ME (ARM) 32107654 1032 01 - * - * Some processors may alter NaN values in a floating point load+store. - * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a - * quiet one. This is catastrophic when NaN space is used in packed - * duk_tval values. See: misc/clang_aliasing.c. - */ - -#if !defined(DUK_DBLUNION_H_INCLUDED) -#define DUK_DBLUNION_H_INCLUDED - -/* - * Union for accessing double parts, also serves as packed duk_tval - */ - -union duk_double_union { - double d; - float f[2]; -#if defined(DUK_USE_64BIT_OPS) - duk_uint64_t ull[1]; -#endif - duk_uint32_t ui[2]; - duk_uint16_t us[4]; - duk_uint8_t uc[8]; -#if defined(DUK_USE_PACKED_TVAL) - void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */ -#endif -}; - -typedef union duk_double_union duk_double_union; - -/* - * Indexes of various types with respect to big endian (logical) layout - */ - -#if defined(DUK_USE_DOUBLE_LE) -#if defined(DUK_USE_64BIT_OPS) -#define DUK_DBL_IDX_ULL0 0 -#endif -#define DUK_DBL_IDX_UI0 1 -#define DUK_DBL_IDX_UI1 0 -#define DUK_DBL_IDX_US0 3 -#define DUK_DBL_IDX_US1 2 -#define DUK_DBL_IDX_US2 1 -#define DUK_DBL_IDX_US3 0 -#define DUK_DBL_IDX_UC0 7 -#define DUK_DBL_IDX_UC1 6 -#define DUK_DBL_IDX_UC2 5 -#define DUK_DBL_IDX_UC3 4 -#define DUK_DBL_IDX_UC4 3 -#define DUK_DBL_IDX_UC5 2 -#define DUK_DBL_IDX_UC6 1 -#define DUK_DBL_IDX_UC7 0 -#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ -#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ -#elif defined(DUK_USE_DOUBLE_BE) -#if defined(DUK_USE_64BIT_OPS) -#define DUK_DBL_IDX_ULL0 0 -#endif -#define DUK_DBL_IDX_UI0 0 -#define DUK_DBL_IDX_UI1 1 -#define DUK_DBL_IDX_US0 0 -#define DUK_DBL_IDX_US1 1 -#define DUK_DBL_IDX_US2 2 -#define DUK_DBL_IDX_US3 3 -#define DUK_DBL_IDX_UC0 0 -#define DUK_DBL_IDX_UC1 1 -#define DUK_DBL_IDX_UC2 2 -#define DUK_DBL_IDX_UC3 3 -#define DUK_DBL_IDX_UC4 4 -#define DUK_DBL_IDX_UC5 5 -#define DUK_DBL_IDX_UC6 6 -#define DUK_DBL_IDX_UC7 7 -#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ -#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ -#elif defined(DUK_USE_DOUBLE_ME) -#if defined(DUK_USE_64BIT_OPS) -#define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */ -#endif -#define DUK_DBL_IDX_UI0 0 -#define DUK_DBL_IDX_UI1 1 -#define DUK_DBL_IDX_US0 1 -#define DUK_DBL_IDX_US1 0 -#define DUK_DBL_IDX_US2 3 -#define DUK_DBL_IDX_US3 2 -#define DUK_DBL_IDX_UC0 3 -#define DUK_DBL_IDX_UC1 2 -#define DUK_DBL_IDX_UC2 1 -#define DUK_DBL_IDX_UC3 0 -#define DUK_DBL_IDX_UC4 7 -#define DUK_DBL_IDX_UC5 6 -#define DUK_DBL_IDX_UC6 5 -#define DUK_DBL_IDX_UC7 4 -#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ -#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ -#else -#error internal error -#endif - -/* - * Helper macros for reading/writing memory representation parts, used - * by duk_numconv.c and duk_tval.h. - */ - -#define DUK_DBLUNION_SET_DOUBLE(u,v) do { \ - (u)->d = (v); \ - } while (0) - -#define DUK_DBLUNION_SET_HIGH32(u,v) do { \ - (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \ - } while (0) - -#if defined(DUK_USE_64BIT_OPS) -#if defined(DUK_USE_DOUBLE_ME) -#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \ - } while (0) -#else -#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \ - } while (0) -#endif -#else /* DUK_USE_64BIT_OPS */ -#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ - (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \ - (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \ - } while (0) -#endif /* DUK_USE_64BIT_OPS */ - -#define DUK_DBLUNION_SET_LOW32(u,v) do { \ - (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \ - } while (0) - -#define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d) -#define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0]) -#define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1]) - -#if defined(DUK_USE_64BIT_OPS) -#if defined(DUK_USE_DOUBLE_ME) -#define DUK_DBLUNION_SET_UINT64(u,v) do { \ - (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \ - (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \ - } while (0) -#define DUK_DBLUNION_GET_UINT64(u) \ - ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \ - ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1])) -#else -#define DUK_DBLUNION_SET_UINT64(u,v) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \ - } while (0) -#define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0]) -#endif -#define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v)) -#define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u))) -#endif /* DUK_USE_64BIT_OPS */ - -/* - * Double NaN manipulation macros related to NaN normalization needed when - * using the packed duk_tval representation. NaN normalization is necessary - * to keep double values compatible with the duk_tval format. - * - * When packed duk_tval is used, the NaN space is used to store pointers - * and other tagged values in addition to NaNs. Actual NaNs are normalized - * to a specific quiet NaN. The macros below are used by the implementation - * to check and normalize NaN values when they might be created. The macros - * are essentially NOPs when the non-packed duk_tval representation is used. - * - * A FULL check is exact and checks all bits. A NOTFULL check is used by - * the packed duk_tval and works correctly for all NaNs except those that - * begin with 0x7ff0. Since the 'normalized NaN' values used with packed - * duk_tval begin with 0x7ff8, the partial check is reliable when packed - * duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a - * quiet NaN regardless of its remaining lower bits. - * - * The ME variant below is specifically for ARM byte order, which has the - * feature that while doubles have a mixed byte order (32107654), unsigned - * long long values has a little endian byte order (76543210). When writing - * a logical double value through a ULL pointer, the 32-bit words need to be - * swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME. - * This is not full ARM support but suffices for some environments. - */ - -#if defined(DUK_USE_64BIT_OPS) -#if defined(DUK_USE_DOUBLE_ME) -/* Macros for 64-bit ops + mixed endian doubles. */ -#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000)) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000)) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000)) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000)) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000)) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000)) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000)) -#else -/* Macros for 64-bit ops + big/little endian doubles. */ -#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000)) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000)) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000)) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000)) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000)) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000)) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000)) -#endif -#else /* DUK_USE_64BIT_OPS */ -/* Macros for no 64-bit ops, any endianness. */ -#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ - (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \ - (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \ - (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \ - (u)->ui[DUK_DBL_IDX_UI1] != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \ - ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) -#define DUK__DBLUNION_IS_ANYINF(u) \ - ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \ - ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) -#define DUK__DBLUNION_IS_POSINF(u) \ - (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \ - ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) -#define DUK__DBLUNION_IS_NEGINF(u) \ - (((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \ - ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \ - ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) -#define DUK__DBLUNION_IS_POSZERO(u) \ - (((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \ - ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - (((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \ - ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) -#endif /* DUK_USE_64BIT_OPS */ - -#define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \ - (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \ - } while (0) - -#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \ - /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \ - ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \ - (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL)) - -#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \ - /* E == 0x7ff, F == 8 => normalized NaN */ \ - ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL) - -#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \ - if (DUK__DBLUNION_IS_NAN_FULL((u))) { \ - DUK__DBLUNION_SET_NAN_FULL((u)); \ - } \ - } while (0) - -#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \ - if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \ - DUK__DBLUNION_SET_NAN_NOTFULL((u)); \ - } \ - } while (0) - -/* Concrete macros for NaN handling used by the implementation internals. - * Chosen so that they match the duk_tval representation: with a packed - * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval - * these are essentially NOPs. - */ - -#if defined(DUK_USE_PACKED_TVAL) -#if defined(DUK_USE_FULL_TVAL) -#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u)) -#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) -#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u)) -#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d)) -#else -#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u)) -#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u)) -#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u)) -#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d)) -#endif -#define DUK_DBLUNION_IS_NORMALIZED(u) \ - (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \ - DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */ -#else /* DUK_USE_PACKED_TVAL */ -#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */ -#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */ -#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */ -#define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */ -#define DUK_DBLUNION_SET_NAN(u) do { \ - /* in non-packed representation we don't care about which NaN is used */ \ - (u)->d = DUK_DOUBLE_NAN; \ - } while (0) -#endif /* DUK_USE_PACKED_TVAL */ - -#define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u)) -#define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u)) -#define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u)) - -#define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u)) -#define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u)) -#define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u)) - -/* XXX: native 64-bit byteswaps when available */ - -/* 64-bit byteswap, same operation independent of target endianness. */ -#define DUK_DBLUNION_BSWAP64(u) do { \ - duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ - duk__bswaptmp1 = (u)->ui[0]; \ - duk__bswaptmp2 = (u)->ui[1]; \ - duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ - duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ - (u)->ui[0] = duk__bswaptmp2; \ - (u)->ui[1] = duk__bswaptmp1; \ - } while (0) - -/* Byteswap an IEEE double in the duk_double_union from host to network - * order. For a big endian target this is a no-op. - */ -#if defined(DUK_USE_DOUBLE_LE) -#define DUK_DBLUNION_DOUBLE_HTON(u) do { \ - duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ - duk__bswaptmp1 = (u)->ui[0]; \ - duk__bswaptmp2 = (u)->ui[1]; \ - duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ - duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ - (u)->ui[0] = duk__bswaptmp2; \ - (u)->ui[1] = duk__bswaptmp1; \ - } while (0) -#elif defined(DUK_USE_DOUBLE_ME) -#define DUK_DBLUNION_DOUBLE_HTON(u) do { \ - duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ - duk__bswaptmp1 = (u)->ui[0]; \ - duk__bswaptmp2 = (u)->ui[1]; \ - duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ - duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ - (u)->ui[0] = duk__bswaptmp1; \ - (u)->ui[1] = duk__bswaptmp2; \ - } while (0) -#elif defined(DUK_USE_DOUBLE_BE) -#define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0) -#else -#error internal error, double endianness insane -#endif - -/* Reverse operation is the same. */ -#define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u)) - -/* Some sign bit helpers. */ -#if defined(DUK_USE_64BIT_OPS) -#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0) -#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U)) -#else -#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0) -#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U)) -#endif - -#endif /* DUK_DBLUNION_H_INCLUDED */ -/* #include duk_replacements.h */ -#line 1 "duk_replacements.h" -#if !defined(DUK_REPLACEMENTS_H_INCLUDED) -#define DUK_REPLACEMENTS_H_INCLUDED - -#if !defined(DUK_SINGLE_FILE) -#if defined(DUK_USE_COMPUTED_INFINITY) -DUK_INTERNAL_DECL double duk_computed_infinity; -#endif -#if defined(DUK_USE_COMPUTED_NAN) -DUK_INTERNAL_DECL double duk_computed_nan; -#endif -#endif /* !DUK_SINGLE_FILE */ - -#if defined(DUK_USE_REPL_FPCLASSIFY) -DUK_INTERNAL_DECL int duk_repl_fpclassify(double x); -#endif -#if defined(DUK_USE_REPL_SIGNBIT) -DUK_INTERNAL_DECL int duk_repl_signbit(double x); -#endif -#if defined(DUK_USE_REPL_ISFINITE) -DUK_INTERNAL_DECL int duk_repl_isfinite(double x); -#endif -#if defined(DUK_USE_REPL_ISNAN) -DUK_INTERNAL_DECL int duk_repl_isnan(double x); -#endif -#if defined(DUK_USE_REPL_ISINF) -DUK_INTERNAL_DECL int duk_repl_isinf(double x); -#endif - -#endif /* DUK_REPLACEMENTS_H_INCLUDED */ -/* #include duk_jmpbuf.h */ -#line 1 "duk_jmpbuf.h" -/* - * Wrapper for jmp_buf. - * - * This is used because jmp_buf is an array type for backward compatibility. - * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc, - * behave more intuitively. - * - * http://en.wikipedia.org/wiki/Setjmp.h#Member_types - */ - -#if !defined(DUK_JMPBUF_H_INCLUDED) -#define DUK_JMPBUF_H_INCLUDED - -#if defined(DUK_USE_CPP_EXCEPTIONS) -struct duk_jmpbuf { - duk_small_int_t dummy; /* unused */ -}; -#else -struct duk_jmpbuf { - DUK_JMPBUF_TYPE jb; -}; -#endif - -#endif /* DUK_JMPBUF_H_INCLUDED */ -/* #include duk_exception.h */ -#line 1 "duk_exception.h" -/* - * Exception for Duktape internal throws when C++ exceptions are used - * for long control transfers. - * - * Doesn't inherit from any exception base class to minimize the chance - * that user code would accidentally catch this exception. - */ - -#if !defined(DUK_EXCEPTION_H_INCLUDED) -#define DUK_EXCEPTION_H_INCLUDED - -#if defined(DUK_USE_CPP_EXCEPTIONS) -class duk_internal_exception { - /* intentionally empty */ -}; -#endif - -#endif /* DUK_EXCEPTION_H_INCLUDED */ -/* #include duk_forwdecl.h */ -#line 1 "duk_forwdecl.h" -/* - * Forward declarations for all Duktape structures. - */ - -#if !defined(DUK_FORWDECL_H_INCLUDED) -#define DUK_FORWDECL_H_INCLUDED - -/* - * Forward declarations - */ - -#if defined(DUK_USE_CPP_EXCEPTIONS) -class duk_internal_exception; -#else -struct duk_jmpbuf; -#endif - -/* duk_tval intentionally skipped */ -struct duk_heaphdr; -struct duk_heaphdr_string; -struct duk_harray; -struct duk_hstring; -struct duk_hstring_external; -struct duk_hobject; -struct duk_hcompfunc; -struct duk_hnatfunc; -struct duk_hboundfunc; -struct duk_hthread; -struct duk_hbufobj; -struct duk_hdecenv; -struct duk_hobjenv; -struct duk_hproxy; -struct duk_hbuffer; -struct duk_hbuffer_fixed; -struct duk_hbuffer_dynamic; -struct duk_hbuffer_external; - -struct duk_propaccessor; -union duk_propvalue; -struct duk_propdesc; - -struct duk_heap; -struct duk_breakpoint; - -struct duk_activation; -struct duk_catcher; -struct duk_strcache; -struct duk_ljstate; -struct duk_strtab_entry; - -#if defined(DUK_USE_DEBUG) -struct duk_fixedbuffer; -#endif - -struct duk_bitdecoder_ctx; -struct duk_bitencoder_ctx; -struct duk_bufwriter_ctx; - -struct duk_token; -struct duk_re_token; -struct duk_lexer_point; -struct duk_lexer_ctx; -struct duk_lexer_codepoint; - -struct duk_compiler_instr; -struct duk_compiler_func; -struct duk_compiler_ctx; - -struct duk_re_matcher_ctx; -struct duk_re_compiler_ctx; - -#if defined(DUK_USE_CPP_EXCEPTIONS) -/* no typedef */ -#else -typedef struct duk_jmpbuf duk_jmpbuf; -#endif - -/* duk_tval intentionally skipped */ -typedef struct duk_heaphdr duk_heaphdr; -typedef struct duk_heaphdr_string duk_heaphdr_string; -typedef struct duk_harray duk_harray; -typedef struct duk_hstring duk_hstring; -typedef struct duk_hstring_external duk_hstring_external; -typedef struct duk_hobject duk_hobject; -typedef struct duk_hcompfunc duk_hcompfunc; -typedef struct duk_hnatfunc duk_hnatfunc; -typedef struct duk_hboundfunc duk_hboundfunc; -typedef struct duk_hthread duk_hthread; -typedef struct duk_hbufobj duk_hbufobj; -typedef struct duk_hdecenv duk_hdecenv; -typedef struct duk_hobjenv duk_hobjenv; -typedef struct duk_hproxy duk_hproxy; -typedef struct duk_hbuffer duk_hbuffer; -typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; -typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic; -typedef struct duk_hbuffer_external duk_hbuffer_external; - -typedef struct duk_propaccessor duk_propaccessor; -typedef union duk_propvalue duk_propvalue; -typedef struct duk_propdesc duk_propdesc; - -typedef struct duk_heap duk_heap; -typedef struct duk_breakpoint duk_breakpoint; - -typedef struct duk_activation duk_activation; -typedef struct duk_catcher duk_catcher; -typedef struct duk_strcache duk_strcache; -typedef struct duk_ljstate duk_ljstate; -typedef struct duk_strtab_entry duk_strtab_entry; - -#if defined(DUK_USE_DEBUG) -typedef struct duk_fixedbuffer duk_fixedbuffer; -#endif - -typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx; -typedef struct duk_bitencoder_ctx duk_bitencoder_ctx; -typedef struct duk_bufwriter_ctx duk_bufwriter_ctx; - -typedef struct duk_token duk_token; -typedef struct duk_re_token duk_re_token; -typedef struct duk_lexer_point duk_lexer_point; -typedef struct duk_lexer_ctx duk_lexer_ctx; -typedef struct duk_lexer_codepoint duk_lexer_codepoint; - -typedef struct duk_compiler_instr duk_compiler_instr; -typedef struct duk_compiler_func duk_compiler_func; -typedef struct duk_compiler_ctx duk_compiler_ctx; - -typedef struct duk_re_matcher_ctx duk_re_matcher_ctx; -typedef struct duk_re_compiler_ctx duk_re_compiler_ctx; - -#endif /* DUK_FORWDECL_H_INCLUDED */ -/* #include duk_tval.h */ -#line 1 "duk_tval.h" -/* - * Tagged type definition (duk_tval) and accessor macros. - * - * Access all fields through the accessor macros, as the representation - * is quite tricky. - * - * There are two packed type alternatives: an 8-byte representation - * based on an IEEE double (preferred for compactness), and a 12-byte - * representation (portability). The latter is needed also in e.g. - * 64-bit environments (it usually pads to 16 bytes per value). - * - * Selecting the tagged type format involves many trade-offs (memory - * use, size and performance of generated code, portability, etc). - * - * NB: because macro arguments are often expressions, macros should - * avoid evaluating their argument more than once. - */ - -#if !defined(DUK_TVAL_H_INCLUDED) -#define DUK_TVAL_H_INCLUDED - -/* sanity */ -#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE) -#error unsupported: cannot determine byte order variant -#endif - -#if defined(DUK_USE_PACKED_TVAL) -/* ======================================================================== */ - -/* - * Packed 8-byte representation - */ - -/* use duk_double_union as duk_tval directly */ -typedef union duk_double_union duk_tval; -typedef struct { - duk_uint16_t a; - duk_uint16_t b; - duk_uint16_t c; - duk_uint16_t d; -} duk_tval_unused; - -/* tags */ -#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */ -/* avoid tag 0xfff0, no risk of confusion with negative infinity */ -#define DUK_TAG_MIN 0xfff1UL -#if defined(DUK_USE_FASTINT) -#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */ -#endif -#define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */ -#define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */ -#define DUK_TAG_NULL 0xfff4UL /* embed: nothing */ -#define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */ -/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */ -#define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */ -#define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */ -#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */ -#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */ -#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */ -#define DUK_TAG_MAX 0xfffaUL - -/* for convenience */ -#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL -#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL - -#define DUK_TVAL_IS_VALID_TAG(tv) \ - (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) - -/* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */ -#define DUK_TVAL_UNUSED_INITIALIZER() \ - { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED } - -/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */ -#if defined(DUK_USE_64BIT_OPS) -#if defined(DUK_USE_DOUBLE_ME) -#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ - (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \ - } while (0) -#else -#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ - (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \ - } while (0) -#endif -#else /* DUK_USE_64BIT_OPS */ -#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \ - duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \ - } while (0) -#endif /* DUK_USE_64BIT_OPS */ - -#if defined(DUK_USE_64BIT_OPS) -/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */ -#if defined(DUK_USE_DOUBLE_ME) -#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ - (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \ - ((duk_uint64_t) (flags)) | \ - (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \ - } while (0) -#else -#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ - (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \ - (((duk_uint64_t) (flags)) << 32) | \ - ((duk_uint64_t) (duk_uint32_t) (fp)); \ - } while (0) -#endif -#else /* DUK_USE_64BIT_OPS */ -#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \ - duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \ - } while (0) -#endif /* DUK_USE_64BIT_OPS */ - -#if defined(DUK_USE_FASTINT) -/* Note: masking is done for 'i' to deal with negative numbers correctly */ -#if defined(DUK_USE_DOUBLE_ME) -#define DUK__TVAL_SET_I48(tv,i) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \ - duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ - } while (0) -#define DUK__TVAL_SET_U32(tv,i) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \ - duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ - } while (0) -#else -#define DUK__TVAL_SET_I48(tv,i) do { \ - (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \ - } while (0) -#define DUK__TVAL_SET_U32(tv,i) do { \ - (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \ - } while (0) -#endif - -/* This needs to go through a cast because sign extension is needed. */ -#define DUK__TVAL_SET_I32(tv,i) do { \ - duk_int64_t duk__tmp = (duk_int64_t) (i); \ - DUK_TVAL_SET_I48((tv), duk__tmp); \ - } while (0) - -/* XXX: Clumsy sign extend and masking of 16 topmost bits. */ -#if defined(DUK_USE_DOUBLE_ME) -#define DUK__TVAL_GET_FASTINT(tv) (((duk_int64_t) ((((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16) -#else -#define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16) -#endif -#define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1]) -#define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1]) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_UNDEFINED(tv) do { \ - (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \ - } while (0) -#define DUK_TVAL_SET_UNUSED(tv) do { \ - (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \ - } while (0) -#define DUK_TVAL_SET_NULL(tv) do { \ - (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \ - } while (0) - -#define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val))) - -#define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv)) - -/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */ -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_DOUBLE(tv,d) do { \ - duk_double_t duk__dblval; \ - duk__dblval = (d); \ - DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ - DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ - } while (0) -#define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i)) -#define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i)) -#define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i)) -#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d)) -#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d)) -#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) -#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ - duk_tval *duk__tv; \ - duk_double_t duk__d; \ - duk__tv = (tv); \ - if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ - duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ - DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ - } \ - } while (0) -#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ - duk_tval *duk__tv; \ - duk_double_t duk__d; \ - duk__tv = (tv); \ - if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ - duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ - DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ - } \ - } while (0) -#else /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_DOUBLE(tv,d) do { \ - duk_double_t duk__dblval; \ - duk__dblval = (d); \ - DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ - DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ - } while (0) -#define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */ -#define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) -#define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) -#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) -#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) -#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) -#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) -#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */ - -#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags)) -#define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING) -#define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT) -#define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER) -#define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER) - -#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) - -/* getters */ -#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1]) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) -#define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv)) -#define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv)) -#define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv)) -#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv)) -#else -#define DUK_TVAL_GET_NUMBER(tv) ((tv)->d) -#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) -#endif -#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ - (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \ - (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \ - } while (0) -#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1])) -#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL) -#define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1]) -#define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1]) -#define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1]) -#define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1]) -#define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1]) - -/* decoding */ -#define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0]) - -#define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED) -#define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED) -#define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL) -#define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN) -#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE) -#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE) -#define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC) -#define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING) -#define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT) -#define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER) -#define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER) -#if defined(DUK_USE_FASTINT) -/* 0xfff0 is -Infinity */ -#define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) -#define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT) -#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL) -#else -#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) -#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) -#endif - -/* This is performance critical because it appears in every DECREF. */ -#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING) - -#if defined(DUK_USE_FASTINT) -DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv); -#endif - -#else /* DUK_USE_PACKED_TVAL */ -/* ======================================================================== */ - -/* - * Portable 12-byte representation - */ - -/* Note: not initializing all bytes is normally not an issue: Duktape won't - * read or use the uninitialized bytes so valgrind won't issue warnings. - * In some special cases a harmless valgrind warning may be issued though. - * For example, the DumpHeap debugger command writes out a compiled function's - * 'data' area as is, including any uninitialized bytes, which causes a - * valgrind warning. - */ - -typedef struct duk_tval_struct duk_tval; - -struct duk_tval_struct { - duk_small_uint_t t; - duk_small_uint_t v_extra; - union { - duk_double_t d; - duk_small_int_t i; -#if defined(DUK_USE_FASTINT) - duk_int64_t fi; /* if present, forces 16-byte duk_tval */ -#endif - void *voidptr; - duk_hstring *hstring; - duk_hobject *hobject; - duk_hcompfunc *hcompfunc; - duk_hnatfunc *hnatfunc; - duk_hthread *hthread; - duk_hbuffer *hbuffer; - duk_heaphdr *heaphdr; - duk_c_function lightfunc; - } v; -}; - -typedef struct { - duk_small_uint_t t; - duk_small_uint_t v_extra; - /* The rest of the fields don't matter except for debug dumps and such - * for which a partial initializer may trigger out-ot-bounds memory - * reads. Include a double field which is usually as large or larger - * than pointers (not always however). - */ - duk_double_t d; -} duk_tval_unused; - -#define DUK_TVAL_UNUSED_INITIALIZER() \ - { DUK_TAG_UNUSED, 0, 0.0 } - -#define DUK_TAG_MIN 0 -#define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */ -#if defined(DUK_USE_FASTINT) -#define DUK_TAG_FASTINT 1 -#endif -#define DUK_TAG_UNDEFINED 2 -#define DUK_TAG_NULL 3 -#define DUK_TAG_BOOLEAN 4 -#define DUK_TAG_POINTER 5 -#define DUK_TAG_LIGHTFUNC 6 -#define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */ -#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */ -#define DUK_TAG_OBJECT 9 -#define DUK_TAG_BUFFER 10 -#define DUK_TAG_MAX 10 - -#define DUK_TVAL_IS_VALID_TAG(tv) \ - (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) - -/* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code - * to support the 8-byte representation. Further, it is a non-heap-allocated - * type so it should come before DUK_TAG_STRING. Finally, it should not break - * the tag value ranges covered by case-clauses in a switch-case. - */ - -/* setters */ -#define DUK_TVAL_SET_UNDEFINED(tv) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_UNDEFINED; \ - } while (0) - -#define DUK_TVAL_SET_UNUSED(tv) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_UNUSED; \ - } while (0) - -#define DUK_TVAL_SET_NULL(tv) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_NULL; \ - } while (0) - -#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_BOOLEAN; \ - duk__tv->v.i = (duk_small_int_t) (val); \ - } while (0) - -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_DOUBLE(tv,val) do { \ - duk_tval *duk__tv; \ - duk_double_t duk__dblval; \ - duk__dblval = (val); \ - DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_NUMBER; \ - duk__tv->v.d = duk__dblval; \ - } while (0) -#define DUK_TVAL_SET_I48(tv,val) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_FASTINT; \ - duk__tv->v.fi = (val); \ - } while (0) -#define DUK_TVAL_SET_U32(tv,val) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_FASTINT; \ - duk__tv->v.fi = (duk_int64_t) (val); \ - } while (0) -#define DUK_TVAL_SET_I32(tv,val) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_FASTINT; \ - duk__tv->v.fi = (duk_int64_t) (val); \ - } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ - duk_tval_set_number_chkfast_fast((tv), (d)) -#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ - duk_tval_set_number_chkfast_slow((tv), (d)) -#define DUK_TVAL_SET_NUMBER(tv,val) \ - DUK_TVAL_SET_DOUBLE((tv), (val)) -#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ - duk_tval *duk__tv; \ - duk_double_t duk__d; \ - duk__tv = (tv); \ - if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ - duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ - DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ - } \ - } while (0) -#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ - duk_tval *duk__tv; \ - duk_double_t duk__d; \ - duk__tv = (tv); \ - if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ - duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ - DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ - } \ - } while (0) -#else /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_DOUBLE(tv,d) \ - DUK_TVAL_SET_NUMBER((tv), (d)) -#define DUK_TVAL_SET_I48(tv,val) \ - DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */ -#define DUK_TVAL_SET_U32(tv,val) \ - DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) -#define DUK_TVAL_SET_I32(tv,val) \ - DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) -#define DUK_TVAL_SET_NUMBER(tv,val) do { \ - duk_tval *duk__tv; \ - duk_double_t duk__dblval; \ - duk__dblval = (val); \ - DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_NUMBER; \ - duk__tv->v.d = duk__dblval; \ - } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ - DUK_TVAL_SET_NUMBER((tv), (d)) -#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ - DUK_TVAL_SET_NUMBER((tv), (d)) -#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) -#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_FASTINT(tv,i) \ - DUK_TVAL_SET_I48((tv), (i)) /* alias */ - -#define DUK_TVAL_SET_POINTER(tv,hptr) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_POINTER; \ - duk__tv->v.voidptr = (hptr); \ - } while (0) - -#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_LIGHTFUNC; \ - duk__tv->v_extra = (flags); \ - duk__tv->v.lightfunc = (duk_c_function) (fp); \ - } while (0) - -#define DUK_TVAL_SET_STRING(tv,hptr) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_STRING; \ - duk__tv->v.hstring = (hptr); \ - } while (0) - -#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_OBJECT; \ - duk__tv->v.hobject = (hptr); \ - } while (0) - -#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_BUFFER; \ - duk__tv->v.hbuffer = (hptr); \ - } while (0) - -#define DUK_TVAL_SET_NAN(tv) do { \ - /* in non-packed representation we don't care about which NaN is used */ \ - duk_tval *duk__tv; \ - duk__tv = (tv); \ - duk__tv->t = DUK_TAG_NUMBER; \ - duk__tv->v.d = DUK_DOUBLE_NAN; \ - } while (0) - -#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) - -/* getters */ -#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->v.i) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) -#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi) -#define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi)) -#define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi)) -#if 0 -#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ - (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \ - DUK_TVAL_GET_DOUBLE((tv))) -#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv)) -#else -/* This seems reasonable overall. */ -#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ - duk_tval_get_number_unpacked_fastint((tv)) : \ - DUK_TVAL_GET_DOUBLE((tv))) -#endif -#else -#define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d) -#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) -#endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr) -#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ - (out_flags) = (duk_uint32_t) (tv)->v_extra; \ - (out_fp) = (tv)->v.lightfunc; \ - } while (0) -#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc) -#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_small_uint_t) ((tv)->v_extra)) -#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring) -#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject) -#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer) -#define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr) - -/* decoding */ -#define DUK_TVAL_GET_TAG(tv) ((tv)->t) -#define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED) -#define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED) -#define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL) -#define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN) -#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0)) -#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0)) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER) -#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT) -#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \ - (tv)->t == DUK_TAG_FASTINT) -#else -#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER) -#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) -#endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER) -#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC) -#define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING) -#define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT) -#define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER) - -/* This is performance critical because it's needed for every DECREF. - * Take advantage of the fact that the first heap allocated tag is 8, - * so that bit 3 is set for all heap allocated tags (and never set for - * non-heap-allocated tags). - */ -#if 0 -#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING) -#endif -#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08) - -#if defined(DUK_USE_FASTINT) -#if 0 -DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv); -#endif -DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv); -#endif - -#endif /* DUK_USE_PACKED_TVAL */ - -/* - * Convenience (independent of representation) - */ - -#define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1) -#define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0) - -#define DUK_TVAL_STRING_IS_SYMBOL(tv) \ - DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv))) - -/* Lightfunc flags packing and unpacking. */ -/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##. - * Avoid signed shifts due to portability limitations. - */ -#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \ - ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8)) -#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \ - (((lf_flags) >> 4) & 0x0fU) -#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \ - ((lf_flags) & 0x0fU) -#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \ - ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs) - -#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */ -#define DUK_LFUNC_NARGS_MIN 0x00 -#define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */ -#define DUK_LFUNC_LENGTH_MIN 0x00 -#define DUK_LFUNC_LENGTH_MAX 0x0f -#define DUK_LFUNC_MAGIC_MIN (-0x80) -#define DUK_LFUNC_MAGIC_MAX 0x7f - -/* fastint constants etc */ -#if defined(DUK_USE_FASTINT) -#define DUK_FASTINT_MIN (DUK_I64_CONSTANT(-0x800000000000)) -#define DUK_FASTINT_MAX (DUK_I64_CONSTANT(0x7fffffffffff)) -#define DUK_FASTINT_BITS 48 - -DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x); -DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x); -#endif - -#endif /* DUK_TVAL_H_INCLUDED */ -/* #include duk_builtins.h */ -#line 1 "duk_builtins.h" -/* - * Automatically generated by genbuiltins.py, do not edit! - */ - -#if !defined(DUK_BUILTINS_H_INCLUDED) -#define DUK_BUILTINS_H_INCLUDED - -#if defined(DUK_USE_ROM_STRINGS) -#error ROM support not enabled, rerun configure.py with --rom-support -#else /* DUK_USE_ROM_STRINGS */ -#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */ -#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED) -#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED) -#define DUK_STRIDX_UC_NULL 1 /* 'Null' */ -#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL) -#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL) -#define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */ -#define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL) -#define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL) -#define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */ -#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS) -#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS) -#define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */ -#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT) -#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT) -#define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */ -#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION) -#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION) -#define DUK_STRIDX_ARRAY 6 /* 'Array' */ -#define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY) -#define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY) -#define DUK_STRIDX_UC_STRING 7 /* 'String' */ -#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING) -#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING) -#define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */ -#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN) -#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN) -#define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */ -#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER) -#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER) -#define DUK_STRIDX_DATE 10 /* 'Date' */ -#define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE) -#define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE) -#define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */ -#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP) -#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP) -#define DUK_STRIDX_UC_ERROR 12 /* 'Error' */ -#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR) -#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR) -#define DUK_STRIDX_MATH 13 /* 'Math' */ -#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH) -#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH) -#define DUK_STRIDX_JSON 14 /* 'JSON' */ -#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON) -#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON) -#define DUK_STRIDX_EMPTY_STRING 15 /* '' */ -#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING) -#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING) -#define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */ -#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER) -#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER) -#define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */ -#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW) -#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW) -#define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */ -#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY) -#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY) -#define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */ -#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY) -#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY) -#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */ -#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY) -#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY) -#define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */ -#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY) -#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY) -#define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */ -#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY) -#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY) -#define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */ -#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY) -#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY) -#define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */ -#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY) -#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY) -#define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */ -#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY) -#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY) -#define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */ -#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY) -#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY) -#define DUK_STRIDX_GLOBAL 27 /* 'global' */ -#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL) -#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL) -#define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */ -#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV) -#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV) -#define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */ -#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV) -#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV) -#define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */ -#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER) -#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER) -#define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */ -#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER) -#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER) -#define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */ -#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD) -#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD) -#define DUK_STRIDX_EVAL 33 /* 'eval' */ -#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL) -#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL) -#define DUK_STRIDX_VALUE 34 /* 'value' */ -#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE) -#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE) -#define DUK_STRIDX_WRITABLE 35 /* 'writable' */ -#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE) -#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE) -#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */ -#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE) -#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE) -#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */ -#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE) -#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE) -#define DUK_STRIDX_JOIN 38 /* 'join' */ -#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN) -#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN) -#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */ -#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING) -#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING) -#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */ -#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF) -#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF) -#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */ -#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING) -#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING) -#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */ -#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING) -#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING) -#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */ -#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING) -#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING) -#define DUK_STRIDX_SOURCE 44 /* 'source' */ -#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE) -#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE) -#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */ -#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE) -#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE) -#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */ -#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE) -#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE) -#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */ -#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX) -#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX) -#define DUK_STRIDX_FLAGS 48 /* 'flags' */ -#define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS) -#define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS) -#define DUK_STRIDX_INDEX 49 /* 'index' */ -#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX) -#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX) -#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */ -#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE) -#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE) -#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */ -#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR) -#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR) -#define DUK_STRIDX_MESSAGE 52 /* 'message' */ -#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE) -#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE) -#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */ -#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN) -#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN) -#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */ -#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER) -#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER) -#define DUK_STRIDX_LC_STRING 55 /* 'string' */ -#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING) -#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING) -#define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */ -#define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL) -#define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL) -#define DUK_STRIDX_LC_OBJECT 57 /* 'object' */ -#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT) -#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT) -#define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */ -#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED) -#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED) -#define DUK_STRIDX_NAN 59 /* 'NaN' */ -#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN) -#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN) -#define DUK_STRIDX_INFINITY 60 /* 'Infinity' */ -#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY) -#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY) -#define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */ -#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY) -#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY) -#define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */ -#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO) -#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO) -#define DUK_STRIDX_COMMA 63 /* ',' */ -#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA) -#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA) -#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */ -#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE) -#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE) -#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */ -#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS) -#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS) -#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */ -#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE) -#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE) -#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */ -#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS) -#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS) -#define DUK_STRIDX_CALLEE 68 /* 'callee' */ -#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE) -#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE) -#define DUK_STRIDX_CALLER 69 /* 'caller' */ -#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER) -#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER) -#define DUK_STRIDX_APPLY 70 /* 'apply' */ -#define DUK_HEAP_STRING_APPLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY) -#define DUK_HTHREAD_STRING_APPLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY) -#define DUK_STRIDX_CONSTRUCT 71 /* 'construct' */ -#define DUK_HEAP_STRING_CONSTRUCT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT) -#define DUK_HTHREAD_STRING_CONSTRUCT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT) -#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */ -#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY) -#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY) -#define DUK_STRIDX_GET 73 /* 'get' */ -#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET) -#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET) -#define DUK_STRIDX_HAS 74 /* 'has' */ -#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS) -#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS) -#define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */ -#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS) -#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS) -#define DUK_STRIDX_SET_PROTOTYPE_OF 76 /* 'setPrototypeOf' */ -#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF) -#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF) -#define DUK_STRIDX___PROTO__ 77 /* '__proto__' */ -#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__) -#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__) -#define DUK_STRIDX_TO_STRING 78 /* 'toString' */ -#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING) -#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING) -#define DUK_STRIDX_TO_JSON 79 /* 'toJSON' */ -#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON) -#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON) -#define DUK_STRIDX_TYPE 80 /* 'type' */ -#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE) -#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE) -#define DUK_STRIDX_DATA 81 /* 'data' */ -#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA) -#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA) -#define DUK_STRIDX_LENGTH 82 /* 'length' */ -#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH) -#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH) -#define DUK_STRIDX_SET 83 /* 'set' */ -#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET) -#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET) -#define DUK_STRIDX_STACK 84 /* 'stack' */ -#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK) -#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK) -#define DUK_STRIDX_PC 85 /* 'pc' */ -#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC) -#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC) -#define DUK_STRIDX_LINE_NUMBER 86 /* 'lineNumber' */ -#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER) -#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER) -#define DUK_STRIDX_INT_TRACEDATA 87 /* '\x82Tracedata' */ -#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA) -#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA) -#define DUK_STRIDX_NAME 88 /* 'name' */ -#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME) -#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME) -#define DUK_STRIDX_FILE_NAME 89 /* 'fileName' */ -#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME) -#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME) -#define DUK_STRIDX_LC_POINTER 90 /* 'pointer' */ -#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER) -#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER) -#define DUK_STRIDX_INT_TARGET 91 /* '\x82Target' */ -#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET) -#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET) -#define DUK_STRIDX_INT_NEXT 92 /* '\x82Next' */ -#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT) -#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT) -#define DUK_STRIDX_INT_BYTECODE 93 /* '\x82Bytecode' */ -#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE) -#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE) -#define DUK_STRIDX_INT_FORMALS 94 /* '\x82Formals' */ -#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS) -#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS) -#define DUK_STRIDX_INT_VARMAP 95 /* '\x82Varmap' */ -#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP) -#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP) -#define DUK_STRIDX_INT_SOURCE 96 /* '\x82Source' */ -#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE) -#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE) -#define DUK_STRIDX_INT_PC2LINE 97 /* '\x82Pc2line' */ -#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE) -#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE) -#define DUK_STRIDX_INT_MAP 98 /* '\x82Map' */ -#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP) -#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP) -#define DUK_STRIDX_INT_VARENV 99 /* '\x82Varenv' */ -#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV) -#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV) -#define DUK_STRIDX_INT_FINALIZER 100 /* '\x82Finalizer' */ -#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER) -#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER) -#define DUK_STRIDX_INT_VALUE 101 /* '\x82Value' */ -#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE) -#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE) -#define DUK_STRIDX_COMPILE 102 /* 'compile' */ -#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE) -#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE) -#define DUK_STRIDX_INPUT 103 /* 'input' */ -#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT) -#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT) -#define DUK_STRIDX_ERR_CREATE 104 /* 'errCreate' */ -#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE) -#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE) -#define DUK_STRIDX_ERR_THROW 105 /* 'errThrow' */ -#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW) -#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW) -#define DUK_STRIDX_ENV 106 /* 'env' */ -#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV) -#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV) -#define DUK_STRIDX_HEX 107 /* 'hex' */ -#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX) -#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX) -#define DUK_STRIDX_BASE64 108 /* 'base64' */ -#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64) -#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64) -#define DUK_STRIDX_JX 109 /* 'jx' */ -#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX) -#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX) -#define DUK_STRIDX_JC 110 /* 'jc' */ -#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC) -#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC) -#define DUK_STRIDX_JSON_EXT_UNDEFINED 111 /* '{"_undef":true}' */ -#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED) -#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED) -#define DUK_STRIDX_JSON_EXT_NAN 112 /* '{"_nan":true}' */ -#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN) -#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN) -#define DUK_STRIDX_JSON_EXT_POSINF 113 /* '{"_inf":true}' */ -#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF) -#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF) -#define DUK_STRIDX_JSON_EXT_NEGINF 114 /* '{"_ninf":true}' */ -#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF) -#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF) -#define DUK_STRIDX_JSON_EXT_FUNCTION1 115 /* '{"_func":true}' */ -#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1) -#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1) -#define DUK_STRIDX_JSON_EXT_FUNCTION2 116 /* '{_func:true}' */ -#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2) -#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2) -#define DUK_STRIDX_BREAK 117 /* 'break' */ -#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK) -#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK) -#define DUK_STRIDX_CASE 118 /* 'case' */ -#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE) -#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE) -#define DUK_STRIDX_CATCH 119 /* 'catch' */ -#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH) -#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH) -#define DUK_STRIDX_CONTINUE 120 /* 'continue' */ -#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE) -#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE) -#define DUK_STRIDX_DEBUGGER 121 /* 'debugger' */ -#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER) -#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER) -#define DUK_STRIDX_DEFAULT 122 /* 'default' */ -#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT) -#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT) -#define DUK_STRIDX_DELETE 123 /* 'delete' */ -#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE) -#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE) -#define DUK_STRIDX_DO 124 /* 'do' */ -#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO) -#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO) -#define DUK_STRIDX_ELSE 125 /* 'else' */ -#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE) -#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE) -#define DUK_STRIDX_FINALLY 126 /* 'finally' */ -#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY) -#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY) -#define DUK_STRIDX_FOR 127 /* 'for' */ -#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR) -#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR) -#define DUK_STRIDX_LC_FUNCTION 128 /* 'function' */ -#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION) -#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION) -#define DUK_STRIDX_IF 129 /* 'if' */ -#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF) -#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF) -#define DUK_STRIDX_IN 130 /* 'in' */ -#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN) -#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN) -#define DUK_STRIDX_INSTANCEOF 131 /* 'instanceof' */ -#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF) -#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF) -#define DUK_STRIDX_NEW 132 /* 'new' */ -#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW) -#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW) -#define DUK_STRIDX_RETURN 133 /* 'return' */ -#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN) -#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN) -#define DUK_STRIDX_SWITCH 134 /* 'switch' */ -#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH) -#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH) -#define DUK_STRIDX_THIS 135 /* 'this' */ -#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS) -#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS) -#define DUK_STRIDX_THROW 136 /* 'throw' */ -#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW) -#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW) -#define DUK_STRIDX_TRY 137 /* 'try' */ -#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY) -#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY) -#define DUK_STRIDX_TYPEOF 138 /* 'typeof' */ -#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF) -#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF) -#define DUK_STRIDX_VAR 139 /* 'var' */ -#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR) -#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR) -#define DUK_STRIDX_CONST 140 /* 'const' */ -#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) -#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) -#define DUK_STRIDX_VOID 141 /* 'void' */ -#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID) -#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID) -#define DUK_STRIDX_WHILE 142 /* 'while' */ -#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE) -#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE) -#define DUK_STRIDX_WITH 143 /* 'with' */ -#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH) -#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH) -#define DUK_STRIDX_CLASS 144 /* 'class' */ -#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS) -#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS) -#define DUK_STRIDX_ENUM 145 /* 'enum' */ -#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM) -#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM) -#define DUK_STRIDX_EXPORT 146 /* 'export' */ -#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT) -#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT) -#define DUK_STRIDX_EXTENDS 147 /* 'extends' */ -#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS) -#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS) -#define DUK_STRIDX_IMPORT 148 /* 'import' */ -#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT) -#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT) -#define DUK_STRIDX_SUPER 149 /* 'super' */ -#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER) -#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER) -#define DUK_STRIDX_LC_NULL 150 /* 'null' */ -#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL) -#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL) -#define DUK_STRIDX_TRUE 151 /* 'true' */ -#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE) -#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE) -#define DUK_STRIDX_FALSE 152 /* 'false' */ -#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE) -#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE) -#define DUK_STRIDX_IMPLEMENTS 153 /* 'implements' */ -#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS) -#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS) -#define DUK_STRIDX_INTERFACE 154 /* 'interface' */ -#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE) -#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE) -#define DUK_STRIDX_LET 155 /* 'let' */ -#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET) -#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET) -#define DUK_STRIDX_PACKAGE 156 /* 'package' */ -#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE) -#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE) -#define DUK_STRIDX_PRIVATE 157 /* 'private' */ -#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE) -#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE) -#define DUK_STRIDX_PROTECTED 158 /* 'protected' */ -#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED) -#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED) -#define DUK_STRIDX_PUBLIC 159 /* 'public' */ -#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC) -#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC) -#define DUK_STRIDX_STATIC 160 /* 'static' */ -#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC) -#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC) -#define DUK_STRIDX_YIELD 161 /* 'yield' */ -#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD) -#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD) - -#define DUK_HEAP_NUM_STRINGS 162 -#define DUK_STRIDX_START_RESERVED 117 -#define DUK_STRIDX_START_STRICT_RESERVED 153 -#define DUK_STRIDX_END_RESERVED 162 /* exclusive endpoint */ - -/* To convert a heap stridx to a token number, subtract - * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED. - */ -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[892]; -#endif /* !DUK_SINGLE_FILE */ -#define DUK_STRDATA_MAX_STRLEN 17 -#define DUK_STRDATA_DATA_LENGTH 892 -#endif /* DUK_USE_ROM_STRINGS */ - -#if defined(DUK_USE_ROM_OBJECTS) -#error RAM support not enabled, rerun configure.py with --ram-support -#else /* DUK_USE_ROM_OBJECTS */ -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_length(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_name(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_clz32(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_imul(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_sign(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_apply(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_construct(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx); -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[176]; -#endif /* !DUK_SINGLE_FILE */ -#define DUK_BIDX_GLOBAL 0 -#define DUK_BIDX_GLOBAL_ENV 1 -#define DUK_BIDX_OBJECT_CONSTRUCTOR 2 -#define DUK_BIDX_OBJECT_PROTOTYPE 3 -#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4 -#define DUK_BIDX_FUNCTION_PROTOTYPE 5 -#define DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE 6 -#define DUK_BIDX_ARRAY_CONSTRUCTOR 7 -#define DUK_BIDX_ARRAY_PROTOTYPE 8 -#define DUK_BIDX_STRING_CONSTRUCTOR 9 -#define DUK_BIDX_STRING_PROTOTYPE 10 -#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 11 -#define DUK_BIDX_BOOLEAN_PROTOTYPE 12 -#define DUK_BIDX_NUMBER_CONSTRUCTOR 13 -#define DUK_BIDX_NUMBER_PROTOTYPE 14 -#define DUK_BIDX_DATE_CONSTRUCTOR 15 -#define DUK_BIDX_DATE_PROTOTYPE 16 -#define DUK_BIDX_REGEXP_CONSTRUCTOR 17 -#define DUK_BIDX_REGEXP_PROTOTYPE 18 -#define DUK_BIDX_ERROR_CONSTRUCTOR 19 -#define DUK_BIDX_ERROR_PROTOTYPE 20 -#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 21 -#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 22 -#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 23 -#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 24 -#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 25 -#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 26 -#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 27 -#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 28 -#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 29 -#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 30 -#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 31 -#define DUK_BIDX_URI_ERROR_PROTOTYPE 32 -#define DUK_BIDX_TYPE_ERROR_THROWER 33 -#define DUK_BIDX_DUKTAPE 34 -#define DUK_BIDX_THREAD_PROTOTYPE 35 -#define DUK_BIDX_POINTER_PROTOTYPE 36 -#define DUK_BIDX_DOUBLE_ERROR 37 -#define DUK_BIDX_SYMBOL_PROTOTYPE 38 -#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 39 -#define DUK_BIDX_DATAVIEW_PROTOTYPE 40 -#define DUK_BIDX_INT8ARRAY_PROTOTYPE 41 -#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 42 -#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 43 -#define DUK_BIDX_INT16ARRAY_PROTOTYPE 44 -#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 45 -#define DUK_BIDX_INT32ARRAY_PROTOTYPE 46 -#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 47 -#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 48 -#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 49 -#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50 -#define DUK_NUM_BUILTINS 51 -#define DUK_NUM_BIDX_BUILTINS 51 -#define DUK_NUM_ALL_BUILTINS 76 -#if defined(DUK_USE_DOUBLE_LE) -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972]; -#endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3972 -#elif defined(DUK_USE_DOUBLE_BE) -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972]; -#endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3972 -#elif defined(DUK_USE_DOUBLE_ME) -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972]; -#endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3972 -#else -#error invalid endianness defines -#endif -#endif /* DUK_USE_ROM_OBJECTS */ -#endif /* DUK_BUILTINS_H_INCLUDED */ -#line 51 "duk_internal.h" - -/* #include duk_util.h */ -#line 1 "duk_util.h" -/* - * Utilities - */ - -#if !defined(DUK_UTIL_H_INCLUDED) -#define DUK_UTIL_H_INCLUDED - -#if defined(DUK_USE_GET_RANDOM_DOUBLE) -#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata) -#else -#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr) -#endif - -/* - * Some useful constants - */ - -#define DUK_DOUBLE_2TO32 4294967296.0 -#define DUK_DOUBLE_2TO31 2147483648.0 -#define DUK_DOUBLE_LOG2E 1.4426950408889634 -#define DUK_DOUBLE_LOG10E 0.4342944819032518 - -/* - * Endian conversion - */ - -#if defined(DUK_USE_INTEGER_LE) -#define DUK_HTON32(x) DUK_BSWAP32((x)) -#define DUK_NTOH32(x) DUK_BSWAP32((x)) -#define DUK_HTON16(x) DUK_BSWAP16((x)) -#define DUK_NTOH16(x) DUK_BSWAP16((x)) -#elif defined(DUK_USE_INTEGER_BE) -#define DUK_HTON32(x) (x) -#define DUK_NTOH32(x) (x) -#define DUK_HTON16(x) (x) -#define DUK_NTOH16(x) (x) -#else -#error internal error, endianness defines broken -#endif - -/* - * Bitstream decoder - */ - -struct duk_bitdecoder_ctx { - const duk_uint8_t *data; - duk_size_t offset; - duk_size_t length; - duk_uint32_t currval; - duk_small_int_t currbits; -}; - -#define DUK_BD_BITPACKED_STRING_MAXLEN 256 - -/* - * Bitstream encoder - */ - -struct duk_bitencoder_ctx { - duk_uint8_t *data; - duk_size_t offset; - duk_size_t length; - duk_uint32_t currval; - duk_small_int_t currbits; - duk_small_int_t truncated; -}; - -/* - * Raw write/read macros for big endian, unaligned basic values. - * Caller ensures there's enough space. The macros update the pointer - * argument automatically on resizes. The idiom seems a bit odd, but - * leads to compact code. - */ - -#define DUK_RAW_WRITE_U8(ptr,val) do { \ - *(ptr)++ = (duk_uint8_t) (val); \ - } while (0) -#define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val)) -#define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val)) -#define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val)) -#define DUK_RAW_WRITE_XUTF8(ptr,val) do { \ - /* 'ptr' is evaluated both as LHS and RHS. */ \ - duk_uint8_t *duk__ptr; \ - duk_small_int_t duk__len; \ - duk__ptr = (duk_uint8_t *) (ptr); \ - duk__len = duk_unicode_encode_xutf8((duk_ucodepoint_t) (val), duk__ptr); \ - duk__ptr += duk__len; \ - (ptr) = duk__ptr; \ - } while (0) -#define DUK_RAW_WRITE_CESU8(ptr,val) do { \ - /* 'ptr' is evaluated both as LHS and RHS. */ \ - duk_uint8_t *duk__ptr; \ - duk_small_int_t duk__len; \ - duk__ptr = (duk_uint8_t *) (ptr); \ - duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \ - duk__ptr += duk__len; \ - (ptr) = duk__ptr; \ - } while (0) - -#define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++)) -#define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr)); -#define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr)); -#define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr)); - -/* - * Buffer writer (dynamic buffer only) - * - * Helper for writing to a dynamic buffer with a concept of a "slack" area - * to reduce resizes. You can ensure there is enough space beforehand and - * then write for a while without further checks, relying on a stable data - * pointer. Slack handling is automatic so call sites only indicate how - * much data they need right now. - * - * There are several ways to write using bufwriter. The best approach - * depends mainly on how much performance matters over code footprint. - * The key issues are (1) ensuring there is space and (2) keeping the - * pointers consistent. Fast code should ensure space for multiple writes - * with one ensure call. Fastest inner loop code can temporarily borrow - * the 'p' pointer but must write it back eventually. - * - * Be careful to ensure all macro arguments (other than static pointers like - * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if - * necessary (if that's not possible, there should be a note near the macro). - * Buffer write arguments often contain arithmetic etc so this is - * particularly important here. - */ - -/* XXX: Migrate bufwriter and other read/write helpers to its own header? */ - -struct duk_bufwriter_ctx { - duk_uint8_t *p; - duk_uint8_t *p_base; - duk_uint8_t *p_limit; - duk_hbuffer_dynamic *buf; -}; - -#if defined(DUK_USE_PREFER_SIZE) -#define DUK_BW_SLACK_ADD 64 -#define DUK_BW_SLACK_SHIFT 4 /* 2^4 -> 1/16 = 6.25% slack */ -#else -#define DUK_BW_SLACK_ADD 64 -#define DUK_BW_SLACK_SHIFT 2 /* 2^2 -> 1/4 = 25% slack */ -#endif - -/* Initialization and finalization (compaction), converting to other types. */ - -#define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \ - duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \ - } while (0) -#define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \ - duk_bw_init((thr), (bw_ctx), (buf)); \ - } while (0) -#define DUK_BW_COMPACT(thr,bw_ctx) do { \ - /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \ - duk_bw_compact((thr), (bw_ctx)); \ - } while (0) -#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \ - duk_push_lstring((thr), \ - (const char *) (bw_ctx)->p_base, \ - (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ - } while (0) -/* Pointers may be NULL for a while when 'buf' size is zero and before any - * ENSURE calls have been made. Once an ENSURE has been made, the pointers - * are required to be non-NULL so that it's always valid to use memcpy() and - * memmove(), even for zero size. - */ -#define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \ - DUK_ASSERT_EXPR((bw_ctx) != NULL && \ - (bw_ctx)->buf != NULL && \ - ((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \ - ((bw_ctx)->p != NULL && \ - (bw_ctx)->p_base != NULL && \ - (bw_ctx)->p_limit != NULL && \ - (bw_ctx)->p_limit >= (bw_ctx)->p_base && \ - (bw_ctx)->p >= (bw_ctx)->p_base && \ - (bw_ctx)->p <= (bw_ctx)->p_limit))) -#define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \ - DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \ - } while (0) - -/* Working with the pointer and current size. */ - -#define DUK_BW_GET_PTR(thr,bw_ctx) \ - ((bw_ctx)->p) -#define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \ - (bw_ctx)->p = (ptr); \ - } while (0) -#define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \ - (bw_ctx)->p += (delta); \ - } while (0) -#define DUK_BW_GET_BASEPTR(thr,bw_ctx) \ - ((bw_ctx)->p_base) -#define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \ - ((bw_ctx)->p_limit) -#define DUK_BW_GET_SIZE(thr,bw_ctx) \ - ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)) -#define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \ - DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ - (bw_ctx)->p = (bw_ctx)->p_base + (sz); \ - } while (0) -#define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \ - /* Reset to zero size, keep current limit. */ \ - (bw_ctx)->p = (bw_ctx)->p_base; \ - } while (0) -#define DUK_BW_GET_BUFFER(thr,bw_ctx) \ - ((bw_ctx)->buf) - -/* Ensuring (reserving) space. */ - -#define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \ - duk_size_t duk__sz, duk__space; \ - DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \ - duk__sz = (sz); \ - duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \ - if (duk__space < duk__sz) { \ - (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \ - } \ - } while (0) -/* NOTE: Multiple evaluation of 'ptr' in this macro. */ -/* XXX: Rework to use an always-inline function? */ -#define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \ - (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \ - (ptr) : \ - ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz)))) -#define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \ - DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p) -#define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \ - (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \ - DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz))) -#define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \ - DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \ - } while (0) - -/* Miscellaneous. */ - -#define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \ - (bw_ctx)->p = (ptr); \ - duk_bw_compact((thr), (bw_ctx)); \ - } while (0) - -/* Fast write calls which assume you control the slack beforehand. - * Multibyte write variants exist and use a temporary write pointer - * because byte writes alias with anything: with a stored pointer - * explicit pointer load/stores get generated (e.g. gcc -Os). - */ - -#define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \ - DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \ - *(bw_ctx)->p++ = (duk_uint8_t) (val); \ - } while (0) -#define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \ - duk_uint8_t *duk__p; \ - DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \ - duk__p = (bw_ctx)->p; \ - *duk__p++ = (duk_uint8_t) (val1); \ - *duk__p++ = (duk_uint8_t) (val2); \ - (bw_ctx)->p = duk__p; \ - } while (0) -#define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \ - duk_uint8_t *duk__p; \ - DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \ - duk__p = (bw_ctx)->p; \ - *duk__p++ = (duk_uint8_t) (val1); \ - *duk__p++ = (duk_uint8_t) (val2); \ - *duk__p++ = (duk_uint8_t) (val3); \ - (bw_ctx)->p = duk__p; \ - } while (0) -#define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ - duk_uint8_t *duk__p; \ - DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \ - duk__p = (bw_ctx)->p; \ - *duk__p++ = (duk_uint8_t) (val1); \ - *duk__p++ = (duk_uint8_t) (val2); \ - *duk__p++ = (duk_uint8_t) (val3); \ - *duk__p++ = (duk_uint8_t) (val4); \ - (bw_ctx)->p = duk__p; \ - } while (0) -#define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ - duk_uint8_t *duk__p; \ - DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \ - duk__p = (bw_ctx)->p; \ - *duk__p++ = (duk_uint8_t) (val1); \ - *duk__p++ = (duk_uint8_t) (val2); \ - *duk__p++ = (duk_uint8_t) (val3); \ - *duk__p++ = (duk_uint8_t) (val4); \ - *duk__p++ = (duk_uint8_t) (val5); \ - (bw_ctx)->p = duk__p; \ - } while (0) -#define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ - duk_uint8_t *duk__p; \ - DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \ - duk__p = (bw_ctx)->p; \ - *duk__p++ = (duk_uint8_t) (val1); \ - *duk__p++ = (duk_uint8_t) (val2); \ - *duk__p++ = (duk_uint8_t) (val3); \ - *duk__p++ = (duk_uint8_t) (val4); \ - *duk__p++ = (duk_uint8_t) (val5); \ - *duk__p++ = (duk_uint8_t) (val6); \ - (bw_ctx)->p = duk__p; \ - } while (0) -#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \ - duk_ucodepoint_t duk__cp; \ - duk_small_int_t duk__enc_len; \ - duk__cp = (duk_ucodepoint_t) (cp); \ - DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \ - duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \ - (bw_ctx)->p += duk__enc_len; \ - } while (0) -#define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \ - duk_ucodepoint_t duk__cp; \ - duk_small_int_t duk__enc_len; \ - duk__cp = (duk_ucodepoint_t) (cp); \ - DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \ - duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \ - (bw_ctx)->p += duk__enc_len; \ - } while (0) -/* XXX: add temporary duk__p pointer here too; sharing */ -#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \ - const void *duk__valptr; \ - duk_size_t duk__valsz; \ - duk__valptr = (const void *) (valptr); \ - duk__valsz = (duk_size_t) (valsz); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ - (bw_ctx)->p += duk__valsz; \ - } while (0) -#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \ - const duk_uint8_t *duk__val; \ - duk_size_t duk__val_len; \ - duk__val = (const duk_uint8_t *) (val); \ - duk__val_len = DUK_STRLEN((const char *) duk__val); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) -#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \ - duk_size_t duk__val_len; \ - duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) -#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \ - duk_size_t duk__val_len; \ - duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) -#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \ - duk_size_t duk__val_len; \ - duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) -#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ - duk_size_t duk__val_len; \ - duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) - -/* Append bytes from a slice already in the buffer. */ -#define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \ - duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len)) - -/* Insert bytes in the middle of the buffer from an external buffer. */ -#define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \ - duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len)) - -/* Insert bytes in the middle of the buffer from a slice already - * in the buffer. Source offset is interpreted "before" the operation. - */ -#define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \ - duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len)) - -/* Insert a reserved area somewhere in the buffer; caller fills it. - * Evaluates to a (duk_uint_t *) pointing to the start of the reserved - * area for convenience. - */ -#define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \ - duk_bw_insert_raw_area((thr), (bw), (off), (len)) - -/* Remove a slice from inside buffer. */ -#define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \ - duk_bw_remove_raw_slice((thr), (bw), (off), (len)) - -/* Safe write calls which will ensure space first. */ - -#define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \ - DUK_BW_ENSURE((thr), (bw_ctx), 1); \ - DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \ - } while (0) -#define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \ - DUK_BW_ENSURE((thr), (bw_ctx), 2); \ - DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \ - } while (0) -#define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \ - DUK_BW_ENSURE((thr), (bw_ctx), 3); \ - DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \ - } while (0) -#define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ - DUK_BW_ENSURE((thr), (bw_ctx), 4); \ - DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \ - } while (0) -#define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ - DUK_BW_ENSURE((thr), (bw_ctx), 5); \ - DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \ - } while (0) -#define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ - DUK_BW_ENSURE((thr), (bw_ctx), 6); \ - DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \ - } while (0) -#define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \ - DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \ - DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \ - } while (0) -#define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \ - DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \ - DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \ - } while (0) -/* XXX: add temporary duk__p pointer here too; sharing */ -#define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \ - const void *duk__valptr; \ - duk_size_t duk__valsz; \ - duk__valptr = (const void *) (valptr); \ - duk__valsz = (duk_size_t) (valsz); \ - DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ - (bw_ctx)->p += duk__valsz; \ - } while (0) -#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \ - const duk_uint8_t *duk__val; \ - duk_size_t duk__val_len; \ - duk__val = (const duk_uint8_t *) (val); \ - duk__val_len = DUK_STRLEN((const char *) duk__val); \ - DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) -#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \ - duk_size_t duk__val_len; \ - duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ - DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) -#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \ - duk_size_t duk__val_len; \ - duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ - DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) -#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \ - duk_size_t duk__val_len; \ - duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ - DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) -#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ - duk_size_t duk__val_len; \ - duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ - DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ - (bw_ctx)->p += duk__val_len; \ - } while (0) - -#define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \ - duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len)) -#define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \ - duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len)) -#define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \ - duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len)) -#define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \ - /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \ - duk_bw_insert_ensure_area((thr), (bw), (off), (len)) -#define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \ - /* No difference between raw/ensure because the buffer shrinks. */ \ - DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len)) - -/* - * Externs and prototypes - */ - -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36]; -DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16]; -DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256]; -#if defined(DUK_USE_HEX_FASTPATH) -DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256]; -DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256]; -#endif -#if defined(DUK_USE_BASE64_FASTPATH) -DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64]; -DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256]; -#endif -#endif /* !DUK_SINGLE_FILE */ - -/* Note: assumes that duk_util_probe_steps size is 32 */ -#if defined(DUK_USE_HOBJECT_HASH_PART) -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; -#endif /* !DUK_SINGLE_FILE */ -#endif - -#if defined(DUK_USE_STRHASH_DENSE) -DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); -#endif - -DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); -DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); -DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value); -DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); -DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx); -DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out); - -DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits); -DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx); - -#if !defined(DUK_USE_GET_RANDOM_DOUBLE) -DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr); -#endif - -DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf); -DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size); -DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz); -DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx); -DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); -DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); -DUK_INTERNAL_DECL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); -DUK_INTERNAL_DECL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); -DUK_INTERNAL_DECL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); -DUK_INTERNAL_DECL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); -DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); -DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); -DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); -/* No duk_bw_remove_ensure_slice(), functionality would be identical. */ - -DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p); -DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p); -DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p); -DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val); -DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val); -DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val); - -#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ -DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len); -#endif - -DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival); -DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival); -DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x); -DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x); -DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x); -DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x); -DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x); -DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x); -DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x); -DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x); -DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x); -DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y); -DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y); -DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y); - -#endif /* DUK_UTIL_H_INCLUDED */ -/* #include duk_strings.h */ -#line 1 "duk_strings.h" -/* - * Shared string macros. - * - * Using shared macros helps minimize strings data size because it's easy - * to check if an existing string could be used. String constants don't - * need to be all defined here; defining a string here makes sense if there's - * a high chance the string could be reused. Also, using macros allows - * a call site express the exact string needed, but the macro may map to an - * approximate string to reduce unique string count. Macros can also be - * more easily tuned for low memory targets than #if defined()s throughout - * the code base. - * - * Because format strings behave differently in the call site (they need to - * be followed by format arguments), they use a special prefix DUK_STR_FMT_. - * - * On some compilers using explicit shared strings is preferable; on others - * it may be better to use straight literals because the compiler will combine - * them anyway, and such strings won't end up unnecessarily in a symbol table. - */ - -#if !defined(DUK_ERRMSG_H_INCLUDED) -#define DUK_ERRMSG_H_INCLUDED - -/* Mostly API and built-in method related */ -#define DUK_STR_INTERNAL_ERROR "internal error" -#define DUK_STR_UNSUPPORTED "unsupported" -#define DUK_STR_INVALID_COUNT "invalid count" -#define DUK_STR_INVALID_ARGS "invalid args" -#define DUK_STR_INVALID_STATE "invalid state" -#define DUK_STR_INVALID_INPUT "invalid input" -#define DUK_STR_INVALID_LENGTH "invalid length" -#define DUK_STR_NOT_CONSTRUCTABLE "not constructable" -#define DUK_STR_CONSTRUCT_ONLY "constructor requires 'new'" -#define DUK_STR_NOT_CALLABLE "not callable" -#define DUK_STR_NOT_EXTENSIBLE "not extensible" -#define DUK_STR_NOT_WRITABLE "not writable" -#define DUK_STR_NOT_CONFIGURABLE "not configurable" -#define DUK_STR_INVALID_CONTEXT "invalid context" -#define DUK_STR_INVALID_INDEX "invalid args" -#define DUK_STR_PUSH_BEYOND_ALLOC_STACK "cannot push beyond allocated stack" -#define DUK_STR_NOT_UNDEFINED "unexpected type" -#define DUK_STR_NOT_NULL "unexpected type" -#define DUK_STR_NOT_BOOLEAN "unexpected type" -#define DUK_STR_NOT_NUMBER "unexpected type" -#define DUK_STR_NOT_STRING "unexpected type" -#define DUK_STR_NOT_OBJECT "unexpected type" -#define DUK_STR_NOT_POINTER "unexpected type" -#define DUK_STR_NOT_BUFFER "not buffer" /* still in use with verbose messages */ -#define DUK_STR_UNEXPECTED_TYPE "unexpected type" -#define DUK_STR_NOT_THREAD "unexpected type" -#define DUK_STR_NOT_COMPFUNC "unexpected type" -#define DUK_STR_NOT_NATFUNC "unexpected type" -#define DUK_STR_NOT_C_FUNCTION "unexpected type" -#define DUK_STR_NOT_FUNCTION "unexpected type" -#define DUK_STR_NOT_REGEXP "unexpected type" -#define DUK_STR_TOPRIMITIVE_FAILED "coercion to primitive failed" -#define DUK_STR_NUMBER_OUTSIDE_RANGE "number outside range" -#define DUK_STR_NOT_OBJECT_COERCIBLE "not object coercible" -#define DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL "cannot number coerce Symbol" -#define DUK_STR_CANNOT_STRING_COERCE_SYMBOL "cannot string coerce Symbol" -#define DUK_STR_STRING_TOO_LONG "string too long" -#define DUK_STR_BUFFER_TOO_LONG "buffer too long" -#define DUK_STR_ALLOC_FAILED "alloc failed" -#define DUK_STR_WRONG_BUFFER_TYPE "wrong buffer type" -#define DUK_STR_BASE64_ENCODE_FAILED "base64 encode failed" -#define DUK_STR_SOURCE_DECODE_FAILED "source decode failed" -#define DUK_STR_UTF8_DECODE_FAILED "utf-8 decode failed" -#define DUK_STR_BASE64_DECODE_FAILED "base64 decode failed" -#define DUK_STR_HEX_DECODE_FAILED "hex decode failed" -#define DUK_STR_INVALID_BYTECODE "invalid bytecode" -#define DUK_STR_NO_SOURCECODE "no sourcecode" -#define DUK_STR_RESULT_TOO_LONG "result too long" -#define DUK_STR_INVALID_CFUNC_RC "invalid C function rc" -#define DUK_STR_INVALID_INSTANCEOF_RVAL "invalid instanceof rval" -#define DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO "instanceof rval has no .prototype" - -/* JSON */ -#define DUK_STR_FMT_PTR "%p" -#define DUK_STR_FMT_INVALID_JSON "invalid json (at offset %ld)" -#define DUK_STR_JSONDEC_RECLIMIT "json decode recursion limit" -#define DUK_STR_JSONENC_RECLIMIT "json encode recursion limit" -#define DUK_STR_CYCLIC_INPUT "cyclic input" - -/* Object property access */ -#define DUK_STR_INVALID_BASE "invalid base value" -#define DUK_STR_STRICT_CALLER_READ "cannot read strict 'caller'" -#define DUK_STR_PROXY_REJECTED "proxy rejected" -#define DUK_STR_INVALID_ARRAY_LENGTH "invalid array length" -#define DUK_STR_SETTER_UNDEFINED "setter undefined" -#define DUK_STR_INVALID_DESCRIPTOR "invalid descriptor" - -/* Proxy */ -#define DUK_STR_PROXY_REVOKED "proxy revoked" -#define DUK_STR_INVALID_TRAP_RESULT "invalid trap result" - -/* Variables */ - -/* Lexer */ -#define DUK_STR_INVALID_ESCAPE "invalid escape" -#define DUK_STR_UNTERMINATED_STRING "unterminated string" -#define DUK_STR_UNTERMINATED_COMMENT "unterminated comment" -#define DUK_STR_UNTERMINATED_REGEXP "unterminated regexp" -#define DUK_STR_TOKEN_LIMIT "token limit" -#define DUK_STR_REGEXP_SUPPORT_DISABLED "regexp support disabled" -#define DUK_STR_INVALID_NUMBER_LITERAL "invalid number literal" -#define DUK_STR_INVALID_TOKEN "invalid token" - -/* Compiler */ -#define DUK_STR_PARSE_ERROR "parse error" -#define DUK_STR_DUPLICATE_LABEL "duplicate label" -#define DUK_STR_INVALID_LABEL "invalid label" -#define DUK_STR_INVALID_ARRAY_LITERAL "invalid array literal" -#define DUK_STR_INVALID_OBJECT_LITERAL "invalid object literal" -#define DUK_STR_INVALID_VAR_DECLARATION "invalid variable declaration" -#define DUK_STR_CANNOT_DELETE_IDENTIFIER "cannot delete identifier" -#define DUK_STR_INVALID_EXPRESSION "invalid expression" -#define DUK_STR_INVALID_LVALUE "invalid lvalue" -#define DUK_STR_INVALID_NEWTARGET "invalid new.target" -#define DUK_STR_EXPECTED_IDENTIFIER "expected identifier" -#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED "empty expression not allowed" -#define DUK_STR_INVALID_FOR "invalid for statement" -#define DUK_STR_INVALID_SWITCH "invalid switch statement" -#define DUK_STR_INVALID_BREAK_CONT_LABEL "invalid break/continue label" -#define DUK_STR_INVALID_RETURN "invalid return" -#define DUK_STR_INVALID_TRY "invalid try" -#define DUK_STR_INVALID_THROW "invalid throw" -#define DUK_STR_WITH_IN_STRICT_MODE "with in strict mode" -#define DUK_STR_FUNC_STMT_NOT_ALLOWED "function statement not allowed" -#define DUK_STR_UNTERMINATED_STMT "unterminated statement" -#define DUK_STR_INVALID_ARG_NAME "invalid argument name" -#define DUK_STR_INVALID_FUNC_NAME "invalid function name" -#define DUK_STR_INVALID_GETSET_NAME "invalid getter/setter name" -#define DUK_STR_FUNC_NAME_REQUIRED "function name required" - -/* RegExp */ -#define DUK_STR_INVALID_QUANTIFIER "invalid regexp quantifier" -#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM "quantifier without preceding atom" -#define DUK_STR_INVALID_QUANTIFIER_VALUES "quantifier values invalid (qmin > qmax)" -#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES "quantifier requires too many atom copies" -#define DUK_STR_UNEXPECTED_CLOSING_PAREN "unexpected closing parenthesis" -#define DUK_STR_UNEXPECTED_END_OF_PATTERN "unexpected end of pattern" -#define DUK_STR_UNEXPECTED_REGEXP_TOKEN "unexpected token in regexp" -#define DUK_STR_INVALID_REGEXP_FLAGS "invalid regexp flags" -#define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape" -#define DUK_STR_INVALID_BACKREFS "invalid backreference(s)" -#define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character" -#define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group" -#define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class" -#define DUK_STR_INVALID_RANGE "invalid range" - -/* Limits */ -#define DUK_STR_VALSTACK_LIMIT "valstack limit" -#define DUK_STR_CALLSTACK_LIMIT "callstack limit" -#define DUK_STR_PROTOTYPE_CHAIN_LIMIT "prototype chain limit" -#define DUK_STR_BOUND_CHAIN_LIMIT "function call bound chain limit" -#define DUK_STR_C_CALLSTACK_LIMIT "C call stack depth limit" -#define DUK_STR_COMPILER_RECURSION_LIMIT "compiler recursion limit" -#define DUK_STR_BYTECODE_LIMIT "bytecode limit" -#define DUK_STR_REG_LIMIT "register limit" -#define DUK_STR_TEMP_LIMIT "temp limit" -#define DUK_STR_CONST_LIMIT "const limit" -#define DUK_STR_FUNC_LIMIT "function limit" -#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT "regexp compiler recursion limit" -#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT "regexp executor recursion limit" -#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT "regexp step limit" - -#endif /* DUK_ERRMSG_H_INCLUDED */ -/* #include duk_js_bytecode.h */ -#line 1 "duk_js_bytecode.h" -/* - * Ecmascript bytecode - */ - -#if !defined(DUK_JS_BYTECODE_H_INCLUDED) -#define DUK_JS_BYTECODE_H_INCLUDED - -/* - * Bytecode instruction layout - * =========================== - * - * Instructions are unsigned 32-bit integers divided as follows: - * - * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! - * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! - * +-----------------------------------------------+---------------+ - * ! C ! B ! A ! OP ! - * +-----------------------------------------------+---------------+ - * - * OP (8 bits): opcode (DUK_OP_*), access should be fastest - * consecutive opcodes allocated when opcode needs flags - * A (8 bits): typically a target register number - * B (8 bits): typically first source register/constant number - * C (8 bits): typically second source register/constant number - * - * Some instructions combine BC or ABC together for larger parameter values. - * Signed integers (e.g. jump offsets) are encoded as unsigned, with an - * opcode specific bias. - * - * Some opcodes have flags which are handled by allocating consecutive - * opcodes to make space for 1-N flags. Flags can also be e.g. in the 'A' - * field when there's room for the specific opcode. - * - * For example, if three flags were needed, they could be allocated from - * the opcode field as follows: - * - * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! - * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! - * +-----------------------------------------------+---------------+ - * ! C ! B ! A ! OP !Z!Y!X! - * +-----------------------------------------------+---------------+ - * - * Some opcodes accept a reg/const argument which is handled by allocating - * flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST(). The - * following convention is shared by most opcodes, so that the compiler - * can handle reg/const flagging without opcode specific code paths: - * - * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! - * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! - * +-----------------------------------------------+---------------+ - * ! C ! B ! A ! OP !Y!X! - * +-----------------------------------------------+---------------+ - * - * X 1=B is const, 0=B is reg - * Y 1=C is const, 0=C is reg - * - * In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the - * 8-bit opcode space for a single logical opcode. The base opcode - * number should be divisible by 4. If the opcode is called 'FOO' - * the following opcode constants would be defined: - * - * DUK_OP_FOO 100 // base opcode number - * DUK_OP_FOO_RR 100 // FOO, B=reg, C=reg - * DUK_OP_FOO_CR 101 // FOO, B=const, C=reg - * DUK_OP_FOO_RC 102 // FOO, B=reg, C=const - * DUK_OP_FOO_CC 103 // FOO, B=const, C=const - * - * If only B or C is a reg/const, the unused opcode combinations can be - * used for other opcodes (which take no reg/const argument). However, - * such opcode values are initially reserved, at least while opcode space - * is available. For example, if 'BAR' uses B for a register field and - * C is a reg/const: - * - * DUK_OP_BAR 116 // base opcode number - * DUK_OP_BAR_RR 116 // BAR, B=reg, C=reg - * DUK_OP_BAR_CR_UNUSED 117 // unused, could be repurposed - * DUK_OP_BAR_RC 118 // BAR, B=reg, C=const - * DUK_OP_BAR_CC_UNUSED 119 // unused, could be repurposed - * - * Macro naming is a bit misleading, e.g. "ABC" in macro name but the - * field layout is concretely "CBA" in the register. - */ - -typedef duk_uint32_t duk_instr_t; - -#define DUK_BC_SHIFT_OP 0 -#define DUK_BC_SHIFT_A 8 -#define DUK_BC_SHIFT_B 16 -#define DUK_BC_SHIFT_C 24 -#define DUK_BC_SHIFT_BC DUK_BC_SHIFT_B -#define DUK_BC_SHIFT_ABC DUK_BC_SHIFT_A - -#define DUK_BC_UNSHIFTED_MASK_OP 0xffUL -#define DUK_BC_UNSHIFTED_MASK_A 0xffUL -#define DUK_BC_UNSHIFTED_MASK_B 0xffUL -#define DUK_BC_UNSHIFTED_MASK_C 0xffUL -#define DUK_BC_UNSHIFTED_MASK_BC 0xffffUL -#define DUK_BC_UNSHIFTED_MASK_ABC 0xffffffUL - -#define DUK_BC_SHIFTED_MASK_OP (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP) -#define DUK_BC_SHIFTED_MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A) -#define DUK_BC_SHIFTED_MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B) -#define DUK_BC_SHIFTED_MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C) -#define DUK_BC_SHIFTED_MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC) -#define DUK_BC_SHIFTED_MASK_ABC (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC) - -#define DUK_DEC_OP(x) ((x) & 0xffUL) -#define DUK_DEC_A(x) (((x) >> 8) & 0xffUL) -#define DUK_DEC_B(x) (((x) >> 16) & 0xffUL) -#define DUK_DEC_C(x) (((x) >> 24) & 0xffUL) -#define DUK_DEC_BC(x) (((x) >> 16) & 0xffffUL) -#define DUK_DEC_ABC(x) (((x) >> 8) & 0xffffffUL) - -#define DUK_ENC_OP(op) ((duk_instr_t) (op)) -#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \ - (((duk_instr_t) (abc)) << 8) | \ - ((duk_instr_t) (op)) \ - )) -#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \ - (((duk_instr_t) (bc)) << 16) | \ - (((duk_instr_t) (a)) << 8) | \ - ((duk_instr_t) (op)) \ - )) -#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \ - (((duk_instr_t) (c)) << 24) | \ - (((duk_instr_t) (b)) << 16) | \ - (((duk_instr_t) (a)) << 8) | \ - ((duk_instr_t) (op)) \ - )) -#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C((op),(a),(b),0) -#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C((op),(a),0,0) -#define DUK_ENC_OP_BC(op,bc) DUK_ENC_OP_A_BC((op),0,(bc)) - -/* Get opcode base value with B/C reg/const flags cleared. */ -#define DUK_BC_NOREGCONST_OP(op) ((op) & 0xfc) - -/* Constants should be signed so that signed arithmetic involving them - * won't cause values to be coerced accidentally to unsigned. - */ -#define DUK_BC_OP_MIN 0 -#define DUK_BC_OP_MAX 0xffL -#define DUK_BC_A_MIN 0 -#define DUK_BC_A_MAX 0xffL -#define DUK_BC_B_MIN 0 -#define DUK_BC_B_MAX 0xffL -#define DUK_BC_C_MIN 0 -#define DUK_BC_C_MAX 0xffL -#define DUK_BC_BC_MIN 0 -#define DUK_BC_BC_MAX 0xffffL -#define DUK_BC_ABC_MIN 0 -#define DUK_BC_ABC_MAX 0xffffffL - -/* Masks for B/C reg/const indicator in opcode field. */ -#define DUK_BC_REGCONST_B (0x01UL) -#define DUK_BC_REGCONST_C (0x02UL) - -/* Misc. masks for opcode field. */ -#define DUK_BC_INCDECP_FLAG_DEC (0x04UL) -#define DUK_BC_INCDECP_FLAG_POST (0x08UL) - -/* Opcodes. */ -#define DUK_OP_LDREG 0 -#define DUK_OP_STREG 1 -#define DUK_OP_JUMP 2 -#define DUK_OP_LDCONST 3 -#define DUK_OP_LDINT 4 -#define DUK_OP_LDINTX 5 -#define DUK_OP_LDTHIS 6 -#define DUK_OP_LDUNDEF 7 -#define DUK_OP_LDNULL 8 -#define DUK_OP_LDTRUE 9 -#define DUK_OP_LDFALSE 10 -#define DUK_OP_GETVAR 11 -#define DUK_OP_BNOT 12 -#define DUK_OP_LNOT 13 -#define DUK_OP_UNM 14 -#define DUK_OP_UNP 15 -#define DUK_OP_EQ 16 -#define DUK_OP_EQ_RR 16 -#define DUK_OP_EQ_CR 17 -#define DUK_OP_EQ_RC 18 -#define DUK_OP_EQ_CC 19 -#define DUK_OP_NEQ 20 -#define DUK_OP_NEQ_RR 20 -#define DUK_OP_NEQ_CR 21 -#define DUK_OP_NEQ_RC 22 -#define DUK_OP_NEQ_CC 23 -#define DUK_OP_SEQ 24 -#define DUK_OP_SEQ_RR 24 -#define DUK_OP_SEQ_CR 25 -#define DUK_OP_SEQ_RC 26 -#define DUK_OP_SEQ_CC 27 -#define DUK_OP_SNEQ 28 -#define DUK_OP_SNEQ_RR 28 -#define DUK_OP_SNEQ_CR 29 -#define DUK_OP_SNEQ_RC 30 -#define DUK_OP_SNEQ_CC 31 -#define DUK_OP_GT 32 -#define DUK_OP_GT_RR 32 -#define DUK_OP_GT_CR 33 -#define DUK_OP_GT_RC 34 -#define DUK_OP_GT_CC 35 -#define DUK_OP_GE 36 -#define DUK_OP_GE_RR 36 -#define DUK_OP_GE_CR 37 -#define DUK_OP_GE_RC 38 -#define DUK_OP_GE_CC 39 -#define DUK_OP_LT 40 -#define DUK_OP_LT_RR 40 -#define DUK_OP_LT_CR 41 -#define DUK_OP_LT_RC 42 -#define DUK_OP_LT_CC 43 -#define DUK_OP_LE 44 -#define DUK_OP_LE_RR 44 -#define DUK_OP_LE_CR 45 -#define DUK_OP_LE_RC 46 -#define DUK_OP_LE_CC 47 -#define DUK_OP_IFTRUE 48 -#define DUK_OP_IFTRUE_R 48 -#define DUK_OP_IFTRUE_C 49 -#define DUK_OP_IFFALSE 50 -#define DUK_OP_IFFALSE_R 50 -#define DUK_OP_IFFALSE_C 51 -#define DUK_OP_ADD 52 -#define DUK_OP_ADD_RR 52 -#define DUK_OP_ADD_CR 53 -#define DUK_OP_ADD_RC 54 -#define DUK_OP_ADD_CC 55 -#define DUK_OP_SUB 56 -#define DUK_OP_SUB_RR 56 -#define DUK_OP_SUB_CR 57 -#define DUK_OP_SUB_RC 58 -#define DUK_OP_SUB_CC 59 -#define DUK_OP_MUL 60 -#define DUK_OP_MUL_RR 60 -#define DUK_OP_MUL_CR 61 -#define DUK_OP_MUL_RC 62 -#define DUK_OP_MUL_CC 63 -#define DUK_OP_DIV 64 -#define DUK_OP_DIV_RR 64 -#define DUK_OP_DIV_CR 65 -#define DUK_OP_DIV_RC 66 -#define DUK_OP_DIV_CC 67 -#define DUK_OP_MOD 68 -#define DUK_OP_MOD_RR 68 -#define DUK_OP_MOD_CR 69 -#define DUK_OP_MOD_RC 70 -#define DUK_OP_MOD_CC 71 -#define DUK_OP_EXP 72 -#define DUK_OP_EXP_RR 72 -#define DUK_OP_EXP_CR 73 -#define DUK_OP_EXP_RC 74 -#define DUK_OP_EXP_CC 75 -#define DUK_OP_BAND 76 -#define DUK_OP_BAND_RR 76 -#define DUK_OP_BAND_CR 77 -#define DUK_OP_BAND_RC 78 -#define DUK_OP_BAND_CC 79 -#define DUK_OP_BOR 80 -#define DUK_OP_BOR_RR 80 -#define DUK_OP_BOR_CR 81 -#define DUK_OP_BOR_RC 82 -#define DUK_OP_BOR_CC 83 -#define DUK_OP_BXOR 84 -#define DUK_OP_BXOR_RR 84 -#define DUK_OP_BXOR_CR 85 -#define DUK_OP_BXOR_RC 86 -#define DUK_OP_BXOR_CC 87 -#define DUK_OP_BASL 88 -#define DUK_OP_BASL_RR 88 -#define DUK_OP_BASL_CR 89 -#define DUK_OP_BASL_RC 90 -#define DUK_OP_BASL_CC 91 -#define DUK_OP_BLSR 92 -#define DUK_OP_BLSR_RR 92 -#define DUK_OP_BLSR_CR 93 -#define DUK_OP_BLSR_RC 94 -#define DUK_OP_BLSR_CC 95 -#define DUK_OP_BASR 96 -#define DUK_OP_BASR_RR 96 -#define DUK_OP_BASR_CR 97 -#define DUK_OP_BASR_RC 98 -#define DUK_OP_BASR_CC 99 -#define DUK_OP_INSTOF 100 -#define DUK_OP_INSTOF_RR 100 -#define DUK_OP_INSTOF_CR 101 -#define DUK_OP_INSTOF_RC 102 -#define DUK_OP_INSTOF_CC 103 -#define DUK_OP_IN 104 -#define DUK_OP_IN_RR 104 -#define DUK_OP_IN_CR 105 -#define DUK_OP_IN_RC 106 -#define DUK_OP_IN_CC 107 -#define DUK_OP_GETPROP 108 -#define DUK_OP_GETPROP_RR 108 -#define DUK_OP_GETPROP_CR 109 -#define DUK_OP_GETPROP_RC 110 -#define DUK_OP_GETPROP_CC 111 -#define DUK_OP_PUTPROP 112 -#define DUK_OP_PUTPROP_RR 112 -#define DUK_OP_PUTPROP_CR 113 -#define DUK_OP_PUTPROP_RC 114 -#define DUK_OP_PUTPROP_CC 115 -#define DUK_OP_DELPROP 116 -#define DUK_OP_DELPROP_RR 116 -#define DUK_OP_DELPROP_CR_UNUSED 117 /* unused now */ -#define DUK_OP_DELPROP_RC 118 -#define DUK_OP_DELPROP_CC_UNUSED 119 /* unused now */ -#define DUK_OP_PREINCR 120 /* pre/post opcode values have constraints, */ -#define DUK_OP_PREDECR 121 /* see duk_js_executor.c and duk_js_compiler.c. */ -#define DUK_OP_POSTINCR 122 -#define DUK_OP_POSTDECR 123 -#define DUK_OP_PREINCV 124 -#define DUK_OP_PREDECV 125 -#define DUK_OP_POSTINCV 126 -#define DUK_OP_POSTDECV 127 -#define DUK_OP_PREINCP 128 /* pre/post inc/dec prop opcodes have constraints */ -#define DUK_OP_PREINCP_RR 128 -#define DUK_OP_PREINCP_CR 129 -#define DUK_OP_PREINCP_RC 130 -#define DUK_OP_PREINCP_CC 131 -#define DUK_OP_PREDECP 132 -#define DUK_OP_PREDECP_RR 132 -#define DUK_OP_PREDECP_CR 133 -#define DUK_OP_PREDECP_RC 134 -#define DUK_OP_PREDECP_CC 135 -#define DUK_OP_POSTINCP 136 -#define DUK_OP_POSTINCP_RR 136 -#define DUK_OP_POSTINCP_CR 137 -#define DUK_OP_POSTINCP_RC 138 -#define DUK_OP_POSTINCP_CC 139 -#define DUK_OP_POSTDECP 140 -#define DUK_OP_POSTDECP_RR 140 -#define DUK_OP_POSTDECP_CR 141 -#define DUK_OP_POSTDECP_RC 142 -#define DUK_OP_POSTDECP_CC 143 -#define DUK_OP_DECLVAR 144 -#define DUK_OP_DECLVAR_RR 144 -#define DUK_OP_DECLVAR_CR 145 -#define DUK_OP_DECLVAR_RC 146 -#define DUK_OP_DECLVAR_CC 147 -#define DUK_OP_REGEXP 148 -#define DUK_OP_REGEXP_RR 148 -#define DUK_OP_REGEXP_CR 149 -#define DUK_OP_REGEXP_RC 150 -#define DUK_OP_REGEXP_CC 151 -#define DUK_OP_CLOSURE 152 -#define DUK_OP_TYPEOF 153 -#define DUK_OP_TYPEOFID 154 -#define DUK_OP_PUTVAR 155 -#define DUK_OP_DELVAR 156 -#define DUK_OP_RETREG 157 -#define DUK_OP_RETUNDEF 158 -#define DUK_OP_RETCONST 159 -#define DUK_OP_RETCONSTN 160 /* return const without incref (e.g. number) */ -#define DUK_OP_LABEL 161 -#define DUK_OP_ENDLABEL 162 -#define DUK_OP_BREAK 163 -#define DUK_OP_CONTINUE 164 -#define DUK_OP_TRYCATCH 165 -#define DUK_OP_ENDTRY 166 -#define DUK_OP_ENDCATCH 167 -#define DUK_OP_ENDFIN 168 -#define DUK_OP_THROW 169 -#define DUK_OP_INVLHS 170 -#define DUK_OP_CSREG 171 -#define DUK_OP_CSVAR 172 -#define DUK_OP_CSVAR_RR 172 -#define DUK_OP_CSVAR_CR 173 -#define DUK_OP_CSVAR_RC 174 -#define DUK_OP_CSVAR_CC 175 -#define DUK_OP_CALL0 176 /* DUK_OP_CALL0 & 0x0F must be zero. */ -#define DUK_OP_CALL1 177 -#define DUK_OP_CALL2 178 -#define DUK_OP_CALL3 179 -#define DUK_OP_CALL4 180 -#define DUK_OP_CALL5 181 -#define DUK_OP_CALL6 182 -#define DUK_OP_CALL7 183 -#define DUK_OP_CALL8 184 -#define DUK_OP_CALL9 185 -#define DUK_OP_CALL10 186 -#define DUK_OP_CALL11 187 -#define DUK_OP_CALL12 188 -#define DUK_OP_CALL13 189 -#define DUK_OP_CALL14 190 -#define DUK_OP_CALL15 191 -#define DUK_OP_NEWOBJ 192 -#define DUK_OP_NEWARR 193 -#define DUK_OP_MPUTOBJ 194 -#define DUK_OP_MPUTOBJI 195 -#define DUK_OP_INITSET 196 -#define DUK_OP_INITGET 197 -#define DUK_OP_MPUTARR 198 -#define DUK_OP_MPUTARRI 199 -#define DUK_OP_SETALEN 200 -#define DUK_OP_INITENUM 201 -#define DUK_OP_NEXTENUM 202 -#define DUK_OP_NEWTARGET 203 -#define DUK_OP_DEBUGGER 204 -#define DUK_OP_NOP 205 -#define DUK_OP_INVALID 206 -#define DUK_OP_UNUSED207 207 -#define DUK_OP_GETPROPC 208 -#define DUK_OP_GETPROPC_RR 208 -#define DUK_OP_GETPROPC_CR 209 -#define DUK_OP_GETPROPC_RC 210 -#define DUK_OP_GETPROPC_CC 211 -#define DUK_OP_UNUSED212 212 -#define DUK_OP_UNUSED213 213 -#define DUK_OP_UNUSED214 214 -#define DUK_OP_UNUSED215 215 -#define DUK_OP_UNUSED216 216 -#define DUK_OP_UNUSED217 217 -#define DUK_OP_UNUSED218 218 -#define DUK_OP_UNUSED219 219 -#define DUK_OP_UNUSED220 220 -#define DUK_OP_UNUSED221 221 -#define DUK_OP_UNUSED222 222 -#define DUK_OP_UNUSED223 223 -#define DUK_OP_UNUSED224 224 -#define DUK_OP_UNUSED225 225 -#define DUK_OP_UNUSED226 226 -#define DUK_OP_UNUSED227 227 -#define DUK_OP_UNUSED228 228 -#define DUK_OP_UNUSED229 229 -#define DUK_OP_UNUSED230 230 -#define DUK_OP_UNUSED231 231 -#define DUK_OP_UNUSED232 232 -#define DUK_OP_UNUSED233 233 -#define DUK_OP_UNUSED234 234 -#define DUK_OP_UNUSED235 235 -#define DUK_OP_UNUSED236 236 -#define DUK_OP_UNUSED237 237 -#define DUK_OP_UNUSED238 238 -#define DUK_OP_UNUSED239 239 -#define DUK_OP_UNUSED240 240 -#define DUK_OP_UNUSED241 241 -#define DUK_OP_UNUSED242 242 -#define DUK_OP_UNUSED243 243 -#define DUK_OP_UNUSED244 244 -#define DUK_OP_UNUSED245 245 -#define DUK_OP_UNUSED246 246 -#define DUK_OP_UNUSED247 247 -#define DUK_OP_UNUSED248 248 -#define DUK_OP_UNUSED249 249 -#define DUK_OP_UNUSED250 250 -#define DUK_OP_UNUSED251 251 -#define DUK_OP_UNUSED252 252 -#define DUK_OP_UNUSED253 253 -#define DUK_OP_UNUSED254 254 -#define DUK_OP_UNUSED255 255 -#define DUK_OP_NONE 256 /* dummy value used as marker (doesn't fit in 8-bit field) */ - -/* XXX: Allocate flags from opcode field? Would take 16 opcode slots - * but avoids shuffling in more cases. Maybe not worth it. - */ -/* DUK_OP_TRYCATCH flags in A. */ -#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1U << 0) -#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1U << 1) -#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1U << 2) -#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1U << 3) - -/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags - * (DUK_PROPDESC_FLAG_XXX). - */ -#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1U << 4) /* function declaration */ - -/* DUK_OP_CALLn flags, part of opcode field. Three lowest bits must match - * DUK_CALL_FLAG_xxx directly. - */ -#define DUK_BC_CALL_FLAG_TAILCALL (1U << 0) -#define DUK_BC_CALL_FLAG_CONSTRUCT (1U << 1) -#define DUK_BC_CALL_FLAG_CALLED_AS_EVAL (1U << 2) -#define DUK_BC_CALL_FLAG_INDIRECT (1U << 3) - -/* Misc constants and helper macros. */ -#define DUK_BC_LDINT_BIAS (1L << 15) -#define DUK_BC_LDINTX_SHIFT 16 -#define DUK_BC_JUMP_BIAS (1L << 23) - -#endif /* DUK_JS_BYTECODE_H_INCLUDED */ -/* #include duk_lexer.h */ -#line 1 "duk_lexer.h" -/* - * Lexer defines. - */ - -#if !defined(DUK_LEXER_H_INCLUDED) -#define DUK_LEXER_H_INCLUDED - -typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct); - -/* - * A token is interpreted as any possible production of InputElementDiv - * and InputElementRegExp, see E5 Section 7 in its entirety. Note that - * the E5 "Token" production does not cover all actual tokens of the - * language (which is explicitly stated in the specification, Section 7.5). - * Null and boolean literals are defined as part of both ReservedWord - * (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions. Here, - * null and boolean values have literal tokens, and are not reserved - * words. - * - * Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER. - * The number tokens always have a non-negative value. The unary minus - * operator in "-1.0" is optimized during compilation to yield a single - * negative constant. - * - * Token numbering is free except that reserved words are required to be - * in a continuous range and in a particular order. See genstrings.py. - */ - -#define DUK_LEXER_INITCTX(ctx) duk_lexer_initctx((ctx)) - -#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt)) - -#define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt)) - -/* Currently 6 characters of lookup are actually needed (duk_lexer.c). */ -#define DUK_LEXER_WINDOW_SIZE 6 -#if defined(DUK_USE_LEXER_SLIDING_WINDOW) -#define DUK_LEXER_BUFFER_SIZE 64 -#endif - -#define DUK_TOK_MINVAL 0 - -/* returned after EOF (infinite amount) */ -#define DUK_TOK_EOF 0 - -/* identifier names (E5 Section 7.6) */ -#define DUK_TOK_IDENTIFIER 1 - -/* reserved words: keywords */ -#define DUK_TOK_START_RESERVED 2 -#define DUK_TOK_BREAK 2 -#define DUK_TOK_CASE 3 -#define DUK_TOK_CATCH 4 -#define DUK_TOK_CONTINUE 5 -#define DUK_TOK_DEBUGGER 6 -#define DUK_TOK_DEFAULT 7 -#define DUK_TOK_DELETE 8 -#define DUK_TOK_DO 9 -#define DUK_TOK_ELSE 10 -#define DUK_TOK_FINALLY 11 -#define DUK_TOK_FOR 12 -#define DUK_TOK_FUNCTION 13 -#define DUK_TOK_IF 14 -#define DUK_TOK_IN 15 -#define DUK_TOK_INSTANCEOF 16 -#define DUK_TOK_NEW 17 -#define DUK_TOK_RETURN 18 -#define DUK_TOK_SWITCH 19 -#define DUK_TOK_THIS 20 -#define DUK_TOK_THROW 21 -#define DUK_TOK_TRY 22 -#define DUK_TOK_TYPEOF 23 -#define DUK_TOK_VAR 24 -#define DUK_TOK_CONST 25 -#define DUK_TOK_VOID 26 -#define DUK_TOK_WHILE 27 -#define DUK_TOK_WITH 28 - -/* reserved words: future reserved words */ -#define DUK_TOK_CLASS 29 -#define DUK_TOK_ENUM 30 -#define DUK_TOK_EXPORT 31 -#define DUK_TOK_EXTENDS 32 -#define DUK_TOK_IMPORT 33 -#define DUK_TOK_SUPER 34 - -/* "null", "true", and "false" are always reserved words. - * Note that "get" and "set" are not! - */ -#define DUK_TOK_NULL 35 -#define DUK_TOK_TRUE 36 -#define DUK_TOK_FALSE 37 - -/* reserved words: additional future reserved words in strict mode */ -#define DUK_TOK_START_STRICT_RESERVED 38 /* inclusive */ -#define DUK_TOK_IMPLEMENTS 38 -#define DUK_TOK_INTERFACE 39 -#define DUK_TOK_LET 40 -#define DUK_TOK_PACKAGE 41 -#define DUK_TOK_PRIVATE 42 -#define DUK_TOK_PROTECTED 43 -#define DUK_TOK_PUBLIC 44 -#define DUK_TOK_STATIC 45 -#define DUK_TOK_YIELD 46 - -#define DUK_TOK_END_RESERVED 47 /* exclusive */ - -/* "get" and "set" are tokens but NOT ReservedWords. They are currently - * parsed and identifiers and these defines are actually now unused. - */ -#define DUK_TOK_GET 47 -#define DUK_TOK_SET 48 - -/* punctuators (unlike the spec, also includes "/" and "/=") */ -#define DUK_TOK_LCURLY 49 -#define DUK_TOK_RCURLY 50 -#define DUK_TOK_LBRACKET 51 -#define DUK_TOK_RBRACKET 52 -#define DUK_TOK_LPAREN 53 -#define DUK_TOK_RPAREN 54 -#define DUK_TOK_PERIOD 55 -#define DUK_TOK_SEMICOLON 56 -#define DUK_TOK_COMMA 57 -#define DUK_TOK_LT 58 -#define DUK_TOK_GT 59 -#define DUK_TOK_LE 60 -#define DUK_TOK_GE 61 -#define DUK_TOK_EQ 62 -#define DUK_TOK_NEQ 63 -#define DUK_TOK_SEQ 64 -#define DUK_TOK_SNEQ 65 -#define DUK_TOK_ADD 66 -#define DUK_TOK_SUB 67 -#define DUK_TOK_MUL 68 -#define DUK_TOK_DIV 69 -#define DUK_TOK_MOD 70 -#define DUK_TOK_EXP 71 -#define DUK_TOK_INCREMENT 72 -#define DUK_TOK_DECREMENT 73 -#define DUK_TOK_ALSHIFT 74 /* named "arithmetic" because result is signed */ -#define DUK_TOK_ARSHIFT 75 -#define DUK_TOK_RSHIFT 76 -#define DUK_TOK_BAND 77 -#define DUK_TOK_BOR 78 -#define DUK_TOK_BXOR 79 -#define DUK_TOK_LNOT 80 -#define DUK_TOK_BNOT 81 -#define DUK_TOK_LAND 82 -#define DUK_TOK_LOR 83 -#define DUK_TOK_QUESTION 84 -#define DUK_TOK_COLON 85 -#define DUK_TOK_EQUALSIGN 86 -#define DUK_TOK_ADD_EQ 87 -#define DUK_TOK_SUB_EQ 88 -#define DUK_TOK_MUL_EQ 89 -#define DUK_TOK_DIV_EQ 90 -#define DUK_TOK_MOD_EQ 91 -#define DUK_TOK_EXP_EQ 92 -#define DUK_TOK_ALSHIFT_EQ 93 -#define DUK_TOK_ARSHIFT_EQ 94 -#define DUK_TOK_RSHIFT_EQ 95 -#define DUK_TOK_BAND_EQ 96 -#define DUK_TOK_BOR_EQ 97 -#define DUK_TOK_BXOR_EQ 98 - -/* literals (E5 Section 7.8), except null, true, false, which are treated - * like reserved words (above). - */ -#define DUK_TOK_NUMBER 99 -#define DUK_TOK_STRING 100 -#define DUK_TOK_REGEXP 101 - -#define DUK_TOK_MAXVAL 101 /* inclusive */ - -#define DUK_TOK_INVALID DUK_SMALL_UINT_MAX - -/* Convert heap string index to a token (reserved words) */ -#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED) - -/* Sanity check */ -#if (DUK_TOK_MAXVAL > 255) -#error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits -#endif - -/* Sanity checks for string and token defines */ -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC) -#error mismatch in token defines -#endif -#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD) -#error mismatch in token defines -#endif - -/* Regexp tokens */ -#define DUK_RETOK_EOF 0 -#define DUK_RETOK_DISJUNCTION 1 -#define DUK_RETOK_QUANTIFIER 2 -#define DUK_RETOK_ASSERT_START 3 -#define DUK_RETOK_ASSERT_END 4 -#define DUK_RETOK_ASSERT_WORD_BOUNDARY 5 -#define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY 6 -#define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD 7 -#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8 -#define DUK_RETOK_ATOM_PERIOD 9 -#define DUK_RETOK_ATOM_CHAR 10 -#define DUK_RETOK_ATOM_DIGIT 11 /* assumptions in regexp compiler */ -#define DUK_RETOK_ATOM_NOT_DIGIT 12 /* -""- */ -#define DUK_RETOK_ATOM_WHITE 13 /* -""- */ -#define DUK_RETOK_ATOM_NOT_WHITE 14 /* -""- */ -#define DUK_RETOK_ATOM_WORD_CHAR 15 /* -""- */ -#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 /* -""- */ -#define DUK_RETOK_ATOM_BACKREFERENCE 17 -#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18 -#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19 -#define DUK_RETOK_ATOM_START_CHARCLASS 20 -#define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED 21 -#define DUK_RETOK_ATOM_END_GROUP 22 - -/* Constants for duk_lexer_ctx.buf. */ -#define DUK_LEXER_TEMP_BUF_LIMIT 256 - -/* A token value. Can be memcpy()'d, but note that slot1/slot2 values are on the valstack. - * Some fields (like num, str1, str2) are only valid for specific token types and may have - * stale values otherwise. - */ -struct duk_token { - duk_small_uint_t t; /* token type (with reserved word identification) */ - duk_small_uint_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */ - duk_double_t num; /* numeric value of token */ - duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */ - duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */ - duk_size_t start_offset; /* start byte offset of token in lexer input */ - duk_int_t start_line; /* start line of token (first char) */ - duk_int_t num_escapes; /* number of escapes and line continuations (for directive prologue) */ - duk_bool_t lineterm; /* token was preceded by a lineterm */ - duk_bool_t allow_auto_semi; /* token allows automatic semicolon insertion (eof or preceded by newline) */ -}; - -#define DUK_RE_QUANTIFIER_INFINITE ((duk_uint32_t) 0xffffffffUL) - -/* A regexp token value. */ -struct duk_re_token { - duk_small_uint_t t; /* token type */ - duk_small_uint_t greedy; - duk_uint32_t num; /* numeric value (character, count) */ - duk_uint32_t qmin; - duk_uint32_t qmax; -}; - -/* A structure for 'snapshotting' a point for rewinding */ -struct duk_lexer_point { - duk_size_t offset; - duk_int_t line; -}; - -/* Lexer codepoint with additional info like offset/line number */ -struct duk_lexer_codepoint { - duk_codepoint_t codepoint; - duk_size_t offset; - duk_int_t line; -}; - -/* Lexer context. Same context is used for Ecmascript and Regexp parsing. */ -struct duk_lexer_ctx { -#if defined(DUK_USE_LEXER_SLIDING_WINDOW) - duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */ - duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE]; -#else - duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */ -#endif - - duk_hthread *thr; /* thread; minimizes argument passing */ - - const duk_uint8_t *input; /* input string (may be a user pointer) */ - duk_size_t input_length; /* input byte length */ - duk_size_t input_offset; /* input offset for window leading edge (not window[0]) */ - duk_int_t input_line; /* input linenumber at input_offset (not window[0]), init to 1 */ - - duk_idx_t slot1_idx; /* valstack slot for 1st token value */ - duk_idx_t slot2_idx; /* valstack slot for 2nd token value */ - duk_idx_t buf_idx; /* valstack slot for temp buffer */ - duk_hbuffer_dynamic *buf; /* temp accumulation buffer */ - duk_bufwriter_ctx bw; /* bufwriter for temp accumulation */ - - duk_int_t token_count; /* number of tokens parsed */ - duk_int_t token_limit; /* maximum token count before error (sanity backstop) */ - - duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */ -}; - -/* - * Prototypes - */ - -DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx); - -DUK_INTERNAL_DECL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt); -DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt); - -DUK_INTERNAL_DECL -void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx, - duk_token *out_token, - duk_bool_t strict_mode, - duk_bool_t regexp_mode); -#if defined(DUK_USE_REGEXP_SUPPORT) -DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token); -DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata); -#endif /* DUK_USE_REGEXP_SUPPORT */ - -#endif /* DUK_LEXER_H_INCLUDED */ -/* #include duk_js_compiler.h */ -#line 1 "duk_js_compiler.h" -/* - * Ecmascript compiler. - */ - -#if !defined(DUK_JS_COMPILER_H_INCLUDED) -#define DUK_JS_COMPILER_H_INCLUDED - -/* ecmascript compiler limits */ -#define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */ - -/* maximum loopcount for peephole optimization */ -#define DUK_COMPILER_PEEPHOLE_MAXITER 3 - -/* maximum bytecode length in instructions */ -#define DUK_COMPILER_MAX_BYTECODE_LENGTH (256L * 1024L * 1024L) /* 1 GB */ - -/* - * Compiler intermediate values - * - * Intermediate values describe either plain values (e.g. strings or - * numbers) or binary operations which have not yet been coerced into - * either a left-hand-side or right-hand-side role (e.g. object property). - */ - -#define DUK_IVAL_NONE 0 /* no value */ -#define DUK_IVAL_PLAIN 1 /* register, constant, or value */ -#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */ -#define DUK_IVAL_PROP 3 /* property access */ -#define DUK_IVAL_VAR 4 /* variable access */ - -#define DUK_ISPEC_NONE 0 /* no value */ -#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */ -#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */ - -/* Bit mask which indicates that a regconst is a constant instead of a register. - * Chosen so that when a regconst is cast to duk_int32_t, all consts are - * negative values. - */ -#define DUK_REGCONST_CONST_MARKER DUK_INT32_MIN /* = -0x80000000 */ - -/* Type to represent a reg/const reference during compilation, with <0 - * indicating a constant. Some call sites also use -1 to indicate 'none'. - */ -typedef duk_int32_t duk_regconst_t; - -typedef struct { - duk_small_uint_t t; /* DUK_ISPEC_XXX */ - duk_regconst_t regconst; - duk_idx_t valstack_idx; /* always set; points to a reserved valstack slot */ -} duk_ispec; - -typedef struct { - /* - * PLAIN: x1 - * ARITH: x1 x2 - * PROP: x1.x2 - * VAR: x1 (name) - */ - - /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */ - duk_small_uint_t t; /* DUK_IVAL_XXX */ - duk_small_uint_t op; /* bytecode opcode for binary ops */ - duk_ispec x1; - duk_ispec x2; -} duk_ivalue; - -/* - * Bytecode instruction representation during compilation - * - * Contains the actual instruction and (optionally) debug info. - */ - -struct duk_compiler_instr { - duk_instr_t ins; -#if defined(DUK_USE_PC2LINE) - duk_uint32_t line; -#endif -}; - -/* - * Compiler state - */ - -#define DUK_LABEL_FLAG_ALLOW_BREAK (1U << 0) -#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1U << 1) - -#define DUK_DECL_TYPE_VAR 0 -#define DUK_DECL_TYPE_FUNC 1 - -/* XXX: optimize to 16 bytes */ -typedef struct { - duk_small_uint_t flags; - duk_int_t label_id; /* numeric label_id (-1 reserved as marker) */ - duk_hstring *h_label; /* borrowed label name */ - duk_int_t catch_depth; /* catch depth at point of definition */ - duk_int_t pc_label; /* pc of label statement: - * pc+1: break jump site - * pc+2: continue jump site - */ - - /* Fast jumps (which avoid longjmp) jump directly to the jump sites - * which are always known even while the iteration/switch statement - * is still being parsed. A final peephole pass "straightens out" - * the jumps. - */ -} duk_labelinfo; - -/* Compiling state of one function, eventually converted to duk_hcompfunc */ -struct duk_compiler_func { - /* These pointers are at the start of the struct so that they pack - * nicely. Mixing pointers and integer values is bad on some - * platforms (e.g. if int is 32 bits and pointers are 64 bits). - */ - - duk_bufwriter_ctx bw_code; /* bufwriter for code */ - - duk_hstring *h_name; /* function name (borrowed reference), ends up in _name */ - /* h_code: held in bw_code */ - duk_hobject *h_consts; /* array */ - duk_hobject *h_funcs; /* array of function templates: [func1, offset1, line1, func2, offset2, line2] - * offset/line points to closing brace to allow skipping on pass 2 - */ - duk_hobject *h_decls; /* array of declarations: [ name1, val1, name2, val2, ... ] - * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars) - * record function and variable declarations in pass 1 - */ - duk_hobject *h_labelnames; /* array of active label names */ - duk_hbuffer_dynamic *h_labelinfos; /* C array of duk_labelinfo */ - duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */ - duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */ - - /* Value stack indices for tracking objects. */ - /* code_idx: not needed */ - duk_idx_t consts_idx; - duk_idx_t funcs_idx; - duk_idx_t decls_idx; - duk_idx_t labelnames_idx; - duk_idx_t labelinfos_idx; - duk_idx_t argnames_idx; - duk_idx_t varmap_idx; - - /* Temp reg handling. */ - duk_regconst_t temp_first; /* first register that is a temporary (below: variables) */ - duk_regconst_t temp_next; /* next temporary register to allocate */ - duk_regconst_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */ - - /* Shuffle registers if large number of regs/consts. */ - duk_regconst_t shuffle1; - duk_regconst_t shuffle2; - duk_regconst_t shuffle3; - - /* Stats for current expression being parsed. */ - duk_int_t nud_count; - duk_int_t led_count; - duk_int_t paren_level; /* parenthesis count, 0 = top level */ - duk_bool_t expr_lhs; /* expression is left-hand-side compatible */ - duk_bool_t allow_in; /* current paren level allows 'in' token */ - - /* Misc. */ - duk_int_t stmt_next; /* statement id allocation (running counter) */ - duk_int_t label_next; /* label id allocation (running counter) */ - duk_int_t catch_depth; /* catch stack depth */ - duk_int_t with_depth; /* with stack depth (affects identifier lookups) */ - duk_int_t fnum_next; /* inner function numbering */ - duk_int_t num_formals; /* number of formal arguments */ - duk_regconst_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_int_t min_line; /* XXX: typing (duk_hcompfunc has duk_uint32_t) */ - duk_int_t max_line; -#endif - - /* Status booleans. */ - duk_uint8_t is_function; /* is an actual function (not global/eval code) */ - duk_uint8_t is_eval; /* is eval code */ - duk_uint8_t is_global; /* is global code */ - duk_uint8_t is_namebinding; /* needs a name binding */ - duk_uint8_t is_constructable; /* result is constructable */ - duk_uint8_t is_setget; /* is a setter/getter */ - duk_uint8_t is_strict; /* function is strict */ - duk_uint8_t is_notail; /* function must not be tail called */ - duk_uint8_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */ - duk_uint8_t in_scanning; /* parsing in "scanning" phase (first pass) */ - duk_uint8_t may_direct_eval; /* function may call direct eval */ - duk_uint8_t id_access_arguments; /* function refers to 'arguments' identifier */ - duk_uint8_t id_access_slow; /* function makes one or more slow path accesses that won't match own static variables */ - duk_uint8_t id_access_slow_own; /* function makes one or more slow path accesses that may match own static variables */ - duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */ - duk_uint8_t needs_shuffle; /* function needs shuffle registers */ - duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */ -}; - -struct duk_compiler_ctx { - duk_hthread *thr; - - /* filename being compiled (ends up in functions' '_filename' property) */ - duk_hstring *h_filename; /* borrowed reference */ - - /* lexing (tokenization) state (contains two valstack slot indices) */ - duk_lexer_ctx lex; - - /* current and previous token for parsing */ - duk_token prev_token; - duk_token curr_token; - duk_idx_t tok11_idx; /* curr_token slot1 (matches 'lex' slot1_idx) */ - duk_idx_t tok12_idx; /* curr_token slot2 (matches 'lex' slot2_idx) */ - duk_idx_t tok21_idx; /* prev_token slot1 */ - duk_idx_t tok22_idx; /* prev_token slot2 */ - - /* recursion limit */ - duk_int_t recursion_depth; - duk_int_t recursion_limit; - - /* code emission temporary */ - duk_int_t emit_jumpslot_pc; - - /* current function being compiled (embedded instead of pointer for more compact access) */ - duk_compiler_func curr_func; -}; - -/* - * Prototypes - */ - -DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags); - -#endif /* DUK_JS_COMPILER_H_INCLUDED */ -/* #include duk_regexp.h */ -#line 1 "duk_regexp.h" -/* - * Regular expression structs, constants, and bytecode defines. - */ - -#if !defined(DUK_REGEXP_H_INCLUDED) -#define DUK_REGEXP_H_INCLUDED - -/* maximum bytecode copies for {n,m} quantifiers */ -#define DUK_RE_MAX_ATOM_COPIES 1000 - -/* regexp compilation limits */ -#define DUK_RE_COMPILE_TOKEN_LIMIT 100000000L /* 1e8 */ - -/* regexp execution limits */ -#define DUK_RE_EXECUTE_STEPS_LIMIT 1000000000L /* 1e9 */ - -/* regexp opcodes */ -#define DUK_REOP_MATCH 1 -#define DUK_REOP_CHAR 2 -#define DUK_REOP_PERIOD 3 -#define DUK_REOP_RANGES 4 -#define DUK_REOP_INVRANGES 5 -#define DUK_REOP_JUMP 6 -#define DUK_REOP_SPLIT1 7 -#define DUK_REOP_SPLIT2 8 -#define DUK_REOP_SQMINIMAL 9 -#define DUK_REOP_SQGREEDY 10 -#define DUK_REOP_SAVE 11 -#define DUK_REOP_WIPERANGE 12 -#define DUK_REOP_LOOKPOS 13 -#define DUK_REOP_LOOKNEG 14 -#define DUK_REOP_BACKREFERENCE 15 -#define DUK_REOP_ASSERT_START 16 -#define DUK_REOP_ASSERT_END 17 -#define DUK_REOP_ASSERT_WORD_BOUNDARY 18 -#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19 - -/* flags */ -#define DUK_RE_FLAG_GLOBAL (1U << 0) -#define DUK_RE_FLAG_IGNORE_CASE (1U << 1) -#define DUK_RE_FLAG_MULTILINE (1U << 2) - -struct duk_re_matcher_ctx { - duk_hthread *thr; - - duk_uint32_t re_flags; - const duk_uint8_t *input; - const duk_uint8_t *input_end; - const duk_uint8_t *bytecode; - const duk_uint8_t *bytecode_end; - const duk_uint8_t **saved; /* allocated from valstack (fixed buffer) */ - duk_uint32_t nsaved; - duk_uint32_t recursion_depth; - duk_uint32_t recursion_limit; - duk_uint32_t steps_count; - duk_uint32_t steps_limit; -}; - -struct duk_re_compiler_ctx { - duk_hthread *thr; - - duk_uint32_t re_flags; - duk_lexer_ctx lex; - duk_re_token curr_token; - duk_bufwriter_ctx bw; - duk_uint32_t captures; /* highest capture number emitted so far (used as: ++captures) */ - duk_uint32_t highest_backref; - duk_uint32_t recursion_depth; - duk_uint32_t recursion_limit; - duk_uint32_t nranges; /* internal temporary value, used for char classes */ -}; - -/* - * Prototypes - */ - -#if defined(DUK_USE_REGEXP_SUPPORT) -DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */ -#endif - -#endif /* DUK_REGEXP_H_INCLUDED */ -/* #include duk_heaphdr.h */ -#line 1 "duk_heaphdr.h" -/* - * Heap header definition and assorted macros, including ref counting. - * Access all fields through the accessor macros. - */ - -#if !defined(DUK_HEAPHDR_H_INCLUDED) -#define DUK_HEAPHDR_H_INCLUDED - -/* - * Common heap header - * - * All heap objects share the same flags and refcount fields. Objects other - * than strings also need to have a single or double linked list pointers - * for insertion into the "heap allocated" list. Strings have single linked - * list pointers for string table chaining. - * - * Technically, 'h_refcount' must be wide enough to guarantee that it cannot - * wrap; otherwise objects might be freed incorrectly after wrapping. The - * default refcount field is 32 bits even on 64-bit systems: while that's in - * theory incorrect, the Duktape heap needs to be larger than 64GB for the - * count to actually wrap (assuming 16-byte duk_tvals). This is very unlikely - * to ever be an issue, but if it is, disabling DUK_USE_REFCOUNT32 causes - * Duktape to use size_t for refcounts which should always be safe. - * - * Heap header size on 32-bit platforms: 8 bytes without reference counting, - * 16 bytes with reference counting. - * - * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not - * defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined() - * around them. - */ - -/* XXX: macro for shared header fields (avoids some padding issues) */ - -struct duk_heaphdr { - duk_uint32_t h_flags; - -#if defined(DUK_USE_REFERENCE_COUNTING) -#if defined(DUK_USE_ASSERTIONS) - /* When assertions enabled, used by mark-and-sweep for refcount - * validation. Largest reasonable type; also detects overflows. - */ - duk_size_t h_assert_refcount; -#endif -#if defined(DUK_USE_REFCOUNT16) - duk_uint16_t h_refcount; -#elif defined(DUK_USE_REFCOUNT32) - duk_uint32_t h_refcount; -#else - duk_size_t h_refcount; -#endif -#endif /* DUK_USE_REFERENCE_COUNTING */ - -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t h_next16; -#else - duk_heaphdr *h_next; -#endif - -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - /* refcounting requires direct heap frees, which in turn requires a dual linked heap */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t h_prev16; -#else - duk_heaphdr *h_prev; -#endif -#endif - - /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the - * struct won't align nicely to 4 bytes. This 16-bit extra field - * is added to make the alignment clean; the field can be used by - * heap objects when 16-bit packing is used. This field is now - * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be - * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP; - * this only matter to low memory environments anyway. - */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t h_extra16; -#endif -}; - -struct duk_heaphdr_string { - /* 16 bits would be enough for shared heaphdr flags and duk_hstring - * flags. The initial parts of duk_heaphdr_string and duk_heaphdr - * must match so changing the flags field size here would be quite - * awkward. However, to minimize struct size, we can pack at least - * 16 bits of duk_hstring data into the flags field. - */ - duk_uint32_t h_flags; - -#if defined(DUK_USE_REFERENCE_COUNTING) -#if defined(DUK_USE_ASSERTIONS) - /* When assertions enabled, used by mark-and-sweep for refcount - * validation. Largest reasonable type; also detects overflows. - */ - duk_size_t h_assert_refcount; -#endif -#if defined(DUK_USE_REFCOUNT16) - duk_uint16_t h_refcount; - duk_uint16_t h_strextra16; /* round out to 8 bytes */ -#elif defined(DUK_USE_REFCOUNT32) - duk_uint32_t h_refcount; -#else - duk_size_t h_refcount; -#endif -#else - duk_uint16_t h_strextra16; -#endif /* DUK_USE_REFERENCE_COUNTING */ - - duk_hstring *h_next; - /* No 'h_prev' pointer for strings. */ -}; - -#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL -#define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK) - - /* 2 bits for heap type */ -#define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */ -#define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */ - -#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n)) -#define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n)) -#define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n))) -#define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n))) - -#define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */ -#define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */ -#define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */ -#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */ -#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */ - -#define DUK_HTYPE_MIN 0 -#define DUK_HTYPE_STRING 0 -#define DUK_HTYPE_OBJECT 1 -#define DUK_HTYPE_BUFFER 2 -#define DUK_HTYPE_MAX 2 - -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HEAPHDR_GET_NEXT(heap,h) \ - ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16)) -#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \ - (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \ - } while (0) -#else -#define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next) -#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \ - (h)->h_next = (val); \ - } while (0) -#endif - -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HEAPHDR_GET_PREV(heap,h) \ - ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16)) -#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \ - (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \ - } while (0) -#else -#define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev) -#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \ - (h)->h_prev = (val); \ - } while (0) -#endif -#endif - -#if defined(DUK_USE_REFERENCE_COUNTING) -#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount) -#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \ - (h)->h_refcount = (val); \ - DUK_ASSERT((h)->h_refcount == (val)); /* No truncation. */ \ - } while (0) -#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */ -#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */ -#else -/* refcount macros not defined without refcounting, caller must #if defined() now */ -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* - * Note: type is treated as a field separate from flags, so some masking is - * involved in the macros below. - */ - -#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags) -#define DUK_HEAPHDR_SET_FLAGS_RAW(h,val) do { \ - (h)->h_flags = (val); } \ - } -#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK) -#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \ - (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \ - } while (0) -#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK) -#define DUK_HEAPHDR_SET_TYPE(h,val) do { \ - (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \ - } while (0) - -/* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero - * and the comparison is unsigned, it's always true and generates warnings. - */ -#define DUK_HEAPHDR_HTYPE_VALID(h) ( \ - DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \ - ) - -#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \ - (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \ - ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \ - } while (0) - -#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \ - DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \ - (h)->h_flags |= (bits); \ - } while (0) - -#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \ - DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \ - (h)->h_flags &= ~((bits)); \ - } while (0) - -#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0) - -#define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) -#define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) -#define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) - -#define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) -#define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) -#define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) - -#define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) -#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) -#define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) - -#define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) -#define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) -#define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) - -#define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) -#define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) -#define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) - -/* get or set a range of flags; m=first bit number, n=number of bits */ -#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL)) - -#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \ - (h)->h_flags = \ - ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \ - | ((v) << (m)); \ - } while (0) - -/* init pointer fields to null */ -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) -#define DUK_HEAPHDR_INIT_NULLS(h) do { \ - DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \ - DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \ - } while (0) -#else -#define DUK_HEAPHDR_INIT_NULLS(h) do { \ - DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \ - } while (0) -#endif - -#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \ - (h)->h_next = NULL; \ - } while (0) - -/* - * Type tests - */ - -/* Take advantage of the fact that for DUK_HTYPE_xxx numbers the lowest bit - * is only set for DUK_HTYPE_OBJECT (= 1). - */ -#if 0 -#define DUK_HEAPHDR_IS_OBJECT(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT) -#endif -#define DUK_HEAPHDR_IS_OBJECT(h) ((h)->h_flags & 0x01UL) -#define DUK_HEAPHDR_IS_STRING(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING) -#define DUK_HEAPHDR_IS_BUFFER(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER) - -/* - * Assert helpers - */ - -/* Check that prev/next links are consistent: if e.g. h->prev is != NULL, - * h->prev->next should point back to h. - */ -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_ASSERTIONS) -#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do { \ - if ((h) != NULL) { \ - duk_heaphdr *h__prev, *h__next; \ - h__prev = DUK_HEAPHDR_GET_PREV((heap), (h)); \ - h__next = DUK_HEAPHDR_GET_NEXT((heap), (h)); \ - DUK_ASSERT(h__prev == NULL || (DUK_HEAPHDR_GET_NEXT((heap), h__prev) == (h))); \ - DUK_ASSERT(h__next == NULL || (DUK_HEAPHDR_GET_PREV((heap), h__next) == (h))); \ - } \ - } while (0) -#else -#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0) -#endif - -#define DUK_ASSERT_HEAPHDR_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((h))); \ - } while (0) - -#endif /* DUK_HEAPHDR_H_INCLUDED */ -/* #include duk_refcount.h */ -#line 1 "duk_refcount.h" -/* - * Reference counting helper macros. The macros take a thread argument - * and must thus always be executed in a specific thread context. The - * thread argument is not really needed anymore: DECREF can operate with - * a heap pointer only, and INCREF needs neither. - */ - -#if !defined(DUK_REFCOUNT_H_INCLUDED) -#define DUK_REFCOUNT_H_INCLUDED - -#if defined(DUK_USE_REFERENCE_COUNTING) - -#if defined(DUK_USE_ROM_OBJECTS) -/* With ROM objects "needs refcount update" is true when the value is - * heap allocated and is not a ROM object. - */ -/* XXX: double evaluation for 'tv' argument. */ -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \ - (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv)))) -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h))) -#else /* DUK_USE_ROM_OBJECTS */ -/* Without ROM objects "needs refcount update" == is heap allocated. */ -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv)) -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1 -#endif /* DUK_USE_ROM_OBJECTS */ - -/* Fast variants, inline refcount operations except for refzero handling. - * Can be used explicitly when speed is always more important than size. - * For a good compiler and a single file build, these are basically the - * same as a forced inline. - */ -#define DUK_TVAL_INCREF_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ - } \ - } while (0) -#define DUK_TVAL_DECREF_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - duk_heaphdr_refzero((thr), duk__h); \ - } \ - } \ - } while (0) -#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - duk_heaphdr_refzero_norz((thr), duk__h); \ - } \ - } \ - } while (0) -#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \ - duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ - DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ - duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - (rzcall)((thr), (rzcast) duk__h); \ - } \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_FAST(thr,h) \ - DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) -#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \ - DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) - -/* Slow variants, call to a helper to reduce code size. - * Can be used explicitly when size is always more important than speed. - */ -#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0) -#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0) -#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0) -#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) - -/* Default variants. Selection depends on speed/size preference. - * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary - * is about +1kB for _FAST variants. - */ -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -/* XXX: It would be nice to specialize for specific duk_hobject subtypes - * but current refzero queue handling prevents that. - */ -#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv)) -#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv)) -#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv)) -#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h)) -#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) -#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) -#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */ -#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) -#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */ -#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#else -#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv)) -#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv)) -#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv)) -#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h)) -#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h)) -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h)) -#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h)) -#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h)) -#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#endif - -/* Convenience for some situations; the above macros don't allow NULLs - * for performance reasons. Macros cover only actually needed cases. - */ -#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) - -/* Called after one or more DECREF NORZ calls to handle pending side effects. - * At present DECREF NORZ does freeing inline but doesn't execute finalizers, - * so these macros check for pending finalizers and execute them. The FAST - * variant is performance critical. - */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -#define DUK_REFZERO_CHECK_FAST(thr) do { \ - duk_refzero_check_fast((thr)); \ - } while (0) -#define DUK_REFZERO_CHECK_SLOW(thr) do { \ - duk_refzero_check_slow((thr)); \ - } while (0) -#else /* DUK_USE_FINALIZER_SUPPORT */ -#define DUK_REFZERO_CHECK_FAST(thr) do { } while (0) -#define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0) -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* - * Macros to set a duk_tval and update refcount of the target (decref the - * old value and incref the new value if necessary). This is both performance - * and footprint critical; any changes made should be measured for size/speed. - */ - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \ - } while (0) - -#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNUSED(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NULL(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NAN(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_I48(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_I32(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_U32(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#else -#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ - DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_STRING(tv__dst, (newval)); \ - DUK_HSTRING_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ - DUK_HOBJECT_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ - DUK_HBUFFER_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups, - * etc, so it's very important for performance. Measure when changing. - * - * NOTE: the source and destination duk_tval pointers may be the same, and - * the macros MUST deal with that correctly. - */ - -/* Original idiom used, minimal code size. */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF((thr), tv__src); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -/* Faster alternative: avoid making a temporary copy of tvptr_dst and use - * fast incref/decref macros. - */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_INCREF_FAST((thr), tv__src); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \ - h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ - DUK_ASSERT(h__obj != NULL); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ - } else { \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - } \ - } while (0) - -/* XXX: no optimized variants yet */ -#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0 -#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 -#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 -#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 -#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 -#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 -#else -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 -#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 -#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 -#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 -#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 - -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -/* Optimized for speed. */ -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#else -/* Optimized for size. */ -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#endif - -#else /* DUK_USE_REFERENCE_COUNTING */ - -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0 -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0 - -#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */ - -#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ - -#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */ -#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */ - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_UNUSED(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NULL(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NAN(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_I48(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_I32(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_U32(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#else -#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ - DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_STRING(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 -#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 -#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 -#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 -#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 -#else -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 -#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 -#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 -#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 -#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 - -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 - -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* - * Some convenience macros that don't have optimized implementations now. - */ - -#define DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr,tv_dst,tv_src) do { \ - duk_hthread *duk__thr = (thr); \ - duk_tval *duk__dst = (tv_dst); \ - duk_tval *duk__src = (tv_src); \ - DUK_UNREF(duk__thr); \ - DUK_TVAL_DECREF_NORZ(thr, duk__dst); \ - DUK_TVAL_SET_TVAL(duk__dst, duk__src); \ - DUK_TVAL_INCREF(thr, duk__dst); \ - } while (0) - -#define DUK_TVAL_SET_U32_UPDREF_NORZ(thr,tv_dst,val) do { \ - duk_hthread *duk__thr = (thr); \ - duk_tval *duk__dst = (tv_dst); \ - duk_uint32_t duk__val = (duk_uint32_t) (val); \ - DUK_UNREF(duk__thr); \ - DUK_TVAL_DECREF_NORZ(thr, duk__dst); \ - DUK_TVAL_SET_U32(duk__dst, duk__val); \ - } while (0) - -/* - * Prototypes - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr); -#endif -DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr); -DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h); -#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ -DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); -#endif -DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); -#else -DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); -#endif -#else /* DUK_USE_REFERENCE_COUNTING */ -/* no refcounting */ -#endif /* DUK_USE_REFERENCE_COUNTING */ - -#endif /* DUK_REFCOUNT_H_INCLUDED */ -/* #include duk_api_internal.h */ -#line 1 "duk_api_internal.h" -/* - * Internal API calls which have (stack and other) semantics similar - * to the public API. - */ - -#if !defined(DUK_API_INTERNAL_H_INCLUDED) -#define DUK_API_INTERNAL_H_INCLUDED - -#define DUK_INTERNAL_SYMBOL(x) ("\x82" x) - -/* duk_push_sprintf constants */ -#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L -#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L) - -/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not - * blamed as source of error for error fileName / lineNumber. - */ -#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24) - -/* Current convention is to use duk_size_t for value stack sizes and global indices, - * and duk_idx_t for local frame indices. - */ -DUK_INTERNAL_DECL void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes); -DUK_INTERNAL_DECL duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes); -DUK_INTERNAL_DECL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug); - -DUK_INTERNAL_DECL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count); - -DUK_INTERNAL_DECL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count); - -DUK_INTERNAL_DECL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start); - -DUK_INTERNAL_DECL void duk_dup_0(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_dup_1(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_dup_2(duk_hthread *thr); -/* duk_dup_m1() would be same as duk_dup_top() */ -DUK_INTERNAL_DECL void duk_dup_m2(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_dup_m3(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_dup_m4(duk_hthread *thr); - -DUK_INTERNAL_DECL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL void duk_remove_m2(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count); -DUK_INTERNAL_DECL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count); - -DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv); -DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv); - -#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) -DUK_INTERNAL_DECL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx); -#endif -DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx); - -DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL void duk_push_tval(duk_hthread *thr, duk_tval *tv); - -/* Push the current 'this' binding; throw TypeError if binding is not object - * coercible (CheckObjectCoercible). - */ -DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_hthread *thr); - -/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */ -DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr); - -/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */ -DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr); - -DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i); - -/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must - * make sure there's an active callstack entry. Note that the returned pointer - * is unstable with regards to side effects. - */ -DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr); - -/* XXX: add fastint support? */ -#define duk_push_u64(thr,val) \ - duk_push_number((thr), (duk_double_t) (val)) -#define duk_push_i64(thr,val) \ - duk_push_number((thr), (duk_double_t) (val)) - -/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */ -#define duk_push_u32(thr,val) \ - duk_push_uint((thr), (duk_uint_t) (val)) -#define duk_push_i32(thr,val) \ - duk_push_int((thr), (duk_int_t) (val)) - -/* sometimes stack and array indices need to go on the stack */ -#define duk_push_idx(thr,val) \ - duk_push_int((thr), (duk_int_t) (val)) -#define duk_push_uarridx(thr,val) \ - duk_push_uint((thr), (duk_uint_t) (val)) -#define duk_push_size_t(thr,val) \ - duk_push_uint((thr), (duk_uint_t) (val)) /* XXX: assumed to fit for now */ - -DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx); - -DUK_INTERNAL_DECL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv); - -DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx); - -DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len, duk_bool_t throw_flag, duk_bool_t *out_isbuffer); - -DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum); - -DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask); -DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask); -DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask); -#define duk_require_hobject_promote_lfunc(thr,idx) \ - duk_require_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC) -#define duk_get_hobject_promote_lfunc(thr,idx) \ - duk_get_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC) - -#if 0 /*unused*/ -DUK_INTERNAL_DECL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx); -#endif - -DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx); - -DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv); - -DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_hthread *thr); -DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx); - -DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx); - -DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr); -DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr); - -#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ -DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx); -#endif -DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv); - -DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */ -DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval); -DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx); - -DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len); -DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx); - -DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum); - -DUK_INTERNAL_DECL void duk_push_hstring(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx); -DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_push_hobject(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h); -#define duk_push_hthread(thr,h) \ - duk_push_hobject((thr), (duk_hobject *) (h)) -#define duk_push_hnatfunc(thr,h) \ - duk_push_hobject((thr), (duk_hobject *) (h)) -DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx); -DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); -DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto); -DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr); -DUK_INTERNAL_DECL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs); -DUK_INTERNAL_DECL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs); - -/* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with - * duk_push_hobject() etc which don't create a new value. - */ -DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_hthread *thr); -DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size); -DUK_INTERNAL_DECL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size); - -DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz); -DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags); -DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv); -#if 0 /* not used yet */ -DUK_INTERNAL_DECL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h); -#endif -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); -#endif - -DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len); -DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len); - -DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv); - -/* The duk_xxx_prop_stridx_short() variants expect their arguments to be short - * enough to be packed into a single 32-bit integer argument. Argument limits - * vary per call; typically 16 bits are assigned to the signed value stack index - * and the stridx. In practice these work well for footprint with constant - * arguments and such call sites are also easiest to verify to be correct. - */ - -DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */ -DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); -#define duk_get_prop_stridx_short(thr,obj_idx,stridx) \ - (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \ - DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ - duk_get_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) -DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */ - -DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */ -DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); -#define duk_put_prop_stridx_short(thr,obj_idx,stridx) \ - (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \ - DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ - duk_put_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) - -DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ -#if 0 /* Too few call sites to be useful. */ -DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); -#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \ - (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \ - DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \ - duk_del_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) -#endif -#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \ - duk_del_prop_stridx((thr), (obj_idx), (stridx)) - -DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ -#if 0 /* Too few call sites to be useful. */ -DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); -#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \ - (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \ - DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \ - duk_has_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) -#endif -#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \ - duk_has_prop_stridx((thr), (obj_idx), (stridx)) - -DUK_INTERNAL_DECL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */ - -DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */ - -/* XXX: Because stridx and desc_flags have a limited range, this call could - * always pack stridx and desc_flags into a single argument. - */ -DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */ -DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); -#define duk_xdef_prop_stridx_short(thr,obj_idx,stridx,desc_flags) \ - (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \ - DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ - DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \ - duk_xdef_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags))) - -#define duk_xdef_prop_wec(thr,obj_idx) \ - duk_xdef_prop((thr), (obj_idx), DUK_PROPDESC_FLAGS_WEC) -#define duk_xdef_prop_index_wec(thr,obj_idx,arr_idx) \ - duk_xdef_prop_index((thr), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC) -#define duk_xdef_prop_stridx_wec(thr,obj_idx,stridx) \ - duk_xdef_prop_stridx((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC) -#define duk_xdef_prop_stridx_short_wec(thr,obj_idx,stridx) \ - duk_xdef_prop_stridx_short((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC) - -#if 0 /*unused*/ -DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */ -#endif - -DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ - -DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count); -DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx); -#if 0 -DUK_INTERNAL_DECL void duk_unpack(duk_hthread *thr); -#endif - -DUK_INTERNAL_DECL void duk_require_constructor_call(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h); - -DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_hthread *thr); - -DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top); -DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr); - -DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count); -DUK_INTERNAL_DECL void duk_pop_unsafe(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_pop_2_unsafe(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_pop_3_unsafe(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count); -DUK_INTERNAL_DECL void duk_pop_nodecref_unsafe(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_pop_2_nodecref_unsafe(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_pop_3_nodecref_unsafe(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_pop_undefined(duk_hthread *thr); - -DUK_INTERNAL_DECL void duk_compact_m1(duk_hthread *thr); - -DUK_INTERNAL_DECL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze); - -DUK_INTERNAL_DECL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx); -DUK_INTERNAL_DECL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count); - -DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr); - -DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags); - -/* Raw internal valstack access macros: access is unsafe so call site - * must have a guarantee that the index is valid. When that is the case, - * using these macro results in faster and smaller code than duk_get_tval(). - * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts. - */ -#define DUK_ASSERT_VALID_NEGIDX(thr,idx) \ - (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx)))) -#define DUK_ASSERT_VALID_POSIDX(thr,idx) \ - (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx)))) -#define DUK_GET_TVAL_NEGIDX(thr,idx) \ - (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_top + (idx)) -#define DUK_GET_TVAL_POSIDX(thr,idx) \ - (DUK_ASSERT_VALID_POSIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_bottom + (idx)) -#define DUK_GET_HOBJECT_NEGIDX(thr,idx) \ - (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_top + (idx))) -#define DUK_GET_HOBJECT_POSIDX(thr,idx) \ - (DUK_ASSERT_VALID_POSIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_bottom + (idx))) - -#define DUK_GET_THIS_TVAL_PTR(thr) \ - (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \ - (thr)->valstack_bottom - 1) - -DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr); -DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr); -DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); - -#endif /* DUK_API_INTERNAL_H_INCLUDED */ -/* #include duk_hstring.h */ -#line 1 "duk_hstring.h" -/* - * Heap string representation. - * - * Strings are byte sequences ordinarily stored in extended UTF-8 format, - * allowing values larger than the official UTF-8 range (used internally) - * and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format). - * Strings may also be invalid UTF-8 altogether which is the case e.g. with - * strings used as internal property names and raw buffers converted to - * strings. In such cases the 'clen' field contains an inaccurate value. - * - * Ecmascript requires support for 32-bit long strings. However, since each - * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only - * support about 1.4G codepoint long strings in extreme cases. This is not - * really a practical issue. - */ - -#if !defined(DUK_HSTRING_H_INCLUDED) -#define DUK_HSTRING_H_INCLUDED - -/* Impose a maximum string length for now. Restricted artificially to - * ensure adding a heap header length won't overflow size_t. The limit - * should be synchronized with DUK_HBUFFER_MAX_BYTELEN. - * - * E5.1 makes provisions to support strings longer than 4G characters. - * This limit should be eliminated on 64-bit platforms (and increased - * closer to maximum support on 32-bit platforms). - */ - -#if defined(DUK_USE_STRLEN16) -#define DUK_HSTRING_MAX_BYTELEN (0x0000ffffUL) -#else -#define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL) -#endif - -/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings), - * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not, - * regexp bytecode is), and "contains non-BMP characters". These are not - * needed right now. - */ - -#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */ -#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */ -#define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */ -#define DUK_HSTRING_FLAG_HIDDEN DUK_HEAPHDR_USER_FLAG(3) /* string is a hidden symbol (implies symbol, Duktape 1.x internal string) */ -#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (non-strict) */ -#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */ -#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */ -#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */ - -#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) -#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) -#define DUK_HSTRING_HAS_SYMBOL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) -#define DUK_HSTRING_HAS_HIDDEN(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) -#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) -#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) -#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) -#define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) - -#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) -#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) -#define DUK_HSTRING_SET_SYMBOL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) -#define DUK_HSTRING_SET_HIDDEN(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) -#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) -#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) -#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) -#define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) - -#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) -#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) -#define DUK_HSTRING_CLEAR_SYMBOL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) -#define DUK_HSTRING_CLEAR_HIDDEN(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) -#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) -#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) -#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) -#define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) - -#if 0 /* Slightly smaller code without explicit flag, but explicit flag - * is very useful when 'clen' is dropped. - */ -#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x))) -#endif -#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */ -#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0) - -#if defined(DUK_USE_STRHASH16) -#define DUK_HSTRING_GET_HASH(x) ((x)->hdr.h_flags >> 16) -#define DUK_HSTRING_SET_HASH(x,v) do { \ - (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \ - } while (0) -#else -#define DUK_HSTRING_GET_HASH(x) ((x)->hash) -#define DUK_HSTRING_SET_HASH(x,v) do { \ - (x)->hash = (v); \ - } while (0) -#endif - -#if defined(DUK_USE_STRLEN16) -#define DUK_HSTRING_GET_BYTELEN(x) ((x)->hdr.h_strextra16) -#define DUK_HSTRING_SET_BYTELEN(x,v) do { \ - (x)->hdr.h_strextra16 = (v); \ - } while (0) -#if defined(DUK_USE_HSTRING_CLEN) -#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) -#define DUK_HSTRING_SET_CHARLEN(x,v) do { \ - (x)->clen16 = (v); \ - } while (0) -#else -#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) -#define DUK_HSTRING_SET_CHARLEN(x,v) do { \ - DUK_ASSERT(0); /* should never be called */ \ - } while (0) -#endif -#else -#define DUK_HSTRING_GET_BYTELEN(x) ((x)->blen) -#define DUK_HSTRING_SET_BYTELEN(x,v) do { \ - (x)->blen = (v); \ - } while (0) -#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) -#define DUK_HSTRING_SET_CHARLEN(x,v) do { \ - (x)->clen = (v); \ - } while (0) -#endif - -#if defined(DUK_USE_HSTRING_EXTDATA) -#define DUK_HSTRING_GET_EXTDATA(x) \ - ((x)->extdata) -#define DUK_HSTRING_GET_DATA(x) \ - (DUK_HSTRING_HAS_EXTDATA((x)) ? \ - DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1))) -#else -#define DUK_HSTRING_GET_DATA(x) \ - ((const duk_uint8_t *) ((x) + 1)) -#endif - -#define DUK_HSTRING_GET_DATA_END(x) \ - (DUK_HSTRING_GET_DATA((x)) + (x)->blen) - -/* Marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest - * valid). - */ -#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL) - -#if defined(DUK_USE_HSTRING_ARRIDX) -#define DUK_HSTRING_GET_ARRIDX_FAST(h) ((h)->arridx) -#define DUK_HSTRING_GET_ARRIDX_SLOW(h) ((h)->arridx) -#else -/* Get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX); - * avoids helper call if string has no array index value. - */ -#define DUK_HSTRING_GET_ARRIDX_FAST(h) \ - (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX) - -/* Slower but more compact variant. */ -#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \ - (duk_js_to_arrayindex_hstring_fast((h))) -#endif - -/* XXX: these actually fit into duk_hstring */ -#define DUK_SYMBOL_TYPE_HIDDEN 0 -#define DUK_SYMBOL_TYPE_GLOBAL 1 -#define DUK_SYMBOL_TYPE_LOCAL 2 -#define DUK_SYMBOL_TYPE_WELLKNOWN 3 - -/* - * Misc - */ - -struct duk_hstring { - /* Smaller heaphdr than for other objects, because strings are held - * in string intern table which requires no link pointers. Much of - * the 32-bit flags field is unused by flags, so we can stuff a 16-bit - * field in there. - */ - duk_heaphdr_string hdr; - - /* String hash. */ -#if defined(DUK_USE_STRHASH16) - /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */ -#else - duk_uint32_t hash; -#endif - - /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */ -#if defined(DUK_USE_HSTRING_ARRIDX) - duk_uarridx_t arridx; -#endif - - /* Length in bytes (not counting NUL term). */ -#if defined(DUK_USE_STRLEN16) - /* placed in duk_heaphdr_string */ -#else - duk_uint32_t blen; -#endif - - /* Length in codepoints (must be E5 compatible). */ -#if defined(DUK_USE_STRLEN16) -#if defined(DUK_USE_HSTRING_CLEN) - duk_uint16_t clen16; -#else - /* computed live */ -#endif -#else - duk_uint32_t clen; -#endif - - /* - * String data of 'blen+1' bytes follows (+1 for NUL termination - * convenience for C API). No alignment needs to be guaranteed - * for strings, but fields above should guarantee alignment-by-4 - * (but not alignment-by-8). - */ -}; - -/* The external string struct is defined even when the feature is inactive. */ -struct duk_hstring_external { - duk_hstring str; - - /* - * For an external string, the NUL-terminated string data is stored - * externally. The user must guarantee that data behind this pointer - * doesn't change while it's used. - */ - - const duk_uint8_t *extdata; -}; - -/* - * Prototypes - */ - -DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware); -DUK_INTERNAL_DECL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr); -DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); -#if !defined(DUK_USE_HSTRING_LAZY_CLEN) -DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h); -#endif - -#endif /* DUK_HSTRING_H_INCLUDED */ -/* #include duk_hobject.h */ -#line 1 "duk_hobject.h" -/* - * Heap object representation. - * - * Heap objects are used for Ecmascript objects, arrays, and functions, - * but also for internal control like declarative and object environment - * records. Compiled functions, native functions, and threads are also - * objects but with an extended C struct. - * - * Objects provide the required Ecmascript semantics and exotic behaviors - * especially for property access. - * - * Properties are stored in three conceptual parts: - * - * 1. A linear 'entry part' contains ordered key-value-attributes triples - * and is the main method of string properties. - * - * 2. An optional linear 'array part' is used for array objects to store a - * (dense) range of [0,N[ array indexed entries with default attributes - * (writable, enumerable, configurable). If the array part would become - * sparse or non-default attributes are required, the array part is - * abandoned and moved to the 'entry part'. - * - * 3. An optional 'hash part' is used to optimize lookups of the entry - * part; it is used only for objects with sufficiently many properties - * and can be abandoned without loss of information. - * - * These three conceptual parts are stored in a single memory allocated area. - * This minimizes memory allocation overhead but also means that all three - * parts are resized together, and makes property access a bit complicated. - */ - -#if !defined(DUK_HOBJECT_H_INCLUDED) -#define DUK_HOBJECT_H_INCLUDED - -/* Object flags. Make sure this stays in sync with debugger object - * inspection code. - */ - -/* XXX: some flags are object subtype specific (e.g. common to all function - * subtypes, duk_harray, etc) and could be reused for different subtypes. - */ -#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */ -#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */ -#define DUK_HOBJECT_FLAG_CALLABLE DUK_HEAPHDR_USER_FLAG(2) /* object is callable */ -#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(3) /* object established using Function.prototype.bind() */ -#define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */ -#define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */ -#define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */ -#define DUK_HOBJECT_FLAG_FASTREFS DUK_HEAPHDR_USER_FLAG(7) /* object has no fields needing DECREF/marking beyond base duk_hobject header */ -#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */ -#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */ -#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */ -#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */ -#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */ -#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */ -#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable (own) finalizer property */ -#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */ -#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */ -#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */ -#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Proxy' object */ -#define DUK_HOBJECT_FLAG_SPECIAL_CALL DUK_HEAPHDR_USER_FLAG(19) /* special casing in call behavior, for .call(), .apply(), etc. */ - -#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20) -#define DUK_HOBJECT_FLAG_CLASS_BITS 5 - -#define DUK_HOBJECT_GET_CLASS_NUMBER(h) \ - DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS) -#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \ - DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v)) - -#define DUK_HOBJECT_GET_CLASS_MASK(h) \ - (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)) - -/* Macro for creating flag initializer from a class number. - * Unsigned type cast is needed to avoid warnings about coercing - * a signed integer to an unsigned one; the largest class values - * have the highest bit (bit 31) set which causes this. - */ -#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE) - -/* E5 Section 8.6.2 + custom classes */ -#define DUK_HOBJECT_CLASS_NONE 0 -#define DUK_HOBJECT_CLASS_OBJECT 1 -#define DUK_HOBJECT_CLASS_ARRAY 2 -#define DUK_HOBJECT_CLASS_FUNCTION 3 -#define DUK_HOBJECT_CLASS_ARGUMENTS 4 -#define DUK_HOBJECT_CLASS_BOOLEAN 5 -#define DUK_HOBJECT_CLASS_DATE 6 -#define DUK_HOBJECT_CLASS_ERROR 7 -#define DUK_HOBJECT_CLASS_JSON 8 -#define DUK_HOBJECT_CLASS_MATH 9 -#define DUK_HOBJECT_CLASS_NUMBER 10 -#define DUK_HOBJECT_CLASS_REGEXP 11 -#define DUK_HOBJECT_CLASS_STRING 12 -#define DUK_HOBJECT_CLASS_GLOBAL 13 -#define DUK_HOBJECT_CLASS_SYMBOL 14 -#define DUK_HOBJECT_CLASS_OBJENV 15 /* custom */ -#define DUK_HOBJECT_CLASS_DECENV 16 /* custom */ -#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */ -#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */ -#define DUK_HOBJECT_CLASS_BUFOBJ_MIN 19 -#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFOBJ */ -#define DUK_HOBJECT_CLASS_DATAVIEW 20 -#define DUK_HOBJECT_CLASS_INT8ARRAY 21 -#define DUK_HOBJECT_CLASS_UINT8ARRAY 22 -#define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23 -#define DUK_HOBJECT_CLASS_INT16ARRAY 24 -#define DUK_HOBJECT_CLASS_UINT16ARRAY 25 -#define DUK_HOBJECT_CLASS_INT32ARRAY 26 -#define DUK_HOBJECT_CLASS_UINT32ARRAY 27 -#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28 -#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29 -#define DUK_HOBJECT_CLASS_BUFOBJ_MAX 29 -#define DUK_HOBJECT_CLASS_MAX 29 - -/* Class masks. */ -#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL) -#define DUK_HOBJECT_CMASK_NONE (1UL << DUK_HOBJECT_CLASS_NONE) -#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS) -#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY) -#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN) -#define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE) -#define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR) -#define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION) -#define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON) -#define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH) -#define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER) -#define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT) -#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP) -#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING) -#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL) -#define DUK_HOBJECT_CMASK_SYMBOL (1UL << DUK_HOBJECT_CLASS_SYMBOL) -#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV) -#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV) -#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER) -#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER) -#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW) -#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY) -#define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY) -#define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY) -#define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY) -#define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY) -#define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY) -#define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY) -#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY) -#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY) - -#define DUK_HOBJECT_CMASK_ALL_BUFOBJS \ - (DUK_HOBJECT_CMASK_ARRAYBUFFER | \ - DUK_HOBJECT_CMASK_DATAVIEW | \ - DUK_HOBJECT_CMASK_INT8ARRAY | \ - DUK_HOBJECT_CMASK_UINT8ARRAY | \ - DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \ - DUK_HOBJECT_CMASK_INT16ARRAY | \ - DUK_HOBJECT_CMASK_UINT16ARRAY | \ - DUK_HOBJECT_CMASK_INT32ARRAY | \ - DUK_HOBJECT_CMASK_UINT32ARRAY | \ - DUK_HOBJECT_CMASK_FLOAT32ARRAY | \ - DUK_HOBJECT_CMASK_FLOAT64ARRAY) - -#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV) -#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV) -#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h))) -#define DUK_HOBJECT_IS_ARRAY(h) DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)) /* Rely on class Array <=> exotic Array */ -#define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) -#define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) -#define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -#define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#else -#define DUK_HOBJECT_IS_BUFOBJ(h) 0 -#endif -#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD) -#if defined(DUK_USE_ES6_PROXY) -#define DUK_HOBJECT_IS_PROXY(h) DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((h)) -#else -#define DUK_HOBJECT_IS_PROXY(h) 0 -#endif - -#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ - DUK_HOBJECT_FLAG_COMPFUNC | \ - DUK_HOBJECT_FLAG_NATFUNC) - -#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ - DUK_HOBJECT_FLAG_BOUNDFUNC | \ - DUK_HOBJECT_FLAG_COMPFUNC | \ - DUK_HOBJECT_FLAG_NATFUNC) - -#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HOBJECT_HAS_CALLABLE((h)) - -/* Object has any exotic behavior(s). */ -#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ - DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \ - DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \ - DUK_HOBJECT_FLAG_BUFOBJ | \ - DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) -#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS) - -/* Object has any virtual properties (not counting Proxy behavior). */ -#define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ - DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \ - DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS) - -#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) -#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) -#define DUK_HOBJECT_HAS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE) -#define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) -#define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) -#define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -#define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#else -#define DUK_HOBJECT_HAS_BUFOBJ(h) 0 -#endif -#define DUK_HOBJECT_HAS_FASTREFS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS) -#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) -#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) -#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) -#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) -#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) -#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) -#define DUK_HOBJECT_HAS_HAVE_FINALIZER(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER) -#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) -#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) -#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) -#if defined(DUK_USE_ES6_PROXY) -#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) -#else -#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) 0 -#endif -#define DUK_HOBJECT_HAS_SPECIAL_CALL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL) - -#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) -#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) -#define DUK_HOBJECT_SET_CALLABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE) -#define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) -#define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) -#define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -#define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#endif -#define DUK_HOBJECT_SET_FASTREFS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS) -#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) -#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) -#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) -#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) -#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) -#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) -#define DUK_HOBJECT_SET_HAVE_FINALIZER(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER) -#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) -#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) -#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) -#if defined(DUK_USE_ES6_PROXY) -#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) -#endif -#define DUK_HOBJECT_SET_SPECIAL_CALL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL) - -#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) -#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) -#define DUK_HOBJECT_CLEAR_CALLABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE) -#define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) -#define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) -#define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -#define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#endif -#define DUK_HOBJECT_CLEAR_FASTREFS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS) -#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) -#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) -#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) -#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) -#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) -#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) -#define DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER) -#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) -#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) -#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) -#if defined(DUK_USE_ES6_PROXY) -#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) -#endif -#define DUK_HOBJECT_CLEAR_SPECIAL_CALL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL) - -/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond - * duk_hobject base header. This is used just for asserts so doesn't need to - * be optimized. - */ -#define DUK_HOBJECT_PROHIBITS_FASTREFS(h) \ - (DUK_HOBJECT_IS_COMPFUNC((h)) || DUK_HOBJECT_IS_DECENV((h)) || DUK_HOBJECT_IS_OBJENV((h)) || \ - DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)) || DUK_HOBJECT_IS_PROXY((h)) || \ - DUK_HOBJECT_IS_BOUNDFUNC((h))) -#define DUK_HOBJECT_ALLOWS_FASTREFS(h) (!DUK_HOBJECT_PROHIBITS_FASTREFS((h))) - -/* Flags used for property attributes in duk_propdesc and packed flags. - * Must fit into 8 bits. - */ -#define DUK_PROPDESC_FLAG_WRITABLE (1U << 0) /* E5 Section 8.6.1 */ -#define DUK_PROPDESC_FLAG_ENUMERABLE (1U << 1) /* E5 Section 8.6.1 */ -#define DUK_PROPDESC_FLAG_CONFIGURABLE (1U << 2) /* E5 Section 8.6.1 */ -#define DUK_PROPDESC_FLAG_ACCESSOR (1U << 3) /* accessor */ -#define DUK_PROPDESC_FLAG_VIRTUAL (1U << 4) /* property is virtual: used in duk_propdesc, never stored - * (used by e.g. buffer virtual properties) - */ -#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \ - DUK_PROPDESC_FLAG_ENUMERABLE | \ - DUK_PROPDESC_FLAG_CONFIGURABLE | \ - DUK_PROPDESC_FLAG_ACCESSOR) - -/* Additional flags which are passed in the same flags argument as property - * flags but are not stored in object properties. - */ -#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1U << 4) /* internal define property: skip write silently if exists */ - -/* Convenience defines for property attributes. */ -#define DUK_PROPDESC_FLAGS_NONE 0 -#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE) -#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE) -#define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE) -#define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE) -#define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE) -#define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE) -#define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \ - DUK_PROPDESC_FLAG_ENUMERABLE | \ - DUK_PROPDESC_FLAG_CONFIGURABLE) - -/* Flags for duk_hobject_get_own_propdesc() and variants. */ -#define DUK_GETDESC_FLAG_PUSH_VALUE (1U << 0) /* push value to stack */ -#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1U << 1) /* don't throw for prototype loop */ - -/* - * Macro for object validity check - * - * Assert for currently guaranteed relations between flags, for instance. - */ - -#define DUK_ASSERT_HOBJECT_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \ - DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ((h)) || \ - (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT16ARRAY || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT16ARRAY || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT32ARRAY || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \ - /* Object is an Array <=> object has exotic array behavior */ \ - DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY((h))) || \ - (DUK_HOBJECT_GET_CLASS_NUMBER((h)) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)))); \ - } while (0) - -/* - * Macros to access the 'props' allocation. - */ - -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HOBJECT_GET_PROPS(heap,h) \ - ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16)) -#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \ - ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \ - } while (0) -#else -#define DUK_HOBJECT_GET_PROPS(heap,h) \ - ((h)->props) -#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \ - (h)->props = (duk_uint8_t *) (x); \ - } while (0) -#endif - -#if defined(DUK_USE_HOBJECT_LAYOUT_1) -/* LAYOUT 1 */ -#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ - ((duk_hstring **) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) \ - )) -#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ - ((duk_propvalue *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \ - )) -#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ - ((duk_uint8_t *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \ - )) -#define DUK_HOBJECT_A_GET_BASE(heap,h) \ - ((duk_tval *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \ - )) -#define DUK_HOBJECT_H_GET_BASE(heap,h) \ - ((duk_uint32_t *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ - DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ - )) -#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ - ( \ - (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ - (n_arr) * sizeof(duk_tval) + \ - (n_hash) * sizeof(duk_uint32_t) \ - ) -#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ - (set_e_k) = (duk_hstring **) (void *) (p_base); \ - (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \ - (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \ - (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \ - (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \ - } while (0) -#elif defined(DUK_USE_HOBJECT_LAYOUT_2) -/* LAYOUT 2 */ -#if (DUK_USE_ALIGN_BY == 4) -#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03) -#elif (DUK_USE_ALIGN_BY == 8) -#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07) -#elif (DUK_USE_ALIGN_BY == 1) -#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0 -#else -#error invalid DUK_USE_ALIGN_BY -#endif -#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ - ((duk_hstring **) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \ - )) -#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ - ((duk_propvalue *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) \ - )) -#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ - ((duk_uint8_t *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \ - )) -#define DUK_HOBJECT_A_GET_BASE(heap,h) \ - ((duk_tval *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ - DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \ - )) -#define DUK_HOBJECT_H_GET_BASE(heap,h) \ - ((duk_uint32_t *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ - DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \ - DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ - )) -#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ - ( \ - (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ - DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \ - (n_arr) * sizeof(duk_tval) + \ - (n_hash) * sizeof(duk_uint32_t) \ - ) -#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ - (set_e_pv) = (duk_propvalue *) (void *) (p_base); \ - (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \ - (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \ - (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \ - sizeof(duk_uint8_t) * (n_ent) + \ - DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \ - (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \ - } while (0) -#elif defined(DUK_USE_HOBJECT_LAYOUT_3) -/* LAYOUT 3 */ -#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ - ((duk_hstring **) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \ - DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ - )) -#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ - ((duk_propvalue *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) \ - )) -#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ - ((duk_uint8_t *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \ - DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \ - DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \ - )) -#define DUK_HOBJECT_A_GET_BASE(heap,h) \ - ((duk_tval *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \ - )) -#define DUK_HOBJECT_H_GET_BASE(heap,h) \ - ((duk_uint32_t *) (void *) ( \ - DUK_HOBJECT_GET_PROPS((heap), (h)) + \ - DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \ - DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ - )) -#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ - ( \ - (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \ - (n_arr) * sizeof(duk_tval) + \ - (n_hash) * sizeof(duk_uint32_t) \ - ) -#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ - (set_e_pv) = (duk_propvalue *) (void *) (p_base); \ - (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \ - (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \ - (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \ - (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \ - } while (0) -#else -#error invalid hobject layout defines -#endif /* hobject property layout */ - -#define DUK_HOBJECT_P_ALLOC_SIZE(h) \ - DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h))) - -#define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v) -#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v) -#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get) -#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get) -#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set) -#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set) -#define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)]) -#define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)]) - -#define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \ - DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \ - } while (0) -#define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \ - DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \ - } while (0) -#define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \ - DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \ - } while (0) -#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \ - DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \ - } while (0) -#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \ - DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \ - } while (0) -#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \ - DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \ - } while (0) -#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \ - DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \ - } while (0) -#define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \ - DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */ -#define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \ - DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \ - } while (0) - -#define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \ - DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \ - } while (0) - -#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \ - DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \ - } while (0) - -#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0) -#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0) -#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0) -#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0) - -#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE) -#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE) -#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE) -#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR) - -#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE) -#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE) -#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE) -#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR) - -#define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0) -#define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0) -#define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0) -#define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0) - -#define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL -#define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL - -/* - * Macros for accessing size fields - */ - -#if defined(DUK_USE_OBJSIZES16) -#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16) -#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0) -#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16) -#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0) -#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++) -#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16) -#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0) -#if defined(DUK_USE_HOBJECT_HASH_PART) -#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16) -#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0) -#else -#define DUK_HOBJECT_GET_HSIZE(h) 0 -#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0) -#endif -#else -#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size) -#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0) -#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next) -#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0) -#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++) -#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size) -#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0) -#if defined(DUK_USE_HOBJECT_HASH_PART) -#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size) -#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0) -#else -#define DUK_HOBJECT_GET_HSIZE(h) 0 -#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0) -#endif -#endif - -/* - * Misc - */ - -/* Maximum prototype traversal depth. Sanity limit which handles e.g. - * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4). - */ -#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L - -/* - * Ecmascript [[Class]] - */ - -/* range check not necessary because all 4-bit values are mapped */ -#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)] - -#define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \ - DUK_HEAP_GET_STRING( \ - (heap), \ - DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \ - ) - -/* - * Macros for property handling - */ - -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \ - ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16)) -#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \ - (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \ - } while (0) -#else -#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \ - ((h)->prototype) -#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \ - (h)->prototype = (x); \ - } while (0) -#endif - -/* Set prototype, DECREF earlier value, INCREF new value (tolerating NULLs). */ -#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p)) - -/* Set initial prototype, assume NULL previous prototype, INCREF new value, - * tolerate NULL. - */ -#define DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr,h,proto) do { \ - duk_hthread *duk__thr = (thr); \ - duk_hobject *duk__obj = (h); \ - duk_hobject *duk__proto = (proto); \ - DUK_UNREF(duk__thr); \ - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(duk__thr->heap, duk__obj) == NULL); \ - DUK_HOBJECT_SET_PROTOTYPE(duk__thr->heap, duk__obj, duk__proto); \ - DUK_HOBJECT_INCREF_ALLOWNULL(duk__thr, duk__proto); \ - } while (0) - -/* - * Finalizer check - */ - -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((heap), (h)) -#else -#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((h)) -#endif - -/* - * Resizing and hash behavior - */ - -/* Sanity limit on max number of properties (allocated, not necessarily used). - * This is somewhat arbitrary, but if we're close to 2**32 properties some - * algorithms will fail (e.g. hash size selection, next prime selection). - * Also, we use negative array/entry table indices to indicate 'not found', - * so anything above 0x80000000 will cause trouble now. - */ -#if defined(DUK_USE_OBJSIZES16) -#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL -#else -#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */ -#endif - -/* internal align target for props allocation, must be 2*n for some n */ -#if (DUK_USE_ALIGN_BY == 4) -#define DUK_HOBJECT_ALIGN_TARGET 4 -#elif (DUK_USE_ALIGN_BY == 8) -#define DUK_HOBJECT_ALIGN_TARGET 8 -#elif (DUK_USE_ALIGN_BY == 1) -#define DUK_HOBJECT_ALIGN_TARGET 1 -#else -#error invalid DUK_USE_ALIGN_BY -#endif - -/* - * PC-to-line constants - */ - -#define DUK_PC2LINE_SKIP 64 - -/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */ -#define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8) - -/* - * Struct defs - */ - -struct duk_propaccessor { - duk_hobject *get; - duk_hobject *set; -}; - -union duk_propvalue { - /* The get/set pointers could be 16-bit pointer compressed but it - * would make no difference on 32-bit platforms because duk_tval is - * 8 bytes or more anyway. - */ - duk_tval v; - duk_propaccessor a; -}; - -struct duk_propdesc { - /* read-only values 'lifted' for ease of use */ - duk_small_uint_t flags; - duk_hobject *get; - duk_hobject *set; - - /* for updating (all are set to < 0 for virtual properties) */ - duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */ - duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */ - duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */ -}; - -struct duk_hobject { - duk_heaphdr hdr; - - /* - * 'props' contains {key,value,flags} entries, optional array entries, and - * an optional hash lookup table for non-array entries in a single 'sliced' - * allocation. There are several layout options, which differ slightly in - * generated code size/speed and alignment/padding; duk_features.h selects - * the layout used. - * - * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1): - * - * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) - * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) - * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable) - * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) - * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), - * 0xffffffffUL = unused, 0xfffffffeUL = deleted - * - * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2): - * - * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) - * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) - * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable) - * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) - * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), - * 0xffffffffUL = unused, 0xfffffffeUL = deleted - * - * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3): - * - * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) - * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) - * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) - * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), - * 0xffffffffUL = unused, 0xfffffffeUL = deleted - * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable) - * - * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms - * requiring 4 or 8 byte alignment. This ensures proper alignment - * for the entries, at the cost of memory footprint. However, it's - * probably preferable to use another layout on such platforms instead. - * - * In layout 2, the key and value parts are swapped to avoid padding - * the key array on platforms requiring alignment by 8. The flags part - * is padded to get alignment for array entries. The 'e_next' count does - * not need to be rounded as in layout 1. - * - * In layout 3, entry values and array values are always aligned properly, - * and assuming pointers are at most 8 bytes, so are the entry keys. Hash - * indices will be properly aligned (assuming pointers are at least 4 bytes). - * Finally, flags don't need additional alignment. This layout provides - * compact allocations without padding (even on platforms with alignment - * requirements) at the cost of a bit slower lookups. - * - * Objects with few keys don't have a hash index; keys are looked up linearly, - * which is cache efficient because the keys are consecutive. Larger objects - * have a hash index part which contains integer indexes to the entries part. - * - * A single allocation reduces memory allocation overhead but requires more - * work when any part needs to be resized. A sliced allocation for entries - * makes linear key matching faster on most platforms (more locality) and - * skimps on flags size (which would be followed by 3 bytes of padding in - * most architectures if entries were placed in a struct). - * - * 'props' also contains internal properties distinguished with a non-BMP - * prefix. Often used properties should be placed early in 'props' whenever - * possible to make accessing them as fast a possible. - */ - -#if defined(DUK_USE_HEAPPTR16) - /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like - * duk_hcompfunc) are not free to use h_extra16 for this reason. - */ -#else - duk_uint8_t *props; -#endif - - /* prototype: the only internal property lifted outside 'e' as it is so central */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t prototype16; -#else - duk_hobject *prototype; -#endif - -#if defined(DUK_USE_OBJSIZES16) - duk_uint16_t e_size16; - duk_uint16_t e_next16; - duk_uint16_t a_size16; -#if defined(DUK_USE_HOBJECT_HASH_PART) - duk_uint16_t h_size16; -#endif -#else - duk_uint32_t e_size; /* entry part size */ - duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */ - duk_uint32_t a_size; /* array part size (entirely gc reachable) */ -#if defined(DUK_USE_HOBJECT_HASH_PART) - duk_uint32_t h_size; /* hash part size or 0 if unused */ -#endif -#endif -}; - -/* - * Exposed data - */ - -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32]; -#endif /* !DUK_SINGLE_FILE */ - -/* - * Prototypes - */ - -/* alloc and init */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags); -#endif -DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags); - -/* resize */ -DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr, - duk_hobject *obj, - duk_uint32_t new_e_size, - duk_uint32_t new_a_size, - duk_uint32_t new_h_size, - duk_bool_t abandon_array); -DUK_INTERNAL_DECL void duk_hobject_resize_entrypart(duk_hthread *thr, - duk_hobject *obj, - duk_uint32_t new_e_size); -#if 0 /*unused*/ -DUK_INTERNAL_DECL void duk_hobject_resize_arraypart(duk_hthread *thr, - duk_hobject *obj, - duk_uint32_t new_a_size); -#endif - -/* low-level property functions */ -DUK_INTERNAL_DECL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx); -DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key); -DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs); -DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags); - -/* XXX: when optimizing for guaranteed property slots, use a guaranteed - * slot for internal value; this call can then access it directly. - */ -#define duk_hobject_get_internal_value_tval_ptr(heap,obj) \ - duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap))) - -/* core property functions */ -DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); - -/* internal property functions */ -#define DUK_DELPROP_FLAG_THROW (1U << 0) -#define DUK_DELPROP_FLAG_FORCE (1U << 1) -DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key); -DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); -DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags); -DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); -#if defined(DUK_USE_HEAPPTR16) -DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj); -#else -DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj); -#endif - -/* helpers for defineProperty() and defineProperties() */ -DUK_INTERNAL_DECL void duk_hobject_prepare_property_descriptor(duk_hthread *thr, - duk_idx_t idx_in, - duk_uint_t *out_defprop_flags, - duk_idx_t *out_idx_value, - duk_hobject **out_getter, - duk_hobject **out_setter); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr, - duk_uint_t defprop_flags, - duk_hobject *obj, - duk_hstring *key, - duk_idx_t idx_value, - duk_hobject *get, - duk_hobject *set, - duk_bool_t throw_flag); - -/* Object built-in methods */ -DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx); -DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags); - -/* internal properties */ -DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv); -DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj); - -/* hobject management functions */ -DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj); - -/* ES2015 proxy */ -#if defined(DUK_USE_ES6_PROXY) -DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler); -DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj); -#endif - -/* enumeration */ -DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags); -DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value); - -/* macros */ -DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); - -/* pc2line */ -#if defined(DUK_USE_PC2LINE) -DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length); -DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc); -#endif - -/* misc */ -DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop); - -#if !defined(DUK_USE_OBJECT_BUILTIN) -/* These declarations are needed when related built-in is disabled and - * genbuiltins.py won't automatically emit the declerations. - */ -DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr); -DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr); -#endif - -#endif /* DUK_HOBJECT_H_INCLUDED */ -/* #include duk_hcompfunc.h */ -#line 1 "duk_hcompfunc.h" -/* - * Heap compiled function (Ecmascript function) representation. - * - * There is a single data buffer containing the Ecmascript function's - * bytecode, constants, and inner functions. - */ - -#if !defined(DUK_HCOMPFUNC_H_INCLUDED) -#define DUK_HCOMPFUNC_H_INCLUDED - -/* - * Field accessor macros - */ - -/* XXX: casts could be improved, especially for GET/SET DATA */ - -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HCOMPFUNC_GET_DATA(heap,h) \ - ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16)) -#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \ - (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ - } while (0) -#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \ - ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16))) -#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \ - (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ - } while (0) -#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \ - ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16))) -#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \ - (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ - } while (0) -#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \ - ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16))) -#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \ - (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ - } while (0) -#define DUK_HCOMPFUNC_GET_VARENV(heap,h) \ - ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16))) -#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \ - (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ - } while (0) -#else -#define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data) -#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \ - (h)->data = (duk_hbuffer *) (v); \ - } while (0) -#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs) -#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \ - (h)->funcs = (v); \ - } while (0) -#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode) -#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \ - (h)->bytecode = (v); \ - } while (0) -#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env) -#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \ - (h)->lex_env = (v); \ - } while (0) -#define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env) -#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \ - (h)->var_env = (v); \ - } while (0) -#endif - -/* - * Accessor macros for function specific data areas - */ - -/* Note: assumes 'data' is always a fixed buffer */ -#define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \ - DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) - -#define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \ - ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h))) - -#define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \ - DUK_HCOMPFUNC_GET_FUNCS((heap), (h)) - -#define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \ - DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)) - -#define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \ - ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h))) - -#define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \ - ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))) - -/* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */ -#define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \ - ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \ - DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h)))) - -#define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \ - ( \ - (duk_size_t) \ - ( \ - ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \ - ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \ - ) \ - ) - -#define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \ - ( \ - (duk_size_t) \ - ( \ - ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \ - ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \ - ) \ - ) - -#define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \ - ( \ - (duk_size_t) \ - ( \ - ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \ - ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \ - ) \ - ) - -#define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \ - ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval))) - -#define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \ - ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *))) - -#define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \ - ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t))) - -/* - * Validity assert - */ - -#define DUK_ASSERT_HCOMPFUNC_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - } while (0) - -/* - * Main struct - */ - -struct duk_hcompfunc { - /* shared object part */ - duk_hobject obj; - - /* - * Pointers to function data area for faster access. Function - * data is a buffer shared between all closures of the same - * "template" function. The data buffer is always fixed (non- - * dynamic, hence stable), with a layout as follows: - * - * constants (duk_tval) - * inner functions (duk_hobject *) - * bytecode (duk_instr_t) - * - * Note: bytecode end address can be computed from 'data' buffer - * size. It is not strictly necessary functionally, assuming - * bytecode never jumps outside its allocated area. However, - * it's a safety/robustness feature for avoiding the chance of - * executing random data as bytecode due to a compiler error. - * - * Note: values in the data buffer must be incref'd (they will - * be decref'd on release) for every compiledfunction referring - * to the 'data' element. - */ - - /* Data area, fixed allocation, stable data ptrs. */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t data16; -#else - duk_hbuffer *data; -#endif - - /* No need for constants pointer (= same as data). - * - * When using 16-bit packing alignment to 4 is nice. 'funcs' will be - * 4-byte aligned because 'constants' are duk_tvals. For now the - * inner function pointers are not compressed, so that 'bytecode' will - * also be 4-byte aligned. - */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t funcs16; - duk_uint16_t bytecode16; -#else - duk_hobject **funcs; - duk_instr_t *bytecode; -#endif - - /* Lexenv: lexical environment of closure, NULL for templates. - * Varenv: variable environment of closure, NULL for templates. - */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t lex_env16; - duk_uint16_t var_env16; -#else - duk_hobject *lex_env; - duk_hobject *var_env; -#endif - - /* - * 'nregs' registers are allocated on function entry, at most 'nargs' - * are initialized to arguments, and the rest to undefined. Arguments - * above 'nregs' are not mapped to registers. All registers in the - * active stack range must be initialized because they are GC reachable. - * 'nargs' is needed so that if the function is given more than 'nargs' - * arguments, the additional arguments do not 'clobber' registers - * beyond 'nregs' which must be consistently initialized to undefined. - * - * Usually there is no need to know which registers are mapped to - * local variables. Registers may be allocated to variable in any - * way (even including gaps). However, a register-variable mapping - * must be the same for the duration of the function execution and - * the register cannot be used for anything else. - * - * When looking up variables by name, the '_Varmap' map is used. - * When an activation closes, registers mapped to arguments are - * copied into the environment record based on the same map. The - * reverse map (from register to variable) is not currently needed - * at run time, except for debugging, so it is not maintained. - */ - - duk_uint16_t nregs; /* regs to allocate */ - duk_uint16_t nargs; /* number of arguments allocated to regs */ - - /* - * Additional control information is placed into the object itself - * as internal properties to avoid unnecessary fields for the - * majority of functions. The compiler tries to omit internal - * control fields when possible. - * - * Function templates: - * - * { - * name: "func", // declaration, named function expressions - * fileName: - * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 }, - * _Formals: [ "arg1", "arg2" ], - * _Source: "function func(arg1, arg2) { ... }", - * _Pc2line: , - * } - * - * Function instances: - * - * { - * length: 2, - * prototype: { constructor: }, - * caller: , - * arguments: , - * name: "func", // declaration, named function expressions - * fileName: - * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 }, - * _Formals: [ "arg1", "arg2" ], - * _Source: "function func(arg1, arg2) { ... }", - * _Pc2line: , - * } - * - * More detailed description of these properties can be found - * in the documentation. - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - /* Line number range for function. Needed during debugging to - * determine active breakpoints. - */ - duk_uint32_t start_line; - duk_uint32_t end_line; -#endif -}; - -#endif /* DUK_HCOMPFUNC_H_INCLUDED */ -/* #include duk_hnatfunc.h */ -#line 1 "duk_hnatfunc.h" -/* - * Heap native function representation. - */ - -#if !defined(DUK_HNATFUNC_H_INCLUDED) -#define DUK_HNATFUNC_H_INCLUDED - -#define DUK_HNATFUNC_NARGS_VARARGS ((duk_int16_t) -1) -#define DUK_HNATFUNC_NARGS_MAX ((duk_int16_t) 0x7fff) - -struct duk_hnatfunc { - /* shared object part */ - duk_hobject obj; - - duk_c_function func; - duk_int16_t nargs; - duk_int16_t magic; - - /* The 'magic' field allows an opaque 16-bit field to be accessed by the - * Duktape/C function. This allows, for instance, the same native function - * to be used for a set of very similar functions, with the 'magic' field - * providing the necessary non-argument flags / values to guide the behavior - * of the native function. The value is signed on purpose: it is easier to - * convert a signed value to unsigned (simply AND with 0xffff) than vice - * versa. - * - * Note: cannot place nargs/magic into the heaphdr flags, because - * duk_hobject takes almost all flags already. - */ -}; - -#endif /* DUK_HNATFUNC_H_INCLUDED */ -/* #include duk_hboundfunc.h */ -#line 1 "duk_hboundfunc.h" -/* - * Bound function representation. - */ - -#if !defined(DUK_HBOUNDFUNC_H_INCLUDED) -#define DUK_HBOUNDFUNC_H_INCLUDED - -/* Artificial limit for args length. Ensures arithmetic won't overflow - * 32 bits when combining bound functions. - */ -#define DUK_HBOUNDFUNC_MAX_ARGS 0x20000000UL - -#define DUK_ASSERT_HBOUNDFUNC_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - DUK_ASSERT(DUK_HOBJECT_IS_BOUNDFUNC((duk_hobject *) (h))); \ - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&(h)->target) || \ - (DUK_TVAL_IS_OBJECT(&(h)->target) && \ - DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&(h)->target)))); \ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&(h)->this_binding)); \ - DUK_ASSERT((h)->nargs == 0 || (h)->args != NULL); \ - } while (0) - -struct duk_hboundfunc { - /* Shared object part. */ - duk_hobject obj; - - /* Final target function, stored as duk_tval so that lightfunc can be - * represented too. - */ - duk_tval target; - - /* This binding. */ - duk_tval this_binding; - - /* Arguments to prepend. */ - duk_tval *args; /* Separate allocation. */ - duk_idx_t nargs; -}; - -#endif /* DUK_HBOUNDFUNC_H_INCLUDED */ -/* #include duk_hbufobj.h */ -#line 1 "duk_hbufobj.h" -/* - * Heap Buffer object representation. Used for all Buffer variants. - */ - -#if !defined(DUK_HBUFOBJ_H_INCLUDED) -#define DUK_HBUFOBJ_H_INCLUDED - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - -/* All element accessors are host endian now (driven by TypedArray spec). */ -#define DUK_HBUFOBJ_ELEM_UINT8 0 -#define DUK_HBUFOBJ_ELEM_UINT8CLAMPED 1 -#define DUK_HBUFOBJ_ELEM_INT8 2 -#define DUK_HBUFOBJ_ELEM_UINT16 3 -#define DUK_HBUFOBJ_ELEM_INT16 4 -#define DUK_HBUFOBJ_ELEM_UINT32 5 -#define DUK_HBUFOBJ_ELEM_INT32 6 -#define DUK_HBUFOBJ_ELEM_FLOAT32 7 -#define DUK_HBUFOBJ_ELEM_FLOAT64 8 -#define DUK_HBUFOBJ_ELEM_MAX 8 - -#define DUK_ASSERT_HBUFOBJ_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - DUK_ASSERT((h)->shift <= 3); \ - DUK_ASSERT((h)->elem_type <= DUK_HBUFOBJ_ELEM_MAX); \ - DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8) || \ - ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) || \ - ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT8) || \ - ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT16) || \ - ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT16) || \ - ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT32) || \ - ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT32) || \ - ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) || \ - ((h)->shift == 3 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64)); \ - DUK_ASSERT((h)->is_typedarray == 0 || (h)->is_typedarray == 1); \ - DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) (h))); \ - if ((h)->buf == NULL) { \ - DUK_ASSERT((h)->offset == 0); \ - DUK_ASSERT((h)->length == 0); \ - } else { \ - /* No assertions for offset or length; in particular, \ - * it's OK for length to be longer than underlying \ - * buffer. Just ensure they don't wrap when added. \ - */ \ - DUK_ASSERT((h)->offset + (h)->length >= (h)->offset); \ - } \ - } while (0) - -/* Get the current data pointer (caller must ensure buf != NULL) as a - * duk_uint8_t ptr. - */ -#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \ - (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ - (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset)) - -/* True if slice is full, i.e. offset is zero and length covers the entire - * buffer. This status may change independently of the duk_hbufobj if - * the underlying buffer is dynamic and changes without the hbufobj - * being changed. - */ -#define DUK_HBUFOBJ_FULL_SLICE(h) \ - (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ - ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf))) - -/* Validate that the whole slice [0,length[ is contained in the underlying - * buffer. Caller must ensure 'buf' != NULL. - */ -#define DUK_HBUFOBJ_VALID_SLICE(h) \ - (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ - ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf))) - -/* Validate byte read/write for virtual 'offset', i.e. check that the - * offset, taking into account h->offset, is within the underlying - * buffer size. This is a safety check which is needed to ensure - * that even a misconfigured duk_hbufobj never causes memory unsafe - * behavior (e.g. if an underlying dynamic buffer changes after being - * setup). Caller must ensure 'buf' != NULL. - */ -#define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \ - (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ - ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf))) - -#define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \ - (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ - ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf))) - -/* Clamp an input byte length (already assumed to be within the nominal - * duk_hbufobj 'length') to the current dynamic buffer limits to yield - * a byte length limit that's safe for memory accesses. This value can - * be invalidated by any side effect because it may trigger a user - * callback that resizes the underlying buffer. - */ -#define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \ - (DUK_ASSERT_EXPR((h) != NULL), \ - duk_hbufobj_clamp_bytelength((h), (len))) - -/* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */ -#define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h) ((h)->is_typedarray) - -struct duk_hbufobj { - /* Shared object part. */ - duk_hobject obj; - - /* Underlying buffer (refcounted), may be NULL. */ - duk_hbuffer *buf; - - /* .buffer reference to an ArrayBuffer, may be NULL. */ - duk_hobject *buf_prop; - - /* Slice and accessor information. - * - * Because the underlying buffer may be dynamic, these may be - * invalidated by the buffer being modified so that both offset - * and length should be validated before every access. Behavior - * when the underlying buffer has changed doesn't need to be clean: - * virtual 'length' doesn't need to be affected, reads can return - * zero/NaN, and writes can be ignored. - * - * Note that a data pointer cannot be precomputed because 'buf' may - * be dynamic and its pointer unstable. - */ - - duk_uint_t offset; /* byte offset to buf */ - duk_uint_t length; /* byte index limit for element access, exclusive */ - duk_uint8_t shift; /* element size shift: - * 0 = u8/i8 - * 1 = u16/i16 - * 2 = u32/i32/float - * 3 = double - */ - duk_uint8_t elem_type; /* element type */ - duk_uint8_t is_typedarray; -}; - -DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len); -DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf); -DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); -DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); -DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx); - -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#endif /* DUK_HBUFOBJ_H_INCLUDED */ -/* #include duk_hthread.h */ -#line 1 "duk_hthread.h" -/* - * Heap thread object representation. - * - * duk_hthread is also the 'context' for public API functions via a - * different typedef. Most API calls operate on the topmost frame - * of the value stack only. - */ - -#if !defined(DUK_HTHREAD_H_INCLUDED) -#define DUK_HTHREAD_H_INCLUDED - -/* - * Stack constants - */ - -/* Initial valstack size, roughly 0.7kiB. */ -#define DUK_VALSTACK_INITIAL_SIZE 96U - -/* Internal extra elements assumed on function entry, always added to - * user-defined 'extra' for e.g. the duk_check_stack() call. - */ -#define DUK_VALSTACK_INTERNAL_EXTRA 32U - -/* Number of elements guaranteed to be user accessible (in addition to call - * arguments) on Duktape/C function entry. This is the major public API - * commitment. - */ -#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK - -/* - * Activation defines - */ - -#define DUK_ACT_FLAG_STRICT (1U << 0) /* function executes in strict mode */ -#define DUK_ACT_FLAG_TAILCALLED (1U << 1) /* activation has tail called one or more times */ -#define DUK_ACT_FLAG_CONSTRUCT (1U << 2) /* function executes as a constructor (called via "new") */ -#define DUK_ACT_FLAG_PREVENT_YIELD (1U << 3) /* activation prevents yield (native call or "new") */ -#define DUK_ACT_FLAG_DIRECT_EVAL (1U << 4) /* activation is a direct eval call */ -#define DUK_ACT_FLAG_CONSTRUCT_PROXY (1U << 5) /* activation is for Proxy 'construct' call, special return value handling */ -#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1U << 6) /* activation has active breakpoint(s) */ - -#define DUK_ACT_GET_FUNC(act) ((act)->func) - -/* - * Flags for __FILE__ / __LINE__ registered into tracedata - */ - -#define DUK_TB_FLAG_NOBLAME_FILELINE (1U << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */ - -/* - * Catcher defines - */ - -/* XXX: remove catcher type entirely */ - -/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */ -#define DUK_CAT_TYPE_MASK 0x0000000fUL -#define DUK_CAT_TYPE_BITS 4 -#define DUK_CAT_LABEL_MASK 0xffffff00UL -#define DUK_CAT_LABEL_BITS 24 -#define DUK_CAT_LABEL_SHIFT 8 - -#define DUK_CAT_FLAG_CATCH_ENABLED (1U << 4) /* catch part will catch */ -#define DUK_CAT_FLAG_FINALLY_ENABLED (1U << 5) /* finally part will catch */ -#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1U << 6) /* request to create catch binding */ -#define DUK_CAT_FLAG_LEXENV_ACTIVE (1U << 7) /* catch or with binding is currently active */ - -#define DUK_CAT_TYPE_UNKNOWN 0 -#define DUK_CAT_TYPE_TCF 1 -#define DUK_CAT_TYPE_LABEL 2 - -#define DUK_CAT_GET_TYPE(c) ((c)->flags & DUK_CAT_TYPE_MASK) -#define DUK_CAT_GET_LABEL(c) (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT) - -#define DUK_CAT_HAS_CATCH_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED) -#define DUK_CAT_HAS_FINALLY_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED) -#define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED) -#define DUK_CAT_HAS_LEXENV_ACTIVE(c) ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE) - -#define DUK_CAT_SET_CATCH_ENABLED(c) do { \ - (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \ - } while (0) -#define DUK_CAT_SET_FINALLY_ENABLED(c) do { \ - (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \ - } while (0) -#define DUK_CAT_SET_CATCH_BINDING_ENABLED(c) do { \ - (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \ - } while (0) -#define DUK_CAT_SET_LEXENV_ACTIVE(c) do { \ - (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \ - } while (0) - -#define DUK_CAT_CLEAR_CATCH_ENABLED(c) do { \ - (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \ - } while (0) -#define DUK_CAT_CLEAR_FINALLY_ENABLED(c) do { \ - (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \ - } while (0) -#define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c) do { \ - (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \ - } while (0) -#define DUK_CAT_CLEAR_LEXENV_ACTIVE(c) do { \ - (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \ - } while (0) - -/* - * Thread defines - */ - -#if defined(DUK_USE_ROM_STRINGS) -#define DUK_HTHREAD_GET_STRING(thr,idx) \ - ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)])) -#else /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HTHREAD_GET_STRING(thr,idx) \ - ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)])) -#else -#define DUK_HTHREAD_GET_STRING(thr,idx) \ - ((thr)->strs[(idx)]) -#endif -#endif /* DUK_USE_ROM_STRINGS */ - -/* values for the state field */ -#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */ -#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */ -#define DUK_HTHREAD_STATE_RESUMED 3 /* thread resumed another thread (active but not running) */ -#define DUK_HTHREAD_STATE_YIELDED 4 /* thread has yielded */ -#define DUK_HTHREAD_STATE_TERMINATED 5 /* thread has terminated */ - -/* Executor interrupt default interval when nothing else requires a - * smaller value. The default interval must be small enough to allow - * for reasonable execution timeout checking but large enough to keep - * impact on execution performance low. - */ -#if defined(DUK_USE_INTERRUPT_COUNTER) -#define DUK_HTHREAD_INTCTR_DEFAULT (256L * 1024L) -#endif - -/* - * Assert context is valid: non-NULL pointer, fields look sane. - * - * This is used by public API call entrypoints to catch invalid 'ctx' pointers - * as early as possible; invalid 'ctx' pointers cause very odd and difficult to - * diagnose behavior so it's worth checking even when the check is not 100%. - */ - -/* Assertions for internals. */ -#define DUK_ASSERT_HTHREAD_VALID(thr) do { \ - DUK_ASSERT((thr) != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (thr)) == DUK_HTYPE_OBJECT); \ - DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (thr))); \ - DUK_ASSERT((thr)->unused1 == 0); \ - DUK_ASSERT((thr)->unused2 == 0); \ - } while (0) - -/* Assertions for public API calls; a bit stronger. */ -#define DUK_ASSERT_CTX_VALID(thr) do { \ - DUK_ASSERT((thr) != NULL); \ - DUK_ASSERT_HTHREAD_VALID((thr)); \ - DUK_ASSERT((thr)->valstack != NULL); \ - DUK_ASSERT((thr)->valstack_bottom != NULL); \ - DUK_ASSERT((thr)->valstack_top != NULL); \ - DUK_ASSERT((thr)->valstack_end != NULL); \ - DUK_ASSERT((thr)->valstack_alloc_end != NULL); \ - DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack); \ - DUK_ASSERT((thr)->valstack_end >= (thr)->valstack); \ - DUK_ASSERT((thr)->valstack_top >= (thr)->valstack); \ - DUK_ASSERT((thr)->valstack_top >= (thr)->valstack_bottom); \ - DUK_ASSERT((thr)->valstack_end >= (thr)->valstack_top); \ - DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack_end); \ - } while (0) - -/* Assertions for API call entry specifically. Checks 'ctx' but also may - * check internal state (e.g. not in a debugger transport callback). - */ -#define DUK_ASSERT_API_ENTRY(thr) do { \ - DUK_ASSERT_CTX_VALID((thr)); \ - DUK_ASSERT((thr)->heap != NULL); \ - DUK_ASSERT((thr)->heap->dbg_calling_transport == 0); \ - } while (0) - -/* - * Assertion helpers. - */ - -#define DUK_ASSERT_STRIDX_VALID(val) \ - DUK_ASSERT((duk_uint_t) (val) < DUK_HEAP_NUM_STRINGS) - -#define DUK_ASSERT_BIDX_VALID(val) \ - DUK_ASSERT((duk_uint_t) (val) < DUK_NUM_BUILTINS) - -/* - * Misc - */ - -/* Fast access to 'this' binding. Assumes there's a call in progress. */ -#define DUK_HTHREAD_THIS_PTR(thr) \ - (DUK_ASSERT_EXPR((thr) != NULL), \ - DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \ - (thr)->valstack_bottom - 1) - -/* - * Struct defines - */ - -/* Fields are ordered for alignment/packing. */ -struct duk_activation { - duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */ - duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */ - duk_activation *parent; /* previous (parent) activation (or NULL if none) */ - duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */ - duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */ - duk_catcher *cat; /* current catcher (or NULL) */ - -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - /* Previous value of 'func' caller, restored when unwound. Only in use - * when 'func' is non-strict. - */ - duk_hobject *prev_caller; -#endif - - duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */ - - /* bottom_byteoff and retval_byteoff are only used for book-keeping - * of Ecmascript-initiated calls, to allow returning to an Ecmascript - * function properly. - */ - - /* Bottom of valstack for this activation, used to reset - * valstack_bottom on return; offset is absolute. There's - * no need to track 'top' because native call handling deals - * with that using locals, and for Ecmascript returns 'nregs' - * indicates the necessary top. - */ - duk_size_t bottom_byteoff; - - /* Return value when returning to this activation (points to caller - * reg, not callee reg); offset is absolute (only set if activation is - * not topmost). - * - * Note: bottom_byteoff is always set, while retval_byteoff is only - * applicable for activations below the topmost one. Currently - * retval_byteoff for the topmost activation is considered garbage - * (and it not initialized on entry or cleared on return; may contain - * previous or garbage values). - */ - duk_size_t retval_byteoff; - - /* Current 'this' binding is the value just below bottom. - * Previously, 'this' binding was handled with an index to the - * (calling) valstack. This works for everything except tail - * calls, which must not "accumulate" valstack temps. - */ - - /* Value stack reserve (valstack_end) byte offset to be restored - * when returning to this activation. Only used by the bytecode - * executor. - */ - duk_size_t reserve_byteoff; - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_uint32_t prev_line; /* needed for stepping */ -#endif - - duk_small_uint_t flags; -}; - -struct duk_catcher { - duk_catcher *parent; /* previous (parent) catcher (or NULL if none) */ - duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */ - /* (reference is valid as long activation exists) */ - duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */ - duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */ - duk_uint32_t flags; /* type and control flags, label number */ - /* XXX: could pack 'flags' and 'idx_base' to same value in practice, - * on 32-bit targets this would make duk_catcher 16 bytes. - */ -}; - -struct duk_hthread { - /* Shared object part */ - duk_hobject obj; - - /* Pointer to bytecode executor's 'curr_pc' variable. Used to copy - * the current PC back into the topmost activation when activation - * state is about to change (or "syncing" is otherwise needed). This - * is rather awkward but important for performance, see execution.rst. - */ - duk_instr_t **ptr_curr_pc; - - /* Backpointers. */ - duk_heap *heap; - - /* Current strictness flag: affects API calls. */ - duk_uint8_t strict; - - /* Thread state. */ - duk_uint8_t state; - duk_uint8_t unused1; - duk_uint8_t unused2; - - /* XXX: Valstack and callstack are currently assumed to have non-NULL - * pointers. Relaxing this would not lead to big benefits (except - * perhaps for terminated threads). - */ - - /* Value stack: these are expressed as pointers for faster stack - * manipulation. [valstack,valstack_top[ is GC-reachable, - * [valstack_top,valstack_alloc_end[ is not GC-reachable but kept - * initialized as 'undefined'. [valstack,valstack_end[ is the - * guaranteed/reserved space and the valstack cannot be resized to - * a smaller size. [valstack_end,valstack_alloc_end[ is currently - * allocated slack that can be used to grow the current guaranteed - * space but may be shrunk away without notice. - * - * - * <----------------------- guaranteed ---> - * <---- slack ---> - * <--- frame ---> - * .-------------+=============+----------+--------------. - * |xxxxxxxxxxxxx|yyyyyyyyyyyyy|uuuuuuuuuu|uuuuuuuuuuuuuu| - * `-------------+=============+----------+--------------' - * - * ^ ^ ^ ^ ^ - * | | | | | - * valstack bottom top end alloc_end - * - * xxx = arbitrary values, below current frame - * yyy = arbitrary values, inside current frame - * uuu = outside active value stack, initialized to 'undefined' - */ - duk_tval *valstack; /* start of valstack allocation */ - duk_tval *valstack_end; /* end of valstack reservation/guarantee (exclusive) */ - duk_tval *valstack_alloc_end; /* end of valstack allocation */ - duk_tval *valstack_bottom; /* bottom of current frame */ - duk_tval *valstack_top; /* top of current frame (exclusive) */ - - /* Call stack, represented as a linked list starting from the current - * activation (or NULL if nothing is active). - */ - duk_activation *callstack_curr; /* current activation (or NULL if none) */ - duk_size_t callstack_top; /* number of activation records in callstack (0 if none) */ - duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */ - - /* Yield/resume book-keeping. */ - duk_hthread *resumer; /* who resumed us (if any) */ - - /* Current compiler state (if any), used for augmenting SyntaxErrors. */ - duk_compiler_ctx *compile_ctx; - -#if defined(DUK_USE_INTERRUPT_COUNTER) - /* Interrupt counter for triggering a slow path check for execution - * timeout, debugger interaction such as breakpoints, etc. The value - * is valid for the current running thread, and both the init and - * counter values are copied whenever a thread switch occurs. It's - * important for the counter to be conveniently accessible for the - * bytecode executor inner loop for performance reasons. - */ - duk_int_t interrupt_counter; /* countdown state */ - duk_int_t interrupt_init; /* start value for current countdown */ -#endif - - /* Builtin-objects; may or may not be shared with other threads, - * threads existing in different "compartments" will have different - * built-ins. Must be stored on a per-thread basis because there - * is no intermediate structure for a thread group / compartment. - * This takes quite a lot of space, currently 43x4 = 172 bytes on - * 32-bit platforms. - * - * In some cases the builtins array could be ROM based, but it's - * sometimes edited (e.g. for sandboxing) so it's better to keep - * this array in RAM. - */ - duk_hobject *builtins[DUK_NUM_BUILTINS]; - - /* Convenience copies from heap/vm for faster access. */ -#if defined(DUK_USE_ROM_STRINGS) - /* No field needed when strings are in ROM. */ -#else -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *strs16; -#else - duk_hstring **strs; -#endif -#endif -}; - -/* - * Prototypes - */ - -DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to); -DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr); -DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr); -DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr); - -DUK_INTERNAL_DECL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act); -DUK_INTERNAL_DECL void duk_hthread_activation_unwind_norz(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr); -DUK_INTERNAL_DECL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level); - -DUK_INTERNAL_DECL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat); -DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act); -DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act); - -#if defined(DUK_USE_FINALIZER_TORTURE) -DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr); -#endif - -DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act); -#endif -DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act); -DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr); - -#endif /* DUK_HTHREAD_H_INCLUDED */ -/* #include duk_harray.h */ -#line 1 "duk_harray.h" -/* - * Array object representation, used for actual Array instances. - * - * All objects with the exotic array behavior (which must coincide with having - * internal class array) MUST be duk_harrays. No other object can be a - * duk_harray. However, duk_harrays may not always have an array part. - */ - -#if !defined(DUK_HARRAY_H_INCLUDED) -#define DUK_HARRAY_H_INCLUDED - -#define DUK_ASSERT_HARRAY_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) (h))); \ - DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) (h))); \ - } while (0) - -#define DUK_HARRAY_LENGTH_WRITABLE(h) (!(h)->length_nonwritable) -#define DUK_HARRAY_LENGTH_NONWRITABLE(h) ((h)->length_nonwritable) -#define DUK_HARRAY_SET_LENGTH_WRITABLE(h) do { (h)->length_nonwritable = 0; } while (0) -#define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h) do { (h)->length_nonwritable = 1; } while (0) - -struct duk_harray { - /* Shared object part. */ - duk_hobject obj; - - /* Array .length. - * - * At present Array .length may be smaller, equal, or even larger - * than the allocated underlying array part. Fast path code must - * always take this into account carefully. - */ - duk_uint32_t length; - - /* Array .length property attributes. The property is always - * non-enumerable and non-configurable. It's initially writable - * but per Object.defineProperty() rules it can be made non-writable - * even if it is non-configurable. Thus we need to track the - * writability explicitly. - * - * XXX: this field to be eliminated and moved into duk_hobject - * flags field to save space. - */ - duk_bool_t length_nonwritable; -}; - -#endif /* DUK_HARRAY_H_INCLUDED */ -/* #include duk_henv.h */ -#line 1 "duk_henv.h" -/* - * Environment object representation. - */ - -#if !defined(DUK_HENV_H_INCLUDED) -#define DUK_HENV_H_INCLUDED - -#define DUK_ASSERT_HDECENV_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) (h))); \ - DUK_ASSERT((h)->thread == NULL || (h)->varmap != NULL); \ - } while (0) - -#define DUK_ASSERT_HOBJENV_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - DUK_ASSERT(DUK_HOBJECT_IS_OBJENV((duk_hobject *) (h))); \ - DUK_ASSERT((h)->target != NULL); \ - DUK_ASSERT((h)->has_this == 0 || (h)->has_this == 1); \ - } while (0) - -struct duk_hdecenv { - /* Shared object part. */ - duk_hobject obj; - - /* These control variables provide enough information to access live - * variables for a closure that is still open. If thread == NULL, - * the record is closed and the identifiers are in the property table. - */ - duk_hthread *thread; - duk_hobject *varmap; - duk_size_t regbase_byteoff; -}; - -struct duk_hobjenv { - /* Shared object part. */ - duk_hobject obj; - - /* Target object and 'this' binding for object binding. */ - duk_hobject *target; - - /* The 'target' object is used as a this binding in only some object - * environments. For example, the global environment does not provide - * a this binding, but a with statement does. - */ - duk_bool_t has_this; -}; - -#endif /* DUK_HENV_H_INCLUDED */ -/* #include duk_hbuffer.h */ -#line 1 "duk_hbuffer.h" -/* - * Heap buffer representation. - * - * Heap allocated user data buffer which is either: - * - * 1. A fixed size buffer (data follows header statically) - * 2. A dynamic size buffer (data pointer follows header) - * - * The data pointer for a variable size buffer of zero size may be NULL. - */ - -#if !defined(DUK_HBUFFER_H_INCLUDED) -#define DUK_HBUFFER_H_INCLUDED - -/* - * Flags - * - * Fixed buffer: 0 - * Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC - * External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL - */ - -#define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */ -#define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */ - -#define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) -#define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) - -#define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) -#define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) - -#define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) -#define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) - -/* - * Misc defines - */ - -/* Impose a maximum buffer length for now. Restricted artificially to - * ensure resize computations or adding a heap header length won't - * overflow size_t and that a signed duk_int_t can hold a buffer - * length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN. - */ - -#if defined(DUK_USE_BUFLEN16) -#define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL) -#else -/* Intentionally not 0x7fffffffUL; at least JSON code expects that - * 2*len + 2 fits in 32 bits. - */ -#define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL) -#endif - -/* - * Field access - */ - -#if defined(DUK_USE_BUFLEN16) -/* size stored in duk_heaphdr unused flag bits */ -#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16) -#define DUK_HBUFFER_SET_SIZE(x,v) do { \ - duk_size_t duk__v; \ - duk__v = (v); \ - DUK_ASSERT(duk__v <= 0xffffUL); \ - (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \ - } while (0) -#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \ - (x)->hdr.h_flags += ((dv) << 16); \ - } while (0) -#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \ - (x)->hdr.h_flags -= ((dv) << 16); \ - } while (0) -#else -#define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size) -#define DUK_HBUFFER_SET_SIZE(x,v) do { \ - ((duk_hbuffer *) (x))->size = (v); \ - } while (0) -#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \ - (x)->size += (dv); \ - } while (0) -#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \ - (x)->size -= (dv); \ - } while (0) -#endif - -#define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) -#define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x)) - -#define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) -#define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v)) -#define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv)) -#define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv)) - -#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) -#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v)) - -#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1)) - -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \ - ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16)) -#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \ - ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ - } while (0) -#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \ - ((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \ - } while (0) -#else -#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc) -#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \ - (x)->curr_alloc = (void *) (v); \ - } while (0) -#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \ - (x)->curr_alloc = (void *) NULL; \ - } while (0) -#endif - -/* No pointer compression because pointer is potentially outside of - * Duktape heap. - */ -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \ - ((void *) (x)->curr_alloc) -#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \ - (x)->curr_alloc = (void *) (v); \ - } while (0) -#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \ - (x)->curr_alloc = (void *) NULL; \ - } while (0) -#else -#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \ - ((void *) (x)->curr_alloc) -#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \ - (x)->curr_alloc = (void *) (v); \ - } while (0) -#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \ - (x)->curr_alloc = (void *) NULL; \ - } while (0) -#endif - -/* Get a pointer to the current buffer contents (matching current allocation - * size). May be NULL for zero size dynamic/external buffer. - */ -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \ - DUK_HBUFFER_HAS_DYNAMIC((x)) ? \ - ( \ - DUK_HBUFFER_HAS_EXTERNAL((x)) ? \ - DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \ - DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \ - ) : \ - DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \ - ) -#else -/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external - * have the same layout so checking for fixed vs. dynamic (or external) is enough. - */ -#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \ - DUK_HBUFFER_HAS_DYNAMIC((x)) ? \ - DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \ - DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \ - ) -#endif - -/* - * Structs - */ - -/* Shared prefix for all buffer types. */ -struct duk_hbuffer { - duk_heaphdr hdr; - - /* It's not strictly necessary to track the current size, but - * it is useful for writing robust native code. - */ - - /* Current size. */ -#if defined(DUK_USE_BUFLEN16) - /* Stored in duk_heaphdr unused flags. */ -#else - duk_size_t size; -#endif - - /* - * Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC - * flag. - * - * If the flag is clear (the buffer is a fixed size one), the buffer - * data follows the header directly, consisting of 'size' bytes. - * - * If the flag is set, the actual buffer is allocated separately, and - * a few control fields follow the header. Specifically: - * - * - a "void *" pointing to the current allocation - * - a duk_size_t indicating the full allocated size (always >= 'size') - * - * If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated - * by user code, so that Duktape won't be able to resize it and won't - * free it. This allows buffers to point to e.g. an externally - * allocated structure such as a frame buffer. - * - * Unlike strings, no terminator byte (NUL) is guaranteed after the - * data. This would be convenient, but would pad aligned user buffers - * unnecessarily upwards in size. For instance, if user code requested - * a 64-byte dynamic buffer, 65 bytes would actually be allocated which - * would then potentially round upwards to perhaps 68 or 72 bytes. - */ -}; - -/* Fixed buffer; data follows struct, with proper alignment guaranteed by - * struct size. - */ -#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA) -#pragma pack(push, 8) -#endif -struct duk_hbuffer_fixed { - /* A union is used here as a portable struct size / alignment trick: - * by adding a 32-bit or a 64-bit (unused) union member, the size of - * the struct is effectively forced to be a multiple of 4 or 8 bytes - * (respectively) without increasing the size of the struct unless - * necessary. - */ - union { - struct { - duk_heaphdr hdr; -#if defined(DUK_USE_BUFLEN16) - /* Stored in duk_heaphdr unused flags. */ -#else - duk_size_t size; -#endif - } s; -#if (DUK_USE_ALIGN_BY == 4) - duk_uint32_t dummy_for_align4; -#elif (DUK_USE_ALIGN_BY == 8) - duk_double_t dummy_for_align8; -#elif (DUK_USE_ALIGN_BY == 1) - /* no extra padding */ -#else -#error invalid DUK_USE_ALIGN_BY -#endif - } u; - - /* - * Data follows the struct header. The struct size is padded by the - * compiler based on the struct members. This guarantees that the - * buffer data will be aligned-by-4 but not necessarily aligned-by-8. - * - * On platforms where alignment does not matter, the struct padding - * could be removed (if there is any). On platforms where alignment - * by 8 is required, the struct size must be forced to be a multiple - * of 8 by some means. Without it, some user code may break, and also - * Duktape itself breaks (e.g. the compiler stores duk_tvals in a - * dynamic buffer). - */ -} -#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR) -__attribute__ ((aligned (8))) -#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR) -__attribute__ ((aligned (8))) -#endif -; -#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA) -#pragma pack(pop) -#endif - -/* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using - * heap allocation primitives. Also used for external buffers when low memory - * options are not used. - */ -struct duk_hbuffer_dynamic { - duk_heaphdr hdr; - -#if defined(DUK_USE_BUFLEN16) - /* Stored in duk_heaphdr unused flags. */ -#else - duk_size_t size; -#endif - -#if defined(DUK_USE_HEAPPTR16) - /* Stored in duk_heaphdr h_extra16. */ -#else - void *curr_alloc; /* may be NULL if alloc_size == 0 */ -#endif - - /* - * Allocation size for 'curr_alloc' is alloc_size. There is no - * automatic NUL terminator for buffers (see above for rationale). - * - * 'curr_alloc' is explicitly allocated with heap allocation - * primitives and will thus always have alignment suitable for - * e.g. duk_tval and an IEEE double. - */ -}; - -/* External buffer with 'curr_alloc' managed by user code and pointing to an - * arbitrary address. When heap pointer compression is not used, this struct - * has the same layout as duk_hbuffer_dynamic. - */ -struct duk_hbuffer_external { - duk_heaphdr hdr; - -#if defined(DUK_USE_BUFLEN16) - /* Stored in duk_heaphdr unused flags. */ -#else - duk_size_t size; -#endif - - /* Cannot be compressed as a heap pointer because may point to - * an arbitrary address. - */ - void *curr_alloc; /* may be NULL if alloc_size == 0 */ -}; - -/* - * Prototypes - */ - -DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata); -DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */ - -/* dynamic buffer ops */ -DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size); -DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf); - -#endif /* DUK_HBUFFER_H_INCLUDED */ -/* #include duk_hproxy.h */ -#line 1 "duk_hproxy.h" -/* - * Proxy object representation. - */ - -#if !defined(DUK_HPROXY_H_INCLUDED) -#define DUK_HPROXY_H_INCLUDED - -#define DUK_ASSERT_HPROXY_VALID(h) do { \ - DUK_ASSERT((h) != NULL); \ - DUK_ASSERT((h)->target != NULL); \ - DUK_ASSERT((h)->handler != NULL); \ - DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((duk_hobject *) (h))); \ - } while (0) - -struct duk_hproxy { - /* Shared object part. */ - duk_hobject obj; - - /* Proxy target object. */ - duk_hobject *target; - - /* Proxy handlers (traps). */ - duk_hobject *handler; -}; - -#endif /* DUK_HPROXY_H_INCLUDED */ -/* #include duk_heap.h */ -#line 1 "duk_heap.h" -/* - * Heap structure. - * - * Heap contains allocated heap objects, interned strings, and built-in - * strings for one or more threads. - */ - -#if !defined(DUK_HEAP_H_INCLUDED) -#define DUK_HEAP_H_INCLUDED - -/* alloc function typedefs in duktape.h */ - -/* - * Heap flags - */ - -#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1U << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ -#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1U << 1) /* executor interrupt running (used to avoid nested interrupts) */ -#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1U << 2) /* heap destruction ongoing, finalizer rescue no longer possible */ -#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1U << 3) /* debugger is paused: talk with debug client until step/resume */ - -#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits)) -#define DUK__HEAP_SET_FLAGS(heap,bits) do { \ - (heap)->flags |= (bits); \ - } while (0) -#define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \ - (heap)->flags &= ~(bits); \ - } while (0) - -#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) -#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) -#define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) - -#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) -#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) -#define DUK_HEAP_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) - -#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) -#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) -#define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) - -/* - * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally') - */ - -#define DUK_LJ_TYPE_UNKNOWN 0 /* unused */ -#define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */ -#define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */ -#define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */ -#define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */ -#define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */ -#define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */ -#define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */ - -/* - * Mark-and-sweep flags - * - * These are separate from heap level flags now but could be merged. - * The heap structure only contains a 'base mark-and-sweep flags' - * field and the GC caller can impose further flags. - */ - -/* Emergency mark-and-sweep: try extra hard, even at the cost of - * performance. - */ -#define DUK_MS_FLAG_EMERGENCY (1U << 0) - -/* Voluntary mark-and-sweep: triggered periodically. */ -#define DUK_MS_FLAG_VOLUNTARY (1U << 1) - -/* Postpone rescue decisions for reachable objects with FINALIZED set. - * Used during finalize_list processing to avoid incorrect rescue - * decisions due to finalize_list being a reachability root. - */ -#define DUK_MS_FLAG_POSTPONE_RESCUE (1U << 2) - -/* Don't compact objects; needed during object property table resize - * to prevent a recursive resize. It would suffice to protect only the - * current object being resized, but this is not yet implemented. - */ -#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1U << 3) - -/* - * Thread switching - * - * To switch heap->curr_thread, use the macro below so that interrupt counters - * get updated correctly. The macro allows a NULL target thread because that - * happens e.g. in call handling. - */ - -#if defined(DUK_USE_INTERRUPT_COUNTER) -#define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr)) -#else -#define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \ - (heap)->curr_thread = (newthr); \ - } while (0) -#endif - -/* - * Stats - */ - -#if defined(DUK_USE_DEBUG) -#define DUK_STATS_INC(heap,fieldname) do { \ - (heap)->fieldname += 1; \ - } while (0) -#else -#define DUK_STATS_INC(heap,fieldname) do {} while (0) -#endif - -/* - * Other heap related defines - */ - -/* Mark-and-sweep interval is relative to combined count of objects and - * strings kept in the heap during the latest mark-and-sweep pass. - * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is - * decreased by each (re)allocation attempt (regardless of size), and each - * refzero processed object. - * - * 'SKIP' indicates how many (re)allocations to wait until a retry if - * GC is skipped because there is no thread do it with yet (happens - * only during init phases). - */ -#if defined(DUK_USE_REFERENCE_COUNTING) -#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */ -#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L -#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L -#else -#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */ -#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L -#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L -#endif - -/* GC torture. */ -#if defined(DUK_USE_GC_TORTURE) -#define DUK_GC_TORTURE(heap) do { duk_heap_mark_and_sweep((heap), 0); } while (0) -#else -#define DUK_GC_TORTURE(heap) do { } while (0) -#endif - -/* Stringcache is used for speeding up char-offset-to-byte-offset - * translations for non-ASCII strings. - */ -#define DUK_HEAP_STRCACHE_SIZE 4 -#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */ - -/* Some list management macros. */ -#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap), (hdr)) -#if defined(DUK_USE_REFERENCE_COUNTING) -#define DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap,hdr) duk_heap_remove_from_heap_allocated((heap), (hdr)) -#endif -#if defined(DUK_USE_FINALIZER_SUPPORT) -#define DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap,hdr) duk_heap_insert_into_finalize_list((heap), (hdr)) -#define DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap,hdr) duk_heap_remove_from_finalize_list((heap), (hdr)) -#endif - -/* - * Built-in strings - */ - -/* heap string indices are autogenerated in duk_strings.h */ -#if defined(DUK_USE_ROM_STRINGS) -#define DUK_HEAP_GET_STRING(heap,idx) \ - ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)])) -#else /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_HEAPPTR16) -#define DUK_HEAP_GET_STRING(heap,idx) \ - ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)])) -#else -#define DUK_HEAP_GET_STRING(heap,idx) \ - ((heap)->strs[(idx)]) -#endif -#endif /* DUK_USE_ROM_STRINGS */ - -/* - * Raw memory calls: relative to heap, but no GC interaction - */ - -#define DUK_ALLOC_RAW(heap,size) \ - ((heap)->alloc_func((heap)->heap_udata, (size))) - -#define DUK_REALLOC_RAW(heap,ptr,newsize) \ - ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize))) - -#define DUK_FREE_RAW(heap,ptr) \ - ((heap)->free_func((heap)->heap_udata, (void *) (ptr))) - -/* - * Memory calls: relative to heap, GC interaction, but no error throwing. - * - * XXX: Currently a mark-and-sweep triggered by memory allocation will run - * using the heap->heap_thread. This thread is also used for running - * mark-and-sweep finalization; this is not ideal because it breaks the - * isolation between multiple global environments. - * - * Notes: - * - * - DUK_FREE() is required to ignore NULL and any other possible return - * value of a zero-sized alloc/realloc (same as ANSI C free()). - * - * - There is no DUK_REALLOC_ZEROED because we don't assume to know the - * old size. Caller must zero the reallocated memory. - * - * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered - * by an allocation failure might invalidate the original 'ptr', thus - * causing a realloc retry to use an invalid pointer. Example: we're - * reallocating the value stack and a finalizer resizes the same value - * stack during mark-and-sweep. The indirect variant requests for the - * current location of the pointer being reallocated using a callback - * right before every realloc attempt; this circuitous approach is used - * to avoid strict aliasing issues in a more straightforward indirect - * pointer (void **) approach. Note: the pointer in the storage - * location is read but is NOT updated; the caller must do that. - */ - -/* callback for indirect reallocs, request for current pointer */ -typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud); - -#define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size)) -#define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size)) -#define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize)) -#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize)) -#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) - -/* - * Checked allocation, relative to a thread - * - * DUK_FREE_CHECKED() doesn't actually throw, but accepts a 'thr' argument - * for convenience. - */ - -#define DUK_ALLOC_CHECKED(thr,size) duk_heap_mem_alloc_checked((thr), (size)) -#define DUK_ALLOC_CHECKED_ZEROED(thr,size) duk_heap_mem_alloc_checked_zeroed((thr), (size)) -#define DUK_FREE_CHECKED(thr,ptr) duk_heap_mem_free((thr)->heap, (ptr)) - -/* - * Memory constants - */ - -#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 10 /* Retry allocation after mark-and-sweep for this - * many times. A single mark-and-sweep round is - * not guaranteed to free all unreferenced memory - * because of finalization (in fact, ANY number of - * rounds is strictly not enough). - */ - -#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode - * for mark-and-sweep. - */ - -/* - * Debugger support - */ - -/* Maximum number of breakpoints. Only breakpoints that are set are - * consulted so increasing this has no performance impact. - */ -#define DUK_HEAP_MAX_BREAKPOINTS 16 - -/* Opcode interval for a Date-based status/peek rate limit check. Only - * relevant when debugger is attached. Requesting a timestamp may be a - * slow operation on some platforms so this shouldn't be too low. On the - * other hand a high value makes Duktape react to a pause request slowly. - */ -#define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000 - -/* Milliseconds between status notify and transport peeks. */ -#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200 - -/* Debugger pause flags. */ -#define DUK_PAUSE_FLAG_ONE_OPCODE (1U << 0) /* pause when a single opcode has been executed */ -#define DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE (1U << 1) /* one opcode pause actually active; artifact of current implementation */ -#define DUK_PAUSE_FLAG_LINE_CHANGE (1U << 2) /* pause when current line number changes */ -#define DUK_PAUSE_FLAG_FUNC_ENTRY (1U << 3) /* pause when entering a function */ -#define DUK_PAUSE_FLAG_FUNC_EXIT (1U << 4) /* pause when exiting current function */ -#define DUK_PAUSE_FLAG_CAUGHT_ERROR (1U << 5) /* pause when about to throw an error that is caught */ -#define DUK_PAUSE_FLAG_UNCAUGHT_ERROR (1U << 6) /* pause when about to throw an error that won't be caught */ - -struct duk_breakpoint { - duk_hstring *filename; - duk_uint32_t line; -}; - -/* - * String cache should ideally be at duk_hthread level, but that would - * cause string finalization to slow down relative to the number of - * threads; string finalization must check the string cache for "weak" - * references to the string being finalized to avoid dead pointers. - * - * Thus, string caches are now at the heap level now. - */ - -struct duk_strcache { - duk_hstring *h; - duk_uint32_t bidx; - duk_uint32_t cidx; -}; - -/* - * Longjmp state, contains the information needed to perform a longjmp. - * Longjmp related values are written to value1, value2, and iserror. - */ - -struct duk_ljstate { - duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */ - duk_small_uint_t type; /* longjmp type */ - duk_bool_t iserror; /* isError flag for yield */ - duk_tval value1; /* 1st related value (type specific) */ - duk_tval value2; /* 2nd related value (type specific) */ -}; - -#define DUK_ASSERT_LJSTATE_UNSET(heap) do { \ - DUK_ASSERT(heap != NULL); \ - DUK_ASSERT(heap->lj.type == DUK_LJ_TYPE_UNKNOWN); \ - DUK_ASSERT(heap->lj.iserror == 0); \ - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value1)); \ - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value2)); \ - } while (0) -#define DUK_ASSERT_LJSTATE_SET(heap) do { \ - DUK_ASSERT(heap != NULL); \ - DUK_ASSERT(heap->lj.type != DUK_LJ_TYPE_UNKNOWN); \ - } while (0) - -/* - * Main heap structure - */ - -struct duk_heap { - duk_small_uint_t flags; - - /* Allocator functions. */ - duk_alloc_function alloc_func; - duk_realloc_function realloc_func; - duk_free_function free_func; - - /* Heap udata, used for allocator functions but also for other heap - * level callbacks like fatal function, pointer compression, etc. - */ - void *heap_udata; - - /* Fatal error handling, called e.g. when a longjmp() is needed but - * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not - * declared as "noreturn" because doing that for typedefs is a bit - * challenging portability-wise. - */ - duk_fatal_function fatal_func; - - /* Main list of allocated heap objects. Objects are either here, - * in finalize_list waiting for processing, or in refzero_list - * temporarily while a DECREF refzero cascade finishes. - */ - duk_heaphdr *heap_allocated; - - /* Temporary work list for freeing a cascade of objects when a DECREF - * (or DECREF_NORZ) encounters a zero refcount. Using a work list - * allows fixed C stack size when refcounts go to zero for a chain of - * objects. Outside of DECREF this is always a NULL because DECREF is - * processed without side effects (only memory free calls). - */ -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_heaphdr *refzero_list; -#endif - -#if defined(DUK_USE_FINALIZER_SUPPORT) - /* Work list for objects to be finalized. */ - duk_heaphdr *finalize_list; -#if defined(DUK_USE_ASSERTIONS) - /* Object whose finalizer is executing right now (no nesting). */ - duk_heaphdr *currently_finalizing; -#endif -#endif - - /* Freelist for duk_activations and duk_catchers. */ -#if defined(DUK_USE_CACHE_ACTIVATION) - duk_activation *activation_free; -#endif -#if defined(DUK_USE_CACHE_CATCHER) - duk_catcher *catcher_free; -#endif - - /* Voluntary mark-and-sweep trigger counter. Intentionally signed - * because we continue decreasing the value when voluntary GC cannot - * run. - */ -#if defined(DUK_USE_VOLUNTARY_GC) - duk_int_t ms_trigger_counter; -#endif - - /* Mark-and-sweep recursion control: too deep recursion causes - * multi-pass processing to avoid growing C stack without bound. - */ - duk_uint_t ms_recursion_depth; - - /* Mark-and-sweep flags automatically active (used for critical sections). */ - duk_small_uint_t ms_base_flags; - - /* Mark-and-sweep running flag. Prevents re-entry, and also causes - * refzero events to be ignored (= objects won't be queued to refzero_list). - */ - duk_uint_t ms_running; - - /* Mark-and-sweep prevent count, stacking. Used to avoid M&S side - * effects (besides finalizers which are controlled separately) such - * as compacting the string table or object property tables. This - * is also bumped when ms_running is set to prevent recursive re-entry. - * Can also be bumped when mark-and-sweep is not running. - */ - duk_uint_t ms_prevent_count; - - /* Finalizer processing prevent count, stacking. Bumped when finalizers - * are processed to prevent recursive finalizer processing (first call site - * processing finalizers handles all finalizers until the list is empty). - * Can also be bumped explicitly to prevent finalizer execution. - */ - duk_uint_t pf_prevent_count; - - /* When processing finalize_list, don't actually run finalizers but - * queue finalizable objects back to heap_allocated as is. This is - * used during heap destruction to deal with finalizers that keep - * on creating more finalizable garbage. - */ - duk_uint_t pf_skip_finalizers; - -#if defined(DUK_USE_ASSERTIONS) - /* Set when we're in a critical path where an error throw would cause - * e.g. sandboxing/protected call violations or state corruption. This - * is just used for asserts. - */ - duk_bool_t error_not_allowed; -#endif - -#if defined(DUK_USE_ASSERTIONS) - /* Set when heap is still being initialized, helps with writing - * some assertions. - */ - duk_bool_t heap_initializing; -#endif - - /* Marker for detecting internal "double faults", errors thrown when - * we're trying to create an error object, see duk_error_throw.c. - */ - duk_bool_t creating_error; - - /* Marker for indicating we're calling a user error augmentation - * (errCreate/errThrow) function. Errors created/thrown during - * such a call are not augmented. - */ -#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE) - duk_bool_t augmenting_error; -#endif - - /* Longjmp state. */ - duk_ljstate lj; - - /* Heap thread, used internally and for finalization. */ - duk_hthread *heap_thread; - - /* Current running thread. */ - duk_hthread *curr_thread; - - /* Heap level "stash" object (e.g., various reachability roots). */ - duk_hobject *heap_object; - - /* duk_handle_call / duk_handle_safe_call recursion depth limiting */ - duk_int_t call_recursion_depth; - duk_int_t call_recursion_limit; - - /* Mix-in value for computing string hashes; should be reasonably unpredictable. */ - duk_uint32_t hash_seed; - - /* Random number state for duk_util_tinyrandom.c. */ -#if !defined(DUK_USE_GET_RANDOM_DOUBLE) -#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS) - duk_uint32_t rnd_state; /* State for Shamir's three-op algorithm */ -#else - duk_uint64_t rnd_state[2]; /* State for xoroshiro128+ */ -#endif -#endif - - /* Counter for unique local symbol creation. */ - /* XXX: When 64-bit types are available, it would be more efficient to - * use a duk_uint64_t at least for incrementing but maybe also for - * string formatting in the Symbol constructor. - */ - duk_uint32_t sym_counter[2]; - - /* For manual debugging: instruction count based on executor and - * interrupt counter book-keeping. Inspect debug logs to see how - * they match up. - */ -#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) - duk_int_t inst_count_exec; - duk_int_t inst_count_interrupt; -#endif - - /* Debugger state. */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - /* Callbacks and udata; dbg_read_cb != NULL is used to indicate attached state. */ - duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */ - duk_debug_write_function dbg_write_cb; /* required */ - duk_debug_peek_function dbg_peek_cb; - duk_debug_read_flush_function dbg_read_flush_cb; - duk_debug_write_flush_function dbg_write_flush_cb; - duk_debug_request_function dbg_request_cb; - duk_debug_detached_function dbg_detached_cb; - void *dbg_udata; - - /* The following are only relevant when debugger is attached. */ - duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */ - duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */ - duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */ - duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */ - duk_small_uint_t dbg_pause_flags; /* flags for automatic pause behavior */ - duk_activation *dbg_pause_act; /* activation related to pause behavior (pause on line change, function entry/exit) */ - duk_uint32_t dbg_pause_startline; /* starting line number for line change related pause behavior */ - duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */ - duk_small_uint_t dbg_breakpoint_count; - duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */ - /* XXX: make active breakpoints actual copies instead of pointers? */ - - /* These are for rate limiting Status notifications and transport peeking. */ - duk_uint_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */ - duk_uint_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */ - duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */ - - /* Used to support single-byte stream lookahead. */ - duk_bool_t dbg_have_next_byte; - duk_uint8_t dbg_next_byte; -#endif /* DUK_USE_DEBUGGER_SUPPORT */ -#if defined(DUK_USE_ASSERTIONS) - duk_bool_t dbg_calling_transport; /* transport call in progress, calling into Duktape forbidden */ -#endif - - /* String intern table (weak refs). */ -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *strtable16; -#else - duk_hstring **strtable; -#endif - duk_uint32_t st_mask; /* mask for lookup, st_size - 1 */ - duk_uint32_t st_size; /* stringtable size */ -#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE) - duk_uint32_t st_count; /* string count for resize load factor checks */ -#endif - duk_bool_t st_resizing; /* string table is being resized; avoid recursive resize */ - - /* String access cache (codepoint offset -> byte offset) for fast string - * character looping; 'weak' reference which needs special handling in GC. - */ - duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; - - /* Built-in strings. */ -#if defined(DUK_USE_ROM_STRINGS) - /* No field needed when strings are in ROM. */ -#else -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS]; -#else - duk_hstring *strs[DUK_HEAP_NUM_STRINGS]; -#endif -#endif - - /* Stats. */ -#if defined(DUK_USE_DEBUG) - duk_int_t stats_exec_opcodes; - duk_int_t stats_exec_interrupt; - duk_int_t stats_exec_throw; - duk_int_t stats_call_all; - duk_int_t stats_call_tailcall; - duk_int_t stats_call_ecmatoecma; - duk_int_t stats_safecall_all; - duk_int_t stats_safecall_nothrow; - duk_int_t stats_safecall_throw; - duk_int_t stats_ms_try_count; - duk_int_t stats_ms_skip_count; - duk_int_t stats_ms_emergency_count; - duk_int_t stats_strtab_intern_hit; - duk_int_t stats_strtab_intern_miss; - duk_int_t stats_strtab_resize_check; - duk_int_t stats_strtab_resize_grow; - duk_int_t stats_strtab_resize_shrink; - duk_int_t stats_object_realloc_props; - duk_int_t stats_object_abandon_array; - duk_int_t stats_getownpropdesc_count; - duk_int_t stats_getownpropdesc_hit; - duk_int_t stats_getownpropdesc_miss; - duk_int_t stats_getpropdesc_count; - duk_int_t stats_getpropdesc_hit; - duk_int_t stats_getpropdesc_miss; - duk_int_t stats_getprop_all; - duk_int_t stats_getprop_arrayidx; - duk_int_t stats_getprop_bufobjidx; - duk_int_t stats_getprop_bufferidx; - duk_int_t stats_getprop_bufferlen; - duk_int_t stats_getprop_stringidx; - duk_int_t stats_getprop_stringlen; - duk_int_t stats_getprop_proxy; - duk_int_t stats_getprop_arguments; - duk_int_t stats_putprop_all; - duk_int_t stats_putprop_arrayidx; - duk_int_t stats_putprop_bufobjidx; - duk_int_t stats_putprop_bufferidx; - duk_int_t stats_putprop_proxy; - duk_int_t stats_getvar_all; - duk_int_t stats_putvar_all; -#endif -}; - -/* - * Prototypes - */ - -DUK_INTERNAL_DECL -duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, - duk_realloc_function realloc_func, - duk_free_function free_func, - void *heap_udata, - duk_fatal_function fatal_func); -DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap); -DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h); -DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h); -DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr); - -DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); -#endif -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL_DECL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr); -DUK_INTERNAL_DECL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr); -#endif -#if defined(DUK_USE_ASSERTIONS) -DUK_INTERNAL_DECL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr); -#endif -#if defined(DUK_USE_INTERRUPT_COUNTER) -DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr); -#endif - -DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); -DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val); -DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h); -#endif -DUK_INTERNAL_DECL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev); -DUK_INTERNAL_DECL void duk_heap_strtable_force_resize(duk_heap *heap); -DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap); -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap); -#endif - -DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h); -DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset); - -#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) -DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size); -DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize); -DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr); -#endif - -DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size); -DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size); -DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size); -DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size); -DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize); -DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize); -DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr); - -DUK_INTERNAL_DECL void duk_heap_free_freelists(duk_heap *heap); - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL_DECL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj); -DUK_INTERNAL_DECL void duk_heap_process_finalize_list(duk_heap *heap); -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -DUK_INTERNAL_DECL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); - -DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len); - -#endif /* DUK_HEAP_H_INCLUDED */ -/* #include duk_debugger.h */ -#line 1 "duk_debugger.h" -#if !defined(DUK_DEBUGGER_H_INCLUDED) -#define DUK_DEBUGGER_H_INCLUDED - -/* Debugger protocol version is defined in the public API header. */ - -/* Initial bytes for markers. */ -#define DUK_DBG_IB_EOM 0x00 -#define DUK_DBG_IB_REQUEST 0x01 -#define DUK_DBG_IB_REPLY 0x02 -#define DUK_DBG_IB_ERROR 0x03 -#define DUK_DBG_IB_NOTIFY 0x04 - -/* Other initial bytes. */ -#define DUK_DBG_IB_INT4 0x10 -#define DUK_DBG_IB_STR4 0x11 -#define DUK_DBG_IB_STR2 0x12 -#define DUK_DBG_IB_BUF4 0x13 -#define DUK_DBG_IB_BUF2 0x14 -#define DUK_DBG_IB_UNUSED 0x15 -#define DUK_DBG_IB_UNDEFINED 0x16 -#define DUK_DBG_IB_NULL 0x17 -#define DUK_DBG_IB_TRUE 0x18 -#define DUK_DBG_IB_FALSE 0x19 -#define DUK_DBG_IB_NUMBER 0x1a -#define DUK_DBG_IB_OBJECT 0x1b -#define DUK_DBG_IB_POINTER 0x1c -#define DUK_DBG_IB_LIGHTFUNC 0x1d -#define DUK_DBG_IB_HEAPPTR 0x1e -/* The short string/integer initial bytes starting from 0x60 don't have - * defines now. - */ - -/* Error codes. */ -#define DUK_DBG_ERR_UNKNOWN 0x00 -#define DUK_DBG_ERR_UNSUPPORTED 0x01 -#define DUK_DBG_ERR_TOOMANY 0x02 -#define DUK_DBG_ERR_NOTFOUND 0x03 -#define DUK_DBG_ERR_APPLICATION 0x04 - -/* Commands and notifys initiated by Duktape. */ -#define DUK_DBG_CMD_STATUS 0x01 -#define DUK_DBG_CMD_UNUSED_2 0x02 /* Duktape 1.x: print notify */ -#define DUK_DBG_CMD_UNUSED_3 0x03 /* Duktape 1.x: alert notify */ -#define DUK_DBG_CMD_UNUSED_4 0x04 /* Duktape 1.x: log notify */ -#define DUK_DBG_CMD_THROW 0x05 -#define DUK_DBG_CMD_DETACHING 0x06 -#define DUK_DBG_CMD_APPNOTIFY 0x07 - -/* Commands initiated by debug client. */ -#define DUK_DBG_CMD_BASICINFO 0x10 -#define DUK_DBG_CMD_TRIGGERSTATUS 0x11 -#define DUK_DBG_CMD_PAUSE 0x12 -#define DUK_DBG_CMD_RESUME 0x13 -#define DUK_DBG_CMD_STEPINTO 0x14 -#define DUK_DBG_CMD_STEPOVER 0x15 -#define DUK_DBG_CMD_STEPOUT 0x16 -#define DUK_DBG_CMD_LISTBREAK 0x17 -#define DUK_DBG_CMD_ADDBREAK 0x18 -#define DUK_DBG_CMD_DELBREAK 0x19 -#define DUK_DBG_CMD_GETVAR 0x1a -#define DUK_DBG_CMD_PUTVAR 0x1b -#define DUK_DBG_CMD_GETCALLSTACK 0x1c -#define DUK_DBG_CMD_GETLOCALS 0x1d -#define DUK_DBG_CMD_EVAL 0x1e -#define DUK_DBG_CMD_DETACH 0x1f -#define DUK_DBG_CMD_DUMPHEAP 0x20 -#define DUK_DBG_CMD_GETBYTECODE 0x21 -#define DUK_DBG_CMD_APPREQUEST 0x22 -#define DUK_DBG_CMD_GETHEAPOBJINFO 0x23 -#define DUK_DBG_CMD_GETOBJPROPDESC 0x24 -#define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25 - -/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx. - * The remaining flags are specific to the debugger. - */ -#define DUK_DBG_PROPFLAG_SYMBOL (1U << 8) -#define DUK_DBG_PROPFLAG_HIDDEN (1U << 9) - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap); - -DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr); - -DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length); -DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr); - -DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length); -DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr); -DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr); -DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr); -/* XXX: exposed duk_debug_read_pointer */ -/* XXX: exposed duk_debug_read_buffer */ -/* XXX: exposed duk_debug_read_hbuffer */ -#if 0 -DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr); -#endif -#if defined(DUK_USE_DEBUGGER_INSPECT) -DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr); -#endif -DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr); - -DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length); -DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x); -DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr); -#if defined(DUK_USE_DEBUGGER_INSPECT) -DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr); -#endif -DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val); -DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x); -DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x); -DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length); -DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data); -DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length); -DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr); -#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT) -DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h); -#endif -DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj); -DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv); -#if 0 /* unused */ -DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command); -#endif -DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg); -DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command); -DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr); - -DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr); -#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) -DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal); -#endif - -DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc); -DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block); - -DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line); -DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index); - -DUK_INTERNAL_DECL duk_bool_t duk_debug_is_attached(duk_heap *heap); -DUK_INTERNAL_DECL duk_bool_t duk_debug_is_paused(duk_heap *heap); -DUK_INTERNAL_DECL void duk_debug_set_paused(duk_heap *heap); -DUK_INTERNAL_DECL void duk_debug_clear_paused(duk_heap *heap); -DUK_INTERNAL_DECL void duk_debug_clear_pause_state(duk_heap *heap); -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -#endif /* DUK_DEBUGGER_H_INCLUDED */ -/* #include duk_debug.h */ -#line 1 "duk_debug.h" -/* - * Debugging macros, DUK_DPRINT() and its variants in particular. - * - * DUK_DPRINT() allows formatted debug prints, and supports standard - * and Duktape specific formatters. See duk_debug_vsnprintf.c for details. - * - * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros - * for technical reasons. They are concretely used to hide 'x' from the - * compiler when the corresponding log level is disabled. This allows - * clean builds on non-C99 compilers, at the cost of more verbose code. - * Examples: - * - * DUK_D(DUK_DPRINT("foo")); - * DUK_DD(DUK_DDPRINT("foo")); - * DUK_DDD(DUK_DDDPRINT("foo")); - * - * This approach is preferable to the old "double parentheses" hack because - * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can - * no longer be added transparently without going through globals, which - * works poorly with threading. - */ - -#if !defined(DUK_DEBUG_H_INCLUDED) -#define DUK_DEBUG_H_INCLUDED - -#if defined(DUK_USE_DEBUG) - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) -#define DUK_D(x) x -#else -#define DUK_D(x) do { } while (0) /* omit */ -#endif - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) -#define DUK_DD(x) x -#else -#define DUK_DD(x) do { } while (0) /* omit */ -#endif - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) -#define DUK_DDD(x) x -#else -#define DUK_DDD(x) do { } while (0) /* omit */ -#endif - -/* - * Exposed debug macros: debugging enabled - */ - -#if defined(DUK_USE_VARIADIC_MACROS) - -/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be - * possible compile time, but waste some space with shared function names. - */ -#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__); - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) -#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__) -#else -#define DUK_DPRINT(...) -#endif - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) -#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__) -#else -#define DUK_DDPRINT(...) -#endif - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) -#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__) -#else -#define DUK_DDDPRINT(...) -#endif - -#else /* DUK_USE_VARIADIC_MACROS */ - -#define DUK__DEBUG_STASH(lev) \ - (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \ - (void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \ - (void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \ - (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \ - (void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \ - (void) (duk_debug_level_stash = (lev)) - -/* Without variadic macros resort to comma expression trickery to handle debug - * prints. This generates a lot of harmless warnings. These hacks are not - * needed normally because DUK_D() and friends will hide the entire debug log - * statement from the compiler. - */ - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) -#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */ -#else -#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ -#endif - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) -#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */ -#else -#define DUK_DDPRINT 0 && /* args */ -#endif - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) -#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */ -#else -#define DUK_DDDPRINT 0 && /* args */ -#endif - -#endif /* DUK_USE_VARIADIC_MACROS */ - -#else /* DUK_USE_DEBUG */ - -/* - * Exposed debug macros: debugging disabled - */ - -#define DUK_D(x) do { } while (0) /* omit */ -#define DUK_DD(x) do { } while (0) /* omit */ -#define DUK_DDD(x) do { } while (0) /* omit */ - -#if defined(DUK_USE_VARIADIC_MACROS) - -#define DUK_DPRINT(...) -#define DUK_DDPRINT(...) -#define DUK_DDDPRINT(...) - -#else /* DUK_USE_VARIADIC_MACROS */ - -#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ -#define DUK_DDPRINT 0 && /* args */ -#define DUK_DDDPRINT 0 && /* args */ - -#endif /* DUK_USE_VARIADIC_MACROS */ - -#endif /* DUK_USE_DEBUG */ - -/* - * Structs - */ - -#if defined(DUK_USE_DEBUG) -struct duk_fixedbuffer { - duk_uint8_t *buffer; - duk_size_t length; - duk_size_t offset; - duk_bool_t truncated; -}; -#endif - -/* - * Prototypes - */ - -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap); -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...); -#endif -DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size); - -#if defined(DUK_USE_VARIADIC_MACROS) -DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...); -#else /* DUK_USE_VARIADIC_MACROS */ -/* parameter passing, not thread safe */ -#define DUK_DEBUG_STASH_SIZE 128 -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; -DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash; -DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; -DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash; -#endif -DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...); -#endif /* DUK_USE_VARIADIC_MACROS */ - -DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length); -DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x); -DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x); -DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...); -DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size); -DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); - -#endif /* DUK_USE_DEBUG */ - -#endif /* DUK_DEBUG_H_INCLUDED */ -/* #include duk_error.h */ -#line 1 "duk_error.h" -/* - * Error handling macros, assertion macro, error codes. - * - * There are three types of 'errors': - * - * 1. Ordinary errors relative to a thread, cause a longjmp, catchable. - * 2. Fatal errors relative to a heap, cause fatal handler to be called. - * 3. Fatal errors without context, cause the default (not heap specific) - * fatal handler to be called. - * - * Fatal errors without context are used by debug code such as assertions. - * By providing a fatal error handler for a Duktape heap, user code can - * avoid fatal errors without context in non-debug builds. - */ - -#if !defined(DUK_ERROR_H_INCLUDED) -#define DUK_ERROR_H_INCLUDED - -/* - * Error codes: defined in duktape.h - * - * Error codes are used as a shorthand to throw exceptions from inside - * the implementation. The appropriate Ecmascript object is constructed - * based on the code. Ecmascript code throws objects directly. The error - * codes are defined in the public API header because they are also used - * by calling code. - */ - -/* - * Normal error - * - * Normal error is thrown with a longjmp() through the current setjmp() - * catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap - * identifies the throwing thread. - * - * Error formatting is usually unnecessary. The error macros provide a - * zero argument version (no formatting) and separate macros for small - * argument counts. Variadic macros are not used to avoid portability - * issues and avoid the need for stash-based workarounds when they're not - * available. Vararg calls are avoided for non-formatted error calls - * because vararg call sites are larger than normal, and there are a lot - * of call sites with no formatting. - * - * Note that special formatting provided by debug macros is NOT available. - * - * The _RAW variants allow the caller to specify file and line. This makes - * it easier to write checked calls which want to use the call site of the - * checked function, not the error macro call inside the checked function. - */ - -#if defined(DUK_USE_VERBOSE_ERRORS) - -/* Because there are quite many call sites, pack error code (require at most - * 8-bit) into a single argument. - */ -#define DUK_ERROR(thr,err,msg) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \ - } while (0) -#define DUK_ERROR_RAW(thr,file,line,err,msg) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \ - } while (0) - -#define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \ - } while (0) -#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \ - } while (0) - -#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \ - } while (0) -#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \ - } while (0) - -#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \ - } while (0) -#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \ - } while (0) - -#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \ - } while (0) -#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \ - duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ - DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ - duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \ - } while (0) - -#else /* DUK_USE_VERBOSE_ERRORS */ - -#define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err)) -#define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err)) - -#define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt)) -#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) - -#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt)) -#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) - -#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt)) -#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) - -#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt)) -#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) - -#endif /* DUK_USE_VERBOSE_ERRORS */ - -/* - * Fatal error without context - * - * The macro is an expression to make it compatible with DUK_ASSERT_EXPR(). - */ - -#define DUK_FATAL_WITHOUT_CONTEXT(msg) \ - duk_default_fatal_handler(NULL, (msg)) - -/* - * Error throwing helpers - * - * The goal is to provide verbose and configurable error messages. Call - * sites should be clean in source code and compile to a small footprint. - * Small footprint is also useful for performance because small cold paths - * reduce code cache pressure. Adding macros here only makes sense if there - * are enough call sites to get concrete benefits. - * - * DUK_ERROR_xxx() macros are generic and can be used anywhere. - * - * DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where - * the "return DUK_RET_xxx;" shorthand is available for low memory targets. - * The DUK_DCERROR_xxx() macros always either throw or perform a - * 'return DUK_RET_xxx' from the calling function. - */ - -#if defined(DUK_USE_VERBOSE_ERRORS) -/* Verbose errors with key/value summaries (non-paranoid) or without key/value - * summaries (paranoid, for some security sensitive environments), the paranoid - * vs. non-paranoid distinction affects only a few specific errors. - */ -#if defined(DUK_USE_PARANOID_ERRORS) -#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ - duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \ - } while (0) -#else /* DUK_USE_PARANOID_ERRORS */ -#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ - duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \ - } while (0) -#endif /* DUK_USE_PARANOID_ERRORS */ - -#define DUK_ERROR_INTERNAL(thr) do { \ - duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#define DUK_DCERROR_INTERNAL(thr) do { \ - DUK_ERROR_INTERNAL((thr)); \ - return 0; \ - } while (0) -#define DUK_ERROR_ALLOC_FAILED(thr) do { \ - duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#define DUK_ERROR_UNSUPPORTED(thr) do { \ - DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \ - } while (0) -#define DUK_ERROR_ERROR(thr,msg) do { \ - duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ - } while (0) -#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \ - duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \ - } while (0) -#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \ - duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \ - DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \ - } while (0) -#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \ - DUK_ERROR_RANGE_INVALID_ARGS((thr)); \ - return 0; \ - } while (0) -#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \ - DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \ - } while (0) -#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \ - DUK_ERROR_RANGE_INVALID_COUNT((thr)); \ - return 0; \ - } while (0) -#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \ - DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \ - } while (0) -#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \ - DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \ - return 0; \ - } while (0) -#define DUK_ERROR_RANGE(thr,msg) do { \ - duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ - } while (0) -#define DUK_ERROR_EVAL(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \ - } while (0) -#define DUK_ERROR_REFERENCE(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \ - } while (0) -#define DUK_ERROR_SYNTAX(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \ - } while (0) -#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \ - duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \ - DUK_ERROR_TYPE_INVALID_ARGS((thr)); \ - return 0; \ - } while (0) -#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \ - duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \ - DUK_ERROR_TYPE_INVALID_STATE((thr)); \ - return 0; \ - } while (0) -#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ - duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ - DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \ - } while (0) -#define DUK_ERROR_TYPE(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \ - } while (0) -#define DUK_ERROR_URI(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \ - } while (0) -#else /* DUK_USE_VERBOSE_ERRORS */ -/* Non-verbose errors for low memory targets: no file, line, or message. */ - -#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ - duk_err_type((thr)); \ - } while (0) - -#define DUK_ERROR_INTERNAL(thr) do { \ - duk_err_error((thr)); \ - } while (0) -#define DUK_DCERROR_INTERNAL(thr) do { \ - DUK_UNREF((thr)); \ - return DUK_RET_ERROR; \ - } while (0) -#define DUK_ERROR_ALLOC_FAILED(thr) do { \ - duk_err_error((thr)); \ - } while (0) -#define DUK_ERROR_UNSUPPORTED(thr) do { \ - duk_err_error((thr)); \ - } while (0) -#define DUK_ERROR_ERROR(thr,msg) do { \ - duk_err_error((thr)); \ - } while (0) -#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \ - duk_err_range((thr)); \ - } while (0) -#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \ - duk_err_range((thr)); \ - } while (0) -#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \ - duk_err_range((thr)); \ - } while (0) -#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \ - DUK_UNREF((thr)); \ - return DUK_RET_RANGE_ERROR; \ - } while (0) -#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \ - duk_err_range((thr)); \ - } while (0) -#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \ - DUK_UNREF((thr)); \ - return DUK_RET_RANGE_ERROR; \ - } while (0) -#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \ - duk_err_range((thr)); \ - } while (0) -#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \ - DUK_UNREF((thr)); \ - return DUK_RET_RANGE_ERROR; \ - } while (0) -#define DUK_ERROR_RANGE(thr,msg) do { \ - duk_err_range((thr)); \ - } while (0) -#define DUK_ERROR_EVAL(thr,msg) do { \ - duk_err_eval((thr)); \ - } while (0) -#define DUK_ERROR_REFERENCE(thr,msg) do { \ - duk_err_reference((thr)); \ - } while (0) -#define DUK_ERROR_SYNTAX(thr,msg) do { \ - duk_err_syntax((thr)); \ - } while (0) -#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \ - duk_err_type((thr)); \ - } while (0) -#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \ - DUK_UNREF((thr)); \ - return DUK_RET_TYPE_ERROR; \ - } while (0) -#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \ - duk_err_type((thr)); \ - } while (0) -#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \ - duk_err_type((thr)); \ - } while (0) -#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ - duk_err_type((thr)); \ - } while (0) -#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ - DUK_UNREF((thr)); \ - return DUK_RET_TYPE_ERROR; \ - } while (0) -#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ - duk_err_type((thr)); \ - } while (0) -#define DUK_ERROR_TYPE(thr,msg) do { \ - duk_err_type((thr)); \ - } while (0) -#define DUK_ERROR_URI(thr,msg) do { \ - duk_err_uri((thr)); \ - } while (0) -#endif /* DUK_USE_VERBOSE_ERRORS */ - -/* - * Assert macro: failure causes a fatal error. - * - * NOTE: since the assert macro doesn't take a heap/context argument, there's - * no way to look up a heap/context specific fatal error handler which may have - * been given by the application. Instead, assertion failures always use the - * internal default fatal error handler; it can be replaced via duk_config.h - * and then applies to all Duktape heaps. - */ - -#if defined(DUK_USE_ASSERTIONS) - -/* The message should be a compile time constant without formatting (less risk); - * we don't care about assertion text size because they're not used in production - * builds. - */ -#define DUK_ASSERT(x) do { \ - if (!(x)) { \ - DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \ - " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \ - } \ - } while (0) - -/* Assertion compatible inside a comma expression, evaluates to void. */ -#define DUK_ASSERT_EXPR(x) \ - ((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \ - " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0))) - -#else /* DUK_USE_ASSERTIONS */ - -#define DUK_ASSERT(x) do { /* assertion omitted */ } while (0) - -#define DUK_ASSERT_EXPR(x) ((void) 0) - -#endif /* DUK_USE_ASSERTIONS */ - -/* this variant is used when an assert would generate a compile warning by - * being always true (e.g. >= 0 comparison for an unsigned value - */ -#define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0) - -/* - * Assertion helpers - */ - -#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) -#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \ - DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \ - } while (0) -#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \ - if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \ - } \ - } while (0) -#else -#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */ -#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */ -#endif - -#define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n)) - -#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL) -#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \ - duk_double_union duk__assert_tmp_du; \ - duk__assert_tmp_du.d = (dval); \ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \ - } while (0) -#else -#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */ -#endif - -#define DUK_ASSERT_VS_SPACE(thr) \ - DUK_ASSERT(thr->valstack_top < thr->valstack_end) - -/* - * Helper to initialize a memory area (e.g. struct) with garbage when - * assertions enabled. - */ - -#if defined(DUK_USE_ASSERTIONS) -#define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \ - DUK_MEMSET((void *) (ptr), 0x5a, size); \ - } while (0) -#else -#define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0) -#endif - -/* - * Helper for valstack space - * - * Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries - * required for its own use, and any child calls which are not (a) Duktape API calls - * or (b) Duktape calls which involve extending the valstack (e.g. getter call). - */ - -#define DUK_VALSTACK_ASSERT_EXTRA 5 /* this is added to checks to allow for Duktape - * API calls in addition to function's own use - */ -#if defined(DUK_USE_ASSERTIONS) -#define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \ - DUK_ASSERT((thr) != NULL); \ - DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \ - } while (0) -#else -#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */ -#endif - -/* - * Prototypes - */ - -#if defined(DUK_USE_VERBOSE_ERRORS) -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...)); -#else /* DUK_USE_VERBOSE_ERRORS */ -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code)); -#endif /* DUK_USE_VERBOSE_ERRORS */ - -#if defined(DUK_USE_VERBOSE_ERRORS) -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line)); -#else -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)); -#endif - -DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc)); - -#define DUK_AUGMENT_FLAG_NOBLAME_FILELINE (1U << 0) /* if set, don't blame C file/line for .fileName and .lineNumber */ -#define DUK_AUGMENT_FLAG_SKIP_ONE (1U << 1) /* if set, skip topmost activation in traceback construction */ - -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) -DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_small_uint_t flags); -#endif -#if defined(DUK_USE_AUGMENT_ERROR_THROW) -DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr); -#endif - -#if defined(DUK_USE_VERBOSE_ERRORS) -#if defined(DUK_USE_PARANOID_ERRORS) -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name)); -#else -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name)); -#endif -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -#else /* DUK_VERBOSE_ERRORS */ -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr)); -#endif /* DUK_VERBOSE_ERRORS */ - -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr)); - -DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg)); - -DUK_INTERNAL_DECL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val); -#if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_INTERNAL_DECL void duk_err_check_debugger_integration(duk_hthread *thr); -#endif - -DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code); - -#endif /* DUK_ERROR_H_INCLUDED */ -/* #include duk_unicode.h */ -#line 1 "duk_unicode.h" -/* - * Unicode helpers - */ - -#if !defined(DUK_UNICODE_H_INCLUDED) -#define DUK_UNICODE_H_INCLUDED - -/* - * UTF-8 / XUTF-8 / CESU-8 constants - */ - -#define DUK_UNICODE_MAX_XUTF8_LENGTH 7 /* up to 36 bit codepoints */ -#define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */ -#define DUK_UNICODE_MAX_CESU8_LENGTH 6 /* all codepoints up to U+10FFFF */ -#define DUK_UNICODE_MAX_CESU8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */ - -/* - * Useful Unicode codepoints - * - * Integer constants must be signed to avoid unexpected coercions - * in comparisons. - */ - -#define DUK_UNICODE_CP_ZWNJ 0x200cL /* zero-width non-joiner */ -#define DUK_UNICODE_CP_ZWJ 0x200dL /* zero-width joiner */ -#define DUK_UNICODE_CP_REPLACEMENT_CHARACTER 0xfffdL /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */ - -/* - * ASCII character constants - * - * C character literals like 'x' have a platform specific value and do - * not match ASCII (UTF-8) values on e.g. EBCDIC platforms. So, use - * these (admittedly awkward) constants instead. These constants must - * also have signed values to avoid unexpected coercions in comparisons. - * - * http://en.wikipedia.org/wiki/ASCII - */ - -#define DUK_ASC_NUL 0x00 -#define DUK_ASC_SOH 0x01 -#define DUK_ASC_STX 0x02 -#define DUK_ASC_ETX 0x03 -#define DUK_ASC_EOT 0x04 -#define DUK_ASC_ENQ 0x05 -#define DUK_ASC_ACK 0x06 -#define DUK_ASC_BEL 0x07 -#define DUK_ASC_BS 0x08 -#define DUK_ASC_HT 0x09 -#define DUK_ASC_LF 0x0a -#define DUK_ASC_VT 0x0b -#define DUK_ASC_FF 0x0c -#define DUK_ASC_CR 0x0d -#define DUK_ASC_SO 0x0e -#define DUK_ASC_SI 0x0f -#define DUK_ASC_DLE 0x10 -#define DUK_ASC_DC1 0x11 -#define DUK_ASC_DC2 0x12 -#define DUK_ASC_DC3 0x13 -#define DUK_ASC_DC4 0x14 -#define DUK_ASC_NAK 0x15 -#define DUK_ASC_SYN 0x16 -#define DUK_ASC_ETB 0x17 -#define DUK_ASC_CAN 0x18 -#define DUK_ASC_EM 0x19 -#define DUK_ASC_SUB 0x1a -#define DUK_ASC_ESC 0x1b -#define DUK_ASC_FS 0x1c -#define DUK_ASC_GS 0x1d -#define DUK_ASC_RS 0x1e -#define DUK_ASC_US 0x1f -#define DUK_ASC_SPACE 0x20 -#define DUK_ASC_EXCLAMATION 0x21 -#define DUK_ASC_DOUBLEQUOTE 0x22 -#define DUK_ASC_HASH 0x23 -#define DUK_ASC_DOLLAR 0x24 -#define DUK_ASC_PERCENT 0x25 -#define DUK_ASC_AMP 0x26 -#define DUK_ASC_SINGLEQUOTE 0x27 -#define DUK_ASC_LPAREN 0x28 -#define DUK_ASC_RPAREN 0x29 -#define DUK_ASC_STAR 0x2a -#define DUK_ASC_PLUS 0x2b -#define DUK_ASC_COMMA 0x2c -#define DUK_ASC_MINUS 0x2d -#define DUK_ASC_PERIOD 0x2e -#define DUK_ASC_SLASH 0x2f -#define DUK_ASC_0 0x30 -#define DUK_ASC_1 0x31 -#define DUK_ASC_2 0x32 -#define DUK_ASC_3 0x33 -#define DUK_ASC_4 0x34 -#define DUK_ASC_5 0x35 -#define DUK_ASC_6 0x36 -#define DUK_ASC_7 0x37 -#define DUK_ASC_8 0x38 -#define DUK_ASC_9 0x39 -#define DUK_ASC_COLON 0x3a -#define DUK_ASC_SEMICOLON 0x3b -#define DUK_ASC_LANGLE 0x3c -#define DUK_ASC_EQUALS 0x3d -#define DUK_ASC_RANGLE 0x3e -#define DUK_ASC_QUESTION 0x3f -#define DUK_ASC_ATSIGN 0x40 -#define DUK_ASC_UC_A 0x41 -#define DUK_ASC_UC_B 0x42 -#define DUK_ASC_UC_C 0x43 -#define DUK_ASC_UC_D 0x44 -#define DUK_ASC_UC_E 0x45 -#define DUK_ASC_UC_F 0x46 -#define DUK_ASC_UC_G 0x47 -#define DUK_ASC_UC_H 0x48 -#define DUK_ASC_UC_I 0x49 -#define DUK_ASC_UC_J 0x4a -#define DUK_ASC_UC_K 0x4b -#define DUK_ASC_UC_L 0x4c -#define DUK_ASC_UC_M 0x4d -#define DUK_ASC_UC_N 0x4e -#define DUK_ASC_UC_O 0x4f -#define DUK_ASC_UC_P 0x50 -#define DUK_ASC_UC_Q 0x51 -#define DUK_ASC_UC_R 0x52 -#define DUK_ASC_UC_S 0x53 -#define DUK_ASC_UC_T 0x54 -#define DUK_ASC_UC_U 0x55 -#define DUK_ASC_UC_V 0x56 -#define DUK_ASC_UC_W 0x57 -#define DUK_ASC_UC_X 0x58 -#define DUK_ASC_UC_Y 0x59 -#define DUK_ASC_UC_Z 0x5a -#define DUK_ASC_LBRACKET 0x5b -#define DUK_ASC_BACKSLASH 0x5c -#define DUK_ASC_RBRACKET 0x5d -#define DUK_ASC_CARET 0x5e -#define DUK_ASC_UNDERSCORE 0x5f -#define DUK_ASC_GRAVE 0x60 -#define DUK_ASC_LC_A 0x61 -#define DUK_ASC_LC_B 0x62 -#define DUK_ASC_LC_C 0x63 -#define DUK_ASC_LC_D 0x64 -#define DUK_ASC_LC_E 0x65 -#define DUK_ASC_LC_F 0x66 -#define DUK_ASC_LC_G 0x67 -#define DUK_ASC_LC_H 0x68 -#define DUK_ASC_LC_I 0x69 -#define DUK_ASC_LC_J 0x6a -#define DUK_ASC_LC_K 0x6b -#define DUK_ASC_LC_L 0x6c -#define DUK_ASC_LC_M 0x6d -#define DUK_ASC_LC_N 0x6e -#define DUK_ASC_LC_O 0x6f -#define DUK_ASC_LC_P 0x70 -#define DUK_ASC_LC_Q 0x71 -#define DUK_ASC_LC_R 0x72 -#define DUK_ASC_LC_S 0x73 -#define DUK_ASC_LC_T 0x74 -#define DUK_ASC_LC_U 0x75 -#define DUK_ASC_LC_V 0x76 -#define DUK_ASC_LC_W 0x77 -#define DUK_ASC_LC_X 0x78 -#define DUK_ASC_LC_Y 0x79 -#define DUK_ASC_LC_Z 0x7a -#define DUK_ASC_LCURLY 0x7b -#define DUK_ASC_PIPE 0x7c -#define DUK_ASC_RCURLY 0x7d -#define DUK_ASC_TILDE 0x7e -#define DUK_ASC_DEL 0x7f - -/* - * Miscellaneous - */ - -/* Uppercase A is 0x41, lowercase a is 0x61; OR 0x20 to convert uppercase - * to lowercase. - */ -#define DUK_LOWERCASE_CHAR_ASCII(x) ((x) | 0x20) - -/* - * Unicode tables - */ - -#if defined(DUK_USE_SOURCE_NONBMP) -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -extern const duk_uint8_t duk_unicode_ids_noa[1036]; -#else -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -extern const duk_uint8_t duk_unicode_ids_noabmp[625]; -#endif - -#if defined(DUK_USE_SOURCE_NONBMP) -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -extern const duk_uint8_t duk_unicode_ids_m_let_noa[42]; -#else -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24]; -#endif - -#if defined(DUK_USE_SOURCE_NONBMP) -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -extern const duk_uint8_t duk_unicode_idp_m_ids_noa[530]; -#else -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357]; -#endif - -/* - * Automatically generated by extract_caseconv.py, do not edit! - */ - -extern const duk_uint8_t duk_unicode_caseconv_uc[1386]; -extern const duk_uint8_t duk_unicode_caseconv_lc[680]; - -#if defined(DUK_USE_REGEXP_CANON_WORKAROUND) -/* - * Automatically generated by extract_caseconv.py, do not edit! - */ - -extern const duk_uint16_t duk_unicode_re_canon_lookup[65536]; -#endif - -#if defined(DUK_USE_REGEXP_CANON_BITMAP) -/* - * Automatically generated by extract_caseconv.py, do not edit! - */ - -#define DUK_CANON_BITMAP_BLKSIZE 32 -#define DUK_CANON_BITMAP_BLKSHIFT 5 -#define DUK_CANON_BITMAP_BLKMASK 31 -extern const duk_uint8_t duk_unicode_re_canon_bitmap[256]; -#endif - -/* - * Extern - */ - -/* duk_unicode_support.c */ -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7]; -DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2]; -DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22]; -DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8]; -DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4]; -DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24]; -DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10]; -DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128]; -#endif /* !DUK_SINGLE_FILE */ - -/* - * Prototypes - */ - -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp); -#if defined(DUK_USE_ASSERTIONS) -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp); -#endif -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out); -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out); -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp); -DUK_INTERNAL_DECL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end); -DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen); -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp); -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp); -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp); -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp); -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp); -DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase); -#if defined(DUK_USE_REGEXP_SUPPORT) -DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp); -DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp); -#endif - -#endif /* DUK_UNICODE_H_INCLUDED */ -/* #include duk_json.h */ -#line 1 "duk_json.h" -/* - * Defines for JSON, especially duk_bi_json.c. - */ - -#if !defined(DUK_JSON_H_INCLUDED) -#define DUK_JSON_H_INCLUDED - -/* Encoding/decoding flags */ -#define DUK_JSON_FLAG_ASCII_ONLY (1U << 0) /* escape any non-ASCII characters */ -#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1U << 1) /* avoid key quotes when key is an ASCII Identifier */ -#define DUK_JSON_FLAG_EXT_CUSTOM (1U << 2) /* extended types: custom encoding */ -#define DUK_JSON_FLAG_EXT_COMPATIBLE (1U << 3) /* extended types: compatible encoding */ - -/* How much stack to require on entry to object/array encode */ -#define DUK_JSON_ENC_REQSTACK 32 - -/* How much stack to require on entry to object/array decode */ -#define DUK_JSON_DEC_REQSTACK 32 - -/* How large a loop detection stack to use */ -#define DUK_JSON_ENC_LOOPARRAY 64 - -/* Encoding state. Heap object references are all borrowed. */ -typedef struct { - duk_hthread *thr; - duk_bufwriter_ctx bw; /* output bufwriter */ - duk_hobject *h_replacer; /* replacer function */ - duk_hstring *h_gap; /* gap (if empty string, NULL) */ - duk_idx_t idx_proplist; /* explicit PropertyList */ - duk_idx_t idx_loop; /* valstack index of loop detection object */ - duk_small_uint_t flags; - duk_small_uint_t flag_ascii_only; - duk_small_uint_t flag_avoid_key_quotes; -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - duk_small_uint_t flag_ext_custom; - duk_small_uint_t flag_ext_compatible; - duk_small_uint_t flag_ext_custom_or_compatible; -#endif - duk_uint_t recursion_depth; - duk_uint_t recursion_limit; - duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */ -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - duk_small_uint_t stridx_custom_undefined; - duk_small_uint_t stridx_custom_nan; - duk_small_uint_t stridx_custom_neginf; - duk_small_uint_t stridx_custom_posinf; - duk_small_uint_t stridx_custom_function; -#endif - duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */ -} duk_json_enc_ctx; - -typedef struct { - duk_hthread *thr; - const duk_uint8_t *p; - const duk_uint8_t *p_start; - const duk_uint8_t *p_end; - duk_idx_t idx_reviver; - duk_small_uint_t flags; -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - duk_small_uint_t flag_ext_custom; - duk_small_uint_t flag_ext_compatible; - duk_small_uint_t flag_ext_custom_or_compatible; -#endif - duk_int_t recursion_depth; - duk_int_t recursion_limit; -} duk_json_dec_ctx; - -#endif /* DUK_JSON_H_INCLUDED */ -/* #include duk_js.h */ -#line 1 "duk_js.h" -/* - * Ecmascript execution, support primitives. - */ - -#if !defined(DUK_JS_H_INCLUDED) -#define DUK_JS_H_INCLUDED - -/* Flags for call handling. Lowest flags must match bytecode DUK_BC_CALL_FLAG_xxx 1:1. */ -#define DUK_CALL_FLAG_TAILCALL (1U << 0) /* setup for a tail call */ -#define DUK_CALL_FLAG_CONSTRUCT (1U << 1) /* constructor call (i.e. called as 'new Foo()') */ -#define DUK_CALL_FLAG_CALLED_AS_EVAL (1U << 2) /* call was made using the identifier 'eval' */ -#define DUK_CALL_FLAG_ALLOW_ECMATOECMA (1U << 3) /* ecma-to-ecma call with executor reuse is possible */ -#define DUK_CALL_FLAG_DIRECT_EVAL (1U << 4) /* call is a direct eval call */ -#define DUK_CALL_FLAG_CONSTRUCT_PROXY (1U << 5) /* handled via 'construct' proxy trap, check return value invariant(s) */ -#define DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED (1U << 6) /* prototype of 'default instance' updated, temporary flag in call handling */ - -/* Flags for duk_js_equals_helper(). */ -#define DUK_EQUALS_FLAG_SAMEVALUE (1U << 0) /* use SameValue instead of non-strict equality */ -#define DUK_EQUALS_FLAG_STRICT (1U << 1) /* use strict equality instead of non-strict equality */ - -/* Flags for duk_js_compare_helper(). */ -#define DUK_COMPARE_FLAG_NEGATE (1U << 0) /* negate result */ -#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1U << 1) /* eval left argument first */ - -/* conversions, coercions, comparison, etc */ -DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv); -DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x); -DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen); -#if !defined(DUK_USE_HSTRING_ARRIDX) -DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h); -DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h); -#endif -DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags); -DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2); -DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2); -#if 0 /* unused */ -DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2); -#endif -DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags); -DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); -DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); -DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x); - -/* arithmetic */ -DUK_INTERNAL_DECL double duk_js_arith_pow(double x, double y); -DUK_INTERNAL_DECL double duk_js_arith_mod(double x, double y); - -#define duk_js_equals(thr,tv_x,tv_y) \ - duk_js_equals_helper((thr), (tv_x), (tv_y), 0) -#define duk_js_strict_equals(tv_x,tv_y) \ - duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT) -#define duk_js_samevalue(tv_x,tv_y) \ - duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE) - -/* E5 Sections 11.8.1, 11.8.5; x < y */ -#define duk_js_lessthan(thr,tv_x,tv_y) \ - duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) - -/* E5 Sections 11.8.2, 11.8.5; x > y --> y < x */ -#define duk_js_greaterthan(thr,tv_x,tv_y) \ - duk_js_compare_helper((thr), (tv_y), (tv_x), 0) - -/* E5 Sections 11.8.3, 11.8.5; x <= y --> not (x > y) --> not (y < x) */ -#define duk_js_lessthanorequal(thr,tv_x,tv_y) \ - duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE) - -/* E5 Sections 11.8.4, 11.8.5; x >= y --> not (x < y) */ -#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \ - duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE) - -/* identifiers and environment handling */ -#if 0 /*unused*/ -DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name); -#endif -DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag); -DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag); -DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict); -DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict); -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name); -#endif -DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name); -DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_uint_t prop_flags, duk_bool_t is_func_decl); -DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act); -DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env); -DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t bottom_byteoff); -DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr, - duk_hcompfunc *fun_temp, - duk_hobject *outer_var_env, - duk_hobject *outer_lex_env, - duk_bool_t add_auto_proto); - -/* call handling */ -DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t idx_func, duk_small_uint_t call_flags); -DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags); -DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t num_stack_args, duk_idx_t num_stack_res); -DUK_INTERNAL_DECL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant); -#if defined(DUK_USE_VERBOSE_ERRORS) -DUK_INTERNAL_DECL void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key); -#endif - -/* bytecode execution */ -DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr); - -#endif /* DUK_JS_H_INCLUDED */ -/* #include duk_numconv.h */ -#line 1 "duk_numconv.h" -/* - * Number-to-string conversion. The semantics of these is very tightly - * bound with the Ecmascript semantics required for call sites. - */ - -#if !defined(DUK_NUMCONV_H_INCLUDED) -#define DUK_NUMCONV_H_INCLUDED - -/* Output a specified number of digits instead of using the shortest - * form. Used for toPrecision() and toFixed(). - */ -#define DUK_N2S_FLAG_FIXED_FORMAT (1U << 0) - -/* Force exponential format. Used for toExponential(). */ -#define DUK_N2S_FLAG_FORCE_EXP (1U << 1) - -/* If number would need zero padding (for whole number part), use - * exponential format instead. E.g. if input number is 12300, 3 - * digits are generated ("123"), output "1.23e+4" instead of "12300". - * Used for toPrecision(). - */ -#define DUK_N2S_FLAG_NO_ZERO_PAD (1U << 2) - -/* Digit count indicates number of fractions (i.e. an absolute - * digit index instead of a relative one). Used together with - * DUK_N2S_FLAG_FIXED_FORMAT for toFixed(). - */ -#define DUK_N2S_FLAG_FRACTION_DIGITS (1U << 3) - -/* - * String-to-number conversion - */ - -/* Maximum exponent value when parsing numbers. This is not strictly - * compliant as there should be no upper limit, but as we parse the - * exponent without a bigint, impose some limit. - */ -#define DUK_S2N_MAX_EXPONENT 1000000000 - -/* Trim white space (= allow leading and trailing whitespace) */ -#define DUK_S2N_FLAG_TRIM_WHITE (1U << 0) - -/* Allow exponent */ -#define DUK_S2N_FLAG_ALLOW_EXP (1U << 1) - -/* Allow trailing garbage (e.g. treat "123foo" as "123) */ -#define DUK_S2N_FLAG_ALLOW_GARBAGE (1U << 2) - -/* Allow leading plus sign */ -#define DUK_S2N_FLAG_ALLOW_PLUS (1U << 3) - -/* Allow leading minus sign */ -#define DUK_S2N_FLAG_ALLOW_MINUS (1U << 4) - -/* Allow 'Infinity' */ -#define DUK_S2N_FLAG_ALLOW_INF (1U << 5) - -/* Allow fraction part */ -#define DUK_S2N_FLAG_ALLOW_FRAC (1U << 6) - -/* Allow naked fraction (e.g. ".123") */ -#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1U << 7) - -/* Allow empty fraction (e.g. "123.") */ -#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1U << 8) - -/* Allow empty string to be interpreted as 0 */ -#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1U << 9) - -/* Allow leading zeroes (e.g. "0123" -> "123") */ -#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1U << 10) - -/* Allow automatic detection of hex base ("0x" or "0X" prefix), - * overrides radix argument and forces integer mode. - */ -#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1U << 11) - -/* Allow automatic detection of legacy octal base ("0n"), - * overrides radix argument and forces integer mode. - */ -#define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1U << 12) - -/* Allow automatic detection of ES2015 octal base ("0o123"), - * overrides radix argument and forces integer mode. - */ -#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1U << 13) - -/* Allow automatic detection of ES2015 binary base ("0b10001"), - * overrides radix argument and forces integer mode. - */ -#define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1U << 14) - -/* - * Prototypes - */ - -DUK_INTERNAL_DECL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags); -DUK_INTERNAL_DECL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags); - -#endif /* DUK_NUMCONV_H_INCLUDED */ -/* #include duk_bi_protos.h */ -#line 1 "duk_bi_protos.h" -/* - * Prototypes for built-in functions not automatically covered by the - * header declarations emitted by genbuiltins.py. - */ - -#if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED) -#define DUK_BUILTIN_PROTOS_H_INCLUDED - -/* Buffer size needed for ISO 8601 formatting. - * Accurate value is 32 + 1 for NUL termination: - * >>> len('+123456-01-23T12:34:56.123+12:34') - * 32 - * Include additional space to be safe. - */ -#define DUK_BI_DATE_ISO8601_BUFSIZE 40 - -/* Helpers exposed for internal use */ -DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags); -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags); -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year); -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x); -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year); -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x); -/* Built-in providers */ -#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(void); -#endif -#if defined(DUK_USE_DATE_NOW_TIME) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(void); -#endif -#if defined(DUK_USE_DATE_NOW_WINDOWS) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(void); -#endif -#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows_subms(void); -#endif -#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) -DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d); -#endif -#if defined(DUK_USE_DATE_TZO_WINDOWS) -DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d); -#endif -#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) -DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d); -#endif -#if defined(DUK_USE_DATE_PRS_STRPTIME) -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str); -#endif -#if defined(DUK_USE_DATE_PRS_GETDATE) -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str); -#endif -#if defined(DUK_USE_DATE_FMT_STRFTIME) -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags); -#endif - -#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void); -#endif -#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void); -#endif - -DUK_INTERNAL_DECL -void duk_bi_json_parse_helper(duk_hthread *thr, - duk_idx_t idx_value, - duk_idx_t idx_reviver, - duk_small_uint_t flags); -DUK_INTERNAL_DECL -void duk_bi_json_stringify_helper(duk_hthread *thr, - duk_idx_t idx_value, - duk_idx_t idx_replacer, - duk_idx_t idx_space, - duk_small_uint_t flags); - -DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr); - -#if defined(DUK_USE_ES6_PROXY) -DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags); -#endif - -#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */ -/* #include duk_selftest.h */ -#line 1 "duk_selftest.h" -/* - * Selftest code - */ - -#if !defined(DUK_SELFTEST_H_INCLUDED) -#define DUK_SELFTEST_H_INCLUDED - -#if defined(DUK_USE_SELF_TESTS) -DUK_INTERNAL_DECL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func, - duk_realloc_function realloc_func, - duk_free_function free_func, - void *udata); -#endif - -#endif /* DUK_SELFTEST_H_INCLUDED */ -#line 82 "duk_internal.h" - -#endif /* DUK_INTERNAL_H_INCLUDED */ -#line 10 "duk_replacements.c" - -#if defined(DUK_USE_COMPUTED_NAN) -DUK_INTERNAL double duk_computed_nan; -#endif - -#if defined(DUK_USE_COMPUTED_INFINITY) -DUK_INTERNAL double duk_computed_infinity; -#endif - -#if defined(DUK_USE_REPL_FPCLASSIFY) -DUK_INTERNAL int duk_repl_fpclassify(double x) { - duk_double_union u; - duk_uint_fast16_t expt; - duk_small_int_t mzero; - - u.d = x; - expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL); - if (expt > 0x0000UL && expt < 0x7ff0UL) { - /* expt values [0x001,0x7fe] = normal */ - return DUK_FP_NORMAL; - } - - mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0); - if (expt == 0x0000UL) { - /* expt 0x000 is zero/subnormal */ - if (mzero) { - return DUK_FP_ZERO; - } else { - return DUK_FP_SUBNORMAL; - } - } else { - /* expt 0xfff is infinite/nan */ - if (mzero) { - return DUK_FP_INFINITE; - } else { - return DUK_FP_NAN; - } - } -} -#endif - -#if defined(DUK_USE_REPL_SIGNBIT) -DUK_INTERNAL int duk_repl_signbit(double x) { - duk_double_union u; - u.d = x; - return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL); -} -#endif - -#if defined(DUK_USE_REPL_ISFINITE) -DUK_INTERNAL int duk_repl_isfinite(double x) { - int c = DUK_FPCLASSIFY(x); - if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { - return 0; - } else { - return 1; - } -} -#endif - -#if defined(DUK_USE_REPL_ISNAN) -DUK_INTERNAL int duk_repl_isnan(double x) { - int c = DUK_FPCLASSIFY(x); - return (c == DUK_FP_NAN); -} -#endif - -#if defined(DUK_USE_REPL_ISINF) -DUK_INTERNAL int duk_repl_isinf(double x) { - int c = DUK_FPCLASSIFY(x); - return (c == DUK_FP_INFINITE); -} -#endif -#line 1 "duk_debug_macros.c" -/* - * Debugging macro calls. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_DEBUG) - -/* - * Debugging enabled - */ - -#include -#include -#include - -#if !defined(DUK_USE_DEBUG_WRITE) -#error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined -#endif - -#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE - -#if defined(DUK_USE_VARIADIC_MACROS) - -DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) { - va_list ap; - long arg_level; - const char *arg_file; - long arg_line; - const char *arg_func; - const char *arg_msg; - char buf[DUK__DEBUG_BUFSIZE]; - - va_start(ap, fmt); - - DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); - duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); - - arg_level = (long) level; - arg_file = (const char *) file; - arg_line = (long) line; - arg_func = (const char *) func; - arg_msg = (const char *) buf; - DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg); - - va_end(ap); -} - -#else /* DUK_USE_VARIADIC_MACROS */ - -DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; -DUK_INTERNAL duk_int_t duk_debug_line_stash; -DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; -DUK_INTERNAL duk_int_t duk_debug_level_stash; - -DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { - va_list ap; - long arg_level; - const char *arg_file; - long arg_line; - const char *arg_func; - const char *arg_msg; - char buf[DUK__DEBUG_BUFSIZE]; - - va_start(ap, fmt); - - DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); - duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); - - arg_level = (long) duk_debug_level_stash; - arg_file = (const char *) duk_debug_file_stash; - arg_line = (long) duk_debug_line_stash; - arg_func = (const char *) duk_debug_func_stash; - arg_msg = (const char *) buf; - DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg); - - va_end(ap); -} - -#endif /* DUK_USE_VARIADIC_MACROS */ - -#else /* DUK_USE_DEBUG */ - -/* - * Debugging disabled - */ - -#endif /* DUK_USE_DEBUG */ - -/* automatic undefs */ -#undef DUK__DEBUG_BUFSIZE -#line 1 "duk_builtins.c" -/* - * Automatically generated by genbuiltins.py, do not edit! - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_ASSERTIONS) -#define DUK__REFCINIT(refc) 0 /*h_assert_refcount*/, (refc) /*actual*/ -#else -#define DUK__REFCINIT(refc) (refc) /*actual*/ -#endif - -#if defined(DUK_USE_ROM_STRINGS) -#error ROM support not enabled, rerun configure.py with --rom-support -#else /* DUK_USE_ROM_STRINGS */ -DUK_INTERNAL const duk_uint8_t duk_strings_data[892] = { -79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103, -35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31, -129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132, -140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224, -193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32, -196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8, -196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11, -229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10, -183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32, -184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64, -178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18, -32,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156, -113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115, -119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137, -101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75, -226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64, -52,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133, -67,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2, -249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190, -186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12, -32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226, -231,146,51,192,204,73,140,224,145,221,102,241,68,196,157,34,79,143,139,166, -233,225,228,227,138,157,173,167,197,211,118,214,210,38,238,74,113,67,76, -105,187,169,147,154,73,225,228,32,193,48,25,100,105,166,113,200,147,44,166, -1,40,79,18,150,134,147,141,163,2,72,171,115,147,136,4,65,130,96,35,64,194, -32,168,89,56,208,48,135,123,144,217,146,39,220,228,193,19,18,101,220,227, -73,121,167,115,129,196,200,39,12,136,220,225,93,22,1,114,62,231,42,8,176, -15,62,231,36,234,68,68,70,231,30,45,37,161,164,38,231,24,7,159,115,149,4, -72,218,171,115,133,67,64,180,100,145,54,231,42,5,208,135,19,152,244,44,133, -67,95,73,164,145,143,5,18,2,100,65,35,30,76,241,117,134,70,212,103,37,204, -16,72,154,218,130,77,196,145,63,127,123,106,141,25,11,189,243,169,198,132, -251,235,119,247,182,154,6,239,124,234,113,161,62,250,221,253,237,164,52, -187,223,58,156,104,79,190,187,127,123,105,168,105,119,190,117,56,208,159, -125,118,254,246,209,104,209,111,124,234,113,161,62,250,205,253,162,209,162, -249,212,227,66,125,244,161,137,0,162,8,18,33,68,9,136,232,19,155,52,54,132, -64,200,26,24,196,137,198,66,130,139,153,134,69,146,100,16,220,66,46,68,57, -80,208,45,120,25,93,20,22,141,20,208,230,137,5,18,26,164,54,83,3,68,71,20, -109,37,141,18,78,145,105,165,100,76,71,36,206,137,22,103,139,172,57,199,6, -158,30,71,20,117,4,74,39,54,83,37,92,129,150,199,66,200,75,34,103,40,150,9, -72,132,109,24,98,93,238,140,206,75,204,141,28,140,134,61,209,153,101,71, -146,36,109,22,178,78,52,33,74,5,200,138,67,30,178,48,141,156,146,134,204, -145,40,4,65,172,147,59,192,37,0,196,59,226,138,130,100,75,226,233,144,83, -32,204,250,5,104,17,165,48,77,2,46,16,69,140, -}; -#endif /* DUK_USE_ROM_STRINGS */ - -#if defined(DUK_USE_ROM_OBJECTS) -#error ROM support not enabled, rerun configure.py with --rom-support -#else /* DUK_USE_ROM_OBJECTS */ -/* native functions: 176 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = { - NULL, - duk_bi_array_constructor, - duk_bi_array_constructor_is_array, - duk_bi_array_prototype_concat, - duk_bi_array_prototype_indexof_shared, - duk_bi_array_prototype_iter_shared, - duk_bi_array_prototype_join_shared, - duk_bi_array_prototype_pop, - duk_bi_array_prototype_push, - duk_bi_array_prototype_reduce_shared, - duk_bi_array_prototype_reverse, - duk_bi_array_prototype_shift, - duk_bi_array_prototype_slice, - duk_bi_array_prototype_sort, - duk_bi_array_prototype_splice, - duk_bi_array_prototype_to_string, - duk_bi_array_prototype_unshift, - duk_bi_arraybuffer_constructor, - duk_bi_arraybuffer_isview, - duk_bi_boolean_constructor, - duk_bi_boolean_prototype_tostring_shared, - duk_bi_buffer_compare_shared, - duk_bi_buffer_readfield, - duk_bi_buffer_slice_shared, - duk_bi_buffer_writefield, - duk_bi_dataview_constructor, - duk_bi_date_constructor, - duk_bi_date_constructor_now, - duk_bi_date_constructor_parse, - duk_bi_date_constructor_utc, - duk_bi_date_prototype_get_shared, - duk_bi_date_prototype_get_timezone_offset, - duk_bi_date_prototype_set_shared, - duk_bi_date_prototype_set_time, - duk_bi_date_prototype_to_json, - duk_bi_date_prototype_tostring_shared, - duk_bi_date_prototype_value_of, - duk_bi_duktape_object_act, - duk_bi_duktape_object_compact, - duk_bi_duktape_object_dec, - duk_bi_duktape_object_enc, - duk_bi_duktape_object_fin, - duk_bi_duktape_object_gc, - duk_bi_duktape_object_info, - duk_bi_error_constructor_shared, - duk_bi_error_prototype_filename_getter, - duk_bi_error_prototype_filename_setter, - duk_bi_error_prototype_linenumber_getter, - duk_bi_error_prototype_linenumber_setter, - duk_bi_error_prototype_stack_getter, - duk_bi_error_prototype_stack_setter, - duk_bi_error_prototype_to_string, - duk_bi_function_constructor, - duk_bi_function_prototype, - duk_bi_function_prototype_apply, - duk_bi_function_prototype_bind, - duk_bi_function_prototype_call, - duk_bi_function_prototype_to_string, - duk_bi_global_object_decode_uri, - duk_bi_global_object_decode_uri_component, - duk_bi_global_object_encode_uri, - duk_bi_global_object_encode_uri_component, - duk_bi_global_object_escape, - duk_bi_global_object_eval, - duk_bi_global_object_is_finite, - duk_bi_global_object_is_nan, - duk_bi_global_object_parse_float, - duk_bi_global_object_parse_int, - duk_bi_global_object_unescape, - duk_bi_json_object_parse, - duk_bi_json_object_stringify, - duk_bi_math_object_clz32, - duk_bi_math_object_hypot, - duk_bi_math_object_imul, - duk_bi_math_object_max, - duk_bi_math_object_min, - duk_bi_math_object_onearg_shared, - duk_bi_math_object_random, - duk_bi_math_object_sign, - duk_bi_math_object_twoarg_shared, - duk_bi_native_function_length, - duk_bi_native_function_name, - duk_bi_nodejs_buffer_byte_length, - duk_bi_nodejs_buffer_concat, - duk_bi_nodejs_buffer_constructor, - duk_bi_nodejs_buffer_copy, - duk_bi_nodejs_buffer_fill, - duk_bi_nodejs_buffer_is_buffer, - duk_bi_nodejs_buffer_is_encoding, - duk_bi_nodejs_buffer_tojson, - duk_bi_nodejs_buffer_tostring, - duk_bi_nodejs_buffer_write, - duk_bi_number_constructor, - duk_bi_number_prototype_to_exponential, - duk_bi_number_prototype_to_fixed, - duk_bi_number_prototype_to_locale_string, - duk_bi_number_prototype_to_precision, - duk_bi_number_prototype_to_string, - duk_bi_number_prototype_value_of, - duk_bi_object_constructor, - duk_bi_object_constructor_assign, - duk_bi_object_constructor_create, - duk_bi_object_constructor_define_properties, - duk_bi_object_constructor_define_property, - duk_bi_object_constructor_get_own_property_descriptor, - duk_bi_object_constructor_is, - duk_bi_object_constructor_is_extensible, - duk_bi_object_constructor_is_sealed_frozen_shared, - duk_bi_object_constructor_keys_shared, - duk_bi_object_constructor_prevent_extensions, - duk_bi_object_constructor_seal_freeze_shared, - duk_bi_object_getprototype_shared, - duk_bi_object_prototype_defineaccessor, - duk_bi_object_prototype_has_own_property, - duk_bi_object_prototype_is_prototype_of, - duk_bi_object_prototype_lookupaccessor, - duk_bi_object_prototype_property_is_enumerable, - duk_bi_object_prototype_to_locale_string, - duk_bi_object_prototype_to_string, - duk_bi_object_prototype_value_of, - duk_bi_object_setprototype_shared, - duk_bi_performance_now, - duk_bi_pointer_constructor, - duk_bi_pointer_prototype_tostring_shared, - duk_bi_proxy_constructor, - duk_bi_reflect_apply, - duk_bi_reflect_construct, - duk_bi_reflect_object_delete_property, - duk_bi_reflect_object_get, - duk_bi_reflect_object_has, - duk_bi_reflect_object_set, - duk_bi_regexp_constructor, - duk_bi_regexp_prototype_exec, - duk_bi_regexp_prototype_flags, - duk_bi_regexp_prototype_shared_getter, - duk_bi_regexp_prototype_test, - duk_bi_regexp_prototype_tostring, - duk_bi_string_constructor, - duk_bi_string_constructor_from_char_code, - duk_bi_string_constructor_from_code_point, - duk_bi_string_prototype_caseconv_shared, - duk_bi_string_prototype_char_at, - duk_bi_string_prototype_char_code_at, - duk_bi_string_prototype_concat, - duk_bi_string_prototype_includes, - duk_bi_string_prototype_indexof_shared, - duk_bi_string_prototype_locale_compare, - duk_bi_string_prototype_match, - duk_bi_string_prototype_repeat, - duk_bi_string_prototype_replace, - duk_bi_string_prototype_search, - duk_bi_string_prototype_slice, - duk_bi_string_prototype_split, - duk_bi_string_prototype_startswith_endswith, - duk_bi_string_prototype_substr, - duk_bi_string_prototype_substring, - duk_bi_string_prototype_to_string, - duk_bi_string_prototype_trim, - duk_bi_textdecoder_constructor, - duk_bi_textdecoder_prototype_decode, - duk_bi_textdecoder_prototype_shared_getter, - duk_bi_textencoder_constructor, - duk_bi_textencoder_prototype_encode, - duk_bi_textencoder_prototype_encoding_getter, - duk_bi_thread_constructor, - duk_bi_thread_current, - duk_bi_thread_resume, - duk_bi_thread_yield, - duk_bi_type_error_thrower, - duk_bi_typedarray_buffer_getter, - duk_bi_typedarray_bytelength_getter, - duk_bi_typedarray_byteoffset_getter, - duk_bi_typedarray_constructor, - duk_bi_typedarray_set, - duk_bi_uint8array_allocplain, - duk_bi_uint8array_plainof, -}; -#if defined(DUK_USE_DOUBLE_LE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = { -144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242, -252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33, -167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228, -64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46, -142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240, -242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0, -1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, -33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17, -13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192, -0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188, -0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85, -217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225, -146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,0,0, -0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1,172,19,120,71,10,25,196,136, -113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,2, -185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,130, -249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,138, -9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,190,15, -38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,53,64, -243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,124, -35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,116, -88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,240,70, -68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,51,132, -9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,105,27, -60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,117,204, -123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,65,112, -152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,39,199, -89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,58,205, -227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,133,18, -2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,39,31,23, -60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,18,84,141, -159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,194,197, -217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,32,130, -166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,151,21,0, -100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,214,111, -31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,10,62, -46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,52, -156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142, -214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173, -165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6, -143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62, -180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129, -54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0, -178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87, -129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104, -201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71, -132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232, -46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35, -193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194, -133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56, -9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14, -134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184, -64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6, -145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67, -77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113, -110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113, -110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2, -127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4, -33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207, -4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,255,255,255,255, -239,127,19,214,33,187,85,2,232,72,0,32,0,0,0,0,0,0,25,136,0,0,0,0,0,0,31, -15,228,122,247,73,19,69,73,180,134,149,13,68,241,0,0,0,0,0,0,3,193,252,143, -90,67,2,104,169,54,144,210,161,168,158,32,0,0,0,0,0,0,120,127,142,73,78,20, -0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68, -13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205, -222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90, -112,164,0,0,0,0,0,0,124,63,226,117,119,128,25,55,112,96,153,57,41,197,13, -53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16, -22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74, -113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104, -97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22, -190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196, -206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208, -76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49, -39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49, -39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112, -163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229, -100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117, -11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68, -157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149, -178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34, -9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62, -49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17, -34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60, -137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248, -199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200, -147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2, -54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56, -7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49, -89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0, -131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217, -231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232, -228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19, -235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1, -64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93, -168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20, -19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,0,0,0,0,93,105,160,91, -60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168, -110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115, -36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145, -139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166, -28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145, -92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41, -100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177, -69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99, -68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9, -49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20, -98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36, -249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242, -136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229, -16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39, -194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68, -89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,104,71,161,196,201,45,167,146,59, -68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,136,71,161,196,201,45,167,146, -59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,168,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,200,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,232,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,8,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,40,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,72,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135,52,102,32,76,72,1,246,136,235, -103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91, -171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13, -158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1, -246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161, -37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79, -75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112, -39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186, -129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237, -17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134, -207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134, -207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38, -78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213, -146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39, -104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208, -146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16, -217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101, -162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201, -77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68, -117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104, -162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123, -102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160, -72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32, -52,171,138,69,133,95,130,160,4,234,219,163,161,0,89,86,214,238,197,172,9,0, -31,86,221,40,29,231,63,95,200,69,220,199,225,122,183,27,72,144,63,160,138, -217,81,197,125,207,195,117,110,54,142,129,32,7,114,147,10,189,229,237,159, -130,235,209,0,96,181,17,83,236,132,37,0,63,101,8,207,71,107,74,6,105,219, -251,52,245,7,49,248,94,202,17,158,148,12,211,183,246,105,234,15,99,242,159, -129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160, -192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152, -27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163, -32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72, -188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29, -13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205, -72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80, -81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128, -153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9, -128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203, -164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113, -120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17, -16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94, -100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14, -108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7, -10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227, -138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43, -80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178, -48,141,156,0,0,0,0,0,0,15,3,243,49,135,16,143,67,137,146,91,79,36,118,136, -178,48,141,156,0,0,0,0,0,0,15,3,245,20,5,173,194,227,214,4,55,0,0,21,196,7, -122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180, -69,145,132,108,224,0,0,0,0,0,0,120,31,153,140,72,132,122,28,76,146,218,121, -35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,80,132,122,28,76,146,218, -121,35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,88,132,122,28,76,146, -218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,96,132,122,28,76, -146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,104,132,122, -28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,112, -132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,16,32,16, -113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224, -104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131, -165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3, -154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232, -147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0, -}; -#elif defined(DUK_USE_DOUBLE_BE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = { -144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242, -252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33, -167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228, -64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46, -142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240, -242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0, -1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, -33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17, -13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192, -0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188, -0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85, -217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225, -146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,1,255, -224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1,172,19,120,71,10,25,196, -136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58, -2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58, -130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180, -138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46, -190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207, -53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94, -124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37, -116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20, -240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153, -51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238, -105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129, -117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0, -65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49, -39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62, -58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129, -133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13, -39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95, -18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37, -194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151, -32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72, -151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113, -214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226, -10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84, -52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142, -214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173, -165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6, -143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62, -180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129, -54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0, -178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87, -129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104, -201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71, -132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232, -46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35, -193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194, -133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56, -9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14, -134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184, -64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6, -145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67, -77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113, -110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113, -110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2, -127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4, -33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207, -4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,127,239,255,255,255,255, -255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,0,0,0,57,136,15,255,0,0,0,0,0, -0,4,122,247,73,19,69,73,180,134,149,13,68,241,1,255,192,0,0,0,0,0,0,143,90, -67,2,104,169,54,144,210,161,168,158,32,127,248,0,0,0,0,0,0,14,73,78,20,0,0, -0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,13, -155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,222, -17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,112, -164,63,252,0,0,0,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,53,224, -65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,22,78, -12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,113,67, -77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,97,47, -128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,190, -96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,206, -185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,76, -150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,39, -195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,39, -198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,163, -18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,100,40, -15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,11,90, -36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,157,160, -3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,178,166, -74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,9,205, -28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,49,13, -164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,34,79, -135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,137,62, -12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,199,54, -103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,147,225, -104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,54,223, -224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,7,38, -193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,89, -252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,131, -64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,231, -197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,228, -74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,235,1, -64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,64, -174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,168, -167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,19, -177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,32,105,221,0,0,0,0,0,91,60, -149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,110, -20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,36,14, -100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,139, -163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,28,1, -204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,92, -203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,100, -73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,69, -49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,68, -152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,49, -39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,98, -79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,249, -68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,136, -108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,16, -217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,194, -173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,89,24, -70,206,1,255,128,0,0,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,68,89, -24,70,206,1,255,128,0,0,0,0,0,1,153,51,136,71,161,196,201,45,167,146,59,68, -89,24,70,206,1,255,128,0,0,0,0,0,1,153,51,168,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,200,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,232,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,8,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,40,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,72,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,1,0,0,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,103, -177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37, -20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142, -183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136, -235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20, -138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161, -37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208, -146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89, -58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214, -207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207, -161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207, -98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78, -209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146, -155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104, -142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146, -155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217, -233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162, -137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77, -156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117, -179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162, -100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,102, -53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,72, -16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,32,2, -223,133,69,138,43,180,132,234,219,163,161,1,0,9,174,198,238,213,84,88,31, -86,221,40,7,252,197,200,95,223,71,61,225,122,183,27,72,144,15,253,197,81, -217,74,224,191,131,117,110,54,142,129,32,31,237,229,189,138,147,114,135,2, -235,209,1,0,36,135,237,81,16,180,96,63,101,8,207,71,107,74,1,255,53,4,243, -51,249,222,104,94,202,17,158,148,3,255,106,9,230,103,243,188,210,159,129, -228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,192,25, -106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,27,165, -171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,32,24, -157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,188,8, -134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,13,65, -74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,72,1, -98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,81, -129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,153, -78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,128,0, -10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,164,237, -35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,120,96, -196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,16,113, -137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,100,108, -144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,108,185, -36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,10,4,28, -200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,138,89, -18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,80,17,42, -4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,48,141,156, -3,255,0,0,0,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,178,48,141, -156,3,255,0,0,0,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,122,192,134, -241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,69,145,132, -108,224,31,248,0,0,0,0,0,0,25,140,72,132,122,28,76,146,218,121,35,180,69, -145,132,108,224,32,0,0,0,0,0,0,0,25,140,80,132,122,28,76,146,218,121,35, -180,69,145,132,108,224,32,0,0,0,0,0,0,0,25,140,88,132,122,28,76,146,218, -121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,96,132,122,28,76,146, -218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,104,132,122,28, -76,146,218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,112,132, -122,28,76,146,218,121,35,180,69,145,132,108,224,32,16,0,0,0,0,0,0,16,113, -225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,104, -82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,165, -1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,154, -102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,147, -161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0, -}; -#elif defined(DUK_USE_DOUBLE_ME) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = { -144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242, -252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33, -167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228, -64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46, -142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240, -242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0, -1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, -33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17, -13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192, -0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188, -0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85, -217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225, -146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,3, -225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1,172,19,120,71,10,25,196, -136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58, -2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58, -130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180, -138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46, -190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207, -53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94, -124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37, -116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20, -240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153, -51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238, -105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129, -117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0, -65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49, -39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62, -58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129, -133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13, -39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95, -18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37, -194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151, -32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72, -151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113, -214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226, -10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84, -52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142, -214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173, -165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6, -143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62, -180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129, -54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0, -178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87, -129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104, -201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71, -132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232, -46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35, -193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194, -133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56, -9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14, -134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184, -64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6, -145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67, -77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113, -110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113, -110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2, -127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4, -33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207, -4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,239,127,255,255, -255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,32,0,0,25,136,0,0,31,15,224,0, -0,0,4,122,247,73,19,69,73,180,134,149,13,68,241,0,0,3,193,252,0,0,0,0,143, -90,67,2,104,169,54,144,210,161,168,158,32,0,0,120,127,128,0,0,0,14,73,78, -20,0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247, -68,13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205, -222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90, -112,164,0,0,124,63,128,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13, -53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16, -22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74, -113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104, -97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22, -190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196, -206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208, -76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49, -39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49, -39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112, -163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229, -100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117, -11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68, -157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149, -178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34, -9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62, -49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17, -34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60, -137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248, -199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200, -147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2, -54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56, -7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49, -89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0, -131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217, -231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232, -228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19, -235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1, -64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93, -168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20, -19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,93,105,160,0,0,0,0,91, -60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168, -110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115, -36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145, -139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166, -28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145, -92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41, -100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177, -69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99, -68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9, -49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20, -98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36, -249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242, -136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229, -16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39, -194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68, -89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59, -68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,136,71,161,196,201,45,167,146, -59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,168,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,200,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,232,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,8,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,40,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,72,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235, -103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91, -171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13, -158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1, -246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161, -37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79, -75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112, -39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186, -129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237, -17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134, -207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134, -207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38, -78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213, -146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39, -104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208, -146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16, -217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101, -162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201, -77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68, -117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104, -162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123, -102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160, -72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,5, -95,130,160,52,171,138,69,132,234,219,163,161,2,197,172,9,0,89,86,214,236, -31,86,221,40,8,69,220,199,253,231,63,95,193,122,183,27,72,144,17,197,125, -207,255,160,138,217,67,117,110,54,142,129,32,61,229,237,159,135,114,147,10, -130,235,209,3,236,132,37,0,96,181,17,80,63,101,8,207,71,107,74,4,245,7,49, -254,105,219,251,48,94,202,17,158,148,9,234,15,99,252,211,183,246,98,159, -129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160, -192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152, -27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163, -32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72, -188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29, -13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205, -72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80, -81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128, -153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9, -128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203, -164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113, -120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17, -16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94, -100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14, -108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7, -10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227, -138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43, -80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178, -48,141,156,0,0,15,3,240,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136, -178,48,141,156,0,0,15,3,240,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7, -122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180, -69,145,132,108,224,0,0,120,31,128,0,0,0,25,140,72,132,122,28,76,146,218, -121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,80,132,122,28,76,146, -218,121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,88,132,122,28,76, -146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,96,132,122, -28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,104, -132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25, -140,112,132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,16,32,0,0, -0,0,16,113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33, -18,224,104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80, -70,131,165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73, -7,78,3,154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154, -232,147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0, -}; -#else -#error invalid endianness defines -#endif -#endif /* DUK_USE_ROM_OBJECTS */ - -/* automatic undefs */ -#undef DUK__REFCINIT -#line 1 "duk_error_macros.c" -/* - * Error and fatal handling. - */ - -/* #include duk_internal.h -> already included */ - -#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */ - -#if defined(DUK_USE_VERBOSE_ERRORS) - -DUK_INTERNAL DUK_COLD void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) { - va_list ap; - char msg[DUK__ERRFMT_BUFSIZE]; - va_start(ap, fmt); - (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap); - msg[sizeof(msg) - 1] = (char) 0; - duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL)); - va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */ -} - -DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) { - duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL)); -} - -#else /* DUK_USE_VERBOSE_ERRORS */ - -DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { - duk_err_create_and_throw(thr, code); -} - -#endif /* DUK_USE_VERBOSE_ERRORS */ - -/* - * Error throwing helpers - */ - -#if defined(DUK_USE_VERBOSE_ERRORS) -#if defined(DUK_USE_PARANOID_ERRORS) -DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) { - DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)", - expect_name, duk_get_type_name(thr, idx), (long) idx); -} -#else -DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) { - DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)", - expect_name, duk_push_string_readable(thr, idx), (long) idx); -} -#endif -DUK_INTERNAL DUK_COLD void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR); -} -DUK_INTERNAL DUK_COLD void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED); -} -DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message); -} -DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message); -} -DUK_INTERNAL DUK_COLD void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) { - DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld", (long) (idx)); -} -DUK_INTERNAL DUK_COLD void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); -} -DUK_INTERNAL DUK_COLD void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS); -} -DUK_INTERNAL DUK_COLD void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE); -} -DUK_INTERNAL DUK_COLD void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT); -} -#else -/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW() - * when non-verbose errors are used. - */ - -DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_errcode_t code)); -DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_errcode_t code) { - DUK_ERROR_RAW(thr, NULL, 0, code, NULL); -} -DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) { - duk__err_shared(thr, DUK_ERR_ERROR); -} -DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) { - duk__err_shared(thr, DUK_ERR_RANGE_ERROR); -} -DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) { - duk__err_shared(thr, DUK_ERR_EVAL_ERROR); -} -DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) { - duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR); -} -DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) { - duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR); -} -DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) { - duk__err_shared(thr, DUK_ERR_TYPE_ERROR); -} -DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) { - duk__err_shared(thr, DUK_ERR_URI_ERROR); -} -#endif - -/* - * Default fatal error handler - */ - -DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) { - DUK_UNREF(udata); - DUK_UNREF(msg); - -#if defined(DUK_USE_FATAL_HANDLER) - /* duk_config.h provided a custom default fatal handler. */ - DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg ? msg : "NULL")); - DUK_USE_FATAL_HANDLER(udata, msg); -#else - /* Default behavior is to abort() on error. There's no printout - * which makes this awkward, so it's always recommended to use an - * explicit fatal error handler. - * - * ==================================================================== - * NOTE: If you are seeing this, you are most likely dealing with an - * uncaught error. You should provide a fatal error handler in Duktape - * heap creation, and should consider using a protected call as your - * first call into an empty Duktape context to properly handle errors. - * See: - * - http://duktape.org/guide.html#error-handling - * - http://wiki.duktape.org/HowtoFatalErrors.html - * - http://duktape.org/api.html#taglist-protected - * ==================================================================== - */ - DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg ? msg : "NULL")); - DUK_ABORT(); -#endif - - DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop")); - for (;;) { - /* Loop forever to ensure we don't return. */ - } -} - -/* automatic undefs */ -#undef DUK__ERRFMT_BUFSIZE -#line 1 "duk_unicode_support.c" -/* - * Various Unicode help functions for character classification predicates, - * case conversion, decoding, etc. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Fast path tables - */ - -#if defined(DUK_USE_IDCHAR_FASTPATH) -DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = { - /* 0: not IdentifierStart or IdentifierPart - * 1: IdentifierStart and IdentifierPart - * -1: IdentifierPart only - */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00...0x0f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10...0x1f */ - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20...0x2f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, /* 0x30...0x3f */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40...0x4f */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50...0x5f */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60...0x6f */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70...0x7f */ -}; -#endif - -/* - * XUTF-8 and CESU-8 encoding/decoding - */ - -DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) { - duk_uint_fast32_t x = (duk_uint_fast32_t) cp; - if (x < 0x80UL) { - /* 7 bits */ - return 1; - } else if (x < 0x800UL) { - /* 11 bits */ - return 2; - } else if (x < 0x10000UL) { - /* 16 bits */ - return 3; - } else if (x < 0x200000UL) { - /* 21 bits */ - return 4; - } else if (x < 0x4000000UL) { - /* 26 bits */ - return 5; - } else if (x < (duk_ucodepoint_t) 0x80000000UL) { - /* 31 bits */ - return 6; - } else { - /* 36 bits */ - return 7; - } -} - -#if defined(DUK_USE_ASSERTIONS) -DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) { - duk_uint_fast32_t x = (duk_uint_fast32_t) cp; - if (x < 0x80UL) { - /* 7 bits */ - return 1; - } else if (x < 0x800UL) { - /* 11 bits */ - return 2; - } else if (x < 0x10000UL) { - /* 16 bits */ - return 3; - } else { - /* Encoded as surrogate pair, each encoding to 3 bytes for - * 6 bytes total. Codepoints above U+10FFFF encode as 6 bytes - * too, see duk_unicode_encode_cesu8(). - */ - return 3 + 3; - } -} -#endif /* DUK_USE_ASSERTIONS */ - -DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = { - 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe -}; - -/* Encode to extended UTF-8; 'out' must have space for at least - * DUK_UNICODE_MAX_XUTF8_LENGTH bytes. Allows encoding of any - * 32-bit (unsigned) codepoint. - */ -DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) { - duk_uint_fast32_t x = (duk_uint_fast32_t) cp; - duk_small_int_t len; - duk_uint8_t marker; - duk_small_int_t i; - - len = duk_unicode_get_xutf8_length(cp); - DUK_ASSERT(len > 0); - - marker = duk_unicode_xutf8_markers[len - 1]; /* 64-bit OK because always >= 0 */ - - i = len; - DUK_ASSERT(i > 0); - do { - i--; - if (i > 0) { - out[i] = (duk_uint8_t) (0x80 + (x & 0x3f)); - x >>= 6; - } else { - /* Note: masking of 'x' is not necessary because of - * range check and shifting -> no bits overlapping - * the marker should be set. - */ - out[0] = (duk_uint8_t) (marker + x); - } - } while (i > 0); - - return len; -} - -/* Encode to CESU-8; 'out' must have space for at least - * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF - * will encode to garbage but won't overwrite the output buffer. - */ -DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) { - duk_uint_fast32_t x = (duk_uint_fast32_t) cp; - duk_small_int_t len; - - if (x < 0x80UL) { - out[0] = (duk_uint8_t) x; - len = 1; - } else if (x < 0x800UL) { - out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f)); - out[1] = (duk_uint8_t) (0x80 + (x & 0x3f)); - len = 2; - } else if (x < 0x10000UL) { - /* surrogate pairs get encoded here */ - out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f)); - out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f)); - out[2] = (duk_uint8_t) (0x80 + (x & 0x3f)); - len = 3; - } else { - /* - * Unicode codepoints above U+FFFF are encoded as surrogate - * pairs here. This ensures that all CESU-8 codepoints are - * 16-bit values as expected in Ecmascript. The surrogate - * pairs always get a 3-byte encoding (each) in CESU-8. - * See: http://en.wikipedia.org/wiki/Surrogate_pair - * - * 20-bit codepoint, 10 bits (A and B) per surrogate pair: - * - * x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB - * sp1 = 0b110110AA AAAAAAAA (0xd800 + ((x >> 10) & 0x3ff)) - * sp2 = 0b110111BB BBBBBBBB (0xdc00 + (x & 0x3ff)) - * - * Encoded into CESU-8: - * - * sp1 -> 0b11101101 (0xe0 + ((sp1 >> 12) & 0x0f)) - * -> 0b1010AAAA (0x80 + ((sp1 >> 6) & 0x3f)) - * -> 0b10AAAAAA (0x80 + (sp1 & 0x3f)) - * sp2 -> 0b11101101 (0xe0 + ((sp2 >> 12) & 0x0f)) - * -> 0b1011BBBB (0x80 + ((sp2 >> 6) & 0x3f)) - * -> 0b10BBBBBB (0x80 + (sp2 & 0x3f)) - * - * Note that 0x10000 must be subtracted first. The code below - * avoids the sp1, sp2 temporaries which saves around 20 bytes - * of code. - */ - - x -= 0x10000UL; - - out[0] = (duk_uint8_t) (0xed); - out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f)); - out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f)); - out[3] = (duk_uint8_t) (0xed); - out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f)); - out[5] = (duk_uint8_t) (0x80 + (x & 0x3f)); - len = 6; - } - - return len; -} - -/* Decode helper. Return zero on error. */ -DUK_INTERNAL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp) { - const duk_uint8_t *p; - duk_uint32_t res; - duk_uint_fast8_t ch; - duk_small_int_t n; - - DUK_UNREF(thr); - - p = *ptr; - if (p < ptr_start || p >= ptr_end) { - goto fail; - } - - /* - * UTF-8 decoder which accepts longer than standard byte sequences. - * This allows full 32-bit code points to be used. - */ - - ch = (duk_uint_fast8_t) (*p++); - if (ch < 0x80) { - /* 0xxx xxxx [7 bits] */ - res = (duk_uint32_t) (ch & 0x7f); - n = 0; - } else if (ch < 0xc0) { - /* 10xx xxxx -> invalid */ - goto fail; - } else if (ch < 0xe0) { - /* 110x xxxx 10xx xxxx [11 bits] */ - res = (duk_uint32_t) (ch & 0x1f); - n = 1; - } else if (ch < 0xf0) { - /* 1110 xxxx 10xx xxxx 10xx xxxx [16 bits] */ - res = (duk_uint32_t) (ch & 0x0f); - n = 2; - } else if (ch < 0xf8) { - /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx [21 bits] */ - res = (duk_uint32_t) (ch & 0x07); - n = 3; - } else if (ch < 0xfc) { - /* 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [26 bits] */ - res = (duk_uint32_t) (ch & 0x03); - n = 4; - } else if (ch < 0xfe) { - /* 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [31 bits] */ - res = (duk_uint32_t) (ch & 0x01); - n = 5; - } else if (ch < 0xff) { - /* 1111 1110 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [36 bits] */ - res = (duk_uint32_t) (0); - n = 6; - } else { - /* 8-byte format could be: - * 1111 1111 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [41 bits] - * - * However, this format would not have a zero bit following the - * leading one bits and would not allow 0xFF to be used as an - * "invalid xutf-8" marker for internal keys. Further, 8-byte - * encodings (up to 41 bit code points) are not currently needed. - */ - goto fail; - } - - DUK_ASSERT(p >= ptr_start); /* verified at beginning */ - if (p + n > ptr_end) { - /* check pointer at end */ - goto fail; - } - - while (n > 0) { - DUK_ASSERT(p >= ptr_start && p < ptr_end); - ch = (duk_uint_fast8_t) (*p++); -#if 0 - if (ch & 0xc0 != 0x80) { - /* not a continuation byte */ - p--; - *ptr = p; - *out_cp = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; - return 1; - } -#endif - res = (res << 6) + (duk_uint32_t) (ch & 0x3f); - n--; - } - - *ptr = p; - *out_cp = res; - return 1; - - fail: - return 0; -} - -/* used by e.g. duk_regexp_executor.c, string built-ins */ -DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end) { - duk_ucodepoint_t cp; - - if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) { - return cp; - } - DUK_ERROR_INTERNAL(thr); - DUK_UNREACHABLE(); - return 0; -} - -/* Compute (extended) utf-8 length without codepoint encoding validation, - * used for string interning. - * - * NOTE: This algorithm is performance critical, more so than string hashing - * in some cases. It is needed when interning a string and needs to scan - * every byte of the string with no skipping. Having an ASCII fast path - * is useful if possible in the algorithm. The current algorithms were - * chosen from several variants, based on x64 gcc -O2 testing. See: - * https://github.com/svaarala/duktape/pull/422 - * - * NOTE: must match tools/dukutil.py:duk_unicode_unvalidated_utf8_length(). - */ - -#if defined(DUK_USE_PREFER_SIZE) -/* Small variant; roughly 150 bytes smaller than the fast variant. */ -DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) { - const duk_uint8_t *p; - const duk_uint8_t *p_end; - duk_size_t ncont; - duk_size_t clen; - - p = data; - p_end = data + blen; - ncont = 0; - while (p != p_end) { - duk_uint8_t x; - x = *p++; - if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { - ncont++; - } - } - - DUK_ASSERT(ncont <= blen); - clen = blen - ncont; - DUK_ASSERT(clen <= blen); - return clen; -} -#else /* DUK_USE_PREFER_SIZE */ -/* This seems like a good overall approach. Fast path for ASCII in 4 byte - * blocks. - */ -DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) { - const duk_uint8_t *p; - const duk_uint8_t *p_end; - const duk_uint32_t *p32_end; - const duk_uint32_t *p32; - duk_size_t ncont; - duk_size_t clen; - - ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */ - p = data; - p_end = data + blen; - if (blen < 16) { - goto skip_fastpath; - } - - /* Align 'p' to 4; the input data may have arbitrary alignment. - * End of string check not needed because blen >= 16. - */ - while (((duk_size_t) (const void *) p) & 0x03U) { - duk_uint8_t x; - x = *p++; - if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { - ncont++; - } - } - - /* Full, aligned 4-byte reads. */ - p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03))); - p32 = (const duk_uint32_t *) (const void *) p; - while (p32 != (const duk_uint32_t *) p32_end) { - duk_uint32_t x; - x = *p32++; - if (DUK_LIKELY((x & 0x80808080UL) == 0)) { - ; /* ASCII fast path */ - } else { - /* Flip highest bit of each byte which changes - * the bit pattern 10xxxxxx into 00xxxxxx which - * allows an easy bit mask test. - */ - x ^= 0x80808080UL; - if (DUK_UNLIKELY(!(x & 0xc0000000UL))) { - ncont++; - } - if (DUK_UNLIKELY(!(x & 0x00c00000UL))) { - ncont++; - } - if (DUK_UNLIKELY(!(x & 0x0000c000UL))) { - ncont++; - } - if (DUK_UNLIKELY(!(x & 0x000000c0UL))) { - ncont++; - } - } - } - p = (const duk_uint8_t *) p32; - /* Fall through to handle the rest. */ - - skip_fastpath: - while (p != p_end) { - duk_uint8_t x; - x = *p++; - if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { - ncont++; - } - } - - DUK_ASSERT(ncont <= blen); - clen = blen - ncont; - DUK_ASSERT(clen <= blen); - return clen; -} -#endif /* DUK_USE_PREFER_SIZE */ - -/* - * Unicode range matcher - * - * Matches a codepoint against a packed bitstream of character ranges. - * Used for slow path Unicode matching. - */ - -/* Must match tools/extract_chars.py, generate_match_table3(). */ -DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) { - duk_uint32_t t; - - t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4); - if (t <= 0x0eU) { - return t; - } - t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8); - if (t <= 0xfdU) { - return t + 0x0f; - } - if (t == 0xfeU) { - t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12); - return t + 0x0fU + 0xfeU; - } else { - t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24); - return t + 0x0fU + 0xfeU + 0x1000UL; - } -} - -DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) { - duk_bitdecoder_ctx bd_ctx; - duk_codepoint_t prev_re; - - DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); - bd_ctx.data = (const duk_uint8_t *) unitab; - bd_ctx.length = (duk_size_t) unilen; - - prev_re = 0; - for (;;) { - duk_codepoint_t r1, r2; - r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx); - if (r1 == 0) { - break; - } - r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx); - - r1 = prev_re + r1; - r2 = r1 + r2; - prev_re = r2; - - /* [r1,r2] is the range */ - - DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]", - (unsigned long) cp, (unsigned long) r1, (unsigned long) r2)); - if (cp >= r1 && cp <= r2) { - return 1; - } - } - - return 0; -} - -/* - * "WhiteSpace" production check. - */ - -DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) { - /* - * E5 Section 7.2 specifies six characters specifically as - * white space: - * - * 0009;;Cc;0;S;;;;;N;CHARACTER TABULATION;;;; - * 000B;;Cc;0;S;;;;;N;LINE TABULATION;;;; - * 000C;;Cc;0;WS;;;;;N;FORM FEED (FF);;;; - * 0020;SPACE;Zs;0;WS;;;;;N;;;;; - * 00A0;NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;NON-BREAKING SPACE;;;; - * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; - * - * It also specifies any Unicode category 'Zs' characters as white - * space. These can be extracted with the "tools/extract_chars.py" script. - * Current result: - * - * RAW OUTPUT: - * =========== - * 0020;SPACE;Zs;0;WS;;;;;N;;;;; - * 00A0;NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;NON-BREAKING SPACE;;;; - * 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; - * 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;; - * 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; - * 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; - * 2002;EN SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 2003;EM SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 2004;THREE-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 2005;FOUR-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 2006;SIX-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 2007;FIGURE SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 2008;PUNCTUATION SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 2009;THIN SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 200A;HAIR SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 202F;NARROW NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;;;;; - * 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS; 0020;;;;N;;;;; - * 3000;IDEOGRAPHIC SPACE;Zs;0;WS; 0020;;;;N;;;;; - * - * RANGES: - * ======= - * 0x0020 - * 0x00a0 - * 0x1680 - * 0x180e - * 0x2000 ... 0x200a - * 0x202f - * 0x205f - * 0x3000 - * - * A manual decoder (below) is probably most compact for this. - */ - - duk_uint_fast8_t lo; - duk_uint_fast32_t hi; - - /* cp == -1 (EOF) never matches and causes return value 0 */ - - lo = (duk_uint_fast8_t) (cp & 0xff); - hi = (duk_uint_fast32_t) (cp >> 8); /* does not fit into an uchar */ - - if (hi == 0x0000UL) { - if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU || - lo == 0x20U || lo == 0xa0U) { - return 1; - } - } else if (hi == 0x0020UL) { - if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) { - return 1; - } - } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L || - cp == 0xfeffL) { - return 1; - } - - return 0; -} - -/* - * "LineTerminator" production check. - */ - -DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) { - /* - * E5 Section 7.3 - * - * A LineTerminatorSequence essentially merges sequences - * into a single line terminator. This must be handled by the caller. - */ - - if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L || - cp == 0x2029L) { - return 1; - } - - return 0; -} - -/* - * "IdentifierStart" production check. - */ - -DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) { - /* - * E5 Section 7.6: - * - * IdentifierStart: - * UnicodeLetter - * $ - * _ - * \ UnicodeEscapeSequence - * - * IdentifierStart production has one multi-character production: - * - * \ UnicodeEscapeSequence - * - * The '\' character is -not- matched by this function. Rather, the caller - * should decode the escape and then call this function to check whether the - * decoded character is acceptable (see discussion in E5 Section 7.6). - * - * The "UnicodeLetter" alternative of the production allows letters - * from various Unicode categories. These can be extracted with the - * "tools/extract_chars.py" script. - * - * Because the result has hundreds of Unicode codepoint ranges, matching - * for any values >= 0x80 are done using a very slow range-by-range scan - * and a packed range format. - * - * The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because - * it matters the most. The ASCII related ranges of IdentifierStart are: - * - * 0x0041 ... 0x005a ['A' ... 'Z'] - * 0x0061 ... 0x007a ['a' ... 'z'] - * 0x0024 ['$'] - * 0x005f ['_'] - */ - - /* ASCII (and EOF) fast path -- quick accept and reject */ - if (cp <= 0x7fL) { -#if defined(DUK_USE_IDCHAR_FASTPATH) - return (cp >= 0) && (duk_is_idchar_tab[cp] > 0); -#else - if ((cp >= 'a' && cp <= 'z') || - (cp >= 'A' && cp <= 'Z') || - cp == '_' || cp == '$') { - return 1; - } - return 0; -#endif - } - - /* Non-ASCII slow path (range-by-range linear comparison), very slow */ - -#if defined(DUK_USE_SOURCE_NONBMP) - if (duk__uni_range_match(duk_unicode_ids_noa, - (duk_size_t) sizeof(duk_unicode_ids_noa), - (duk_codepoint_t) cp)) { - return 1; - } - return 0; -#else - if (cp < 0x10000L) { - if (duk__uni_range_match(duk_unicode_ids_noabmp, - sizeof(duk_unicode_ids_noabmp), - (duk_codepoint_t) cp)) { - return 1; - } - return 0; - } else { - /* without explicit non-BMP support, assume non-BMP characters - * are always accepted as identifier characters. - */ - return 1; - } -#endif -} - -/* - * "IdentifierPart" production check. - */ - -DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) { - /* - * E5 Section 7.6: - * - * IdentifierPart: - * IdentifierStart - * UnicodeCombiningMark - * UnicodeDigit - * UnicodeConnectorPunctuation - * [U+200C] - * [U+200D] - * - * IdentifierPart production has one multi-character production - * as part of its IdentifierStart alternative. The '\' character - * of an escape sequence is not matched here, see discussion in - * duk_unicode_is_identifier_start(). - * - * To match non-ASCII characters (codepoints >= 0x80), a very slow - * linear range-by-range scan is used. The codepoint is first compared - * to the IdentifierStart ranges, and if it doesn't match, then to a - * set consisting of code points in IdentifierPart but not in - * IdentifierStart. This is done to keep the unicode range data small, - * at the expense of speed. - * - * The ASCII fast path consists of: - * - * 0x0030 ... 0x0039 ['0' ... '9', UnicodeDigit] - * 0x0041 ... 0x005a ['A' ... 'Z', IdentifierStart] - * 0x0061 ... 0x007a ['a' ... 'z', IdentifierStart] - * 0x0024 ['$', IdentifierStart] - * 0x005f ['_', IdentifierStart and - * UnicodeConnectorPunctuation] - * - * UnicodeCombiningMark has no code points <= 0x7f. - * - * The matching code reuses the "identifier start" tables, and then - * consults a separate range set for characters in "identifier part" - * but not in "identifier start". These can be extracted with the - * "tools/extract_chars.py" script. - * - * UnicodeCombiningMark -> categories Mn, Mc - * UnicodeDigit -> categories Nd - * UnicodeConnectorPunctuation -> categories Pc - */ - - /* ASCII (and EOF) fast path -- quick accept and reject */ - if (cp <= 0x7fL) { -#if defined(DUK_USE_IDCHAR_FASTPATH) - return (cp >= 0) && (duk_is_idchar_tab[cp] != 0); -#else - if ((cp >= 'a' && cp <= 'z') || - (cp >= 'A' && cp <= 'Z') || - (cp >= '0' && cp <= '9') || - cp == '_' || cp == '$') { - return 1; - } - return 0; -#endif - } - - /* Non-ASCII slow path (range-by-range linear comparison), very slow */ - -#if defined(DUK_USE_SOURCE_NONBMP) - if (duk__uni_range_match(duk_unicode_ids_noa, - sizeof(duk_unicode_ids_noa), - (duk_codepoint_t) cp) || - duk__uni_range_match(duk_unicode_idp_m_ids_noa, - sizeof(duk_unicode_idp_m_ids_noa), - (duk_codepoint_t) cp)) { - return 1; - } - return 0; -#else - if (cp < 0x10000L) { - if (duk__uni_range_match(duk_unicode_ids_noabmp, - sizeof(duk_unicode_ids_noabmp), - (duk_codepoint_t) cp) || - duk__uni_range_match(duk_unicode_idp_m_ids_noabmp, - sizeof(duk_unicode_idp_m_ids_noabmp), - (duk_codepoint_t) cp)) { - return 1; - } - return 0; - } else { - /* without explicit non-BMP support, assume non-BMP characters - * are always accepted as identifier characters. - */ - return 1; - } -#endif -} - -/* - * Unicode letter check. - */ - -DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) { - /* - * Unicode letter is now taken to be the categories: - * - * Lu, Ll, Lt, Lm, Lo - * - * (Not sure if this is exactly correct.) - * - * The ASCII fast path consists of: - * - * 0x0041 ... 0x005a ['A' ... 'Z'] - * 0x0061 ... 0x007a ['a' ... 'z'] - */ - - /* ASCII (and EOF) fast path -- quick accept and reject */ - if (cp <= 0x7fL) { - if ((cp >= 'a' && cp <= 'z') || - (cp >= 'A' && cp <= 'Z')) { - return 1; - } - return 0; - } - - /* Non-ASCII slow path (range-by-range linear comparison), very slow */ - -#if defined(DUK_USE_SOURCE_NONBMP) - if (duk__uni_range_match(duk_unicode_ids_noa, - sizeof(duk_unicode_ids_noa), - (duk_codepoint_t) cp) && - !duk__uni_range_match(duk_unicode_ids_m_let_noa, - sizeof(duk_unicode_ids_m_let_noa), - (duk_codepoint_t) cp)) { - return 1; - } - return 0; -#else - if (cp < 0x10000L) { - if (duk__uni_range_match(duk_unicode_ids_noabmp, - sizeof(duk_unicode_ids_noabmp), - (duk_codepoint_t) cp) && - !duk__uni_range_match(duk_unicode_ids_m_let_noabmp, - sizeof(duk_unicode_ids_m_let_noabmp), - (duk_codepoint_t) cp)) { - return 1; - } - return 0; - } else { - /* without explicit non-BMP support, assume non-BMP characters - * are always accepted as letters. - */ - return 1; - } -#endif -} - -/* - * Complex case conversion helper which decodes a bit-packed conversion - * control stream generated by tools/extract_caseconv.py. The conversion - * is very slow because it runs through the conversion data in a linear - * fashion to save space (which is why ASCII characters have a special - * fast path before arriving here). - * - * The particular bit counts etc have been determined experimentally to - * be small but still sufficient, and must match the Python script - * (tools/extract_caseconv.py). - * - * The return value is the case converted codepoint or -1 if the conversion - * results in multiple characters (this is useful for regexp Canonicalization - * operation). If 'buf' is not NULL, the result codepoint(s) are also - * appended to the hbuffer. - * - * Context and locale specific rules must be checked before consulting - * this function. - */ - -DUK_LOCAL -duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr, - duk_bufwriter_ctx *bw, - duk_codepoint_t cp, - duk_bitdecoder_ctx *bd_ctx) { - duk_small_int_t skip = 0; - duk_small_int_t n; - duk_small_int_t t; - duk_small_int_t count; - duk_codepoint_t tmp_cp; - duk_codepoint_t start_i; - duk_codepoint_t start_o; - - DUK_ASSERT(bd_ctx != NULL); - DUK_UNREF(thr); - - DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp)); - - /* range conversion with a "skip" */ - DUK_DDD(DUK_DDDPRINT("checking ranges")); - for (;;) { - skip++; - n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6); - if (n == 0x3f) { - /* end marker */ - break; - } - DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld", (long) skip, (long) n)); - - while (n--) { - start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); - start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); - count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); - DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld", - (long) start_i, (long) start_o, (long) count, (long) skip)); - - if (cp >= start_i) { - tmp_cp = cp - start_i; /* always >= 0 */ - if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip && - (tmp_cp % (duk_codepoint_t) skip) == 0) { - DUK_DDD(DUK_DDDPRINT("range matches input codepoint")); - cp = start_o + tmp_cp; - goto single; - } - } - } - } - - /* 1:1 conversion */ - n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); - DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n)); - while (n--) { - start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); - start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); - DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld", (long) start_i, (long) start_o)); - if (cp == start_i) { - DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint")); - cp = start_o; - goto single; - } - } - - /* complex, multicharacter conversion */ - n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); - DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)", (long) n)); - while (n--) { - start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); - t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2); - DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars", (long) start_i, (long) t)); - if (cp == start_i) { - DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint")); - if (bw != NULL) { - while (t--) { - tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); - DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp); - } - } - return -1; - } else { - while (t--) { - (void) duk_bd_decode(bd_ctx, 16); - } - } - } - - /* default: no change */ - DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input")); - /* fall through */ - - single: - if (bw != NULL) { - DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp); - } - return cp; -} - -/* - * Case conversion helper, with context/local sensitivity. - * For proper case conversion, one needs to know the character - * and the preceding and following characters, as well as - * locale/language. - */ - -/* XXX: add 'language' argument when locale/language sensitive rule - * support added. - */ -DUK_LOCAL -duk_codepoint_t duk__case_transform_helper(duk_hthread *thr, - duk_bufwriter_ctx *bw, - duk_codepoint_t cp, - duk_codepoint_t prev, - duk_codepoint_t next, - duk_bool_t uppercase) { - duk_bitdecoder_ctx bd_ctx; - - /* fast path for ASCII */ - if (cp < 0x80L) { - /* XXX: there are language sensitive rules for the ASCII range. - * If/when language/locale support is implemented, they need to - * be implemented here for the fast path. There are no context - * sensitive rules for ASCII range. - */ - - if (uppercase) { - if (cp >= 'a' && cp <= 'z') { - cp = cp - 'a' + 'A'; - } - } else { - if (cp >= 'A' && cp <= 'Z') { - cp = cp - 'A' + 'a'; - } - } - - if (bw != NULL) { - DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp); - } - return cp; - } - - /* context and locale specific rules which cannot currently be represented - * in the caseconv bitstream: hardcoded rules in C - */ - if (uppercase) { - /* XXX: turkish / azeri */ - } else { - /* - * Final sigma context specific rule. This is a rather tricky - * rule and this handling is probably not 100% correct now. - * The rule is not locale/language specific so it is supported. - */ - - if (cp == 0x03a3L && /* U+03A3 = GREEK CAPITAL LETTER SIGMA */ - duk_unicode_is_letter(prev) && /* prev exists and is not a letter */ - !duk_unicode_is_letter(next)) { /* next does not exist or next is not a letter */ - /* Capital sigma occurred at "end of word", lowercase to - * U+03C2 = GREEK SMALL LETTER FINAL SIGMA. Otherwise - * fall through and let the normal rules lowercase it to - * U+03C3 = GREEK SMALL LETTER SIGMA. - */ - cp = 0x03c2L; - goto singlechar; - } - - /* XXX: lithuanian not implemented */ - /* XXX: lithuanian, explicit dot rules */ - /* XXX: turkish / azeri, lowercase rules */ - } - - /* 1:1 or special conversions, but not locale/context specific: script generated rules */ - DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); - if (uppercase) { - bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc; - bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc); - } else { - bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc; - bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc); - } - return duk__slow_case_conversion(thr, bw, cp, &bd_ctx); - - singlechar: - if (bw != NULL) { - DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp); - } - return cp; - - /* unused now, not needed until Turkish/Azeri */ -#if 0 - nochar: - return -1; -#endif -} - -/* - * Replace valstack top with case converted version. - */ - -DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase) { - duk_hstring *h_input; - duk_bufwriter_ctx bw_alloc; - duk_bufwriter_ctx *bw; - const duk_uint8_t *p, *p_start, *p_end; - duk_codepoint_t prev, curr, next; - - h_input = duk_require_hstring(thr, -1); /* Accept symbols. */ - DUK_ASSERT(h_input != NULL); - - bw = &bw_alloc; - DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); - - /* [ ... input buffer ] */ - - p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); - p = p_start; - - prev = -1; DUK_UNREF(prev); - curr = -1; - next = -1; - for (;;) { - prev = curr; - curr = next; - next = -1; - if (p < p_end) { - next = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); - } else { - /* end of input and last char has been processed */ - if (curr < 0) { - break; - } - } - - /* on first round, skip */ - if (curr >= 0) { - /* XXX: could add a fast path to process chunks of input codepoints, - * but relative benefit would be quite small. - */ - - /* Ensure space for maximum multi-character result; estimate is overkill. */ - DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH); - - duk__case_transform_helper(thr, - bw, - (duk_codepoint_t) curr, - prev, - next, - uppercase); - } - } - - DUK_BW_COMPACT(thr, bw); - (void) duk_buffer_to_string(thr, -1); /* Safe, output is encoded. */ - /* invalidates h_buf pointer */ - duk_remove_m2(thr); -} - -#if defined(DUK_USE_REGEXP_SUPPORT) - -/* - * Canonicalize() abstract operation needed for canonicalization of individual - * codepoints during regexp compilation and execution, see E5 Section 15.10.2.8. - * Note that codepoints are canonicalized one character at a time, so no context - * specific rules can apply. Locale specific rules can apply, though. - */ - -DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) { -#if defined(DUK_USE_REGEXP_CANON_WORKAROUND) - /* Fast canonicalization lookup at the cost of 128kB footprint. */ - DUK_ASSERT(cp >= 0); - DUK_UNREF(thr); - if (DUK_LIKELY(cp < 0x10000L)) { - return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp]; - } - return cp; -#else /* DUK_USE_REGEXP_CANON_WORKAROUND */ - duk_codepoint_t y; - - y = duk__case_transform_helper(thr, - NULL, /* NULL is allowed, no output */ - cp, /* curr char */ - -1, /* prev char */ - -1, /* next char */ - 1); /* uppercase */ - - if ((y < 0) || (cp >= 0x80 && y < 0x80)) { - /* multiple codepoint conversion or non-ASCII mapped to ASCII - * --> leave as is. - */ - return cp; - } - - return y; -#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */ -} - -/* - * E5 Section 15.10.2.6 "IsWordChar" abstract operation. Assume - * x < 0 for characters read outside the string. - */ - -DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) { - /* - * Note: the description in E5 Section 15.10.2.6 has a typo, it - * contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_]. - */ - if ((x >= '0' && x <= '9') || - (x >= 'a' && x <= 'z') || - (x >= 'A' && x <= 'Z') || - (x == '_')) { - return 1; - } - return 0; -} - -/* - * Regexp range tables - */ - -/* exposed because lexer needs these too */ -DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = { - (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL, -}; -DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = { - (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL, - (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL, - (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL, - (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL, - (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL, - (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL, - (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL, - (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL, - (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL, - (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL, - (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL, -}; -DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = { - (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL, - (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL, - (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL, - (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL, -}; -DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = { - (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL, - (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL, -}; -DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = { - (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL, - (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL, - (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL, - (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL, - (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL, - (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL, - (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL, - (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL, - (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL, - (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL, - (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL, - (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL, -}; -DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = { - (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL, - (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL, - (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL, - (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL, - (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL, -}; - -#endif /* DUK_USE_REGEXP_SUPPORT */ -#line 1 "duk_util_misc.c" -/* - * Misc util stuff - */ - -/* #include duk_internal.h -> already included */ - -/* - * Lowercase digits for radix values 2 to 36. Also doubles as lowercase - * hex nybble table. - */ - -DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = { - DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, - DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, - DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B, - DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F, - DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J, - DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N, - DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R, - DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V, - DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z -}; - -DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = { - DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, - DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, - DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B, - DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F -}; - -/* - * Table for hex decoding ASCII hex digits - */ - -DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = { - /* -1 if invalid */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */ - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */ - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */ -}; - -#if defined(DUK_USE_HEX_FASTPATH) -/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */ -DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */ - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */ - -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */ - -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */ -}; -#endif - -/* - * Table for hex encoding bytes - */ - -#if defined(DUK_USE_HEX_FASTPATH) -/* Lookup to encode one byte directly into 2 characters: - * - * def genhextab(bswap): - * for i in xrange(256): - * t = chr(i).encode('hex') - * if bswap: - * t = t[1] + t[0] - * print('0x' + t.encode('hex') + 'U') - * print('big endian'); genhextab(False) - * print('little endian'); genhextab(True) -*/ -DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = { -#if defined(DUK_USE_INTEGER_BE) - 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U, - 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U, - 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U, - 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U, - 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U, - 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U, - 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U, - 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U, - 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U, - 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U, - 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U, - 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U, - 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U, - 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U, - 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U, - 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U, - 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U, - 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U, - 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U, - 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U, - 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U, - 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U, - 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U, - 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U, - 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U, - 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U, - 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U, - 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U, - 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U, - 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U, - 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U, - 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U -#else /* DUK_USE_INTEGER_BE */ - 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U, - 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U, - 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U, - 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U, - 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U, - 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U, - 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U, - 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U, - 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U, - 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U, - 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U, - 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U, - 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U, - 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U, - 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U, - 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U, - 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U, - 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U, - 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U, - 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U, - 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U, - 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U, - 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U, - 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U, - 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U, - 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U, - 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U, - 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U, - 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U, - 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U, - 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U, - 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U -#endif /* DUK_USE_INTEGER_BE */ -}; -#endif /* DUK_USE_HEX_FASTPATH */ - -/* - * Table for base-64 encoding - */ - -#if defined(DUK_USE_BASE64_FASTPATH) -DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = { - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */ - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */ - 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */ - 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */ -}; -#endif /* DUK_USE_BASE64_FASTPATH */ - -/* - * Table for base-64 decoding - */ - -#if defined(DUK_USE_BASE64_FASTPATH) -DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = { - /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */ - -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */ - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */ - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */ -}; -#endif /* DUK_USE_BASE64_FASTPATH */ - -/* - * Arbitrary byteswap for potentially unaligned values - * - * Used to byteswap pointers e.g. in debugger code. - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ -DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) { - duk_uint8_t tmp; - duk_uint8_t *q = p + len - 1; - - while (p - q < 0) { - tmp = *p; - *p = *q; - *q = tmp; - p++; - q--; - } -} -#endif - -/* - * Miscellaneous coercion / clamping helpers. - */ - -/* Check whether a duk_double_t is a whole number in the 32-bit range (reject - * negative zero), and if so, return a duk_int32_t. - * For compiler use: don't allow negative zero as it will cause trouble with - * LDINT+LDINTX, positive zero is OK. - */ -DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) { - duk_int32_t t; - - t = (duk_int32_t) x; - if (!((duk_double_t) t == x)) { - return 0; - } - if (t == 0) { - duk_double_union du; - du.d = x; - if (DUK_DBLUNION_HAS_SIGNBIT(&du)) { - return 0; - } - } - *ival = t; - return 1; -} - -/* Check whether a duk_double_t is a whole number in the 32-bit range, and if - * so, return a duk_int32_t. - */ -DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) { - duk_int32_t t; - - t = (duk_int32_t) x; - if (!((duk_double_t) t == x)) { - return 0; - } - *ival = t; - return 1; -} - -/* - * IEEE double checks - */ - -DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) { - duk_double_union du; - du.d = x; - return DUK_DBLUNION_IS_ANYINF(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) { - duk_double_union du; - du.d = x; - return DUK_DBLUNION_IS_POSINF(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) { - duk_double_union du; - du.d = x; - return DUK_DBLUNION_IS_NEGINF(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) { - duk_double_union du; - du.d = x; - /* Assumes we're dealing with a Duktape internal NaN which is - * NaN normalized if duk_tval requires it. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - return DUK_DBLUNION_IS_NAN(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) { - duk_double_union du; - du.d = x; - /* Assumes we're dealing with a Duktape internal NaN which is - * NaN normalized if duk_tval requires it. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) { - duk_double_union du; - du.d = x; - /* If exponent is 0x7FF the argument is either a NaN or an - * infinity. We don't need to check any other fields. - */ -#if defined(DUK_USE_64BIT_OPS) -#if defined(DUK_USE_DOUBLE_ME) - return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000); -#else - return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000); -#endif -#else - return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL; -#endif -} - -DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) { - duk_double_union du; -#if defined(DUK_USE_64BIT_OPS) - duk_uint64_t t; -#else - duk_uint32_t t; -#endif - du.d = x; -#if defined(DUK_USE_64BIT_OPS) -#if defined(DUK_USE_DOUBLE_ME) - t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000); - if (t == DUK_U64_CONSTANT(0x0000000000000000)) { - t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000); - return t == 0; - } - if (t == DUK_U64_CONSTANT(0x000000007ff00000)) { - return 1; - } -#else - t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000); - if (t == DUK_U64_CONSTANT(0x0000000000000000)) { - t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000); - return t == 0; - } - if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) { - return 1; - } -#endif -#else - t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL; - if (t == 0x00000000UL) { - return DUK_DBLUNION_IS_ANYZERO(&du); - } - if (t == 0x7ff00000UL) { - return 1; - } -#endif - return 0; -} - -DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) { - duk_double_union du; - du.d = x; - return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du); -} - -DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) { - /* XXX: optimize */ - duk_small_uint_t s = duk_double_signbit(x); - x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */ - if (s) { - x = -x; - } - return x; -} - -DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) { - duk_double_union du1; - duk_double_union du2; - du1.d = x; - du2.d = y; - - return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0); -} - -DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) { - /* Doesn't replicate fmin() behavior exactly: for fmin() if one - * argument is a NaN, the other argument should be returned. - * Duktape doesn't rely on this behavior so the replacement can - * be simplified. - */ - return (x < y ? x : y); -} - -DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) { - /* Doesn't replicate fmax() behavior exactly: for fmax() if one - * argument is a NaN, the other argument should be returned. - * Duktape doesn't rely on this behavior so the replacement can - * be simplified. - */ - return (x > y ? x : y); -} -#line 1 "duk_hobject_class.c" -/* - * Hobject Ecmascript [[Class]]. - */ - -/* #include duk_internal.h -> already included */ - -#if (DUK_STRIDX_UC_ARGUMENTS > 255) -#error constant too large -#endif -#if (DUK_STRIDX_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UC_BOOLEAN > 255) -#error constant too large -#endif -#if (DUK_STRIDX_DATE > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UC_ERROR > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UC_FUNCTION > 255) -#error constant too large -#endif -#if (DUK_STRIDX_JSON > 255) -#error constant too large -#endif -#if (DUK_STRIDX_MATH > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UC_NUMBER > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UC_OBJECT > 255) -#error constant too large -#endif -#if (DUK_STRIDX_REG_EXP > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UC_STRING > 255) -#error constant too large -#endif -#if (DUK_STRIDX_GLOBAL > 255) -#error constant too large -#endif -#if (DUK_STRIDX_OBJ_ENV > 255) -#error constant too large -#endif -#if (DUK_STRIDX_DEC_ENV > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UC_POINTER > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UC_THREAD > 255) -#error constant too large -#endif -#if (DUK_STRIDX_ARRAY_BUFFER > 255) -#error constant too large -#endif -#if (DUK_STRIDX_DATA_VIEW > 255) -#error constant too large -#endif -#if (DUK_STRIDX_INT8_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UINT8_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_INT16_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UINT16_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_INT32_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_UINT32_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_FLOAT32_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_FLOAT64_ARRAY > 255) -#error constant too large -#endif -#if (DUK_STRIDX_EMPTY_STRING > 255) -#error constant too large -#endif - -/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */ -DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = { - DUK_STRIDX_EMPTY_STRING, /* NONE, intentionally empty */ - DUK_STRIDX_UC_OBJECT, - DUK_STRIDX_ARRAY, - DUK_STRIDX_UC_FUNCTION, - DUK_STRIDX_UC_ARGUMENTS, - DUK_STRIDX_UC_BOOLEAN, - DUK_STRIDX_DATE, - DUK_STRIDX_UC_ERROR, - DUK_STRIDX_JSON, - DUK_STRIDX_MATH, - DUK_STRIDX_UC_NUMBER, - DUK_STRIDX_REG_EXP, - DUK_STRIDX_UC_STRING, - DUK_STRIDX_GLOBAL, - DUK_STRIDX_UC_SYMBOL, - DUK_STRIDX_OBJ_ENV, - DUK_STRIDX_DEC_ENV, - DUK_STRIDX_UC_POINTER, - DUK_STRIDX_UC_THREAD, - DUK_STRIDX_ARRAY_BUFFER, - DUK_STRIDX_DATA_VIEW, - DUK_STRIDX_INT8_ARRAY, - DUK_STRIDX_UINT8_ARRAY, - DUK_STRIDX_UINT8_CLAMPED_ARRAY, - DUK_STRIDX_INT16_ARRAY, - DUK_STRIDX_UINT16_ARRAY, - DUK_STRIDX_INT32_ARRAY, - DUK_STRIDX_UINT32_ARRAY, - DUK_STRIDX_FLOAT32_ARRAY, - DUK_STRIDX_FLOAT64_ARRAY, - DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ - DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ -}; -#line 1 "duk_alloc_default.c" -/* - * Default allocation functions. - * - * Assumes behavior such as malloc allowing zero size, yielding - * a NULL or a unique pointer which is a no-op for free. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) -DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) { - void *res; - DUK_UNREF(udata); - res = DUK_ANSI_MALLOC(size); - DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p", - (unsigned long) size, (void *) res)); - return res; -} - -DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) { - void *res; - DUK_UNREF(udata); - res = DUK_ANSI_REALLOC(ptr, newsize); - DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p", - (void *) ptr, (unsigned long) newsize, (void *) res)); - return res; -} - -DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) { - DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr)); - DUK_UNREF(udata); - DUK_ANSI_FREE(ptr); -} -#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */ -#line 1 "duk_api_buffer.c" -/* - * Buffer - */ - -/* #include duk_internal.h -> already included */ - -DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t new_size) { - duk_hbuffer_dynamic *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx); - DUK_ASSERT(h != NULL); - - if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { - DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); - } - - /* maximum size check is handled by callee */ - duk_hbuffer_resize(thr, h, new_size); - - return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); -} - -DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { - duk_hbuffer_dynamic *h; - void *ptr; - duk_size_t sz; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx); - DUK_ASSERT(h != NULL); - - if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { - DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); - } - - /* Forget the previous allocation, setting size to 0 and alloc to - * NULL. Caller is responsible for freeing the previous allocation. - * Getting the allocation and clearing it is done in the same API - * call to avoid any chance of a realloc. - */ - ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); - sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h); - if (out_size) { - *out_size = sz; - } - DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h); - DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0); - - return ptr; -} - -DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, duk_size_t len) { - duk_hbuffer_external *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hbuffer_external *) duk_require_hbuffer(thr, idx); - DUK_ASSERT(h != NULL); - - if (!DUK_HBUFFER_HAS_EXTERNAL(h)) { - DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); - } - DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h)); - - DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr); - DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len); -} -#line 1 "duk_api_bytecode.c" -/* - * Bytecode dump/load - * - * The bytecode load primitive is more important performance-wise than the - * dump primitive. - * - * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be - * memory safe for invalid arguments - caller beware! There's little point - * in trying to achieve memory safety unless bytecode instructions are also - * validated which is not easy to do with indirect register references etc. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT) - -#define DUK__SER_MARKER 0xbf -#define DUK__SER_STRING 0x00 -#define DUK__SER_NUMBER 0x01 -#define DUK__BYTECODE_INITIAL_ALLOC 256 -#define DUK__NO_FORMALS 0xffffffffUL - -/* - * Dump/load helpers, xxx_raw() helpers do no buffer checks - */ - -DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_hthread *thr, duk_uint8_t *p) { - duk_uint32_t len; - - len = DUK_RAW_READ_U32_BE(p); - duk_push_lstring(thr, (const char *) p, len); - p += len; - return p; -} - -DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, duk_uint8_t *p) { - duk_uint32_t len; - duk_uint8_t *buf; - - len = DUK_RAW_READ_U32_BE(p); - buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); - DUK_ASSERT(buf != NULL); - DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len); - p += len; - return p; -} - -DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) { - duk_size_t len; - duk_uint32_t tmp32; - - DUK_ASSERT(h != NULL); - - len = DUK_HSTRING_GET_BYTELEN(h); - DUK_ASSERT(len <= 0xffffffffUL); /* string limits */ - tmp32 = (duk_uint32_t) len; - DUK_RAW_WRITE_U32_BE(p, tmp32); - DUK_MEMCPY((void *) p, - (const void *) DUK_HSTRING_GET_DATA(h), - len); - p += len; - return p; -} - -DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) { - duk_size_t len; - duk_uint32_t tmp32; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(h != NULL); - DUK_UNREF(thr); - - len = DUK_HBUFFER_GET_SIZE(h); - DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */ - tmp32 = (duk_uint32_t) len; - DUK_RAW_WRITE_U32_BE(p, tmp32); - DUK_MEMCPY((void *) p, - (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h), - len); - p += len; - return p; -} - -DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) { - duk_hstring *h_str; - duk_tval *tv; - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); - if (tv != NULL && DUK_TVAL_IS_STRING(tv)) { - h_str = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h_str != NULL); - } else { - h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); - DUK_ASSERT(h_str != NULL); - } - DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(h_str), p); - p = duk__dump_hstring_raw(p, h_str); - return p; -} - -DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) { - duk_tval *tv; - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); - if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) { - duk_hbuffer *h_buf; - h_buf = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h_buf != NULL); - DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HBUFFER_GET_SIZE(h_buf), p); - p = duk__dump_hbuffer_raw(thr, p, h_buf); - } else { - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); - DUK_RAW_WRITE_U32_BE(p, 0); - } - return p; -} - -DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx, duk_uint32_t def_value) { - duk_tval *tv; - duk_uint32_t val; - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); - if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) { - val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv); - } else { - val = def_value; - } - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); - DUK_RAW_WRITE_U32_BE(p, val); - return p; -} - -DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { - duk_tval *tv; - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); - if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h; - duk_uint_fast32_t i; - - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - - /* We know _Varmap only has own properties so walk property - * table directly. We also know _Varmap is dense and all - * values are numbers; assert for these. GC and finalizers - * shouldn't affect _Varmap so side effects should be fine. - */ - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { - duk_hstring *key; - duk_tval *tv_val; - duk_uint32_t val; - - key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i); - DUK_ASSERT(key != NULL); /* _Varmap is dense */ - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)); - tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i); - DUK_ASSERT(tv_val != NULL); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */ -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val)); - DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */ - val = DUK_TVAL_GET_FASTINT_U32(tv_val); -#else - val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val); -#endif - - DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(key) + 4U, p); - p = duk__dump_hstring_raw(p, key); - DUK_RAW_WRITE_U32_BE(p, val); - } - } - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); - DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */ - return p; -} - -DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { - duk_tval *tv; - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr)); - if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { - duk_harray *h; - duk_uint32_t i; - - /* Here we rely on _Formals being a dense array containing - * strings. This should be the case unless _Formals has been - * tweaked by the application (which we don't support right - * now). - */ - h = (duk_harray *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h)); - DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h)); - - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); - DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */ - DUK_RAW_WRITE_U32_BE(p, h->length); - - for (i = 0; i < h->length; i++) { - duk_tval *tv_val; - duk_hstring *varname; - - tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i); - DUK_ASSERT(tv_val != NULL); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val)); - - varname = DUK_TVAL_GET_STRING(tv_val); - DUK_ASSERT(varname != NULL); - DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); - - DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(varname), p); - p = duk__dump_hstring_raw(p, varname); - } - } else { - DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals")); - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); - DUK_RAW_WRITE_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */ - } - return p; -} - -static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) { - duk_tval *tv, *tv_end; - duk_instr_t *ins, *ins_end; - duk_hobject **fn, **fn_end; - duk_hstring *h_str; - duk_uint32_t count_instr; - duk_uint32_t tmp32; - duk_uint16_t tmp16; - duk_double_t d; - - DUK_DD(DUK_DDPRINT("dumping function %p to %p: " - "consts=[%p,%p[ (%ld bytes, %ld items), " - "funcs=[%p,%p[ (%ld bytes, %ld items), " - "code=[%p,%p[ (%ld bytes, %ld items)", - (void *) func, - (void *) p, - (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func), - (void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func), - (long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func), - (long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func), - (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func), - (void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func), - (long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func), - (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func), - (void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func), - (void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func), - (long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func), - (long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func))); - - DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */ - count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func); - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3U * 4U + 2U * 2U + 3U * 4U + count_instr * 4U, p); - - /* Fixed header info. */ - tmp32 = count_instr; - DUK_RAW_WRITE_U32_BE(p, tmp32); - tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func); - DUK_RAW_WRITE_U32_BE(p, tmp32); - tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func); - DUK_RAW_WRITE_U32_BE(p, tmp32); - tmp16 = func->nregs; - DUK_RAW_WRITE_U16_BE(p, tmp16); - tmp16 = func->nargs; - DUK_RAW_WRITE_U16_BE(p, tmp16); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - tmp32 = func->start_line; - DUK_RAW_WRITE_U32_BE(p, tmp32); - tmp32 = func->end_line; - DUK_RAW_WRITE_U32_BE(p, tmp32); -#else - DUK_RAW_WRITE_U32_BE(p, 0); - DUK_RAW_WRITE_U32_BE(p, 0); -#endif - tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func); /* masks flags, only duk_hobject flags */ - tmp32 &= ~(DUK_HOBJECT_FLAG_HAVE_FINALIZER); /* finalizer flag is lost */ - DUK_RAW_WRITE_U32_BE(p, tmp32); - - /* Bytecode instructions: endian conversion needed unless - * platform is big endian. - */ - ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func); - ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func); - DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr); -#if defined(DUK_USE_INTEGER_BE) - DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins)); - p += (size_t) (ins_end - ins); -#else - while (ins != ins_end) { - tmp32 = (duk_uint32_t) (*ins); - DUK_RAW_WRITE_U32_BE(p, tmp32); - ins++; - } -#endif - - /* Constants: variable size encoding. */ - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func); - tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func); - while (tv != tv_end) { - /* constants are strings or numbers now */ - DUK_ASSERT(DUK_TVAL_IS_STRING(tv) || - DUK_TVAL_IS_NUMBER(tv)); - - if (DUK_TVAL_IS_STRING(tv)) { - h_str = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h_str != NULL); - DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p), - *p++ = DUK__SER_STRING; - p = duk__dump_hstring_raw(p, h_str); - } else { - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 8U, p); - *p++ = DUK__SER_NUMBER; - d = DUK_TVAL_GET_NUMBER(tv); - DUK_RAW_WRITE_DOUBLE_BE(p, d); - } - tv++; - } - - /* Inner functions recursively. */ - fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func); - fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func); - while (fn != fn_end) { - /* XXX: This causes recursion up to inner function depth - * which is normally not an issue, e.g. mark-and-sweep uses - * a recursion limiter to avoid C stack issues. Avoiding - * this would mean some sort of a work list or just refusing - * to serialize deep functions. - */ - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn)); - p = duk__dump_func(thr, (duk_hcompfunc *) *fn, bw_ctx, p); - fn++; - } - - /* Lexenv and varenv are not dumped. */ - - /* Object extra properties. - * - * There are some difference between function templates and functions. - * For example, function templates don't have .length and nargs is - * normally used to instantiate the functions. - */ - - p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs); -#if defined(DUK_USE_FUNC_NAME_PROPERTY) - p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME); -#endif -#if defined(DUK_USE_FUNC_FILENAME_PROPERTY) - p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME); -#endif -#if defined(DUK_USE_PC2LINE) - p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE); -#endif - p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func); - p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func); - - DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p)); - - return p; -} - -/* Load a function from bytecode. The function object returned here must - * match what is created by duk_js_push_closure() with respect to its flags, - * properties, etc. - * - * NOTE: there are intentionally no input buffer length / bound checks. - * Adding them would be easy but wouldn't ensure memory safety as untrusted - * or broken bytecode is unsafe during execution unless the opcodes themselves - * are validated (which is quite complex, especially for indirect opcodes). - */ - -#define DUK__ASSERT_LEFT(n) do { \ - DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \ - } while (0) - -static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t *p_end) { - duk_hcompfunc *h_fun; - duk_hbuffer *h_data; - duk_size_t data_size; - duk_uint32_t count_instr, count_const, count_funcs; - duk_uint32_t n; - duk_uint32_t tmp32; - duk_small_uint_t const_type; - duk_uint8_t *fun_data; - duk_uint8_t *q; - duk_idx_t idx_base; - duk_tval *tv1; - duk_uarridx_t arr_idx; - duk_uarridx_t arr_limit; - duk_hobject *func_env; - duk_bool_t need_pop; - - /* XXX: There's some overlap with duk_js_closure() here, but - * seems difficult to share code. Ensure that the final function - * looks the same as created by duk_js_closure(). - */ - - DUK_ASSERT(thr != NULL); - - DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end)); - - DUK__ASSERT_LEFT(3 * 4); - count_instr = DUK_RAW_READ_U32_BE(p); - count_const = DUK_RAW_READ_U32_BE(p); - count_funcs = DUK_RAW_READ_U32_BE(p); - - data_size = sizeof(duk_tval) * count_const + - sizeof(duk_hobject *) * count_funcs + - sizeof(duk_instr_t) * count_instr; - - DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld", - (long) count_instr, (long) count_const, - (long) count_const, (long) data_size)); - - /* Value stack is used to ensure reachability of constants and - * inner functions being loaded. Require enough space to handle - * large functions correctly. - */ - duk_require_stack(thr, (duk_idx_t) (2 + count_const + count_funcs)); - idx_base = duk_get_top(thr); - - /* Push function object, init flags etc. This must match - * duk_js_push_closure() quite carefully. - */ - h_fun = duk_push_hcompfunc(thr); - DUK_ASSERT(h_fun != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun)); - DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); - - h_fun->nregs = DUK_RAW_READ_U16_BE(p); - h_fun->nargs = DUK_RAW_READ_U16_BE(p); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - h_fun->start_line = DUK_RAW_READ_U32_BE(p); - h_fun->end_line = DUK_RAW_READ_U32_BE(p); -#else - p += 8; /* skip line info */ -#endif - - /* duk_hcompfunc flags; quite version specific */ - tmp32 = DUK_RAW_READ_U32_BE(p); - DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */ - - /* standard prototype (no need to set here, already set) */ - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); -#if 0 - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); -#endif - - /* assert just a few critical flags */ - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj)); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj)); - DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&h_fun->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj)); - - /* Create function 'data' buffer but don't attach it yet. */ - fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, data_size); - DUK_ASSERT(fun_data != NULL); - - /* Load bytecode instructions. */ - DUK_ASSERT(sizeof(duk_instr_t) == 4); - DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t)); -#if defined(DUK_USE_INTEGER_BE) - q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; - DUK_MEMCPY((void *) q, - (const void *) p, - sizeof(duk_instr_t) * count_instr); - p += sizeof(duk_instr_t) * count_instr; -#else - q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; - for (n = count_instr; n > 0; n--) { - *((duk_instr_t *) (void *) q) = DUK_RAW_READ_U32_BE(p); - q += sizeof(duk_instr_t); - } -#endif - - /* Load constants onto value stack but don't yet copy to buffer. */ - for (n = count_const; n > 0; n--) { - DUK__ASSERT_LEFT(1); - const_type = DUK_RAW_READ_U8(p); - switch (const_type) { - case DUK__SER_STRING: { - p = duk__load_string_raw(thr, p); - break; - } - case DUK__SER_NUMBER: { - /* Important to do a fastint check so that constants are - * properly read back as fastints. - */ - duk_tval tv_tmp; - duk_double_t val; - DUK__ASSERT_LEFT(8); - val = DUK_RAW_READ_DOUBLE_BE(p); - DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val); - duk_push_tval(thr, &tv_tmp); - break; - } - default: { - goto format_error; - } - } - } - - /* Load inner functions to value stack, but don't yet copy to buffer. */ - for (n = count_funcs; n > 0; n--) { - p = duk__load_func(thr, p, p_end); - if (p == NULL) { - goto format_error; - } - } - - /* With constants and inner functions on value stack, we can now - * atomically finish the function 'data' buffer, bump refcounts, - * etc. - * - * Here we take advantage of the value stack being just a duk_tval - * array: we can just memcpy() the constants as long as we incref - * them afterwards. - */ - - h_data = (duk_hbuffer *) duk_known_hbuffer(thr, idx_base + 1); - DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data)); - DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data); - DUK_HBUFFER_INCREF(thr, h_data); - - tv1 = duk_get_tval(thr, idx_base + 2); /* may be NULL if no constants or inner funcs */ - DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL); - - q = fun_data; - if (count_const > 0) { - /* Explicit zero size check to avoid NULL 'tv1'. */ - DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const); - for (n = count_const; n > 0; n--) { - DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */ - q += sizeof(duk_tval); - } - tv1 += count_const; - } - - DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q); - for (n = count_funcs; n > 0; n--) { - duk_hobject *h_obj; - - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1)); - h_obj = DUK_TVAL_GET_OBJECT(tv1); - DUK_ASSERT(h_obj != NULL); - tv1++; - DUK_HOBJECT_INCREF(thr, h_obj); - - *((duk_hobject **) (void *) q) = h_obj; - q += sizeof(duk_hobject *); - } - - DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q); - - /* The function object is now reachable and refcounts are fine, - * so we can pop off all the temporaries. - */ - DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(thr, idx_base))); - duk_set_top(thr, idx_base + 1); - - /* Setup function properties. */ - tmp32 = DUK_RAW_READ_U32_BE(p); - duk_push_u32(thr, tmp32); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); - -#if defined(DUK_USE_FUNC_NAME_PROPERTY) - p = duk__load_string_raw(thr, p); /* -> [ func funcname ] */ - func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - DUK_ASSERT(func_env != NULL); - need_pop = 0; - if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) { - /* Original function instance/template had NAMEBINDING. - * Must create a lexical environment on loading to allow - * recursive functions like 'function foo() { foo(); }'. - */ - duk_hdecenv *new_env; - - new_env = duk_hdecenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); - DUK_ASSERT(new_env != NULL); - DUK_ASSERT(new_env->thread == NULL); /* Closed. */ - DUK_ASSERT(new_env->varmap == NULL); - DUK_ASSERT(new_env->regbase_byteoff == 0); - DUK_ASSERT_HDECENV_VALID(new_env); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); - DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, func_env); - DUK_HOBJECT_INCREF(thr, func_env); - - func_env = (duk_hobject *) new_env; - - duk_push_hobject(thr, (duk_hobject *) new_env); - - duk_dup_m2(thr); /* -> [ func funcname env funcname ] */ - duk_dup(thr, idx_base); /* -> [ func funcname env funcname func ] */ - duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */ - - need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */ - } - DUK_ASSERT(func_env != NULL); - DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env); - DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env); - DUK_HOBJECT_INCREF(thr, func_env); - DUK_HOBJECT_INCREF(thr, func_env); - if (need_pop) { - duk_pop(thr); - } - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); -#endif /* DUK_USE_FUNC_NAME_PROPERTY */ - -#if defined(DUK_USE_FUNC_FILENAME_PROPERTY) - p = duk__load_string_raw(thr, p); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C); -#endif /* DUK_USE_FUNC_FILENAME_PROPERTY */ - - if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) { - /* Restore empty external .prototype only for constructable - * functions. - */ - duk_push_object(thr); - duk_dup_m2(thr); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */ - duk_compact_m1(thr); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); - } - -#if defined(DUK_USE_PC2LINE) - p = duk__load_buffer_raw(thr, p); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC); -#endif /* DUK_USE_PC2LINE */ - - duk_push_object(thr); /* _Varmap */ - for (;;) { - /* XXX: awkward */ - p = duk__load_string_raw(thr, p); - if (duk_get_length(thr, -1) == 0) { - duk_pop(thr); - break; - } - tmp32 = DUK_RAW_READ_U32_BE(p); - duk_push_u32(thr, tmp32); - duk_put_prop(thr, -3); - } - duk_compact_m1(thr); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); - - /* _Formals may have been missing in the original function, which is - * handled using a marker length. - */ - arr_limit = DUK_RAW_READ_U32_BE(p); - if (arr_limit != DUK__NO_FORMALS) { - duk_push_array(thr); /* _Formals */ - for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) { - p = duk__load_string_raw(thr, p); - duk_put_prop_index(thr, -2, arr_idx); - } - duk_compact_m1(thr); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); - } else { - DUK_DD(DUK_DDPRINT("no _Formals in dumped function")); - } - - /* Return with final function pushed on stack top. */ - DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(thr, -1))); - DUK_ASSERT_TOP(thr, idx_base + 1); - return p; - - format_error: - return NULL; -} - -DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) { - duk_hcompfunc *func; - duk_bufwriter_ctx bw_ctx_alloc; - duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc; - duk_uint8_t *p; - - DUK_ASSERT_API_ENTRY(thr); - - /* Bound functions don't have all properties so we'd either need to - * lookup the non-bound target function or reject bound functions. - * For now, bound functions are rejected with TypeError. - */ - func = duk_require_hcompfunc(thr, -1); - DUK_ASSERT(func != NULL); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj)); - - /* Estimating the result size beforehand would be costly, so - * start with a reasonable size and extend as needed. - */ - DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC); - p = DUK_BW_GET_PTR(thr, bw_ctx); - *p++ = DUK__SER_MARKER; - p = duk__dump_func(thr, func, bw_ctx, p); - DUK_BW_SET_PTR(thr, bw_ctx, p); - DUK_BW_COMPACT(thr, bw_ctx); - - DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(thr, -1))); - - duk_remove_m2(thr); /* [ ... func buf ] -> [ ... buf ] */ -} - -DUK_EXTERNAL void duk_load_function(duk_hthread *thr) { - duk_uint8_t *p_buf, *p, *p_end; - duk_size_t sz; - - DUK_ASSERT_API_ENTRY(thr); - - p_buf = (duk_uint8_t *) duk_require_buffer(thr, -1, &sz); - DUK_ASSERT(p_buf != NULL); - - /* The caller is responsible for being sure that bytecode being loaded - * is valid and trusted. Invalid bytecode can cause memory unsafe - * behavior directly during loading or later during bytecode execution - * (instruction validation would be quite complex to implement). - * - * This signature check is the only sanity check for detecting - * accidental invalid inputs. The initial byte ensures no ordinary - * string or Symbol will be accepted by accident. - */ - p = p_buf; - p_end = p_buf + sz; - if (sz < 1 || p[0] != DUK__SER_MARKER) { - goto format_error; - } - p++; - - p = duk__load_func(thr, p, p_end); - if (p == NULL) { - goto format_error; - } - - duk_remove_m2(thr); /* [ ... buf func ] -> [ ... func ] */ - return; - - format_error: - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE); -} - -#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */ - -DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ERROR_UNSUPPORTED(thr); -} - -DUK_EXTERNAL void duk_load_function(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ERROR_UNSUPPORTED(thr); -} - -#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */ - -/* automatic undefs */ -#undef DUK__ASSERT_LEFT -#undef DUK__BYTECODE_INITIAL_ALLOC -#undef DUK__NO_FORMALS -#undef DUK__SER_MARKER -#undef DUK__SER_NUMBER -#undef DUK__SER_STRING -#line 1 "duk_api_call.c" -/* - * Calls. - * - * Protected variants should avoid ever throwing an error. Must be careful - * to catch errors related to value stack manipulation and property lookup, - * not just the call itself. - * - * The only exception is when arguments are insane, e.g. nargs/nrets are out - * of bounds; in such cases an error is thrown for two reasons. First, we - * can't always respect the value stack input/output guarantees in such cases - * so the caller would end up with the value stack in an unexpected state. - * Second, an attempt to create an error might itself fail (although this - * could be avoided by pushing a preallocated object/string or a primitive - * value). - */ - -/* #include duk_internal.h -> already included */ - -/* - * Helpers - */ - -struct duk__pcall_prop_args { - duk_idx_t obj_idx; - duk_idx_t nargs; - duk_small_uint_t call_flags; -}; -typedef struct duk__pcall_prop_args duk__pcall_prop_args; - -struct duk__pcall_method_args { - duk_idx_t nargs; - duk_small_uint_t call_flags; -}; -typedef struct duk__pcall_method_args duk__pcall_method_args; - -struct duk__pcall_args { - duk_idx_t nargs; - duk_small_uint_t call_flags; -}; -typedef struct duk__pcall_args duk__pcall_args; - -/* Compute and validate idx_func for a certain 'nargs' and 'other' - * parameter count (1 or 2, depending on whether 'this' binding is - * present). - */ -DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) { - duk_idx_t idx_func; - - /* XXX: byte arithmetic? */ - - DUK_ASSERT(other >= 0); - - idx_func = duk_get_top(thr) - nargs - other; - if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */ - DUK_ERROR_TYPE_INVALID_ARGS(thr); - /* unreachable */ - } - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - return idx_func; -} - -/* Compute idx_func, assume index will be valid. This is a valid assumption - * for protected calls: nargs < 0 is checked explicitly and duk_safe_call() - * validates the argument count. - */ -DUK_LOCAL duk_idx_t duk__call_get_idx_func_unvalidated(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) { - duk_idx_t idx_func; - - /* XXX: byte arithmetic? */ - - DUK_ASSERT(nargs >= 0); - DUK_ASSERT(other >= 0); - - idx_func = duk_get_top(thr) - nargs - other; - DUK_ASSERT(idx_func >= 0); - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - return idx_func; -} - -/* Prepare value stack for a method call through an object property. - * May currently throw an error e.g. when getting the property. - */ -DUK_LOCAL void duk__call_prop_prep_stack(duk_hthread *thr, duk_idx_t normalized_obj_idx, duk_idx_t nargs) { - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(nargs >= 0); - - DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld", - (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(thr))); - - /* [... key arg1 ... argN] */ - - /* duplicate key */ - duk_dup(thr, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */ - (void) duk_get_prop(thr, normalized_obj_idx); - - DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(thr, -1))); - -#if defined(DUK_USE_VERBOSE_ERRORS) - if (DUK_UNLIKELY(!duk_is_callable(thr, -1))) { - duk_tval *tv_targ; - duk_tval *tv_base; - duk_tval *tv_key; - - tv_targ = DUK_GET_TVAL_NEGIDX(thr, -1); - tv_base = DUK_GET_TVAL_POSIDX(thr, normalized_obj_idx); - tv_key = DUK_GET_TVAL_NEGIDX(thr, -nargs - 2); - DUK_ASSERT(tv_targ >= thr->valstack_bottom && tv_targ < thr->valstack_top); - DUK_ASSERT(tv_base >= thr->valstack_bottom && tv_base < thr->valstack_top); - DUK_ASSERT(tv_key >= thr->valstack_bottom && tv_key < thr->valstack_top); - - duk_call_setup_propcall_error(thr, tv_targ, tv_base, tv_key); - } -#endif - - /* [... key arg1 ... argN func] */ - - duk_replace(thr, -nargs - 2); - - /* [... func arg1 ... argN] */ - - duk_dup(thr, normalized_obj_idx); - duk_insert(thr, -nargs - 1); - - /* [... func this arg1 ... argN] */ -} - -DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs) { - duk_small_uint_t call_flags; - duk_idx_t idx_func; - - DUK_ASSERT_API_ENTRY(thr); - - idx_func = duk__call_get_idx_func(thr, nargs, 1); - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - - duk_insert_undefined(thr, idx_func + 1); - - call_flags = 0; /* not protected, respect reclimit, not constructor */ - duk_handle_call_unprotected(thr, idx_func, call_flags); -} - -DUK_EXTERNAL void duk_call_method(duk_hthread *thr, duk_idx_t nargs) { - duk_small_uint_t call_flags; - duk_idx_t idx_func; - - DUK_ASSERT_API_ENTRY(thr); - - idx_func = duk__call_get_idx_func(thr, nargs, 2); - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - - call_flags = 0; /* not protected, respect reclimit, not constructor */ - duk_handle_call_unprotected(thr, idx_func, call_flags); -} - -DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) { - /* - * XXX: if duk_handle_call() took values through indices, this could be - * made much more sensible. However, duk_handle_call() needs to fudge - * the 'this' and 'func' values to handle bound functions, which is now - * done "in-place", so this is not a trivial change. - */ - - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */ - if (DUK_UNLIKELY(nargs < 0)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - } - - duk__call_prop_prep_stack(thr, obj_idx, nargs); - - duk_call_method(thr, nargs); -} - -DUK_LOCAL duk_ret_t duk__pcall_raw(duk_hthread *thr, void *udata) { - duk__pcall_args *args; - duk_idx_t idx_func; - duk_int_t ret; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(udata != NULL); - - args = (duk__pcall_args *) udata; - idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 1); - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - - duk_insert_undefined(thr, idx_func + 1); - - ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags); - DUK_ASSERT(ret == 0); - DUK_UNREF(ret); - - return 1; -} - -DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) { - duk__pcall_args args; - - DUK_ASSERT_API_ENTRY(thr); - - args.nargs = nargs; - if (DUK_UNLIKELY(nargs < 0)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ - } - args.call_flags = 0; - - return duk_safe_call(thr, duk__pcall_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); -} - -DUK_LOCAL duk_ret_t duk__pcall_method_raw(duk_hthread *thr, void *udata) { - duk__pcall_method_args *args; - duk_idx_t idx_func; - duk_int_t ret; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(udata != NULL); - - args = (duk__pcall_method_args *) udata; - - idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 2); - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - - ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags); - DUK_ASSERT(ret == 0); - DUK_UNREF(ret); - - return 1; -} - -DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags) { - duk__pcall_method_args args; - - DUK_ASSERT_API_ENTRY(thr); - - args.nargs = nargs; - if (DUK_UNLIKELY(nargs < 0)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ - } - args.call_flags = call_flags; - - return duk_safe_call(thr, duk__pcall_method_raw, (void *) &args /*udata*/, nargs + 2 /*nargs*/, 1 /*nrets*/); -} - -DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs) { - DUK_ASSERT_API_ENTRY(thr); - - return duk_pcall_method_flags(thr, nargs, 0); -} - -DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_hthread *thr, void *udata) { - duk__pcall_prop_args *args; - duk_idx_t obj_idx; - duk_int_t ret; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(udata != NULL); - - args = (duk__pcall_prop_args *) udata; - - obj_idx = duk_require_normalize_index(thr, args->obj_idx); /* make absolute */ - duk__call_prop_prep_stack(thr, obj_idx, args->nargs); - - ret = duk_handle_call_unprotected_nargs(thr, args->nargs, args->call_flags); - DUK_ASSERT(ret == 0); - DUK_UNREF(ret); - return 1; -} - -DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) { - duk__pcall_prop_args args; - - DUK_ASSERT_API_ENTRY(thr); - - args.obj_idx = obj_idx; - args.nargs = nargs; - if (DUK_UNLIKELY(nargs < 0)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ - } - args.call_flags = 0; - - return duk_safe_call(thr, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); -} - -DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) { - duk_int_t rc; - - DUK_ASSERT_API_ENTRY(thr); - - /* nargs condition; fail if: top - bottom < nargs - * <=> top < bottom + nargs - * nrets condition; fail if: end - (top - nargs) < nrets - * <=> end - top + nargs < nrets - * <=> end + nargs < top + nrets - */ - /* XXX: check for any reserve? */ - - if (DUK_UNLIKELY((nargs | nrets) < 0 || /* nargs < 0 || nrets < 0; OR sign bits */ - thr->valstack_top < thr->valstack_bottom + nargs || /* nargs too large compared to top */ - thr->valstack_end + nargs < thr->valstack_top + nrets)) { /* nrets too large compared to reserve */ - DUK_D(DUK_DPRINT("not enough stack reserve for safe call or invalid arguments: " - "nargs=%ld < 0 (?), nrets=%ld < 0 (?), top=%ld < bottom=%ld + nargs=%ld (?), " - "end=%ld + nargs=%ld < top=%ld + nrets=%ld (?)", - (long) nargs, - (long) nrets, - (long) (thr->valstack_top - thr->valstack), - (long) (thr->valstack_bottom - thr->valstack), - (long) nargs, - (long) (thr->valstack_end - thr->valstack), - (long) nargs, - (long) (thr->valstack_top - thr->valstack), - (long) nrets)); - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ - } - - rc = duk_handle_safe_call(thr, /* thread */ - func, /* func */ - udata, /* udata */ - nargs, /* num_stack_args */ - nrets); /* num_stack_res */ - - return rc; -} - -DUK_EXTERNAL void duk_new(duk_hthread *thr, duk_idx_t nargs) { - duk_idx_t idx_func; - - DUK_ASSERT_API_ENTRY(thr); - - idx_func = duk__call_get_idx_func(thr, nargs, 1); - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - - duk_push_object(thr); /* default instance; internal proto updated by call handling */ - duk_insert(thr, idx_func + 1); - - duk_handle_call_unprotected(thr, idx_func, DUK_CALL_FLAG_CONSTRUCT); -} - -DUK_LOCAL duk_ret_t duk__pnew_helper(duk_hthread *thr, void *udata) { - duk_idx_t nargs; - - DUK_ASSERT(udata != NULL); - nargs = *((duk_idx_t *) udata); - - duk_new(thr, nargs); - return 1; -} - -DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) { - duk_int_t rc; - - DUK_ASSERT_API_ENTRY(thr); - - /* For now, just use duk_safe_call() to wrap duk_new(). We can't - * simply use a protected duk_handle_call() because pushing the - * default instance might throw. - */ - - if (DUK_UNLIKELY(nargs < 0)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ - } - - rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); - return rc; -} - -DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_hthread *thr) { - duk_activation *act; - - DUK_ASSERT_API_ENTRY(thr); - - act = thr->callstack_curr; - if (act != NULL) { - return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); - } - return 0; -} - -/* XXX: Make this obsolete by adding a function flag for rejecting a - * non-constructor call automatically? - */ -DUK_INTERNAL void duk_require_constructor_call(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - if (!duk_is_constructor_call(thr)) { - DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY); - } -} - -DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) { - duk_activation *act; - - /* For user code this could just return 1 (strict) always - * because all Duktape/C functions are considered strict, - * and strict is also the default when nothing is running. - * However, Duktape may call this function internally when - * the current activation is an Ecmascript function, so - * this cannot be replaced by a 'return 1' without fixing - * the internal call sites. - */ - - DUK_ASSERT_API_ENTRY(thr); - - act = thr->callstack_curr; - if (act != NULL) { - return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); - } else { - /* Strict by default. */ - return 1; - } -} - -/* - * Duktape/C function magic - */ - -DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_hthread *thr) { - duk_activation *act; - duk_hobject *func; - - DUK_ASSERT_API_ENTRY(thr); - - act = thr->callstack_curr; - if (act) { - func = DUK_ACT_GET_FUNC(act); - if (!func) { - duk_tval *tv = &act->tv_func; - duk_small_uint_t lf_flags; - lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); - return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); - } - DUK_ASSERT(func != NULL); - - if (DUK_HOBJECT_IS_NATFUNC(func)) { - duk_hnatfunc *nf = (duk_hnatfunc *) func; - return (duk_int_t) nf->magic; - } - } - return 0; -} - -DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, idx); - if (DUK_TVAL_IS_OBJECT(tv)) { - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_HAS_NATFUNC(h)) { - goto type_error; - } - return (duk_int_t) ((duk_hnatfunc *) h)->magic; - } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); - return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); - } - - /* fall through */ - type_error: - DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); - return 0; -} - -DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) { - duk_hnatfunc *nf; - - DUK_ASSERT_API_ENTRY(thr); - - nf = duk_require_hnatfunc(thr, idx); - DUK_ASSERT(nf != NULL); - nf->magic = (duk_int16_t) magic; -} - -/* - * Misc helpers - */ - -/* Resolve a bound function on value stack top to a non-bound target - * (leave other values as is). - */ -DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) { - duk_tval *tv; - - DUK_ASSERT_HTHREAD_VALID(thr); - - tv = DUK_GET_TVAL_NEGIDX(thr, -1); - if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h; - - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) { - duk_push_tval(thr, &((duk_hboundfunc *) h)->target); - duk_replace(thr, -2); -#if 0 - DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target); - DUK_TVAL_INCREF(thr, tv); - DUK_HOBJECT_DECREF_NORZ(thr, h); -#endif - /* Rely on Function.prototype.bind() on never creating a bound - * function whose target is not proper. This is now safe - * because the target is not even an internal property but a - * struct member. - */ - DUK_ASSERT(duk_is_lightfunc(thr, -1) || duk_is_callable(thr, -1)); - } - } - - /* Lightfuncs cannot be bound but are always callable and - * constructable. - */ -} -#line 1 "duk_api_codec.c" -/* - * Encoding and decoding basic formats: hex, base64. - * - * These are in-place operations which may allow an optimized implementation. - * - * Base-64: https://tools.ietf.org/html/rfc4648#section-4 - */ - -/* #include duk_internal.h -> already included */ - -/* Shared handling for encode/decode argument. Fast path handling for - * buffer and string values because they're the most common. In particular, - * avoid creating a temporary string or buffer when possible. - */ -DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { - void *ptr; - duk_bool_t isbuffer; - - DUK_ASSERT(duk_is_valid_index(thr, idx)); /* checked by caller */ - - /* XXX: with def_ptr set to a stack related pointer, isbuffer could - * be removed from the helper? - */ - ptr = duk_get_buffer_data_raw(thr, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer); - if (isbuffer) { - DUK_ASSERT(*out_len == 0 || ptr != NULL); - return (const duk_uint8_t *) ptr; - } - return (const duk_uint8_t *) duk_to_lstring(thr, idx, out_len); -} - -#if defined(DUK_USE_BASE64_FASTPATH) -DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { - duk_uint_t t; - duk_size_t n_full, n_full3, n_final; - const duk_uint8_t *src_end_fast; - - n_full = srclen / 3; /* full 3-byte -> 4-char conversions */ - n_full3 = n_full * 3; - n_final = srclen - n_full3; - DUK_ASSERT_DISABLE(n_final >= 0); - DUK_ASSERT(n_final <= 2); - - src_end_fast = src + n_full3; - while (DUK_UNLIKELY(src != src_end_fast)) { - t = (duk_uint_t) (*src++); - t = (t << 8) + (duk_uint_t) (*src++); - t = (t << 8) + (duk_uint_t) (*src++); - - *dst++ = duk_base64_enctab[t >> 18]; - *dst++ = duk_base64_enctab[(t >> 12) & 0x3f]; - *dst++ = duk_base64_enctab[(t >> 6) & 0x3f]; - *dst++ = duk_base64_enctab[t & 0x3f]; - -#if 0 /* Tested: not faster on x64 */ - /* aaaaaabb bbbbcccc ccdddddd */ - dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f]; - dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)]; - dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)]; - dst[3] = duk_base64_enctab[src[2] & 0x3f]; - src += 3; dst += 4; -#endif - } - - switch (n_final) { - /* case 0: nop */ - case 1: { - /* XX== */ - t = (duk_uint_t) (*src++); - *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */ - *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */ - *dst++ = DUK_ASC_EQUALS; - *dst++ = DUK_ASC_EQUALS; - break; - } - case 2: { - /* XXX= */ - t = (duk_uint_t) (*src++); - t = (t << 8) + (duk_uint_t) (*src++); - *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */ - *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */ - *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */ - *dst++ = DUK_ASC_EQUALS; - break; - } - } -} -#else /* DUK_USE_BASE64_FASTPATH */ -DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { - duk_small_uint_t i, snip; - duk_uint_t t; - duk_uint_fast8_t x, y; - const duk_uint8_t *src_end; - - src_end = src + srclen; - - while (src < src_end) { - /* read 3 bytes into 't', padded by zero */ - snip = 4; - t = 0; - for (i = 0; i < 3; i++) { - t = t << 8; - if (src >= src_end) { - snip--; - } else { - t += (duk_uint_t) (*src++); - } - } - - /* - * Missing bytes snip base64 example - * 0 4 XXXX - * 1 3 XXX= - * 2 2 XX== - */ - - DUK_ASSERT(snip >= 2 && snip <= 4); - - for (i = 0; i < 4; i++) { - x = (duk_uint_fast8_t) ((t >> 18) & 0x3f); - t = t << 6; - - /* A straightforward 64-byte lookup would be faster - * and cleaner, but this is shorter. - */ - if (i >= snip) { - y = '='; - } else if (x <= 25) { - y = x + 'A'; - } else if (x <= 51) { - y = x - 26 + 'a'; - } else if (x <= 61) { - y = x - 52 + '0'; - } else if (x == 62) { - y = '+'; - } else { - y = '/'; - } - - *dst++ = (duk_uint8_t) y; - } - } -} -#endif /* DUK_USE_BASE64_FASTPATH */ - -#if defined(DUK_USE_BASE64_FASTPATH) -DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { - duk_int_t x; - duk_int_t t; - duk_small_uint_t n_equal; - duk_small_uint_t n_chars; - const duk_uint8_t *src_end; - const duk_uint8_t *src_end_safe; - - src_end = src + srclen; - src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */ - - /* Innermost fast path processes 4 valid base-64 characters at a time - * but bails out on whitespace, padding chars ('=') and invalid chars. - * Once the slow path segment has been processed, we return to the - * inner fast path again. This handles e.g. base64 with newlines - * reasonably well because the majority of a line is in the fast path. - */ - for (;;) { - /* Fast path, handle units with just actual encoding characters. */ - - while (src <= src_end_safe) { - /* The lookup byte is intentionally sign extended to (at least) - * 32 bits and then ORed. This ensures that is at least 1 byte - * is negative, the highest bit of 't' will be set at the end - * and we don't need to check every byte. - */ - DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p", - (const void *) src, (const void *) src_end_safe, (const void *) src_end)); - - t = (duk_int_t) duk_base64_dectab[*src++]; - t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; - t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; - t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; - - if (DUK_UNLIKELY(t < 0)) { - DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit")); - src -= 4; - break; - } - - DUK_ASSERT(t <= 0xffffffL); - DUK_ASSERT((t >> 24) == 0); - *dst++ = (duk_uint8_t) (t >> 16); - *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); - *dst++ = (duk_uint8_t) (t & 0xff); - } - - /* Handle one slow path unit (or finish if we're done). */ - - n_equal = 0; - n_chars = 0; - t = 0; - for (;;) { - DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld", - (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t)); - - if (DUK_UNLIKELY(src >= src_end)) { - goto done; /* two level break */ - } - - x = duk_base64_dectab[*src++]; - if (DUK_UNLIKELY(x < 0)) { - if (x == -2) { - continue; /* allowed ascii whitespace */ - } else if (x == -3) { - n_equal++; - t <<= 6; - } else { - DUK_ASSERT(x == -1); - goto decode_error; - } - } else { - DUK_ASSERT(x >= 0 && x <= 63); - if (n_equal > 0) { - /* Don't allow actual chars after equal sign. */ - goto decode_error; - } - t = (t << 6) + x; - } - - if (DUK_UNLIKELY(n_chars == 3)) { - /* Emit 3 bytes and backtrack if there was padding. There's - * always space for the whole 3 bytes so no check needed. - */ - DUK_ASSERT(t <= 0xffffffL); - DUK_ASSERT((t >> 24) == 0); - *dst++ = (duk_uint8_t) (t >> 16); - *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); - *dst++ = (duk_uint8_t) (t & 0xff); - - if (DUK_UNLIKELY(n_equal > 0)) { - DUK_ASSERT(n_equal <= 4); - - /* There may be whitespace between the equal signs. */ - if (n_equal == 1) { - /* XXX= */ - dst -= 1; - } else if (n_equal == 2) { - /* XX== */ - dst -= 2; - } else { - goto decode_error; /* invalid padding */ - } - - /* Continue parsing after padding, allows concatenated, - * padded base64. - */ - } - break; /* back to fast loop */ - } else { - n_chars++; - } - } - } - done: - DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld", - (const void *) src, (const void *) src_end, (long) n_chars)); - - DUK_ASSERT(src == src_end); - - if (n_chars != 0) { - /* Here we'd have the option of decoding unpadded base64 - * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not - * accepted. - */ - goto decode_error; - } - - *out_dst_final = dst; - return 1; - - decode_error: - return 0; -} -#else /* DUK_USE_BASE64_FASTPATH */ -DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { - duk_uint_t t; - duk_uint_fast8_t x, y; - duk_small_uint_t group_idx; - duk_small_uint_t n_equal; - const duk_uint8_t *src_end; - - src_end = src + srclen; - t = 0; - group_idx = 0; - n_equal = 0; - - while (src < src_end) { - x = *src++; - - if (x >= 'A' && x <= 'Z') { - y = x - 'A' + 0; - } else if (x >= 'a' && x <= 'z') { - y = x - 'a' + 26; - } else if (x >= '0' && x <= '9') { - y = x - '0' + 52; - } else if (x == '+') { - y = 62; - } else if (x == '/') { - y = 63; - } else if (x == '=') { - /* We don't check the zero padding bytes here right now - * (that they're actually zero). This seems to be common - * behavior for base-64 decoders. - */ - - n_equal++; - t <<= 6; /* shift in zeroes */ - goto skip_add; - } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) { - /* allow basic ASCII whitespace */ - continue; - } else { - goto decode_error; - } - - if (n_equal > 0) { - /* Don't allow mixed padding and actual chars. */ - goto decode_error; - } - t = (t << 6) + y; - skip_add: - - if (group_idx == 3) { - /* output 3 bytes from 't' */ - *dst++ = (duk_uint8_t) ((t >> 16) & 0xff); - *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); - *dst++ = (duk_uint8_t) (t & 0xff); - - if (DUK_UNLIKELY(n_equal > 0)) { - /* Backtrack. */ - DUK_ASSERT(n_equal <= 4); - if (n_equal == 1) { - dst -= 1; - } else if (n_equal == 2) { - dst -= 2; - } else { - goto decode_error; /* invalid padding */ - } - - /* Here we can choose either to end parsing and ignore - * whatever follows, or to continue parsing in case - * multiple (possibly padded) base64 strings have been - * concatenated. Currently, keep on parsing. - */ - n_equal = 0; - } - - t = 0; - group_idx = 0; - } else { - group_idx++; - } - } - - if (group_idx != 0) { - /* Here we'd have the option of decoding unpadded base64 - * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not - * accepted. - */ - goto decode_error; - } - - *out_dst_final = dst; - return 1; - - decode_error: - return 0; -} -#endif /* DUK_USE_BASE64_FASTPATH */ - -DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) { - const duk_uint8_t *src; - duk_size_t srclen; - duk_size_t dstlen; - duk_uint8_t *dst; - const char *ret; - - DUK_ASSERT_API_ENTRY(thr); - - /* XXX: optimize for string inputs: no need to coerce to a buffer - * which makes a copy of the input. - */ - - idx = duk_require_normalize_index(thr, idx); - src = duk__prep_codec_arg(thr, idx, &srclen); - /* Note: for srclen=0, src may be NULL */ - - /* Computation must not wrap; this limit works for 32-bit size_t: - * >>> srclen = 3221225469 - * >>> '%x' % ((srclen + 2) / 3 * 4) - * 'fffffffc' - */ - if (srclen > 3221225469UL) { - goto type_error; - } - dstlen = (srclen + 2) / 3 * 4; - dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen); - - duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst); - - ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */ - duk_replace(thr, idx); - return ret; - - type_error: - DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED); - return NULL; /* never here */ -} - -DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) { - const duk_uint8_t *src; - duk_size_t srclen; - duk_size_t dstlen; - duk_uint8_t *dst; - duk_uint8_t *dst_final; - duk_bool_t retval; - - DUK_ASSERT_API_ENTRY(thr); - - /* XXX: optimize for buffer inputs: no need to coerce to a string - * which causes an unnecessary interning. - */ - - idx = duk_require_normalize_index(thr, idx); - src = duk__prep_codec_arg(thr, idx, &srclen); - - /* Computation must not wrap, only srclen + 3 is at risk of - * wrapping because after that the number gets smaller. - * This limit works for 32-bit size_t: - * 0x100000000 - 3 - 1 = 4294967292 - */ - if (srclen > 4294967292UL) { - goto type_error; - } - dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */ - dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen); - /* Note: for dstlen=0, dst may be NULL */ - - retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final); - if (!retval) { - goto type_error; - } - - /* XXX: convert to fixed buffer? */ - (void) duk_resize_buffer(thr, -1, (duk_size_t) (dst_final - dst)); - duk_replace(thr, idx); - return; - - type_error: - DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED); -} - -DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) { - const duk_uint8_t *inp; - duk_size_t len; - duk_size_t i; - duk_uint8_t *buf; - const char *ret; -#if defined(DUK_USE_HEX_FASTPATH) - duk_size_t len_safe; - duk_uint16_t *p16; -#endif - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - inp = duk__prep_codec_arg(thr, idx, &len); - DUK_ASSERT(inp != NULL || len == 0); - - /* Fixed buffer, no zeroing because we'll fill all the data. */ - buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len * 2); - DUK_ASSERT(buf != NULL); - -#if defined(DUK_USE_HEX_FASTPATH) - DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */ - p16 = (duk_uint16_t *) (void *) buf; - len_safe = len & ~0x03U; - for (i = 0; i < len_safe; i += 4) { - p16[0] = duk_hex_enctab[inp[i]]; - p16[1] = duk_hex_enctab[inp[i + 1]]; - p16[2] = duk_hex_enctab[inp[i + 2]]; - p16[3] = duk_hex_enctab[inp[i + 3]]; - p16 += 4; - } - for (; i < len; i++) { - *p16++ = duk_hex_enctab[inp[i]]; - } -#else /* DUK_USE_HEX_FASTPATH */ - for (i = 0; i < len; i++) { - duk_small_uint_t t; - t = (duk_small_uint_t) inp[i]; - buf[i*2 + 0] = duk_lc_digits[t >> 4]; - buf[i*2 + 1] = duk_lc_digits[t & 0x0f]; - } -#endif /* DUK_USE_HEX_FASTPATH */ - - /* XXX: Using a string return value forces a string intern which is - * not always necessary. As a rough performance measure, hex encode - * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s - * without string coercion. Change to returning a buffer and let the - * caller coerce to string if necessary? - */ - - ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */ - duk_replace(thr, idx); - return ret; -} - -DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) { - const duk_uint8_t *inp; - duk_size_t len; - duk_size_t i; - duk_int_t t; - duk_uint8_t *buf; -#if defined(DUK_USE_HEX_FASTPATH) - duk_int_t chk; - duk_uint8_t *p; - duk_size_t len_safe; -#endif - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - inp = duk__prep_codec_arg(thr, idx, &len); - DUK_ASSERT(inp != NULL || len == 0); - - if (len & 0x01) { - goto type_error; - } - - /* Fixed buffer, no zeroing because we'll fill all the data. */ - buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len / 2); - DUK_ASSERT(buf != NULL); - -#if defined(DUK_USE_HEX_FASTPATH) - p = buf; - len_safe = len & ~0x07U; - for (i = 0; i < len_safe; i += 8) { - t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) | - ((duk_int_t) duk_hex_dectab[inp[i + 1]]); - chk = t; - p[0] = (duk_uint8_t) t; - t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) | - ((duk_int_t) duk_hex_dectab[inp[i + 3]]); - chk |= t; - p[1] = (duk_uint8_t) t; - t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) | - ((duk_int_t) duk_hex_dectab[inp[i + 5]]); - chk |= t; - p[2] = (duk_uint8_t) t; - t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) | - ((duk_int_t) duk_hex_dectab[inp[i + 7]]); - chk |= t; - p[3] = (duk_uint8_t) t; - p += 4; - - /* Check if any lookup above had a negative result. */ - if (DUK_UNLIKELY(chk < 0)) { - goto type_error; - } - } - for (; i < len; i += 2) { - t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | - ((duk_int_t) duk_hex_dectab[inp[i + 1]]); - if (DUK_UNLIKELY(t < 0)) { - goto type_error; - } - *p++ = (duk_uint8_t) t; - } -#else /* DUK_USE_HEX_FASTPATH */ - for (i = 0; i < len; i += 2) { - /* For invalid characters the value -1 gets extended to - * at least 16 bits. If either nybble is invalid, the - * resulting 't' will be < 0. - */ - t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | - ((duk_int_t) duk_hex_dectab[inp[i + 1]]); - if (DUK_UNLIKELY(t < 0)) { - goto type_error; - } - buf[i >> 1] = (duk_uint8_t) t; - } -#endif /* DUK_USE_HEX_FASTPATH */ - - duk_replace(thr, idx); - return; - - type_error: - DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED); -} - -#if defined(DUK_USE_JSON_SUPPORT) -DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) { -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t top_at_entry; -#endif - const char *ret; - - DUK_ASSERT_API_ENTRY(thr); -#if defined(DUK_USE_ASSERTIONS) - top_at_entry = duk_get_top(thr); -#endif - - idx = duk_require_normalize_index(thr, idx); - duk_bi_json_stringify_helper(thr, - idx /*idx_value*/, - DUK_INVALID_INDEX /*idx_replacer*/, - DUK_INVALID_INDEX /*idx_space*/, - 0 /*flags*/); - DUK_ASSERT(duk_is_string(thr, -1)); - duk_replace(thr, idx); - ret = duk_get_string(thr, idx); - - DUK_ASSERT(duk_get_top(thr) == top_at_entry); - - return ret; -} - -DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) { -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t top_at_entry; -#endif - - DUK_ASSERT_API_ENTRY(thr); -#if defined(DUK_USE_ASSERTIONS) - top_at_entry = duk_get_top(thr); -#endif - - idx = duk_require_normalize_index(thr, idx); - duk_bi_json_parse_helper(thr, - idx /*idx_value*/, - DUK_INVALID_INDEX /*idx_reviver*/, - 0 /*flags*/); - duk_replace(thr, idx); - - DUK_ASSERT(duk_get_top(thr) == top_at_entry); -} -#else /* DUK_USE_JSON_SUPPORT */ -DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(idx); - DUK_ERROR_UNSUPPORTED(thr); -} - -DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(idx); - DUK_ERROR_UNSUPPORTED(thr); -} -#endif /* DUK_USE_JSON_SUPPORT */ -#line 1 "duk_api_compile.c" -/* - * Compilation and evaluation - */ - -/* #include duk_internal.h -> already included */ - -typedef struct duk__compile_raw_args duk__compile_raw_args; -struct duk__compile_raw_args { - duk_size_t src_length; /* should be first on 64-bit platforms */ - const duk_uint8_t *src_buffer; - duk_uint_t flags; -}; - -/* Eval is just a wrapper now. */ -DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { - duk_int_t rc; - - DUK_ASSERT_API_ENTRY(thr); - - /* Note: strictness is *not* inherited from the current Duktape/C. - * This would be confusing because the current strictness state - * depends on whether we're running inside a Duktape/C activation - * (= strict mode) or outside of any activation (= non-strict mode). - * See tests/api/test-eval-strictness.c for more discussion. - */ - - /* [ ... source? filename? ] (depends on flags) */ - - rc = duk_compile_raw(thr, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */ - - /* [ ... closure/error ] */ - - if (rc != DUK_EXEC_SUCCESS) { - rc = DUK_EXEC_ERROR; - goto got_rc; - } - - duk_push_global_object(thr); /* explicit 'this' binding, see GH-164 */ - - if (flags & DUK_COMPILE_SAFE) { - rc = duk_pcall_method(thr, 0); - } else { - duk_call_method(thr, 0); - rc = DUK_EXEC_SUCCESS; - } - - /* [ ... result/error ] */ - - got_rc: - if (flags & DUK_COMPILE_NORESULT) { - duk_pop(thr); - } - - return rc; -} - -/* Helper which can be called both directly and with duk_safe_call(). */ -DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) { - duk__compile_raw_args *comp_args; - duk_uint_t flags; - duk_hcompfunc *h_templ; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(udata != NULL); - - /* Note: strictness is not inherited from the current Duktape/C - * context. Otherwise it would not be possible to compile - * non-strict code inside a Duktape/C activation (which is - * always strict now). See tests/api/test-eval-strictness.c - * for discussion. - */ - - /* [ ... source? filename? ] (depends on flags) */ - - comp_args = (duk__compile_raw_args *) udata; - flags = comp_args->flags; - - if (flags & DUK_COMPILE_NOFILENAME) { - /* Automatic filename: 'eval' or 'input'. */ - duk_push_hstring_stridx(thr, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT); - } - - /* [ ... source? filename ] */ - - if (!comp_args->src_buffer) { - duk_hstring *h_sourcecode; - - h_sourcecode = duk_get_hstring(thr, -2); - if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */ - (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */ - DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE); - } - DUK_ASSERT(h_sourcecode != NULL); - comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode); - comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode); - } - DUK_ASSERT(comp_args->src_buffer != NULL); - - if (flags & DUK_COMPILE_FUNCTION) { - flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR; - } - - /* [ ... source? filename ] */ - - duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags); - - /* [ ... source? func_template ] */ - - if (flags & DUK_COMPILE_NOSOURCE) { - ; - } else { - duk_remove_m2(thr); - } - - /* [ ... func_template ] */ - - h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -1); - duk_js_push_closure(thr, - h_templ, - thr->builtins[DUK_BIDX_GLOBAL_ENV], - thr->builtins[DUK_BIDX_GLOBAL_ENV], - 1 /*add_auto_proto*/); - duk_remove_m2(thr); /* -> [ ... closure ] */ - - /* [ ... closure ] */ - - return 1; -} - -DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { - duk__compile_raw_args comp_args_alloc; - duk__compile_raw_args *comp_args = &comp_args_alloc; - - DUK_ASSERT_API_ENTRY(thr); - - if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) { - /* String length is computed here to avoid multiple evaluation - * of a macro argument in the calling side. - */ - src_length = DUK_STRLEN(src_buffer); - } - - comp_args->src_buffer = (const duk_uint8_t *) src_buffer; - comp_args->src_length = src_length; - comp_args->flags = flags; - - /* [ ... source? filename? ] (depends on flags) */ - - if (flags & DUK_COMPILE_SAFE) { - duk_int_t rc; - duk_int_t nargs; - duk_int_t nrets = 1; - - /* Arguments can be: [ source? filename? &comp_args] so that - * nargs is 1 to 3. Call site encodes the correct nargs count - * directly into flags. - */ - nargs = flags & 0x07; - DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) + - ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1)); - rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets); - - /* [ ... closure ] */ - return rc; - } - - (void) duk__do_compile(thr, (void *) comp_args); - - /* [ ... closure ] */ - return DUK_EXEC_SUCCESS; -} -#line 1 "duk_api_debug.c" -/* - * Debugging related API calls - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_JSON_SUPPORT) -DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) { - duk_idx_t idx; - duk_idx_t top; - - DUK_ASSERT_API_ENTRY(thr); - - /* We don't duk_require_stack() here now, but rely on the caller having - * enough space. - */ - - top = duk_get_top(thr); - duk_push_array(thr); - for (idx = 0; idx < top; idx++) { - duk_dup(thr, idx); - duk_put_prop_index(thr, -2, (duk_uarridx_t) idx); - } - - /* XXX: conversion errors should not propagate outwards. - * Perhaps values need to be coerced individually? - */ - duk_bi_json_stringify_helper(thr, - duk_get_top_index(thr), /*idx_value*/ - DUK_INVALID_INDEX, /*idx_replacer*/ - DUK_INVALID_INDEX, /*idx_space*/ - DUK_JSON_FLAG_EXT_CUSTOM | - DUK_JSON_FLAG_ASCII_ONLY | - DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/); - - duk_push_sprintf(thr, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(thr, -1)); - duk_replace(thr, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */ - duk_pop(thr); - DUK_ASSERT(duk_is_string(thr, -1)); -} -#else /* DUK_USE_JSON_SUPPORT */ -DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ERROR_UNSUPPORTED(thr); -} -#endif /* DUK_USE_JSON_SUPPORT */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - -DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr, - duk_debug_read_function read_cb, - duk_debug_write_function write_cb, - duk_debug_peek_function peek_cb, - duk_debug_read_flush_function read_flush_cb, - duk_debug_write_flush_function write_flush_cb, - duk_debug_request_function request_cb, - duk_debug_detached_function detached_cb, - void *udata) { - duk_heap *heap; - const char *str; - duk_size_t len; - - /* XXX: should there be an error or an automatic detach if - * already attached? - */ - - DUK_D(DUK_DPRINT("application called duk_debugger_attach()")); - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(read_cb != NULL); - DUK_ASSERT(write_cb != NULL); - /* Other callbacks are optional. */ - - heap = thr->heap; - heap->dbg_read_cb = read_cb; - heap->dbg_write_cb = write_cb; - heap->dbg_peek_cb = peek_cb; - heap->dbg_read_flush_cb = read_flush_cb; - heap->dbg_write_flush_cb = write_flush_cb; - heap->dbg_request_cb = request_cb; - heap->dbg_detached_cb = detached_cb; - heap->dbg_udata = udata; - heap->dbg_have_next_byte = 0; - - /* Start in paused state. */ - heap->dbg_processing = 0; - heap->dbg_state_dirty = 0; - heap->dbg_force_restart = 0; - heap->dbg_pause_flags = 0; - heap->dbg_pause_act = NULL; - heap->dbg_pause_startline = 0; - heap->dbg_exec_counter = 0; - heap->dbg_last_counter = 0; - heap->dbg_last_time = 0.0; - duk_debug_set_paused(heap); /* XXX: overlap with fields above */ - - /* Send version identification and flush right afterwards. Note that - * we must write raw, unframed bytes here. - */ - duk_push_sprintf(thr, "%ld %ld %s %s\n", - (long) DUK_DEBUG_PROTOCOL_VERSION, - (long) DUK_VERSION, - (const char *) DUK_GIT_DESCRIBE, - (const char *) DUK_USE_TARGET_INFO); - str = duk_get_lstring(thr, -1, &len); - DUK_ASSERT(str != NULL); - duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len); - duk_debug_write_flush(thr); - duk_pop(thr); -} - -DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) { - DUK_D(DUK_DPRINT("application called duk_debugger_detach()")); - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->heap != NULL); - - /* Can be called multiple times with no harm. */ - duk_debug_do_detach(thr->heap); -} - -DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) { - duk_bool_t processed_messages; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->heap != NULL); - - if (!duk_debug_is_attached(thr->heap)) { - return; - } - if (thr->callstack_curr != NULL || thr->heap->dbg_processing) { - /* Calling duk_debugger_cooperate() while Duktape is being - * called into is not supported. This is not a 100% check - * but prevents any damage in most cases. - */ - return; - } - - processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/); - DUK_UNREF(processed_messages); -} - -DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) { - duk_idx_t top; - duk_idx_t idx; - duk_bool_t ret = 0; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->heap != NULL); - - DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues)); - - top = duk_get_top(thr); - if (top < nvalues) { - DUK_ERROR_RANGE(thr, "not enough stack values for notify"); - return ret; /* unreachable */ - } - if (duk_debug_is_attached(thr->heap)) { - duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY); - for (idx = top - nvalues; idx < top; idx++) { - duk_tval *tv = DUK_GET_TVAL_POSIDX(thr, idx); - duk_debug_write_tval(thr, tv); - } - duk_debug_write_eom(thr); - - /* Return non-zero (true) if we have a good reason to believe - * the notify was delivered; if we're still attached at least - * a transport error was not indicated by the transport write - * callback. This is not a 100% guarantee of course. - */ - if (duk_debug_is_attached(thr->heap)) { - ret = 1; - } - } - duk_pop_n(thr, nvalues); - return ret; -} - -DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->heap != NULL); - - DUK_D(DUK_DPRINT("application called duk_debugger_pause()")); - - /* Treat like a debugger statement: ignore when not attached. */ - if (duk_debug_is_attached(thr->heap)) { - if (duk_debug_is_paused(thr->heap)) { - DUK_D(DUK_DPRINT("duk_debugger_pause() called when already paused; ignoring")); - } else { - duk_debug_set_paused(thr->heap); - - /* Pause on the next opcode executed. This is always safe to do even - * inside the debugger message loop: the interrupt counter will be reset - * to its proper value when the message loop exits. - */ - thr->interrupt_init = 1; - thr->interrupt_counter = 0; - } - } -} - -#else /* DUK_USE_DEBUGGER_SUPPORT */ - -DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr, - duk_debug_read_function read_cb, - duk_debug_write_function write_cb, - duk_debug_peek_function peek_cb, - duk_debug_read_flush_function read_flush_cb, - duk_debug_write_flush_function write_flush_cb, - duk_debug_request_function request_cb, - duk_debug_detached_function detached_cb, - void *udata) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(read_cb); - DUK_UNREF(write_cb); - DUK_UNREF(peek_cb); - DUK_UNREF(read_flush_cb); - DUK_UNREF(write_flush_cb); - DUK_UNREF(request_cb); - DUK_UNREF(detached_cb); - DUK_UNREF(udata); - DUK_ERROR_TYPE(thr, "no debugger support"); -} - -DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ERROR_TYPE(thr, "no debugger support"); -} - -DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) { - /* nop */ - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(thr); -} - -DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) { - duk_idx_t top; - - DUK_ASSERT_API_ENTRY(thr); - - top = duk_get_top(thr); - if (top < nvalues) { - DUK_ERROR_RANGE_INVALID_COUNT(thr); - return 0; /* unreachable */ - } - - /* No debugger support, just pop values. */ - duk_pop_n(thr, nvalues); - return 0; -} - -DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) { - /* Treat like debugger statement: nop */ - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(thr); -} - -#endif /* DUK_USE_DEBUGGER_SUPPORT */ -#line 1 "duk_api_heap.c" -/* - * Heap creation and destruction - */ - -/* #include duk_internal.h -> already included */ - -typedef struct duk_internal_thread_state duk_internal_thread_state; - -struct duk_internal_thread_state { - duk_ljstate lj; - duk_bool_t creating_error; - duk_hthread *curr_thread; - duk_int_t call_recursion_depth; -}; - -DUK_EXTERNAL duk_hthread *duk_create_heap(duk_alloc_function alloc_func, - duk_realloc_function realloc_func, - duk_free_function free_func, - void *heap_udata, - duk_fatal_function fatal_handler) { - duk_heap *heap = NULL; - duk_hthread *thr; - - /* Assume that either all memory funcs are NULL or non-NULL, mixed - * cases will now be unsafe. - */ - - /* XXX: just assert non-NULL values here and make caller arguments - * do the defaulting to the default implementations (smaller code)? - */ - - if (!alloc_func) { - DUK_ASSERT(realloc_func == NULL); - DUK_ASSERT(free_func == NULL); -#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) - alloc_func = duk_default_alloc_function; - realloc_func = duk_default_realloc_function; - free_func = duk_default_free_function; -#else - DUK_D(DUK_DPRINT("no allocation functions given and no default providers")); - return NULL; -#endif - } else { - DUK_ASSERT(realloc_func != NULL); - DUK_ASSERT(free_func != NULL); - } - - if (!fatal_handler) { - fatal_handler = duk_default_fatal_handler; - } - - DUK_ASSERT(alloc_func != NULL); - DUK_ASSERT(realloc_func != NULL); - DUK_ASSERT(free_func != NULL); - DUK_ASSERT(fatal_handler != NULL); - - heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler); - if (!heap) { - return NULL; - } - thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - return thr; -} - -DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr) { - duk_heap *heap; - - if (!thr) { - return; - } - DUK_ASSERT_API_ENTRY(thr); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - duk_heap_free(heap); -} - -DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) { - duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state; - duk_heap *heap; - duk_ljstate *lj; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(state != NULL); /* unvalidated */ - - /* Currently not supported when called from within a finalizer. - * If that is done, the finalizer will remain running indefinitely, - * preventing other finalizers from executing. The assert is a bit - * wider, checking that it would be OK to run pending finalizers. - */ - DUK_ASSERT(thr->heap->pf_prevent_count == 0); - - /* Currently not supported to duk_suspend() from an errCreate() - * call. - */ - DUK_ASSERT(thr->heap->creating_error == 0); - - heap = thr->heap; - lj = &heap->lj; - - duk_push_tval(thr, &lj->value1); - duk_push_tval(thr, &lj->value2); - - /* XXX: creating_error == 0 is asserted above, so no need to store. */ - DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate)); - snapshot->creating_error = heap->creating_error; - snapshot->curr_thread = heap->curr_thread; - snapshot->call_recursion_depth = heap->call_recursion_depth; - - lj->jmpbuf_ptr = NULL; - lj->type = DUK_LJ_TYPE_UNKNOWN; - DUK_TVAL_SET_UNDEFINED(&lj->value1); - DUK_TVAL_SET_UNDEFINED(&lj->value2); - heap->creating_error = 0; - heap->curr_thread = NULL; - heap->call_recursion_depth = 0; -} - -DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) { - const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state; - duk_heap *heap; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(state != NULL); /* unvalidated */ - - /* Shouldn't be necessary if duk_suspend() is called before - * duk_resume(), but assert in case API sequence is incorrect. - */ - DUK_ASSERT(thr->heap->pf_prevent_count == 0); - DUK_ASSERT(thr->heap->creating_error == 0); - - heap = thr->heap; - - DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate)); - heap->creating_error = snapshot->creating_error; - heap->curr_thread = snapshot->curr_thread; - heap->call_recursion_depth = snapshot->call_recursion_depth; - - duk_pop_2(thr); -} - -/* XXX: better place for this */ -DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr) { - duk_hobject *h_glob; - duk_hobject *h_prev_glob; - duk_hobjenv *h_env; - duk_hobject *h_prev_env; - - DUK_ASSERT_API_ENTRY(thr); - - DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(thr, -1))); - - h_glob = duk_require_hobject(thr, -1); - DUK_ASSERT(h_glob != NULL); - - /* - * Replace global object. - */ - - h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL]; - DUK_UNREF(h_prev_glob); - thr->builtins[DUK_BIDX_GLOBAL] = h_glob; - DUK_HOBJECT_INCREF(thr, h_glob); - DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */ - - /* - * Replace lexical environment for global scope - * - * Create a new object environment for the global lexical scope. - * We can't just reset the _Target property of the current one, - * because the lexical scope is shared by other threads with the - * same (initial) built-ins. - */ - - h_env = duk_hobjenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); - DUK_ASSERT(h_env != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_env) == NULL); - - DUK_ASSERT(h_env->target == NULL); - DUK_ASSERT(h_glob != NULL); - h_env->target = h_glob; - DUK_HOBJECT_INCREF(thr, h_glob); - DUK_ASSERT(h_env->has_this == 0); - - /* [ ... new_glob ] */ - - h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - thr->builtins[DUK_BIDX_GLOBAL_ENV] = (duk_hobject *) h_env; - DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_env); - DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */ - DUK_UNREF(h_env); /* without refcounts */ - DUK_UNREF(h_prev_env); - - /* [ ... new_glob ] */ - - duk_pop(thr); - - /* [ ... ] */ -} -#line 1 "duk_api_inspect.c" -/* - * Inspection - */ - -/* #include duk_internal.h -> already included */ - -/* For footprint efficient multiple value setting: arrays are much better than - * varargs, format string with parsing is often better than string pointer arrays. - */ -DUK_LOCAL void duk__inspect_multiple_uint(duk_hthread *thr, const char *fmt, duk_int_t *vals) { - duk_int_t val; - const char *p; - const char *p_curr; - duk_size_t len; - - for (p = fmt;;) { - len = DUK_STRLEN(p); - p_curr = p; - p += len + 1; - if (len == 0) { - /* Double NUL (= empty key) terminates. */ - break; - } - val = *vals++; - if (val >= 0) { - /* Negative values are markers to skip key. */ - duk_push_string(thr, p_curr); - duk_push_int(thr, val); - duk_put_prop(thr, -3); - } - } -} - -/* Raw helper to extract internal information / statistics about a value. - * The return value is an object with properties that are version specific. - * The properties must not expose anything that would lead to security - * issues (e.g. exposing compiled function 'data' buffer might be an issue). - * Currently only counts and sizes and such are given so there shouldn't - * be security implications. - */ - -#define DUK__IDX_TYPE 0 -#define DUK__IDX_ITAG 1 -#define DUK__IDX_REFC 2 -#define DUK__IDX_HBYTES 3 -#define DUK__IDX_CLASS 4 -#define DUK__IDX_PBYTES 5 -#define DUK__IDX_ESIZE 6 -#define DUK__IDX_ENEXT 7 -#define DUK__IDX_ASIZE 8 -#define DUK__IDX_HSIZE 9 -#define DUK__IDX_BCBYTES 10 -#define DUK__IDX_DBYTES 11 -#define DUK__IDX_TSTATE 12 -#define DUK__IDX_VARIANT 13 - -DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_heaphdr *h; - /* The temporary values should be in an array rather than individual - * variables which (in practice) ensures that the compiler won't map - * them to registers and emit a lot of unnecessary shuffling code. - */ - duk_int_t vals[14]; - - DUK_ASSERT_API_ENTRY(thr); - - /* Assume two's complement and set everything to -1. */ - DUK_MEMSET((void *) &vals, (int) 0xff, sizeof(vals)); - DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */ - - tv = duk_get_tval_or_unused(thr, idx); - h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL); - - vals[DUK__IDX_TYPE] = duk_get_type_tval(tv); - vals[DUK__IDX_ITAG] = (duk_int_t) DUK_TVAL_GET_TAG(tv); - - duk_push_bare_object(thr); /* Invalidates 'tv'. */ - tv = NULL; - - if (h == NULL) { - goto finish; - } - duk_push_pointer(thr, (void *) h); - duk_put_prop_string(thr, -2, "hptr"); - -#if 0 - /* Covers a lot of information, e.g. buffer and string variants. */ - duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h)); - duk_put_prop_string(thr, -2, "hflags"); -#endif - -#if defined(DUK_USE_REFERENCE_COUNTING) - vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h); -#endif - vals[DUK__IDX_VARIANT] = 0; - - /* Heaphdr size and additional allocation size, followed by - * type specific stuff (with varying value count). - */ - switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) { - case DUK_HTYPE_STRING: { - duk_hstring *h_str = (duk_hstring *) h; - vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1); -#if defined(DUK_USE_HSTRING_EXTDATA) - if (DUK_HSTRING_HAS_EXTDATA(h_str)) { - vals[DUK__IDX_VARIANT] = 1; - } -#endif - break; - } - case DUK_HTYPE_OBJECT: { - duk_hobject *h_obj = (duk_hobject *) h; - - /* XXX: variants here are maybe pointless; class is enough? */ - if (DUK_HOBJECT_IS_ARRAY(h_obj)) { - vals[DUK__IDX_HBYTES] = sizeof(duk_harray); - } else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { - vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc); - } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) { - vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc); - } else if (DUK_HOBJECT_IS_THREAD(h_obj)) { - vals[DUK__IDX_HBYTES] = sizeof(duk_hthread); - vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state; -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { - vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj); - /* XXX: some size information */ -#endif - } else { - vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject); - } - - vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj); - vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj), - vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj); - vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj); - vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj); - vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj); - - /* Note: e_next indicates the number of gc-reachable entries - * in the entry part, and also indicates the index where the - * next new property would be inserted. It does *not* indicate - * the number of non-NULL keys present in the object. That - * value could be counted separately but requires a pass through - * the key list. - */ - - if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { - duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj); - vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0); - } - break; - } - case DUK_HTYPE_BUFFER: { - duk_hbuffer *h_buf = (duk_hbuffer *) h; - - if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) { - if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) { - vals[DUK__IDX_VARIANT] = 2; /* buffer variant 2: external */ - vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external)); - } else { - /* When alloc_size == 0 the second allocation may not - * actually exist. - */ - vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */ - vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic)); - } - vals[DUK__IDX_DBYTES] = (duk_int_t) (DUK_HBUFFER_GET_SIZE(h_buf)); - } else { - DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */ - vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf)); - } - break; - } - } - - finish: - duk__inspect_multiple_uint(thr, - "type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00" - "pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00" - "bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00", - (duk_int_t *) &vals); -} - -DUK_EXTERNAL void duk_inspect_callstack_entry(duk_hthread *thr, duk_int_t level) { - duk_activation *act; - duk_uint_fast32_t pc; - duk_uint_fast32_t line; - - DUK_ASSERT_API_ENTRY(thr); - - /* -1 = top callstack entry - * -2 = caller of level -1 - * etc - */ - act = duk_hthread_get_activation_for_level(thr, level); - if (act == NULL) { - duk_push_undefined(thr); - return; - } - duk_push_bare_object(thr); - - /* Relevant PC is just before current one because PC is - * post-incremented. This should match what error augment - * code does. - */ - pc = duk_hthread_get_act_prev_pc(thr, act); - - duk_push_tval(thr, &act->tv_func); - - duk_push_uint(thr, (duk_uint_t) pc); - duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_PC); - -#if defined(DUK_USE_PC2LINE) - line = duk_hobject_pc2line_query(thr, -1, pc); -#else - line = 0; -#endif - duk_push_uint(thr, (duk_uint_t) line); - duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_LINE_NUMBER); - - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_LC_FUNCTION); - /* Providing access to e.g. act->lex_env would be dangerous: these - * internal structures must never be accessible to the application. - * Duktape relies on them having consistent data, and this consistency - * is only asserted for, not checked for. - */ -} - -/* automatic undefs */ -#undef DUK__IDX_ASIZE -#undef DUK__IDX_BCBYTES -#undef DUK__IDX_CLASS -#undef DUK__IDX_DBYTES -#undef DUK__IDX_ENEXT -#undef DUK__IDX_ESIZE -#undef DUK__IDX_HBYTES -#undef DUK__IDX_HSIZE -#undef DUK__IDX_ITAG -#undef DUK__IDX_PBYTES -#undef DUK__IDX_REFC -#undef DUK__IDX_TSTATE -#undef DUK__IDX_TYPE -#undef DUK__IDX_VARIANT -#line 1 "duk_api_memory.c" -/* - * Memory calls. - */ - -/* #include duk_internal.h -> already included */ - -DUK_EXTERNAL void *duk_alloc_raw(duk_hthread *thr, duk_size_t size) { - DUK_ASSERT_API_ENTRY(thr); - - return DUK_ALLOC_RAW(thr->heap, size); -} - -DUK_EXTERNAL void duk_free_raw(duk_hthread *thr, void *ptr) { - DUK_ASSERT_API_ENTRY(thr); - - DUK_FREE_RAW(thr->heap, ptr); -} - -DUK_EXTERNAL void *duk_realloc_raw(duk_hthread *thr, void *ptr, duk_size_t size) { - DUK_ASSERT_API_ENTRY(thr); - - return DUK_REALLOC_RAW(thr->heap, ptr, size); -} - -DUK_EXTERNAL void *duk_alloc(duk_hthread *thr, duk_size_t size) { - DUK_ASSERT_API_ENTRY(thr); - - return DUK_ALLOC(thr->heap, size); -} - -DUK_EXTERNAL void duk_free(duk_hthread *thr, void *ptr) { - DUK_ASSERT_API_ENTRY(thr); - - DUK_FREE_CHECKED(thr, ptr); -} - -DUK_EXTERNAL void *duk_realloc(duk_hthread *thr, void *ptr, duk_size_t size) { - DUK_ASSERT_API_ENTRY(thr); - - /* - * Note: since this is an exposed API call, there should be - * no way a mark-and-sweep could have a side effect on the - * memory allocation behind 'ptr'; the pointer should never - * be something that Duktape wants to change. - * - * Thus, no need to use DUK_REALLOC_INDIRECT (and we don't - * have the storage location here anyway). - */ - - return DUK_REALLOC(thr->heap, ptr, size); -} - -DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs) { - duk_heap *heap; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(out_funcs != NULL); - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - - heap = thr->heap; - out_funcs->alloc_func = heap->alloc_func; - out_funcs->realloc_func = heap->realloc_func; - out_funcs->free_func = heap->free_func; - out_funcs->udata = heap->heap_udata; -} - -DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) { - duk_heap *heap; - duk_small_uint_t ms_flags; - - DUK_ASSERT_API_ENTRY(thr); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - DUK_D(DUK_DPRINT("mark-and-sweep requested by application")); - DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY); /* Compact flag is 1:1 with emergency flag which forces compaction. */ - ms_flags = (duk_small_uint_t) flags; - duk_heap_mark_and_sweep(heap, ms_flags); -} -#line 1 "duk_api_object.c" -/* - * Object handling: property access and other support functions. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Property handling - * - * The API exposes only the most common property handling functions. - * The caller can invoke Ecmascript built-ins for full control (e.g. - * defineProperty, getOwnPropertyDescriptor). - */ - -DUK_EXTERNAL duk_bool_t duk_get_prop(duk_hthread *thr, duk_idx_t obj_idx) { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_bool_t rc; - - DUK_ASSERT_API_ENTRY(thr); - - /* Note: copying tv_obj and tv_key to locals to shield against a valstack - * resize is not necessary for a property get right now. - */ - - tv_obj = duk_require_tval(thr, obj_idx); - tv_key = duk_require_tval(thr, -1); - - rc = duk_hobject_getprop(thr, tv_obj, tv_key); - DUK_ASSERT(rc == 0 || rc == 1); - /* a value is left on stack regardless of rc */ - - duk_remove_m2(thr); /* remove key */ - DUK_ASSERT(duk_is_undefined(thr, -1) || rc == 1); - return rc; /* 1 if property found, 0 otherwise */ -} - -DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(key != NULL); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_string(thr, key); - return duk_get_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(key != NULL); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_lstring(thr, key, key_len); - return duk_get_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_uarridx(thr, arr_idx); - return duk_get_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ - return duk_get_prop(thr, obj_idx); -} - -DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_STRIDX_VALID(stridx); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); - return duk_get_prop(thr, obj_idx); -} - -DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { - return duk_get_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), - (duk_small_uint_t) (packed_args & 0xffffUL)); -} - -DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) { - duk_bool_t rc; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_STRIDX_VALID(stridx); - - rc = duk_get_prop_stridx(thr, obj_idx, stridx); - if (out_has_prop) { - *out_has_prop = rc; - } - rc = duk_to_boolean(thr, -1); - DUK_ASSERT(rc == 0 || rc == 1); - duk_pop(thr); - return rc; -} - -DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_tval *tv_val; - duk_bool_t throw_flag; - duk_bool_t rc; - - /* Note: copying tv_obj and tv_key to locals to shield against a valstack - * resize is not necessary for a property put right now (putprop protects - * against it internally). - */ - - /* Key and value indices are either (-2, -1) or (-1, -2). Given idx_key, - * idx_val is always (idx_key ^ 0x01). - */ - DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) || - (idx_key == -1 && (idx_key ^ 1) == -2)); - /* XXX: Direct access; faster validation. */ - tv_obj = duk_require_tval(thr, obj_idx); - tv_key = duk_require_tval(thr, idx_key); - tv_val = duk_require_tval(thr, idx_key ^ 1); - throw_flag = duk_is_strict_call(thr); - - rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag); - DUK_ASSERT(rc == 0 || rc == 1); - - duk_pop_2(thr); /* remove key and value */ - return rc; /* 1 if property found, 0 otherwise */ -} - -DUK_EXTERNAL duk_bool_t duk_put_prop(duk_hthread *thr, duk_idx_t obj_idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__put_prop_shared(thr, obj_idx, -2); -} - -DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(key != NULL); - - /* Careful here and with other duk_put_prop_xxx() helpers: the - * target object and the property value may be in the same value - * stack slot (unusual, but still conceptually clear). - */ - obj_idx = duk_normalize_index(thr, obj_idx); - (void) duk_push_string(thr, key); - return duk__put_prop_shared(thr, obj_idx, -1); -} - -DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(key != NULL); - - obj_idx = duk_normalize_index(thr, obj_idx); - (void) duk_push_lstring(thr, key, key_len); - return duk__put_prop_shared(thr, obj_idx, -1); -} - -DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_uarridx(thr, arr_idx); - return duk__put_prop_shared(thr, obj_idx, -1); -} - -DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ - return duk__put_prop_shared(thr, obj_idx, -1); -} - - -DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_STRIDX_VALID(stridx); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); - return duk__put_prop_shared(thr, obj_idx, -1); -} - -DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { - return duk_put_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), - (duk_small_uint_t) (packed_args & 0xffffUL)); -} - -DUK_EXTERNAL duk_bool_t duk_del_prop(duk_hthread *thr, duk_idx_t obj_idx) { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_bool_t throw_flag; - duk_bool_t rc; - - DUK_ASSERT_API_ENTRY(thr); - - /* Note: copying tv_obj and tv_key to locals to shield against a valstack - * resize is not necessary for a property delete right now. - */ - - tv_obj = duk_require_tval(thr, obj_idx); - tv_key = duk_require_tval(thr, -1); - throw_flag = duk_is_strict_call(thr); - - rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag); - DUK_ASSERT(rc == 0 || rc == 1); - - duk_pop(thr); /* remove key */ - return rc; -} - -DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(key != NULL); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_string(thr, key); - return duk_del_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(key != NULL); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_lstring(thr, key, key_len); - return duk_del_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_uarridx(thr, arr_idx); - return duk_del_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ - return duk_del_prop(thr, obj_idx); -} - -DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_STRIDX_VALID(stridx); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); - return duk_del_prop(thr, obj_idx); -} - -#if 0 -DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { - return duk_del_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), - (duk_small_uint_t) (packed_args & 0xffffUL)); -} -#endif - -DUK_EXTERNAL duk_bool_t duk_has_prop(duk_hthread *thr, duk_idx_t obj_idx) { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_bool_t rc; - - DUK_ASSERT_API_ENTRY(thr); - - /* Note: copying tv_obj and tv_key to locals to shield against a valstack - * resize is not necessary for a property existence check right now. - */ - - tv_obj = duk_require_tval(thr, obj_idx); - tv_key = duk_require_tval(thr, -1); - - rc = duk_hobject_hasprop(thr, tv_obj, tv_key); - DUK_ASSERT(rc == 0 || rc == 1); - - duk_pop(thr); /* remove key */ - return rc; /* 1 if property found, 0 otherwise */ -} - -DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(key != NULL); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_string(thr, key); - return duk_has_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(key != NULL); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_lstring(thr, key, key_len); - return duk_has_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_uarridx(thr, arr_idx); - return duk_has_prop(thr, obj_idx); -} - -DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ - return duk_has_prop(thr, obj_idx); -} - -DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_STRIDX_VALID(stridx); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); - return duk_has_prop(thr, obj_idx); -} - -#if 0 -DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { - return duk_has_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), - (duk_small_uint_t) (packed_args & 0xffffUL)); -} -#endif - -/* Define own property without inheritance lookups and such. This differs from - * [[DefineOwnProperty]] because special behaviors (like Array 'length') are - * not invoked by this method. The caller must be careful to invoke any such - * behaviors if necessary. - */ -DUK_INTERNAL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags) { - duk_hobject *obj; - duk_hstring *key; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_require_hobject(thr, obj_idx); - DUK_ASSERT(obj != NULL); - key = duk_to_property_key_hstring(thr, -2); - DUK_ASSERT(key != NULL); - DUK_ASSERT(duk_require_tval(thr, -1) != NULL); - - duk_hobject_define_property_internal(thr, obj, key, desc_flags); - - duk_pop(thr); /* pop key */ -} - -DUK_INTERNAL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) { - duk_hobject *obj; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_require_hobject(thr, obj_idx); - DUK_ASSERT(obj != NULL); - - duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags); - /* value popped by call */ -} - -DUK_INTERNAL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) { - duk_hobject *obj; - duk_hstring *key; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_STRIDX_VALID(stridx); - - obj = duk_require_hobject(thr, obj_idx); - DUK_ASSERT(obj != NULL); - key = DUK_HTHREAD_GET_STRING(thr, stridx); - DUK_ASSERT(key != NULL); - DUK_ASSERT(duk_require_tval(thr, -1) != NULL); - - duk_hobject_define_property_internal(thr, obj, key, desc_flags); - /* value popped by call */ -} - -DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { - duk_xdef_prop_stridx(thr, (duk_idx_t) (duk_int8_t) (packed_args >> 24), - (duk_small_uint_t) (packed_args >> 8) & 0xffffUL, - (duk_small_uint_t) (packed_args & 0xffL)); -} - -#if 0 /*unused*/ -DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) { - duk_hobject *obj; - duk_hstring *key; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_STRIDX_VALID(stridx); - DUK_ASSERT_BIDX_VALID(builtin_idx); - - obj = duk_require_hobject(thr, obj_idx); - DUK_ASSERT(obj != NULL); - key = DUK_HTHREAD_GET_STRING(thr, stridx); - DUK_ASSERT(key != NULL); - - duk_push_hobject(thr, thr->builtins[builtin_idx]); - duk_hobject_define_property_internal(thr, obj, key, desc_flags); - /* value popped by call */ -} -#endif - -/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3) - * setter/getter into an object property. This is needed by the 'arguments' - * object creation code, function instance creation code, and Function.prototype.bind(). - */ - -DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_hstring_stridx(thr, stridx); - duk_push_hobject_bidx(thr, DUK_BIDX_TYPE_ERROR_THROWER); - duk_dup_top(thr); - duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */ -} - -/* Object.getOwnPropertyDescriptor() equivalent C binding. */ -DUK_EXTERNAL void duk_get_prop_desc(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(flags); /* no flags defined yet */ - - duk_hobject_object_get_own_property_descriptor(thr, obj_idx); /* [ ... key ] -> [ ... desc ] */ -} - -/* Object.defineProperty() equivalent C binding. */ -DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) { - duk_idx_t idx_base; - duk_hobject *obj; - duk_hstring *key; - duk_idx_t idx_value; - duk_hobject *get; - duk_hobject *set; - duk_uint_t is_data_desc; - duk_uint_t is_acc_desc; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_require_hobject(thr, obj_idx); - - is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE); - is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); - if (is_data_desc && is_acc_desc) { - /* "Have" flags must not be conflicting so that they would - * apply to both a plain property and an accessor at the same - * time. - */ - goto fail_invalid_desc; - } - - idx_base = duk_get_top_index(thr); - if (flags & DUK_DEFPROP_HAVE_SETTER) { - duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED | - DUK_TYPE_MASK_OBJECT | - DUK_TYPE_MASK_LIGHTFUNC); - set = duk_get_hobject_promote_lfunc(thr, idx_base); - if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) { - goto fail_not_callable; - } - idx_base--; - } else { - set = NULL; - } - if (flags & DUK_DEFPROP_HAVE_GETTER) { - duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED | - DUK_TYPE_MASK_OBJECT | - DUK_TYPE_MASK_LIGHTFUNC); - get = duk_get_hobject_promote_lfunc(thr, idx_base); - if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) { - goto fail_not_callable; - } - idx_base--; - } else { - get = NULL; - } - if (flags & DUK_DEFPROP_HAVE_VALUE) { - idx_value = idx_base; - idx_base--; - } else { - idx_value = (duk_idx_t) -1; - } - key = duk_to_property_key_hstring(thr, idx_base); - DUK_ASSERT(key != NULL); - - duk_require_valid_index(thr, idx_base); - - duk_hobject_define_property_helper(thr, - flags /*defprop_flags*/, - obj, - key, - idx_value, - get, - set, - 1 /*throw_flag*/); - - /* Clean up stack */ - - duk_set_top(thr, idx_base); - - /* [ ... obj ... ] */ - - return; - - fail_invalid_desc: - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR); - return; - - fail_not_callable: - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); - return; -} - -/* - * Object related - * - * Note: seal() and freeze() are accessible through Ecmascript bindings, - * and are not exposed through the API. - */ - -DUK_EXTERNAL void duk_compact(duk_hthread *thr, duk_idx_t obj_idx) { - duk_hobject *obj; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_get_hobject(thr, obj_idx); - if (obj) { - /* Note: this may fail, caller should protect the call if necessary */ - duk_hobject_compact_props(thr, obj); - } -} - -DUK_INTERNAL void duk_compact_m1(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - duk_compact(thr, -1); -} - -/* XXX: the duk_hobject_enum.c stack APIs should be reworked */ - -DUK_EXTERNAL void duk_enum(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t enum_flags) { - DUK_ASSERT_API_ENTRY(thr); - - duk_dup(thr, obj_idx); - duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - duk_hobject_enumerator_create(thr, enum_flags); /* [target] -> [enum] */ -} - -DUK_EXTERNAL duk_bool_t duk_next(duk_hthread *thr, duk_idx_t enum_index, duk_bool_t get_value) { - DUK_ASSERT_API_ENTRY(thr); - - duk_require_hobject(thr, enum_index); - duk_dup(thr, enum_index); - return duk_hobject_enumerator_next(thr, get_value); -} - -DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze) { - duk_tval *tv; - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, obj_idx); - DUK_ASSERT(tv != NULL); - - /* Seal/freeze are quite rare in practice so it'd be nice to get the - * correct behavior simply via automatic promotion (at the cost of some - * memory churn). However, the promoted objects don't behave the same, - * e.g. promoted lightfuncs are extensible. - */ - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_BUFFER: - /* Plain buffer: already sealed, but not frozen (and can't be frozen - * because index properties can't be made non-writable. - */ - if (is_freeze) { - goto fail_cannot_freeze; - } - break; - case DUK_TAG_LIGHTFUNC: - /* Lightfunc: already sealed and frozen, success. */ - break; - case DUK_TAG_OBJECT: - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) { - /* Buffer objects cannot be frozen because there's no internal - * support for making virtual array indices non-writable. - */ - DUK_DD(DUK_DDPRINT("cannot freeze a buffer object")); - goto fail_cannot_freeze; - } - duk_hobject_object_seal_freeze_helper(thr, h, is_freeze); - - /* Sealed and frozen objects cannot gain any more properties, - * so this is a good time to compact them. - */ - duk_hobject_compact_props(thr, h); - break; - default: - /* ES2015 Sections 19.1.2.5, 19.1.2.17 */ - break; - } - return; - - fail_cannot_freeze: - DUK_ERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */ -} - -DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) { - DUK_ASSERT_API_ENTRY(thr); - - duk_seal_freeze_raw(thr, obj_idx, 0 /*is_freeze*/); -} - -DUK_EXTERNAL void duk_freeze(duk_hthread *thr, duk_idx_t obj_idx) { - DUK_ASSERT_API_ENTRY(thr); - - duk_seal_freeze_raw(thr, obj_idx, 1 /*is_freeze*/); -} - -/* - * Helpers for writing multiple properties - */ - -DUK_EXTERNAL void duk_put_function_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_function_list_entry *funcs) { - const duk_function_list_entry *ent = funcs; - - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - if (ent != NULL) { - while (ent->key != NULL) { - duk_push_c_function(thr, ent->value, ent->nargs); - duk_put_prop_string(thr, obj_idx, ent->key); - ent++; - } - } -} - -DUK_EXTERNAL void duk_put_number_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_number_list_entry *numbers) { - const duk_number_list_entry *ent = numbers; - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - obj_idx = duk_require_normalize_index(thr, obj_idx); - if (ent != NULL) { - while (ent->key != NULL) { - tv = thr->valstack_top++; - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */ - DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */ - duk_put_prop_string(thr, obj_idx, ent->key); - ent++; - } - } -} - -/* - * Shortcut for accessing global object properties - */ - -DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_hthread *thr, const char *key) { - duk_bool_t ret; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - - /* XXX: direct implementation */ - - duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); - ret = duk_get_prop_string(thr, -1, key); - duk_remove_m2(thr); - return ret; -} - -DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) { - duk_bool_t ret; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - - /* XXX: direct implementation */ - - duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); - ret = duk_get_prop_lstring(thr, -1, key, key_len); - duk_remove_m2(thr); - return ret; -} - -DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) { - duk_bool_t ret; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - - /* XXX: direct implementation */ - - duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); - duk_insert(thr, -2); - ret = duk_put_prop_string(thr, -2, key); /* [ ... global val ] -> [ ... global ] */ - duk_pop(thr); - return ret; -} - -DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) { - duk_bool_t ret; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - - /* XXX: direct implementation */ - - duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); - duk_insert(thr, -2); - ret = duk_put_prop_lstring(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */ - duk_pop(thr); - return ret; -} - -/* - * Object prototype - */ - -DUK_EXTERNAL void duk_get_prototype(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *obj; - duk_hobject *proto; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_require_hobject(thr, idx); - DUK_ASSERT(obj != NULL); - - /* XXX: shared helper for duk_push_hobject_or_undefined()? */ - proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj); - if (proto) { - duk_push_hobject(thr, proto); - } else { - duk_push_undefined(thr); - } -} - -DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *obj; - duk_hobject *proto; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_require_hobject(thr, idx); - DUK_ASSERT(obj != NULL); - duk_require_type_mask(thr, -1, DUK_TYPE_MASK_UNDEFINED | - DUK_TYPE_MASK_OBJECT); - proto = duk_get_hobject(thr, -1); - /* proto can also be NULL here (allowed explicitly) */ - -#if defined(DUK_USE_ROM_OBJECTS) - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */ - return; - } -#endif - - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto); - - duk_pop(thr); -} - -/* - * Object finalizer - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -/* XXX: these could be implemented as macros calling an internal function - * directly. - * XXX: same issue as with Duktape.fin: there's no way to delete the property - * now (just set it to undefined). - */ -DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - duk_get_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER); -} - -DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - duk_bool_t callable; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_require_hobject(thr, idx); /* Get before 'put' so that 'idx' is correct. */ - callable = duk_is_callable(thr, -1); - duk_put_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER); - - /* In addition to setting the finalizer property, keep a "have - * finalizer" flag in duk_hobject in sync so that refzero can do - * a very quick finalizer check by walking the prototype chain - * and checking the flag alone. (Note that this means that just - * setting _Finalizer on an object won't affect finalizer checks.) - * - * NOTE: if the argument is a Proxy object, this flag will be set - * on the Proxy, not the target. As a result, the target won't get - * a finalizer flag and the Proxy also won't be finalized as there's - * an explicit Proxy check in finalization now. - */ - if (callable) { - DUK_HOBJECT_SET_HAVE_FINALIZER(h); - } else { - DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h); - } -} -#else /* DUK_USE_FINALIZER_SUPPORT */ -DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(idx); - DUK_ERROR_UNSUPPORTED(thr); -} - -DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(idx); - DUK_ERROR_UNSUPPORTED(thr); -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ -#line 1 "duk_api_stack.c" -/* - * API calls related to general value stack manipulation: resizing the value - * stack, pushing and popping values, type checking and reading values, - * coercing values, etc. - * - * Also contains internal functions (such as duk_get_tval()), defined - * in duk_api_internal.h, with semantics similar to the public API. - */ - -/* XXX: repetition of stack pre-checks -> helper or macro or inline */ -/* XXX: shared api error strings, and perhaps even throw code for rare cases? */ - -/* #include duk_internal.h -> already included */ - -/* - * Forward declarations - */ - -DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx); - -/* - * Global state for working around missing variadic macros - */ - -#if !defined(DUK_USE_VARIADIC_MACROS) -DUK_EXTERNAL const char *duk_api_global_filename = NULL; -DUK_EXTERNAL duk_int_t duk_api_global_line = 0; -#endif - -/* - * Misc helpers - */ - -DUK_LOCAL const char * const duk__symbol_type_strings[4] = { - "hidden", "global", "local", "wellknown" -}; - -#if !defined(DUK_USE_PACKED_TVAL) -DUK_LOCAL const duk_uint_t duk__type_from_tag[] = { - DUK_TYPE_NUMBER, - DUK_TYPE_NUMBER, /* fastint */ - DUK_TYPE_UNDEFINED, - DUK_TYPE_NULL, - DUK_TYPE_BOOLEAN, - DUK_TYPE_POINTER, - DUK_TYPE_LIGHTFUNC, - DUK_TYPE_NONE, - DUK_TYPE_STRING, - DUK_TYPE_OBJECT, - DUK_TYPE_BUFFER, -}; -DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = { - DUK_TYPE_MASK_NUMBER, - DUK_TYPE_MASK_NUMBER, /* fastint */ - DUK_TYPE_MASK_UNDEFINED, - DUK_TYPE_MASK_NULL, - DUK_TYPE_MASK_BOOLEAN, - DUK_TYPE_MASK_POINTER, - DUK_TYPE_MASK_LIGHTFUNC, - DUK_TYPE_MASK_NONE, - DUK_TYPE_MASK_STRING, - DUK_TYPE_MASK_OBJECT, - DUK_TYPE_MASK_BUFFER, -}; -#endif /* !DUK_USE_PACKED_TVAL */ - -/* Assert that there's room for one value. */ -#define DUK__ASSERT_SPACE() do { \ - DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \ - } while (0) - -/* Check that there's room to push one value. */ -#if defined(DUK_USE_VALSTACK_UNSAFE) -/* Faster but value stack overruns are memory unsafe. */ -#define DUK__CHECK_SPACE() DUK__ASSERT_SPACE() -#else -#define DUK__CHECK_SPACE() do { \ - if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \ - DUK_ERROR_RANGE_PUSH_BEYOND(thr); \ - } \ - } while (0) -#endif - -DUK_LOCAL duk_small_uint_t duk__get_symbol_type(duk_hstring *h) { - const duk_uint8_t *data; - duk_size_t len; - - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HSTRING_HAS_SYMBOL(h)); - DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h) >= 1); /* always true, symbol prefix */ - - data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); - len = DUK_HSTRING_GET_BYTELEN(h); - DUK_ASSERT(len >= 1); - - /* XXX: differentiate between 0x82 and 0xff (hidden vs. internal?)? */ - - if (data[0] == 0xffU) { - return DUK_SYMBOL_TYPE_HIDDEN; - } else if (data[0] == 0x82U) { - return DUK_SYMBOL_TYPE_HIDDEN; - } else if (data[0] == 0x80U) { - return DUK_SYMBOL_TYPE_GLOBAL; - } else if (data[len - 1] != 0xffU) { - return DUK_SYMBOL_TYPE_LOCAL; - } else { - return DUK_SYMBOL_TYPE_WELLKNOWN; - } -} - -DUK_LOCAL const char *duk__get_symbol_type_string(duk_hstring *h) { - duk_small_uint_t idx; - idx = duk__get_symbol_type(h); - DUK_ASSERT(idx < sizeof(duk__symbol_type_strings)); - return duk__symbol_type_strings[idx]; -} - -DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag); - -DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) { - duk_tval *tv; - duk_small_int_t c; - duk_double_t d; - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - - /* - * Special cases like NaN and +/- Infinity are handled explicitly - * because a plain C coercion from double to int handles these cases - * in undesirable ways. For instance, NaN may coerce to INT_MIN - * (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX). - * - * This double-to-int coercion differs from ToInteger() because it - * has a finite range (ToInteger() allows e.g. +/- Infinity). It - * also differs from ToInt32() because the INT_MIN/INT_MAX clamping - * depends on the size of the int type on the platform. In particular, - * on platforms with a 64-bit int type, the full range is allowed. - */ - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv)) { - duk_int64_t t = DUK_TVAL_GET_FASTINT(tv); -#if (DUK_INT_MAX <= 0x7fffffffL) - /* Clamping only necessary for 32-bit ints. */ - if (t < DUK_INT_MIN) { - t = DUK_INT_MIN; - } else if (t > DUK_INT_MAX) { - t = DUK_INT_MAX; - } -#endif - return (duk_int_t) t; - } -#endif - - if (DUK_TVAL_IS_NUMBER(tv)) { - d = DUK_TVAL_GET_NUMBER(tv); - c = (duk_small_int_t) DUK_FPCLASSIFY(d); - if (c == DUK_FP_NAN) { - return 0; - } else if (d < (duk_double_t) DUK_INT_MIN) { - /* covers -Infinity */ - return DUK_INT_MIN; - } else if (d > (duk_double_t) DUK_INT_MAX) { - /* covers +Infinity */ - return DUK_INT_MAX; - } else { - /* coerce towards zero */ - return (duk_int_t) d; - } - } - - if (require) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); - /* not reachable */ - } - - return def_value; -} - -DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) { - duk_tval *tv; - duk_small_int_t c; - duk_double_t d; - - /* Same as above but for unsigned int range. */ - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv)) { - duk_int64_t t = DUK_TVAL_GET_FASTINT(tv); - if (t < 0) { - t = 0; - } -#if (DUK_UINT_MAX <= 0xffffffffUL) - /* Clamping only necessary for 32-bit ints. */ - else if (t > DUK_UINT_MAX) { - t = DUK_UINT_MAX; - } -#endif - return (duk_uint_t) t; - } -#endif - - if (DUK_TVAL_IS_NUMBER(tv)) { - d = DUK_TVAL_GET_NUMBER(tv); - c = (duk_small_int_t) DUK_FPCLASSIFY(d); - if (c == DUK_FP_NAN) { - return 0; - } else if (d < 0.0) { - /* covers -Infinity */ - return (duk_uint_t) 0; - } else if (d > (duk_double_t) DUK_UINT_MAX) { - /* covers +Infinity */ - return (duk_uint_t) DUK_UINT_MAX; - } else { - /* coerce towards zero */ - return (duk_uint_t) d; - } - } - - if (require) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); - /* not reachable */ - } - - return def_value; -} - -/* - * Stack index validation/normalization and getting a stack duk_tval ptr. - * - * These are called by many API entrypoints so the implementations must be - * fast and "inlined". - * - * There's some repetition because of this; keep the functions in sync. - */ - -DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_hthread *thr, duk_idx_t idx) { - duk_uidx_t vs_size; - duk_uidx_t uidx; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_INVALID_INDEX < 0); - - /* Care must be taken to avoid pointer wrapping in the index - * validation. For instance, on a 32-bit platform with 8-byte - * duk_tval the index 0x20000000UL would wrap the memory space - * once. - */ - - /* Assume value stack sizes (in elements) fits into duk_idx_t. */ - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); - DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ - - if (idx < 0) { - uidx = vs_size + (duk_uidx_t) idx; - } else { - /* since index non-negative */ - DUK_ASSERT(idx != DUK_INVALID_INDEX); - uidx = (duk_uidx_t) idx; - } - - /* DUK_INVALID_INDEX won't be accepted as a valid index. */ - DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - - if (DUK_LIKELY(uidx < vs_size)) { - return (duk_idx_t) uidx; - } - return DUK_INVALID_INDEX; -} - -DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t idx) { - duk_uidx_t vs_size; - duk_uidx_t uidx; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_INVALID_INDEX < 0); - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); - DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ - - if (idx < 0) { - uidx = vs_size + (duk_uidx_t) idx; - } else { - DUK_ASSERT(idx != DUK_INVALID_INDEX); - uidx = (duk_uidx_t) idx; - } - - /* DUK_INVALID_INDEX won't be accepted as a valid index. */ - DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - - if (DUK_LIKELY(uidx < vs_size)) { - return (duk_idx_t) uidx; - } - DUK_ERROR_RANGE_INDEX(thr, idx); - return 0; /* unreachable */ -} - -DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) { - duk_uidx_t vs_size; - duk_uidx_t uidx; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_INVALID_INDEX < 0); - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); - DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ - - if (idx < 0) { - uidx = vs_size + (duk_uidx_t) idx; - } else { - DUK_ASSERT(idx != DUK_INVALID_INDEX); - uidx = (duk_uidx_t) idx; - } - - /* DUK_INVALID_INDEX won't be accepted as a valid index. */ - DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - - if (DUK_LIKELY(uidx < vs_size)) { - return thr->valstack_bottom + uidx; - } - return NULL; -} - -/* Variant of duk_get_tval() which is guaranteed to return a valid duk_tval - * pointer. When duk_get_tval() would return NULL, this variant returns a - * pointer to a duk_tval with tag DUK_TAG_UNUSED. This allows the call site - * to avoid an unnecessary NULL check which sometimes leads to better code. - * The return duk_tval is read only (at least for the UNUSED value). - */ -DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER(); - -DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval(thr, idx); - if (tv != NULL) { - return tv; - } - return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused); -} - -DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) { - duk_uidx_t vs_size; - duk_uidx_t uidx; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_INVALID_INDEX < 0); - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); - DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ - - /* Use unsigned arithmetic to optimize comparison. */ - if (idx < 0) { - uidx = vs_size + (duk_uidx_t) idx; - } else { - DUK_ASSERT(idx != DUK_INVALID_INDEX); - uidx = (duk_uidx_t) idx; - } - - /* DUK_INVALID_INDEX won't be accepted as a valid index. */ - DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - - if (DUK_LIKELY(uidx < vs_size)) { - return thr->valstack_bottom + uidx; - } - DUK_ERROR_RANGE_INDEX(thr, idx); - return NULL; -} - -/* Non-critical. */ -DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_INVALID_INDEX < 0); - - return (duk_normalize_index(thr, idx) >= 0); -} - -/* Non-critical. */ -DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_INVALID_INDEX < 0); - - if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) { - DUK_ERROR_RANGE_INDEX(thr, idx); - return; /* unreachable */ - } -} - -/* - * Value stack top handling - */ - -DUK_EXTERNAL duk_idx_t duk_get_top(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); -} - -/* Internal helper to get current top but to require a minimum top value - * (TypeError if not met). - */ -DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top) { - duk_idx_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (DUK_UNLIKELY(ret < min_top)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - } - return ret; -} - -/* Set stack top within currently allocated range, but don't reallocate. - * This is performance critical especially for call handling, so whenever - * changing, profile and look at generated code. - */ -DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) { - duk_uidx_t vs_size; - duk_uidx_t vs_limit; - duk_uidx_t uidx; - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_INVALID_INDEX < 0); - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom); - vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); - vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom); - - if (idx < 0) { - /* Negative indices are always within allocated stack but - * must not go below zero index. - */ - uidx = vs_size + (duk_uidx_t) idx; - } else { - /* Positive index can be higher than valstack top but must - * not go above allocated stack (equality is OK). - */ - uidx = (duk_uidx_t) idx; - } - - /* DUK_INVALID_INDEX won't be accepted as a valid index. */ - DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit); - -#if defined(DUK_USE_VALSTACK_UNSAFE) - DUK_ASSERT(uidx <= vs_limit); - DUK_UNREF(vs_limit); -#else - if (DUK_UNLIKELY(uidx > vs_limit)) { - DUK_ERROR_RANGE_INDEX(thr, idx); - return; /* unreachable */ - } -#endif - DUK_ASSERT(uidx <= vs_limit); - - /* Handle change in value stack top. Respect value stack - * initialization policy: 'undefined' above top. Note that - * DECREF may cause a side effect that reallocates valstack, - * so must relookup after DECREF. - */ - - if (uidx >= vs_size) { - /* Stack size increases or stays the same. */ -#if defined(DUK_USE_ASSERTIONS) - duk_uidx_t count; - - count = uidx - vs_size; - while (count != 0) { - count--; - tv = thr->valstack_top + count; - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); - } -#endif - thr->valstack_top = thr->valstack_bottom + uidx; - } else { - /* Stack size decreases. */ -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_uidx_t count; - duk_tval *tv_end; - - count = vs_size - uidx; - DUK_ASSERT(count > 0); - tv = thr->valstack_top; - tv_end = tv - count; - DUK_ASSERT(tv > tv_end); /* Because count > 0. */ - do { - tv--; - DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); - } while (tv != tv_end); - thr->valstack_top = tv_end; - DUK_REFZERO_CHECK_FAST(thr); -#else /* DUK_USE_REFERENCE_COUNTING */ - duk_uidx_t count; - duk_tval *tv_end; - - count = vs_size - uidx; - tv = thr->valstack_top; - tv_end = tv - count; - DUK_ASSERT(tv > tv_end); - do { - tv--; - DUK_TVAL_SET_UNDEFINED(tv); - } while (tv != tv_end); - thr->valstack_top = tv_end; -#endif /* DUK_USE_REFERENCE_COUNTING */ - } -} - -/* Internal variant with a non-negative index and no runtime size checks. */ -#if defined(DUK_USE_PREFER_SIZE) -DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - duk_set_top(thr, idx); -} -#else /* DUK_USE_PREFER_SIZE */ -DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) { - duk_uidx_t uidx; - duk_uidx_t vs_size; - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom); - DUK_ASSERT(idx >= 0); - DUK_ASSERT(idx <= (duk_idx_t) (thr->valstack_end - thr->valstack_bottom)); - - /* XXX: byte arithmetic */ - uidx = (duk_uidx_t) idx; - vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); - - if (uidx >= vs_size) { - /* Stack size increases or stays the same. */ -#if defined(DUK_USE_ASSERTIONS) - duk_uidx_t count; - - count = uidx - vs_size; - while (count != 0) { - count--; - tv = thr->valstack_top + count; - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); - } -#endif - thr->valstack_top = thr->valstack_bottom + uidx; - } else { - /* Stack size decreases. */ -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_uidx_t count; - duk_tval *tv_end; - - count = vs_size - uidx; - DUK_ASSERT(count > 0); - tv = thr->valstack_top; - tv_end = tv - count; - DUK_ASSERT(tv > tv_end); /* Because count > 0. */ - do { - tv--; - DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); - } while (tv != tv_end); - thr->valstack_top = tv_end; - DUK_REFZERO_CHECK_FAST(thr); -#else /* DUK_USE_REFERENCE_COUNTING */ - duk_uidx_t count; - duk_tval *tv_end; - - count = vs_size - uidx; - tv = thr->valstack_top; - tv_end = tv - count; - DUK_ASSERT(tv > tv_end); - do { - tv--; - DUK_TVAL_SET_UNDEFINED(tv); - } while (tv != tv_end); - thr->valstack_top = tv_end; -#endif /* DUK_USE_REFERENCE_COUNTING */ - } -} -#endif /* DUK_USE_PREFER_SIZE */ - -/* Internal helper: set top to 'top', and set [idx_wipe_start,top[ to - * 'undefined' (doing nothing if idx_wipe_start == top). Indices are - * positive and within value stack reserve. This is used by call handling. - */ -DUK_INTERNAL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(top >= 0); - DUK_ASSERT(idx_wipe_start >= 0); - DUK_ASSERT(idx_wipe_start <= top); - DUK_ASSERT(thr->valstack_bottom + top <= thr->valstack_end); - DUK_ASSERT(thr->valstack_bottom + idx_wipe_start <= thr->valstack_end); - - duk_set_top_unsafe(thr, idx_wipe_start); - duk_set_top_unsafe(thr, top); -} - -DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_hthread *thr) { - duk_idx_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; - if (DUK_UNLIKELY(ret < 0)) { - /* Return invalid index; if caller uses this without checking - * in another API call, the index won't map to a valid stack - * entry. - */ - return DUK_INVALID_INDEX; - } - return ret; -} - -/* Internal variant: call assumes there is at least one element on the value - * stack frame; this is only asserted for. - */ -DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr) { - duk_idx_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; - return ret; -} - -DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) { - duk_idx_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; - if (DUK_UNLIKELY(ret < 0)) { - DUK_ERROR_RANGE_INDEX(thr, -1); - return 0; /* unreachable */ - } - return ret; -} - -/* - * Value stack resizing. - * - * This resizing happens above the current "top": the value stack can be - * grown or shrunk, but the "top" is not affected. The value stack cannot - * be resized to a size below the current reserve. - * - * The low level reallocation primitive must carefully recompute all value - * stack pointers, and must also work if ALL pointers are NULL. The resize - * is quite tricky because the valstack realloc may cause a mark-and-sweep, - * which may run finalizers. Running finalizers may resize the valstack - * recursively (the same value stack we're working on). So, after realloc - * returns, we know that the valstack bottom, top, and reserve should still - * be the same (there should not be live values above the "top"), but its - * underlying size, alloc_end, and base pointer may have changed. - * - * 'new_size' is known to be <= DUK_USE_VALSTACK_LIMIT, which ensures that - * size_t and pointer arithmetic won't wrap in duk__resize_valstack(). - */ - -/* Low level valstack resize primitive, used for both grow and shrink. All - * adjustments for slack etc have already been done. Doesn't throw but does - * have allocation side effects. - */ -DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__resize_valstack(duk_hthread *thr, duk_size_t new_size) { - duk_tval *pre_valstack; - duk_tval *pre_bottom; - duk_tval *pre_top; - duk_tval *pre_end; - duk_tval *pre_alloc_end; - duk_ptrdiff_t ptr_diff; - duk_tval *new_valstack; - duk_size_t new_alloc_size; - duk_tval *tv_prev_alloc_end; - duk_tval *p; - - DUK_ASSERT_HTHREAD_VALID(thr); - DUK_ASSERT(thr->valstack_bottom >= thr->valstack); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */ - DUK_ASSERT(new_size <= DUK_USE_VALSTACK_LIMIT); /* valstack limit caller has check, prevents wrapping */ - DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */ - - /* Pre-realloc pointer copies for asserts and debug logs. */ - pre_valstack = thr->valstack; - pre_bottom = thr->valstack_bottom; - pre_top = thr->valstack_top; - pre_end = thr->valstack_end; - pre_alloc_end = thr->valstack_alloc_end; - - DUK_UNREF(pre_valstack); - DUK_UNREF(pre_bottom); - DUK_UNREF(pre_top); - DUK_UNREF(pre_end); - DUK_UNREF(pre_alloc_end); - - /* If finalizer torture enabled, force base pointer change every time - * when it would be allowed. - */ -#if defined(DUK_USE_FINALIZER_TORTURE) - if (thr->heap->pf_prevent_count == 0) { - duk_hthread_valstack_torture_realloc(thr); - } -#endif - - /* Allocate a new valstack using DUK_REALLOC_DIRECT() to deal with - * a side effect changing the base pointer. - */ - new_alloc_size = sizeof(duk_tval) * new_size; - new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size); - if (DUK_UNLIKELY(new_valstack == NULL)) { - /* Because new_size != 0, if condition doesn't need to be - * (new_valstack != NULL || new_size == 0). - */ - DUK_ASSERT(new_size != 0); - DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)", - (unsigned long) new_size, (unsigned long) new_alloc_size)); - return 0; - } - - /* Debug log any changes in pointer(s) by side effects. These don't - * necessarily imply any incorrect behavior, but should be rare in - * practice. - */ -#if defined(DUK_USE_DEBUG) - if (thr->valstack != pre_valstack) { - DUK_D(DUK_DPRINT("valstack base pointer changed during valstack resize: %p -> %p", - (void *) pre_valstack, (void *) thr->valstack)); - } - if (thr->valstack_bottom != pre_bottom) { - DUK_D(DUK_DPRINT("valstack bottom pointer changed during valstack resize: %p -> %p", - (void *) pre_bottom, (void *) thr->valstack_bottom)); - } - if (thr->valstack_top != pre_top) { - DUK_D(DUK_DPRINT("valstack top pointer changed during valstack resize: %p -> %p", - (void *) pre_top, (void *) thr->valstack_top)); - } - if (thr->valstack_end != pre_end) { - DUK_D(DUK_DPRINT("valstack end pointer changed during valstack resize: %p -> %p", - (void *) pre_end, (void *) thr->valstack_end)); - } - if (thr->valstack_alloc_end != pre_alloc_end) { - DUK_D(DUK_DPRINT("valstack alloc_end pointer changed during valstack resize: %p -> %p", - (void *) pre_alloc_end, (void *) thr->valstack_alloc_end)); - } -#endif - - /* Assertions: offsets for bottom, top, and end (reserve) must not - * have changed even with side effects because they are always - * restored in unwind. For alloc_end there's no guarantee: it may - * have grown or shrunk (but remain above 'end'). - */ - DUK_ASSERT(thr->valstack_bottom - thr->valstack == pre_bottom - pre_valstack); - DUK_ASSERT(thr->valstack_top - thr->valstack == pre_top - pre_valstack); - DUK_ASSERT(thr->valstack_end - thr->valstack == pre_end - pre_valstack); - DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); - - /* Write new pointers. Most pointers can be handled as a pointer - * difference. - */ - ptr_diff = (duk_ptrdiff_t) ((duk_uint8_t *) new_valstack - (duk_uint8_t *) thr->valstack); - tv_prev_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_alloc_end + ptr_diff); - thr->valstack = new_valstack; - thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + ptr_diff); - thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + ptr_diff); - thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_end + ptr_diff); - thr->valstack_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + new_alloc_size); - - /* Assertions: pointer sanity after pointer updates. */ - DUK_ASSERT(thr->valstack_bottom >= thr->valstack); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); - - DUK_D(DUK_DPRINT("resized valstack %lu -> %lu elements (%lu -> %lu bytes): " - "base=%p -> %p, bottom=%p -> %p (%ld), top=%p -> %p (%ld), " - "end=%p -> %p (%ld), alloc_end=%p -> %p (%ld);" - " tv_prev_alloc_end=%p (-> %ld inits; <0 means shrink)", - (unsigned long) (pre_alloc_end - pre_valstack), - (unsigned long) new_size, - (unsigned long) ((duk_uint8_t *) pre_alloc_end - (duk_uint8_t *) pre_valstack), - (unsigned long) new_alloc_size, - (void *) pre_valstack, (void *) thr->valstack, - (void *) pre_bottom, (void *) thr->valstack_bottom, (long) (thr->valstack_bottom - thr->valstack), - (void *) pre_top, (void *) thr->valstack_top, (long) (thr->valstack_top - thr->valstack), - (void *) pre_end, (void *) thr->valstack_end, (long) (thr->valstack_end - thr->valstack), - (void *) pre_alloc_end, (void *) thr->valstack_alloc_end, (long) (thr->valstack_alloc_end - thr->valstack), - (void *) tv_prev_alloc_end, (long) (thr->valstack_alloc_end - tv_prev_alloc_end))); - - /* If allocation grew, init any new slots to 'undefined'. */ - p = tv_prev_alloc_end; - while (p < thr->valstack_alloc_end) { - /* Never executed if new size is smaller. */ - DUK_TVAL_SET_UNDEFINED(p); - p++; - } - - /* Assert for value stack initialization policy. */ -#if defined(DUK_USE_ASSERTIONS) - p = thr->valstack_top; - while (p < thr->valstack_alloc_end) { - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p)); - p++; - } -#endif - - return 1; -} - -DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr, duk_size_t min_bytes, duk_bool_t throw_on_error) { - duk_size_t min_size; - duk_size_t new_size; - - DUK_ASSERT(min_bytes / sizeof(duk_tval) * sizeof(duk_tval) == min_bytes); - min_size = min_bytes / sizeof(duk_tval); /* from bytes to slots */ - -#if defined(DUK_USE_VALSTACK_GROW_SHIFT) - /* New size is minimum size plus a proportional slack, e.g. shift of - * 2 means a 25% slack. - */ - new_size = min_size + (min_size >> DUK_USE_VALSTACK_GROW_SHIFT); -#else - /* New size is tight with no slack. This is sometimes preferred in - * low memory environments. - */ - new_size = min_size; -#endif - - if (DUK_UNLIKELY(new_size > DUK_USE_VALSTACK_LIMIT || new_size < min_size /*wrap*/)) { - /* Note: may be triggered even if minimal new_size would not reach the limit, - * plan limit accordingly. - */ - if (throw_on_error) { - DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT); - } - return 0; - } - - if (duk__resize_valstack(thr, new_size) == 0) { - if (throw_on_error) { - DUK_ERROR_ALLOC_FAILED(thr); - } - return 0; - } - - thr->valstack_end = thr->valstack + min_size; - DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); - - return 1; -} - -/* Hot, inlined value stack grow check. Because value stack almost never - * grows, the actual resize call is in a NOINLINE helper. - */ -DUK_INTERNAL DUK_INLINE void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes) { - duk_tval *tv; - - tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes); - if (DUK_LIKELY(thr->valstack_end >= tv)) { - return; - } - if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) { - /* Values in [valstack_top,valstack_alloc_end[ are initialized - * to 'undefined' so we can just move the end pointer. - */ - thr->valstack_end = tv; - return; - } - (void) duk__valstack_grow(thr, min_bytes, 1 /*throw_on_error*/); -} - -/* Hot, inlined value stack grow check which doesn't throw. */ -DUK_INTERNAL DUK_INLINE duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes) { - duk_tval *tv; - - tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes); - if (DUK_LIKELY(thr->valstack_end >= tv)) { - return 1; - } - if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) { - thr->valstack_end = tv; - return 1; - } - return duk__valstack_grow(thr, min_bytes, 0 /*throw_on_error*/); -} - -/* Value stack shrink check, called from mark-and-sweep. */ -DUK_INTERNAL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug) { - duk_size_t alloc_bytes; - duk_size_t reserve_bytes; - duk_size_t shrink_bytes; - - alloc_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack); - reserve_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); - DUK_ASSERT(alloc_bytes >= reserve_bytes); - - /* We're free to shrink the value stack allocation down to - * reserve_bytes but not more. If 'snug' (emergency GC) - * shrink whatever we can. Otherwise only shrink if the new - * size would be considerably smaller. - */ - -#if defined(DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT) - if (snug) { - shrink_bytes = reserve_bytes; - } else { - duk_size_t proportion, slack; - - /* Require that value stack shrinks by at least X% of its - * current size. For example, shift of 2 means at least - * 25%. The proportion is computed as bytes and may not - * be a multiple of sizeof(duk_tval); that's OK here. - */ - proportion = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT; - if (alloc_bytes - reserve_bytes < proportion) { - /* Too little would be freed, do nothing. */ - return; - } - - /* Keep a slack after shrinking. The slack is again a - * proportion of the current size (the proportion should - * of course be smaller than the check proportion above). - */ -#if defined(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT) - DUK_ASSERT(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT > DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT); - slack = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT; -#else - slack = 0; -#endif - shrink_bytes = reserve_bytes + - slack / sizeof(duk_tval) * sizeof(duk_tval); /* multiple of duk_tval */ - } -#else /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */ - /* Always snug, useful in some low memory environments. */ - DUK_UNREF(snug); - shrink_bytes = reserve_bytes; -#endif /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */ - - DUK_D(DUK_DPRINT("valstack shrink check: alloc_bytes=%ld, reserve_bytes=%ld, shrink_bytes=%ld (unvalidated)", - (long) alloc_bytes, (long) reserve_bytes, (long) shrink_bytes)); - DUK_ASSERT(shrink_bytes >= reserve_bytes); - if (shrink_bytes >= alloc_bytes) { - /* Skip if shrink target is same as current one (or higher, - * though that shouldn't happen in practice). - */ - return; - } - DUK_ASSERT(shrink_bytes / sizeof(duk_tval) * sizeof(duk_tval) == shrink_bytes); - - DUK_D(DUK_DPRINT("valstack shrink check: decided to shrink, snug: %ld", (long) snug)); - - duk__resize_valstack(thr, shrink_bytes / sizeof(duk_tval)); -} - -DUK_EXTERNAL duk_bool_t duk_check_stack(duk_hthread *thr, duk_idx_t extra) { - duk_size_t min_new_bytes; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr != NULL); - - if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) { - if (extra < 0) { - /* Clamping to zero makes the API more robust to calling code - * calculation errors. - */ - extra = 0; - } else { - /* Cause grow check to fail without wrapping arithmetic. */ - extra = DUK_USE_VALSTACK_LIMIT; - } - } - - min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) + - sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA); - return duk_valstack_grow_check_nothrow(thr, min_new_bytes); -} - -DUK_EXTERNAL void duk_require_stack(duk_hthread *thr, duk_idx_t extra) { - duk_size_t min_new_bytes; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr != NULL); - - if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) { - if (extra < 0) { - /* Clamping to zero makes the API more robust to calling code - * calculation errors. - */ - extra = 0; - } else { - /* Cause grow check to fail without wrapping arithmetic. */ - extra = DUK_USE_VALSTACK_LIMIT; - } - } - - min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) + - sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA); - duk_valstack_grow_check_throw(thr, min_new_bytes); -} - -DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_hthread *thr, duk_idx_t top) { - duk_size_t min_new_bytes; - - DUK_ASSERT_API_ENTRY(thr); - - if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) { - if (top < 0) { - /* Clamping to zero makes the API more robust to calling code - * calculation errors. - */ - top = 0; - } else { - /* Cause grow check to fail without wrapping arithmetic. */ - top = DUK_USE_VALSTACK_LIMIT; - } - } - - DUK_ASSERT(top >= 0); - min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) + - sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA); - return duk_valstack_grow_check_nothrow(thr, min_new_bytes); -} - -DUK_EXTERNAL void duk_require_stack_top(duk_hthread *thr, duk_idx_t top) { - duk_size_t min_new_bytes; - - DUK_ASSERT_API_ENTRY(thr); - - if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) { - if (top < 0) { - /* Clamping to zero makes the API more robust to calling code - * calculation errors. - */ - top = 0; - } else { - /* Cause grow check to fail without wrapping arithmetic. */ - top = DUK_USE_VALSTACK_LIMIT; - } - } - - DUK_ASSERT(top >= 0); - min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) + - sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA); - duk_valstack_grow_check_throw(thr, min_new_bytes); -} - -/* - * Basic stack manipulation: swap, dup, insert, replace, etc - */ - -DUK_EXTERNAL void duk_swap(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { - duk_tval *tv1; - duk_tval *tv2; - duk_tval tv_tmp; - - DUK_ASSERT_API_ENTRY(thr); - - tv1 = duk_require_tval(thr, idx1); - DUK_ASSERT(tv1 != NULL); - tv2 = duk_require_tval(thr, idx2); - DUK_ASSERT(tv2 != NULL); - - /* If tv1==tv2 this is a NOP, no check is needed */ - DUK_TVAL_SET_TVAL(&tv_tmp, tv1); - DUK_TVAL_SET_TVAL(tv1, tv2); - DUK_TVAL_SET_TVAL(tv2, &tv_tmp); -} - -DUK_EXTERNAL void duk_swap_top(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - duk_swap(thr, idx, -1); -} - -DUK_EXTERNAL void duk_dup(duk_hthread *thr, duk_idx_t from_idx) { - duk_tval *tv_from; - duk_tval *tv_to; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - - tv_from = duk_require_tval(thr, from_idx); - tv_to = thr->valstack_top++; - DUK_ASSERT(tv_from != NULL); - DUK_ASSERT(tv_to != NULL); - DUK_TVAL_SET_TVAL(tv_to, tv_from); - DUK_TVAL_INCREF(thr, tv_to); /* no side effects */ -} - -DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) { -#if defined(DUK_USE_PREFER_SIZE) - duk_dup(thr, -1); -#else - duk_tval *tv_from; - duk_tval *tv_to; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - - if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) { - DUK_ERROR_RANGE_INDEX(thr, -1); - return; /* unreachable */ - } - tv_from = thr->valstack_top - 1; - tv_to = thr->valstack_top++; - DUK_ASSERT(tv_from != NULL); - DUK_ASSERT(tv_to != NULL); - DUK_TVAL_SET_TVAL(tv_to, tv_from); - DUK_TVAL_INCREF(thr, tv_to); /* no side effects */ -#endif -} - -DUK_INTERNAL void duk_dup_0(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_dup(thr, 0); -} -DUK_INTERNAL void duk_dup_1(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_dup(thr, 1); -} -DUK_INTERNAL void duk_dup_2(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_dup(thr, 2); -} -DUK_INTERNAL void duk_dup_m2(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_dup(thr, -2); -} -DUK_INTERNAL void duk_dup_m3(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_dup(thr, -3); -} -DUK_INTERNAL void duk_dup_m4(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_dup(thr, -4); -} - -DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) { - duk_tval *p; - duk_tval *q; - duk_tval tv_tmp; - duk_size_t nbytes; - - DUK_ASSERT_API_ENTRY(thr); - - p = duk_require_tval(thr, to_idx); - DUK_ASSERT(p != NULL); - q = duk_require_tval(thr, -1); - DUK_ASSERT(q != NULL); - - DUK_ASSERT(q >= p); - - /* nbytes - * <---------> - * [ ... | p | x | x | q ] - * => [ ... | q | p | x | x ] - */ - - nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */ - - DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu", - (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes)); - - /* No net refcount changes. */ - - if (nbytes > 0) { - DUK_TVAL_SET_TVAL(&tv_tmp, q); - DUK_ASSERT(nbytes > 0); - DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes); - DUK_TVAL_SET_TVAL(p, &tv_tmp); - } else { - /* nop: insert top to top */ - DUK_ASSERT(nbytes == 0); - DUK_ASSERT(p == q); - } -} - -DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(idx >= 0); /* Doesn't support negative indices. */ - - duk_push_undefined(thr); - duk_insert(thr, idx); -} - -DUK_INTERNAL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) { - duk_tval *tv, *tv_end; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(idx >= 0); /* Doesn't support negative indices or count. */ - DUK_ASSERT(count >= 0); - - tv = duk_reserve_gap(thr, idx, count); - tv_end = tv + count; - while (tv != tv_end) { - DUK_TVAL_SET_UNDEFINED(tv); - tv++; - } -} - -DUK_EXTERNAL void duk_replace(duk_hthread *thr, duk_idx_t to_idx) { - duk_tval *tv1; - duk_tval *tv2; - duk_tval tv_tmp; - - DUK_ASSERT_API_ENTRY(thr); - - tv1 = duk_require_tval(thr, -1); - DUK_ASSERT(tv1 != NULL); - tv2 = duk_require_tval(thr, to_idx); - DUK_ASSERT(tv2 != NULL); - - /* For tv1 == tv2, both pointing to stack top, the end result - * is same as duk_pop(thr). - */ - DUK_TVAL_SET_TVAL(&tv_tmp, tv2); - DUK_TVAL_SET_TVAL(tv2, tv1); - DUK_TVAL_SET_UNDEFINED(tv1); - thr->valstack_top--; - DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ -} - -DUK_EXTERNAL void duk_copy(duk_hthread *thr, duk_idx_t from_idx, duk_idx_t to_idx) { - duk_tval *tv1; - duk_tval *tv2; - - DUK_ASSERT_API_ENTRY(thr); - - tv1 = duk_require_tval(thr, from_idx); - DUK_ASSERT(tv1 != NULL); - tv2 = duk_require_tval(thr, to_idx); - DUK_ASSERT(tv2 != NULL); - - /* For tv1 == tv2, this is a no-op (no explicit check needed). */ - DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */ -} - -DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) { - duk_tval *p; - duk_tval *q; -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_tval tv_tmp; -#endif - duk_size_t nbytes; - - DUK_ASSERT_API_ENTRY(thr); - - p = duk_require_tval(thr, idx); - DUK_ASSERT(p != NULL); - q = duk_require_tval(thr, -1); - DUK_ASSERT(q != NULL); - - DUK_ASSERT(q >= p); - - /* nbytes zero size case - * <---------> - * [ ... | p | x | x | q ] [ ... | p==q ] - * => [ ... | x | x | q ] [ ... ] - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - /* use a temp: decref only when valstack reachable values are correct */ - DUK_TVAL_SET_TVAL(&tv_tmp, p); -#endif - - nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */ - DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */ - - DUK_TVAL_SET_UNDEFINED(q); - thr->valstack_top--; - -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ -#endif -} - -DUK_INTERNAL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - duk_remove(thr, idx); /* XXX: no optimization for now */ -} - -DUK_INTERNAL void duk_remove_m2(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - duk_remove(thr, -2); -} - -DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) { -#if defined(DUK_USE_PREFER_SIZE) - /* XXX: maybe too slow even when preferring size? */ - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(count >= 0); - DUK_ASSERT(idx >= 0); - - while (count-- > 0) { - duk_remove(thr, idx); - } -#else /* DUK_USE_PREFER_SIZE */ - duk_tval *tv_src; - duk_tval *tv_dst; - duk_tval *tv_newtop; - duk_tval *tv; - duk_size_t bytes; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(count >= 0); - DUK_ASSERT(idx >= 0); - - tv_dst = thr->valstack_bottom + idx; - DUK_ASSERT(tv_dst <= thr->valstack_top); - tv_src = tv_dst + count; - DUK_ASSERT(tv_src <= thr->valstack_top); - bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src); - - for (tv = tv_dst; tv < tv_src; tv++) { - DUK_TVAL_DECREF_NORZ(thr, tv); - } - - DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, bytes); - - tv_newtop = thr->valstack_top - count; - for (tv = tv_newtop; tv < thr->valstack_top; tv++) { - DUK_TVAL_SET_UNDEFINED(tv); - } - thr->valstack_top = tv_newtop; - - /* When not preferring size, only NORZ macros are used; caller - * is expected to DUK_REFZERO_CHECK(). - */ -#endif /* DUK_USE_PREFER_SIZE */ -} - -DUK_INTERNAL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) { - DUK_ASSERT_API_ENTRY(thr); - - duk_remove_n(thr, idx, count); /* XXX: no optimization for now */ -} - -/* - * Stack slice primitives - */ - -DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, duk_idx_t count, duk_bool_t is_copy) { - void *src; - duk_size_t nbytes; - duk_tval *p; - duk_tval *q; - - /* XXX: several pointer comparison issues here */ - - DUK_ASSERT_API_ENTRY(to_thr); - DUK_ASSERT_CTX_VALID(to_thr); - DUK_ASSERT_CTX_VALID(from_thr); - DUK_ASSERT(to_thr->heap == from_thr->heap); - - if (DUK_UNLIKELY(to_thr == from_thr)) { - DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT); - return; - } - if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) { - /* Maximum value check ensures 'nbytes' won't wrap below. - * Also handles negative count. - */ - DUK_ERROR_RANGE_INVALID_COUNT(to_thr); - return; - } - DUK_ASSERT(count >= 0); - - nbytes = sizeof(duk_tval) * (duk_size_t) count; - if (DUK_UNLIKELY(nbytes == 0)) { - return; - } - DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); - if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) { - DUK_ERROR_RANGE_PUSH_BEYOND(to_thr); - } - src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); - if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) { - DUK_ERROR_RANGE_INVALID_COUNT(to_thr); - } - - /* copy values (no overlap even if to_thr == from_thr; that's not - * allowed now anyway) - */ - DUK_ASSERT(nbytes > 0); - DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes); - - p = to_thr->valstack_top; - to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes); - - if (is_copy) { - /* Incref copies, keep originals. */ - q = to_thr->valstack_top; - while (p < q) { - DUK_TVAL_INCREF(to_thr, p); /* no side effects */ - p++; - } - } else { - /* No net refcount change. */ - p = from_thr->valstack_top; - q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes); - from_thr->valstack_top = q; - - while (p > q) { - p--; - DUK_TVAL_SET_UNDEFINED(p); - /* XXX: fast primitive to set a bunch of values to UNDEFINED */ - } - } -} - -/* Internal helper: reserve a gap of 'count' elements at 'idx_base' and return a - * pointer to the gap. Values in the gap are garbage and MUST be initialized by - * the caller before any side effects may occur. The caller must ensure there's - * enough stack reserve for 'count' values. - */ -DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count) { - duk_tval *tv_src; - duk_tval *tv_dst; - duk_size_t gap_bytes; - duk_size_t copy_bytes; - - /* Caller is responsible for ensuring there's enough preallocated - * value stack. - */ - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(count >= 0); - DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack_top) >= (duk_size_t) count); - - tv_src = thr->valstack_bottom + idx_base; - gap_bytes = (duk_size_t) count * sizeof(duk_tval); - tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes); - copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src); - thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes); - DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, copy_bytes); - - /* Values in the gap are left as garbage: caller must fill them in - * and INCREF them before any side effects. - */ - return tv_src; -} - -/* - * Get/opt/require - */ - -DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED); - } -} - -DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL); - } -} - -DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) { - duk_bool_t ret; - duk_tval *tv; - - DUK_ASSERT_CTX_VALID(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_BOOLEAN(tv)) { - ret = DUK_TVAL_GET_BOOLEAN(tv); - DUK_ASSERT(ret == 0 || ret == 1); - } else { - ret = def_value; - /* Not guaranteed to be 0 or 1. */ - } - - return ret; -} - -DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return duk__get_boolean_raw(thr, idx, 0); /* default: false */ -} - -DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) { - DUK_ASSERT_API_ENTRY(thr); - - return duk__get_boolean_raw(thr, idx, def_value); -} - -DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_bool_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) { - ret = DUK_TVAL_GET_BOOLEAN(tv); - DUK_ASSERT(ret == 0 || ret == 1); - return ret; - } else { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN); - } -} - -DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - return def_value; - } - return duk_require_boolean(thr, idx); -} - -DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) { - duk_double_union ret; - duk_tval *tv; - - DUK_ASSERT_CTX_VALID(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv)) { - ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */ - } - else -#endif - if (DUK_TVAL_IS_DOUBLE(tv)) { - /* When using packed duk_tval, number must be in NaN-normalized form - * for it to be a duk_tval, so no need to normalize. NOP for unpacked - * duk_tval. - */ - ret.d = DUK_TVAL_GET_DOUBLE(tv); - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); - } else { - ret.d = def_value; - /* Default value (including NaN) may not be normalized. */ - } - - return ret.d; -} - -DUK_EXTERNAL duk_double_t duk_get_number(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__get_number_raw(thr, idx, DUK_DOUBLE_NAN); /* default: NaN */ -} - -DUK_EXTERNAL duk_double_t duk_get_number_default(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) { - DUK_ASSERT_API_ENTRY(thr); - return duk__get_number_raw(thr, idx, def_value); -} - -DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_double_union ret; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); - } - - ret.d = DUK_TVAL_GET_NUMBER(tv); - - /* When using packed duk_tval, number must be in NaN-normalized form - * for it to be a duk_tval, so no need to normalize. NOP for unpacked - * duk_tval. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); - return ret.d; -} - -DUK_EXTERNAL duk_double_t duk_opt_number(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - /* User provided default is not NaN normalized. */ - return def_value; - } - return duk_require_number(thr, idx); -} - -DUK_EXTERNAL duk_int_t duk_get_int(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/); -} - -DUK_EXTERNAL duk_uint_t duk_get_uint(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/); -} - -DUK_EXTERNAL duk_int_t duk_get_int_default(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) { - DUK_ASSERT_API_ENTRY(thr); - - return (duk_int_t) duk__api_coerce_d2i(thr, idx, def_value, 0 /*require*/); -} - -DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) { - DUK_ASSERT_API_ENTRY(thr); - - return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, def_value, 0 /*require*/); -} - -DUK_EXTERNAL duk_int_t duk_require_int(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 1 /*require*/); -} - -DUK_EXTERNAL duk_uint_t duk_require_uint(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 1 /*require*/); -} - -DUK_EXTERNAL duk_int_t duk_opt_int(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - return def_value; - } - return duk_require_int(thr, idx); -} - -DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - return def_value; - } - return duk_require_uint(thr, idx); -} - -DUK_EXTERNAL const char *duk_get_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { - duk_hstring *h; - const char *ret; - duk_size_t len; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_get_hstring(thr, idx); - if (h != NULL) { - len = DUK_HSTRING_GET_BYTELEN(h); - ret = (const char *) DUK_HSTRING_GET_DATA(h); - } else { - len = 0; - ret = NULL; - } - - if (out_len != NULL) { - *out_len = len; - } - return ret; -} - -DUK_EXTERNAL const char *duk_require_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_require_hstring(thr, idx); - DUK_ASSERT(h != NULL); - if (out_len) { - *out_len = DUK_HSTRING_GET_BYTELEN(h); - } - return (const char *) DUK_HSTRING_GET_DATA(h); -} - -DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_require_hstring_notsymbol(thr, idx); - DUK_ASSERT(h != NULL); - if (out_len) { - *out_len = DUK_HSTRING_GET_BYTELEN(h); - } - return (const char *) DUK_HSTRING_GET_DATA(h); -} - -DUK_EXTERNAL const char *duk_get_string(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_get_hstring(thr, idx); - if (h != NULL) { - return (const char *) DUK_HSTRING_GET_DATA(h); - } else { - return NULL; - } -} - -DUK_EXTERNAL const char *duk_opt_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - if (out_len != NULL) { - *out_len = def_len; - } - return def_ptr; - } - return duk_require_lstring(thr, idx, out_len); -} - -DUK_EXTERNAL const char *duk_opt_string(duk_hthread *thr, duk_idx_t idx, const char *def_ptr) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - return def_ptr; - } - return duk_require_string(thr, idx); -} - -DUK_EXTERNAL const char *duk_get_lstring_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { - duk_hstring *h; - const char *ret; - duk_size_t len; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_get_hstring(thr, idx); - if (h != NULL) { - len = DUK_HSTRING_GET_BYTELEN(h); - ret = (const char *) DUK_HSTRING_GET_DATA(h); - } else { - len = def_len; - ret = def_ptr; - } - - if (out_len != NULL) { - *out_len = len; - } - return ret; -} - -DUK_EXTERNAL const char *duk_get_string_default(duk_hthread *thr, duk_idx_t idx, const char *def_value) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_get_hstring(thr, idx); - if (h != NULL) { - return (const char *) DUK_HSTRING_GET_DATA(h); - } else { - return def_value; - } -} - -DUK_INTERNAL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_get_hstring_notsymbol(thr, idx); - if (h) { - return (const char *) DUK_HSTRING_GET_DATA(h); - } else { - return NULL; - } -} - -DUK_EXTERNAL const char *duk_require_string(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return duk_require_lstring(thr, idx, NULL); -} - -DUK_INTERNAL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_require_hstring_notsymbol(thr, idx); - DUK_ASSERT(h != NULL); - return (const char *) DUK_HSTRING_GET_DATA(h); -} - -DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT); - } -} - -DUK_LOCAL void *duk__get_pointer_raw(duk_hthread *thr, duk_idx_t idx, void *def_value) { - duk_tval *tv; - void *p; - - DUK_ASSERT_CTX_VALID(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_POINTER(tv)) { - return def_value; - } - - p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ - return p; -} - -DUK_EXTERNAL void *duk_get_pointer(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__get_pointer_raw(thr, idx, NULL /*def_value*/); -} - -DUK_EXTERNAL void *duk_opt_pointer(duk_hthread *thr, duk_idx_t idx, void *def_value) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - return def_value; - } - return duk_require_pointer(thr, idx); -} - -DUK_EXTERNAL void *duk_get_pointer_default(duk_hthread *thr, duk_idx_t idx, void *def_value) { - DUK_ASSERT_API_ENTRY(thr); - return duk__get_pointer_raw(thr, idx, def_value); -} - -DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - void *p; - - DUK_ASSERT_API_ENTRY(thr); - - /* Note: here we must be wary of the fact that a pointer may be - * valid and be a NULL. - */ - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER); - } - p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ - return p; -} - -#if 0 /*unused*/ -DUK_INTERNAL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_heaphdr *h; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - return NULL; - } - - h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - return (void *) h; -} -#endif - -DUK_LOCAL void *duk__get_buffer_helper(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) { - duk_hbuffer *h; - void *ret; - duk_size_t len; - duk_tval *tv; - - DUK_ASSERT_CTX_VALID(thr); - - if (out_size != NULL) { - *out_size = 0; - } - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) { - h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - - len = DUK_HBUFFER_GET_SIZE(h); - ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); - } else { - if (throw_flag) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); - } - len = def_size; - ret = def_ptr; - } - - if (out_size != NULL) { - *out_size = len; - } - return ret; -} - -DUK_EXTERNAL void *duk_get_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { - DUK_ASSERT_API_ENTRY(thr); - - return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/); -} - -DUK_EXTERNAL void *duk_opt_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - if (out_size != NULL) { - *out_size = def_size; - } - return def_ptr; - } - return duk_require_buffer(thr, idx, out_size); -} - -DUK_EXTERNAL void *duk_get_buffer_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) { - DUK_ASSERT_API_ENTRY(thr); - - return duk__get_buffer_helper(thr, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/); -} - -DUK_EXTERNAL void *duk_require_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { - DUK_ASSERT_API_ENTRY(thr); - - return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/); -} - -/* Get the active buffer data area for a plain buffer or a buffer object. - * Return NULL if the the value is not a buffer. Note that a buffer may - * have a NULL data pointer when its size is zero, the optional 'out_isbuffer' - * argument allows caller to detect this reliably. - */ -DUK_INTERNAL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - if (out_isbuffer != NULL) { - *out_isbuffer = 0; - } - if (out_size != NULL) { - *out_size = def_size; - } - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_BUFFER(tv)) { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - if (out_size != NULL) { - *out_size = DUK_HBUFFER_GET_SIZE(h); - } - if (out_isbuffer != NULL) { - *out_isbuffer = 1; - } - return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ - } -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - else if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - if (DUK_HOBJECT_IS_BUFOBJ(h)) { - /* XXX: this is probably a useful shared helper: for a - * duk_hbufobj, get a validated buffer pointer/length. - */ - duk_hbufobj *h_bufobj = (duk_hbufobj *) h; - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - if (h_bufobj->buf != NULL && - DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { - duk_uint8_t *p; - - p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf); - if (out_size != NULL) { - *out_size = (duk_size_t) h_bufobj->length; - } - if (out_isbuffer != NULL) { - *out_isbuffer = 1; - } - return (void *) (p + h_bufobj->offset); - } - /* if slice not fully valid, treat as error */ - } - } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - - if (throw_flag) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); - } - return def_ptr; -} - -DUK_EXTERNAL void *duk_get_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { - DUK_ASSERT_API_ENTRY(thr); - return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL); -} - -DUK_EXTERNAL void *duk_get_buffer_data_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { - DUK_ASSERT_API_ENTRY(thr); - return duk_get_buffer_data_raw(thr, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL); -} - -DUK_EXTERNAL void *duk_opt_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - if (out_size != NULL) { - *out_size = def_size; - } - return def_ptr; - } - return duk_require_buffer_data(thr, idx, out_size); -} - -DUK_EXTERNAL void *duk_require_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { - DUK_ASSERT_API_ENTRY(thr); - return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL); -} - -/* Raw helper for getting a value from the stack, checking its tag. - * The tag cannot be a number because numbers don't have an internal - * tag in the packed representation. - */ - -DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag) { - duk_tval *tv; - duk_heaphdr *ret; - - DUK_ASSERT_CTX_VALID(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_GET_TAG(tv) != tag) { - return (duk_heaphdr *) NULL; - } - - ret = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */ - return ret; - -} - -DUK_INTERNAL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); -} - -DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); - if (DUK_UNLIKELY(h && DUK_HSTRING_HAS_SYMBOL(h))) { - return NULL; - } - return h; -} - -DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); - if (DUK_UNLIKELY(h == NULL)) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING); - } - return h; -} - -DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); - if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING); - } - return h; -} - -DUK_INTERNAL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); -} - -DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(h == NULL)) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT); - } - return h; -} - -DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER); -} - -DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) { - duk_hbuffer *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER); - if (DUK_UNLIKELY(h == NULL)) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); - } - return h; -} - -DUK_INTERNAL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) { - h = NULL; - } - return (duk_hthread *) h; -} - -DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD); - } - return (duk_hthread *) h; -} - -DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) { - h = NULL; - } - return (duk_hcompfunc *) h; -} - -DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC); - } - return (duk_hcompfunc *) h; -} - -DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) { - h = NULL; - } - return (duk_hnatfunc *) h; -} - -DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); - } - return (duk_hnatfunc *) h; -} - -DUK_EXTERNAL duk_c_function duk_get_c_function(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_hobject *h; - duk_hnatfunc *f; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { - return NULL; - } - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - - if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) { - return NULL; - } - DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h)); - f = (duk_hnatfunc *) h; - - return f->func; -} - -DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - return def_value; - } - return duk_require_c_function(thr, idx); -} - -DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) { - duk_c_function ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = duk_get_c_function(thr, idx); - if (ret != NULL) { - return ret; - } - - return def_value; -} - -DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t idx) { - duk_c_function ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = duk_get_c_function(thr, idx); - if (DUK_UNLIKELY(!ret)) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); - } - return ret; -} - -DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - if (DUK_UNLIKELY(!duk_is_function(thr, idx))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function", DUK_STR_NOT_FUNCTION); - } -} - -DUK_INTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC); - if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE); - } - /* Lightfuncs (h == NULL) are constructable. */ -} - -DUK_EXTERNAL duk_hthread *duk_get_context(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return duk_get_hthread(thr, idx); -} - -DUK_EXTERNAL duk_hthread *duk_require_context(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return duk_require_hthread(thr, idx); -} - -DUK_EXTERNAL duk_hthread *duk_opt_context(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - return def_value; - } - return duk_require_context(thr, idx); -} - -DUK_EXTERNAL duk_hthread *duk_get_context_default(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) { - duk_hthread *ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = duk_get_context(thr, idx); - if (ret != NULL) { - return ret; - } - - return def_value; -} - -DUK_EXTERNAL void *duk_get_heapptr(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - void *ret; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { - return (void *) NULL; - } - - ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(ret != NULL); - return ret; -} - -DUK_EXTERNAL void *duk_opt_heapptr(duk_hthread *thr, duk_idx_t idx, void *def_value) { - DUK_ASSERT_API_ENTRY(thr); - - if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { - return def_value; - } - return duk_require_heapptr(thr, idx); -} - -DUK_EXTERNAL void *duk_get_heapptr_default(duk_hthread *thr, duk_idx_t idx, void *def_value) { - void *ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = duk_get_heapptr(thr, idx); - if (ret != NULL) { - return ret; - } - - return def_value; -} - -DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - void *ret; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE); - } - - ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(ret != NULL); - return ret; -} - -/* Internal helper for getting/requiring a duk_hobject with possible promotion. */ -DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) { - duk_uint_t val_mask; - duk_hobject *res; - - DUK_ASSERT_CTX_VALID(thr); - - res = duk_get_hobject(thr, idx); /* common case, not promoted */ - if (DUK_LIKELY(res != NULL)) { - DUK_ASSERT(res != NULL); - return res; - } - - val_mask = duk_get_type_mask(thr, idx); - if (val_mask & type_mask) { - if (type_mask & DUK_TYPE_MASK_PROMOTE) { - res = duk_to_hobject(thr, idx); - DUK_ASSERT(res != NULL); - return res; - } else { - return NULL; /* accept without promoting */ - } - } - - if (type_mask & DUK_TYPE_MASK_THROW) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT); - } - return NULL; -} - -/* Get a duk_hobject * at 'idx'; if the value is not an object but matches the - * supplied 'type_mask', promote it to an object and return the duk_hobject *. - * This is useful for call sites which want an object but also accept a plain - * buffer and/or a lightfunc which gets automatically promoted to an object. - * Return value is NULL if value is neither an object nor a plain type allowed - * by the mask. - */ -DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) { - DUK_ASSERT_API_ENTRY(thr); - return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_PROMOTE); -} - -/* Like duk_get_hobject_promote_mask() but throw a TypeError instead of - * returning a NULL. - */ -DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) { - DUK_ASSERT_API_ENTRY(thr); - return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE); -} - -/* Require a duk_hobject * at 'idx'; if the value is not an object but matches the - * supplied 'type_mask', return a NULL instead. Otherwise throw a TypeError. - */ -DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) { - DUK_ASSERT_API_ENTRY(thr); - return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW); -} - -DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */ - DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) { - h = NULL; - } - return h; -} - -DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */ - DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); - - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); - if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) { - duk_hstring *h_class; - h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum)); - DUK_UNREF(h_class); - - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE); - } - return h; -} - -DUK_EXTERNAL duk_size_t duk_get_length(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: - case DUK_TAG_NULL: - case DUK_TAG_BOOLEAN: - case DUK_TAG_POINTER: - return 0; -#if defined(DUK_USE_PREFER_SIZE) - /* String and buffer have a virtual non-configurable .length property - * which is within size_t range so it can be looked up without specific - * type checks. Lightfuncs inherit from %NativeFunctionPrototype% - * which provides an inherited .length accessor; it could be overwritten - * to produce unexpected types or values, but just number convert and - * duk_size_t cast for now. - */ - case DUK_TAG_STRING: - case DUK_TAG_BUFFER: - case DUK_TAG_LIGHTFUNC: { - duk_size_t ret; - duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH); - ret = (duk_size_t) duk_to_number_m1(thr); - duk_pop_unsafe(thr); - return ret; - } -#else /* DUK_USE_PREFER_SIZE */ - case DUK_TAG_STRING: { - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - return 0; - } - return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h); - } - case DUK_TAG_BUFFER: { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - return (duk_size_t) DUK_HBUFFER_GET_SIZE(h); - } - case DUK_TAG_LIGHTFUNC: { - /* We could look up the length from the lightfunc duk_tval, - * but since Duktape 2.2 lightfunc .length comes from - * %NativeFunctionPrototype% which can be overridden, so - * look up the property explicitly. - */ - duk_size_t ret; - duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH); - ret = (duk_size_t) duk_to_number_m1(thr); - duk_pop_unsafe(thr); - return ret; - } -#endif /* DUK_USE_PREFER_SIZE */ - case DUK_TAG_OBJECT: { - duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - return (duk_size_t) duk_hobject_get_length(thr, h); - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: - /* number or 'unused' */ - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv) || DUK_TVAL_IS_UNUSED(tv)); - return 0; - } - - DUK_UNREACHABLE(); -} - -/* - * duk_known_xxx() helpers - * - * Used internally when we're 100% sure that a certain index is valid and - * contains an object of a certain type. For example, if we duk_push_object() - * we can then safely duk_known_hobject(thr, -1). These helpers just assert - * for the index and type, and if the assumptions are not valid, memory unsafe - * behavior happens. - */ - -DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_heaphdr *h; - - DUK_ASSERT_CTX_VALID(thr); - if (idx < 0) { - tv = thr->valstack_top + idx; - } else { - tv = thr->valstack_bottom + idx; - } - DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_ASSERT(tv < thr->valstack_top); - h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - return h; -} - -DUK_INTERNAL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(duk_get_hstring(thr, idx) != NULL); - return (duk_hstring *) duk__known_heaphdr(thr, idx); -} - -DUK_INTERNAL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(duk_get_hobject(thr, idx) != NULL); - return (duk_hobject *) duk__known_heaphdr(thr, idx); -} - -DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(duk_get_hbuffer(thr, idx) != NULL); - return (duk_hbuffer *) duk__known_heaphdr(thr, idx); -} - -DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(duk_get_hcompfunc(thr, idx) != NULL); - return (duk_hcompfunc *) duk__known_heaphdr(thr, idx); -} - -DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(duk_get_hnatfunc(thr, idx) != NULL); - return (duk_hnatfunc *) duk__known_heaphdr(thr, idx); -} - -DUK_EXTERNAL void duk_set_length(duk_hthread *thr, duk_idx_t idx, duk_size_t len) { - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_normalize_index(thr, idx); - duk_push_uint(thr, (duk_uint_t) len); - duk_put_prop_stridx(thr, idx, DUK_STRIDX_LENGTH); -} - -/* - * Conversions and coercions - * - * The conversion/coercions are in-place operations on the value stack. - * Some operations are implemented here directly, while others call a - * helper in duk_js_ops.c after validating arguments. - */ - -/* E5 Section 8.12.8 */ - -DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t func_stridx) { - if (duk_get_prop_stridx(thr, idx, func_stridx)) { - /* [ ... func ] */ - if (duk_is_callable(thr, -1)) { - duk_dup(thr, idx); /* -> [ ... func this ] */ - duk_call_method(thr, 0); /* -> [ ... retval ] */ - if (duk_is_primitive(thr, -1)) { - duk_replace(thr, idx); - return 1; - } - /* [ ... retval ]; popped below */ - } - } - duk_pop_unsafe(thr); /* [ ... func/retval ] -> [ ... ] */ - return 0; -} - -DUK_EXTERNAL void duk_to_undefined(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, idx); - DUK_ASSERT(tv != NULL); - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ -} - -DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, idx); - DUK_ASSERT(tv != NULL); - DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */ -} - -/* E5 Section 9.1 */ -DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) { - /* inline initializer for coercers[] is not allowed by old compilers like BCC */ - duk_small_uint_t coercers[2]; - duk_small_uint_t class_number; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING); - - idx = duk_require_normalize_index(thr, idx); - - if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT | - DUK_TYPE_MASK_LIGHTFUNC | - DUK_TYPE_MASK_BUFFER)) { - /* Any other values stay as is. */ - DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */ - return; - } - - class_number = duk_get_class_number(thr, idx); - - /* XXX: Symbol objects normally coerce via the ES2015-revised ToPrimitive() - * algorithm which consults value[@@toPrimitive] and avoids calling - * .valueOf() and .toString(). Before that is implemented, special - * case Symbol objects to behave as if they had the default @@toPrimitive - * algorithm of E6 Section 19.4.3.4, i.e. return the plain symbol value - * with no further side effects. - */ - - if (class_number == DUK_HOBJECT_CLASS_SYMBOL) { - duk_hobject *h_obj; - duk_hstring *h_str; - - /* XXX: pretty awkward, index based API for internal value access? */ - h_obj = duk_known_hobject(thr, idx); - h_str = duk_hobject_get_internal_value_string(thr->heap, h_obj); - if (h_str) { - duk_push_hstring(thr, h_str); - duk_replace(thr, idx); - return; - } - } - - - /* Objects are coerced based on E5 specification. - * Lightfuncs are coerced because they behave like - * objects even if they're internally a primitive - * type. Same applies to plain buffers, which behave - * like ArrayBuffer objects since Duktape 2.x. - */ - - coercers[0] = DUK_STRIDX_VALUE_OF; - coercers[1] = DUK_STRIDX_TO_STRING; - - if (hint == DUK_HINT_NONE) { - if (class_number == DUK_HOBJECT_CLASS_DATE) { - hint = DUK_HINT_STRING; - } else { - hint = DUK_HINT_NUMBER; - } - } - - if (hint == DUK_HINT_STRING) { - coercers[0] = DUK_STRIDX_TO_STRING; - coercers[1] = DUK_STRIDX_VALUE_OF; - } - - if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[0])) { - DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */ - return; - } - - if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[1])) { - DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */ - return; - } - - DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED); -} - -/* E5 Section 9.2 */ -DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_bool_t val; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - tv = DUK_GET_TVAL_POSIDX(thr, idx); - DUK_ASSERT(tv != NULL); - - val = duk_js_toboolean(tv); - DUK_ASSERT(val == 0 || val == 1); - - /* Note: no need to re-lookup tv, conversion is side effect free. */ - DUK_ASSERT(tv != NULL); - DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */ - return val; -} - -DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_double_t d; - - DUK_ASSERT_API_ENTRY(thr); - - /* XXX: No need to normalize; the whole operation could be inlined here to - * avoid 'tv' re-lookup. - */ - idx = duk_require_normalize_index(thr, idx); - tv = DUK_GET_TVAL_POSIDX(thr, idx); - DUK_ASSERT(tv != NULL); - d = duk_js_tonumber(thr, tv); /* XXX: fastint coercion? now result will always be a non-fastint */ - - /* ToNumber() may have side effects so must relookup 'tv'. */ - tv = DUK_GET_TVAL_POSIDX(thr, idx); - DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */ - return d; -} - -DUK_INTERNAL duk_double_t duk_to_number_m1(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - return duk_to_number(thr, -1); -} -DUK_INTERNAL duk_double_t duk_to_number_m2(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - return duk_to_number(thr, -2); -} - -DUK_INTERNAL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv) { -#if defined(DUK_USE_PREFER_SIZE) - duk_double_t res; - - DUK_ASSERT_API_ENTRY(thr); - - duk_push_tval(thr, tv); - res = duk_to_number_m1(thr); - duk_pop_unsafe(thr); - return res; -#else - duk_double_t res; - duk_tval *tv_dst; - - DUK_ASSERT_API_ENTRY(thr); - DUK__ASSERT_SPACE(); - - tv_dst = thr->valstack_top++; - DUK_TVAL_SET_TVAL(tv_dst, tv); - DUK_TVAL_INCREF(thr, tv_dst); /* decref not necessary */ - res = duk_to_number_m1(thr); /* invalidates tv_dst */ - - tv_dst = --thr->valstack_top; - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_dst)); - DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_dst)); /* plain number */ - DUK_TVAL_SET_UNDEFINED(tv_dst); /* valstack init policy */ - - return res; -#endif -} - -/* XXX: combine all the integer conversions: they share everything - * but the helper function for coercion. - */ - -typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv); - -DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_hthread *thr, duk_idx_t idx, duk__toint_coercer coerce_func) { - duk_tval *tv; - duk_double_t d; - - DUK_ASSERT_CTX_VALID(thr); - - tv = duk_require_tval(thr, idx); - DUK_ASSERT(tv != NULL); - -#if defined(DUK_USE_FASTINT) - /* If argument is a fastint, guarantee that it remains one. - * There's no downgrade check for other cases. - */ - if (DUK_TVAL_IS_FASTINT(tv)) { - /* XXX: Unnecessary conversion back and forth. */ - return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); - } -#endif - d = coerce_func(thr, tv); - - /* XXX: fastint? */ - - /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ - tv = duk_require_tval(thr, idx); - DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */ - return d; -} - -DUK_EXTERNAL duk_int_t duk_to_int(duk_hthread *thr, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4, - * API return value coercion: custom. - */ - DUK_ASSERT_API_ENTRY(thr); - (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger); - return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/); -} - -DUK_EXTERNAL duk_uint_t duk_to_uint(duk_hthread *thr, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4, - * API return value coercion: custom. - */ - DUK_ASSERT_API_ENTRY(thr); - (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger); - return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/); -} - -DUK_EXTERNAL duk_int32_t duk_to_int32(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_int32_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, idx); - DUK_ASSERT(tv != NULL); - ret = duk_js_toint32(thr, tv); - - /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ - tv = duk_require_tval(thr, idx); - DUK_TVAL_SET_I32_UPDREF(thr, tv, ret); /* side effects */ - return ret; -} - -DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_uint32_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, idx); - DUK_ASSERT(tv != NULL); - ret = duk_js_touint32(thr, tv); - - /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ - tv = duk_require_tval(thr, idx); - DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */ - return ret; -} - -DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_uint16_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, idx); - DUK_ASSERT(tv != NULL); - ret = duk_js_touint16(thr, tv); - - /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ - tv = duk_require_tval(thr, idx); - DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */ - return ret; -} - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Special coercion for Uint8ClampedArray. */ -DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx) { - duk_double_t d; - duk_double_t t; - duk_uint8_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - /* XXX: Simplify this algorithm, should be possible to come up with - * a shorter and faster algorithm by inspecting IEEE representation - * directly. - */ - - d = duk_to_number(thr, idx); - if (d <= 0.0) { - return 0; - } else if (d >= 255) { - return 255; - } else if (DUK_ISNAN(d)) { - /* Avoid NaN-to-integer coercion as it is compiler specific. */ - return 0; - } - - t = d - DUK_FLOOR(d); - if (t == 0.5) { - /* Exact halfway, round to even. */ - ret = (duk_uint8_t) d; - ret = (ret + 1) & 0xfe; /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4 - * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4 - */ - } else { - /* Not halfway, round to nearest. */ - ret = (duk_uint8_t) (d + 0.5); - } - return ret; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -DUK_EXTERNAL const char *duk_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { - DUK_ASSERT_API_ENTRY(thr); - - (void) duk_to_string(thr, idx); - DUK_ASSERT(duk_is_string(thr, idx)); - return duk_require_lstring(thr, idx, out_len); -} - -DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_hthread *thr, void *udata) { - DUK_ASSERT_CTX_VALID(thr); - DUK_UNREF(udata); - - duk_to_string(thr, -1); - return 1; -} - -DUK_EXTERNAL const char *duk_safe_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - - /* We intentionally ignore the duk_safe_call() return value and only - * check the output type. This way we don't also need to check that - * the returned value is indeed a string in the success case. - */ - - duk_dup(thr, idx); - (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/); - if (!duk_is_string(thr, -1)) { - /* Error: try coercing error to string once. */ - (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/); - if (!duk_is_string(thr, -1)) { - /* Double error */ - duk_pop_unsafe(thr); - duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR); - } else { - ; - } - } else { - /* String; may be a symbol, accepted. */ - ; - } - DUK_ASSERT(duk_is_string(thr, -1)); - - duk_replace(thr, idx); - DUK_ASSERT(duk_get_string(thr, idx) != NULL); - return duk_get_lstring(thr, idx, out_len); -} - -DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - - duk_to_primitive(thr, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */ - h = duk_get_hstring(thr, idx); - if (h == NULL) { - /* The "is string?" check may seem unnecessary, but as things - * are duk_to_hstring() invokes ToString() which fails for - * symbols. But since symbols are already strings for Duktape - * C API, we check for that before doing the coercion. - */ - h = duk_to_hstring(thr, idx); - } - DUK_ASSERT(h != NULL); - return h; -} - -#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ -DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - (void) duk_safe_to_string(thr, idx); - DUK_ASSERT(duk_is_string(thr, idx)); - DUK_ASSERT(duk_get_hstring(thr, idx) != NULL); - return duk_known_hstring(thr, idx); -} -#endif - -/* Push Object.prototype.toString() output for 'tv'. */ -DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv) { - duk_small_uint_t stridx; - duk_hstring *h_strclass; - - DUK_ASSERT_API_ENTRY(thr); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */ - case DUK_TAG_UNDEFINED: { - stridx = DUK_STRIDX_UC_UNDEFINED; - break; - } - case DUK_TAG_NULL: { - stridx = DUK_STRIDX_UC_NULL; - break; - } - case DUK_TAG_BOOLEAN: { - stridx = DUK_STRIDX_UC_BOOLEAN; - break; - } - case DUK_TAG_POINTER: { - stridx = DUK_STRIDX_UC_POINTER; - break; - } - case DUK_TAG_LIGHTFUNC: { - stridx = DUK_STRIDX_UC_FUNCTION; - break; - } - case DUK_TAG_STRING: { - duk_hstring *h; - h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - stridx = DUK_STRIDX_UC_SYMBOL; - } else { - stridx = DUK_STRIDX_UC_STRING; - } - break; - } - case DUK_TAG_OBJECT: { - duk_hobject *h; - duk_small_uint_t classnum; - - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h); - stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum); - - /* XXX: This is not entirely correct anymore; in ES2015 the - * default lookup should use @@toStringTag to come up with - * e.g. [object Symbol], [object Uint8Array], etc. See - * ES2015 Section 19.1.3.6. The downside of implementing that - * directly is that the @@toStringTag lookup may have side - * effects, so all call sites must be checked for that. - * Some may need a side-effect free lookup, e.g. avoiding - * getters which are not typical. - */ - break; - } - case DUK_TAG_BUFFER: { - stridx = DUK_STRIDX_UINT8_ARRAY; - break; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: - /* Fall through to generic number case. */ -#endif - default: { - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* number (maybe fastint) */ - stridx = DUK_STRIDX_UC_NUMBER; - break; - } - } - h_strclass = DUK_HTHREAD_GET_STRING(thr, stridx); - DUK_ASSERT(h_strclass != NULL); - - duk_push_sprintf(thr, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass)); -} - -/* XXX: other variants like uint, u32 etc */ -DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) { - duk_tval *tv; - duk_tval tv_tmp; - duk_double_t d, dmin, dmax; - duk_int_t res; - duk_bool_t clamped = 0; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, idx); - DUK_ASSERT(tv != NULL); - d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */ - - dmin = (duk_double_t) minval; - dmax = (duk_double_t) maxval; - - if (d < dmin) { - clamped = 1; - res = minval; - d = dmin; - } else if (d > dmax) { - clamped = 1; - res = maxval; - d = dmax; - } else { - res = (duk_int_t) d; - } - DUK_UNREF(d); /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */ - /* 'd' and 'res' agree here */ - - /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */ - tv = duk_get_tval(thr, idx); - DUK_ASSERT(tv != NULL); /* not popped by side effect */ - DUK_TVAL_SET_TVAL(&tv_tmp, tv); -#if defined(DUK_USE_FASTINT) -#if (DUK_INT_MAX <= 0x7fffffffL) - DUK_TVAL_SET_I32(tv, res); -#else - /* Clamping needed if duk_int_t is 64 bits. */ - if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) { - DUK_TVAL_SET_FASTINT(tv, res); - } else { - DUK_TVAL_SET_NUMBER(tv, d); - } -#endif -#else - DUK_TVAL_SET_NUMBER(tv, d); /* no need to incref */ -#endif - DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ - - if (out_clamped) { - *out_clamped = clamped; - } else { - /* coerced value is updated to value stack even when RangeError thrown */ - if (clamped) { - DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE); - } - } - - return res; -} - -DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) { - duk_bool_t dummy; - - DUK_ASSERT_API_ENTRY(thr); - - return duk_to_int_clamped_raw(thr, idx, minval, maxval, &dummy); -} - -DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) { - DUK_ASSERT_API_ENTRY(thr); - return duk_to_int_clamped_raw(thr, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */ -} - -DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - tv = DUK_GET_TVAL_POSIDX(thr, idx); - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: { - duk_push_hstring_stridx(thr, DUK_STRIDX_LC_UNDEFINED); - break; - } - case DUK_TAG_NULL: { - duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL); - break; - } - case DUK_TAG_BOOLEAN: { - if (DUK_TVAL_GET_BOOLEAN(tv)) { - duk_push_hstring_stridx(thr, DUK_STRIDX_TRUE); - } else { - duk_push_hstring_stridx(thr, DUK_STRIDX_FALSE); - } - break; - } - case DUK_TAG_STRING: { - /* Nop for actual strings, TypeError for Symbols. - * Because various internals rely on ToString() coercion of - * internal strings, -allow- (NOP) string coercion for hidden - * symbols. - */ -#if 1 - duk_hstring *h; - h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL); - } else { - goto skip_replace; - } -#else - goto skip_replace; -#endif - } - case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */ - case DUK_TAG_OBJECT: { - /* Plain buffers: go through ArrayBuffer.prototype.toString() - * for coercion. - * - * Symbol objects: duk_to_primitive() results in a plain symbol - * value, and duk_to_string() then causes a TypeError. - */ - duk_to_primitive(thr, idx, DUK_HINT_STRING); - DUK_ASSERT(!duk_is_buffer(thr, idx)); /* ToPrimitive() must guarantee */ - DUK_ASSERT(!duk_is_object(thr, idx)); - return duk_to_string(thr, idx); /* Note: recursive call */ - } - case DUK_TAG_POINTER: { - void *ptr = DUK_TVAL_GET_POINTER(tv); - if (ptr != NULL) { - duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) ptr); - } else { - /* Represent a null pointer as 'null' to be consistent with - * the JX format variant. Native '%p' format for a NULL - * pointer may be e.g. '(nil)'. - */ - duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL); - } - break; - } - case DUK_TAG_LIGHTFUNC: { - /* Should match Function.prototype.toString() */ - duk_push_lightfunc_tostring(thr, tv); - break; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: { - /* number */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - duk_push_tval(thr, tv); - duk_numconv_stringify(thr, - 10 /*radix*/, - 0 /*precision:shortest*/, - 0 /*force_exponential*/); - break; - } - } - - duk_replace(thr, idx); - - skip_replace: - DUK_ASSERT(duk_is_string(thr, idx)); - return duk_require_string(thr, idx); -} - -DUK_INTERNAL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *ret; - - DUK_ASSERT_API_ENTRY(thr); - - duk_to_string(thr, idx); - ret = duk_get_hstring(thr, idx); - DUK_ASSERT(ret != NULL); - return ret; -} - -DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - return duk_to_hstring(thr, -1); -} - -DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *ret; - - DUK_ASSERT_API_ENTRY(thr); - - ret = duk_get_hstring(thr, idx); - if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) { - return ret; - } - return duk_to_hstring(thr, idx); -} - -/* Convert a plain buffer or any buffer object into a string, using the buffer - * bytes 1:1 in the internal string representation. For views the active byte - * slice (not element slice interpreted as an initializer) is used. This is - * necessary in Duktape 2.x because ToString(plainBuffer) no longer creates a - * string with the same bytes as in the buffer but rather (usually) - * '[object ArrayBuffer]'. - */ -DUK_EXTERNAL const char *duk_buffer_to_string(duk_hthread *thr, duk_idx_t idx) { - void *ptr_src; - duk_size_t len; - const char *res; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - - ptr_src = duk_require_buffer_data(thr, idx, &len); - DUK_ASSERT(ptr_src != NULL || len == 0); - - res = duk_push_lstring(thr, (const char *) ptr_src, len); - duk_replace(thr, idx); - return res; -} - -DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) { - duk_hbuffer *h_buf; - const duk_uint8_t *src_data; - duk_size_t src_size; - duk_uint8_t *dst_data; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - - h_buf = duk_get_hbuffer(thr, idx); - if (h_buf != NULL) { - /* Buffer is kept as is, with the fixed/dynamic nature of the - * buffer only changed if requested. An external buffer - * is converted into a non-external dynamic buffer in a - * duk_to_dynamic_buffer() call. - */ - duk_uint_t tmp; - duk_uint8_t *tmp_ptr; - - tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf); - src_data = (const duk_uint8_t *) tmp_ptr; - src_size = DUK_HBUFFER_GET_SIZE(h_buf); - - tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED); - if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) || - mode == DUK_BUF_MODE_DONTCARE) { - /* Note: src_data may be NULL if input is a zero-size - * dynamic buffer. - */ - dst_data = tmp_ptr; - goto skip_copy; - } - } else { - /* Non-buffer value is first ToString() coerced, then converted - * to a buffer (fixed buffer is used unless a dynamic buffer is - * explicitly requested). Symbols are rejected with a TypeError. - * XXX: C API could maybe allow symbol-to-buffer coercion? - */ - src_data = (const duk_uint8_t *) duk_to_lstring(thr, idx, &src_size); - } - - dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/); - if (DUK_LIKELY(src_size > 0)) { - /* When src_size == 0, src_data may be NULL (if source - * buffer is dynamic), and dst_data may be NULL (if - * target buffer is dynamic). Avoid zero-size memcpy() - * with an invalid pointer. - */ - DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size); - } - duk_replace(thr, idx); - skip_copy: - - if (out_size) { - *out_size = src_size; - } - return dst_data; -} - -DUK_EXTERNAL void *duk_to_pointer(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - void *res; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - tv = DUK_GET_TVAL_POSIDX(thr, idx); - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: - case DUK_TAG_NULL: - case DUK_TAG_BOOLEAN: - res = NULL; - break; - case DUK_TAG_POINTER: - res = DUK_TVAL_GET_POINTER(tv); - break; - case DUK_TAG_STRING: - case DUK_TAG_OBJECT: - case DUK_TAG_BUFFER: - /* Heap allocated: return heap pointer which is NOT useful - * for the caller, except for debugging. - */ - res = (void *) DUK_TVAL_GET_HEAPHDR(tv); - break; - case DUK_TAG_LIGHTFUNC: - /* Function pointers do not always cast correctly to void * - * (depends on memory and segmentation model for instance), - * so they coerce to NULL. - */ - res = NULL; - break; -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: - /* number */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - res = NULL; - break; - } - - duk_push_pointer(thr, res); - duk_replace(thr, idx); - return res; -} - -DUK_LOCAL void duk__push_func_from_lightfunc(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) { - duk_idx_t nargs; - duk_uint_t flags = 0; /* shared flags for a subset of types */ - duk_small_uint_t lf_len; - duk_hnatfunc *nf; - - nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags); - if (nargs == DUK_LFUNC_NARGS_VARARGS) { - nargs = (duk_idx_t) DUK_VARARGS; - } - - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_CONSTRUCTABLE | - DUK_HOBJECT_FLAG_CALLABLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_NATFUNC | - DUK_HOBJECT_FLAG_NEWENV | - DUK_HOBJECT_FLAG_STRICT | - DUK_HOBJECT_FLAG_NOTAIL | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); - (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE); - - lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); - if ((duk_idx_t) lf_len != nargs) { - /* Explicit length is only needed if it differs from 'nargs'. */ - duk_push_int(thr, (duk_int_t) lf_len); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); - } - -#if defined(DUK_USE_FUNC_NAME_PROPERTY) - duk_push_lightfunc_name_raw(thr, func, lf_flags); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); -#endif - - nf = duk_known_hnatfunc(thr, -1); - nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); -} - -DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_uint_t flags = 0; /* shared flags for a subset of types */ - duk_small_int_t proto = 0; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); - tv = DUK_GET_TVAL_POSIDX(thr, idx); - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { -#if !defined(DUK_USE_BUFFEROBJECT_SUPPORT) - case DUK_TAG_BUFFER: /* With no bufferobject support, don't object coerce. */ -#endif - case DUK_TAG_UNDEFINED: - case DUK_TAG_NULL: { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); - break; - } - case DUK_TAG_BOOLEAN: { - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN); - proto = DUK_BIDX_BOOLEAN_PROTOTYPE; - goto create_object; - } - case DUK_TAG_STRING: { - duk_hstring *h; - h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL); - proto = DUK_BIDX_SYMBOL_PROTOTYPE; - } else { - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); - proto = DUK_BIDX_STRING_PROTOTYPE; - } - goto create_object; - } - case DUK_TAG_OBJECT: { - /* nop */ - break; - } -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - case DUK_TAG_BUFFER: { - /* A plain buffer object coerces to a full ArrayBuffer which - * is not fully transparent behavior (ToObject() should be a - * nop for an object). This behavior matches lightfuncs which - * also coerce to an equivalent Function object. There are - * also downsides to defining ToObject(plainBuffer) as a no-op; - * for example duk_to_hobject() could result in a NULL pointer. - */ - duk_hbuffer *h_buf; - - h_buf = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h_buf != NULL); - duk_hbufobj_push_uint8array_from_plain(thr, h_buf); - goto replace_value; - } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - case DUK_TAG_POINTER: { - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER); - proto = DUK_BIDX_POINTER_PROTOTYPE; - goto create_object; - } - case DUK_TAG_LIGHTFUNC: { - /* Lightfunc coerces to a Function instance with concrete - * properties. Since 'length' is virtual for Duktape/C - * functions, don't need to define that. The result is made - * extensible to mimic what happens to strings in object - * coercion: - * - * > Object.isExtensible(Object('foo')) - * true - */ - duk_small_uint_t lf_flags; - duk_c_function func; - - DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); - duk__push_func_from_lightfunc(thr, func, lf_flags); - goto replace_value; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: { - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); - proto = DUK_BIDX_NUMBER_PROTOTYPE; - goto create_object; - } - } - DUK_ASSERT(duk_is_object(thr, idx)); - return; - - create_object: - (void) duk_push_object_helper(thr, flags, proto); - - /* Note: Boolean prototype's internal value property is not writable, - * but duk_xdef_prop_stridx() disregards the write protection. Boolean - * instances are immutable. - * - * String and buffer special behaviors are already enabled which is not - * ideal, but a write to the internal value is not affected by them. - */ - duk_dup(thr, idx); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); - - replace_value: - duk_replace(thr, idx); - DUK_ASSERT(duk_is_object(thr, idx)); -} - -DUK_INTERNAL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *ret; - - DUK_ASSERT_API_ENTRY(thr); - - duk_to_object(thr, idx); - ret = duk_known_hobject(thr, idx); - return ret; -} - -/* - * Type checking - */ - -DUK_LOCAL duk_bool_t duk__tag_check(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t tag) { - duk_tval *tv; - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - return (DUK_TVAL_GET_TAG(tv) == tag); -} - -DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_hthread *thr, duk_idx_t idx, duk_uint_t flag_mask) { - duk_hobject *obj; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_get_hobject(thr, idx); - if (obj) { - return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0); - } - return 0; -} - -DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) { - DUK_ASSERT(tv != NULL); - -#if defined(DUK_USE_PACKED_TVAL) - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNUSED: - return DUK_TYPE_NONE; - case DUK_TAG_UNDEFINED: - return DUK_TYPE_UNDEFINED; - case DUK_TAG_NULL: - return DUK_TYPE_NULL; - case DUK_TAG_BOOLEAN: - return DUK_TYPE_BOOLEAN; - case DUK_TAG_STRING: - return DUK_TYPE_STRING; - case DUK_TAG_OBJECT: - return DUK_TYPE_OBJECT; - case DUK_TAG_BUFFER: - return DUK_TYPE_BUFFER; - case DUK_TAG_POINTER: - return DUK_TYPE_POINTER; - case DUK_TAG_LIGHTFUNC: - return DUK_TYPE_LIGHTFUNC; -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: - /* Note: number has no explicit tag (in 8-byte representation) */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - return DUK_TYPE_NUMBER; - } -#else /* DUK_USE_PACKED_TVAL */ - DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv)); - DUK_ASSERT(sizeof(duk__type_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1); - return (duk_int_t) duk__type_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN]; -#endif /* DUK_USE_PACKED_TVAL */ -} - -DUK_EXTERNAL duk_int_t duk_get_type(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - - return duk_get_type_tval(tv); -} - -#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) -DUK_LOCAL const char * const duk__type_names[] = { - "none", - "undefined", - "null", - "boolean", - "number", - "string", - "object", - "buffer", - "pointer", - "lightfunc" -}; - -DUK_INTERNAL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx) { - duk_int_t type_tag; - - DUK_ASSERT_API_ENTRY(thr); - - type_tag = duk_get_type(thr, idx); - DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX); - DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1); - - return duk__type_names[type_tag]; -} -#endif /* DUK_USE_VERBOSE_ERRORS && DUK_USE_PARANOID_ERRORS */ - -DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_hobject *obj; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_OBJECT: - obj = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(obj != NULL); - return DUK_HOBJECT_GET_CLASS_NUMBER(obj); - case DUK_TAG_BUFFER: - /* Buffers behave like Uint8Array objects. */ - return DUK_HOBJECT_CLASS_UINT8ARRAY; - case DUK_TAG_LIGHTFUNC: - /* Lightfuncs behave like Function objects. */ - return DUK_HOBJECT_CLASS_FUNCTION; - default: - /* Primitive or UNUSED, no class number. */ - return DUK_HOBJECT_CLASS_NONE; - } -} - -DUK_EXTERNAL duk_bool_t duk_check_type(duk_hthread *thr, duk_idx_t idx, duk_int_t type) { - DUK_ASSERT_API_ENTRY(thr); - - return (duk_get_type(thr, idx) == type) ? 1 : 0; -} - -DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) { - DUK_ASSERT(tv != NULL); - -#if defined(DUK_USE_PACKED_TVAL) - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNUSED: - return DUK_TYPE_MASK_NONE; - case DUK_TAG_UNDEFINED: - return DUK_TYPE_MASK_UNDEFINED; - case DUK_TAG_NULL: - return DUK_TYPE_MASK_NULL; - case DUK_TAG_BOOLEAN: - return DUK_TYPE_MASK_BOOLEAN; - case DUK_TAG_STRING: - return DUK_TYPE_MASK_STRING; - case DUK_TAG_OBJECT: - return DUK_TYPE_MASK_OBJECT; - case DUK_TAG_BUFFER: - return DUK_TYPE_MASK_BUFFER; - case DUK_TAG_POINTER: - return DUK_TYPE_MASK_POINTER; - case DUK_TAG_LIGHTFUNC: - return DUK_TYPE_MASK_LIGHTFUNC; -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: - /* Note: number has no explicit tag (in 8-byte representation) */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - return DUK_TYPE_MASK_NUMBER; - } -#else /* DUK_USE_PACKED_TVAL */ - DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv)); - DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1); - return duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN]; -#endif /* DUK_USE_PACKED_TVAL */ -} - -DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - - return duk_get_type_mask_tval(tv); -} - -DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t mask) { - DUK_ASSERT_API_ENTRY(thr); - - if (DUK_LIKELY((duk_get_type_mask(thr, idx) & mask) != 0U)) { - return 1; - } - if (mask & DUK_TYPE_MASK_THROW) { - DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); - DUK_UNREACHABLE(); - } - return 0; -} - -DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__tag_check(thr, idx, DUK_TAG_UNDEFINED); -} - -DUK_EXTERNAL duk_bool_t duk_is_null(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__tag_check(thr, idx, DUK_TAG_NULL); -} - -DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__tag_check(thr, idx, DUK_TAG_BOOLEAN); -} - -DUK_EXTERNAL duk_bool_t duk_is_number(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - /* - * Number is special because it doesn't have a specific - * tag in the 8-byte representation. - */ - - /* XXX: shorter version for unpacked representation? */ - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - return DUK_TVAL_IS_NUMBER(tv); -} - -DUK_EXTERNAL duk_bool_t duk_is_nan(duk_hthread *thr, duk_idx_t idx) { - /* XXX: This will now return false for non-numbers, even though they would - * coerce to NaN (as a general rule). In particular, duk_get_number() - * returns a NaN for non-numbers, so should this function also return - * true for non-numbers? - */ - - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - - /* XXX: for packed duk_tval an explicit "is number" check is unnecessary */ - if (!DUK_TVAL_IS_NUMBER(tv)) { - return 0; - } - return (duk_bool_t) DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv)); -} - -DUK_EXTERNAL duk_bool_t duk_is_string(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__tag_check(thr, idx, DUK_TAG_STRING); -} - -DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk_get_hstring_notsymbol(thr, idx) != NULL; -} - -DUK_EXTERNAL duk_bool_t duk_is_object(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__tag_check(thr, idx, DUK_TAG_OBJECT); -} - -DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__tag_check(thr, idx, DUK_TAG_BUFFER); -} - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_BUFFER(tv)) { - return 1; - } else if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - if (DUK_HOBJECT_IS_BUFOBJ(h)) { - return 1; - } - } - return 0; -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - - return duk_is_buffer(thr, idx); -} - -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__tag_check(thr, idx, DUK_TAG_POINTER); -} - -DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__tag_check(thr, idx, DUK_TAG_LIGHTFUNC); -} - -DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - DUK_ASSERT_API_ENTRY(thr); - h = duk_get_hstring(thr, idx); - /* Use DUK_LIKELY() here because caller may be more likely to type - * check an expected symbol than not. - */ - if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) { - return 1; - } - return 0; -} - -DUK_EXTERNAL duk_bool_t duk_is_array(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *obj; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_get_hobject(thr, idx); - if (obj) { - return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0); - } - return 0; -} - -DUK_EXTERNAL duk_bool_t duk_is_function(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h; - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0; - } - if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - return 1; - } - return 0; -} - -DUK_INTERNAL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv) { - DUK_ASSERT_API_ENTRY(thr); - - DUK_UNREF(thr); - - if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h; - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0; - } - if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - return 1; - } - return 0; -} - -DUK_EXTERNAL duk_bool_t duk_is_constructable(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h; - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - return DUK_HOBJECT_HAS_CONSTRUCTABLE(h) ? 1 : 0; - } - if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - return 1; - } - return 0; -} - -DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__obj_flag_any_default_false(thr, - idx, - DUK_HOBJECT_FLAG_NATFUNC); -} - -DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__obj_flag_any_default_false(thr, - idx, - DUK_HOBJECT_FLAG_COMPFUNC); -} - -DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk__obj_flag_any_default_false(thr, - idx, - DUK_HOBJECT_FLAG_BOUNDFUNC); -} - -DUK_EXTERNAL duk_bool_t duk_is_thread(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *obj; - - DUK_ASSERT_API_ENTRY(thr); - - obj = duk_get_hobject(thr, idx); - if (obj) { - return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0); - } - return 0; -} - -DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_BUFFER(tv)) { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1); - } - return 0; -} - -DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_BUFFER(tv)) { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0); - } - return 0; -} - -DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_get_tval_or_unused(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_BUFFER(tv)) { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0); - } - return 0; -} - -DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_hthread *thr, duk_idx_t idx) { - duk_hobject *h; - duk_uint_t sanity; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_get_hobject(thr, idx); - - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - do { - if (!h) { - return DUK_ERR_NONE; - } - - /* XXX: something more convenient? */ - - if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) { - return DUK_ERR_EVAL_ERROR; - } - if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) { - return DUK_ERR_RANGE_ERROR; - } - if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) { - return DUK_ERR_REFERENCE_ERROR; - } - if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) { - return DUK_ERR_SYNTAX_ERROR; - } - if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) { - return DUK_ERR_TYPE_ERROR; - } - if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) { - return DUK_ERR_URI_ERROR; - } - if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) { - return DUK_ERR_ERROR; - } - - h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - } while (--sanity > 0); - - return DUK_ERR_NONE; -} - -/* - * Pushers - */ - -DUK_INTERNAL void duk_push_tval(duk_hthread *thr, duk_tval *tv) { - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(tv != NULL); - - DUK__CHECK_SPACE(); - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_TVAL(tv_slot, tv); - DUK_TVAL_INCREF(thr, tv); /* no side effects */ -} - -DUK_EXTERNAL void duk_push_undefined(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - DUK__CHECK_SPACE(); - - /* Because value stack init policy is 'undefined above top', - * we don't need to write, just assert. - */ - thr->valstack_top++; - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1)); -} - -DUK_EXTERNAL void duk_push_null(duk_hthread *thr) { - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_NULL(tv_slot); -} - -DUK_EXTERNAL void duk_push_boolean(duk_hthread *thr, duk_bool_t val) { - duk_tval *tv_slot; - duk_small_int_t b; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */ - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_BOOLEAN(tv_slot, b); -} - -DUK_EXTERNAL void duk_push_true(duk_hthread *thr) { - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot); -} - -DUK_EXTERNAL void duk_push_false(duk_hthread *thr) { - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot); -} - -/* normalize NaN which may not match our canonical internal NaN */ -DUK_EXTERNAL void duk_push_number(duk_hthread *thr, duk_double_t val) { - duk_tval *tv_slot; - duk_double_union du; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - du.d = val; - DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_NUMBER(tv_slot, du.d); -} - -DUK_EXTERNAL void duk_push_int(duk_hthread *thr, duk_int_t val) { -#if defined(DUK_USE_FASTINT) - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - tv_slot = thr->valstack_top++; -#if DUK_INT_MAX <= 0x7fffffffL - DUK_TVAL_SET_I32(tv_slot, (duk_int32_t) val); -#else - if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) { - DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val); - } else { - duk_double_t = (duk_double_t) val; - DUK_TVAL_SET_NUMBER(tv_slot, d); - } -#endif -#else /* DUK_USE_FASTINT */ - duk_tval *tv_slot; - duk_double_t d; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - d = (duk_double_t) val; - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_NUMBER(tv_slot, d); -#endif /* DUK_USE_FASTINT */ -} - -DUK_EXTERNAL void duk_push_uint(duk_hthread *thr, duk_uint_t val) { -#if defined(DUK_USE_FASTINT) - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - tv_slot = thr->valstack_top++; -#if DUK_UINT_MAX <= 0xffffffffUL - DUK_TVAL_SET_U32(tv_slot, (duk_uint32_t) val); -#else - if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */ - /* XXX: take advantage of val being unsigned, no need to mask */ - DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val); - } else { - duk_double_t = (duk_double_t) val; - DUK_TVAL_SET_NUMBER(tv_slot, d); - } -#endif -#else /* DUK_USE_FASTINT */ - duk_tval *tv_slot; - duk_double_t d; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - d = (duk_double_t) val; - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_NUMBER(tv_slot, d); -#endif /* DUK_USE_FASTINT */ -} - -DUK_EXTERNAL void duk_push_nan(duk_hthread *thr) { - duk_tval *tv_slot; - duk_double_union du; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - DUK_DBLUNION_SET_NAN(&du); - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_NUMBER(tv_slot, du.d); -} - -DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk_size_t len) { - duk_hstring *h; - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - - /* check stack before interning (avoid hanging temp) */ - DUK__CHECK_SPACE(); - - /* NULL with zero length represents an empty string; NULL with higher - * length is also now trated like an empty string although it is - * a bit dubious. This is unlike duk_push_string() which pushes a - * 'null' if the input string is a NULL. - */ - if (!str) { - len = 0; - } - - /* Check for maximum string length */ - if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { - DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); - } - - h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); - DUK_ASSERT(h != NULL); - - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_STRING(tv_slot, h); - DUK_HSTRING_INCREF(thr, h); /* no side effects */ - - return (const char *) DUK_HSTRING_GET_DATA(h); -} - -DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) { - DUK_ASSERT_API_ENTRY(thr); - - if (str) { - return duk_push_lstring(thr, str, DUK_STRLEN(str)); - } else { - duk_push_null(thr); - return NULL; - } -} - -DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) { - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - DUK__CHECK_SPACE(); - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_POINTER(tv_slot, val); -} - -DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i) { - duk_hstring *h_tmp; - - DUK_ASSERT_API_ENTRY(thr); - - /* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */ - duk_push_uint(thr, (duk_uint_t) i); - h_tmp = duk_to_hstring_m1(thr); - DUK_ASSERT(h_tmp != NULL); - return h_tmp; -} - -DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_object_coercible) { - duk_tval *tv_slot; - - DUK__CHECK_SPACE(); - - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */ - tv_slot = thr->valstack_top++; - - if (DUK_UNLIKELY(thr->callstack_curr == NULL)) { - if (check_object_coercible) { - goto type_error; - } - /* 'undefined' already on stack top */ - } else { - duk_tval *tv; - - /* 'this' binding is just before current activation's bottom */ - DUK_ASSERT(thr->valstack_bottom > thr->valstack); - tv = thr->valstack_bottom - 1; - if (check_object_coercible && - (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) { - /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */ - goto type_error; - } - - DUK_TVAL_SET_TVAL(tv_slot, tv); - DUK_TVAL_INCREF(thr, tv); - } - return; - - type_error: - DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); -} - -DUK_EXTERNAL void duk_push_this(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - duk__push_this_helper(thr, 0 /*check_object_coercible*/); -} - -DUK_INTERNAL void duk_push_this_check_object_coercible(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - duk__push_this_helper(thr, 1 /*check_object_coercible*/); -} - -DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - duk__push_this_helper(thr, 1 /*check_object_coercible*/); - h = duk_to_hobject(thr, -1); - DUK_ASSERT(h != NULL); - return h; -} - -DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - duk__push_this_helper(thr, 1 /*check_object_coercible*/); - return duk_to_hstring_m1(thr); /* This will reject all Symbol values; accepts Symbol objects. */ -} - -DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */ - DUK_ASSERT(thr->callstack_curr != NULL); /* caller required to know */ - DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */ - DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */ - - return thr->valstack_bottom - 1; -} - -DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) { - duk_activation *act; - - DUK_ASSERT_API_ENTRY(thr); - - act = thr->callstack_curr; - if (act != NULL) { - duk_push_tval(thr, &act->tv_func); - } else { - duk_push_undefined(thr); - } -} - -DUK_EXTERNAL void duk_push_current_thread(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - if (thr->heap->curr_thread) { - duk_push_hobject(thr, (duk_hobject *) thr->heap->curr_thread); - } else { - duk_push_undefined(thr); - } -} - -DUK_EXTERNAL void duk_push_global_object(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL); -} - -/* XXX: size optimize */ -DUK_LOCAL void duk__push_stash(duk_hthread *thr) { - if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE)) { - DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use")); - duk_pop_unsafe(thr); - duk_push_bare_object(thr); - duk_dup_top(thr); - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */ - } - duk_remove_m2(thr); -} - -DUK_EXTERNAL void duk_push_heap_stash(duk_hthread *thr) { - duk_heap *heap; - DUK_ASSERT_API_ENTRY(thr); - heap = thr->heap; - DUK_ASSERT(heap->heap_object != NULL); - duk_push_hobject(thr, heap->heap_object); - duk__push_stash(thr); -} - -DUK_EXTERNAL void duk_push_global_stash(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_push_global_object(thr); - duk__push_stash(thr); -} - -DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_thr) { - DUK_ASSERT_API_ENTRY(thr); - if (DUK_UNLIKELY(target_thr == NULL)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return; /* not reached */ - } - duk_push_hobject(thr, (duk_hobject *) target_thr); - duk__push_stash(thr); -} - -/* XXX: duk_ssize_t would be useful here */ -DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_hthread *thr, void *buf, duk_size_t sz, const char *fmt, va_list ap) { - duk_int_t len; - - DUK_ASSERT_CTX_VALID(thr); - DUK_UNREF(thr); - - /* NUL terminator handling doesn't matter here */ - len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap); - if (len < (duk_int_t) sz) { - /* Return value of 'sz' or more indicates output was (potentially) - * truncated. - */ - return (duk_int_t) len; - } - return -1; -} - -DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va_list ap) { - duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE]; - duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE; - duk_bool_t pushed_buf = 0; - void *buf; - duk_int_t len; /* XXX: duk_ssize_t */ - const char *res; - - DUK_ASSERT_API_ENTRY(thr); - - /* special handling of fmt==NULL */ - if (!fmt) { - duk_hstring *h_str; - duk_push_hstring_empty(thr); - h_str = duk_known_hstring(thr, -1); - return (const char *) DUK_HSTRING_GET_DATA(h_str); - } - - /* initial estimate based on format string */ - sz = DUK_STRLEN(fmt) + 16; /* format plus something to avoid just missing */ - if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) { - sz = DUK_PUSH_SPRINTF_INITIAL_SIZE; - } - DUK_ASSERT(sz > 0); - - /* Try to make do with a stack buffer to avoid allocating a temporary buffer. - * This works 99% of the time which is quite nice. - */ - for (;;) { - va_list ap_copy; /* copied so that 'ap' can be reused */ - - if (sz <= sizeof(stack_buf)) { - buf = stack_buf; - } else if (!pushed_buf) { - pushed_buf = 1; - buf = duk_push_dynamic_buffer(thr, sz); - } else { - buf = duk_resize_buffer(thr, -1, sz); - } - DUK_ASSERT(buf != NULL); - - DUK_VA_COPY(ap_copy, ap); - len = duk__try_push_vsprintf(thr, buf, sz, fmt, ap_copy); - va_end(ap_copy); - if (len >= 0) { - break; - } - - /* failed, resize and try again */ - sz = sz * 2; - if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) { - DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); - } - } - - /* Cannot use duk_buffer_to_string() on the buffer because it is - * usually larger than 'len'; 'buf' is also usually a stack buffer. - */ - res = duk_push_lstring(thr, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */ - if (pushed_buf) { - duk_remove_m2(thr); - } - return res; -} - -DUK_EXTERNAL const char *duk_push_sprintf(duk_hthread *thr, const char *fmt, ...) { - va_list ap; - const char *ret; - - DUK_ASSERT_API_ENTRY(thr); - - /* allow fmt==NULL */ - va_start(ap, fmt); - ret = duk_push_vsprintf(thr, fmt, ap); - va_end(ap); - - return ret; -} - -DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { - duk_tval *tv_slot; - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(prototype_bidx == -1 || - (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS)); - - DUK__CHECK_SPACE(); - - h = duk_hobject_alloc(thr, hobject_flags_and_class); - DUK_ASSERT(h != NULL); - - DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags)); - - tv_slot = thr->valstack_top; - DUK_TVAL_SET_OBJECT(tv_slot, h); - DUK_HOBJECT_INCREF(thr, h); /* no side effects */ - thr->valstack_top++; - - /* object is now reachable */ - - if (prototype_bidx >= 0) { - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, thr->builtins[prototype_bidx]); - } else { - DUK_ASSERT(prototype_bidx == -1); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL); - } - - return h; -} - -DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto) { - duk_hobject *h; - - DUK_ASSERT_API_ENTRY(thr); - - h = duk_push_object_helper(thr, hobject_flags_and_class, -1); - DUK_ASSERT(h != NULL); - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, proto); - return h; -} - -DUK_EXTERNAL duk_idx_t duk_push_object(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - (void) duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), - DUK_BIDX_OBJECT_PROTOTYPE); - return duk_get_top_index_unsafe(thr); -} - -DUK_EXTERNAL duk_idx_t duk_push_array(duk_hthread *thr) { - duk_uint_t flags; - duk_harray *obj; - duk_idx_t ret; - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_ARRAY_PART | - DUK_HOBJECT_FLAG_EXOTIC_ARRAY | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY); - - obj = duk_harray_alloc(thr, flags); - DUK_ASSERT(obj != NULL); - - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]); - - tv_slot = thr->valstack_top; - DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); - DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */ - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - thr->valstack_top++; - - DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */ - return ret; -} - -DUK_INTERNAL duk_harray *duk_push_harray(duk_hthread *thr) { - /* XXX: API call could do this directly, cast to void in API macro. */ - duk_harray *a; - - DUK_ASSERT_API_ENTRY(thr); - - (void) duk_push_array(thr); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1)); - a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1); - DUK_ASSERT(a != NULL); - return a; -} - -/* Push a duk_harray with preallocated size (.length also set to match size). - * Caller may then populate array part of the duk_harray directly. - */ -DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size) { - duk_harray *a; - - DUK_ASSERT_API_ENTRY(thr); - - a = duk_push_harray(thr); - - duk_hobject_realloc_props(thr, - (duk_hobject *) a, - 0, - size, - 0, - 0); - a->length = size; - return a; -} - -DUK_INTERNAL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size) { - duk_harray *a; - - DUK_ASSERT_API_ENTRY(thr); - - a = duk_push_harray_with_size(thr, size); - DUK_ASSERT(a != NULL); - return DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a); -} - -DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) { - duk_hthread *obj; - duk_idx_t ret; - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - - DUK__CHECK_SPACE(); - - obj = duk_hthread_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - DUK_ASSERT(obj != NULL); - obj->state = DUK_HTHREAD_STATE_INACTIVE; -#if defined(DUK_USE_ROM_STRINGS) - /* Nothing to initialize, strs[] is in ROM. */ -#else -#if defined(DUK_USE_HEAPPTR16) - obj->strs16 = thr->strs16; -#else - obj->strs = thr->strs; -#endif -#endif - DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags)); - - /* make the new thread reachable */ - tv_slot = thr->valstack_top; - DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); - DUK_HTHREAD_INCREF(thr, obj); - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - thr->valstack_top++; - - /* important to do this *after* pushing, to make the thread reachable for gc */ - if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) { - DUK_ERROR_ALLOC_FAILED(thr); - } - - /* initialize built-ins - either by copying or creating new ones */ - if (flags & DUK_THREAD_NEW_GLOBAL_ENV) { - duk_hthread_create_builtin_objects(obj); - } else { - duk_hthread_copy_builtin_objects(thr, obj); - } - - /* default prototype */ - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]); - - /* Initial stack size satisfies the stack slack constraints so there - * is no need to require stack here. - */ - DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >= - DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); - - return ret; -} - -DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) { - duk_hcompfunc *obj; - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - - DUK__CHECK_SPACE(); - - /* Template functions are not strictly constructable (they don't - * have a "prototype" property for instance), so leave the - * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here. - */ - - obj = duk_hcompfunc_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_CALLABLE | - DUK_HOBJECT_FLAG_COMPFUNC | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); - if (DUK_UNLIKELY(obj == NULL)) { - DUK_ERROR_ALLOC_FAILED(thr); - } - - DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags)); - - tv_slot = thr->valstack_top; - DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); - DUK_HOBJECT_INCREF(thr, obj); - thr->valstack_top++; - - /* default prototype */ - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL); - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); - - return obj; -} - -DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) { - duk_hboundfunc *obj; - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - - DUK__CHECK_SPACE(); - obj = duk_hboundfunc_alloc(thr->heap, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BOUNDFUNC | - DUK_HOBJECT_FLAG_CONSTRUCTABLE | - DUK_HOBJECT_FLAG_CALLABLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } - - tv_slot = thr->valstack_top++; - DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); - DUK_HOBJECT_INCREF(thr, obj); - - /* Prototype is left as NULL because the caller always sets it (and - * it depends on the target function). - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL); - - return obj; -} - -DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx) { - duk_hnatfunc *obj; - duk_idx_t ret; - duk_tval *tv_slot; - duk_int16_t func_nargs; - - DUK_ASSERT_CTX_VALID(thr); - - DUK__CHECK_SPACE(); - - if (DUK_UNLIKELY(func == NULL)) { - goto api_error; - } - if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) { - func_nargs = (duk_int16_t) nargs; - } else if (nargs == DUK_VARARGS) { - func_nargs = DUK_HNATFUNC_NARGS_VARARGS; - } else { - goto api_error; - } - - obj = duk_hnatfunc_alloc(thr, flags); - DUK_ASSERT(obj != NULL); - - obj->func = func; - obj->nargs = func_nargs; - - DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld", - (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs)); - - tv_slot = thr->valstack_top; - DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); - DUK_HOBJECT_INCREF(thr, obj); - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - thr->valstack_top++; - - DUK_ASSERT_BIDX_VALID(proto_bidx); - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[proto_bidx]); - return ret; - - api_error: - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return 0; /* not reached */ -} - -DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) { - duk_uint_t flags; - - DUK_ASSERT_API_ENTRY(thr); - - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_CONSTRUCTABLE | - DUK_HOBJECT_FLAG_CALLABLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_NATFUNC | - DUK_HOBJECT_FLAG_NEWENV | - DUK_HOBJECT_FLAG_STRICT | - DUK_HOBJECT_FLAG_NOTAIL | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); - - /* Default prototype is a Duktape specific %NativeFunctionPrototype% - * which provides .length and .name getters. - */ - return duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE); -} - -DUK_INTERNAL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs) { - duk_uint_t flags; - - DUK_ASSERT_API_ENTRY(thr); - - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_CONSTRUCTABLE | - DUK_HOBJECT_FLAG_CALLABLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_NATFUNC | - DUK_HOBJECT_FLAG_NEWENV | - DUK_HOBJECT_FLAG_STRICT | - DUK_HOBJECT_FLAG_NOTAIL | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); - - /* Must use Function.prototype for standard built-in functions. */ - (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE); -} - -DUK_INTERNAL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs) { - duk_uint_t flags; - - DUK_ASSERT_API_ENTRY(thr); - - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_CALLABLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_NATFUNC | - DUK_HOBJECT_FLAG_NEWENV | - DUK_HOBJECT_FLAG_STRICT | - DUK_HOBJECT_FLAG_NOTAIL | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); - - /* Must use Function.prototype for standard built-in functions. */ - (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE); -} - -DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) { - duk_small_uint_t lf_flags; - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - - DUK__CHECK_SPACE(); - - if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { - /* as is */ - } else if (nargs == DUK_VARARGS) { - nargs = DUK_LFUNC_NARGS_VARARGS; - } else { - goto api_error; - } - if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) { - goto api_error; - } - if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) { - goto api_error; - } - - lf_flags = DUK_LFUNC_FLAGS_PACK((duk_small_int_t) magic, (duk_small_uint_t) length, (duk_small_uint_t) nargs); - tv_slot = thr->valstack_top++; - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_slot)); - DUK_TVAL_SET_LIGHTFUNC(tv_slot, func, lf_flags); - DUK_ASSERT(tv_slot >= thr->valstack_bottom); - return (duk_idx_t) (tv_slot - thr->valstack_bottom); - - api_error: - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return 0; /* not reached */ -} - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { - duk_hbufobj *obj; - duk_tval *tv_slot; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(prototype_bidx >= 0); - - DUK__CHECK_SPACE(); - - obj = duk_hbufobj_alloc(thr, hobject_flags_and_class); - DUK_ASSERT(obj != NULL); - - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]); - DUK_ASSERT_HBUFOBJ_VALID(obj); - - tv_slot = thr->valstack_top; - DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); - DUK_HOBJECT_INCREF(thr, obj); - thr->valstack_top++; - - return obj; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* XXX: There's quite a bit of overlap with buffer creation handling in - * duk_bi_buffer.c. Look for overlap and refactor. - */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,istypedarray) \ - (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (istypedarray)) - -static const duk_uint32_t duk__bufobj_flags_lookup[] = { - /* Node.js Buffers are Uint8Array instances which inherit from Buffer.prototype. */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_NODEJS_BUFFER */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DATAVIEW */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */ -}; -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) { - duk_hbufobj *h_bufobj; - duk_hbuffer *h_val; - duk_hobject *h_arraybuf; - duk_uint32_t tmp; - duk_uint_t classnum; - duk_uint_t protobidx; - duk_uint_t lookupidx; - duk_uint_t uint_offset, uint_length, uint_added; - - DUK_ASSERT_API_ENTRY(thr); - - /* The underlying types for offset/length in duk_hbufobj is - * duk_uint_t; make sure argument values fit. - */ - uint_offset = (duk_uint_t) byte_offset; - uint_length = (duk_uint_t) byte_length; - if (sizeof(duk_size_t) != sizeof(duk_uint_t)) { - if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) { - goto range_error; - } - } - - DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */ - lookupidx = flags; - if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) { - goto arg_error; - } - tmp = duk__bufobj_flags_lookup[lookupidx]; - classnum = tmp >> 24; - protobidx = (tmp >> 16) & 0xff; - - h_arraybuf = duk_get_hobject(thr, idx_buffer); - if (h_arraybuf != NULL && /* argument is an object */ - flags != DUK_BUFOBJ_ARRAYBUFFER && /* creating a view */ - DUK_HOBJECT_GET_CLASS_NUMBER(h_arraybuf) == DUK_HOBJECT_CLASS_ARRAYBUFFER /* argument is ArrayBuffer */) { - duk_uint_t tmp_offset; - - DUK_ASSERT_HBUFOBJ_VALID((duk_hbufobj *) h_arraybuf); - h_val = ((duk_hbufobj *) h_arraybuf)->buf; - if (DUK_UNLIKELY(h_val == NULL)) { - goto arg_error; - } - - tmp_offset = uint_offset + ((duk_hbufobj *) h_arraybuf)->offset; - if (DUK_UNLIKELY(tmp_offset < uint_offset)) { - goto range_error; - } - uint_offset = tmp_offset; - - /* Note intentional difference to new TypedArray(): we allow - * caller to create an uncovered typed array (which is memory - * safe); new TypedArray() rejects it. - */ - } else { - /* Handle unexpected object arguments here too, for nice error - * messages. - */ - h_arraybuf = NULL; - h_val = duk_require_hbuffer(thr, idx_buffer); - } - - /* Wrap check for offset+length. */ - uint_added = uint_offset + uint_length; - if (DUK_UNLIKELY(uint_added < uint_offset)) { - goto range_error; - } - DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length); - - DUK_ASSERT(h_val != NULL); - - h_bufobj = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(classnum), - (duk_small_int_t) protobidx); - DUK_ASSERT(h_bufobj != NULL); - - h_bufobj->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_bufobj->buf_prop = h_arraybuf; - DUK_HOBJECT_INCREF_ALLOWNULL(thr, h_arraybuf); - h_bufobj->offset = uint_offset; - h_bufobj->length = uint_length; - h_bufobj->shift = (tmp >> 4) & 0x0f; - h_bufobj->elem_type = (tmp >> 8) & 0xff; - h_bufobj->is_typedarray = tmp & 0x0f; - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - /* TypedArray views need an automatic ArrayBuffer which must be - * provided as .buffer property of the view. The ArrayBuffer is - * referenced via duk_hbufobj->buf_prop and an inherited .buffer - * accessor returns it. The ArrayBuffer is created lazily on first - * access if necessary so we don't need to do anything more here. - */ - return; - - range_error: - DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS); - return; /* not reached */ - - arg_error: - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS); - return; /* not reached */ -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(idx_buffer); - DUK_UNREF(byte_offset); - DUK_UNREF(byte_length); - DUK_UNREF(flags); - DUK_ERROR_UNSUPPORTED(thr); -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) { - duk_hobject *proto; -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) - duk_small_uint_t augment_flags; -#endif - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr != NULL); - DUK_UNREF(filename); - DUK_UNREF(line); - - /* Error code also packs a tracedata related flag. */ -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) - augment_flags = 0; - if (err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE) { - augment_flags = DUK_AUGMENT_FLAG_NOBLAME_FILELINE; - } -#endif - err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE); - - /* error gets its 'name' from the prototype */ - proto = duk_error_prototype_from_code(thr, err_code); - (void) duk_push_object_helper_proto(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), - proto); - - /* ... and its 'message' from an instance property */ - if (fmt) { - duk_push_vsprintf(thr, fmt, ap); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); - } else { - /* If no explicit message given, put error code into message field - * (as a number). This is not fully in keeping with the Ecmascript - * error model because messages are supposed to be strings (Error - * constructors use ToString() on their argument). However, it's - * probably more useful than having a separate 'code' property. - */ - duk_push_int(thr, err_code); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); - } - - /* XXX: .code = err_code disabled, not sure if useful */ - - /* Creation time error augmentation */ -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) - /* filename may be NULL in which case file/line is not recorded */ - duk_err_augment_error_create(thr, thr, filename, line, augment_flags); /* may throw an error */ -#endif - - return duk_get_top_index_unsafe(thr); -} - -DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { - va_list ap; - duk_idx_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - va_start(ap, fmt); - ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); - va_end(ap); - return ret; -} - -#if !defined(DUK_USE_VARIADIC_MACROS) -DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) { - const char *filename = duk_api_global_filename; - duk_int_t line = duk_api_global_line; - va_list ap; - duk_idx_t ret; - - DUK_ASSERT_API_ENTRY(thr); - - duk_api_global_filename = NULL; - duk_api_global_line = 0; - va_start(ap, fmt); - ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); - va_end(ap); - return ret; -} -#endif /* DUK_USE_VARIADIC_MACROS */ - -DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_small_uint_t flags) { - duk_tval *tv_slot; - duk_hbuffer *h; - void *buf_data; - - DUK_ASSERT_API_ENTRY(thr); - - DUK__CHECK_SPACE(); - - /* Check for maximum buffer length. */ - if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) { - DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); - } - - h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); - if (DUK_UNLIKELY(h == NULL)) { - DUK_ERROR_ALLOC_FAILED(thr); - } - - tv_slot = thr->valstack_top; - DUK_TVAL_SET_BUFFER(tv_slot, h); - DUK_HBUFFER_INCREF(thr, h); - thr->valstack_top++; - - return (void *) buf_data; -} - -DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len) { - DUK_ASSERT_API_ENTRY(thr); - return duk_push_buffer_raw(thr, len, DUK_BUF_FLAG_NOZERO); -} - -DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len) { - void *ptr; - - DUK_ASSERT_API_ENTRY(thr); - - ptr = duk_push_buffer_raw(thr, len, 0); -#if !defined(DUK_USE_ZERO_BUFFER_DATA) - /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA - * is not set. - */ - DUK_MEMZERO((void *) ptr, (size_t) len); -#endif - return ptr; -} - -#if defined(DUK_USE_ES6_PROXY) -DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) { - duk_hobject *h_target; - duk_hobject *h_handler; - duk_hproxy *h_proxy; - duk_tval *tv_slot; - duk_uint_t flags; - - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(proxy_flags); - - /* DUK__CHECK_SPACE() unnecessary because the Proxy is written to - * value stack in-place. - */ -#if 0 - DUK__CHECK_SPACE(); -#endif - - /* Reject a proxy object as the target because it would need - * special handling in property lookups. (ES2015 has no such - * restriction.) - */ - h_target = duk_require_hobject_promote_mask(thr, -2, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - DUK_ASSERT(h_target != NULL); - if (DUK_HOBJECT_IS_PROXY(h_target)) { - goto fail_args; - } - - /* Reject a proxy object as the handler because it would cause - * potentially unbounded recursion. (ES2015 has no such - * restriction.) - * - * There's little practical reason to use a lightfunc or a plain - * buffer as the handler table: one could only provide traps via - * their prototype objects (Function.prototype and ArrayBuffer.prototype). - * Even so, as lightfuncs and plain buffers mimic their object - * counterparts, they're promoted and accepted here. - */ - h_handler = duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - DUK_ASSERT(h_handler != NULL); - if (DUK_HOBJECT_IS_PROXY(h_handler)) { - goto fail_args; - } - - /* XXX: Proxy object currently has no prototype, so ToPrimitive() - * coercion fails which is a bit confusing. - */ - - /* CALLABLE and CONSTRUCTABLE flags are copied from the (initial) - * target, see ES2015 Sections 9.5.15 and 9.5.13. - */ - flags = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h_target) & - (DUK_HOBJECT_FLAG_CALLABLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE); - flags |= DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ; - if (flags & DUK_HOBJECT_FLAG_CALLABLE) { - flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION) | - DUK_HOBJECT_FLAG_SPECIAL_CALL; - } else { - flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT); - } - - h_proxy = duk_hproxy_alloc(thr, flags); - DUK_ASSERT(h_proxy != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_proxy) == NULL); - - /* Initialize Proxy target and handler references; avoid INCREF - * by stealing the value stack refcounts via direct value stack - * manipulation. INCREF is needed for the Proxy itself however. - */ - DUK_ASSERT(h_target != NULL); - h_proxy->target = h_target; - DUK_ASSERT(h_handler != NULL); - h_proxy->handler = h_handler; - DUK_ASSERT_HPROXY_VALID(h_proxy); - - DUK_ASSERT(duk_get_hobject(thr, -2) == h_target); - DUK_ASSERT(duk_get_hobject(thr, -1) == h_handler); - tv_slot = thr->valstack_top - 2; - DUK_ASSERT(tv_slot >= thr->valstack_bottom); - DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) h_proxy); - DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_proxy); - tv_slot++; - DUK_TVAL_SET_UNDEFINED(tv_slot); /* [ ... target handler ] -> [ ... proxy undefined ] */ - thr->valstack_top = tv_slot; /* -> [ ... proxy ] */ - - DUK_DD(DUK_DDPRINT("created Proxy: %!iT", duk_get_tval(thr, -1))); - - return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom - 1); - - fail_args: - DUK_ERROR_TYPE_INVALID_ARGS(thr); -} -#else /* DUK_USE_ES6_PROXY */ -DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(proxy_flags); - DUK_ERROR_UNSUPPORTED(thr); -} -#endif /* DUK_USE_ES6_PROXY */ - -#if defined(DUK_USE_ASSERTIONS) -DUK_LOCAL void duk__validate_push_heapptr(duk_hthread *thr, void *ptr) { - duk_heaphdr *h; - duk_heaphdr *curr; - duk_bool_t found = 0; - - h = (duk_heaphdr *) ptr; - if (h == NULL) { - /* Allowed. */ - return; - } - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - - /* One particular problem case is where an object has been - * queued for finalization but the finalizer hasn't yet been - * executed. - * - * Corner case: we're running in a finalizer for object X, and - * user code calls duk_push_heapptr() for X itself. In this - * case X will be in finalize_list, and we can detect the case - * by seeing that X's FINALIZED flag is set (which is done before - * the finalizer starts executing). - */ -#if defined(DUK_USE_FINALIZER_SUPPORT) - for (curr = thr->heap->finalize_list; - curr != NULL; - curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { - /* FINALIZABLE is set for all objects on finalize_list - * except for an object being finalized right now. So - * can't assert here. - */ -#if 0 - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); -#endif - - if (curr == h) { - if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) { - /* Object is currently being finalized. */ - DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ - found = 1; - } else { - /* Not being finalized but on finalize_list, - * allowed since Duktape 2.1. - */ - DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ - found = 1; - } - } - } -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Because refzero_list is now processed to completion inline with - * no side effects, it's always empty here. - */ - DUK_ASSERT(thr->heap->refzero_list == NULL); -#endif - - /* If not present in finalize_list (or refzero_list), it - * must be either in heap_allocated or the string table. - */ - if (DUK_HEAPHDR_IS_STRING(h)) { - duk_uint32_t i; - duk_hstring *str; - duk_heap *heap = thr->heap; - - DUK_ASSERT(found == 0); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_STRTAB_PTRCOMP) - str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); -#else - str = heap->strtable[i]; -#endif - while (str != NULL) { - if (str == (duk_hstring *) h) { - DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ - found = 1; - break; - } - str = str->hdr.h_next; - } - } - DUK_ASSERT(found != 0); - } else { - for (curr = thr->heap->heap_allocated; - curr != NULL; - curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { - if (curr == h) { - DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ - found = 1; - } - } - DUK_ASSERT(found != 0); - } -} -#endif /* DUK_USE_ASSERTIONS */ - -DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_hthread *thr, void *ptr) { - duk_idx_t ret; - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - /* Reviving an object using a heap pointer is a dangerous API - * operation: if the application doesn't guarantee that the - * pointer target is always reachable, difficult-to-diagnose - * problems may ensue. Try to validate the 'ptr' argument to - * the extent possible. - */ - -#if defined(DUK_USE_ASSERTIONS) - duk__validate_push_heapptr(thr, ptr); -#endif - - DUK__CHECK_SPACE(); - - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - tv = thr->valstack_top++; - - if (ptr == NULL) { - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); - return ret; - } - - DUK_ASSERT_HEAPHDR_VALID((duk_heaphdr *) ptr); - - /* If the argument is on finalize_list it has technically been - * unreachable before duk_push_heapptr() but it's still safe to - * push it. Starting from Duktape 2.1 allow application code to - * do so. There are two main cases: - * - * (1) The object is on the finalize_list and we're called by - * the finalizer for the object being finalized. In this - * case do nothing: finalize_list handling will deal with - * the object queueing. This is detected by the object not - * having a FINALIZABLE flag despite being on the finalize_list; - * the flag is cleared for the object being finalized only. - * - * (2) The object is on the finalize_list but is not currently - * being processed. In this case the object can be queued - * back to heap_allocated with a few flags cleared, in effect - * cancelling the finalizer. - */ - if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) { - duk_heaphdr *curr; - - DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue")); - - curr = (duk_heaphdr *) ptr; - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - - /* Because FINALIZED is set prior to finalizer call, it will - * be set for the object being currently finalized, but not - * for other objects on finalize_list. - */ - DUK_HEAPHDR_CLEAR_FINALIZED(curr); - - /* Dequeue object from finalize_list and queue it back to - * heap_allocated. - */ -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */ - DUK_HEAPHDR_PREDEC_REFCOUNT(curr); -#endif - DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr); - - /* Continue with the rest. */ - } - - switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { - case DUK_HTYPE_STRING: - DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr); - break; - case DUK_HTYPE_OBJECT: - DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr); - break; - default: - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER); - DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr); - break; - } - - DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr); - - return ret; -} - -/* Push object with no prototype, i.e. a "bare" object. */ -DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - (void) duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), - -1); /* no prototype */ - return duk_get_top_index_unsafe(thr); -} - -DUK_INTERNAL void duk_push_hstring(duk_hthread *thr, duk_hstring *h) { - duk_tval tv; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(h != NULL); - - DUK_TVAL_SET_STRING(&tv, h); - duk_push_tval(thr, &tv); -} - -DUK_INTERNAL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT_STRIDX_VALID(stridx); - duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); -} - -DUK_INTERNAL void duk_push_hstring_empty(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING)); -} - -DUK_INTERNAL void duk_push_hobject(duk_hthread *thr, duk_hobject *h) { - duk_tval tv; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(h != NULL); - - DUK_TVAL_SET_OBJECT(&tv, h); - duk_push_tval(thr, &tv); -} - -DUK_INTERNAL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h) { - duk_tval tv; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(h != NULL); - - DUK_TVAL_SET_BUFFER(&tv, h); - duk_push_tval(thr, &tv); -} - -DUK_INTERNAL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS); - DUK_ASSERT(thr->builtins[builtin_idx] != NULL); - - duk_push_hobject(thr, thr->builtins[builtin_idx]); -} - -/* - * Poppers - */ - -DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_n_unsafe_raw(duk_hthread *thr, duk_idx_t count) { - duk_tval *tv; -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_tval *tv_end; -#endif - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(count >= 0); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); - -#if defined(DUK_USE_REFERENCE_COUNTING) - tv = thr->valstack_top; - tv_end = tv - count; - while (tv != tv_end) { - tv--; - DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); - } - thr->valstack_top = tv; - DUK_REFZERO_CHECK_FAST(thr); -#else - tv = thr->valstack_top; - while (count > 0) { - count--; - tv--; - DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_TVAL_SET_UNDEFINED(tv); - } - thr->valstack_top = tv; -#endif - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); -} - -DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - - if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) { - DUK_ERROR_RANGE_INVALID_COUNT(thr); - return; - } - DUK_ASSERT(count >= 0); - - duk__pop_n_unsafe_raw(thr, count); -} - -#if defined(DUK_USE_PREFER_SIZE) -DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n(thr, count); -} -#else /* DUK_USE_PREFER_SIZE */ -DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) { - DUK_ASSERT_API_ENTRY(thr); - duk__pop_n_unsafe_raw(thr, count); -} -#endif /* DUK_USE_PREFER_SIZE */ - -/* Pop N elements without DECREF (in effect "stealing" any actual refcounts). */ -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(count >= 0); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); - - tv = thr->valstack_top; - while (count > 0) { - count--; - tv--; - DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_TVAL_SET_UNDEFINED(tv); - } - thr->valstack_top = tv; - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); -} -#else /* DUK_USE_REFERENCE_COUNTING */ -DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n_unsafe(thr, count); -} -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* Popping one element is called so often that when footprint is not an issue, - * compile a specialized function for it. - */ -#if defined(DUK_USE_PREFER_SIZE) -DUK_EXTERNAL void duk_pop(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n(thr, 1); -} -DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n_unsafe(thr, 1); -} -DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n_nodecref_unsafe(thr, 1); -} -#else /* DUK_USE_PREFER_SIZE */ -DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_unsafe_raw(duk_hthread *thr) { - duk_tval *tv; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); - - tv = --thr->valstack_top; - DUK_ASSERT(tv >= thr->valstack_bottom); -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ -#else - DUK_TVAL_SET_UNDEFINED(tv); -#endif - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); -} -DUK_EXTERNAL void duk_pop(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { - DUK_ERROR_RANGE_INVALID_COUNT(thr); - } - - duk__pop_unsafe_raw(thr); -} -DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk__pop_unsafe_raw(thr); -} -DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); - - tv = --thr->valstack_top; - DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_TVAL_SET_UNDEFINED(tv); - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); -} -#endif /* !DUK_USE_PREFER_SIZE */ - -#if defined(DUK_USE_PREFER_SIZE) -DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_nodecref_unsafe(thr); -} -#else /* DUK_USE_PREFER_SIZE */ -DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); - - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1)); - thr->valstack_top--; - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); -} -#endif /* !DUK_USE_PREFER_SIZE */ - -#if defined(DUK_USE_PREFER_SIZE) -DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n(thr, 2); -} -DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n_unsafe(thr, 2); -} -DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n_nodecref_unsafe(thr, 2); -} -#else -DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_2_unsafe_raw(duk_hthread *thr) { - duk_tval *tv; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2); - - tv = --thr->valstack_top; - DUK_ASSERT(tv >= thr->valstack_bottom); -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ -#else - DUK_TVAL_SET_UNDEFINED(tv); -#endif - tv = --thr->valstack_top; - DUK_ASSERT(tv >= thr->valstack_bottom); -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ -#else - DUK_TVAL_SET_UNDEFINED(tv); -#endif - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); -} -DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) { - DUK_ERROR_RANGE_INVALID_COUNT(thr); - } - - duk__pop_2_unsafe_raw(thr); -} -DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk__pop_2_unsafe_raw(thr); -} -DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2); - - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 2)); - thr->valstack_top -= 2; - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); -} -#endif /* !DUK_USE_PREFER_SIZE */ - -DUK_EXTERNAL void duk_pop_3(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n(thr, 3); -} - -DUK_INTERNAL void duk_pop_3_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n_unsafe(thr, 3); -} - -DUK_INTERNAL void duk_pop_3_nodecref_unsafe(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_pop_n_nodecref_unsafe(thr, 3); -} - -/* - * Pack and unpack (pack value stack entries into an array and vice versa) - */ - -/* XXX: pack index range? array index offset? */ -DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) { - duk_tval *tv_src; - duk_tval *tv_dst; - duk_tval *tv_curr; - duk_tval *tv_limit; - duk_idx_t top; - - DUK_ASSERT_API_ENTRY(thr); - - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - DUK_ASSERT(top >= 0); - if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) { - /* Also handles negative count. */ - DUK_ERROR_RANGE_INVALID_COUNT(thr); - return; - } - DUK_ASSERT(count >= 0); - - /* Wrapping is controlled by the check above: value stack top can be - * at most DUK_USE_VALSTACK_LIMIT which is low enough so that - * multiplying with sizeof(duk_tval) won't wrap. - */ - DUK_ASSERT(count >= 0 && count <= (duk_idx_t) DUK_USE_VALSTACK_LIMIT); - DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval)); /* no wrapping */ - - tv_dst = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count); /* XXX: uninitialized would be OK */ - DUK_ASSERT(count == 0 || tv_dst != NULL); - - /* Copy value stack values directly to the array part without - * any refcount updates: net refcount changes are zero. - */ - - tv_src = thr->valstack_top - count - 1; - DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval)); - - /* Overwrite result array to final value stack location and wipe - * the rest; no refcount operations needed. - */ - - tv_dst = tv_src; /* when count == 0, same as tv_src (OK) */ - tv_src = thr->valstack_top - 1; - DUK_TVAL_SET_TVAL(tv_dst, tv_src); - - /* XXX: internal helper to wipe a value stack segment? */ - tv_curr = tv_dst + 1; - tv_limit = thr->valstack_top; - while (tv_curr != tv_limit) { - /* Wipe policy: keep as 'undefined'. */ - DUK_TVAL_SET_UNDEFINED(tv_curr); - tv_curr++; - } - thr->valstack_top = tv_dst + 1; -} - -DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - - tv = duk_require_tval(thr, idx); - if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv))) { - duk_hobject *h; - duk_uint32_t len; - duk_uint32_t i; - - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - DUK_UNREF(h); - -#if defined(DUK_USE_ARRAY_FASTPATH) /* close enough */ - if (DUK_LIKELY(DUK_HOBJECT_IS_ARRAY(h) && - ((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h))) { - duk_harray *h_arr; - duk_tval *tv_src; - duk_tval *tv_dst; - - h_arr = (duk_harray *) h; - len = h_arr->length; - if (DUK_UNLIKELY(len >= 0x80000000UL)) { - goto fail_over_2g; - } - duk_require_stack(thr, (duk_idx_t) len); - - /* The potential allocation in duk_require_stack() may - * run a finalizer which modifies the argArray so that - * e.g. becomes sparse. So, we need to recheck that the - * array didn't change size and that there's still a - * valid backing array part. - * - * XXX: alternatively, could prevent finalizers for the - * duration. - */ - if (DUK_UNLIKELY(len != h_arr->length || - h_arr->length > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr))) { - goto skip_fast; - } - - /* Main fast path: arguments array is almost always - * an actual array (though it might also be an arguments - * object). - */ - - DUK_DDD(DUK_DDDPRINT("fast path for %ld elements", (long) h_arr->length)); - tv_src = DUK_HOBJECT_A_GET_BASE(thr->heap, h); - tv_dst = thr->valstack_top; - while (len-- > 0) { - DUK_ASSERT(tv_dst < thr->valstack_end); - if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_src))) { - /* Gaps are very unlikely. Skip over them, - * without an ancestor lookup (technically - * not compliant). - */ - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_dst)); /* valstack policy */ - } else { - DUK_TVAL_SET_TVAL(tv_dst, tv_src); - DUK_TVAL_INCREF(thr, tv_dst); - } - tv_src++; - tv_dst++; - } - DUK_ASSERT(tv_dst <= thr->valstack_end); - thr->valstack_top = tv_dst; - return (duk_idx_t) h_arr->length; - } - skip_fast: -#endif /* DUK_USE_ARRAY_FASTPATH */ - - /* Slow path: actual lookups. The initial 'length' lookup - * decides the output length, regardless of side effects that - * may resize or change the argArray while we read the - * indices. - */ - idx = duk_normalize_index(thr, idx); - duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH); - len = duk_to_uint32(thr, -1); /* ToUint32() coercion required */ - if (DUK_UNLIKELY(len >= 0x80000000UL)) { - goto fail_over_2g; - } - duk_pop_unsafe(thr); - DUK_DDD(DUK_DDDPRINT("slow path for %ld elements", (long) len)); - - duk_require_stack(thr, (duk_idx_t) len); - for (i = 0; i < len; i++) { - duk_get_prop_index(thr, idx, (duk_uarridx_t) i); - } - return (duk_idx_t) len; - } else if (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv)) { - return 0; - } - - DUK_ERROR_TYPE_INVALID_ARGS(thr); - return 0; - - fail_over_2g: - DUK_ERROR_RANGE_INVALID_LENGTH(thr); - return 0; -} - -/* - * Error throwing - */ - -DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) { - duk_tval *tv_val; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr->valstack_bottom >= thr->valstack); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - - if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - } - - /* Errors are augmented when they are created, not when they are - * thrown or re-thrown. The current error handler, however, runs - * just before an error is thrown. - */ - - /* Sync so that augmentation sees up-to-date activations, NULL - * thr->ptr_curr_pc so that it's not used if side effects occur - * in augmentation or longjmp handling. - */ - duk_hthread_sync_and_null_currpc(thr); - -#if defined(DUK_USE_AUGMENT_ERROR_THROW) - DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(thr, -1))); - duk_err_augment_error_throw(thr); -#endif - DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(thr, -1))); - - tv_val = DUK_GET_TVAL_NEGIDX(thr, -1); - duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_err_check_debugger_integration(thr); -#endif - - /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't - * need to check that here. If the value is NULL, a fatal error occurs - * because we can't return. - */ - - duk_err_longjmp(thr); - DUK_UNREACHABLE(); -} - -DUK_EXTERNAL void duk_fatal_raw(duk_hthread *thr, const char *err_msg) { - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(thr->heap->fatal_func != NULL); - - DUK_D(DUK_DPRINT("fatal error occurred: %s", err_msg ? err_msg : "NULL")); - - /* fatal_func should be noreturn, but noreturn declarations on function - * pointers has a very spotty support apparently so it's not currently - * done. - */ - thr->heap->fatal_func(thr->heap->heap_udata, err_msg); - - /* If the fatal handler returns, all bets are off. It'd be nice to - * print something here but since we don't want to depend on stdio, - * there's no way to do so portably. - */ - DUK_D(DUK_DPRINT("fatal error handler returned, all bets are off!")); - for (;;) { - /* loop forever, don't return (function marked noreturn) */ - } -} - -DUK_EXTERNAL void duk_error_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) { - DUK_ASSERT_API_ENTRY(thr); - - duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); - (void) duk_throw(thr); -} - -DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { - va_list ap; - - DUK_ASSERT_API_ENTRY(thr); - - va_start(ap, fmt); - duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); - va_end(ap); - (void) duk_throw(thr); -} - -#if !defined(DUK_USE_VARIADIC_MACROS) -DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap)); - -DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap) { - const char *filename; - duk_int_t line; - - DUK_ASSERT_CTX_VALID(thr); - - filename = duk_api_global_filename; - line = duk_api_global_line; - duk_api_global_filename = NULL; - duk_api_global_line = 0; - - duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); - (void) duk_throw(thr); -} - -#define DUK__ERROR_STASH_SHARED(code) do { \ - va_list ap; \ - va_start(ap, fmt); \ - duk__throw_error_from_stash(thr, (code), fmt, ap); \ - va_end(ap); \ - /* Never reached; if return 0 here, gcc/clang will complain. */ \ - } while (0) - -DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) { - DUK_ASSERT_API_ENTRY(thr); - DUK__ERROR_STASH_SHARED(err_code); -} -DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_hthread *thr, const char *fmt, ...) { - DUK_ASSERT_API_ENTRY(thr); - DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR); -} -DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_hthread *thr, const char *fmt, ...) { - DUK_ASSERT_API_ENTRY(thr); - DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR); -} -DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_hthread *thr, const char *fmt, ...) { - DUK_ASSERT_API_ENTRY(thr); - DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR); -} -DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_hthread *thr, const char *fmt, ...) { - DUK_ASSERT_API_ENTRY(thr); - DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR); -} -DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_hthread *thr, const char *fmt, ...) { - DUK_ASSERT_API_ENTRY(thr); - DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR); -} -DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_hthread *thr, const char *fmt, ...) { - DUK_ASSERT_API_ENTRY(thr); - DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR); -} -DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_hthread *thr, const char *fmt, ...) { - DUK_ASSERT_API_ENTRY(thr); - DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR); -} -#endif /* DUK_USE_VARIADIC_MACROS */ - -/* - * Comparison - */ - -DUK_EXTERNAL duk_bool_t duk_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { - duk_tval *tv1, *tv2; - - DUK_ASSERT_API_ENTRY(thr); - - tv1 = duk_get_tval(thr, idx1); - tv2 = duk_get_tval(thr, idx2); - if ((tv1 == NULL) || (tv2 == NULL)) { - return 0; - } - - /* Coercion may be needed, the helper handles that by pushing the - * tagged values to the stack. - */ - return duk_js_equals(thr, tv1, tv2); -} - -DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { - duk_tval *tv1, *tv2; - - DUK_ASSERT_API_ENTRY(thr); - - tv1 = duk_get_tval(thr, idx1); - tv2 = duk_get_tval(thr, idx2); - if ((tv1 == NULL) || (tv2 == NULL)) { - return 0; - } - - /* No coercions or other side effects, so safe */ - return duk_js_strict_equals(tv1, tv2); -} - -DUK_EXTERNAL duk_bool_t duk_samevalue(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { - duk_tval *tv1, *tv2; - - DUK_ASSERT_API_ENTRY(thr); - - tv1 = duk_get_tval(thr, idx1); - tv2 = duk_get_tval(thr, idx2); - if ((tv1 == NULL) || (tv2 == NULL)) { - return 0; - } - - /* No coercions or other side effects, so safe */ - return duk_js_samevalue(tv1, tv2); -} - -/* - * instanceof - */ - -DUK_EXTERNAL duk_bool_t duk_instanceof(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { - duk_tval *tv1, *tv2; - - DUK_ASSERT_API_ENTRY(thr); - - /* Index validation is strict, which differs from duk_equals(). - * The strict behavior mimics how instanceof itself works, e.g. - * it is a TypeError if rval is not a -callable- object. It would - * be somewhat inconsistent if rval would be allowed to be - * non-existent without a TypeError. - */ - tv1 = duk_require_tval(thr, idx1); - DUK_ASSERT(tv1 != NULL); - tv2 = duk_require_tval(thr, idx2); - DUK_ASSERT(tv2 != NULL); - - return duk_js_instanceof(thr, tv1, tv2); -} - -/* - * Lightfunc - */ - -DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) { - /* Lightfunc name, includes Duktape/C native function pointer, which - * can often be used to locate the function from a symbol table. - * The name also includes the 16-bit duk_tval flags field because it - * includes the magic value. Because a single native function often - * provides different functionality depending on the magic value, it - * seems reasonably to include it in the name. - * - * On the other hand, a complicated name increases string table - * pressure in low memory environments (but only when function name - * is accessed). - */ - - DUK_ASSERT_API_ENTRY(thr); - - duk_push_sprintf(thr, "light_"); - duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func)); - duk_push_sprintf(thr, "_%04x", (unsigned int) lf_flags); - duk_concat(thr, 3); -} - -DUK_INTERNAL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv) { - duk_c_function func; - duk_small_uint_t lf_flags; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); - - DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); - duk_push_lightfunc_name_raw(thr, func, lf_flags); -} - -DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) { - duk_c_function func; - duk_small_uint_t lf_flags; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); - - DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */ - duk_push_string(thr, "function "); - duk_push_lightfunc_name_raw(thr, func, lf_flags); - duk_push_string(thr, "() { [lightfunc code] }"); - duk_concat(thr, 3); -} - -/* - * Function pointers - * - * Printing function pointers is non-portable, so we do that by hex printing - * bytes from memory. - */ - -DUK_INTERNAL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz) { - duk_uint8_t buf[32 * 2]; - duk_uint8_t *p, *q; - duk_small_uint_t i; - duk_small_uint_t t; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */ - - p = buf; -#if defined(DUK_USE_INTEGER_LE) - q = ptr + sz; -#else - q = ptr; -#endif - for (i = 0; i < sz; i++) { -#if defined(DUK_USE_INTEGER_LE) - t = *(--q); -#else - t = *(q++); -#endif - *p++ = duk_lc_digits[t >> 4]; - *p++ = duk_lc_digits[t & 0x0f]; - } - - duk_push_lstring(thr, (const char *) buf, sz * 2); -} - -/* - * Push readable string summarizing duk_tval. The operation is side effect - * free and will only throw from internal errors (e.g. out of memory). - * This is used by e.g. property access code to summarize a key/base safely, - * and is not intended to be fast (but small and safe). - */ - -/* String limits for summary strings. */ -#define DUK__READABLE_SUMMARY_MAXCHARS 96 /* maximum supported by helper */ -#define DUK__READABLE_STRING_MAXCHARS 32 /* for strings/symbols */ -#define DUK__READABLE_ERRMSG_MAXCHARS 96 /* for error messages */ - -/* String sanitizer which escapes ASCII control characters and a few other - * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with - * question marks. No errors are thrown for any input string, except in out - * of memory situations. - */ -DUK_LOCAL void duk__push_hstring_readable_unicode(duk_hthread *thr, duk_hstring *h_input, duk_small_uint_t maxchars) { - const duk_uint8_t *p, *p_start, *p_end; - duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_SUMMARY_MAXCHARS + - 2 /*quotes*/ + 3 /*periods*/]; - duk_uint8_t *q; - duk_ucodepoint_t cp; - duk_small_uint_t nchars; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(h_input != NULL); - DUK_ASSERT(maxchars <= DUK__READABLE_SUMMARY_MAXCHARS); - - p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); - p = p_start; - q = buf; - - nchars = 0; - *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE; - for (;;) { - if (p >= p_end) { - break; - } - if (nchars == maxchars) { - *q++ = (duk_uint8_t) DUK_ASC_PERIOD; - *q++ = (duk_uint8_t) DUK_ASC_PERIOD; - *q++ = (duk_uint8_t) DUK_ASC_PERIOD; - break; - } - if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) { - if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) { - DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */ - DUK_ASSERT((cp >> 4) <= 0x0f); - *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH; - *q++ = (duk_uint8_t) DUK_ASC_LC_X; - *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4]; - *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f]; - } else { - q += duk_unicode_encode_xutf8(cp, q); - } - } else { - p++; /* advance manually */ - *q++ = (duk_uint8_t) DUK_ASC_QUESTION; - } - nchars++; - } - *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE; - - duk_push_lstring(thr, (const char *) buf, (duk_size_t) (q - buf)); -} - -DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval *tv, duk_bool_t error_aware) { - DUK_ASSERT_CTX_VALID(thr); - /* 'tv' may be NULL */ - - if (tv == NULL) { - duk_push_string(thr, "none"); - } else { - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_STRING: { - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - if (DUK_HSTRING_HAS_SYMBOL(h)) { - /* XXX: string summary produces question marks - * so this is not very ideal. - */ - duk_push_string(thr, "[Symbol "); - duk_push_string(thr, duk__get_symbol_type_string(h)); - duk_push_string(thr, " "); - duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS); - duk_push_string(thr, "]"); - duk_concat(thr, 5); - break; - } - duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS); - break; - } - case DUK_TAG_OBJECT: { - duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - - if (error_aware && - duk_hobject_prototype_chain_contains(thr, h, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) { - /* Get error message in a side effect free way if - * possible; if not, summarize as a generic object. - * Error message currently gets quoted. - */ - /* XXX: better internal getprop call; get without side effects - * but traverse inheritance chain. - */ - duk_tval *tv_msg; - tv_msg = duk_hobject_find_existing_entry_tval_ptr(thr->heap, h, DUK_HTHREAD_STRING_MESSAGE(thr)); - if (tv_msg != NULL && DUK_TVAL_IS_STRING(tv_msg)) { - /* It's critical to avoid recursion so - * only summarize a string .message. - */ - duk__push_hstring_readable_unicode(thr, DUK_TVAL_GET_STRING(tv_msg), DUK__READABLE_ERRMSG_MAXCHARS); - break; - } - } - duk_push_class_string_tval(thr, tv); - break; - } - case DUK_TAG_BUFFER: { - /* While plain buffers mimic Uint8Arrays, they summarize differently. - * This is useful so that the summarized string accurately reflects the - * internal type which may matter for figuring out bugs etc. - */ - /* XXX: Hex encoded, length limited buffer summary here? */ - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - duk_push_sprintf(thr, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h)); - break; - } - case DUK_TAG_POINTER: { - /* Surround with parentheses like in JX, ensures NULL pointer - * is distinguishable from null value ("(null)" vs "null"). - */ - duk_push_tval(thr, tv); - duk_push_sprintf(thr, "(%s)", duk_to_string(thr, -1)); - duk_remove_m2(thr); - break; - } - default: { - duk_push_tval(thr, tv); - break; - } - } - } - - return duk_to_string(thr, -1); -} -DUK_INTERNAL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv) { - DUK_ASSERT_API_ENTRY(thr); - return duk__push_string_tval_readable(thr, tv, 0 /*error_aware*/); -} - -DUK_INTERNAL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx) { - DUK_ASSERT_API_ENTRY(thr); - return duk_push_string_tval_readable(thr, duk_get_tval(thr, idx)); -} - -DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv) { - DUK_ASSERT_API_ENTRY(thr); - return duk__push_string_tval_readable(thr, tv, 1 /*error_aware*/); -} - -DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h) { - const duk_uint8_t *p; - const duk_uint8_t *p_end; - const duk_uint8_t *q; - - DUK_ASSERT_API_ENTRY(thr); - - /* .toString() */ - duk_push_string(thr, "Symbol("); - p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); - p_end = p + DUK_HSTRING_GET_BYTELEN(h); - DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80); - p++; - for (q = p; q < p_end; q++) { - if (*q == 0xffU) { - /* Terminate either at end-of-string (but NUL MUST - * be accepted without terminating description) or - * 0xFF, which is used to mark start of unique trailer - * (and cannot occur in CESU-8 / extended UTF-8). - */ - break; - } - } - duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p)); - duk_push_string(thr, ")"); - duk_concat(thr, 3); -} - -/* - * Functions - */ - -#if 0 /* not used yet */ -DUK_INTERNAL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h) { - duk_c_function func; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)); - - duk_push_sprintf(thr, "native_"); - func = h->func; - duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func)); - duk_push_sprintf(thr, "_%04x_%04x", - (unsigned int) (duk_uint16_t) h->nargs, - (unsigned int) (duk_uint16_t) h->magic); - duk_concat(thr, 3); -} -#endif - -/* - * duk_tval slice copy - */ - -DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count) { - duk_tval *tv; - - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(thr); - DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */ - DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval)); - - tv = tv_dst; - while (count-- > 0) { - DUK_TVAL_INCREF(thr, tv); - tv++; - } -} - -/* automatic undefs */ -#undef DUK__ASSERT_SPACE -#undef DUK__CHECK_SPACE -#undef DUK__ERROR_STASH_SHARED -#undef DUK__PACK_ARGS -#undef DUK__READABLE_ERRMSG_MAXCHARS -#undef DUK__READABLE_STRING_MAXCHARS -#undef DUK__READABLE_SUMMARY_MAXCHARS -#line 1 "duk_api_string.c" -/* - * String manipulation - */ - -/* #include duk_internal.h -> already included */ - -DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) { - duk_uint_t count; - duk_uint_t i; - duk_size_t idx; - duk_size_t len; - duk_hstring *h; - duk_uint8_t *buf; - - DUK_ASSERT_CTX_VALID(thr); - - if (DUK_UNLIKELY(count_in <= 0)) { - if (count_in < 0) { - DUK_ERROR_RANGE_INVALID_COUNT(thr); - return; - } - DUK_ASSERT(count_in == 0); - duk_push_hstring_empty(thr); - return; - } - count = (duk_uint_t) count_in; - - if (is_join) { - duk_size_t t1, t2, limit; - h = duk_to_hstring(thr, -((duk_idx_t) count) - 1); - DUK_ASSERT(h != NULL); - - /* A bit tricky overflow test, see doc/code-issues.rst. */ - t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); - t2 = (duk_size_t) (count - 1); - limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN; - if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) { - /* Combined size of separators already overflows. */ - goto error_overflow; - } - len = (duk_size_t) (t1 * t2); - } else { - len = (duk_size_t) 0; - } - - for (i = count; i >= 1; i--) { - duk_size_t new_len; - h = duk_to_hstring(thr, -((duk_idx_t) i)); - new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); - - /* Impose a string maximum length, need to handle overflow - * correctly. - */ - if (new_len < len || /* wrapped */ - new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) { - goto error_overflow; - } - len = new_len; - } - - DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes", - (unsigned long) count, (unsigned long) len)); - - /* Use stack allocated buffer to ensure reachability in errors - * (e.g. intern error). - */ - buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len); - DUK_ASSERT(buf != NULL); - - /* [ ... (sep) str1 str2 ... strN buf ] */ - - idx = 0; - for (i = count; i >= 1; i--) { - if (is_join && i != count) { - h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */ - DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); - idx += DUK_HSTRING_GET_BYTELEN(h); - } - h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */ - DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); - idx += DUK_HSTRING_GET_BYTELEN(h); - } - - DUK_ASSERT(idx == len); - - /* [ ... (sep) str1 str2 ... strN buf ] */ - - /* Get rid of the strings early to minimize memory use before intern. */ - - if (is_join) { - duk_replace(thr, -((duk_idx_t) count) - 2); /* overwrite sep */ - duk_pop_n(thr, (duk_idx_t) count); - } else { - duk_replace(thr, -((duk_idx_t) count) - 1); /* overwrite str1 */ - duk_pop_n(thr, (duk_idx_t) (count - 1)); - } - - /* [ ... buf ] */ - - (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */ - - /* [ ... res ] */ - return; - - error_overflow: - DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); -} - -DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) { - DUK_ASSERT_API_ENTRY(thr); - - duk__concat_and_join_helper(thr, count, 0 /*is_join*/); -} - -#if defined(DUK_USE_PREFER_SIZE) -DUK_INTERNAL void duk_concat_2(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - duk_concat(thr, 2); -} -#else /* DUK_USE_PREFER_SIZE */ -DUK_INTERNAL void duk_concat_2(duk_hthread *thr) { - duk_hstring *h1; - duk_hstring *h2; - duk_uint8_t *buf; - duk_size_t len1; - duk_size_t len2; - duk_size_t len; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(duk_get_top(thr) >= 2); /* Trusted caller. */ - - h1 = duk_to_hstring(thr, -2); - h2 = duk_to_hstring(thr, -1); - len1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1); - len2 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2); - len = len1 + len2; - if (DUK_UNLIKELY(len < len1 || /* wrapped */ - len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN)) { - goto error_overflow; - } - buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len); - DUK_ASSERT(buf != NULL); - - DUK_MEMCPY((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1); - DUK_MEMCPY((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2); - (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */ - - /* [ ... str1 str2 buf ] */ - - duk_replace(thr, -3); - duk_pop_unsafe(thr); - return; - - error_overflow: - DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); -} -#endif /* DUK_USE_PREFER_SIZE */ - -DUK_EXTERNAL void duk_join(duk_hthread *thr, duk_idx_t count) { - DUK_ASSERT_API_ENTRY(thr); - - duk__concat_and_join_helper(thr, count, 1 /*is_join*/); -} - -/* XXX: could map/decode be unified with duk_unicode_support.c code? - * Case conversion needs also the character surroundings though. - */ - -DUK_EXTERNAL void duk_decode_string(duk_hthread *thr, duk_idx_t idx, duk_decode_char_function callback, void *udata) { - duk_hstring *h_input; - const duk_uint8_t *p, *p_start, *p_end; - duk_codepoint_t cp; - - DUK_ASSERT_API_ENTRY(thr); - - h_input = duk_require_hstring(thr, idx); /* Accept symbols. */ - DUK_ASSERT(h_input != NULL); - - p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); - p = p_start; - - for (;;) { - if (p >= p_end) { - break; - } - cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); - callback(udata, cp); - } -} - -DUK_EXTERNAL void duk_map_string(duk_hthread *thr, duk_idx_t idx, duk_map_char_function callback, void *udata) { - duk_hstring *h_input; - duk_bufwriter_ctx bw_alloc; - duk_bufwriter_ctx *bw; - const duk_uint8_t *p, *p_start, *p_end; - duk_codepoint_t cp; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_normalize_index(thr, idx); - - h_input = duk_require_hstring(thr, idx); /* Accept symbols. */ - DUK_ASSERT(h_input != NULL); - - bw = &bw_alloc; - DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* Reasonable output estimate. */ - - p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); - p = p_start; - - for (;;) { - /* XXX: could write output in chunks with fewer ensure calls, - * but relative benefit would be small here. - */ - - if (p >= p_end) { - break; - } - cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); - cp = callback(udata, cp); - - DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp); - } - - DUK_BW_COMPACT(thr, bw); - (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 encoded. */ - duk_replace(thr, idx); -} - -DUK_EXTERNAL void duk_substring(duk_hthread *thr, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) { - duk_hstring *h; - duk_hstring *res; - duk_size_t start_byte_offset; - duk_size_t end_byte_offset; - duk_size_t charlen; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */ - h = duk_require_hstring(thr, idx); - DUK_ASSERT(h != NULL); - - charlen = DUK_HSTRING_GET_CHARLEN(h); - if (end_offset >= charlen) { - end_offset = charlen; - } - if (start_offset > end_offset) { - start_offset = end_offset; - } - - DUK_ASSERT_DISABLE(start_offset >= 0); - DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h)); - DUK_ASSERT_DISABLE(end_offset >= 0); - DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h)); - - /* Guaranteed by string limits. */ - DUK_ASSERT(start_offset <= DUK_UINT32_MAX); - DUK_ASSERT(end_offset <= DUK_UINT32_MAX); - - start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset); - end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset); - - DUK_ASSERT(end_byte_offset >= start_byte_offset); - DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */ - - /* No size check is necessary. */ - res = duk_heap_strtable_intern_checked(thr, - DUK_HSTRING_GET_DATA(h) + start_byte_offset, - (duk_uint32_t) (end_byte_offset - start_byte_offset)); - - duk_push_hstring(thr, res); - duk_replace(thr, idx); -} - -/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and - * forwards with a callback to process codepoints? - */ -DUK_EXTERNAL void duk_trim(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */ - const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */ - duk_codepoint_t cp; - - DUK_ASSERT_API_ENTRY(thr); - - idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */ - h = duk_require_hstring(thr, idx); - DUK_ASSERT(h != NULL); - - p_start = DUK_HSTRING_GET_DATA(h); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h); - - p = p_start; - while (p < p_end) { - p_tmp1 = p; - cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end); - if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) { - break; - } - p = p_tmp1; - } - q_start = p; - if (p == p_end) { - /* Entire string is whitespace. */ - q_end = p; - goto scan_done; - } - - p = p_end; - while (p > p_start) { - p_tmp1 = p; - while (p > p_start) { - p--; - if (((*p) & 0xc0) != 0x80) { - break; - } - } - p_tmp2 = p; - - cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end); - if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) { - p = p_tmp1; - break; - } - } - q_end = p; - - scan_done: - /* This may happen when forward and backward scanning disagree - * (possible for non-extended-UTF-8 strings). - */ - if (q_end < q_start) { - q_end = q_start; - } - - DUK_ASSERT(q_start >= p_start && q_start <= p_end); - DUK_ASSERT(q_end >= p_start && q_end <= p_end); - DUK_ASSERT(q_end >= q_start); - - DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p", - (const void *) p_start, (const void *) p_end, - (const void *) q_start, (const void *) q_end)); - - if (q_start == p_start && q_end == p_end) { - DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)")); - return; - } - - duk_push_lstring(thr, (const char *) q_start, (duk_size_t) (q_end - q_start)); - duk_replace(thr, idx); -} - -DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, duk_size_t char_offset) { - duk_hstring *h; - duk_ucodepoint_t cp; - - DUK_ASSERT_API_ENTRY(thr); - - /* XXX: Share code with String.prototype.charCodeAt? Main difference - * is handling of clamped offsets. - */ - - h = duk_require_hstring(thr, idx); /* Accept symbols. */ - DUK_ASSERT(h != NULL); - - DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */ - if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) { - return 0; - } - - DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* Guaranteed by string limits. */ - cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/); - return (duk_codepoint_t) cp; -} -#line 1 "duk_api_time.c" -/* - * Date/time. - */ - -/* #include duk_internal.h -> already included */ - -DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) { - /* Ecmascript time, with millisecond fractions. Exposed via - * duk_get_now() for example. - */ - DUK_UNREF(thr); - return (duk_double_t) DUK_USE_DATE_GET_NOW(thr); -} - -DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) { - /* Ecmascript time without millisecond fractions. Exposed via - * the Date built-in which doesn't allow fractions. - */ - DUK_UNREF(thr); - return (duk_double_t) DUK_FLOOR(DUK_USE_DATE_GET_NOW(thr)); -} - -DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) { - DUK_UNREF(thr); -#if defined(DUK_USE_GET_MONOTONIC_TIME) - return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr); -#else - return (duk_double_t) DUK_USE_DATE_GET_NOW(thr); -#endif -} - -DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(thr); - - /* This API intentionally allows millisecond fractions. */ - return duk_time_get_ecmascript_time(thr); -} - -#if 0 /* XXX: worth exposing? */ -DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) { - DUK_ASSERT_API_ENTRY(thr); - DUK_UNREF(thr); - - return duk_time_get_monotonic_time(thr); -} -#endif - -DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) { - duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; - duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; - duk_uint_t flags; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(comp != NULL); /* XXX: or check? */ - DUK_UNREF(thr); - - /* Convert as one-based, but change month to zero-based to match the - * Ecmascript Date built-in behavior 1:1. - */ - flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO; - - duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags); - - /* XXX: sub-millisecond accuracy for the API */ - - DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0); - comp->year = dparts[DUK_DATE_IDX_YEAR]; - comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0; - comp->day = dparts[DUK_DATE_IDX_DAY]; - comp->hours = dparts[DUK_DATE_IDX_HOUR]; - comp->minutes = dparts[DUK_DATE_IDX_MINUTE]; - comp->seconds = dparts[DUK_DATE_IDX_SECOND]; - comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND]; - comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY]; -} - -DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_components *comp) { - duk_double_t d; - duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; - duk_uint_t flags; - - DUK_ASSERT_API_ENTRY(thr); - DUK_ASSERT(comp != NULL); /* XXX: or check? */ - DUK_UNREF(thr); - - /* Match Date constructor behavior (with UTC time). Month is given - * as zero-based. Day-of-month is given as one-based so normalize - * it to zero-based as the internal conversion helpers expects all - * components to be zero-based. - */ - flags = 0; - - /* XXX: expensive conversion; use array format in API instead, or unify - * time provider and time API to use same struct? - */ - - dparts[DUK_DATE_IDX_YEAR] = comp->year; - dparts[DUK_DATE_IDX_MONTH] = comp->month; - dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0; - dparts[DUK_DATE_IDX_HOUR] = comp->hours; - dparts[DUK_DATE_IDX_MINUTE] = comp->minutes; - dparts[DUK_DATE_IDX_SECOND] = comp->seconds; - dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds; - dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */ - - d = duk_bi_date_get_timeval_from_dparts(dparts, flags); - - return d; -} -#line 1 "duk_bi_array.c" -/* - * Array built-ins - * - * Most Array built-ins are intentionally generic in Ecmascript, and are - * intended to work even when the 'this' binding is not an Array instance. - * This Ecmascript feature is also used by much real world code. For this - * reason the implementations here don't assume exotic Array behavior or - * e.g. presence of a .length property. However, some algorithms have a - * fast path for duk_harray backed actual Array instances, enabled when - * footprint is not a concern. - * - * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and - * [[Delete]] operations, but it's currently false throughout. Go through - * all put/delete cases and check throw flag use. Need a new API primitive - * which allows throws flag to be specified. - * - * XXX: array lengths above 2G won't work reliably. There are many places - * where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff], - * i.e. -33- bits). Although array 'length' cannot be written to be outside - * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so) - * some intermediate values may be above 0xffffffff and this may not be always - * correctly handled now (duk_uint32_t is not enough for all algorithms). - * For instance, push() can legitimately write entries beyond length 0xffffffff - * and cause a RangeError only at the end. To do this properly, the current - * push() implementation tracks the array index using a 'double' instead of a - * duk_uint32_t (which is somewhat awkward). See test-bi-array-push-maxlen.js. - * - * On using "put" vs. "def" prop - * ============================= - * - * Code below must be careful to use the appropriate primitive as it matters - * for compliance. When using "put" there may be inherited properties in - * Array.prototype which cause side effects when values are written. When - * using "define" there are no such side effects, and many test262 test cases - * check for this (for real world code, such side effects are very rare). - * Both "put" and "define" are used in the E5.1 specification; as a rule, - * "put" is used when modifying an existing array (or a non-array 'this' - * binding) and "define" for setting values into a fresh result array. - */ - -/* #include duk_internal.h -> already included */ - -/* Perform an intermediate join when this many elements have been pushed - * on the value stack. - */ -#define DUK__ARRAY_MID_JOIN_LIMIT 4096 - -#if defined(DUK_USE_ARRAY_BUILTIN) - -/* - * Shared helpers. - */ - -/* Shared entry code for many Array built-ins: the 'this' binding is pushed - * on the value stack and object coerced, and the current .length is returned. - * Note that length is left on stack (it could be popped, but that's not - * usually necessary because call handling will clean it up automatically). - */ -DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_hthread *thr) { - duk_uint32_t len; - - /* XXX: push more directly? */ - (void) duk_push_this_coercible_to_object(thr); - DUK_ASSERT_HOBJECT_VALID(duk_get_hobject(thr, -1)); - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_LENGTH); - len = duk_to_uint32(thr, -1); - - /* -> [ ... ToObject(this) ToUint32(length) ] */ - return len; -} - -DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) { - /* Range limited to [0, 0x7fffffff] range, i.e. range that can be - * represented with duk_int32_t. Use this when the method doesn't - * handle the full 32-bit unsigned range correctly. - */ - duk_uint32_t ret = duk__push_this_obj_len_u32(thr); - if (DUK_UNLIKELY(ret >= 0x80000000UL)) { - DUK_ERROR_RANGE_INVALID_LENGTH(thr); - } - return ret; -} - -#if defined(DUK_USE_ARRAY_FASTPATH) -/* Check if 'this' binding is an Array instance (duk_harray) which satisfies - * a few other guarantees for fast path operation. The fast path doesn't - * need to handle all operations, even for duk_harrays, but must handle a - * significant fraction to improve performance. Return a non-NULL duk_harray - * pointer when all fast path criteria are met, NULL otherwise. - */ -DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_hthread *thr) { - duk_tval *tv; - duk_hobject *h; - duk_uint_t flags_mask, flags_bits, flags_value; - - DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* because call in progress */ - tv = DUK_GET_THIS_TVAL_PTR(thr); - - /* Fast path requires that 'this' is a duk_harray. Read only arrays - * (ROM backed) are also rejected for simplicity. - */ - if (!DUK_TVAL_IS_OBJECT(tv)) { - DUK_DD(DUK_DDPRINT("reject array fast path: not an object")); - return NULL; - } - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - flags_mask = DUK_HOBJECT_FLAG_ARRAY_PART | \ - DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ - DUK_HEAPHDR_FLAG_READONLY; - flags_bits = DUK_HOBJECT_FLAG_ARRAY_PART | \ - DUK_HOBJECT_FLAG_EXOTIC_ARRAY; - flags_value = DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) h); - if ((flags_value & flags_mask) != flags_bits) { - DUK_DD(DUK_DDPRINT("reject array fast path: object flag check failed")); - return NULL; - } - - /* In some cases a duk_harray's 'length' may be larger than the - * current array part allocation. Avoid the fast path in these - * cases, so that all fast path code can safely assume that all - * items in the range [0,length[ are backed by the current array - * part allocation. - */ - if (((duk_harray *) h)->length > DUK_HOBJECT_GET_ASIZE(h)) { - DUK_DD(DUK_DDPRINT("reject array fast path: length > array part size")); - return NULL; - } - - /* Guarantees for fast path. */ - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, h) != NULL); - DUK_ASSERT(((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h)); - - DUK_DD(DUK_DDPRINT("array fast path allowed for: %!O", (duk_heaphdr *) h)); - return (duk_harray *) h; -} -#endif /* DUK_USE_ARRAY_FASTPATH */ - -/* - * Constructor - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_hthread *thr) { - duk_idx_t nargs; - duk_harray *a; - duk_double_t d; - duk_uint32_t len; - duk_uint32_t len_prealloc; - - nargs = duk_get_top(thr); - - if (nargs == 1 && duk_is_number(thr, 0)) { - /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */ - d = duk_get_number(thr, 0); - len = duk_to_uint32(thr, 0); - if (((duk_double_t) len) != d) { - DUK_DCERROR_RANGE_INVALID_LENGTH(thr); - } - - /* For small lengths create a dense preallocated array. - * For large arrays preallocate an initial part. - */ - len_prealloc = len < 64 ? len : 64; - a = duk_push_harray_with_size(thr, len_prealloc); - DUK_ASSERT(a != NULL); - a->length = len; - return 1; - } - - duk_pack(thr, nargs); - return 1; -} - -/* - * isArray() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_hthread *thr) { - duk_hobject *h; - - h = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_ARRAY); - duk_push_boolean(thr, (h != NULL)); - return 1; -} - -/* - * toString() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) { - (void) duk_push_this_coercible_to_object(thr); - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_JOIN); - - /* [ ... this func ] */ - if (!duk_is_callable(thr, -1)) { - /* Fall back to the initial (original) Object.toString(). We don't - * currently have pointers to the built-in functions, only the top - * level global objects (like "Array") so this is now done in a bit - * of a hacky manner. It would be cleaner to push the (original) - * function and use duk_call_method(). - */ - - /* XXX: 'this' will be ToObject() coerced twice, which is incorrect - * but should have no visible side effects. - */ - DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString")); - duk_set_top(thr, 0); - return duk_bi_object_prototype_to_string(thr); /* has access to 'this' binding */ - } - - /* [ ... this func ] */ - - duk_insert(thr, -2); - - /* [ ... func this ] */ - - DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - duk_call_method(thr, 0); - - return 1; -} - -/* - * concat() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) { - duk_idx_t i, n; - duk_uarridx_t idx, idx_last; - duk_uarridx_t j, len; - duk_hobject *h; - - /* XXX: the insert here is a bit expensive if there are a lot of items. - * It could also be special cased in the outermost for loop quite easily - * (as the element is dup()'d anyway). - */ - - (void) duk_push_this_coercible_to_object(thr); - duk_insert(thr, 0); - n = duk_get_top(thr); - duk_push_array(thr); /* -> [ ToObject(this) item1 ... itemN arr ] */ - - /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index() - * (which differs from the official algorithm). If no error is thrown, this - * doesn't matter as the length is updated at the end. However, if an error - * is thrown, the length will be unset. That shouldn't matter because the - * caller won't get a reference to the intermediate value. - */ - - idx = 0; - idx_last = 0; - for (i = 0; i < n; i++) { - DUK_ASSERT_TOP(thr, n + 1); - - /* [ ToObject(this) item1 ... itemN arr ] */ - - duk_dup(thr, i); - h = duk_get_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_ARRAY); - if (!h) { - duk_xdef_prop_index_wec(thr, -2, idx++); - idx_last = idx; - continue; - } - - /* [ ToObject(this) item1 ... itemN arr item(i) ] */ - - /* XXX: an array can have length higher than 32 bits; this is not handled - * correctly now. - */ - len = (duk_uarridx_t) duk_get_length(thr, -1); - for (j = 0; j < len; j++) { - if (duk_get_prop_index(thr, -1, j)) { - /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */ - duk_xdef_prop_index_wec(thr, -3, idx++); - idx_last = idx; - } else { - idx++; - duk_pop_undefined(thr); -#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER) - /* According to E5.1 Section 15.4.4.4 nonexistent trailing - * elements do not affect 'length' of the result. Test262 - * and other engines disagree, so update idx_last here too. - */ - idx_last = idx; -#else - /* Strict standard behavior, ignore trailing elements for - * result 'length'. - */ -#endif - } - } - duk_pop_unsafe(thr); - } - - /* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly - * in the end, but because we're operating with an internal value which - * is known to be an array, this should be equivalent. - */ - duk_push_uarridx(thr, idx_last); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); - - DUK_ASSERT_TOP(thr, n + 1); - return 1; -} - -/* - * join(), toLocaleString() - * - * Note: checking valstack is necessary, but only in the per-element loop. - * - * Note: the trivial approach of pushing all the elements on the value stack - * and then calling duk_join() fails when the array contains a large number - * of elements. This problem can't be offloaded to duk_join() because the - * elements to join must be handled here and have special handling. Current - * approach is to do intermediate joins with very large number of elements. - * There is no fancy handling; the prefix gets re-joined multiple times. - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_hthread *thr) { - duk_uint32_t len, count; - duk_uint32_t idx; - duk_small_int_t to_locale_string = duk_get_current_magic(thr); - duk_idx_t valstack_required; - - /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and - * setting the top essentially pushes an undefined to the stack, - * thus defaulting to a comma separator. - */ - duk_set_top(thr, 1); - if (duk_is_undefined(thr, 0)) { - duk_pop_undefined(thr); - duk_push_hstring_stridx(thr, DUK_STRIDX_COMMA); - } else { - duk_to_string(thr, 0); - } - - len = duk__push_this_obj_len_u32(thr); - - /* [ sep ToObject(this) len ] */ - - DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu", - (duk_tval *) duk_get_tval(thr, 0), - (duk_tval *) duk_get_tval(thr, 1), - (unsigned long) len)); - - /* The extra (+4) is tight. */ - valstack_required = (duk_idx_t) ((len >= DUK__ARRAY_MID_JOIN_LIMIT ? - DUK__ARRAY_MID_JOIN_LIMIT : len) + 4); - duk_require_stack(thr, valstack_required); - - duk_dup_0(thr); - - /* [ sep ToObject(this) len sep ] */ - - count = 0; - idx = 0; - for (;;) { - DUK_DDD(DUK_DDDPRINT("join idx=%ld", (long) idx)); - if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */ - idx >= len) { /* end of loop (careful with len==0) */ - /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */ - DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld", - (long) count, (long) idx, (long) len)); - duk_join(thr, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */ - duk_dup_0(thr); /* -> [ sep ToObject(this) len str sep ] */ - duk_insert(thr, -2); /* -> [ sep ToObject(this) len sep str ] */ - count = 1; - } - if (idx >= len) { - /* if true, the stack already contains the final result */ - break; - } - - duk_get_prop_index(thr, 1, (duk_uarridx_t) idx); - if (duk_is_null_or_undefined(thr, -1)) { - duk_pop_nodecref_unsafe(thr); - duk_push_hstring_empty(thr); - } else { - if (to_locale_string) { - duk_to_object(thr, -1); - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_LOCALE_STRING); - duk_insert(thr, -2); /* -> [ ... toLocaleString ToObject(val) ] */ - duk_call_method(thr, 0); - } - duk_to_string(thr, -1); - } - - count++; - idx++; - } - - /* [ sep ToObject(this) len sep result ] */ - - return 1; -} - -/* - * pop(), push() - */ - -#if defined(DUK_USE_ARRAY_FASTPATH) -DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_hthread *thr, duk_harray *h_arr) { - duk_tval *tv_arraypart; - duk_tval *tv_val; - duk_uint32_t len; - - tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr); - len = h_arr->length; - if (len <= 0) { - /* nop, return undefined */ - return 0; - } - - len--; - h_arr->length = len; - - /* Fast path doesn't check for an index property inherited from - * Array.prototype. This is quite often acceptable; if not, - * disable fast path. - */ - DUK_ASSERT_VS_SPACE(thr); - tv_val = tv_arraypart + len; - if (DUK_TVAL_IS_UNUSED(tv_val)) { - /* No net refcount change. Value stack already has - * 'undefined' based on value stack init policy. - */ - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); - DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv_val)); - } else { - /* No net refcount change. */ - DUK_TVAL_SET_TVAL(thr->valstack_top, tv_val); - DUK_TVAL_SET_UNUSED(tv_val); - } - thr->valstack_top++; - - /* XXX: there's no shrink check in the fast path now */ - - return 1; -} -#endif /* DUK_USE_ARRAY_FASTPATH */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_hthread *thr) { - duk_uint32_t len; - duk_uint32_t idx; -#if defined(DUK_USE_ARRAY_FASTPATH) - duk_harray *h_arr; -#endif - - DUK_ASSERT_TOP(thr, 0); - -#if defined(DUK_USE_ARRAY_FASTPATH) - h_arr = duk__arraypart_fastpath_this(thr); - if (h_arr) { - return duk__array_pop_fastpath(thr, h_arr); - } -#endif - - /* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */ - - len = duk__push_this_obj_len_u32(thr); - if (len == 0) { - duk_push_int(thr, 0); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); - return 0; - } - idx = len - 1; - - duk_get_prop_index(thr, 0, (duk_uarridx_t) idx); - duk_del_prop_index(thr, 0, (duk_uarridx_t) idx); - duk_push_u32(thr, idx); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); - return 1; -} - -#if defined(DUK_USE_ARRAY_FASTPATH) -DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_hthread *thr, duk_harray *h_arr) { - duk_tval *tv_arraypart; - duk_tval *tv_src; - duk_tval *tv_dst; - duk_uint32_t len; - duk_idx_t i, n; - - len = h_arr->length; - tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr); - - n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - DUK_ASSERT(n >= 0); - DUK_ASSERT((duk_uint32_t) n <= DUK_UINT32_MAX); - if (DUK_UNLIKELY(len + (duk_uint32_t) n < len)) { - DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw")); - DUK_DCERROR_RANGE_INVALID_LENGTH(thr); /* != 0 return value returned as is by caller */ - } - if (len + (duk_uint32_t) n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) { - /* Array part would need to be extended. Rely on slow path - * for now. - * - * XXX: Rework hobject code a bit and add extend support. - */ - return 0; - } - - tv_src = thr->valstack_bottom; - tv_dst = tv_arraypart + len; - for (i = 0; i < n; i++) { - /* No net refcount change; reset value stack values to - * undefined to satisfy value stack init policy. - */ - DUK_TVAL_SET_TVAL(tv_dst, tv_src); - DUK_TVAL_SET_UNDEFINED(tv_src); - tv_src++; - tv_dst++; - } - thr->valstack_top = thr->valstack_bottom; - len += (duk_uint32_t) n; - h_arr->length = len; - - DUK_ASSERT((duk_uint_t) len == len); - duk_push_uint(thr, (duk_uint_t) len); - return 1; -} -#endif /* DUK_USE_ARRAY_FASTPATH */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_hthread *thr) { - /* Note: 'this' is not necessarily an Array object. The push() - * algorithm is supposed to work for other kinds of objects too, - * so the algorithm has e.g. an explicit update for the 'length' - * property which is normally "magical" in arrays. - */ - - duk_uint32_t len; - duk_idx_t i, n; -#if defined(DUK_USE_ARRAY_FASTPATH) - duk_harray *h_arr; -#endif - -#if defined(DUK_USE_ARRAY_FASTPATH) - h_arr = duk__arraypart_fastpath_this(thr); - if (h_arr) { - duk_ret_t rc; - rc = duk__array_push_fastpath(thr, h_arr); - if (rc != 0) { - return rc; - } - DUK_DD(DUK_DDPRINT("array push() fast path exited, resize case")); - } -#endif - - n = duk_get_top(thr); - len = duk__push_this_obj_len_u32(thr); - - /* [ arg1 ... argN obj length ] */ - - /* Technically Array.prototype.push() can create an Array with length - * longer than 2^32-1, i.e. outside the 32-bit range. The final length - * is *not* wrapped to 32 bits in the specification. - * - * This implementation tracks length with a uint32 because it's much - * more practical. - * - * See: test-bi-array-push-maxlen.js. - */ - - if (len + (duk_uint32_t) n < len) { - DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw")); - DUK_DCERROR_RANGE_INVALID_LENGTH(thr); - } - - for (i = 0; i < n; i++) { - duk_dup(thr, i); - duk_put_prop_index(thr, -3, (duk_uarridx_t) (len + (duk_uint32_t) i)); - } - len += (duk_uint32_t) n; - - duk_push_u32(thr, len); - duk_dup_top(thr); - duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH); - - /* [ arg1 ... argN obj length new_length ] */ - return 1; -} - -/* - * sort() - * - * Currently qsort with random pivot. This is now really, really slow, - * because there is no fast path for array parts. - * - * Signed indices are used because qsort() leaves and degenerate cases - * may use a negative offset. - */ - -DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_hthread *thr, duk_int_t idx1, duk_int_t idx2) { - duk_bool_t have1, have2; - duk_bool_t undef1, undef2; - duk_small_int_t ret; - duk_idx_t idx_obj = 1; /* fixed offsets in valstack */ - duk_idx_t idx_fn = 0; - duk_hstring *h1, *h2; - - /* Fast exit if indices are identical. This is valid for a non-existent property, - * for an undefined value, and almost always for ToString() coerced comparison of - * arbitrary values (corner cases where this is not the case include e.g. a an - * object with varying ToString() coercion). - * - * The specification does not prohibit "caching" of values read from the array, so - * assuming equality for comparing an index with itself falls into the category of - * "caching". - * - * Also, compareFn may be inconsistent, so skipping a call to compareFn here may - * have an effect on the final result. The specification does not require any - * specific behavior for inconsistent compare functions, so again, this fast path - * is OK. - */ - - if (idx1 == idx2) { - DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit", - (long) idx1, (long) idx2)); - return 0; - } - - have1 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx1); - have2 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx2); - - DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T", - (long) idx1, (long) idx2, (long) have1, (long) have2, - (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1))); - - if (have1) { - if (have2) { - ; - } else { - ret = -1; - goto pop_ret; - } - } else { - if (have2) { - ret = 1; - goto pop_ret; - } else { - ret = 0; - goto pop_ret; - } - } - - undef1 = duk_is_undefined(thr, -2); - undef2 = duk_is_undefined(thr, -1); - if (undef1) { - if (undef2) { - ret = 0; - goto pop_ret; - } else { - ret = 1; - goto pop_ret; - } - } else { - if (undef2) { - ret = -1; - goto pop_ret; - } else { - ; - } - } - - if (!duk_is_undefined(thr, idx_fn)) { - duk_double_t d; - - /* No need to check callable; duk_call() will do that. */ - duk_dup(thr, idx_fn); /* -> [ ... x y fn ] */ - duk_insert(thr, -3); /* -> [ ... fn x y ] */ - duk_call(thr, 2); /* -> [ ... res ] */ - - /* ES5 is a bit vague about what to do if the return value is - * not a number. ES2015 provides a concrete description: - * http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare. - */ - - d = duk_to_number_m1(thr); - if (d < 0.0) { - ret = -1; - } else if (d > 0.0) { - ret = 1; - } else { - /* Because NaN compares to false, NaN is handled here - * without an explicit check above. - */ - ret = 0; - } - - duk_pop_nodecref_unsafe(thr); - DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret)); - return ret; - } - - /* string compare is the default (a bit oddly) */ - - /* XXX: any special handling for plain array; causes repeated coercion now? */ - h1 = duk_to_hstring(thr, -2); - h2 = duk_to_hstring_m1(thr); - DUK_ASSERT(h1 != NULL); - DUK_ASSERT(h2 != NULL); - - ret = duk_js_string_compare(h1, h2); /* retval is directly usable */ - goto pop_ret; - - pop_ret: - duk_pop_2_unsafe(thr); - DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret)); - return ret; -} - -DUK_LOCAL void duk__array_sort_swap(duk_hthread *thr, duk_int_t l, duk_int_t r) { - duk_bool_t have_l, have_r; - duk_idx_t idx_obj = 1; /* fixed offset in valstack */ - - if (l == r) { - return; - } - - /* swap elements; deal with non-existent elements correctly */ - have_l = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) l); - have_r = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) r); - - if (have_r) { - /* right exists, [[Put]] regardless whether or not left exists */ - duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) l); - } else { - duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) l); - duk_pop_undefined(thr); - } - - if (have_l) { - duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) r); - } else { - duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) r); - duk_pop_undefined(thr); - } -} - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) -/* Debug print which visualizes the qsort partitioning process. */ -DUK_LOCAL void duk__debuglog_qsort_state(duk_hthread *thr, duk_int_t lo, duk_int_t hi, duk_int_t pivot) { - char buf[4096]; - char *ptr = buf; - duk_int_t i, n; - n = (duk_int_t) duk_get_length(thr, 1); - if (n > 4000) { - n = 4000; - } - *ptr++ = '['; - for (i = 0; i < n; i++) { - if (i == pivot) { - *ptr++ = '|'; - } else if (i == lo) { - *ptr++ = '<'; - } else if (i == hi) { - *ptr++ = '>'; - } else if (i >= lo && i <= hi) { - *ptr++ = '-'; - } else { - *ptr++ = ' '; - } - } - *ptr++ = ']'; - *ptr++ = '\0'; - - DUK_DDD(DUK_DDDPRINT("%s (lo=%ld, hi=%ld, pivot=%ld)", - (const char *) buf, (long) lo, (long) hi, (long) pivot)); -} -#endif - -DUK_LOCAL void duk__array_qsort(duk_hthread *thr, duk_int_t lo, duk_int_t hi) { - duk_int_t p, l, r; - - /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */ - - DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T", - (long) lo, (long) hi, (duk_tval *) duk_get_tval(thr, 1))); - - DUK_ASSERT_TOP(thr, 3); - - /* In some cases it may be that lo > hi, or hi < 0; these - * degenerate cases happen e.g. for empty arrays, and in - * recursion leaves. - */ - - /* trivial cases */ - if (hi - lo < 1) { - DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately")); - return; - } - DUK_ASSERT(hi > lo); - DUK_ASSERT(hi - lo + 1 >= 2); - - /* randomized pivot selection */ - p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE(thr) * (duk_double_t) (hi - lo + 1)); - DUK_ASSERT(p >= lo && p <= hi); - DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p)); - - /* move pivot out of the way */ - duk__array_sort_swap(thr, p, lo); - p = lo; - DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(thr, 1))); - - l = lo + 1; - r = hi; - for (;;) { - /* find elements to swap */ - for (;;) { - DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld", - (long) l, (long) r, (long) p)); - if (l >= hi) { - break; - } - if (duk__array_sort_compare(thr, l, p) >= 0) { /* !(l < p) */ - break; - } - l++; - } - for (;;) { - DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld", - (long) l, (long) r, (long) p)); - if (r <= lo) { - break; - } - if (duk__array_sort_compare(thr, p, r) >= 0) { /* !(p < r) */ - break; - } - r--; - } - if (l >= r) { - goto done; - } - DUK_ASSERT(l < r); - - DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r)); - - duk__array_sort_swap(thr, l, r); - - DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(thr, 1))); - l++; - r--; - } - done: - /* Note that 'l' and 'r' may cross, i.e. r < l */ - DUK_ASSERT(l >= lo && l <= hi); - DUK_ASSERT(r >= lo && r <= hi); - - /* XXX: there's no explicit recursion bound here now. For the average - * qsort recursion depth O(log n) that's not really necessary: e.g. for - * 2**32 recursion depth would be about 32 which is OK. However, qsort - * worst case recursion depth is O(n) which may be a problem. - */ - - /* move pivot to its final place */ - DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(thr, 1))); - duk__array_sort_swap(thr, lo, r); - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - duk__debuglog_qsort_state(thr, lo, hi, r); -#endif - - DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(thr, 1))); - duk__array_qsort(thr, lo, r - 1); - duk__array_qsort(thr, r + 1, hi); -} - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_hthread *thr) { - duk_uint32_t len; - - /* XXX: len >= 0x80000000 won't work below because a signed type - * is needed by qsort. - */ - len = duk__push_this_obj_len_u32_limited(thr); - - /* stack[0] = compareFn - * stack[1] = ToObject(this) - * stack[2] = ToUint32(length) - */ - - if (len > 0) { - /* avoid degenerate cases, so that (len - 1) won't underflow */ - duk__array_qsort(thr, (duk_int_t) 0, (duk_int_t) (len - 1)); - } - - DUK_ASSERT_TOP(thr, 3); - duk_pop_nodecref_unsafe(thr); - return 1; /* return ToObject(this) */ -} - -/* - * splice() - */ - -/* XXX: this compiles to over 500 bytes now, even without special handling - * for an array part. Uses signed ints so does not handle full array range correctly. - */ - -/* XXX: can shift() / unshift() use the same helper? - * shift() is (close to?) <--> splice(0, 1) - * unshift is (close to?) <--> splice(0, 0, [items])? - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_hthread *thr) { - duk_idx_t nargs; - duk_uint32_t len_u32; - duk_int_t len; - duk_bool_t have_delcount; - duk_int_t item_count; - duk_int_t act_start; - duk_int_t del_count; - duk_int_t i, n; - - DUK_UNREF(have_delcount); - - nargs = duk_get_top(thr); - if (nargs < 2) { - duk_set_top(thr, 2); - nargs = 2; - have_delcount = 0; - } else { - have_delcount = 1; - } - - /* XXX: len >= 0x80000000 won't work below because we need to be - * able to represent -len. - */ - len_u32 = duk__push_this_obj_len_u32_limited(thr); - len = (duk_int_t) len_u32; - DUK_ASSERT(len >= 0); - - act_start = duk_to_int_clamped(thr, 0, -len, len); - if (act_start < 0) { - act_start = len + act_start; - } - DUK_ASSERT(act_start >= 0 && act_start <= len); - -#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT) - if (have_delcount) { -#endif - del_count = duk_to_int_clamped(thr, 1, 0, len - act_start); -#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT) - } else { - /* E5.1 standard behavior when deleteCount is not given would be - * to treat it just like if 'undefined' was given, which coerces - * ultimately to 0. Real world behavior is to splice to the end - * of array, see test-bi-array-proto-splice-no-delcount.js. - */ - del_count = len - act_start; - } -#endif - - DUK_ASSERT(nargs >= 2); - item_count = (duk_int_t) (nargs - 2); - - DUK_ASSERT(del_count >= 0 && del_count <= len - act_start); - DUK_ASSERT(del_count + act_start <= len); - - /* For now, restrict result array into 32-bit length range. */ - if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) { - DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw")); - DUK_DCERROR_RANGE_INVALID_LENGTH(thr); - } - - duk_push_array(thr); - - /* stack[0] = start - * stack[1] = deleteCount - * stack[2...nargs-1] = items - * stack[nargs] = ToObject(this) -3 - * stack[nargs+1] = ToUint32(length) -2 - * stack[nargs+2] = result array -1 - */ - - DUK_ASSERT_TOP(thr, nargs + 3); - - /* Step 9: copy elements-to-be-deleted into the result array */ - - for (i = 0; i < del_count; i++) { - if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (act_start + i))) { - duk_xdef_prop_index_wec(thr, -2, (duk_uarridx_t) i); /* throw flag irrelevant (false in std alg) */ - } else { - duk_pop_undefined(thr); - } - } - duk_push_u32(thr, (duk_uint32_t) del_count); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); - - /* Steps 12 and 13: reorganize elements to make room for itemCount elements */ - - if (item_count < del_count) { - /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1 - * -> [ A B F G H ] (conceptual intermediate step) - * -> [ A B . F G H ] (placeholder marked) - * [ A B C F G H ] (actual result at this point, C will be replaced) - */ - - DUK_ASSERT_TOP(thr, nargs + 3); - - n = len - del_count; - for (i = act_start; i < n; i++) { - if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) { - duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count)); - } else { - duk_pop_undefined(thr); - duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count)); - } - } - - DUK_ASSERT_TOP(thr, nargs + 3); - - /* loop iterator init and limit changed from standard algorithm */ - n = len - del_count + item_count; - for (i = len - 1; i >= n; i--) { - duk_del_prop_index(thr, -3, (duk_uarridx_t) i); - } - - DUK_ASSERT_TOP(thr, nargs + 3); - } else if (item_count > del_count) { - /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4 - * -> [ A B F G H ] (conceptual intermediate step) - * -> [ A B . . . . F G H ] (placeholder marked) - * [ A B C D E F F G H ] (actual result at this point) - */ - - DUK_ASSERT_TOP(thr, nargs + 3); - - /* loop iterator init and limit changed from standard algorithm */ - for (i = len - del_count - 1; i >= act_start; i--) { - if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) { - duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count)); - } else { - duk_pop_undefined(thr); - duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count)); - } - } - - DUK_ASSERT_TOP(thr, nargs + 3); - } else { - /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3 - * -> [ A B F G H ] (conceptual intermediate step) - * -> [ A B . . . F G H ] (placeholder marked) - * [ A B C D E F G H ] (actual result at this point) - */ - } - DUK_ASSERT_TOP(thr, nargs + 3); - - /* Step 15: insert itemCount elements into the hole made above */ - - for (i = 0; i < item_count; i++) { - duk_dup(thr, i + 2); /* args start at index 2 */ - duk_put_prop_index(thr, -4, (duk_uarridx_t) (act_start + i)); - } - - /* Step 16: update length; note that the final length may be above 32 bit range - * (but we checked above that this isn't the case here) - */ - - duk_push_u32(thr, (duk_uint32_t) (len - del_count + item_count)); - duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH); - - /* result array is already at the top of stack */ - DUK_ASSERT_TOP(thr, nargs + 3); - return 1; -} - -/* - * reverse() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_hthread *thr) { - duk_uint32_t len; - duk_uint32_t middle; - duk_uint32_t lower, upper; - duk_bool_t have_lower, have_upper; - - len = duk__push_this_obj_len_u32(thr); - middle = len / 2; - - /* If len <= 1, middle will be 0 and for-loop bails out - * immediately (0 < 0 -> false). - */ - - for (lower = 0; lower < middle; lower++) { - DUK_ASSERT(len >= 2); - DUK_ASSERT_TOP(thr, 2); - - DUK_ASSERT(len >= lower + 1); - upper = len - lower - 1; - - have_lower = duk_get_prop_index(thr, -2, (duk_uarridx_t) lower); - have_upper = duk_get_prop_index(thr, -3, (duk_uarridx_t) upper); - - /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */ - - if (have_upper) { - duk_put_prop_index(thr, -4, (duk_uarridx_t) lower); - } else { - duk_del_prop_index(thr, -4, (duk_uarridx_t) lower); - duk_pop_undefined(thr); - } - - if (have_lower) { - duk_put_prop_index(thr, -3, (duk_uarridx_t) upper); - } else { - duk_del_prop_index(thr, -3, (duk_uarridx_t) upper); - duk_pop_undefined(thr); - } - - DUK_ASSERT_TOP(thr, 2); - } - - DUK_ASSERT_TOP(thr, 2); - duk_pop_unsafe(thr); /* -> [ ToObject(this) ] */ - return 1; -} - -/* - * slice() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_hthread *thr) { - duk_uint32_t len_u32; - duk_int_t len; - duk_int_t start, end; - duk_int_t i; - duk_uarridx_t idx; - duk_uint32_t res_length = 0; - - /* XXX: len >= 0x80000000 won't work below because we need to be - * able to represent -len. - */ - len_u32 = duk__push_this_obj_len_u32_limited(thr); - len = (duk_int_t) len_u32; - DUK_ASSERT(len >= 0); - - duk_push_array(thr); - - /* stack[0] = start - * stack[1] = end - * stack[2] = ToObject(this) - * stack[3] = ToUint32(length) - * stack[4] = result array - */ - - start = duk_to_int_clamped(thr, 0, -len, len); - if (start < 0) { - start = len + start; - } - /* XXX: could duk_is_undefined() provide defaulting undefined to 'len' - * (the upper limit)? - */ - if (duk_is_undefined(thr, 1)) { - end = len; - } else { - end = duk_to_int_clamped(thr, 1, -len, len); - if (end < 0) { - end = len + end; - } - } - DUK_ASSERT(start >= 0 && start <= len); - DUK_ASSERT(end >= 0 && end <= len); - - idx = 0; - for (i = start; i < end; i++) { - DUK_ASSERT_TOP(thr, 5); - if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) { - duk_xdef_prop_index_wec(thr, 4, idx); - res_length = idx + 1; - } else { - duk_pop_undefined(thr); - } - idx++; - DUK_ASSERT_TOP(thr, 5); - } - - duk_push_u32(thr, res_length); - duk_xdef_prop_stridx_short(thr, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); - - DUK_ASSERT_TOP(thr, 5); - return 1; -} - -/* - * shift() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_hthread *thr) { - duk_uint32_t len; - duk_uint32_t i; - - len = duk__push_this_obj_len_u32(thr); - if (len == 0) { - duk_push_int(thr, 0); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); - return 0; - } - - duk_get_prop_index(thr, 0, 0); - - /* stack[0] = object (this) - * stack[1] = ToUint32(length) - * stack[2] = elem at index 0 (retval) - */ - - for (i = 1; i < len; i++) { - DUK_ASSERT_TOP(thr, 3); - if (duk_get_prop_index(thr, 0, (duk_uarridx_t) i)) { - /* fromPresent = true */ - duk_put_prop_index(thr, 0, (duk_uarridx_t) (i - 1)); - } else { - /* fromPresent = false */ - duk_del_prop_index(thr, 0, (duk_uarridx_t) (i - 1)); - duk_pop_undefined(thr); - } - } - duk_del_prop_index(thr, 0, (duk_uarridx_t) (len - 1)); - - duk_push_u32(thr, (duk_uint32_t) (len - 1)); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); - - DUK_ASSERT_TOP(thr, 3); - return 1; -} - -/* - * unshift() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_hthread *thr) { - duk_idx_t nargs; - duk_uint32_t len; - duk_uint32_t i; - - nargs = duk_get_top(thr); - len = duk__push_this_obj_len_u32(thr); - - /* stack[0...nargs-1] = unshift args (vararg) - * stack[nargs] = ToObject(this) - * stack[nargs+1] = ToUint32(length) - */ - - DUK_ASSERT_TOP(thr, nargs + 2); - - /* Note: unshift() may operate on indices above unsigned 32-bit range - * and the final length may be >= 2**32. However, we restrict the - * final result to 32-bit range for practicality. - */ - - if (len + (duk_uint32_t) nargs < len) { - DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw")); - DUK_DCERROR_RANGE_INVALID_LENGTH(thr); - } - - i = len; - while (i > 0) { - DUK_ASSERT_TOP(thr, nargs + 2); - i--; - /* k+argCount-1; note that may be above 32-bit range */ - - if (duk_get_prop_index(thr, -2, (duk_uarridx_t) i)) { - /* fromPresent = true */ - /* [ ... ToObject(this) ToUint32(length) val ] */ - duk_put_prop_index(thr, -3, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */ - } else { - /* fromPresent = false */ - /* [ ... ToObject(this) ToUint32(length) val ] */ - duk_pop_undefined(thr); - duk_del_prop_index(thr, -2, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */ - } - DUK_ASSERT_TOP(thr, nargs + 2); - } - - for (i = 0; i < (duk_uint32_t) nargs; i++) { - DUK_ASSERT_TOP(thr, nargs + 2); - duk_dup(thr, (duk_idx_t) i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */ - duk_put_prop_index(thr, -3, (duk_uarridx_t) i); - DUK_ASSERT_TOP(thr, nargs + 2); - } - - DUK_ASSERT_TOP(thr, nargs + 2); - duk_push_u32(thr, len + (duk_uint32_t) nargs); - duk_dup_top(thr); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */ - duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH); - return 1; -} - -/* - * indexOf(), lastIndexOf() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_hthread *thr) { - duk_idx_t nargs; - duk_int_t i, len; - duk_int_t from_idx; - duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for indexOf, -1 for lastIndexOf */ - - /* lastIndexOf() needs to be a vararg function because we must distinguish - * between an undefined fromIndex and a "not given" fromIndex; indexOf() is - * made vararg for symmetry although it doesn't strictly need to be. - */ - - nargs = duk_get_top(thr); - duk_set_top(thr, 2); - - /* XXX: must be able to represent -len */ - len = (duk_int_t) duk__push_this_obj_len_u32_limited(thr); - if (len == 0) { - goto not_found; - } - - /* Index clamping is a bit tricky, we must ensure that we'll only iterate - * through elements that exist and that the specific requirements from E5.1 - * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially: - * - * - indexOf: clamp to [-len,len], negative handling -> [0,len], - * if clamped result is len, for-loop bails out immediately - * - * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1], - * if clamped result is -1, for-loop bails out immediately - * - * If fromIndex is not given, ToInteger(undefined) = 0, which is correct - * for indexOf() but incorrect for lastIndexOf(). Hence special handling, - * and why lastIndexOf() needs to be a vararg function. - */ - - if (nargs >= 2) { - /* indexOf: clamp fromIndex to [-len, len] - * (if fromIndex == len, for-loop terminates directly) - * - * lastIndexOf: clamp fromIndex to [-len - 1, len - 1] - * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly) - */ - from_idx = duk_to_int_clamped(thr, - 1, - (idx_step > 0 ? -len : -len - 1), - (idx_step > 0 ? len : len - 1)); - if (from_idx < 0) { - /* for lastIndexOf, result may be -1 (mark immediate termination) */ - from_idx = len + from_idx; - } - } else { - /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but - * handle both indexOf and lastIndexOf specially here. - */ - if (idx_step > 0) { - from_idx = 0; - } else { - from_idx = len - 1; - } - } - - /* stack[0] = searchElement - * stack[1] = fromIndex - * stack[2] = object - * stack[3] = length (not needed, but not popped above) - */ - - for (i = from_idx; i >= 0 && i < len; i += idx_step) { - DUK_ASSERT_TOP(thr, 4); - - if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) { - DUK_ASSERT_TOP(thr, 5); - if (duk_strict_equals(thr, 0, 4)) { - duk_push_int(thr, i); - return 1; - } - } - - duk_pop_unsafe(thr); - } - - not_found: - duk_push_int(thr, -1); - return 1; -} - -/* - * every(), some(), forEach(), map(), filter() - */ - -#define DUK__ITER_EVERY 0 -#define DUK__ITER_SOME 1 -#define DUK__ITER_FOREACH 2 -#define DUK__ITER_MAP 3 -#define DUK__ITER_FILTER 4 - -/* XXX: This helper is a bit awkward because the handling for the different iteration - * callers is quite different. This now compiles to a bit less than 500 bytes, so with - * 5 callers the net result is about 100 bytes / caller. - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) { - duk_uint32_t len; - duk_uint32_t i; - duk_uarridx_t k; - duk_bool_t bval; - duk_small_int_t iter_type = duk_get_current_magic(thr); - duk_uint32_t res_length = 0; - - /* each call this helper serves has nargs==2 */ - DUK_ASSERT_TOP(thr, 2); - - len = duk__push_this_obj_len_u32(thr); - duk_require_callable(thr, 0); - /* if thisArg not supplied, behave as if undefined was supplied */ - - if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) { - duk_push_array(thr); - } else { - duk_push_undefined(thr); - } - - /* stack[0] = callback - * stack[1] = thisArg - * stack[2] = object - * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop) - * stack[4] = result array (or undefined) - */ - - k = 0; /* result index for filter() */ - for (i = 0; i < len; i++) { - DUK_ASSERT_TOP(thr, 5); - - if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) { -#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER) - /* Real world behavior for map(): trailing non-existent - * elements don't invoke the user callback, but are still - * counted towards result 'length'. - */ - if (iter_type == DUK__ITER_MAP) { - res_length = i + 1; - } -#else - /* Standard behavior for map(): trailing non-existent - * elements don't invoke the user callback and are not - * counted towards result 'length'. - */ -#endif - duk_pop_undefined(thr); - continue; - } - - /* The original value needs to be preserved for filter(), hence - * this funny order. We can't re-get the value because of side - * effects. - */ - - duk_dup_0(thr); - duk_dup_1(thr); - duk_dup_m3(thr); - duk_push_u32(thr, i); - duk_dup_2(thr); /* [ ... val callback thisArg val i obj ] */ - duk_call_method(thr, 3); /* -> [ ... val retval ] */ - - switch (iter_type) { - case DUK__ITER_EVERY: - bval = duk_to_boolean(thr, -1); - if (!bval) { - /* stack top contains 'false' */ - return 1; - } - break; - case DUK__ITER_SOME: - bval = duk_to_boolean(thr, -1); - if (bval) { - /* stack top contains 'true' */ - return 1; - } - break; - case DUK__ITER_FOREACH: - /* nop */ - break; - case DUK__ITER_MAP: - duk_dup_top(thr); - duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) i); /* retval to result[i] */ - res_length = i + 1; - break; - case DUK__ITER_FILTER: - bval = duk_to_boolean(thr, -1); - if (bval) { - duk_dup_m2(thr); /* orig value */ - duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) k); - k++; - res_length = k; - } - break; - default: - DUK_UNREACHABLE(); - break; - } - duk_pop_2_unsafe(thr); - - DUK_ASSERT_TOP(thr, 5); - } - - switch (iter_type) { - case DUK__ITER_EVERY: - duk_push_true(thr); - break; - case DUK__ITER_SOME: - duk_push_false(thr); - break; - case DUK__ITER_FOREACH: - duk_push_undefined(thr); - break; - case DUK__ITER_MAP: - case DUK__ITER_FILTER: - DUK_ASSERT_TOP(thr, 5); - DUK_ASSERT(duk_is_array(thr, -1)); /* topmost element is the result array already */ - duk_push_u32(thr, res_length); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); - break; - default: - DUK_UNREACHABLE(); - break; - } - - return 1; -} - -/* - * reduce(), reduceRight() - */ - -DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_hthread *thr) { - duk_idx_t nargs; - duk_bool_t have_acc; - duk_uint32_t i, len; - duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for reduce, -1 for reduceRight */ - - /* We're a varargs function because we need to detect whether - * initialValue was given or not. - */ - nargs = duk_get_top(thr); - DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs)); - - duk_set_top(thr, 2); - len = duk__push_this_obj_len_u32(thr); - duk_require_callable(thr, 0); - - /* stack[0] = callback fn - * stack[1] = initialValue - * stack[2] = object (coerced this) - * stack[3] = length (not needed, but not popped above) - * stack[4] = accumulator - */ - - have_acc = 0; - if (nargs >= 2) { - duk_dup_1(thr); - have_acc = 1; - } - DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T", - (long) have_acc, (duk_tval *) duk_get_tval(thr, 3))); - - /* For len == 0, i is initialized to len - 1 which underflows. - * The condition (i < len) will then exit the for-loop on the - * first round which is correct. Similarly, loop termination - * happens by i underflowing. - */ - - for (i = (idx_step >= 0 ? 0 : len - 1); - i < len; /* i >= 0 would always be true */ - i += (duk_uint32_t) idx_step) { - DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T", - (long) i, (long) len, (long) have_acc, - (long) duk_get_top(thr), - (duk_tval *) duk_get_tval(thr, 4))); - - DUK_ASSERT((have_acc && duk_get_top(thr) == 5) || - (!have_acc && duk_get_top(thr) == 4)); - - if (!duk_has_prop_index(thr, 2, (duk_uarridx_t) i)) { - continue; - } - - if (!have_acc) { - DUK_ASSERT_TOP(thr, 4); - duk_get_prop_index(thr, 2, (duk_uarridx_t) i); - have_acc = 1; - DUK_ASSERT_TOP(thr, 5); - } else { - DUK_ASSERT_TOP(thr, 5); - duk_dup_0(thr); - duk_dup(thr, 4); - duk_get_prop_index(thr, 2, (duk_uarridx_t) i); - duk_push_u32(thr, i); - duk_dup_2(thr); - DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T", - (duk_tval *) duk_get_tval(thr, -5), (duk_tval *) duk_get_tval(thr, -4), - (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - duk_call(thr, 4); - DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(thr, -1))); - duk_replace(thr, 4); - DUK_ASSERT_TOP(thr, 5); - } - } - - if (!have_acc) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - - DUK_ASSERT_TOP(thr, 5); - return 1; -} - -#endif /* DUK_USE_ARRAY_BUILTIN */ - -/* automatic undefs */ -#undef DUK__ARRAY_MID_JOIN_LIMIT -#undef DUK__ITER_EVERY -#undef DUK__ITER_FILTER -#undef DUK__ITER_FOREACH -#undef DUK__ITER_MAP -#undef DUK__ITER_SOME -#line 1 "duk_bi_boolean.c" -/* - * Boolean built-ins - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_BOOLEAN_BUILTIN) - -/* Shared helper to provide toString() and valueOf(). Checks 'this', gets - * the primitive value to stack top, and optionally coerces with ToString(). - */ -DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_hthread *thr) { - duk_tval *tv; - duk_hobject *h; - duk_small_int_t coerce_tostring = duk_get_current_magic(thr); - - /* XXX: there is room to use a shared helper here, many built-ins - * check the 'this' type, and if it's an object, check its class, - * then get its internal value, etc. - */ - - duk_push_this(thr); - tv = duk_get_tval(thr, -1); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_BOOLEAN(tv)) { - goto type_ok; - } else if (DUK_TVAL_IS_OBJECT(tv)) { - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - - if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) { - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); - DUK_ASSERT(duk_is_boolean(thr, -1)); - goto type_ok; - } - } - - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - /* never here */ - - type_ok: - if (coerce_tostring) { - duk_to_string(thr, -1); - } - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_hthread *thr) { - duk_hobject *h_this; - - duk_to_boolean(thr, 0); - - if (duk_is_constructor_call(thr)) { - /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */ - duk_push_this(thr); - h_this = duk_known_hobject(thr, -1); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]); - - DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN); - - duk_dup_0(thr); /* -> [ val obj val ] */ - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */ - } /* unbalanced stack */ - - return 1; -} - -#endif /* DUK_USE_BOOLEAN_BUILTIN */ -#line 1 "duk_bi_buffer.c" -/* - * ES2015 TypedArray and Node.js Buffer built-ins - */ - -/* #include duk_internal.h -> already included */ - -/* - * Helpers for buffer handling, enabled with DUK_USE_BUFFEROBJECT_SUPPORT. - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Map class number (minus DUK_HOBJECT_CLASS_BUFOBJ_MIN) to a bidx for the - * default internal prototype. - */ -static const duk_uint8_t duk__buffer_proto_from_classnum[] = { - DUK_BIDX_ARRAYBUFFER_PROTOTYPE, - DUK_BIDX_DATAVIEW_PROTOTYPE, - DUK_BIDX_INT8ARRAY_PROTOTYPE, - DUK_BIDX_UINT8ARRAY_PROTOTYPE, - DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, - DUK_BIDX_INT16ARRAY_PROTOTYPE, - DUK_BIDX_UINT16ARRAY_PROTOTYPE, - DUK_BIDX_INT32ARRAY_PROTOTYPE, - DUK_BIDX_UINT32ARRAY_PROTOTYPE, - DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, - DUK_BIDX_FLOAT64ARRAY_PROTOTYPE -}; - -/* Map DUK_HBUFOBJ_ELEM_xxx to duk_hobject class number. - * Sync with duk_hbufobj.h and duk_hobject.h. - */ -static const duk_uint8_t duk__buffer_class_from_elemtype[9] = { - DUK_HOBJECT_CLASS_UINT8ARRAY, - DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, - DUK_HOBJECT_CLASS_INT8ARRAY, - DUK_HOBJECT_CLASS_UINT16ARRAY, - DUK_HOBJECT_CLASS_INT16ARRAY, - DUK_HOBJECT_CLASS_UINT32ARRAY, - DUK_HOBJECT_CLASS_INT32ARRAY, - DUK_HOBJECT_CLASS_FLOAT32ARRAY, - DUK_HOBJECT_CLASS_FLOAT64ARRAY -}; - -/* Map DUK_HBUFOBJ_ELEM_xxx to prototype object built-in index. - * Sync with duk_hbufobj.h. - */ -static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = { - DUK_BIDX_UINT8ARRAY_PROTOTYPE, - DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, - DUK_BIDX_INT8ARRAY_PROTOTYPE, - DUK_BIDX_UINT16ARRAY_PROTOTYPE, - DUK_BIDX_INT16ARRAY_PROTOTYPE, - DUK_BIDX_UINT32ARRAY_PROTOTYPE, - DUK_BIDX_INT32ARRAY_PROTOTYPE, - DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, - DUK_BIDX_FLOAT64ARRAY_PROTOTYPE -}; - -/* Map DUK__FLD_xxx to byte size. */ -static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = { - 1, /* DUK__FLD_8BIT */ - 2, /* DUK__FLD_16BIT */ - 4, /* DUK__FLD_32BIT */ - 4, /* DUK__FLD_FLOAT */ - 8, /* DUK__FLD_DOUBLE */ - 0 /* DUK__FLD_VARINT; not relevant here */ -}; - -/* Bitfield for each DUK_HBUFOBJ_ELEM_xxx indicating which element types - * are compatible with a blind byte copy for the TypedArray set() method (also - * used for TypedArray constructor). Array index is target buffer elem type, - * bitfield indicates compatible source types. The types must have same byte - * size and they must be coercion compatible. - */ -#if !defined(DUK_USE_PREFER_SIZE) -static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = { - /* xxx -> DUK_HBUFOBJ_ELEM_UINT8 */ - (1U << DUK_HBUFOBJ_ELEM_UINT8) | - (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) | - (1U << DUK_HBUFOBJ_ELEM_INT8), - - /* xxx -> DUK_HBUFOBJ_ELEM_UINT8CLAMPED - * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00. - */ - (1U << DUK_HBUFOBJ_ELEM_UINT8) | - (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED), - - /* xxx -> DUK_HBUFOBJ_ELEM_INT8 */ - (1U << DUK_HBUFOBJ_ELEM_UINT8) | - (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) | - (1U << DUK_HBUFOBJ_ELEM_INT8), - - /* xxx -> DUK_HBUFOBJ_ELEM_UINT16 */ - (1U << DUK_HBUFOBJ_ELEM_UINT16) | - (1U << DUK_HBUFOBJ_ELEM_INT16), - - /* xxx -> DUK_HBUFOBJ_ELEM_INT16 */ - (1U << DUK_HBUFOBJ_ELEM_UINT16) | - (1U << DUK_HBUFOBJ_ELEM_INT16), - - /* xxx -> DUK_HBUFOBJ_ELEM_UINT32 */ - (1U << DUK_HBUFOBJ_ELEM_UINT32) | - (1U << DUK_HBUFOBJ_ELEM_INT32), - - /* xxx -> DUK_HBUFOBJ_ELEM_INT32 */ - (1U << DUK_HBUFOBJ_ELEM_UINT32) | - (1U << DUK_HBUFOBJ_ELEM_INT32), - - /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT32 */ - (1U << DUK_HBUFOBJ_ELEM_FLOAT32), - - /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT64 */ - (1U << DUK_HBUFOBJ_ELEM_FLOAT64) -}; -#endif /* !DUK_USE_PREFER_SIZE */ - -DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_hthread *thr) { - duk_tval *tv_dst; - duk_hbufobj *res; - - duk_push_this(thr); - DUK_ASSERT(duk_is_buffer(thr, -1)); - res = (duk_hbufobj *) duk_to_hobject(thr, -1); - DUK_ASSERT_HBUFOBJ_VALID(res); - DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(thr, -1))); - - tv_dst = duk_get_borrowed_this_tval(thr); - DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res); - duk_pop(thr); - - return res; -} - -#define DUK__BUFOBJ_FLAG_THROW (1 << 0) -#define DUK__BUFOBJ_FLAG_PROMOTE (1 << 1) - -/* Shared helper. When DUK__BUFOBJ_FLAG_PROMOTE is given, the return value is - * always a duk_hbufobj *. Without the flag the return value can also be a - * plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER(). - */ -DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_uint_t flags) { - duk_tval *tv; - duk_hbufobj *h_this; - - DUK_ASSERT(thr != NULL); - - tv = duk_get_borrowed_this_tval(thr); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_OBJECT(tv)) { - h_this = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h_this != NULL); - if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_this)) { - DUK_ASSERT_HBUFOBJ_VALID(h_this); - return (duk_heaphdr *) h_this; - } - } else if (DUK_TVAL_IS_BUFFER(tv)) { - if (flags & DUK__BUFOBJ_FLAG_PROMOTE) { - /* Promote a plain buffer to a Uint8Array. This is very - * inefficient but allows plain buffer to be used wherever an - * Uint8Array is used with very small cost; hot path functions - * like index read/write calls should provide direct buffer - * support to avoid promotion. - */ - /* XXX: make this conditional to a flag if call sites need it? */ - h_this = duk__hbufobj_promote_this(thr); - DUK_ASSERT(h_this != NULL); - DUK_ASSERT_HBUFOBJ_VALID(h_this); - return (duk_heaphdr *) h_this; - } else { - /* XXX: ugly, share return pointer for duk_hbuffer. */ - return (duk_heaphdr *) DUK_TVAL_GET_BUFFER(tv); - } - } - - if (flags & DUK__BUFOBJ_FLAG_THROW) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); - } - return NULL; -} - -/* Check that 'this' is a duk_hbufobj and return a pointer to it. */ -DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_hthread *thr) { - return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_PROMOTE); -} - -/* Check that 'this' is a duk_hbufobj and return a pointer to it - * (NULL if not). - */ -DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_hthread *thr) { - return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE); -} - -/* Check that value is a duk_hbufobj and return a pointer to it. */ -DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx) { - duk_tval *tv; - duk_hbufobj *h_obj; - - /* Don't accept relative indices now. */ - DUK_ASSERT(idx >= 0); - - tv = duk_require_tval(thr, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_OBJECT(tv)) { - h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h_obj != NULL); - if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_obj)) { - DUK_ASSERT_HBUFOBJ_VALID(h_obj); - return h_obj; - } - } else if (DUK_TVAL_IS_BUFFER(tv)) { - h_obj = (duk_hbufobj *) duk_to_hobject(thr, idx); - DUK_ASSERT(h_obj != NULL); - DUK_ASSERT_HBUFOBJ_VALID(h_obj); - return h_obj; - } - - DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); - return NULL; /* not reachable */ -} - -DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(h_bufobj != NULL); - DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */ - DUK_ASSERT(h_val != NULL); - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - DUK_UNREF(thr); - - h_bufobj->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val); - DUK_ASSERT(h_bufobj->shift == 0); - DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8); - DUK_ASSERT(h_bufobj->is_typedarray == 0); - - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); -} - -/* Shared offset/length coercion helper. */ -DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr, - duk_hbufobj *h_bufarg, - duk_idx_t idx_offset, - duk_idx_t idx_length, - duk_uint_t *out_offset, - duk_uint_t *out_length, - duk_bool_t throw_flag) { - duk_int_t offset_signed; - duk_int_t length_signed; - duk_uint_t offset; - duk_uint_t length; - - offset_signed = duk_to_int(thr, idx_offset); - if (offset_signed < 0) { - goto fail_range; - } - offset = (duk_uint_t) offset_signed; - if (offset > h_bufarg->length) { - goto fail_range; - } - DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */ - DUK_ASSERT(offset <= h_bufarg->length); - - if (duk_is_undefined(thr, idx_length)) { - DUK_ASSERT(h_bufarg->length >= offset); - length = h_bufarg->length - offset; /* >= 0 */ - } else { - length_signed = duk_to_int(thr, idx_length); - if (length_signed < 0) { - goto fail_range; - } - length = (duk_uint_t) length_signed; - DUK_ASSERT(h_bufarg->length >= offset); - if (length > h_bufarg->length - offset) { - /* Unlike for negative arguments, some call sites - * want length to be clamped if it's positive. - */ - if (throw_flag) { - goto fail_range; - } else { - length = h_bufarg->length - offset; - } - } - } - DUK_ASSERT_DISABLE(length >= 0); /* unsigned */ - DUK_ASSERT(offset + length <= h_bufarg->length); - - *out_offset = offset; - *out_length = length; - return; - - fail_range: - DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS); -} - -/* Shared lenient buffer length clamping helper. No negative indices, no - * element/byte shifting. - */ -DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_hthread *thr, - duk_int_t buffer_length, - duk_idx_t idx_start, - duk_idx_t idx_end, - duk_int_t *out_start_offset, - duk_int_t *out_end_offset) { - duk_int_t start_offset; - duk_int_t end_offset; - - DUK_ASSERT(out_start_offset != NULL); - DUK_ASSERT(out_end_offset != NULL); - - /* undefined coerces to zero which is correct */ - start_offset = duk_to_int_clamped(thr, idx_start, 0, buffer_length); - if (duk_is_undefined(thr, idx_end)) { - end_offset = buffer_length; - } else { - end_offset = duk_to_int_clamped(thr, idx_end, start_offset, buffer_length); - } - - DUK_ASSERT(start_offset >= 0); - DUK_ASSERT(start_offset <= buffer_length); - DUK_ASSERT(end_offset >= 0); - DUK_ASSERT(end_offset <= buffer_length); - DUK_ASSERT(start_offset <= end_offset); - - *out_start_offset = start_offset; - *out_end_offset = end_offset; -} - -/* Shared lenient buffer length clamping helper. Indices are treated as - * element indices (though output values are byte offsets) which only - * really matters for TypedArray views as other buffer object have a zero - * shift. Negative indices are counted from end of input slice; crossed - * indices are clamped to zero length; and final indices are clamped - * against input slice. Used for e.g. ArrayBuffer slice(). - */ -DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_hthread *thr, - duk_int_t buffer_length, - duk_uint8_t buffer_shift, - duk_idx_t idx_start, - duk_idx_t idx_end, - duk_int_t *out_start_offset, - duk_int_t *out_end_offset) { - duk_int_t start_offset; - duk_int_t end_offset; - - DUK_ASSERT(out_start_offset != NULL); - DUK_ASSERT(out_end_offset != NULL); - - buffer_length >>= buffer_shift; /* as (full) elements */ - - /* Resolve start/end offset as element indices first; arguments - * at idx_start/idx_end are element offsets. Working with element - * indices first also avoids potential for wrapping. - */ - - start_offset = duk_to_int(thr, idx_start); - if (start_offset < 0) { - start_offset = buffer_length + start_offset; - } - if (duk_is_undefined(thr, idx_end)) { - end_offset = buffer_length; - } else { - end_offset = duk_to_int(thr, idx_end); - if (end_offset < 0) { - end_offset = buffer_length + end_offset; - } - } - /* Note: start_offset/end_offset can still be < 0 here. */ - - if (start_offset < 0) { - start_offset = 0; - } else if (start_offset > buffer_length) { - start_offset = buffer_length; - } - if (end_offset < start_offset) { - end_offset = start_offset; - } else if (end_offset > buffer_length) { - end_offset = buffer_length; - } - DUK_ASSERT(start_offset >= 0); - DUK_ASSERT(start_offset <= buffer_length); - DUK_ASSERT(end_offset >= 0); - DUK_ASSERT(end_offset <= buffer_length); - DUK_ASSERT(start_offset <= end_offset); - - /* Convert indices to byte offsets. */ - start_offset <<= buffer_shift; - end_offset <<= buffer_shift; - - *out_start_offset = start_offset; - *out_end_offset = end_offset; -} - -DUK_INTERNAL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx) { - if (duk_is_buffer(thr, idx)) { - duk_to_object(thr, idx); - } -} - -DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) { - /* Push Uint8Array which will share the same underlying buffer as - * the plain buffer argument. Also create an ArrayBuffer with the - * same backing for the result .buffer property. - */ - - duk_push_hbuffer(thr, h_buf); - duk_push_buffer_object(thr, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY); - duk_remove_m2(thr); - -#if 0 - /* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */ - h_bufobj = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY), - DUK_BIDX_UINT8ARRAY_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); - duk__set_bufobj_buffer(thr, h_bufobj, h_buf); - h_bufobj->is_typedarray = 1; - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - h_arrbuf = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_arrbuf != NULL); - duk__set_bufobj_buffer(thr, h_arrbuf, h_buf); - DUK_ASSERT(h_arrbuf->is_typedarray == 0); - DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf); - - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; - DUK_ASSERT(h_arrbuf != NULL); - DUK_HBUFOBJ_INCREF(thr, h_arrbuf); - duk_pop(thr); -#endif -} - -/* Indexed read helper for buffer objects, also called from outside this file. */ -DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { - duk_double_union du; - - DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size); - - switch (h_bufobj->elem_type) { - case DUK_HBUFOBJ_ELEM_UINT8: - case DUK_HBUFOBJ_ELEM_UINT8CLAMPED: - duk_push_uint(thr, (duk_uint_t) du.uc[0]); - break; - case DUK_HBUFOBJ_ELEM_INT8: - duk_push_int(thr, (duk_int_t) (duk_int8_t) du.uc[0]); - break; - case DUK_HBUFOBJ_ELEM_UINT16: - duk_push_uint(thr, (duk_uint_t) du.us[0]); - break; - case DUK_HBUFOBJ_ELEM_INT16: - duk_push_int(thr, (duk_int_t) (duk_int16_t) du.us[0]); - break; - case DUK_HBUFOBJ_ELEM_UINT32: - duk_push_uint(thr, (duk_uint_t) du.ui[0]); - break; - case DUK_HBUFOBJ_ELEM_INT32: - duk_push_int(thr, (duk_int_t) (duk_int32_t) du.ui[0]); - break; - case DUK_HBUFOBJ_ELEM_FLOAT32: - duk_push_number(thr, (duk_double_t) du.f[0]); - break; - case DUK_HBUFOBJ_ELEM_FLOAT64: - duk_push_number(thr, (duk_double_t) du.d); - break; - default: - DUK_UNREACHABLE(); - } -} - -/* Indexed write helper for buffer objects, also called from outside this file. */ -DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { - duk_double_union du; - - /* NOTE! Caller must ensure that any side effects from the - * coercions below are safe. If that cannot be guaranteed - * (which is normally the case), caller must coerce the - * argument using duk_to_number() before any pointer - * validations; the result of duk_to_number() always coerces - * without side effects here. - */ - - switch (h_bufobj->elem_type) { - case DUK_HBUFOBJ_ELEM_UINT8: - du.uc[0] = (duk_uint8_t) duk_to_uint32(thr, -1); - break; - case DUK_HBUFOBJ_ELEM_UINT8CLAMPED: - du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(thr, -1); - break; - case DUK_HBUFOBJ_ELEM_INT8: - du.uc[0] = (duk_uint8_t) duk_to_int32(thr, -1); - break; - case DUK_HBUFOBJ_ELEM_UINT16: - du.us[0] = (duk_uint16_t) duk_to_uint32(thr, -1); - break; - case DUK_HBUFOBJ_ELEM_INT16: - du.us[0] = (duk_uint16_t) duk_to_int32(thr, -1); - break; - case DUK_HBUFOBJ_ELEM_UINT32: - du.ui[0] = (duk_uint32_t) duk_to_uint32(thr, -1); - break; - case DUK_HBUFOBJ_ELEM_INT32: - du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1); - break; - case DUK_HBUFOBJ_ELEM_FLOAT32: - du.f[0] = (duk_float_t) duk_to_number_m1(thr); - break; - case DUK_HBUFOBJ_ELEM_FLOAT64: - du.d = (duk_double_t) duk_to_number_m1(thr); - break; - default: - DUK_UNREACHABLE(); - } - - DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size); -} - -/* Helper to create a fixed buffer from argument value at index 0. - * Node.js and allocPlain() compatible. - */ -DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) { - duk_int_t len; - duk_int_t i; - duk_size_t buf_size; - duk_uint8_t *buf; - - switch (duk_get_type(thr, 0)) { - case DUK_TYPE_NUMBER: { - len = duk_to_int_clamped(thr, 0, 0, DUK_INT_MAX); - (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len); - break; - } - case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */ - goto slow_copy; - } - case DUK_TYPE_OBJECT: { - duk_hobject *h; - duk_hbufobj *h_bufobj; - - /* For Node.js Buffers "Passing an ArrayBuffer returns a Buffer - * that shares allocated memory with the given ArrayBuffer." - * https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe - */ - - h = duk_known_hobject(thr, 0); - if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) { - DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h)); - h_bufobj = (duk_hbufobj *) h; - if (DUK_UNLIKELY(h_bufobj->buf == NULL)) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - } - if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) { - /* No support for ArrayBuffers with slice - * offset/length. - */ - DUK_ERROR_TYPE_INVALID_ARGS(thr); - } - duk_push_hbuffer(thr, h_bufobj->buf); - return h_bufobj->buf; - } - goto slow_copy; - } - case DUK_TYPE_STRING: { - /* ignore encoding for now */ - duk_require_hstring_notsymbol(thr, 0); - duk_dup_0(thr); - (void) duk_to_buffer(thr, -1, &buf_size); - break; - } - default: - DUK_ERROR_TYPE_INVALID_ARGS(thr); - } - - done: - DUK_ASSERT(duk_is_buffer(thr, -1)); - return duk_known_hbuffer(thr, -1); - - slow_copy: - /* XXX: fast path for typed arrays and other buffer objects? */ - - (void) duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); - len = duk_to_int_clamped(thr, -1, 0, DUK_INT_MAX); - duk_pop(thr); - buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); /* no zeroing, all indices get initialized */ - for (i = 0; i < len; i++) { - /* XXX: fast path for array or buffer arguments? */ - duk_get_prop_index(thr, 0, (duk_uarridx_t) i); - buf[i] = (duk_uint8_t) (duk_to_uint32(thr, -1) & 0xffU); - duk_pop(thr); - } - goto done; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer constructor - * - * Node.js Buffers are just Uint8Arrays with internal prototype set to - * Buffer.prototype so they're handled otherwise the same as Uint8Array. - * However, the constructor arguments are very different so a separate - * constructor entry point is used. - */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) { - duk_hbuffer *h_buf; - - h_buf = duk__hbufobj_fixed_from_argvalue(thr); - DUK_ASSERT(h_buf != NULL); - - duk_push_buffer_object(thr, - -1, - 0, - DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) h_buf), - DUK_BUFOBJ_UINT8ARRAY); - duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); - duk_set_prototype(thr, -2); - - /* XXX: a more direct implementation */ - - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * ArrayBuffer, DataView, and TypedArray constructors - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_hthread *thr) { - duk_hbufobj *h_bufobj; - duk_hbuffer *h_val; - duk_int_t len; - - DUK_ASSERT_CTX_VALID(thr); - - duk_require_constructor_call(thr); - - len = duk_to_int(thr, 0); - if (len < 0) { - goto fail_length; - } - (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len); - h_val = (duk_hbuffer *) duk_known_hbuffer(thr, -1); - - h_bufobj = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); - - duk__set_bufobj_buffer(thr, h_bufobj, h_val); - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - return 1; - - fail_length: - DUK_DCERROR_RANGE_INVALID_LENGTH(thr); -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - - -/* Format of magic, bits: - * 0...1: elem size shift (0-3) - * 2...5: elem type (DUK_HBUFOBJ_ELEM_xxx) - * - * XXX: add prototype bidx explicitly to magic instead of using a mapping? - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) { - duk_tval *tv; - duk_hobject *h_obj; - duk_hbufobj *h_bufobj = NULL; - duk_hbufobj *h_bufarg = NULL; - duk_hbuffer *h_val; - duk_small_uint_t magic; - duk_small_uint_t shift; - duk_small_uint_t elem_type; - duk_small_uint_t elem_size; - duk_small_uint_t class_num; - duk_small_uint_t proto_bidx; - duk_uint_t align_mask; - duk_uint_t elem_length; - duk_int_t elem_length_signed; - duk_uint_t byte_length; - duk_small_uint_t copy_mode; - - /* XXX: The same copy helpers could be shared with at least some - * buffer functions. - */ - - duk_require_constructor_call(thr); - - /* We could fit built-in index into magic but that'd make the magic - * number dependent on built-in numbering (genbuiltins.py doesn't - * handle that yet). So map both class and prototype from the - * element type. - */ - magic = (duk_small_uint_t) duk_get_current_magic(thr); - shift = magic & 0x03U; /* bits 0...1: shift */ - elem_type = (magic >> 2) & 0x0fU; /* bits 2...5: type */ - elem_size = 1U << shift; - align_mask = elem_size - 1; - DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t)); - proto_bidx = duk__buffer_proto_from_elemtype[elem_type]; - DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS); - DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t)); - class_num = duk__buffer_class_from_elemtype[elem_type]; - - DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, " - "elem_size=%d, proto_bidx=%d, class_num=%d", - (int) magic, (int) shift, (int) elem_type, (int) elem_size, - (int) proto_bidx, (int) class_num)); - - /* Argument variants. When the argument is an ArrayBuffer a view to - * the same buffer is created; otherwise a new ArrayBuffer is always - * created. - */ - - /* XXX: initial iteration to treat a plain buffer like an ArrayBuffer: - * coerce to an ArrayBuffer object and use that as .buffer. The underlying - * buffer will be the same but result .buffer !== inputPlainBuffer. - */ - duk_hbufobj_promote_plain(thr, 0); - - tv = duk_get_tval(thr, 0); - DUK_ASSERT(tv != NULL); /* arg count */ - if (DUK_TVAL_IS_OBJECT(tv)) { - h_obj = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h_obj != NULL); - - if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) { - /* ArrayBuffer: unlike any other argument variant, create - * a view into the existing buffer. - */ - - duk_int_t byte_offset_signed; - duk_uint_t byte_offset; - - h_bufarg = (duk_hbufobj *) h_obj; - - byte_offset_signed = duk_to_int(thr, 1); - if (byte_offset_signed < 0) { - goto fail_arguments; - } - byte_offset = (duk_uint_t) byte_offset_signed; - if (byte_offset > h_bufarg->length || - (byte_offset & align_mask) != 0) { - /* Must be >= 0 and multiple of element size. */ - goto fail_arguments; - } - if (duk_is_undefined(thr, 2)) { - DUK_ASSERT(h_bufarg->length >= byte_offset); - byte_length = h_bufarg->length - byte_offset; - if ((byte_length & align_mask) != 0) { - /* Must be element size multiple from - * start offset to end of buffer. - */ - goto fail_arguments; - } - elem_length = (byte_length >> shift); - } else { - elem_length_signed = duk_to_int(thr, 2); - if (elem_length_signed < 0) { - goto fail_arguments; - } - elem_length = (duk_uint_t) elem_length_signed; - byte_length = elem_length << shift; - if ((byte_length >> shift) != elem_length) { - /* Byte length would overflow. */ - /* XXX: easier check with less code? */ - goto fail_arguments; - } - DUK_ASSERT(h_bufarg->length >= byte_offset); - if (byte_length > h_bufarg->length - byte_offset) { - /* Not enough data. */ - goto fail_arguments; - } - } - DUK_UNREF(elem_length); - DUK_ASSERT_DISABLE(byte_offset >= 0); - DUK_ASSERT(byte_offset <= h_bufarg->length); - DUK_ASSERT_DISABLE(byte_length >= 0); - DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length); - DUK_ASSERT((elem_length << shift) == byte_length); - - h_bufobj = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(class_num), - (duk_small_int_t) proto_bidx); - h_val = h_bufarg->buf; - if (h_val == NULL) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - h_bufobj->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_bufobj->offset = h_bufarg->offset + byte_offset; - h_bufobj->length = byte_length; - h_bufobj->shift = (duk_uint8_t) shift; - h_bufobj->elem_type = (duk_uint8_t) elem_type; - h_bufobj->is_typedarray = 1; - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - /* Set .buffer to the argument ArrayBuffer. */ - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_bufarg; - DUK_ASSERT(h_bufarg != NULL); - DUK_HBUFOBJ_INCREF(thr, h_bufarg); - return 1; - } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { - /* TypedArray (or other non-ArrayBuffer duk_hbufobj). - * Conceptually same behavior as for an Array-like argument, - * with a few fast paths. - */ - - h_bufarg = (duk_hbufobj *) h_obj; - DUK_ASSERT_HBUFOBJ_VALID(h_bufarg); - elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift); - if (h_bufarg->buf == NULL) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - - /* Select copy mode. Must take into account element - * compatibility and validity of the underlying source - * buffer. - */ - - DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, " - "src byte_length=%ld, src shift=%d, " - "src/dst elem_length=%ld; " - "dst shift=%d -> dst byte_length=%ld", - (long) h_bufarg->length, (int) h_bufarg->shift, - (long) elem_length_signed, (int) shift, - (long) (elem_length_signed << shift))); - - copy_mode = 2; /* default is explicit index read/write copy */ -#if !defined(DUK_USE_PREFER_SIZE) - /* With a size optimized build copy_mode 2 is enough. - * Modes 0 and 1 are faster but conceptually the same. - */ - DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t)); - if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) { - if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) { - DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy")); - DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */ - copy_mode = 0; - } else { - DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy")); - copy_mode = 1; - } - } -#endif /* !DUK_USE_PREFER_SIZE */ - } else { - /* Array or Array-like */ - elem_length_signed = (duk_int_t) duk_get_length(thr, 0); - copy_mode = 2; - } - } else { - /* Non-object argument is simply int coerced, matches - * V8 behavior (except for "null", which we coerce to - * 0 but V8 TypeErrors). - */ - elem_length_signed = duk_to_int(thr, 0); - copy_mode = 3; - } - if (elem_length_signed < 0) { - goto fail_arguments; - } - elem_length = (duk_uint_t) elem_length_signed; - byte_length = (duk_uint_t) (elem_length << shift); - if ((byte_length >> shift) != elem_length) { - /* Byte length would overflow. */ - /* XXX: easier check with less code? */ - goto fail_arguments; - } - - DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld", - (long) elem_length, (long) byte_length)); - - /* ArrayBuffer argument is handled specially above; the rest of the - * argument variants are handled by shared code below. - * - * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset. - * It will be automatically created by the .buffer accessor on - * first access. - */ - - /* Push the resulting view object on top of a plain fixed buffer. */ - (void) duk_push_fixed_buffer(thr, byte_length); - h_val = duk_known_hbuffer(thr, -1); - DUK_ASSERT(h_val != NULL); - - h_bufobj = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(class_num), - (duk_small_int_t) proto_bidx); - - h_bufobj->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - DUK_ASSERT(h_bufobj->offset == 0); - h_bufobj->length = byte_length; - h_bufobj->shift = (duk_uint8_t) shift; - h_bufobj->elem_type = (duk_uint8_t) elem_type; - h_bufobj->is_typedarray = 1; - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - /* Copy values, the copy method depends on the arguments. - * - * Copy mode decision may depend on the validity of the underlying - * buffer of the source argument; there must be no harmful side effects - * from there to here for copy_mode to still be valid. - */ - DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode)); - switch (copy_mode) { - /* Copy modes 0 and 1 can be omitted in size optimized build, - * copy mode 2 handles them (but more slowly). - */ -#if !defined(DUK_USE_PREFER_SIZE) - case 0: { - /* Use byte copy. */ - - duk_uint8_t *p_src; - duk_uint8_t *p_dst; - - DUK_ASSERT(h_bufobj != NULL); - DUK_ASSERT(h_bufobj->buf != NULL); - DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj)); - DUK_ASSERT(h_bufarg != NULL); - DUK_ASSERT(h_bufarg->buf != NULL); - DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg)); - - p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj); - p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); - - DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld", - (void *) p_src, (void *) p_dst, (long) byte_length)); - - DUK_MEMCPY((void *) p_dst, (const void *) p_src, (size_t) byte_length); - break; - } - case 1: { - /* Copy values through direct validated reads and writes. */ - - duk_small_uint_t src_elem_size; - duk_small_uint_t dst_elem_size; - duk_uint8_t *p_src; - duk_uint8_t *p_src_end; - duk_uint8_t *p_dst; - - DUK_ASSERT(h_bufobj != NULL); - DUK_ASSERT(h_bufobj->buf != NULL); - DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj)); - DUK_ASSERT(h_bufarg != NULL); - DUK_ASSERT(h_bufarg->buf != NULL); - DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg)); - - src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift); - dst_elem_size = elem_size; - - p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); - p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj); - p_src_end = p_src + h_bufarg->length; - - DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, " - "src_elem_size=%d, dst_elem_size=%d", - (void *) p_src, (void *) p_src_end, (void *) p_dst, - (int) src_elem_size, (int) dst_elem_size)); - - while (p_src != p_src_end) { - DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: " - "p_src=%p, p_src_end=%p, p_dst=%p", - (void *) p_src, (void *) p_src_end, (void *) p_dst)); - /* A validated read() is always a number, so it's write coercion - * is always side effect free an won't invalidate pointers etc. - */ - duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size); - duk_hbufobj_validated_write(thr, h_bufobj, p_dst, dst_elem_size); - duk_pop(thr); - p_src += src_elem_size; - p_dst += dst_elem_size; - } - break; - } -#endif /* !DUK_USE_PREFER_SIZE */ - case 2: { - /* Copy values by index reads and writes. Let virtual - * property handling take care of coercion. - */ - duk_uint_t i; - - DUK_DDD(DUK_DDDPRINT("using slow copy")); - - for (i = 0; i < elem_length; i++) { - duk_get_prop_index(thr, 0, (duk_uarridx_t) i); - duk_put_prop_index(thr, -2, (duk_uarridx_t) i); - } - break; - } - default: - case 3: { - /* No copy, leave zero bytes in the buffer. There's no - * ambiguity with Float32/Float64 because zero bytes also - * represent 0.0. - */ - - DUK_DDD(DUK_DDDPRINT("using no copy")); - break; - } - } - - return 1; - - fail_arguments: - DUK_DCERROR_RANGE_INVALID_ARGS(thr); -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -/* When bufferobject support is disabled, new Uint8Array() could still be - * supported to create a plain fixed buffer. Disabled for now. - */ -#if 0 -DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) { - duk_int_t elem_length_signed; - duk_uint_t byte_length; - - /* XXX: The same copy helpers could be shared with at least some - * buffer functions. - */ - - duk_require_constructor_call(thr); - - elem_length_signed = duk_require_int(thr, 0); - if (elem_length_signed < 0) { - goto fail_arguments; - } - byte_length = (duk_uint_t) elem_length_signed; - - (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) byte_length); - return 1; - - fail_arguments: - DUK_DCERROR_RANGE_INVALID_ARGS(thr); -} -#endif /* 0 */ -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_hthread *thr) { - duk_hbufobj *h_bufarg; - duk_hbufobj *h_bufobj; - duk_hbuffer *h_val; - duk_uint_t offset; - duk_uint_t length; - - duk_require_constructor_call(thr); - - h_bufarg = duk__require_bufobj_value(thr, 0); - DUK_ASSERT(h_bufarg != NULL); - if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - - duk__resolve_offset_opt_length(thr, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/); - DUK_ASSERT(offset <= h_bufarg->length); - DUK_ASSERT(offset + length <= h_bufarg->length); - - h_bufobj = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW), - DUK_BIDX_DATAVIEW_PROTOTYPE); - - h_val = h_bufarg->buf; - if (h_val == NULL) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - h_bufobj->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_bufobj->offset = h_bufarg->offset + offset; - h_bufobj->length = length; - DUK_ASSERT(h_bufobj->shift == 0); - DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8); - DUK_ASSERT(h_bufobj->is_typedarray == 0); - - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_bufarg; - DUK_ASSERT(h_bufarg != NULL); - DUK_HBUFOBJ_INCREF(thr, h_bufarg); - - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * ArrayBuffer.isView() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_hthread *thr) { - duk_hobject *h_obj; - duk_bool_t ret = 0; - - if (duk_is_buffer(thr, 0)) { - ret = 1; - } else { - h_obj = duk_get_hobject(thr, 0); - if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) { - /* DataView needs special casing: ArrayBuffer.isView() is - * true, but ->is_typedarray is 0. - */ - ret = ((duk_hbufobj *) h_obj)->is_typedarray || - (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW); - } - } - duk_push_boolean(thr, ret); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Uint8Array.allocPlain() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_hthread *thr) { - duk__hbufobj_fixed_from_argvalue(thr); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Uint8Array.plainOf() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_hthread *thr) { - duk_hbufobj *h_bufobj; - -#if !defined(DUK_USE_PREFER_SIZE) - /* Avoid churn if argument is already a plain buffer. */ - if (duk_is_buffer(thr, 0)) { - return 1; - } -#endif - - /* Promotes plain buffers to ArrayBuffers, so for a plain buffer - * argument we'll create a pointless temporary (but still work - * correctly). - */ - h_bufobj = duk__require_bufobj_value(thr, 0); - if (h_bufobj->buf == NULL) { - duk_push_undefined(thr); - } else { - duk_push_hbuffer(thr, h_bufobj->buf); - } - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer: toString([encoding], [start], [end]) - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) { - duk_hbufobj *h_this; - duk_int_t start_offset, end_offset; - duk_uint8_t *buf_slice; - duk_size_t slice_length; - - h_this = duk__get_bufobj_this(thr); - if (h_this == NULL) { - /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */ - duk_push_string(thr, "[object Object]"); - return 1; - } - DUK_ASSERT_HBUFOBJ_VALID(h_this); - - /* Ignore encoding for now. */ - - duk__clamp_startend_nonegidx_noshift(thr, - (duk_int_t) h_this->length, - 1 /*idx_start*/, - 2 /*idx_end*/, - &start_offset, - &end_offset); - - slice_length = (duk_size_t) (end_offset - start_offset); - buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, slice_length); /* all bytes initialized below */ - DUK_ASSERT(buf_slice != NULL); - - /* Neutered or uncovered, TypeError. */ - if (h_this->buf == NULL || - !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - - /* XXX: ideally we wouldn't make a copy but a view into the buffer for the - * decoding process. Or the decoding helper could be changed to accept - * the slice info (a buffer pointer is NOT a good approach because guaranteeing - * its stability is difficult). - */ - - DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)); - DUK_MEMCPY((void *) buf_slice, - (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), - (size_t) slice_length); - - /* Use the equivalent of: new TextEncoder().encode(this) to convert the - * string. Result will be valid UTF-8; non-CESU-8 inputs are currently - * interpreted loosely. Value stack convention is a bit odd for now. - */ - duk_replace(thr, 0); - duk_set_top(thr, 1); - return duk_textdecoder_decode_utf8_nodejs(thr); -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.prototype: toJSON() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_hthread *thr) { - duk_hbufobj *h_this; - duk_uint8_t *buf; - duk_uint_t i, n; - duk_tval *tv; - - h_this = duk__require_bufobj_this(thr); - DUK_ASSERT(h_this != NULL); - - if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) { - /* Serialize uncovered backing buffer as a null; doesn't - * really matter as long we're memory safe. - */ - duk_push_null(thr); - return 1; - } - - duk_push_object(thr); - duk_push_hstring_stridx(thr, DUK_STRIDX_UC_BUFFER); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_TYPE); - - /* XXX: uninitialized would be OK */ - DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX); - tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */ - - DUK_ASSERT(h_this->buf != NULL); - buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); - for (i = 0, n = h_this->length; i < n; i++) { - DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]); /* no need for decref or incref */ - } - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_DATA); - - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.prototype.equals() - * Node.js Buffer.prototype.compare() - * Node.js Buffer.compare() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_hthread *thr) { - duk_small_uint_t magic; - duk_hbufobj *h_bufarg1; - duk_hbufobj *h_bufarg2; - duk_small_int_t comp_res; - - /* XXX: keep support for plain buffers and non-Node.js buffers? */ - - magic = (duk_small_uint_t) duk_get_current_magic(thr); - if (magic & 0x02U) { - /* Static call style. */ - h_bufarg1 = duk__require_bufobj_value(thr, 0); - h_bufarg2 = duk__require_bufobj_value(thr, 1); - } else { - h_bufarg1 = duk__require_bufobj_this(thr); - h_bufarg2 = duk__require_bufobj_value(thr, 0); - } - DUK_ASSERT(h_bufarg1 != NULL); - DUK_ASSERT(h_bufarg2 != NULL); - - /* We want to compare the slice/view areas of the arguments. - * If either slice/view is invalid (underlying buffer is shorter) - * ensure equals() is false, but otherwise the only thing that - * matters is to be memory safe. - */ - - if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg1) && - DUK_HBUFOBJ_VALID_SLICE(h_bufarg2)) { - comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset, - (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset, - (duk_size_t) h_bufarg1->length, - (duk_size_t) h_bufarg2->length); - } else { - comp_res = -1; /* either nonzero value is ok */ - } - - if (magic & 0x01U) { - /* compare: similar to string comparison but for buffer data. */ - duk_push_int(thr, comp_res); - } else { - /* equals */ - duk_push_boolean(thr, (comp_res == 0)); - } - - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.prototype.fill() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) { - duk_hbufobj *h_this; - const duk_uint8_t *fill_str_ptr; - duk_size_t fill_str_len; - duk_uint8_t fill_value; - duk_int_t fill_offset; - duk_int_t fill_end; - duk_size_t fill_length; - duk_uint8_t *p; - - h_this = duk__require_bufobj_this(thr); - DUK_ASSERT(h_this != NULL); - if (h_this->buf == NULL) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - - /* [ value offset end ] */ - - if (duk_is_string_notsymbol(thr, 0)) { - fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(thr, 0, &fill_str_len); - DUK_ASSERT(fill_str_ptr != NULL); - } else { - /* Symbols get ToNumber() coerced and cause TypeError. */ - fill_value = (duk_uint8_t) duk_to_uint32(thr, 0); - fill_str_ptr = (const duk_uint8_t *) &fill_value; - fill_str_len = 1; - } - - /* Fill offset handling is more lenient than in Node.js. */ - - duk__clamp_startend_nonegidx_noshift(thr, - (duk_int_t) h_this->length, - 1 /*idx_start*/, - 2 /*idx_end*/, - &fill_offset, - &fill_end); - - DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld", - (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length)); - - DUK_ASSERT(fill_end - fill_offset >= 0); - DUK_ASSERT(h_this->buf != NULL); - - p = (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + fill_offset); - fill_length = (duk_size_t) (fill_end - fill_offset); - if (fill_str_len == 1) { - /* Handle single character fills as memset() even when - * the fill data comes from a one-char argument. - */ - DUK_MEMSET((void *) p, (int) fill_str_ptr[0], (size_t) fill_length); - } else if (fill_str_len > 1) { - duk_size_t i, n, t; - - for (i = 0, n = (duk_size_t) (fill_end - fill_offset), t = 0; i < n; i++) { - p[i] = fill_str_ptr[t++]; - if (t >= fill_str_len) { - t = 0; - } - } - } else { - DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently")); - } - - /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */ - duk_push_this(thr); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.prototype.write(string, [offset], [length], [encoding]) - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) { - duk_hbufobj *h_this; - duk_uint_t offset; - duk_uint_t length; - const duk_uint8_t *str_data; - duk_size_t str_len; - - /* XXX: very inefficient support for plain buffers */ - h_this = duk__require_bufobj_this(thr); - DUK_ASSERT(h_this != NULL); - - /* Argument must be a string, e.g. a buffer is not allowed. */ - str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(thr, 0, &str_len); - - duk__resolve_offset_opt_length(thr, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/); - DUK_ASSERT(offset <= h_this->length); - DUK_ASSERT(offset + length <= h_this->length); - - /* XXX: encoding is ignored now. */ - - if (length > str_len) { - length = (duk_uint_t) str_len; - } - - if (DUK_HBUFOBJ_VALID_SLICE(h_this)) { - /* Cannot overlap. */ - DUK_MEMCPY((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset), - (const void *) str_data, - (size_t) length); - } else { - DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore")); - } - - duk_push_uint(thr, length); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.prototype.copy() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) { - duk_hbufobj *h_this; - duk_hbufobj *h_bufarg; - duk_int_t source_length; - duk_int_t target_length; - duk_int_t target_start, source_start, source_end; - duk_uint_t target_ustart, source_ustart, source_uend; - duk_uint_t copy_size = 0; - - /* [ targetBuffer targetStart sourceStart sourceEnd ] */ - - h_this = duk__require_bufobj_this(thr); - h_bufarg = duk__require_bufobj_value(thr, 0); - DUK_ASSERT(h_this != NULL); - DUK_ASSERT(h_bufarg != NULL); - source_length = (duk_int_t) h_this->length; - target_length = (duk_int_t) h_bufarg->length; - - target_start = duk_to_int(thr, 1); - source_start = duk_to_int(thr, 2); - if (duk_is_undefined(thr, 3)) { - source_end = source_length; - } else { - source_end = duk_to_int(thr, 3); - } - - DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, " - "source_start=%ld, source_end=%ld, source_length=%ld", - (long) target_start, (long) h_bufarg->length, - (long) source_start, (long) source_end, (long) source_length)); - - /* This behavior mostly mimics Node.js now. */ - - if (source_start < 0 || source_end < 0 || target_start < 0) { - /* Negative offsets cause a RangeError. */ - goto fail_bounds; - } - source_ustart = (duk_uint_t) source_start; - source_uend = (duk_uint_t) source_end; - target_ustart = (duk_uint_t) target_start; - if (source_ustart >= source_uend || /* crossed offsets or zero size */ - source_ustart >= (duk_uint_t) source_length || /* source out-of-bounds (but positive) */ - target_ustart >= (duk_uint_t) target_length) { /* target out-of-bounds (but positive) */ - goto silent_ignore; - } - if (source_uend >= (duk_uint_t) source_length) { - /* Source end clamped silently to available length. */ - source_uend = (duk_uint_t) source_length; - } - copy_size = source_uend - source_ustart; - if (target_ustart + copy_size > (duk_uint_t) target_length) { - /* Clamp to target's end if too long. - * - * NOTE: there's no overflow possibility in the comparison; - * both target_ustart and copy_size are >= 0 and based on - * values in duk_int_t range. Adding them as duk_uint_t - * values is then guaranteed not to overflow. - */ - DUK_ASSERT(target_ustart + copy_size >= target_ustart); /* no overflow */ - DUK_ASSERT(target_ustart + copy_size >= copy_size); /* no overflow */ - copy_size = (duk_uint_t) target_length - target_ustart; - } - - DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu", - (unsigned long) target_ustart, (unsigned long) source_ustart, - (unsigned long) copy_size)); - - DUK_ASSERT(copy_size >= 1); - DUK_ASSERT(source_ustart <= (duk_uint_t) source_length); - DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length); - DUK_ASSERT(target_ustart <= (duk_uint_t) target_length); - DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length); - - /* Ensure copy is covered by underlying buffers. */ - DUK_ASSERT(h_bufarg->buf != NULL); /* length check */ - DUK_ASSERT(h_this->buf != NULL); /* length check */ - if (DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) && - DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) { - /* Must use memmove() because copy area may overlap (source and target - * buffer may be the same, or from different slices. - */ - DUK_MEMMOVE((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart), - (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart), - (size_t) copy_size); - } else { - DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring")); - } - - silent_ignore: - /* Return value is like write(), number of bytes written. - * The return value matters because of code like: - * "off += buf.copy(...)". - */ - duk_push_uint(thr, copy_size); - return 1; - - fail_bounds: - DUK_DCERROR_RANGE_INVALID_ARGS(thr); -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * TypedArray.prototype.set() - * - * TypedArray set() is pretty interesting to implement because: - * - * - The source argument may be a plain array or a typedarray. If the - * source is a TypedArray, values are decoded and re-encoded into the - * target (not as a plain byte copy). This may happen even when the - * element byte size is the same, e.g. integer values may be re-encoded - * into floats. - * - * - Source and target may refer to the same underlying buffer, so that - * the set() operation may overlap. The specification requires that this - * must work as if a copy was made before the operation. Note that this - * is NOT a simple memmove() situation because the source and target - * byte sizes may be different -- e.g. a 4-byte source (Int8Array) may - * expand to a 16-byte target (Uint32Array) so that the target overlaps - * the source both from beginning and the end (unlike in typical memmove). - * - * - Even if 'buf' pointers of the source and target differ, there's no - * guarantee that their memory areas don't overlap. This may be the - * case with external buffers. - * - * Even so, it is nice to optimize for the common case: - * - * - Source and target separate buffers or non-overlapping. - * - * - Source and target have a compatible type so that a plain byte copy - * is possible. Note that while e.g. uint8 and int8 are compatible - * (coercion one way or another doesn't change the byte representation), - * e.g. int8 and uint8clamped are NOT compatible when writing int8 - * values into uint8clamped typedarray (-1 would clamp to 0 for instance). - * - * See test-bi-typedarray-proto-set.js. - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) { - duk_hbufobj *h_this; - duk_hobject *h_obj; - duk_uarridx_t i, n; - duk_int_t offset_signed; - duk_uint_t offset_elems; - duk_uint_t offset_bytes; - - h_this = duk__require_bufobj_this(thr); - DUK_ASSERT(h_this != NULL); - DUK_ASSERT_HBUFOBJ_VALID(h_this); - - if (h_this->buf == NULL) { - DUK_DDD(DUK_DDDPRINT("source neutered, skip copy")); - return 0; - } - - duk_hbufobj_promote_plain(thr, 0); - h_obj = duk_require_hobject(thr, 0); - - /* XXX: V8 throws a TypeError for negative values. Would it - * be more useful to interpret negative offsets here from the - * end of the buffer too? - */ - offset_signed = duk_to_int(thr, 1); - if (offset_signed < 0) { - /* For some reason this is a TypeError (at least in V8). */ - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - offset_elems = (duk_uint_t) offset_signed; - offset_bytes = offset_elems << h_this->shift; - if ((offset_bytes >> h_this->shift) != offset_elems) { - /* Byte length would overflow. */ - /* XXX: easier check with less code? */ - goto fail_args; - } - if (offset_bytes > h_this->length) { - /* Equality may be OK but >length not. Checking - * this explicitly avoids some overflow cases - * below. - */ - goto fail_args; - } - DUK_ASSERT(offset_bytes <= h_this->length); - - /* Fast path: source is a TypedArray (or any bufobj). */ - - if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { - duk_hbufobj *h_bufarg; -#if !defined(DUK_USE_PREFER_SIZE) - duk_uint16_t comp_mask; -#endif - duk_small_int_t no_overlap = 0; - duk_uint_t src_length; - duk_uint_t dst_length; - duk_uint_t dst_length_elems; - duk_uint8_t *p_src_base; - duk_uint8_t *p_src_end; - duk_uint8_t *p_src; - duk_uint8_t *p_dst_base; - duk_uint8_t *p_dst; - duk_small_uint_t src_elem_size; - duk_small_uint_t dst_elem_size; - - h_bufarg = (duk_hbufobj *) h_obj; - DUK_ASSERT_HBUFOBJ_VALID(h_bufarg); - - if (h_bufarg->buf == NULL) { - DUK_DDD(DUK_DDDPRINT("target neutered, skip copy")); - return 0; - } - - /* Nominal size check. */ - src_length = h_bufarg->length; /* bytes in source */ - dst_length_elems = (src_length >> h_bufarg->shift); /* elems in source and dest */ - dst_length = dst_length_elems << h_this->shift; /* bytes in dest */ - if ((dst_length >> h_this->shift) != dst_length_elems) { - /* Byte length would overflow. */ - /* XXX: easier check with less code? */ - goto fail_args; - } - DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld", - (long) src_length, (long) dst_length)); - DUK_ASSERT(offset_bytes <= h_this->length); - if (dst_length > h_this->length - offset_bytes) { - /* Overflow not an issue because subtraction is used on the right - * side and guaranteed to be >= 0. - */ - DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length")); - goto fail_args; - } - if (!DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) { - DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore")); - return 0; - } - - p_src_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); - p_dst_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes; - - /* Check actual underlying buffers for validity and that they - * cover the copy. No side effects are allowed after the check - * so that the validity status doesn't change. - */ - if (!DUK_HBUFOBJ_VALID_SLICE(h_this) || - !DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) { - /* The condition could be more narrow and check for the - * copy area only, but there's no need for fine grained - * behavior when the underlying buffer is misconfigured. - */ - DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy")); - return 0; - } - - /* We want to do a straight memory copy if possible: this is - * an important operation because .set() is the TypedArray - * way to copy chunks of memory. However, because set() - * conceptually works in terms of elements, not all views are - * compatible with direct byte copying. - * - * If we do manage a direct copy, the "overlap issue" handled - * below can just be solved using memmove() because the source - * and destination element sizes are necessarily equal. - */ - -#if !defined(DUK_USE_PREFER_SIZE) - DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t)); - comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type]; - if (comp_mask & (1 << h_bufarg->elem_type)) { - DUK_ASSERT(src_length == dst_length); - - DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible")); - DUK_MEMMOVE((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length); - return 0; - } - DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item")); -#endif /* !DUK_USE_PREFER_SIZE */ - - /* We want to avoid making a copy to process set() but that's - * not always possible: the source and the target may overlap - * and because element sizes are different, the overlap cannot - * always be handled with a memmove() or choosing the copy - * direction in a certain way. For example, if source type is - * uint8 and target type is uint32, the target area may exceed - * the source area from both ends! - * - * Note that because external buffers may point to the same - * memory areas, we must ultimately make this check using - * pointers. - * - * NOTE: careful with side effects: any side effect may cause - * a buffer resize (or external buffer pointer/length update)! - */ - - DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, " - "p_dst_base=%p, dst_length=%ld", - (void *) p_src_base, (long) src_length, - (void *) p_dst_base, (long) dst_length)); - - if (p_src_base >= p_dst_base + dst_length || /* source starts after dest ends */ - p_src_base + src_length <= p_dst_base) { /* source ends before dest starts */ - no_overlap = 1; - } - - if (!no_overlap) { - /* There's overlap: the desired end result is that - * conceptually a copy is made to avoid "trampling" - * of source data by destination writes. We make - * an actual temporary copy to handle this case. - */ - duk_uint8_t *p_src_copy; - - DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source")); - p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length); - DUK_ASSERT(p_src_copy != NULL); - DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length); - - p_src_base = p_src_copy; /* use p_src_base from now on */ - } - /* Value stack intentionally mixed size here. */ - - DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, " - "p_dst_base=%p, dst_length=%ld, valstack top=%ld", - (void *) p_src_base, (long) src_length, - (void *) p_dst_base, (long) dst_length, - (long) duk_get_top(thr))); - - /* Ready to make the copy. We must proceed element by element - * and must avoid any side effects that might cause the buffer - * validity check above to become invalid. - * - * Although we work through the value stack here, only plain - * numbers are handled which should be side effect safe. - */ - - src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift); - dst_elem_size = (duk_small_uint_t) (1U << h_this->shift); - p_src = p_src_base; - p_dst = p_dst_base; - p_src_end = p_src_base + src_length; - - while (p_src != p_src_end) { - DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: " - "p_src=%p, p_src_end=%p, p_dst=%p", - (void *) p_src, (void *) p_src_end, (void *) p_dst)); - /* A validated read() is always a number, so it's write coercion - * is always side effect free an won't invalidate pointers etc. - */ - duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size); - duk_hbufobj_validated_write(thr, h_this, p_dst, dst_elem_size); - duk_pop(thr); - p_src += src_elem_size; - p_dst += dst_elem_size; - } - - return 0; - } else { - /* Slow path: quite slow, but we save space by using the property code - * to write coerce target values. We don't need to worry about overlap - * here because the source is not a TypedArray. - * - * We could use the bufobj write coercion helper but since the - * property read may have arbitrary side effects, full validity checks - * would be needed for every element anyway. - */ - - n = (duk_uarridx_t) duk_get_length(thr, 0); - DUK_ASSERT(offset_bytes <= h_this->length); - if ((n << h_this->shift) > h_this->length - offset_bytes) { - /* Overflow not an issue because subtraction is used on the right - * side and guaranteed to be >= 0. - */ - DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length")); - goto fail_args; - } - - /* There's no need to check for buffer validity status for the - * target here: the property access code will do that for each - * element. Moreover, if we did check the validity here, side - * effects from reading the source argument might invalidate - * the results anyway. - */ - - DUK_ASSERT_TOP(thr, 2); - duk_push_this(thr); - - for (i = 0; i < n; i++) { - duk_get_prop_index(thr, 0, i); - duk_put_prop_index(thr, 2, offset_elems + i); - } - } - - return 0; - - fail_args: - DUK_DCERROR_RANGE_INVALID_ARGS(thr); -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.prototype.slice([start], [end]) - * ArrayBuffer.prototype.slice(begin, [end]) - * TypedArray.prototype.subarray(begin, [end]) - * - * The API calls are almost identical; negative indices are counted from end - * of buffer, and final indices are clamped (allowing crossed indices). Main - * differences: - * - * - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create - * views, ArrayBuffer .slice() creates a copy - * - * - Resulting object has a different class and prototype depending on the - * call (or 'this' argument) - * - * - TypedArray .subarray() arguments are element indices, not byte offsets - * - * - Plain buffer argument creates a plain buffer slice - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val) { - duk_int_t start_offset, end_offset; - duk_uint_t slice_length; - duk_uint8_t *p_copy; - duk_size_t copy_length; - - duk__clamp_startend_negidx_shifted(thr, - (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val), - 0 /*buffer_shift*/, - 0 /*idx_start*/, - 1 /*idx_end*/, - &start_offset, - &end_offset); - DUK_ASSERT(end_offset <= (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val)); - DUK_ASSERT(start_offset >= 0); - DUK_ASSERT(end_offset >= start_offset); - slice_length = (duk_uint_t) (end_offset - start_offset); - - p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) slice_length); - DUK_ASSERT(p_copy != NULL); - copy_length = slice_length; - - DUK_MEMCPY((void *) p_copy, - (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset), - copy_length); -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Shared helper for slice/subarray operation. - * Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling. - */ -DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) { - duk_small_int_t magic; - duk_small_uint_t res_class_num; - duk_small_int_t res_proto_bidx; - duk_hbufobj *h_this; - duk_hbufobj *h_bufobj; - duk_hbuffer *h_val; - duk_int_t start_offset, end_offset; - duk_uint_t slice_length; - duk_tval *tv; - - /* [ start end ] */ - - magic = duk_get_current_magic(thr); - - tv = duk_get_borrowed_this_tval(thr); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_BUFFER(tv)) { - /* For plain buffers return a plain buffer slice. */ - h_val = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h_val != NULL); - - if (magic & 0x02) { - /* Make copy: ArrayBuffer.prototype.slice() uses this. */ - duk__arraybuffer_plain_slice(thr, h_val); - return 1; - } else { - /* View into existing buffer: cannot be done if the - * result is a plain buffer because there's no slice - * info. So return an ArrayBuffer instance; coerce - * the 'this' binding into an object and behave as if - * the original call was for an Object-coerced plain - * buffer (handled automatically by duk__require_bufobj_this()). - */ - - DUK_DDD(DUK_DDDPRINT("slice() doesn't handle view into plain buffer, coerce 'this' to ArrayBuffer object")); - /* fall through */ - } - } - tv = NULL; /* No longer valid nor needed. */ - - h_this = duk__require_bufobj_this(thr); - - /* Slice offsets are element (not byte) offsets, which only matters - * for TypedArray views, Node.js Buffer and ArrayBuffer have shift - * zero so byte and element offsets are the same. Negative indices - * are counted from end of slice, crossed indices are allowed (and - * result in zero length result), and final values are clamped - * against the current slice. There's intentionally no check - * against the underlying buffer here. - */ - - duk__clamp_startend_negidx_shifted(thr, - (duk_int_t) h_this->length, - (duk_uint8_t) h_this->shift, - 0 /*idx_start*/, - 1 /*idx_end*/, - &start_offset, - &end_offset); - DUK_ASSERT(end_offset >= start_offset); - DUK_ASSERT(start_offset >= 0); - DUK_ASSERT(end_offset >= 0); - slice_length = (duk_uint_t) (end_offset - start_offset); - - /* The resulting buffer object gets the same class and prototype as - * the buffer in 'this', e.g. if the input is a Uint8Array the - * result is a Uint8Array; if the input is a Float32Array, the - * result is a Float32Array. The result internal prototype should - * be the default prototype for the class (e.g. initial value of - * Uint8Array.prototype), not copied from the argument (Duktape 1.x - * did that). - * - * Node.js Buffers have special handling: they're Uint8Arrays as far - * as the internal class is concerned, so the new Buffer should also - * be an Uint8Array but inherit from Buffer.prototype. - */ - res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this); - DUK_ASSERT(res_class_num >= DUK_HOBJECT_CLASS_BUFOBJ_MIN); /* type check guarantees */ - DUK_ASSERT(res_class_num <= DUK_HOBJECT_CLASS_BUFOBJ_MAX); - res_proto_bidx = duk__buffer_proto_from_classnum[res_class_num - DUK_HOBJECT_CLASS_BUFOBJ_MIN]; - if (magic & 0x04) { - res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE; - } - h_bufobj = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num), - res_proto_bidx); - DUK_ASSERT(h_bufobj != NULL); - - DUK_ASSERT(h_bufobj->length == 0); - h_bufobj->shift = h_this->shift; /* inherit */ - h_bufobj->elem_type = h_this->elem_type; /* inherit */ - h_bufobj->is_typedarray = magic & 0x01; - DUK_ASSERT(h_bufobj->is_typedarray == 0 || h_bufobj->is_typedarray == 1); - - h_val = h_this->buf; - if (h_val == NULL) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - - if (magic & 0x02) { - /* non-zero: make copy */ - duk_uint8_t *p_copy; - duk_size_t copy_length; - - p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */ - DUK_ASSERT(p_copy != NULL); - - /* Copy slice, respecting underlying buffer limits; remainder - * is left as zero. - */ - copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length); - DUK_MEMCPY((void *) p_copy, - (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), - copy_length); - - h_val = duk_known_hbuffer(thr, -1); - - h_bufobj->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_bufobj->length = slice_length; - DUK_ASSERT(h_bufobj->offset == 0); - - duk_pop(thr); /* reachable so pop OK */ - } else { - h_bufobj->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_bufobj->length = slice_length; - h_bufobj->offset = h_this->offset + (duk_uint_t) start_offset; - - /* Copy the .buffer property, needed for TypedArray.prototype.subarray(). - * - * XXX: limit copy only for TypedArray classes specifically? - */ - - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = h_this->buf_prop; /* may be NULL */ - DUK_HOBJECT_INCREF_ALLOWNULL(thr, (duk_hobject *) h_bufobj->buf_prop); - } - /* unbalanced stack on purpose */ - - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.isEncoding() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_hthread *thr) { - const char *encoding; - - /* only accept lowercase 'utf8' now. */ - - encoding = duk_to_string(thr, 0); - DUK_ASSERT(duk_is_string(thr, 0)); /* guaranteed by duk_to_string() */ - duk_push_boolean(thr, DUK_STRCMP(encoding, "utf8") == 0); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.isBuffer() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_hthread *thr) { - duk_hobject *h; - duk_hobject *h_proto; - duk_bool_t ret = 0; - - DUK_ASSERT(duk_get_top(thr) >= 1); /* nargs */ - h = duk_get_hobject(thr, 0); - if (h != NULL) { - h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE]; - DUK_ASSERT(h_proto != NULL); - - h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - if (h != NULL) { - ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/); - } - } - - duk_push_boolean(thr, ret); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.byteLength() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_hthread *thr) { - const char *str; - duk_size_t len; - - /* At the moment Buffer() will just use the string bytes as - * is (ignoring encoding), so we return the string length here - * unconditionally. - */ - - /* XXX: to be revised; Old Node.js behavior just coerces any buffer - * values to string: - * $ node - * > Buffer.byteLength(new Uint32Array(10)) - * 20 - * > Buffer.byteLength(new Uint32Array(100)) - * 20 - * (The 20 comes from '[object Uint32Array]'.length - */ - - str = duk_to_lstring(thr, 0, &len); - DUK_UNREF(str); - duk_push_size_t(thr, len); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Node.js Buffer.concat() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) { - duk_hobject *h_arg; - duk_uint_t total_length; - duk_hbufobj *h_bufobj; - duk_hbufobj *h_bufres; - duk_hbuffer *h_val; - duk_uint_t i, n; - duk_uint8_t *p; - duk_size_t space_left; - duk_size_t copy_size; - - /* Node.js accepts only actual Arrays. */ - h_arg = duk_require_hobject(thr, 0); - if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - - /* Compute result length and validate argument buffers. */ - n = (duk_uint_t) duk_get_length(thr, 0); - total_length = 0; - for (i = 0; i < n; i++) { - /* Neutered checks not necessary here: neutered buffers have - * zero 'length' so we'll effectively skip them. - */ - DUK_ASSERT_TOP(thr, 2); /* [ array totalLength ] */ - duk_get_prop_index(thr, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */ - h_bufobj = duk__require_bufobj_value(thr, 2); - DUK_ASSERT(h_bufobj != NULL); - total_length += h_bufobj->length; - if (DUK_UNLIKELY(total_length < h_bufobj->length)) { - DUK_DCERROR_RANGE_INVALID_ARGS(thr); /* Wrapped. */ - } - duk_pop(thr); - } - /* In Node.js v0.12.1 a 1-element array is special and won't create a - * copy, this was fixed later so an explicit check no longer needed. - */ - - /* User totalLength overrides a computed length, but we'll check - * every copy in the copy loop. Note that duk_to_int() can - * technically have arbitrary side effects so we need to recheck - * the buffers in the copy loop. - */ - if (!duk_is_undefined(thr, 1) && n > 0) { - /* For n == 0, Node.js ignores totalLength argument and - * returns a zero length buffer. - */ - duk_int_t total_length_signed; - total_length_signed = duk_to_int(thr, 1); - if (total_length_signed < 0) { - DUK_DCERROR_RANGE_INVALID_ARGS(thr); - } - total_length = (duk_uint_t) total_length_signed; - } - - h_bufres = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY), - DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); - DUK_ASSERT(h_bufres != NULL); - - p = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, total_length); /* must be zeroed, all bytes not necessarily written over */ - DUK_ASSERT(p != NULL); - space_left = (duk_size_t) total_length; - - for (i = 0; i < n; i++) { - DUK_ASSERT_TOP(thr, 4); /* [ array totalLength bufres buf ] */ - - duk_get_prop_index(thr, 0, (duk_uarridx_t) i); - h_bufobj = duk__require_bufobj_value(thr, 4); - DUK_ASSERT(h_bufobj != NULL); - - copy_size = h_bufobj->length; - if (copy_size > space_left) { - copy_size = space_left; - } - - if (h_bufobj->buf != NULL && - DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { - DUK_MEMCPY((void *) p, - (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj), - copy_size); - } else { - /* Just skip, leaving zeroes in the result. */ - ; - } - p += copy_size; - space_left -= copy_size; - - duk_pop(thr); - } - - h_val = duk_known_hbuffer(thr, -1); - - duk__set_bufobj_buffer(thr, h_bufres, h_val); - h_bufres->is_typedarray = 1; - DUK_ASSERT_HBUFOBJ_VALID(h_bufres); - - duk_pop(thr); /* pop plain buffer, now reachable through h_bufres */ - - return 1; /* return h_bufres */ -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Shared readfield and writefield methods - * - * The readfield/writefield methods need support for endianness and field - * types. All offsets are byte based so no offset shifting is needed. - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Format of magic, bits: - * 0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused - * 3: endianness: 0=little, 1=big - * 4: signed: 1=yes, 0=no - * 5: typedarray: 1=yes, 0=no - */ -#define DUK__FLD_8BIT 0 -#define DUK__FLD_16BIT 1 -#define DUK__FLD_32BIT 2 -#define DUK__FLD_FLOAT 3 -#define DUK__FLD_DOUBLE 4 -#define DUK__FLD_VARINT 5 -#define DUK__FLD_BIGENDIAN (1 << 3) -#define DUK__FLD_SIGNED (1 << 4) -#define DUK__FLD_TYPEDARRAY (1 << 5) - -/* XXX: split into separate functions for each field type? */ -DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) { - duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr); - duk_small_int_t magic_ftype; - duk_small_int_t magic_bigendian; - duk_small_int_t magic_signed; - duk_small_int_t magic_typedarray; - duk_small_int_t endswap; - duk_hbufobj *h_this; - duk_bool_t no_assert; - duk_int_t offset_signed; - duk_uint_t offset; - duk_uint_t buffer_length; - duk_uint_t check_length; - duk_uint8_t *buf; - duk_double_union du; - - magic_ftype = magic & 0x0007; - magic_bigendian = magic & 0x0008; - magic_signed = magic & 0x0010; - magic_typedarray = magic & 0x0020; - - h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */ - DUK_ASSERT(h_this != NULL); - buffer_length = h_this->length; - - /* [ offset noAssert ], when ftype != DUK__FLD_VARINT */ - /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */ - /* [ offset littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */ - - /* Handle TypedArray vs. Node.js Buffer arg differences */ - if (magic_typedarray) { - no_assert = 0; -#if defined(DUK_USE_INTEGER_LE) - endswap = !duk_to_boolean(thr, 1); /* 1=little endian */ -#else - endswap = duk_to_boolean(thr, 1); /* 1=little endian */ -#endif - } else { - no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1); -#if defined(DUK_USE_INTEGER_LE) - endswap = magic_bigendian; -#else - endswap = !magic_bigendian; -#endif - } - - /* Offset is coerced first to signed integer range and then to unsigned. - * This ensures we can add a small byte length (1-8) to the offset in - * bound checks and not wrap. - */ - offset_signed = duk_to_int(thr, 0); - offset = (duk_uint_t) offset_signed; - if (offset_signed < 0) { - goto fail_bounds; - } - - DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, " - "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, " - "endswap=%d", - (long) buffer_length, (long) offset, (int) no_assert, - (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3), - (int) (magic_signed >> 4), (int) endswap)); - - /* Update 'buffer_length' to be the effective, safe limit which - * takes into account the underlying buffer. This value will be - * potentially invalidated by any side effect. - */ - check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length); - DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld", - (long) buffer_length, (long) check_length)); - - if (h_this->buf) { - buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); - } else { - /* Neutered. We could go into the switch-case safely with - * buf == NULL because check_length == 0. To avoid scanbuild - * warnings, fail directly instead. - */ - DUK_ASSERT(check_length == 0); - goto fail_neutered; - } - DUK_ASSERT(buf != NULL); - - switch (magic_ftype) { - case DUK__FLD_8BIT: { - duk_uint8_t tmp; - if (offset + 1U > check_length) { - goto fail_bounds; - } - tmp = buf[offset]; - if (magic_signed) { - duk_push_int(thr, (duk_int_t) ((duk_int8_t) tmp)); - } else { - duk_push_uint(thr, (duk_uint_t) tmp); - } - break; - } - case DUK__FLD_16BIT: { - duk_uint16_t tmp; - if (offset + 2U > check_length) { - goto fail_bounds; - } - DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 2); - tmp = du.us[0]; - if (endswap) { - tmp = DUK_BSWAP16(tmp); - } - if (magic_signed) { - duk_push_int(thr, (duk_int_t) ((duk_int16_t) tmp)); - } else { - duk_push_uint(thr, (duk_uint_t) tmp); - } - break; - } - case DUK__FLD_32BIT: { - duk_uint32_t tmp; - if (offset + 4U > check_length) { - goto fail_bounds; - } - DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4); - tmp = du.ui[0]; - if (endswap) { - tmp = DUK_BSWAP32(tmp); - } - if (magic_signed) { - duk_push_int(thr, (duk_int_t) ((duk_int32_t) tmp)); - } else { - duk_push_uint(thr, (duk_uint_t) tmp); - } - break; - } - case DUK__FLD_FLOAT: { - duk_uint32_t tmp; - if (offset + 4U > check_length) { - goto fail_bounds; - } - DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4); - if (endswap) { - tmp = du.ui[0]; - tmp = DUK_BSWAP32(tmp); - du.ui[0] = tmp; - } - duk_push_number(thr, (duk_double_t) du.f[0]); - break; - } - case DUK__FLD_DOUBLE: { - if (offset + 8U > check_length) { - goto fail_bounds; - } - DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 8); - if (endswap) { - DUK_DBLUNION_BSWAP64(&du); - } - duk_push_number(thr, (duk_double_t) du.d); - break; - } - case DUK__FLD_VARINT: { - /* Node.js Buffer variable width integer field. We don't really - * care about speed here, so aim for shortest algorithm. - */ - duk_int_t field_bytelen; - duk_int_t i, i_step, i_end; -#if defined(DUK_USE_64BIT_OPS) - duk_int64_t tmp; - duk_small_uint_t shift_tmp; -#else - duk_double_t tmp; - duk_small_int_t highbyte; -#endif - const duk_uint8_t *p; - - field_bytelen = duk_get_int(thr, 1); /* avoid side effects! */ - if (field_bytelen < 1 || field_bytelen > 6) { - goto fail_field_length; - } - if (offset + (duk_uint_t) field_bytelen > check_length) { - goto fail_bounds; - } - p = (const duk_uint8_t *) (buf + offset); - - /* Slow gathering of value using either 64-bit arithmetic - * or IEEE doubles if 64-bit types not available. Handling - * of negative numbers is a bit non-obvious in both cases. - */ - - if (magic_bigendian) { - /* Gather in big endian */ - i = 0; - i_step = 1; - i_end = field_bytelen; /* one i_step over */ - } else { - /* Gather in little endian */ - i = field_bytelen - 1; - i_step = -1; - i_end = -1; /* one i_step over */ - } - -#if defined(DUK_USE_64BIT_OPS) - tmp = 0; - do { - DUK_ASSERT(i >= 0 && i < field_bytelen); - tmp = (tmp << 8) + (duk_int64_t) p[i]; - i += i_step; - } while (i != i_end); - - if (magic_signed) { - /* Shift to sign extend. */ - shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U); - tmp = (tmp << shift_tmp) >> shift_tmp; - } - - duk_push_i64(thr, tmp); -#else - highbyte = p[i]; - if (magic_signed && (highbyte & 0x80) != 0) { - /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */ - tmp = (duk_double_t) (highbyte - 256); - } else { - tmp = (duk_double_t) highbyte; - } - for (;;) { - i += i_step; - if (i == i_end) { - break; - } - DUK_ASSERT(i >= 0 && i < field_bytelen); - tmp = (tmp * 256.0) + (duk_double_t) p[i]; - } - - duk_push_number(thr, tmp); -#endif - break; - } - default: { /* should never happen but default here */ - goto fail_bounds; - } - } - - return 1; - - fail_neutered: - fail_field_length: - fail_bounds: - if (no_assert) { - /* Node.js return value for noAssert out-of-bounds reads is - * usually (but not always) NaN. Return NaN consistently. - */ - duk_push_nan(thr); - return 1; - } - DUK_DCERROR_RANGE_INVALID_ARGS(thr); -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* XXX: split into separate functions for each field type? */ -DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) { - duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr); - duk_small_int_t magic_ftype; - duk_small_int_t magic_bigendian; - duk_small_int_t magic_signed; - duk_small_int_t magic_typedarray; - duk_small_int_t endswap; - duk_hbufobj *h_this; - duk_bool_t no_assert; - duk_int_t offset_signed; - duk_uint_t offset; - duk_uint_t buffer_length; - duk_uint_t check_length; - duk_uint8_t *buf; - duk_double_union du; - duk_int_t nbytes = 0; - - magic_ftype = magic & 0x0007; - magic_bigendian = magic & 0x0008; - magic_signed = magic & 0x0010; - magic_typedarray = magic & 0x0020; - DUK_UNREF(magic_signed); - - h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */ - DUK_ASSERT(h_this != NULL); - buffer_length = h_this->length; - - /* [ value offset noAssert ], when ftype != DUK__FLD_VARINT */ - /* [ value offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */ - /* [ offset value littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */ - - /* Handle TypedArray vs. Node.js Buffer arg differences */ - if (magic_typedarray) { - no_assert = 0; -#if defined(DUK_USE_INTEGER_LE) - endswap = !duk_to_boolean(thr, 2); /* 1=little endian */ -#else - endswap = duk_to_boolean(thr, 2); /* 1=little endian */ -#endif - duk_swap(thr, 0, 1); /* offset/value order different from Node.js */ - } else { - no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2); -#if defined(DUK_USE_INTEGER_LE) - endswap = magic_bigendian; -#else - endswap = !magic_bigendian; -#endif - } - - /* Offset is coerced first to signed integer range and then to unsigned. - * This ensures we can add a small byte length (1-8) to the offset in - * bound checks and not wrap. - */ - offset_signed = duk_to_int(thr, 1); - offset = (duk_uint_t) offset_signed; - - /* We need 'nbytes' even for a failed offset; return value must be - * (offset + nbytes) even when write fails due to invalid offset. - */ - if (magic_ftype != DUK__FLD_VARINT) { - DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t))); - nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype]; - } else { - nbytes = duk_get_int(thr, 2); - if (nbytes < 1 || nbytes > 6) { - goto fail_field_length; - } - } - DUK_ASSERT(nbytes >= 1 && nbytes <= 8); - - /* Now we can check offset validity. */ - if (offset_signed < 0) { - goto fail_bounds; - } - - DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, " - "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, " - "endswap=%d", - duk_get_tval(thr, 0), (long) buffer_length, (long) offset, (int) no_assert, - (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3), - (int) (magic_signed >> 4), (int) endswap)); - - /* Coerce value to a number before computing check_length, so that - * the field type specific coercion below can't have side effects - * that would invalidate check_length. - */ - duk_to_number(thr, 0); - - /* Update 'buffer_length' to be the effective, safe limit which - * takes into account the underlying buffer. This value will be - * potentially invalidated by any side effect. - */ - check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length); - DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld", - (long) buffer_length, (long) check_length)); - - if (h_this->buf) { - buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); - } else { - /* Neutered. We could go into the switch-case safely with - * buf == NULL because check_length == 0. To avoid scanbuild - * warnings, fail directly instead. - */ - DUK_ASSERT(check_length == 0); - goto fail_neutered; - } - DUK_ASSERT(buf != NULL); - - switch (magic_ftype) { - case DUK__FLD_8BIT: { - if (offset + 1U > check_length) { - goto fail_bounds; - } - /* sign doesn't matter when writing */ - buf[offset] = (duk_uint8_t) duk_to_uint32(thr, 0); - break; - } - case DUK__FLD_16BIT: { - duk_uint16_t tmp; - if (offset + 2U > check_length) { - goto fail_bounds; - } - tmp = (duk_uint16_t) duk_to_uint32(thr, 0); - if (endswap) { - tmp = DUK_BSWAP16(tmp); - } - du.us[0] = tmp; - /* sign doesn't matter when writing */ - DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 2); - break; - } - case DUK__FLD_32BIT: { - duk_uint32_t tmp; - if (offset + 4U > check_length) { - goto fail_bounds; - } - tmp = (duk_uint32_t) duk_to_uint32(thr, 0); - if (endswap) { - tmp = DUK_BSWAP32(tmp); - } - du.ui[0] = tmp; - /* sign doesn't matter when writing */ - DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4); - break; - } - case DUK__FLD_FLOAT: { - duk_uint32_t tmp; - if (offset + 4U > check_length) { - goto fail_bounds; - } - du.f[0] = (duk_float_t) duk_to_number(thr, 0); - if (endswap) { - tmp = du.ui[0]; - tmp = DUK_BSWAP32(tmp); - du.ui[0] = tmp; - } - /* sign doesn't matter when writing */ - DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4); - break; - } - case DUK__FLD_DOUBLE: { - if (offset + 8U > check_length) { - goto fail_bounds; - } - du.d = (duk_double_t) duk_to_number(thr, 0); - if (endswap) { - DUK_DBLUNION_BSWAP64(&du); - } - /* sign doesn't matter when writing */ - DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 8); - break; - } - case DUK__FLD_VARINT: { - /* Node.js Buffer variable width integer field. We don't really - * care about speed here, so aim for shortest algorithm. - */ - duk_int_t field_bytelen; - duk_int_t i, i_step, i_end; -#if defined(DUK_USE_64BIT_OPS) - duk_int64_t tmp; -#else - duk_double_t tmp; -#endif - duk_uint8_t *p; - - field_bytelen = (duk_int_t) nbytes; - if (offset + (duk_uint_t) field_bytelen > check_length) { - goto fail_bounds; - } - - /* Slow writing of value using either 64-bit arithmetic - * or IEEE doubles if 64-bit types not available. There's - * no special sign handling when writing varints. - */ - - if (magic_bigendian) { - /* Write in big endian */ - i = field_bytelen; /* one i_step added at top of loop */ - i_step = -1; - i_end = 0; - } else { - /* Write in little endian */ - i = -1; /* one i_step added at top of loop */ - i_step = 1; - i_end = field_bytelen - 1; - } - - /* XXX: The duk_to_number() cast followed by integer coercion - * is platform specific so NaN, +/- Infinity, and out-of-bounds - * values result in platform specific output now. - * See: test-bi-nodejs-buffer-proto-varint-special.js - */ - -#if defined(DUK_USE_64BIT_OPS) - tmp = (duk_int64_t) duk_to_number(thr, 0); - p = (duk_uint8_t *) (buf + offset); - do { - i += i_step; - DUK_ASSERT(i >= 0 && i < field_bytelen); - p[i] = (duk_uint8_t) (tmp & 0xff); - tmp = tmp >> 8; /* unnecessary shift for last byte */ - } while (i != i_end); -#else - tmp = duk_to_number(thr, 0); - p = (duk_uint8_t *) (buf + offset); - do { - i += i_step; - tmp = DUK_FLOOR(tmp); - DUK_ASSERT(i >= 0 && i < field_bytelen); - p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0)); - tmp = tmp / 256.0; /* unnecessary div for last byte */ - } while (i != i_end); -#endif - break; - } - default: { /* should never happen but default here */ - goto fail_bounds; - } - } - - /* Node.js Buffer: return offset + #bytes written (i.e. next - * write offset). - */ - if (magic_typedarray) { - /* For TypedArrays 'undefined' return value is specified - * by ES2015 (matches V8). - */ - return 0; - } - duk_push_uint(thr, offset + (duk_uint_t) nbytes); - return 1; - - fail_neutered: - fail_field_length: - fail_bounds: - if (no_assert) { - /* Node.js return value for failed writes is offset + #bytes - * that would have been written. - */ - /* XXX: for negative input offsets, 'offset' will be a large - * positive value so the result here is confusing. - */ - if (magic_typedarray) { - return 0; - } - duk_push_uint(thr, offset + (duk_uint_t) nbytes); - return 1; - } - DUK_DCERROR_RANGE_INVALID_ARGS(thr); -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Accessors for .buffer, .byteLength, .byteOffset - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_hthread *thr, duk_hbuffer *h_buf) { - duk_hbufobj *h_res; - - h_res = duk_push_bufobj_raw(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_res != NULL); - DUK_UNREF(h_res); - - duk__set_bufobj_buffer(thr, h_res, h_buf); - DUK_ASSERT_HBUFOBJ_VALID(h_res); - DUK_ASSERT(h_res->buf_prop == NULL); - return h_res; -} - -DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) { - duk_hbufobj *h_bufobj; - - h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/); - DUK_ASSERT(h_bufobj != NULL); - if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { - DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer")); - (void) duk__autospawn_arraybuffer(thr, (duk_hbuffer *) h_bufobj); - return 1; - } else { - if (h_bufobj->buf_prop == NULL && - DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER && - h_bufobj->buf != NULL) { - duk_hbufobj *h_arrbuf; - - DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView")); - h_arrbuf = duk__autospawn_arraybuffer(thr, h_bufobj->buf); - - if (h_bufobj->buf_prop == NULL) { - /* Must recheck buf_prop, in case ArrayBuffer - * alloc had a side effect which already filled - * it! - */ - - /* Set ArrayBuffer's .byteOffset and .byteLength based - * on the view so that Arraybuffer[view.byteOffset] - * matches view[0]. - */ - h_arrbuf->offset = 0; - DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */ - h_arrbuf->length = h_bufobj->offset + h_bufobj->length; - DUK_ASSERT(h_arrbuf->buf_prop == NULL); - - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; - DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ - } - - /* Left on stack; pushed for the second time below (OK). */ - } - if (h_bufobj->buf_prop) { - duk_push_hobject(thr, h_bufobj->buf_prop); - return 1; - } - } - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) { - duk_hbufobj *h_bufobj; - - h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/); - DUK_ASSERT(h_bufobj != NULL); - if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { - duk_push_uint(thr, 0); - } else { - /* If neutered must return 0; offset is zeroed during - * neutering. - */ - duk_push_uint(thr, h_bufobj->offset); - } - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) { - duk_hbufobj *h_bufobj; - - h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/); - DUK_ASSERT(h_bufobj != NULL); - if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { - duk_hbuffer *h_buf; - - h_buf = (duk_hbuffer *) h_bufobj; - DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX); /* Buffer limits. */ - duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf)); - } else { - /* If neutered must return 0; length is zeroed during - * neutering. - */ - duk_push_uint(thr, h_bufobj->length); - } - return 1; -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -/* No .buffer getter without ArrayBuffer support. */ -#if 0 -DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) { - return 0; -} -#endif - -DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) { - duk_push_uint(thr, 0); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) { - duk_hbuffer *h_buf; - - /* XXX: helper? */ - duk_push_this(thr); - h_buf = duk_require_hbuffer(thr, -1); - duk_push_uint(thr, DUK_HBUFFER_GET_SIZE(h_buf)); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* automatic undefs */ -#undef DUK__BUFOBJ_FLAG_PROMOTE -#undef DUK__BUFOBJ_FLAG_THROW -#undef DUK__FLD_16BIT -#undef DUK__FLD_32BIT -#undef DUK__FLD_8BIT -#undef DUK__FLD_BIGENDIAN -#undef DUK__FLD_DOUBLE -#undef DUK__FLD_FLOAT -#undef DUK__FLD_SIGNED -#undef DUK__FLD_TYPEDARRAY -#undef DUK__FLD_VARINT -#line 1 "duk_bi_date.c" -/* - * Date built-ins - * - * Unlike most built-ins, Date has some platform dependencies for getting - * UTC time, converting between UTC and local time, and parsing and - * formatting time values. These are all abstracted behind DUK_USE_xxx - * config options. There are built-in platform specific providers for - * POSIX and Windows, but external providers can also be used. - * - * See doc/datetime.rst. - * - */ - -/* #include duk_internal.h -> already included */ - -/* XXX: currently defines unnecessary symbols when DUK_USE_DATE_BUILTIN is disabled. */ - -/* - * Forward declarations - */ - -DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset); -DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags); -DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val); -DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags); - -/* - * Other file level defines - */ - -/* Debug macro to print all parts and dparts (used manually because of debug level). */ -#define DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts) do { \ - DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \ - (long) (parts)[0], (long) (parts)[1], \ - (long) (parts)[2], (long) (parts)[3], \ - (long) (parts)[4], (long) (parts)[5], \ - (long) (parts)[6], (long) (parts)[7], \ - (double) (dparts)[0], (double) (dparts)[1], \ - (double) (dparts)[2], (double) (dparts)[3], \ - (double) (dparts)[4], (double) (dparts)[5], \ - (double) (dparts)[6], (double) (dparts)[7])); \ - } while (0) -#define DUK__DPRINT_PARTS(parts) do { \ - DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \ - (long) (parts)[0], (long) (parts)[1], \ - (long) (parts)[2], (long) (parts)[3], \ - (long) (parts)[4], (long) (parts)[5], \ - (long) (parts)[6], (long) (parts)[7])); \ - } while (0) -#define DUK__DPRINT_DPARTS(dparts) do { \ - DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \ - (double) (dparts)[0], (double) (dparts)[1], \ - (double) (dparts)[2], (double) (dparts)[3], \ - (double) (dparts)[4], (double) (dparts)[5], \ - (double) (dparts)[6], (double) (dparts)[7])); \ - } while (0) - -/* Equivalent year for DST calculations outside [1970,2038[ range, see - * E5 Section 15.9.1.8. Equivalent year has the same leap-year-ness and - * starts with the same weekday on Jan 1. - * https://bugzilla.mozilla.org/show_bug.cgi?id=351066 - */ -#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970)) -DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = { -#if 1 - /* This is based on V8 EquivalentYear() algorithm (see util/genequivyear.py): - * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146 - */ - - /* non-leap year: sunday, monday, ... */ - DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031), - DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011), - - /* leap year: sunday, monday, ... */ - DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020), - DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028) -#endif - -#if 0 - /* This is based on Rhino EquivalentYear() algorithm: - * https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java - */ - - /* non-leap year: sunday, monday, ... */ - DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986), - DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977), - - /* leap year: sunday, monday, ... */ - DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992), - DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972) -#endif -}; - -/* - * ISO 8601 subset parser. - */ - -/* Parser part count. */ -#define DUK__NUM_ISO8601_PARSER_PARTS 9 - -/* Parser part indices. */ -#define DUK__PI_YEAR 0 -#define DUK__PI_MONTH 1 -#define DUK__PI_DAY 2 -#define DUK__PI_HOUR 3 -#define DUK__PI_MINUTE 4 -#define DUK__PI_SECOND 5 -#define DUK__PI_MILLISECOND 6 -#define DUK__PI_TZHOUR 7 -#define DUK__PI_TZMINUTE 8 - -/* Parser part masks. */ -#define DUK__PM_YEAR (1 << DUK__PI_YEAR) -#define DUK__PM_MONTH (1 << DUK__PI_MONTH) -#define DUK__PM_DAY (1 << DUK__PI_DAY) -#define DUK__PM_HOUR (1 << DUK__PI_HOUR) -#define DUK__PM_MINUTE (1 << DUK__PI_MINUTE) -#define DUK__PM_SECOND (1 << DUK__PI_SECOND) -#define DUK__PM_MILLISECOND (1 << DUK__PI_MILLISECOND) -#define DUK__PM_TZHOUR (1 << DUK__PI_TZHOUR) -#define DUK__PM_TZMINUTE (1 << DUK__PI_TZMINUTE) - -/* Parser separator indices. */ -#define DUK__SI_PLUS 0 -#define DUK__SI_MINUS 1 -#define DUK__SI_T 2 -#define DUK__SI_SPACE 3 -#define DUK__SI_COLON 4 -#define DUK__SI_PERIOD 5 -#define DUK__SI_Z 6 -#define DUK__SI_NUL 7 - -/* Parser separator masks. */ -#define DUK__SM_PLUS (1 << DUK__SI_PLUS) -#define DUK__SM_MINUS (1 << DUK__SI_MINUS) -#define DUK__SM_T (1 << DUK__SI_T) -#define DUK__SM_SPACE (1 << DUK__SI_SPACE) -#define DUK__SM_COLON (1 << DUK__SI_COLON) -#define DUK__SM_PERIOD (1 << DUK__SI_PERIOD) -#define DUK__SM_Z (1 << DUK__SI_Z) -#define DUK__SM_NUL (1 << DUK__SI_NUL) - -/* Rule control flags. */ -#define DUK__CF_NEG (1 << 0) /* continue matching, set neg_tzoffset flag */ -#define DUK__CF_ACCEPT (1 << 1) /* accept string */ -#define DUK__CF_ACCEPT_NUL (1 << 2) /* accept string if next char is NUL (otherwise reject) */ - -#define DUK__PACK_RULE(partmask,sepmask,nextpart,flags) \ - ((duk_uint32_t) (partmask) + \ - (((duk_uint32_t) (sepmask)) << 9) + \ - (((duk_uint32_t) (nextpart)) << 17) + \ - (((duk_uint32_t) (flags)) << 21)) - -#define DUK__UNPACK_RULE(rule,var_nextidx,var_flags) do { \ - (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \ - (var_flags) = (duk_small_uint_t) ((rule) >> 21); \ - } while (0) - -#define DUK__RULE_MASK_PART_SEP 0x1ffffUL - -/* Matching separator index is used in the control table */ -DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = { - DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, DUK_ASC_SPACE /*3*/, - DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, DUK_ASC_NUL /*7*/ -}; - -/* Rule table: first matching rule is used to determine what to do next. */ -DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = { - DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0), - DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0), - DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0), - DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0), - DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0), - DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0), - DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0), - DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_PLUS, DUK__PI_TZHOUR, 0), - DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_MINUS, DUK__PI_TZHOUR, DUK__CF_NEG), - DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_Z, 0, DUK__CF_ACCEPT_NUL), - DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND | DUK__PM_TZHOUR /*Note2*/ | DUK__PM_TZMINUTE, DUK__SM_NUL, 0, DUK__CF_ACCEPT) - - /* Note1: the specification doesn't require matching a time form with - * just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z". - * - * Note2: the specification doesn't require matching a timezone offset - * with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02" - */ -}; - -DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const char *str) { - duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS]; - duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; - duk_double_t d; - const duk_uint8_t *p; - duk_small_uint_t part_idx = 0; - duk_int_t accum = 0; - duk_small_uint_t ndigits = 0; - duk_bool_t neg_year = 0; - duk_bool_t neg_tzoffset = 0; - duk_uint_fast8_t ch; - duk_small_uint_t i; - - /* During parsing, month and day are one-based; set defaults here. */ - DUK_MEMZERO(parts, sizeof(parts)); - DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */ - parts[DUK_DATE_IDX_MONTH] = 1; - parts[DUK_DATE_IDX_DAY] = 1; - - /* Special handling for year sign. */ - p = (const duk_uint8_t *) str; - ch = p[0]; - if (ch == DUK_ASC_PLUS) { - p++; - } else if (ch == DUK_ASC_MINUS) { - neg_year = 1; - p++; - } - - for (;;) { - ch = *p++; - DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')", - (long) part_idx, (long) ch, - (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : DUK_ASC_QUESTION))); - - if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) { - if (ndigits >= 9) { - DUK_DDD(DUK_DDDPRINT("too many digits -> reject")); - goto reject; - } - if (part_idx == DUK__PI_MILLISECOND && ndigits >= 3) { - /* ignore millisecond fractions after 3 */ - } else { - accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00; - ndigits++; - } - } else { - duk_uint_fast32_t match_val; - duk_small_uint_t sep_idx; - - if (ndigits <= 0) { - goto reject; - } - if (part_idx == DUK__PI_MILLISECOND) { - /* complete the millisecond field */ - while (ndigits < 3) { - accum *= 10; - ndigits++; - } - } - parts[part_idx] = accum; - DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld", (long) part_idx, (long) accum)); - - accum = 0; - ndigits = 0; - - for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) { - if (duk__parse_iso8601_seps[i] == ch) { - break; - } - } - if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) { - DUK_DDD(DUK_DDDPRINT("separator character doesn't match -> reject")); - goto reject; - } - - sep_idx = i; - match_val = (1UL << part_idx) + (1UL << (sep_idx + 9)); /* match against rule part/sep bits */ - - for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) { - duk_uint_fast32_t rule = duk__parse_iso8601_control[i]; - duk_small_uint_t nextpart; - duk_small_uint_t cflags; - - DUK_DDD(DUK_DDDPRINT("part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx", - (long) part_idx, (long) sep_idx, - (unsigned long) match_val, (unsigned long) rule)); - - if ((rule & match_val) != match_val) { - continue; - } - - DUK__UNPACK_RULE(rule, nextpart, cflags); - - DUK_DDD(DUK_DDDPRINT("rule match -> part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, " - "rule=0x%08lx -> nextpart=%ld, cflags=0x%02lx", - (long) part_idx, (long) sep_idx, - (unsigned long) match_val, (unsigned long) rule, - (long) nextpart, (unsigned long) cflags)); - - if (cflags & DUK__CF_NEG) { - neg_tzoffset = 1; - } - - if (cflags & DUK__CF_ACCEPT) { - goto accept; - } - - if (cflags & DUK__CF_ACCEPT_NUL) { - DUK_ASSERT(*(p - 1) != (char) 0); - if (*p == DUK_ASC_NUL) { - goto accept; - } - goto reject; - } - - part_idx = nextpart; - break; - } /* rule match */ - - if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) { - DUK_DDD(DUK_DDDPRINT("no rule matches -> reject")); - goto reject; - } - - if (ch == 0) { - /* This shouldn't be necessary, but check just in case - * to avoid any chance of overruns. - */ - DUK_DDD(DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject")); - goto reject; - } - } /* if-digit-else-ctrl */ - } /* char loop */ - - /* We should never exit the loop above. */ - DUK_UNREACHABLE(); - - reject: - DUK_DDD(DUK_DDDPRINT("reject")); - return 0; - - accept: - DUK_DDD(DUK_DDDPRINT("accept")); - - /* Apply timezone offset to get the main parts in UTC */ - if (neg_year) { - parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR]; - } - if (neg_tzoffset) { - parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR]; - parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE]; - } else { - parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR]; - parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE]; - } - parts[DUK__PI_MONTH] -= 1; /* zero-based month */ - parts[DUK__PI_DAY] -= 1; /* zero-based day */ - - /* Use double parts, they tolerate unnormalized time. - * - * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR) - * on purpose. It won't be actually used by duk_bi_date_get_timeval_from_dparts(), - * but will make the value initialized just in case, and avoid any - * potential for Valgrind issues. - */ - for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) { - DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld", (long) i, (long) parts[i])); - dparts[i] = parts[i]; - } - - d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/); - duk_push_number(thr, d); - return 1; -} - -/* - * Date/time parsing helper. - * - * Parse a datetime string into a time value. We must first try to parse - * the input according to the standard format in E5.1 Section 15.9.1.15. - * If that fails, we can try to parse using custom parsing, which can - * either be platform neutral (custom code) or platform specific (using - * existing platform API calls). - * - * Note in particular that we must parse whatever toString(), toUTCString(), - * and toISOString() can produce; see E5.1 Section 15.9.4.2. - * - * Returns 1 to allow tail calling. - * - * There is much room for improvement here with respect to supporting - * alternative datetime formats. For instance, V8 parses '2012-01-01' as - * UTC and '2012/01/01' as local time. - */ - -DUK_LOCAL duk_ret_t duk__parse_string(duk_hthread *thr, const char *str) { - /* XXX: there is a small risk here: because the ISO 8601 parser is - * very loose, it may end up parsing some datetime values which - * would be better parsed with a platform specific parser. - */ - - DUK_ASSERT(str != NULL); - DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str)); - - if (duk__parse_string_iso8601_subset(thr, str) != 0) { - return 1; - } - -#if defined(DUK_USE_DATE_PARSE_STRING) - /* Contract, either: - * - Push value on stack and return 1 - * - Don't push anything on stack and return 0 - */ - - if (DUK_USE_DATE_PARSE_STRING(thr, str) != 0) { - return 1; - } -#else - /* No platform-specific parsing, this is not an error. */ -#endif - - duk_push_nan(thr); - return 1; -} - -/* - * Calendar helpers - * - * Some helpers are used for getters and can operate on normalized values - * which can be represented with 32-bit signed integers. Other helpers are - * needed by setters and operate on un-normalized double values, must watch - * out for non-finite numbers etc. - */ - -DUK_LOCAL duk_uint8_t duk__days_in_month[12] = { - (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30, - (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31, - (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31 -}; - -/* Maximum iteration count for computing UTC-to-local time offset when - * creating an Ecmascript time value from local parts. - */ -#define DUK__LOCAL_TZOFFSET_MAXITER 4 - -/* Because 'day since epoch' can be negative and is used to compute weekday - * using a modulo operation, add this multiple of 7 to avoid negative values - * when year is below 1970 epoch. Ecmascript time values are restricted to - * +/- 100 million days from epoch, so this adder fits nicely into 32 bits. - * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin. - */ -#define DUK__WEEKDAY_MOD_ADDER (20000000 * 7) /* 0x08583b00 */ - -DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) { - if ((year % 4) != 0) { - return 0; - } - if ((year % 100) != 0) { - return 1; - } - if ((year % 400) != 0) { - return 0; - } - return 1; -} - -DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) { - return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS); -} - -DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) { - return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= DUK_DATE_MSEC_100M_DAYS_LEEWAY); -} - -DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) { - return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR); -} - -DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) { - if (!DUK_ISFINITE(x)) { - return DUK_DOUBLE_NAN; - } - - if (!duk_bi_date_timeval_in_valid_range(x)) { - return DUK_DOUBLE_NAN; - } - - x = duk_js_tointeger_number(x); - - /* Here we'd have the option to normalize -0 to +0. */ - return x; -} - -/* Integer division which floors also negative values correctly. */ -DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) { - DUK_ASSERT(b > 0); - if (a >= 0) { - return a / b; - } else { - /* e.g. a = -4, b = 5 --> -4 - 5 + 1 / 5 --> -8 / 5 --> -1 - * a = -5, b = 5 --> -5 - 5 + 1 / 5 --> -9 / 5 --> -1 - * a = -6, b = 5 --> -6 - 5 + 1 / 5 --> -10 / 5 --> -2 - */ - return (a - b + 1) / b; - } -} - -/* Compute day number of the first day of a given year. */ -DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) { - /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative - * values, but is incorrect for negative ones. - */ - return 365 * (year - 1970) - + duk__div_floor(year - 1969, 4) - - duk__div_floor(year - 1901, 100) - + duk__div_floor(year - 1601, 400); -} - -/* Given a day number, determine year and day-within-year. */ -DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year) { - duk_int_t year; - duk_int_t diff_days; - - /* estimate year upwards (towards positive infinity), then back down; - * two iterations should be enough - */ - - if (day >= 0) { - year = 1970 + day / 365; - } else { - year = 1970 + day / 366; - } - - for (;;) { - diff_days = duk__day_from_year(year) - day; - DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld", (long) year, (long) day, (long) diff_days)); - if (diff_days <= 0) { - DUK_ASSERT(-diff_days < 366); /* fits into duk_small_int_t */ - *out_day_within_year = -diff_days; - DUK_DDD(DUK_DDDPRINT("--> year=%ld, day-within-year=%ld", - (long) year, (long) *out_day_within_year)); - DUK_ASSERT(*out_day_within_year >= 0); - DUK_ASSERT(*out_day_within_year < (duk_bi_date_is_leap_year(year) ? 366 : 365)); - return year; - } - - /* Note: this is very tricky; we must never 'overshoot' the - * correction downwards. - */ - year -= 1 + (diff_days - 1) / 366; /* conservative */ - } -} - -/* Given a (year, month, day-within-month) triple, compute day number. - * The input triple is un-normalized and may contain non-finite values. - */ -DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day) { - duk_int_t day_num; - duk_bool_t is_leap; - duk_small_int_t i, n; - - /* Assume that year, month, day are all coerced to whole numbers. - * They may also be NaN or infinity, in which case this function - * must return NaN or infinity to ensure time value becomes NaN. - * If 'day' is NaN, the final return will end up returning a NaN, - * so it doesn't need to be checked here. - */ - - if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) { - return DUK_DOUBLE_NAN; - } - - year += DUK_FLOOR(month / 12.0); - - month = DUK_FMOD(month, 12.0); - if (month < 0.0) { - /* handle negative values */ - month += 12.0; - } - - /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but - * does not normalize the day-of-month (nor check whether or not - * it is finite) because it's not necessary for finding the day - * number which matches the (year,month) pair. - * - * We assume that duk__day_from_year() is exact here. - * - * Without an explicit infinity / NaN check in the beginning, - * day_num would be a bogus integer here. - * - * It's possible for 'year' to be out of integer range here. - * If so, we need to return NaN without integer overflow. - * This fixes test-bug-setyear-overflow.js. - */ - - if (!duk_bi_date_year_in_valid_range(year)) { - DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid integer overflow: %lf", (double) year)); - return DUK_DOUBLE_NAN; - } - day_num = duk__day_from_year((duk_int_t) year); - is_leap = duk_bi_date_is_leap_year((duk_int_t) year); - - n = (duk_small_int_t) month; - for (i = 0; i < n; i++) { - day_num += duk__days_in_month[i]; - if (i == 1 && is_leap) { - day_num++; - } - } - - /* If 'day' is NaN, returns NaN. */ - return (duk_double_t) day_num + day; -} - -/* Split time value into parts. The time value may contain fractions (it may - * come from duk_time_to_components() API call) which are truncated. Possible - * local time adjustment has already been applied when reading the time value. - */ -DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags) { - duk_double_t d1, d2; - duk_int_t t1, t2; - duk_int_t day_since_epoch; - duk_int_t year; /* does not fit into 16 bits */ - duk_small_int_t day_in_year; - duk_small_int_t month; - duk_small_int_t day; - duk_small_int_t dim; - duk_int_t jan1_since_epoch; - duk_small_int_t jan1_weekday; - duk_int_t equiv_year; - duk_small_uint_t i; - duk_bool_t is_leap; - duk_small_int_t arridx; - - DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */ - d = DUK_FLOOR(d); /* remove fractions if present */ - DUK_ASSERT(DUK_FLOOR(d) == d); - - /* The timevalue must be in valid Ecmascript range, but since a local - * time offset can be applied, we need to allow a +/- 24h leeway to - * the value. In other words, although the UTC time is within the - * Ecmascript range, the local part values can be just outside of it. - */ - DUK_UNREF(duk_bi_date_timeval_in_leeway_range); - DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d)); - - /* These computations are guaranteed to be exact for the valid - * E5 time value range, assuming milliseconds without fractions. - */ - d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY); - if (d1 < 0.0) { - /* deal with negative values */ - d1 += (duk_double_t) DUK_DATE_MSEC_DAY; - } - d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY)); - DUK_ASSERT(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1 == d); - /* now expected to fit into a 32-bit integer */ - t1 = (duk_int_t) d1; - t2 = (duk_int_t) d2; - day_since_epoch = t2; - DUK_ASSERT((duk_double_t) t1 == d1); - DUK_ASSERT((duk_double_t) t2 == d2); - - /* t1 = milliseconds within day (fits 32 bit) - * t2 = day number from epoch (fits 32 bit, may be negative) - */ - - parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000; - parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60; - parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60; - parts[DUK_DATE_IDX_HOUR] = t1; - DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999); - DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59); - DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59); - DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23); - - DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld", - (double) d, (double) d1, (double) d2, (long) t1, (long) t2, - (long) parts[DUK_DATE_IDX_HOUR], - (long) parts[DUK_DATE_IDX_MINUTE], - (long) parts[DUK_DATE_IDX_SECOND], - (long) parts[DUK_DATE_IDX_MILLISECOND])); - - /* This assert depends on the input parts representing time inside - * the Ecmascript range. - */ - DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0); - parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */ - DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6); - - year = duk__year_from_day(t2, &day_in_year); - day = day_in_year; - is_leap = duk_bi_date_is_leap_year(year); - for (month = 0; month < 12; month++) { - dim = duk__days_in_month[month]; - if (month == 1 && is_leap) { - dim++; - } - DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld", - (long) month, (long) dim, (long) day)); - if (day < dim) { - break; - } - day -= dim; - } - DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month)); - DUK_ASSERT(month >= 0 && month <= 11); - DUK_ASSERT(day >= 0 && day <= 31); - - /* Equivalent year mapping, used to avoid DST trouble when platform - * may fail to provide reasonable DST answers for dates outside the - * ordinary range (e.g. 1970-2038). An equivalent year has the same - * leap-year-ness as the original year and begins on the same weekday - * (Jan 1). - * - * The year 2038 is avoided because there seem to be problems with it - * on some platforms. The year 1970 is also avoided as there were - * practical problems with it; an equivalent year is used for it too, - * which breaks some DST computations for 1970 right now, see e.g. - * test-bi-date-tzoffset-brute-fi.js. - */ - if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) { - DUK_ASSERT(is_leap == 0 || is_leap == 1); - - jan1_since_epoch = day_since_epoch - day_in_year; /* day number for Jan 1 since epoch */ - DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0); - jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */ - DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6); - arridx = jan1_weekday; - if (is_leap) { - arridx += 7; - } - DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t))); - - equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970; - year = equiv_year; - DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, " - "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld", - (long) year, (long) day_in_year, (long) day_since_epoch, - (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year)); - } - - parts[DUK_DATE_IDX_YEAR] = year; - parts[DUK_DATE_IDX_MONTH] = month; - parts[DUK_DATE_IDX_DAY] = day; - - if (flags & DUK_DATE_FLAG_ONEBASED) { - parts[DUK_DATE_IDX_MONTH]++; /* zero-based -> one-based */ - parts[DUK_DATE_IDX_DAY]++; /* -""- */ - } - - if (dparts != NULL) { - for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) { - dparts[i] = (duk_double_t) parts[i]; - } - } -} - -/* Compute time value from (double) parts. The parts can be either UTC - * or local time; if local, they need to be (conceptually) converted into - * UTC time. The parts may represent valid or invalid time, and may be - * wildly out of range (but may cancel each other and still come out in - * the valid Date range). - */ -DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags) { -#if defined(DUK_USE_PARANOID_DATE_COMPUTATION) - /* See comments below on MakeTime why these are volatile. */ - volatile duk_double_t tmp_time; - volatile duk_double_t tmp_day; - volatile duk_double_t d; -#else - duk_double_t tmp_time; - duk_double_t tmp_day; - duk_double_t d; -#endif - duk_small_uint_t i; - duk_int_t tzoff, tzoffprev1, tzoffprev2; - - /* Expects 'this' at top of stack on entry. */ - - /* Coerce all finite parts with ToInteger(). ToInteger() must not - * be called for NaN/Infinity because it will convert e.g. NaN to - * zero. If ToInteger() has already been called, this has no side - * effects and is idempotent. - * - * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind - * issues if the value is uninitialized. - */ - for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) { - /* SCANBUILD: scan-build complains here about assigned value - * being garbage or undefined. This is correct but operating - * on undefined values has no ill effect and is ignored by the - * caller in the case where this happens. - */ - d = dparts[i]; - if (DUK_ISFINITE(d)) { - dparts[i] = duk_js_tointeger_number(d); - } - } - - /* Use explicit steps in computation to try to ensure that - * computation happens with intermediate results coerced to - * double values (instead of using something more accurate). - * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754 - * rules (= Ecmascript '+' and '*' operators). - * - * Without 'volatile' even this approach fails on some platform - * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu - * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js - * would fail because of some optimizations when computing tmp_time - * (MakeTime below). Adding 'volatile' to tmp_time solved this - * particular problem (annoyingly, also adding debug prints or - * running the executable under valgrind hides it). - */ - - /* MakeTime */ - tmp_time = 0.0; - tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR); - tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE); - tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND); - tmp_time += dparts[DUK_DATE_IDX_MILLISECOND]; - - /* MakeDay */ - tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]); - - /* MakeDate */ - d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time; - - DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf", - (double) tmp_time, (double) tmp_day, (double) d)); - - /* Optional UTC conversion. */ - if (flags & DUK_DATE_FLAG_LOCALTIME) { - /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a - * time value computed from UTC parts. At this point we only - * have 'd' which is a time value computed from local parts, so - * it is off by the UTC-to-local time offset which we don't know - * yet. The current solution for computing the UTC-to-local - * time offset is to iterate a few times and detect a fixed - * point or a two-cycle loop (or a sanity iteration limit), - * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js. - * - * E5.1 Section 15.9.1.9: - * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA) - * - * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0. - */ - -#if 0 - /* Old solution: don't iterate, incorrect */ - tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); - DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", (long) tzoff)); - d -= tzoff * 1000L; - DUK_UNREF(tzoffprev1); - DUK_UNREF(tzoffprev2); -#endif - - /* Iteration solution */ - tzoff = 0; - tzoffprev1 = 999999999L; /* invalid value which never matches */ - for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) { - tzoffprev2 = tzoffprev1; - tzoffprev1 = tzoff; - tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L); - DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld", - (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2)); - if (tzoff == tzoffprev1) { - DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld", - (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2)); - break; - } else if (tzoff == tzoffprev2) { - /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js. - * In these cases, favor a higher tzoffset to get a consistent - * result which is independent of iteration count. Not sure if - * this is a generically correct solution. - */ - DUK_DDD(DUK_DDDPRINT("tzoffset iteration two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld", - (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2)); - if (tzoffprev1 > tzoff) { - tzoff = tzoffprev1; - } - break; - } - } - DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld", (long) tzoff)); - d -= tzoff * 1000L; - } - - /* TimeClip(), which also handles Infinity -> NaN conversion */ - d = duk__timeclip(d); - - return d; -} - -/* - * API oriented helpers - */ - -/* Push 'this' binding, check that it is a Date object; then push the - * internal time value. At the end, stack is: [ ... this timeval ]. - * Returns the time value. Local time adjustment is done if requested. - */ -DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset) { - duk_hobject *h; - duk_double_t d; - duk_int_t tzoffset = 0; - - duk_push_this(thr); - h = duk_get_hobject(thr, -1); /* XXX: getter with class check, useful in built-ins */ - if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) { - DUK_ERROR_TYPE(thr, "expected Date"); - } - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); - d = duk_to_number_m1(thr); - duk_pop(thr); - - if (DUK_ISNAN(d)) { - if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) { - d = 0.0; - } - if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) { - DUK_ERROR_RANGE(thr, "Invalid Date"); - } - } - /* if no NaN handling flag, may still be NaN here, but not Inf */ - DUK_ASSERT(!DUK_ISINF(d)); - - if (flags & DUK_DATE_FLAG_LOCALTIME) { - /* Note: DST adjustment is determined using UTC time. - * If 'd' is NaN, tzoffset will be 0. - */ - tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); /* seconds */ - d += tzoffset * 1000L; - } - if (out_tzoffset) { - *out_tzoffset = tzoffset; - } - - /* [ ... this ] */ - return d; -} - -DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags) { - return duk__push_this_get_timeval_tzoffset(thr, flags, NULL); -} - -/* Set timeval to 'this' from dparts, push the new time value onto the - * value stack and return 1 (caller can then tail call us). Expects - * the value stack to contain 'this' on the stack top. - */ -DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags) { - duk_double_t d; - - /* [ ... this ] */ - - d = duk_bi_date_get_timeval_from_dparts(dparts, flags); - duk_push_number(thr, d); /* -> [ ... this timeval_new ] */ - duk_dup_top(thr); /* -> [ ... this timeval_new timeval_new ] */ - duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE); - - /* stack top: new time value, return 1 to allow tail calls */ - return 1; -} - -/* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */ -DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags, duk_uint8_t *out_buf) { - char yearstr[8]; /* "-123456\0" */ - char tzstr[8]; /* "+11:22\0" */ - char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE; - - DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12); - DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31); - DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && parts[DUK_DATE_IDX_YEAR] <= 999999); - - /* Note: %06d for positive value, %07d for negative value to include - * sign and 6 digits. - */ - DUK_SNPRINTF(yearstr, - sizeof(yearstr), - (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] <= 9999) ? "%04ld" : - ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : "%07ld"), - (long) parts[DUK_DATE_IDX_YEAR]); - yearstr[sizeof(yearstr) - 1] = (char) 0; - - if (flags & DUK_DATE_FLAG_LOCALTIME) { - /* tzoffset seconds are dropped; 16 bits suffice for - * time offset in minutes - */ - const char *fmt; - duk_small_int_t tmp, arg_hours, arg_minutes; - - if (tzoffset >= 0) { - tmp = tzoffset; - fmt = "+%02d:%02d"; - } else { - tmp = -tzoffset; - fmt = "-%02d:%02d"; - } - tmp = tmp / 60; - arg_hours = tmp / 60; - arg_minutes = tmp % 60; - DUK_ASSERT(arg_hours <= 24); /* Even less is actually guaranteed for a valid tzoffset. */ - arg_hours = arg_hours & 0x3f; /* For [0,24] this is a no-op, but fixes GCC 7 warning, see https://github.com/svaarala/duktape/issues/1602. */ - - DUK_SNPRINTF(tzstr, sizeof(tzstr), fmt, (int) arg_hours, (int) arg_minutes); - tzstr[sizeof(tzstr) - 1] = (char) 0; - } else { - tzstr[0] = DUK_ASC_UC_Z; - tzstr[1] = (char) 0; - } - - /* Unlike year, the other parts fit into 16 bits so %d format - * is portable. - */ - if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) { - DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s", - (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep, - (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE], - (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr); - } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) { - DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d", - (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]); - } else { - DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME); - DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s", - (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE], - (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], - (const char *) tzstr); - } -} - -/* Helper for string conversion calls: check 'this' binding, get the - * internal time value, and format date and/or time in a few formats. - * Return value allows tail calls. - */ -DUK_LOCAL duk_ret_t duk__to_string_helper(duk_hthread *thr, duk_small_uint_t flags) { - duk_double_t d; - duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; - duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */ - duk_bool_t rc; - duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE]; - - DUK_UNREF(rc); /* unreferenced with some options */ - - d = duk__push_this_get_timeval_tzoffset(thr, flags, &tzoffset); - if (DUK_ISNAN(d)) { - duk_push_hstring_stridx(thr, DUK_STRIDX_INVALID_DATE); - return 1; - } - DUK_ASSERT(DUK_ISFINITE(d)); - - /* formatters always get one-based month/day-of-month */ - duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED); - DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12); - DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31); - - if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) { - /* try locale specific formatter; if it refuses to format the - * string, fall back to an ISO 8601 formatted value in local - * time. - */ -#if defined(DUK_USE_DATE_FORMAT_STRING) - /* Contract, either: - * - Push string to value stack and return 1 - * - Don't push anything and return 0 - */ - - rc = DUK_USE_DATE_FORMAT_STRING(thr, parts, tzoffset, flags); - if (rc != 0) { - return 1; - } -#else - /* No locale specific formatter; this is OK, we fall back - * to ISO 8601. - */ -#endif - } - - /* Different calling convention than above used because the helper - * is shared. - */ - duk__format_parts_iso8601(parts, tzoffset, flags, buf); - duk_push_string(thr, (const char *) buf); - return 1; -} - -/* Helper for component getter calls: check 'this' binding, get the - * internal time value, split it into parts (either as UTC time or - * local time), push a specified component as a return value to the - * value stack and return 1 (caller can then tail call us). - */ -DUK_LOCAL duk_ret_t duk__get_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_idx) { - duk_double_t d; - duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; - duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */ - - DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */ - DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS); - - d = duk__push_this_get_timeval(thr, flags_and_idx); - if (DUK_ISNAN(d)) { - duk_push_nan(thr); - return 1; - } - DUK_ASSERT(DUK_ISFINITE(d)); - - duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx); /* no need to mask idx portion */ - - /* Setter APIs detect special year numbers (0...99) and apply a +1900 - * only in certain cases. The legacy getYear() getter applies -1900 - * unconditionally. - */ - duk_push_int(thr, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]); - return 1; -} - -/* Helper for component setter calls: check 'this' binding, get the - * internal time value, split it into parts (either as UTC time or - * local time), modify one or more components as specified, recompute - * the time value, set it as the internal value. Finally, push the - * new time value as a return value to the value stack and return 1 - * (caller can then tail call us). - */ -DUK_LOCAL duk_ret_t duk__set_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_maxnargs) { - duk_double_t d; - duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; - duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; - duk_idx_t nargs; - duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */ - duk_small_uint_t idx_first, idx; - duk_small_uint_t i; - - nargs = duk_get_top(thr); - d = duk__push_this_get_timeval(thr, flags_and_maxnargs); - DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d)); - - if (DUK_ISFINITE(d)) { - duk_bi_date_timeval_to_parts(d, parts, dparts, flags_and_maxnargs); - } else { - /* NaN timevalue: we need to coerce the arguments, but - * the resulting internal timestamp needs to remain NaN. - * This works but is not pretty: parts and dparts will - * be partially uninitialized, but we only write to them. - */ - } - - /* - * Determining which datetime components to overwrite based on - * stack arguments is a bit complicated, but important to factor - * out from setters themselves for compactness. - * - * If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type: - * - * 1 -> millisecond - * 2 -> second, [millisecond] - * 3 -> minute, [second], [millisecond] - * 4 -> hour, [minute], [second], [millisecond] - * - * Else: - * - * 1 -> date - * 2 -> month, [date] - * 3 -> year, [month], [date] - * - * By comparing nargs and maxnargs (and flags) we know which - * components to override. We rely on part index ordering. - */ - - if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) { - DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4); - idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1); - } else { - DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3); - idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1); - } - DUK_ASSERT_DISABLE(idx_first >= 0); /* unsigned */ - DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS); - - for (i = 0; i < maxnargs; i++) { - if ((duk_idx_t) i >= nargs) { - /* no argument given -> leave components untouched */ - break; - } - idx = idx_first + i; - DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */ - DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS); - - if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) { - duk__twodigit_year_fixup(thr, (duk_idx_t) i); - } - - dparts[idx] = duk_to_number(thr, (duk_idx_t) i); - - if (idx == DUK_DATE_IDX_DAY) { - /* Day-of-month is one-based in the API, but zero-based - * internally, so fix here. Note that month is zero-based - * both in the API and internally. - */ - /* SCANBUILD: complains about use of uninitialized values. - * The complaint is correct, but operating in undefined - * values here is intentional in some cases and the caller - * ignores the results. - */ - dparts[idx] -= 1.0; - } - } - - /* Leaves new timevalue on stack top and returns 1, which is correct - * for part setters. - */ - if (DUK_ISFINITE(d)) { - return duk__set_this_timeval_from_dparts(thr, dparts, flags_and_maxnargs); - } else { - /* Internal timevalue is already NaN, so don't touch it. */ - duk_push_nan(thr); - return 1; - } -} - -/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add - * 1900 and replace value at idx_val. - */ -DUK_LOCAL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val) { - duk_double_t d; - - /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t - * might not generate better code due to casting. - */ - - /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */ - duk_to_number(thr, idx_val); - if (duk_is_nan(thr, idx_val)) { - return; - } - duk_dup(thr, idx_val); - duk_to_int(thr, -1); - d = duk_get_number(thr, -1); /* get as double to handle huge numbers correctly */ - if (d >= 0.0 && d <= 99.0) { - d += 1900.0; - duk_push_number(thr, d); - duk_replace(thr, idx_val); - } - duk_pop(thr); -} - -/* Set datetime parts from stack arguments, defaulting any missing values. - * Day-of-week is not set; it is not required when setting the time value. - */ -DUK_LOCAL void duk__set_parts_from_args(duk_hthread *thr, duk_double_t *dparts, duk_idx_t nargs) { - duk_double_t d; - duk_small_uint_t i; - duk_small_uint_t idx; - - /* Causes a ToNumber() coercion, but doesn't break coercion order since - * year is coerced first anyway. - */ - duk__twodigit_year_fixup(thr, 0); - - /* There are at most 7 args, but we use 8 here so that also - * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential - * for any Valgrind gripes later. - */ - for (i = 0; i < 8; i++) { - /* Note: rely on index ordering */ - idx = DUK_DATE_IDX_YEAR + i; - if ((duk_idx_t) i < nargs) { - d = duk_to_number(thr, (duk_idx_t) i); - if (idx == DUK_DATE_IDX_DAY) { - /* Convert day from one-based to zero-based (internal). This may - * cause the day part to be negative, which is OK. - */ - d -= 1.0; - } - } else { - /* All components default to 0 except day-of-month which defaults - * to 1. However, because our internal day-of-month is zero-based, - * it also defaults to zero here. - */ - d = 0.0; - } - dparts[idx] = d; - } - - DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf", - (double) dparts[0], (double) dparts[1], - (double) dparts[2], (double) dparts[3], - (double) dparts[4], (double) dparts[5], - (double) dparts[6], (double) dparts[7])); -} - -/* - * Indirect magic value lookup for Date methods. - * - * Date methods don't put their control flags into the function magic value - * because they wouldn't fit into a LIGHTFUNC's magic field. Instead, the - * magic value is set to an index pointing to the array of control flags - * below. - * - * This must be kept in strict sync with genbuiltins.py! - */ - -static duk_uint16_t duk__date_magics[] = { - /* 0: toString */ - DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME, - - /* 1: toDateString */ - DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME, - - /* 2: toTimeString */ - DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME, - - /* 3: toLocaleString */ - DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME, - - /* 4: toLocaleDateString */ - DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME, - - /* 5: toLocaleTimeString */ - DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME, - - /* 6: toUTCString */ - DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME, - - /* 7: toISOString */ - DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T, - - /* 8: getFullYear */ - DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 9: getUTCFullYear */ - 0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 10: getMonth */ - DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 11: getUTCMonth */ - 0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 12: getDate */ - DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 13: getUTCDate */ - DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 14: getDay */ - DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 15: getUTCDay */ - 0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 16: getHours */ - DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 17: getUTCHours */ - 0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 18: getMinutes */ - DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 19: getUTCMinutes */ - 0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 20: getSeconds */ - DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 21: getUTCSeconds */ - 0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 22: getMilliseconds */ - DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 23: getUTCMilliseconds */ - 0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 24: setMilliseconds */ - DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 25: setUTCMilliseconds */ - DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 26: setSeconds */ - DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 27: setUTCSeconds */ - DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 28: setMinutes */ - DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 29: setUTCMinutes */ - DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 30: setHours */ - DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 31: setUTCHours */ - DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 32: setDate */ - DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 33: setUTCDate */ - 0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 34: setMonth */ - DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 35: setUTCMonth */ - 0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 36: setFullYear */ - DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 37: setUTCFullYear */ - DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 38: getYear */ - DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT), - - /* 39: setYear */ - DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT), -}; - -DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_hthread *thr) { - duk_small_uint_t magicidx = (duk_small_uint_t) duk_get_current_magic(thr); - DUK_ASSERT(magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t))); - return (duk_small_uint_t) duk__date_magics[magicidx]; -} - -#if defined(DUK_USE_DATE_BUILTIN) -/* - * Constructor calls - */ - -DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_hthread *thr) { - duk_idx_t nargs = duk_get_top(thr); - duk_bool_t is_cons = duk_is_constructor_call(thr); - duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; - duk_double_t d; - - DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons)); - - (void) duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), - DUK_BIDX_DATE_PROTOTYPE); - - /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date - * is mutable. - */ - - if (nargs == 0 || !is_cons) { - d = duk__timeclip(duk_time_get_ecmascript_time_nofrac(thr)); - duk_push_number(thr, d); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); - if (!is_cons) { - /* called as a normal function: return new Date().toString() */ - duk_to_string(thr, -1); - } - return 1; - } else if (nargs == 1) { - const char *str; - duk_to_primitive(thr, 0, DUK_HINT_NONE); - str = duk_get_string_notsymbol(thr, 0); - if (str) { - duk__parse_string(thr, str); - duk_replace(thr, 0); /* may be NaN */ - } - d = duk__timeclip(duk_to_number(thr, 0)); /* symbols fail here */ - duk_push_number(thr, d); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); - return 1; - } - - duk__set_parts_from_args(thr, dparts, nargs); - - /* Parts are in local time, convert when setting. */ - - (void) duk__set_this_timeval_from_dparts(thr, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */ - duk_pop(thr); /* -> [ ... this ] */ - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_hthread *thr) { - return duk__parse_string(thr, duk_to_string(thr, 0)); -} - -DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_hthread *thr) { - duk_idx_t nargs = duk_get_top(thr); - duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; - duk_double_t d; - - /* Behavior for nargs < 2 is implementation dependent: currently we'll - * set a NaN time value (matching V8 behavior) in this case. - */ - - if (nargs < 2) { - duk_push_nan(thr); - } else { - duk__set_parts_from_args(thr, dparts, nargs); - d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/); - duk_push_number(thr, d); - } - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) { - duk_double_t d; - - d = duk_time_get_ecmascript_time_nofrac(thr); - DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */ - duk_push_number(thr, d); - return 1; -} - -/* - * String/JSON conversions - * - * Human readable conversions are now basically ISO 8601 with a space - * (instead of 'T') as the date/time separator. This is a good baseline - * and is platform independent. - * - * A shared native helper to provide many conversions. Magic value contains - * a set of flags. The helper provides: - * - * toString() - * toDateString() - * toTimeString() - * toLocaleString() - * toLocaleDateString() - * toLocaleTimeString() - * toUTCString() - * toISOString() - * - * Notes: - * - * - Date.prototype.toGMTString() and Date.prototype.toUTCString() are - * required to be the same Ecmascript function object (!), so it is - * omitted from here. - * - * - Date.prototype.toUTCString(): E5.1 specification does not require a - * specific format, but result should be human readable. The - * specification suggests using ISO 8601 format with a space (instead - * of 'T') separator if a more human readable format is not available. - * - * - Date.prototype.toISOString(): unlike other conversion functions, - * toISOString() requires a RangeError for invalid date values. - */ - -DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_hthread *thr) { - duk_small_uint_t flags = duk__date_get_indirect_magic(thr); - return duk__to_string_helper(thr, flags); -} - -DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_hthread *thr) { - /* This native function is also used for Date.prototype.getTime() - * as their behavior is identical. - */ - - duk_double_t d = duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ this ] */ - DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d)); - duk_push_number(thr, d); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_hthread *thr) { - /* Note: toJSON() is a generic function which works even if 'this' - * is not a Date. The sole argument is ignored. - */ - - duk_push_this(thr); - duk_to_object(thr, -1); - - duk_dup_top(thr); - duk_to_primitive(thr, -1, DUK_HINT_NUMBER); - if (duk_is_number(thr, -1)) { - duk_double_t d = duk_get_number(thr, -1); - if (!DUK_ISFINITE(d)) { - duk_push_null(thr); - return 1; - } - } - duk_pop(thr); - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_ISO_STRING); - duk_dup_m2(thr); /* -> [ O toIsoString O ] */ - duk_call_method(thr, 0); - return 1; -} - -/* - * Getters. - * - * Implementing getters is quite easy. The internal time value is either - * NaN, or represents milliseconds (without fractions) from Jan 1, 1970. - * The internal time value can be converted to integer parts, and each - * part will be normalized and will fit into a 32-bit signed integer. - * - * A shared native helper to provide all getters. Magic value contains - * a set of flags and also packs the date component index argument. The - * helper provides: - * - * getFullYear() - * getUTCFullYear() - * getMonth() - * getUTCMonth() - * getDate() - * getUTCDate() - * getDay() - * getUTCDay() - * getHours() - * getUTCHours() - * getMinutes() - * getUTCMinutes() - * getSeconds() - * getUTCSeconds() - * getMilliseconds() - * getUTCMilliseconds() - * getYear() - * - * Notes: - * - * - Date.prototype.getDate(): 'date' means day-of-month, and is - * zero-based in internal calculations but public API expects it to - * be one-based. - * - * - Date.prototype.getTime() and Date.prototype.valueOf() have identical - * behavior. They have separate function objects, but share the same C - * function (duk_bi_date_prototype_value_of). - */ - -DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_hthread *thr) { - duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(thr); - return duk__get_part_helper(thr, flags_and_idx); -} - -DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_hthread *thr) { - /* - * Return (t - LocalTime(t)) in minutes: - * - * t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t)) - * = -(LocalTZA + DaylightSavingTA(t)) - * - * where DaylightSavingTA() is checked for time 't'. - * - * Note that the sign of the result is opposite to common usage, - * e.g. for EE(S)T which normally is +2h or +3h from UTC, this - * function returns -120 or -180. - * - */ - - duk_double_t d; - duk_int_t tzoffset; - - /* Note: DST adjustment is determined using UTC time. */ - d = duk__push_this_get_timeval(thr, 0 /*flags*/); - DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d)); - if (DUK_ISNAN(d)) { - duk_push_nan(thr); - } else { - DUK_ASSERT(DUK_ISFINITE(d)); - tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); - duk_push_int(thr, -tzoffset / 60); - } - return 1; -} - -/* - * Setters. - * - * Setters are a bit more complicated than getters. Component setters - * break down the current time value into its (normalized) component - * parts, replace one or more components with -unnormalized- new values, - * and the components are then converted back into a time value. As an - * example of using unnormalized values: - * - * var d = new Date(1234567890); - * - * is equivalent to: - * - * var d = new Date(0); - * d.setUTCMilliseconds(1234567890); - * - * A shared native helper to provide almost all setters. Magic value - * contains a set of flags and also packs the "maxnargs" argument. The - * helper provides: - * - * setMilliseconds() - * setUTCMilliseconds() - * setSeconds() - * setUTCSeconds() - * setMinutes() - * setUTCMinutes() - * setHours() - * setUTCHours() - * setDate() - * setUTCDate() - * setMonth() - * setUTCMonth() - * setFullYear() - * setUTCFullYear() - * setYear() - * - * Notes: - * - * - Date.prototype.setYear() (Section B addition): special year check - * is omitted. NaN / Infinity will just flow through and ultimately - * result in a NaN internal time value. - * - * - Date.prototype.setYear() does not have optional arguments for - * setting month and day-in-month (like setFullYear()), but we indicate - * 'maxnargs' to be 3 to get the year written to the correct component - * index in duk__set_part_helper(). The function has nargs == 1, so only - * the year will be set regardless of actual argument count. - */ - -DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_hthread *thr) { - duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(thr); - return duk__set_part_helper(thr, flags_and_maxnargs); -} - -DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) { - duk_double_t d; - - (void) duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ timeval this ] */ - d = duk__timeclip(duk_to_number(thr, 0)); - duk_push_number(thr, d); - duk_dup_top(thr); - duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */ - - return 1; -} - -#endif /* DUK_USE_DATE_BUILTIN */ - -/* automatic undefs */ -#undef DUK__CF_ACCEPT -#undef DUK__CF_ACCEPT_NUL -#undef DUK__CF_NEG -#undef DUK__DPRINT_DPARTS -#undef DUK__DPRINT_PARTS -#undef DUK__DPRINT_PARTS_AND_DPARTS -#undef DUK__LOCAL_TZOFFSET_MAXITER -#undef DUK__NUM_ISO8601_PARSER_PARTS -#undef DUK__PACK_RULE -#undef DUK__PI_DAY -#undef DUK__PI_HOUR -#undef DUK__PI_MILLISECOND -#undef DUK__PI_MINUTE -#undef DUK__PI_MONTH -#undef DUK__PI_SECOND -#undef DUK__PI_TZHOUR -#undef DUK__PI_TZMINUTE -#undef DUK__PI_YEAR -#undef DUK__PM_DAY -#undef DUK__PM_HOUR -#undef DUK__PM_MILLISECOND -#undef DUK__PM_MINUTE -#undef DUK__PM_MONTH -#undef DUK__PM_SECOND -#undef DUK__PM_TZHOUR -#undef DUK__PM_TZMINUTE -#undef DUK__PM_YEAR -#undef DUK__RULE_MASK_PART_SEP -#undef DUK__SI_COLON -#undef DUK__SI_MINUS -#undef DUK__SI_NUL -#undef DUK__SI_PERIOD -#undef DUK__SI_PLUS -#undef DUK__SI_SPACE -#undef DUK__SI_T -#undef DUK__SI_Z -#undef DUK__SM_COLON -#undef DUK__SM_MINUS -#undef DUK__SM_NUL -#undef DUK__SM_PERIOD -#undef DUK__SM_PLUS -#undef DUK__SM_SPACE -#undef DUK__SM_T -#undef DUK__SM_Z -#undef DUK__UNPACK_RULE -#undef DUK__WEEKDAY_MOD_ADDER -#undef DUK__YEAR -#line 1 "duk_bi_date_unix.c" -/* - * Unix-like Date providers - * - * Generally useful Unix / POSIX / ANSI Date providers. - */ - -/* #include duk_internal.h -> already included */ - -/* The necessary #includes are in place in duk_config.h. */ - -/* Buffer sizes for some UNIX calls. Larger than strictly necessary - * to avoid Valgrind errors. - */ -#define DUK__STRPTIME_BUF_SIZE 64 -#define DUK__STRFTIME_BUF_SIZE 64 - -#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) -/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */ -DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) { - struct timeval tv; - duk_double_t d; - - if (gettimeofday(&tv, NULL) != 0) { - DUK_D(DUK_DPRINT("gettimeofday() failed")); - return 0.0; - } - - /* As of Duktape 2.2.0 allow fractions. */ - d = ((duk_double_t) tv.tv_sec) * 1000.0 + - ((duk_double_t) tv.tv_usec) / 1000.0; - - return d; -} -#endif /* DUK_USE_DATE_NOW_GETTIMEOFDAY */ - -#if defined(DUK_USE_DATE_NOW_TIME) -/* Not a very good provider: only full seconds are available. */ -DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(void) { - time_t t; - - t = time(NULL); - if (t == (time_t) -1) { - DUK_D(DUK_DPRINT("time() failed")); - return 0.0; - } - return ((duk_double_t) t) * 1000.0; -} -#endif /* DUK_USE_DATE_NOW_TIME */ - -#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) -/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */ -DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { - time_t t, t1, t2; - duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; - duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; - struct tm tms[2]; -#if defined(DUK_USE_DATE_TZO_GMTIME) - struct tm *tm_ptr; -#endif - - /* For NaN/inf, the return value doesn't matter. */ - if (!DUK_ISFINITE(d)) { - return 0; - } - - /* If not within Ecmascript range, some integer time calculations - * won't work correctly (and some asserts will fail), so bail out - * if so. This fixes test-bug-date-insane-setyear.js. There is - * a +/- 24h leeway in this range check to avoid a test262 corner - * case documented in test-bug-date-timeval-edges.js. - */ - if (!duk_bi_date_timeval_in_leeway_range(d)) { - DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows")); - return 0; - } - - /* - * This is a bit tricky to implement portably. The result depends - * on the timestamp (specifically, DST depends on the timestamp). - * If e.g. UNIX APIs are used, they'll have portability issues with - * very small and very large years. - * - * Current approach: - * - * - Stay within portable UNIX limits by using equivalent year mapping. - * Avoid year 1970 and 2038 as some conversions start to fail, at - * least on some platforms. Avoiding 1970 means that there are - * currently DST discrepancies for 1970. - * - * - Create a UTC and local time breakdowns from 't'. Then create - * a time_t using gmtime() and localtime() and compute the time - * difference between the two. - * - * Equivalent year mapping (E5 Section 15.9.1.8): - * - * If the host environment provides functionality for determining - * daylight saving time, the implementation of ECMAScript is free - * to map the year in question to an equivalent year (same - * leap-year-ness and same starting week day for the year) for which - * the host environment provides daylight saving time information. - * The only restriction is that all equivalent years should produce - * the same result. - * - * This approach is quite reasonable but not entirely correct, e.g. - * the specification also states (E5 Section 15.9.1.8): - * - * The implementation of ECMAScript should not try to determine - * whether the exact time was subject to daylight saving time, but - * just whether daylight saving time would have been in effect if - * the _current daylight saving time algorithm_ had been used at the - * time. This avoids complications such as taking into account the - * years that the locale observed daylight saving time year round. - * - * Since we rely on the platform APIs for conversions between local - * time and UTC, we can't guarantee the above. Rather, if the platform - * has historical DST rules they will be applied. This seems to be the - * general preferred direction in Ecmascript standardization (or at least - * implementations) anyway, and even the equivalent year mapping should - * be disabled if the platform is known to handle DST properly for the - * full Ecmascript range. - * - * The following has useful discussion and links: - * - * https://bugzilla.mozilla.org/show_bug.cgi?id=351066 - */ - - duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/); - DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038); - - d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/); - DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0); /* unsigned 31-bit range */ - t = (time_t) (d / 1000.0); - DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t)); - - DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2); - -#if defined(DUK_USE_DATE_TZO_GMTIME_R) - (void) gmtime_r(&t, &tms[0]); - (void) localtime_r(&t, &tms[1]); -#elif defined(DUK_USE_DATE_TZO_GMTIME_S) - (void) gmtime_s(&t, &tms[0]); - (void) localtime_s(&t, &tms[1]); -#elif defined(DUK_USE_DATE_TZO_GMTIME) - tm_ptr = gmtime(&t); - DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm)); - tm_ptr = localtime(&t); - DUK_MEMCPY((void *) &tms[1], tm_ptr, sizeof(struct tm)); -#else -#error internal error -#endif - DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld," - "wday:%ld,yday:%ld,isdst:%ld}", - (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour, - (long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year, - (long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst)); - DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld," - "wday:%ld,yday:%ld,isdst:%ld}", - (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour, - (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year, - (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst)); - - /* tm_isdst is both an input and an output to mktime(), use 0 to - * avoid DST handling in mktime(): - * - https://github.com/svaarala/duktape/issues/406 - * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst - */ - tms[0].tm_isdst = 0; - tms[1].tm_isdst = 0; - t1 = mktime(&tms[0]); /* UTC */ - t2 = mktime(&tms[1]); /* local */ - if (t1 == (time_t) -1 || t2 == (time_t) -1) { - /* This check used to be for (t < 0) but on some platforms - * time_t is unsigned and apparently the proper way to detect - * an mktime() error return is the cast above. See e.g.: - * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html - */ - goto mktime_error; - } - DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2)); - - /* Compute final offset in seconds, positive if local time ahead of - * UTC (returned value is UTC-to-local offset). - * - * difftime() returns a double, so coercion to int generates quite - * a lot of code. Direct subtraction is not portable, however. - * XXX: allow direct subtraction on known platforms. - */ -#if 0 - return (duk_int_t) (t2 - t1); -#endif - return (duk_int_t) difftime(t2, t1); - - mktime_error: - /* XXX: return something more useful, so that caller can throw? */ - DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d)); - return 0; -} -#endif /* DUK_USE_DATE_TZO_GMTIME */ - -#if defined(DUK_USE_DATE_PRS_STRPTIME) -DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str) { - struct tm tm; - time_t t; - char buf[DUK__STRPTIME_BUF_SIZE]; - - /* Copy to buffer with slack to avoid Valgrind gripes from strptime. */ - DUK_ASSERT(str != NULL); - DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */ - DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str); - buf[sizeof(buf) - 1] = (char) 0; - - DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf)); - - DUK_MEMZERO(&tm, sizeof(tm)); - if (strptime((const char *) buf, "%c", &tm) != NULL) { - DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld," - "wday:%ld,yday:%ld,isdst:%ld}", - (long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour, - (long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year, - (long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst)); - tm.tm_isdst = -1; /* negative: dst info not available */ - - t = mktime(&tm); - DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t)); - if (t >= 0) { - duk_push_number(thr, ((duk_double_t) t) * 1000.0); - return 1; - } - } - - return 0; -} -#endif /* DUK_USE_DATE_PRS_STRPTIME */ - -#if defined(DUK_USE_DATE_PRS_GETDATE) -DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str) { - struct tm tm; - duk_small_int_t rc; - time_t t; - - /* For this to work, DATEMSK must be set, so this is not very - * convenient for an embeddable interpreter. - */ - - DUK_MEMZERO(&tm, sizeof(struct tm)); - rc = (duk_small_int_t) getdate_r(str, &tm); - DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc)); - - if (rc == 0) { - t = mktime(&tm); - DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t)); - if (t >= 0) { - duk_push_number(thr, (duk_double_t) t); - return 1; - } - } - - return 0; -} -#endif /* DUK_USE_DATE_PRS_GETDATE */ - -#if defined(DUK_USE_DATE_FMT_STRFTIME) -DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) { - char buf[DUK__STRFTIME_BUF_SIZE]; - struct tm tm; - const char *fmt; - - DUK_UNREF(tzoffset); - - /* If the platform doesn't support the entire Ecmascript range, we need - * to return 0 so that the caller can fall back to the default formatter. - * - * For now, assume that if time_t is 8 bytes or more, the whole Ecmascript - * range is supported. For smaller time_t values (4 bytes in practice), - * assumes that the signed 32-bit range is supported. - * - * XXX: detect this more correctly per platform. The size of time_t is - * probably not an accurate guarantee of strftime() supporting or not - * supporting a large time range (the full Ecmascript range). - */ - if (sizeof(time_t) < 8 && - (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) { - /* be paranoid for 32-bit time values (even avoiding negative ones) */ - return 0; - } - - DUK_MEMZERO(&tm, sizeof(tm)); - tm.tm_sec = parts[DUK_DATE_IDX_SECOND]; - tm.tm_min = parts[DUK_DATE_IDX_MINUTE]; - tm.tm_hour = parts[DUK_DATE_IDX_HOUR]; - tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */ - tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */ - tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900; - tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY]; - tm.tm_isdst = 0; - - DUK_MEMZERO(buf, sizeof(buf)); - if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) { - fmt = "%c"; - } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) { - fmt = "%x"; - } else { - DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME); - fmt = "%X"; - } - (void) strftime(buf, sizeof(buf) - 1, fmt, &tm); - DUK_ASSERT(buf[sizeof(buf) - 1] == 0); - - duk_push_string(thr, buf); - return 1; -} -#endif /* DUK_USE_DATE_FMT_STRFTIME */ - -#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME) -DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { - return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0; - } else { - DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed")); - return 0.0; - } -} -#endif - -/* automatic undefs */ -#undef DUK__STRFTIME_BUF_SIZE -#undef DUK__STRPTIME_BUF_SIZE -#line 1 "duk_bi_date_windows.c" -/* - * Windows Date providers - * - * Platform specific links: - * - * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx - */ - -/* #include duk_internal.h -> already included */ - -/* The necessary #includes are in place in duk_config.h. */ - -#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) -/* Shared Windows helpers. */ -DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) { - FILETIME ft; - if (SystemTimeToFileTime(st, &ft) == 0) { - DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0")); - res->QuadPart = 0; - } else { - res->LowPart = ft.dwLowDateTime; - res->HighPart = ft.dwHighDateTime; - } -} - -DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) { - res->LowPart = ft->dwLowDateTime; - res->HighPart = ft->dwHighDateTime; -} - -DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) { - DUK_MEMZERO((void *) st, sizeof(*st)); - st->wYear = 1970; - st->wMonth = 1; - st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */ - st->wDay = 1; - DUK_ASSERT(st->wHour == 0); - DUK_ASSERT(st->wMinute == 0); - DUK_ASSERT(st->wSecond == 0); - DUK_ASSERT(st->wMilliseconds == 0); -} -#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */ - -#if defined(DUK_USE_DATE_NOW_WINDOWS) -DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) { - /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970: - * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx - */ - SYSTEMTIME st1, st2; - ULARGE_INTEGER tmp1, tmp2; - - GetSystemTime(&st1); - duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1); - - duk__set_systime_jan1970(&st2); - duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); - - /* Difference is in 100ns units, convert to milliseconds, keeping - * fractions since Duktape 2.2.0. This is only theoretical because - * SYSTEMTIME is limited to milliseconds. - */ - return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0; -} -#endif /* DUK_USE_DATE_NOW_WINDOWS */ - -#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) -DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) { - /* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime() - * for more accuracy. - */ - FILETIME ft1; - SYSTEMTIME st2; - ULARGE_INTEGER tmp1, tmp2; - - GetSystemTimePreciseAsFileTime(&ft1); - duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1); - - duk__set_systime_jan1970(&st2); - duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); - - /* Difference is in 100ns units, convert to milliseconds, keeping - * fractions since Duktape 2.2.0. - */ - return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0; -} -#endif /* DUK_USE_DATE_NOW_WINDOWS */ - -#if defined(DUK_USE_DATE_TZO_WINDOWS) -DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) { - SYSTEMTIME st1; - SYSTEMTIME st2; - SYSTEMTIME st3; - ULARGE_INTEGER tmp1; - ULARGE_INTEGER tmp2; - ULARGE_INTEGER tmp3; - FILETIME ft1; - - /* XXX: handling of timestamps outside Windows supported range. - * How does Windows deal with dates before 1600? Does windows - * support all Ecmascript years (like -200000 and +200000)? - * Should equivalent year mapping be used here too? If so, use - * a shared helper (currently integrated into timeval-to-parts). - */ - - /* Use the approach described in "Remarks" of FileTimeToLocalFileTime: - * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx - */ - - duk__set_systime_jan1970(&st1); - duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1); - tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */ - tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */ - - ft1.dwLowDateTime = tmp2.LowPart; - ft1.dwHighDateTime = tmp2.HighPart; - FileTimeToSystemTime((const FILETIME *) &ft1, &st2); - if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) { - DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0")); - return 0; - } - duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3); - - /* Positive if local time ahead of UTC. */ - return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */ -} -#endif /* DUK_USE_DATE_TZO_WINDOWS */ - -#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) -DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) { - SYSTEMTIME st1; - SYSTEMTIME st2; - FILETIME ft1; - FILETIME ft2; - ULARGE_INTEGER tmp1; - ULARGE_INTEGER tmp2; - - /* Do a similar computation to duk_bi_date_get_local_tzoffset_windows - * but without accounting for daylight savings time. Use this on - * Windows platforms (like Durango) that don't support the - * SystemTimeToTzSpecificLocalTime() call. - */ - - /* current time not needed for this computation */ - DUK_UNREF(d); - - duk__set_systime_jan1970(&st1); - duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1); - - ft1.dwLowDateTime = tmp1.LowPart; - ft1.dwHighDateTime = tmp1.HighPart; - FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2); - - FileTimeToSystemTime((const FILETIME *) &ft2, &st2); - duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); - - return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */ -} -#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */ - -#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) -DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) { - LARGE_INTEGER count, freq; - - /* There are legacy issues with QueryPerformanceCounter(): - * - Potential jumps: https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward - * - Differences between cores (XP): https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions - * - * We avoid these by enabling QPC by default only for Vista or later. - */ - - if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) { - /* XXX: QueryPerformanceFrequency() can be cached */ - return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0; - } else { - /* MSDN: "On systems that run Windows XP or later, the function - * will always succeed and will thus never return zero." - * Provide minimal error path just in case user enables this - * feature in pre-XP Windows. - */ - return 0.0; - } -} -#endif /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */ -#line 1 "duk_bi_duktape.c" -/* - * Duktape built-ins - * - * Size optimization note: it might seem that vararg multipurpose functions - * like fin(), enc(), and dec() are not very size optimal, but using a single - * user-visible Ecmascript function saves a lot of run-time footprint; each - * Function instance takes >100 bytes. Using a shared native helper and a - * 'magic' value won't save much if there are multiple Function instances - * anyway. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_DUKTAPE_BUILTIN) - -DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) { - duk_inspect_value(thr, -1); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) { - duk_int_t level; - - level = duk_to_int(thr, 0); - duk_inspect_callstack_entry(thr, level); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) { - duk_small_uint_t flags; - - flags = (duk_small_uint_t) duk_get_uint(thr, 0); - duk_heap_mark_and_sweep(thr->heap, flags); - - /* XXX: Not sure what the best return value would be in the API. - * Return true for now. - */ - duk_push_true(thr); - return 1; -} - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_hthread *thr) { - (void) duk_require_hobject(thr, 0); - if (duk_get_top(thr) >= 2) { - /* Set: currently a finalizer is disabled by setting it to - * undefined; this does not remove the property at the moment. - * The value could be type checked to be either a function - * or something else; if something else, the property could - * be deleted. Must use duk_set_finalizer() to keep - * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync. - */ - duk_set_top(thr, 2); - duk_set_finalizer(thr, 0); - return 0; - } else { - /* Get. */ - DUK_ASSERT(duk_get_top(thr) == 1); - duk_get_finalizer(thr, 0); - return 1; - } -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_hthread *thr) { - duk_hstring *h_str; - - /* Vararg function: must be careful to check/require arguments. - * The JSON helpers accept invalid indices and treat them like - * non-existent optional parameters. - */ - - h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons. */ - duk_require_valid_index(thr, 1); - - if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { - duk_set_top(thr, 2); - duk_hex_encode(thr, 1); - DUK_ASSERT_TOP(thr, 2); - } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) { - duk_set_top(thr, 2); - duk_base64_encode(thr, 1); - DUK_ASSERT_TOP(thr, 2); -#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX) - } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) { - duk_bi_json_stringify_helper(thr, - 1 /*idx_value*/, - 2 /*idx_replacer*/, - 3 /*idx_space*/, - DUK_JSON_FLAG_EXT_CUSTOM | - DUK_JSON_FLAG_ASCII_ONLY | - DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/); -#endif -#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC) - } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) { - duk_bi_json_stringify_helper(thr, - 1 /*idx_value*/, - 2 /*idx_replacer*/, - 3 /*idx_space*/, - DUK_JSON_FLAG_EXT_COMPATIBLE | - DUK_JSON_FLAG_ASCII_ONLY /*flags*/); -#endif - } else { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_hthread *thr) { - duk_hstring *h_str; - - /* Vararg function: must be careful to check/require arguments. - * The JSON helpers accept invalid indices and treat them like - * non-existent optional parameters. - */ - - h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons */ - duk_require_valid_index(thr, 1); - - if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { - duk_set_top(thr, 2); - duk_hex_decode(thr, 1); - DUK_ASSERT_TOP(thr, 2); - } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) { - duk_set_top(thr, 2); - duk_base64_decode(thr, 1); - DUK_ASSERT_TOP(thr, 2); -#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX) - } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) { - duk_bi_json_parse_helper(thr, - 1 /*idx_value*/, - 2 /*idx_replacer*/, - DUK_JSON_FLAG_EXT_CUSTOM /*flags*/); -#endif -#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC) - } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) { - duk_bi_json_parse_helper(thr, - 1 /*idx_value*/, - 2 /*idx_replacer*/, - DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/); -#endif - } else { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - return 1; -} - -/* - * Compact an object - */ - -DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_hthread *thr) { - DUK_ASSERT_TOP(thr, 1); - duk_compact(thr, 0); - return 1; /* return the argument object */ -} - -#endif /* DUK_USE_DUKTAPE_BUILTIN */ -#line 1 "duk_bi_encoding.c" -/* - * WHATWG Encoding API built-ins - * - * API specification: https://encoding.spec.whatwg.org/#api - * Web IDL: https://www.w3.org/TR/WebIDL/ - */ - -/* #include duk_internal.h -> already included */ - -/* - * Data structures for encoding/decoding - */ - -typedef struct { - duk_uint8_t *out; /* where to write next byte(s) */ - duk_codepoint_t lead; /* lead surrogate */ -} duk__encode_context; - -typedef struct { - /* UTF-8 decoding state */ - duk_codepoint_t codepoint; /* built up incrementally */ - duk_uint8_t upper; /* max value of next byte (decode error otherwise) */ - duk_uint8_t lower; /* min value of next byte (ditto) */ - duk_uint8_t needed; /* how many more bytes we need */ - duk_uint8_t bom_handled; /* BOM seen or no longer expected */ - - /* Decoder configuration */ - duk_uint8_t fatal; - duk_uint8_t ignore_bom; -} duk__decode_context; - -/* The signed duk_codepoint_t type is used to signal a decoded codepoint - * (>= 0) or various other states using negative values. - */ -#define DUK__CP_CONTINUE (-1) /* continue to next byte, no completed codepoint */ -#define DUK__CP_ERROR (-2) /* decoding error */ -#define DUK__CP_RETRY (-3) /* decoding error; retry last byte */ - -/* - * Raw helpers for encoding/decoding - */ - -/* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */ -DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) { - *ptr++ = 0xef; - *ptr++ = 0xbf; - *ptr++ = 0xbd; - return ptr; -} - -DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) { - /* (Re)init the decoding state of 'dec_ctx' but leave decoder - * configuration fields untouched. - */ - dec_ctx->codepoint = 0x0000L; - dec_ctx->upper = 0xbf; - dec_ctx->lower = 0x80; - dec_ctx->needed = 0; - dec_ctx->bom_handled = 0; -} - -DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) { - /* - * UTF-8 algorithm based on the Encoding specification: - * https://encoding.spec.whatwg.org/#utf-8-decoder - * - * Two main states: decoding initial byte vs. decoding continuation - * bytes. Shortest length encoding is validated by restricting the - * allowed range of first continuation byte using 'lower' and 'upper'. - */ - - if (dec_ctx->needed == 0) { - /* process initial byte */ - if (x <= 0x7f) { - /* U+0000-U+007F, 1 byte (ASCII) */ - return (duk_codepoint_t) x; - } else if (x >= 0xc2 && x <= 0xdf) { - /* U+0080-U+07FF, 2 bytes */ - dec_ctx->needed = 1; - dec_ctx->codepoint = x & 0x1f; - DUK_ASSERT(dec_ctx->lower == 0x80); - DUK_ASSERT(dec_ctx->upper == 0xbf); - return DUK__CP_CONTINUE; - } else if (x >= 0xe0 && x <= 0xef) { - /* U+0800-U+FFFF, 3 bytes */ - if (x == 0xe0) { - dec_ctx->lower = 0xa0; - DUK_ASSERT(dec_ctx->upper == 0xbf); - } else if (x == 0xed) { - DUK_ASSERT(dec_ctx->lower == 0x80); - dec_ctx->upper = 0x9f; - } - dec_ctx->needed = 2; - dec_ctx->codepoint = x & 0x0f; - return DUK__CP_CONTINUE; - } else if (x >= 0xf0 && x <= 0xf4) { - /* U+010000-U+10FFFF, 4 bytes */ - if (x == 0xf0) { - dec_ctx->lower = 0x90; - DUK_ASSERT(dec_ctx->upper == 0xbf); - } else if (x == 0xf4) { - DUK_ASSERT(dec_ctx->lower == 0x80); - dec_ctx->upper = 0x8f; - } - dec_ctx->needed = 3; - dec_ctx->codepoint = x & 0x07; - return DUK__CP_CONTINUE; - } else { - /* not a legal initial byte */ - return DUK__CP_ERROR; - } - } else { - /* process continuation byte */ - if (x >= dec_ctx->lower && x <= dec_ctx->upper) { - dec_ctx->lower = 0x80; - dec_ctx->upper = 0xbf; - dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f); - if (--dec_ctx->needed > 0) { - /* need more bytes */ - return DUK__CP_CONTINUE; - } else { - /* got a codepoint */ - duk_codepoint_t ret; - DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL); /* Decoding rules guarantee. */ - ret = dec_ctx->codepoint; - dec_ctx->codepoint = 0x0000L; - dec_ctx->needed = 0; - return ret; - } - } else { - /* We just encountered an illegal UTF-8 continuation byte. This might - * be the initial byte of the next character; if we return a plain - * error status and the decoder is in replacement mode, the character - * will be masked. We still need to alert the caller to the error - * though. - */ - dec_ctx->codepoint = 0x0000L; - dec_ctx->needed = 0; - dec_ctx->lower = 0x80; - dec_ctx->upper = 0xbf; - return DUK__CP_RETRY; - } - } -} - -#if defined(DUK_USE_ENCODING_BUILTINS) -DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) { - duk__encode_context *enc_ctx; - - DUK_ASSERT(codepoint >= 0); - enc_ctx = (duk__encode_context *) udata; - DUK_ASSERT(enc_ctx != NULL); - -#if !defined(DUK_USE_PREFER_SIZE) - if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) { - /* Fast path for ASCII. */ - *enc_ctx->out++ = (duk_uint8_t) codepoint; - return; - } -#endif - - if (DUK_UNLIKELY(codepoint > 0x10ffffL)) { - /* cannot legally encode in UTF-8 */ - codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; - } else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) { - if (codepoint <= 0xdbffL) { - /* high surrogate */ - duk_codepoint_t prev_lead = enc_ctx->lead; - enc_ctx->lead = codepoint; - if (prev_lead == 0x0000L) { - /* high surrogate, no output */ - return; - } else { - /* consecutive high surrogates, consider first one unpaired */ - codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; - } - } else { - /* low surrogate */ - if (enc_ctx->lead != 0x0000L) { - codepoint = (duk_codepoint_t) (0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L)); - enc_ctx->lead = 0x0000L; - } else { - /* unpaired low surrogate */ - DUK_ASSERT(enc_ctx->lead == 0x0000L); - codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; - } - } - } else { - if (enc_ctx->lead != 0x0000L) { - /* unpaired high surrogate: emit replacement character and the input codepoint */ - enc_ctx->lead = 0x0000L; - enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out); - } - } - - /* Codepoint may be original input, a decoded surrogate pair, or may - * have been replaced with U+FFFD. - */ - enc_ctx->out += duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, enc_ctx->out); -} -#endif /* DUK_USE_ENCODING_BUILTINS */ - -/* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8 - * decoder. - */ -DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *dec_ctx) { - const duk_uint8_t *input; - duk_size_t len = 0; - duk_size_t len_tmp; - duk_bool_t stream = 0; - duk_codepoint_t codepoint; - duk_uint8_t *output; - const duk_uint8_t *in; - duk_uint8_t *out; - - DUK_ASSERT(dec_ctx != NULL); - - /* Careful with input buffer pointer: any side effects involving - * code execution (e.g. getters, coercion calls, and finalizers) - * may cause a resize and invalidate a pointer we've read. This - * is why the pointer is actually looked up at the last minute. - * Argument validation must still happen first to match WHATWG - * required side effect order. - */ - - if (duk_is_undefined(thr, 0)) { - duk_push_fixed_buffer_nozero(thr, 0); - duk_replace(thr, 0); - } - (void) duk_require_buffer_data(thr, 0, &len); /* Need 'len', avoid pointer. */ - - if (duk_check_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED | - DUK_TYPE_MASK_NULL | - DUK_TYPE_MASK_NONE)) { - /* Use defaults, treat missing value like undefined. */ - } else { - duk_require_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED | - DUK_TYPE_MASK_NULL | - DUK_TYPE_MASK_LIGHTFUNC | - DUK_TYPE_MASK_BUFFER | - DUK_TYPE_MASK_OBJECT); - if (duk_get_prop_string(thr, 1, "stream")) { - stream = duk_to_boolean(thr, -1); - } - } - - /* Allowance is 3*len in the general case because all bytes may potentially - * become U+FFFD. If the first byte completes a non-BMP codepoint it will - * decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to - * compensate: (1*3)+3 = 6. Non-BMP codepoints are safe otherwise because - * the 4->6 expansion is well under the 3x allowance. - * - * XXX: As with TextEncoder, need a better buffer allocation strategy here. - */ - if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) { - DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG); - } - output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */ - - input = (const duk_uint8_t *) duk_get_buffer_data(thr, 0, &len_tmp); - DUK_ASSERT(input != NULL || len == 0); - if (DUK_UNLIKELY(len != len_tmp)) { - /* Very unlikely but possible: source buffer was resized by - * a side effect when fixed buffer was pushed. Output buffer - * may not be large enough to hold output, so just fail if - * length has changed. - */ - DUK_D(DUK_DPRINT("input buffer resized by side effect, fail")); - goto fail_type; - } - - /* From this point onwards it's critical that no side effect occur - * which may disturb 'input': finalizer execution, property accesses, - * active coercions, etc. Even an allocation related mark-and-sweep - * may affect the pointer because it may trigger a pending finalizer. - */ - - in = input; - out = output; - while (in < input + len) { - codepoint = duk__utf8_decode_next(dec_ctx, *in++); - if (codepoint < 0) { - if (codepoint == DUK__CP_CONTINUE) { - continue; - } - - /* Decoding error with or without retry. */ - DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY); - if (codepoint == DUK__CP_RETRY) { - --in; /* retry last byte */ - } - /* replacement mode: replace with U+FFFD */ - codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; - if (dec_ctx->fatal) { - /* fatal mode: throw a TypeError */ - goto fail_type; - } - /* Continue with 'codepoint', Unicode replacement. */ - } - DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL); - - if (!dec_ctx->bom_handled) { - dec_ctx->bom_handled = 1; - if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) { - continue; - } - } - - out += duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, out); - DUK_ASSERT(out <= output + (3 + (3 * len))); - } - - if (!stream) { - if (dec_ctx->needed != 0) { - /* truncated sequence at end of buffer */ - if (dec_ctx->fatal) { - goto fail_type; - } else { - out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out); - DUK_ASSERT(out <= output + (3 + (3 * len))); - } - } - duk__utf8_decode_init(dec_ctx); /* Initialize decoding state for potential reuse. */ - } - - /* Output buffer is fixed and thus stable even if there had been - * side effects (which there shouldn't be). - */ - duk_push_lstring(thr, (const char *) output, (duk_size_t) (out - output)); - return 1; - - fail_type: - DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED); - DUK_UNREACHABLE(); -} - -/* - * Built-in bindings - */ - -#if defined(DUK_USE_ENCODING_BUILTINS) -DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) { - /* TextEncoder currently requires no persistent state, so the constructor - * does nothing on purpose. - */ - - duk_require_constructor_call(thr); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) { - duk_push_string(thr, "utf-8"); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) { - duk__encode_context enc_ctx; - duk_size_t len; - duk_size_t final_len; - duk_uint8_t *output; - - DUK_ASSERT_TOP(thr, 1); - if (duk_is_undefined(thr, 0)) { - len = 0; - } else { - duk_hstring *h_input; - - h_input = duk_to_hstring(thr, 0); - DUK_ASSERT(h_input != NULL); - - len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input); - if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) { - DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG); - } - } - - /* Allowance is 3*len because all bytes can potentially be replaced with - * U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8. - * Rely on dynamic buffer data pointer stability: no other code has - * access to the data pointer. - * - * XXX: The buffer allocation strategy used here is rather inefficient. - * Maybe switch to a chunk-based strategy, or preprocess the string to - * figure out the space needed ahead of time? - */ - DUK_ASSERT(3 * len >= len); - output = (duk_uint8_t *) duk_push_dynamic_buffer(thr, 3 * len); - - if (len > 0) { - DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */ - - /* XXX: duk_decode_string() is used to process the input - * string. For standard Ecmascript strings, represented - * internally as CESU-8, this is fine. However, behavior - * beyond CESU-8 is not very strict: codepoints using an - * extended form of UTF-8 are also accepted, and invalid - * codepoint sequences (which are allowed in Duktape strings) - * are not handled as well as they could (e.g. invalid - * continuation bytes may mask following codepoints). - * This is how Ecmascript code would also see such strings. - * Maybe replace duk_decode_string() with an explicit strict - * CESU-8 decoder here? - */ - enc_ctx.lead = 0x0000L; - enc_ctx.out = output; - duk_decode_string(thr, 0, duk__utf8_encode_char, (void *) &enc_ctx); - if (enc_ctx.lead != 0x0000L) { - /* unpaired high surrogate at end of string */ - enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out); - DUK_ASSERT(enc_ctx.out <= output + (3 * len)); - } - - /* The output buffer is usually very much oversized, so shrink it to - * actually needed size. Pointer stability assumed up to this point. - */ - DUK_ASSERT_TOP(thr, 2); - DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(thr, -1, NULL)); - - final_len = (duk_size_t) (enc_ctx.out - output); - duk_resize_buffer(thr, -1, final_len); - /* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */ - } else { - final_len = 0; - } - - /* Standard WHATWG output is a Uint8Array. Here the Uint8Array will - * be backed by a dynamic buffer which differs from e.g. Uint8Arrays - * created as 'new Uint8Array(N)'. Ecmascript code won't see the - * difference but C code will. When bufferobjects are not supported, - * returns a plain dynamic buffer. - */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - duk_push_buffer_object(thr, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY); -#endif - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) { - duk__decode_context *dec_ctx; - duk_bool_t fatal = 0; - duk_bool_t ignore_bom = 0; - - DUK_ASSERT_TOP(thr, 2); - duk_require_constructor_call(thr); - if (!duk_is_undefined(thr, 0)) { - /* XXX: For now ignore 'label' (encoding identifier). */ - duk_to_string(thr, 0); - } - if (!duk_is_null_or_undefined(thr, 1)) { - if (duk_get_prop_string(thr, 1, "fatal")) { - fatal = duk_to_boolean(thr, -1); - } - if (duk_get_prop_string(thr, 1, "ignoreBOM")) { - ignore_bom = duk_to_boolean(thr, -1); - } - } - - duk_push_this(thr); - - /* The decode context is not assumed to be zeroed; all fields are - * initialized explicitly. - */ - dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(thr, sizeof(duk__decode_context)); - dec_ctx->fatal = (duk_uint8_t) fatal; - dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom; - duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */ - - duk_put_prop_string(thr, -2, DUK_INTERNAL_SYMBOL("Context")); - return 0; -} - -/* Get TextDecoder context from 'this'; leaves garbage on stack. */ -DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) { - duk__decode_context *dec_ctx; - duk_push_this(thr); - duk_get_prop_string(thr, -1, DUK_INTERNAL_SYMBOL("Context")); - dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL); - DUK_ASSERT(dec_ctx != NULL); - return dec_ctx; -} - -DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *thr) { - duk__decode_context *dec_ctx; - duk_int_t magic; - - dec_ctx = duk__get_textdecoder_context(thr); - magic = duk_get_current_magic(thr); - switch (magic) { - case 0: - /* Encoding is now fixed, so _Context lookup is only needed to - * validate the 'this' binding (TypeError if not TextDecoder-like). - */ - duk_push_string(thr, "utf-8"); - break; - case 1: - duk_push_boolean(thr, dec_ctx->fatal); - break; - default: - duk_push_boolean(thr, dec_ctx->ignore_bom); - break; - } - - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_hthread *thr) { - duk__decode_context *dec_ctx; - - dec_ctx = duk__get_textdecoder_context(thr); - return duk__decode_helper(thr, dec_ctx); -} -#endif /* DUK_USE_ENCODING_BUILTINS */ - -/* - * Internal helper for Node.js Buffer - */ - -/* Internal helper used for Node.js Buffer .toString(). Value stack convention - * is currently odd: it mimics TextDecoder .decode() so that argument must be at - * index 0, and decode options (not present for Buffer) at index 1. Return value - * is a Duktape/C function return value. - */ -DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr) { - duk__decode_context dec_ctx; - - dec_ctx.fatal = 0; /* use replacement chars */ - dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */ - duk__utf8_decode_init(&dec_ctx); - - return duk__decode_helper(thr, &dec_ctx); -} - -/* automatic undefs */ -#undef DUK__CP_CONTINUE -#undef DUK__CP_ERROR -#undef DUK__CP_RETRY -#line 1 "duk_bi_error.c" -/* - * Error built-ins - */ - -/* #include duk_internal.h -> already included */ - -DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_hthread *thr) { - /* Behavior for constructor and non-constructor call is - * the same except for augmenting the created error. When - * called as a constructor, the caller (duk_new()) will handle - * augmentation; when called as normal function, we need to do - * it here. - */ - - duk_small_int_t bidx_prototype = duk_get_current_magic(thr); - - /* same for both error and each subclass like TypeError */ - duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR); - - (void) duk_push_object_helper(thr, flags_and_class, bidx_prototype); - - /* If message is undefined, the own property 'message' is not set at - * all to save property space. An empty message is inherited anyway. - */ - if (!duk_is_undefined(thr, 0)) { - duk_to_string(thr, 0); - duk_dup_0(thr); /* [ message error message ] */ - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); - } - - /* Augment the error if called as a normal function. __FILE__ and __LINE__ - * are not desirable in this case. - */ - -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) - if (!duk_is_constructor_call(thr)) { - duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE); - } -#endif - - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) { - /* XXX: optimize with more direct internal access */ - - duk_push_this(thr); - (void) duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - - /* [ ... this ] */ - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME); - if (duk_is_undefined(thr, -1)) { - duk_pop(thr); - duk_push_string(thr, "Error"); - } else { - duk_to_string(thr, -1); - } - - /* [ ... this name ] */ - - /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by - * accident or are they actually needed? The first ToString() - * could conceivably return 'undefined'. - */ - duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE); - if (duk_is_undefined(thr, -1)) { - duk_pop(thr); - duk_push_hstring_empty(thr); - } else { - duk_to_string(thr, -1); - } - - /* [ ... this name message ] */ - - if (duk_get_length(thr, -2) == 0) { - /* name is empty -> return message */ - return 1; - } - if (duk_get_length(thr, -1) == 0) { - /* message is empty -> return name */ - duk_pop(thr); - return 1; - } - duk_push_string(thr, ": "); - duk_insert(thr, -2); /* ... name ': ' message */ - duk_concat(thr, 3); - - return 1; -} - -#if defined(DUK_USE_TRACEBACKS) - -/* - * Traceback handling - * - * The unified helper decodes the traceback and produces various requested - * outputs. It should be optimized for size, and may leave garbage on stack, - * only the topmost return value matters. For instance, traceback separator - * and decoded strings are pushed even when looking for filename only. - * - * NOTE: although _Tracedata is an internal property, user code can currently - * write to the array (or replace it with something other than an array). - * The code below must tolerate arbitrary _Tracedata. It can throw errors - * etc, but cannot cause a segfault or memory unsafe behavior. - */ - -/* constants arbitrary, chosen for small loads */ -#define DUK__OUTPUT_TYPE_TRACEBACK (-1) -#define DUK__OUTPUT_TYPE_FILENAME 0 -#define DUK__OUTPUT_TYPE_LINENUMBER 1 - -DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t output_type) { - duk_idx_t idx_td; - duk_small_int_t i; /* traceback depth fits into 16 bits */ - duk_small_int_t t; /* stack type fits into 16 bits */ - duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */ - const char *str_tailcall = " tailcall"; - const char *str_strict = " strict"; - const char *str_construct = " construct"; - const char *str_prevyield = " preventsyield"; - const char *str_directeval = " directeval"; - const char *str_empty = ""; - - DUK_ASSERT_TOP(thr, 0); /* fixed arg count */ - - duk_push_this(thr); - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TRACEDATA); - idx_td = duk_get_top_index(thr); - - duk_push_hstring_stridx(thr, DUK_STRIDX_NEWLINE_4SPACE); - duk_push_this(thr); - - /* [ ... this tracedata sep this ] */ - - /* XXX: skip null filename? */ - - if (duk_check_type(thr, idx_td, DUK_TYPE_OBJECT)) { - /* Current tracedata contains 2 entries per callstack entry. */ - for (i = 0; ; i += 2) { - duk_int_t pc; - duk_uint_t line; - duk_uint_t flags; - duk_double_t d; - const char *funcname; - const char *filename; - duk_hobject *h_func; - duk_hstring *h_name; - - duk_require_stack(thr, 5); - duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i); - duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1)); - d = duk_to_number_m1(thr); - pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32); - flags = (duk_uint_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32); - t = (duk_small_int_t) duk_get_type(thr, -2); - - if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) { - /* - * Ecmascript/native function call or lightfunc call - */ - - count_func++; - - /* [ ... v1(func) v2(pc+flags) ] */ - - /* These may be systematically omitted by Duktape - * with certain config options, but allow user to - * set them on a case-by-case basis. - */ - duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME); - duk_get_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME); - -#if defined(DUK_USE_PC2LINE) - line = (duk_uint_t) duk_hobject_pc2line_query(thr, -4, (duk_uint_fast32_t) pc); -#else - line = 0; -#endif - - /* [ ... v1 v2 name filename ] */ - - /* When looking for .fileName/.lineNumber, blame first - * function which has a .fileName. - */ - if (duk_is_string_notsymbol(thr, -1)) { - if (output_type == DUK__OUTPUT_TYPE_FILENAME) { - return 1; - } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { - duk_push_uint(thr, line); - return 1; - } - } - - /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */ - /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */ - h_name = duk_get_hstring_notsymbol(thr, -2); /* may be NULL */ - funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ? - "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name); - filename = duk_get_string_notsymbol(thr, -1); - filename = filename ? filename : ""; - DUK_ASSERT(funcname != NULL); - DUK_ASSERT(filename != NULL); - - h_func = duk_get_hobject(thr, -4); /* NULL for lightfunc */ - - if (h_func == NULL) { - duk_push_sprintf(thr, "at %s light%s%s%s%s%s", - (const char *) funcname, - (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); - } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) { - duk_push_sprintf(thr, "at %s (%s) native%s%s%s%s%s", - (const char *) funcname, - (const char *) filename, - (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); - } else { - duk_push_sprintf(thr, "at %s (%s:%lu)%s%s%s%s%s", - (const char *) funcname, - (const char *) filename, - (unsigned long) line, - (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), - (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); - } - duk_replace(thr, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */ - duk_pop_3(thr); /* -> [ ... str ] */ - } else if (t == DUK_TYPE_STRING) { - const char *str_file; - - /* - * __FILE__ / __LINE__ entry, here 'pc' is line number directly. - * Sometimes __FILE__ / __LINE__ is reported as the source for - * the error (fileName, lineNumber), sometimes not. - */ - - /* [ ... v1(filename) v2(line+flags) ] */ - - /* When looking for .fileName/.lineNumber, blame compilation - * or C call site unless flagged not to do so. - */ - if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) { - if (output_type == DUK__OUTPUT_TYPE_FILENAME) { - duk_pop(thr); - return 1; - } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { - duk_push_int(thr, pc); - return 1; - } - } - - /* Tracedata is trusted but avoid any risk of using a NULL - * for %s format because it has undefined behavior. Symbols - * don't need to be explicitly rejected as they pose no memory - * safety issues. - */ - str_file = (const char *) duk_get_string(thr, -2); - duk_push_sprintf(thr, "at [anon] (%s:%ld) internal", - (const char *) (str_file ? str_file : "null"), (long) pc); - duk_replace(thr, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */ - duk_pop(thr); /* -> [ ... str ] */ - } else { - /* unknown, ignore */ - duk_pop_2(thr); - break; - } - } - - if (count_func >= DUK_USE_TRACEBACK_DEPTH) { - /* Possibly truncated; there is no explicit truncation - * marker so this is the best we can do. - */ - - duk_push_hstring_stridx(thr, DUK_STRIDX_BRACKETED_ELLIPSIS); - } - } - - /* [ ... this tracedata sep this str1 ... strN ] */ - - if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) { - return 0; - } else { - /* The 'this' after 'sep' will get ToString() coerced by - * duk_join() automatically. We don't want to do that - * coercion when providing .fileName or .lineNumber (GH-254). - */ - duk_join(thr, duk_get_top(thr) - (idx_td + 2) /*count, not including sep*/); - return 1; - } -} - -/* XXX: Output type could be encoded into native function 'magic' value to - * save space. For setters the stridx could be encoded into 'magic'. - */ - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) { - return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_TRACEBACK); -} - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) { - return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_FILENAME); -} - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) { - return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_LINENUMBER); -} - -#else /* DUK_USE_TRACEBACKS */ - -/* - * Traceback handling when tracebacks disabled. - * - * The fileName / lineNumber stubs are now necessary because built-in - * data will include the accessor properties in Error.prototype. If those - * are removed for builds without tracebacks, these can also be removed. - * 'stack' should still be present and produce a ToString() equivalent: - * this is useful for user code which prints a stacktrace and expects to - * see something useful. A normal stacktrace also begins with a ToString() - * of the error so this makes sense. - */ - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) { - /* XXX: remove this native function and map 'stack' accessor - * to the toString() implementation directly. - */ - return duk_bi_error_prototype_to_string(thr); -} - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) { - DUK_UNREF(thr); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) { - DUK_UNREF(thr); - return 0; -} - -#endif /* DUK_USE_TRACEBACKS */ - -DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_hthread *thr, duk_small_uint_t stridx_key) { - /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if - * user code called Object.defineProperty() to create an overriding - * own property. This allows user code to overwrite .fileName etc - * intuitively as e.g. "err.fileName = 'dummy'" as one might expect. - * See https://github.com/svaarala/duktape/issues/387. - */ - - DUK_ASSERT_TOP(thr, 1); /* fixed arg count: value */ - - duk_push_this(thr); - duk_push_hstring_stridx(thr, stridx_key); - duk_dup_0(thr); - - /* [ ... obj key value ] */ - - DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T", - duk_get_tval(thr, -3), duk_get_tval(thr, -2), duk_get_tval(thr, -1))); - - duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE | - DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE | - DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/ - DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_hthread *thr) { - return duk__error_setter_helper(thr, DUK_STRIDX_STACK); -} - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_hthread *thr) { - return duk__error_setter_helper(thr, DUK_STRIDX_FILE_NAME); -} - -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_hthread *thr) { - return duk__error_setter_helper(thr, DUK_STRIDX_LINE_NUMBER); -} - -/* automatic undefs */ -#undef DUK__OUTPUT_TYPE_FILENAME -#undef DUK__OUTPUT_TYPE_LINENUMBER -#undef DUK__OUTPUT_TYPE_TRACEBACK -#line 1 "duk_bi_function.c" -/* - * Function built-ins - */ - -/* #include duk_internal.h -> already included */ - -/* Needed even when Function built-in is disabled. */ -DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_hthread *thr) { - /* ignore arguments, return undefined (E5 Section 15.3.4) */ - DUK_UNREF(thr); - return 0; -} - -#if defined(DUK_USE_FUNCTION_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) { - duk_hstring *h_sourcecode; - duk_idx_t nargs; - duk_idx_t i; - duk_small_uint_t comp_flags; - duk_hcompfunc *func; - duk_hobject *outer_lex_env; - duk_hobject *outer_var_env; - - /* normal and constructor calls have identical semantics */ - - nargs = duk_get_top(thr); - for (i = 0; i < nargs; i++) { - duk_to_string(thr, i); /* Rejects Symbols during coercion. */ - } - - if (nargs == 0) { - duk_push_hstring_empty(thr); - duk_push_hstring_empty(thr); - } else if (nargs == 1) { - /* XXX: cover this with the generic >1 case? */ - duk_push_hstring_empty(thr); - } else { - duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */ - duk_push_string(thr, ","); - duk_insert(thr, 1); - duk_join(thr, nargs - 1); - } - - /* [ body formals ], formals is comma separated list that needs to be parsed */ - - DUK_ASSERT_TOP(thr, 2); - - /* XXX: this placeholder is not always correct, but use for now. - * It will fail in corner cases; see test-dev-func-cons-args.js. - */ - duk_push_string(thr, "function("); - duk_dup_1(thr); - duk_push_string(thr, "){"); - duk_dup_0(thr); - duk_push_string(thr, "}"); - duk_concat(thr, 5); - - /* [ body formals source ] */ - - DUK_ASSERT_TOP(thr, 3); - - /* strictness is not inherited, intentional */ - comp_flags = DUK_COMPILE_FUNCEXPR; - - duk_push_hstring_stridx(thr, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */ - h_sourcecode = duk_require_hstring(thr, -2); /* no symbol check needed; -2 is concat'd code */ - duk_js_compile(thr, - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode), - (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode), - comp_flags); - - /* Force .name to 'anonymous' (ES2015). */ - duk_push_string(thr, "anonymous"); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); - - func = (duk_hcompfunc *) duk_known_hobject(thr, -1); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func)); - DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func)); - - /* [ body formals source template ] */ - - /* only outer_lex_env matters, as functions always get a new - * variable declaration environment. - */ - - outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - - duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/); - - /* [ body formals source template closure ] */ - - return 1; -} -#endif /* DUK_USE_FUNCTION_BUILTIN */ - -#if defined(DUK_USE_FUNCTION_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_hthread *thr) { - duk_tval *tv; - - /* - * E5 Section 15.3.4.2 places few requirements on the output of - * this function: the result is implementation dependent, must - * follow FunctionDeclaration syntax (in particular, must have a - * name even for anonymous functions or functions with empty name). - * The output does NOT need to compile into anything useful. - * - * E6 Section 19.2.3.5 changes the requirements completely: the - * result must either eval() to a functionally equivalent object - * OR eval() to a SyntaxError. - * - * We opt for the SyntaxError approach for now, with a syntax that - * mimics V8's native function syntax: - * - * 'function cos() { [native code] }' - * - * but extended with [ecmascript code], [bound code], and - * [lightfunc code]. - */ - - duk_push_this(thr); - tv = DUK_GET_TVAL_NEGIDX(thr, -1); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv); - const char *func_name; - - /* Function name: missing/undefined is mapped to empty string, - * otherwise coerce to string. No handling for invalid identifier - * characters or e.g. '{' in the function name. This doesn't - * really matter as long as a SyntaxError results. Technically - * if the name contained a suitable prefix followed by '//' it - * might cause the result to parse without error. - */ - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME); - if (duk_is_undefined(thr, -1)) { - func_name = ""; - } else { - func_name = duk_to_string(thr, -1); - DUK_ASSERT(func_name != NULL); - } - - if (DUK_HOBJECT_IS_COMPFUNC(obj)) { - duk_push_sprintf(thr, "function %s() { [ecmascript code] }", (const char *) func_name); - } else if (DUK_HOBJECT_IS_NATFUNC(obj)) { - duk_push_sprintf(thr, "function %s() { [native code] }", (const char *) func_name); - } else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) { - duk_push_sprintf(thr, "function %s() { [bound code] }", (const char *) func_name); - } else { - goto type_error; - } - } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - duk_push_lightfunc_tostring(thr, tv); - } else { - goto type_error; - } - - return 1; - - type_error: - DUK_DCERROR_TYPE_INVALID_ARGS(thr); -} -#endif - -/* Always present because the native function pointer is needed in call - * handling. - */ -DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_hthread *thr) { - /* .call() is dealt with in call handling by simulating its - * effects so this function is actually never called. - */ - DUK_UNREF(thr); - return DUK_RET_TYPE_ERROR; -} - -DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_hthread *thr) { - /* Like .call(), never actually called. */ - DUK_UNREF(thr); - return DUK_RET_TYPE_ERROR; -} - -DUK_INTERNAL duk_ret_t duk_bi_reflect_apply(duk_hthread *thr) { - /* Like .call(), never actually called. */ - DUK_UNREF(thr); - return DUK_RET_TYPE_ERROR; -} - -DUK_INTERNAL duk_ret_t duk_bi_reflect_construct(duk_hthread *thr) { - /* Like .call(), never actually called. */ - DUK_UNREF(thr); - return DUK_RET_TYPE_ERROR; -} - -#if defined(DUK_USE_FUNCTION_BUILTIN) -/* Create a bound function which points to a target function which may - * be bound or non-bound. If the target is bound, the argument lists - * and 'this' binding of the functions are merged and the resulting - * function points directly to the non-bound target. - */ -DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) { - duk_hboundfunc *h_bound; - duk_idx_t nargs; /* bound args, not counting 'this' binding */ - duk_idx_t bound_nargs; - duk_int_t bound_len; - duk_tval *tv_prevbound; - duk_idx_t n_prevbound; - duk_tval *tv_res; - duk_tval *tv_tmp; - - /* XXX: C API call, e.g. duk_push_bound_function(thr, target_idx, nargs); */ - - /* Vararg function, careful arg handling, e.g. thisArg may not - * be present. - */ - nargs = duk_get_top(thr) - 1; /* actual args, not counting 'this' binding */ - if (nargs < 0) { - nargs++; - duk_push_undefined(thr); - } - DUK_ASSERT(nargs >= 0); - - /* Limit 'nargs' for bound functions to guarantee arithmetic - * below will never wrap. - */ - if (nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) { - DUK_DCERROR_RANGE_INVALID_COUNT(thr); - } - - duk_push_this(thr); - duk_require_callable(thr, -1); - - /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs+1 total) */ - DUK_ASSERT_TOP(thr, nargs + 2); - - /* Create bound function object. */ - h_bound = duk_push_hboundfunc(thr); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->target)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->this_binding)); - DUK_ASSERT(h_bound->args == NULL); - DUK_ASSERT(h_bound->nargs == 0); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_bound) == NULL); - - /* [ thisArg arg1 ... argN func boundFunc ] */ - - /* If the target is a bound function, argument lists must be - * merged. The 'this' binding closest to the target function - * wins because in call handling the 'this' gets replaced over - * and over again until we call the non-bound function. - */ - tv_prevbound = NULL; - n_prevbound = 0; - tv_tmp = DUK_GET_TVAL_POSIDX(thr, 0); - DUK_TVAL_SET_TVAL(&h_bound->this_binding, tv_tmp); - tv_tmp = DUK_GET_TVAL_NEGIDX(thr, -2); - DUK_TVAL_SET_TVAL(&h_bound->target, tv_tmp); - - if (DUK_TVAL_IS_OBJECT(tv_tmp)) { - duk_hobject *h_target; - duk_hobject *bound_proto; - - h_target = DUK_TVAL_GET_OBJECT(tv_tmp); - DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(h_target)); - - /* Internal prototype must be copied from the target. - * For lightfuncs Function.prototype is used and is already - * in place. - */ - bound_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target); - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto); - - /* The 'strict' flag is copied to get the special [[Get]] of E5.1 - * Section 15.3.5.4 to apply when a 'caller' value is a strict bound - * function. Not sure if this is correct, because the specification - * is a bit ambiguous on this point but it would make sense. - */ - /* Strictness is inherited from target. */ - if (DUK_HOBJECT_HAS_STRICT(h_target)) { - DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound); - } - - if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) { - duk_hboundfunc *h_boundtarget; - - h_boundtarget = (duk_hboundfunc *) h_target; - - /* The final function should always be non-bound, unless - * there's a bug in the internals. Assert for it. - */ - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h_boundtarget->target) || - (DUK_TVAL_IS_OBJECT(&h_boundtarget->target) && - DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)) && - !DUK_HOBJECT_IS_BOUNDFUNC(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)))); - - DUK_TVAL_SET_TVAL(&h_bound->target, &h_boundtarget->target); - DUK_TVAL_SET_TVAL(&h_bound->this_binding, &h_boundtarget->this_binding); - - tv_prevbound = h_boundtarget->args; - n_prevbound = h_boundtarget->nargs; - } - } else { - /* Lightfuncs are always strict. */ - duk_hobject *bound_proto; - - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_tmp)); - DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound); - bound_proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]; - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto); - } - - DUK_TVAL_INCREF(thr, &h_bound->target); /* old values undefined, no decref needed */ - DUK_TVAL_INCREF(thr, &h_bound->this_binding); - - bound_nargs = n_prevbound + nargs; - if (bound_nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) { - DUK_DCERROR_RANGE_INVALID_COUNT(thr); - } - tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval)); - DUK_ASSERT(tv_res != NULL); - DUK_ASSERT(h_bound->args == NULL); - DUK_ASSERT(h_bound->nargs == 0); - h_bound->args = tv_res; - h_bound->nargs = bound_nargs; - - DUK_ASSERT(n_prevbound >= 0); - duk_copy_tvals_incref(thr, tv_res, tv_prevbound, (duk_size_t) n_prevbound); - DUK_ASSERT(nargs >= 0); - duk_copy_tvals_incref(thr, tv_res + n_prevbound, DUK_GET_TVAL_POSIDX(thr, 1), (duk_size_t) nargs); - - /* [ thisArg arg1 ... argN func boundFunc ] */ - - /* Bound function 'length' property is interesting. - * For lightfuncs, simply read the virtual property. - */ - duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH); - bound_len = duk_get_int(thr, -1); /* ES2015: no coercion */ - if (bound_len < nargs) { - bound_len = 0; - } else { - bound_len -= nargs; - } - if (sizeof(duk_int_t) > 4 && bound_len > (duk_int_t) DUK_UINT32_MAX) { - bound_len = (duk_int_t) DUK_UINT32_MAX; - } - duk_pop(thr); - DUK_ASSERT(bound_len >= 0); - tv_tmp = thr->valstack_top++; - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_tmp)); - DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_tmp)); - DUK_TVAL_SET_U32(tv_tmp, (duk_uint32_t) bound_len); /* in-place update, fastint */ - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */ - - /* XXX: could these be virtual? */ - /* Caller and arguments must use the same thrower, [[ThrowTypeError]]. */ - duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_CALLER); - duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS); - - /* Function name and fileName (non-standard). */ - duk_push_string(thr, "bound "); /* ES2015 19.2.3.2. */ - duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME); - if (!duk_is_string_notsymbol(thr, -1)) { - /* ES2015 has requirement to check that .name of target is a string - * (also must check for Symbol); if not, targetName should be the - * empty string. ES2015 19.2.3.2. - */ - duk_pop(thr); - duk_push_hstring_empty(thr); - } - duk_concat(thr, 2); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); -#if defined(DUK_USE_FUNC_FILENAME_PROPERTY) - duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C); -#endif - - DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(thr, -1))); - - return 1; -} -#endif /* DUK_USE_FUNCTION_BUILTIN */ - -/* %NativeFunctionPrototype% .length getter. */ -DUK_INTERNAL duk_ret_t duk_bi_native_function_length(duk_hthread *thr) { - duk_tval *tv; - duk_hnatfunc *h; - duk_int16_t func_nargs; - - tv = duk_get_borrowed_this_tval(thr); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_OBJECT(tv)) { - h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) { - goto fail_type; - } - func_nargs = h->nargs; - duk_push_int(thr, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs); - } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - duk_small_uint_t lf_flags; - duk_small_uint_t lf_len; - - lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); - lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); - duk_push_uint(thr, lf_len); - } else { - goto fail_type; - } - return 1; - - fail_type: - DUK_DCERROR_TYPE_INVALID_ARGS(thr); -} - -/* %NativeFunctionPrototype% .name getter. */ -DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) { - duk_tval *tv; - duk_hnatfunc *h; - - tv = duk_get_borrowed_this_tval(thr); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_OBJECT(tv)) { - h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) { - goto fail_type; - } -#if 0 - duk_push_hnatfunc_name(thr, h); -#endif - duk_push_hstring_empty(thr); - } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - duk_push_lightfunc_name(thr, tv); - } else { - goto fail_type; - } - return 1; - - fail_type: - DUK_DCERROR_TYPE_INVALID_ARGS(thr); -} -#line 1 "duk_bi_global.c" -/* - * Global object built-ins - */ - -/* #include duk_internal.h -> already included */ - -/* - * Encoding/decoding helpers - */ - -/* XXX: Could add fast path (for each transform callback) with direct byte - * lookups (no shifting) and no explicit check for x < 0x80 before table - * lookup. - */ - -/* Macros for creating and checking bitmasks for character encoding. - * Bit number is a bit counterintuitive, but minimizes code size. - */ -#define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \ - ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \ - ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \ - )) -#define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07))) - -/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */ -DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = { - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ - DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ - DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */ -}; - -/* E5.1 Section 15.1.3.4: uriUnescaped */ -DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = { - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ - DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ - DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ - DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */ -}; - -/* E5.1 Section 15.1.3.1: uriReserved + '#' */ -DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = { - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ - DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */ - DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */ -}; - -/* E5.1 Section 15.1.3.2: empty */ -DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = { - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */ -}; - -#if defined(DUK_USE_SECTION_B) -/* E5.1 Section B.2.2, step 7. */ -DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = { - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ - DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ - DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ - DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */ -}; -#endif /* DUK_USE_SECTION_B */ - -typedef struct { - duk_hthread *thr; - duk_hstring *h_str; - duk_bufwriter_ctx bw; - const duk_uint8_t *p; - const duk_uint8_t *p_start; - const duk_uint8_t *p_end; -} duk__transform_context; - -typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp); - -/* XXX: refactor and share with other code */ -DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) { - duk_small_int_t ch; - duk_small_int_t t = 0; - - while (n > 0) { - t = t * 16; - ch = (duk_small_int_t) duk_hex_dectab[*p++]; - if (DUK_LIKELY(ch >= 0)) { - t += ch; - } else { - return -1; - } - n--; - } - return t; -} - -DUK_LOCAL int duk__transform_helper(duk_hthread *thr, duk__transform_callback callback, const void *udata) { - duk__transform_context tfm_ctx_alloc; - duk__transform_context *tfm_ctx = &tfm_ctx_alloc; - duk_codepoint_t cp; - - tfm_ctx->thr = thr; - - tfm_ctx->h_str = duk_to_hstring(thr, 0); - DUK_ASSERT(tfm_ctx->h_str != NULL); - - DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */ - - tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str); - tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str); - tfm_ctx->p = tfm_ctx->p_start; - - while (tfm_ctx->p < tfm_ctx->p_end) { - cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end); - callback(tfm_ctx, udata, cp); - } - - DUK_BW_COMPACT(thr, &tfm_ctx->bw); - - (void) duk_buffer_to_string(thr, -1); /* Safe if transform is safe. */ - return 1; -} - -DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { - duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH]; - duk_small_int_t len; - duk_codepoint_t cp1, cp2; - duk_small_int_t i, t; - const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata; - - /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes. - * Codepoint range is restricted so this is a slightly too large - * but doesn't matter. - */ - DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH); - - if (cp < 0) { - goto uri_error; - } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) { - DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp); - return; - } else if (cp >= 0xdc00L && cp <= 0xdfffL) { - goto uri_error; - } else if (cp >= 0xd800L && cp <= 0xdbffL) { - /* Needs lookahead */ - if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) { - goto uri_error; - } - if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) { - goto uri_error; - } - cp1 = cp; - cp = (duk_codepoint_t) (((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L); - } else if (cp > 0x10ffffL) { - /* Although we can allow non-BMP characters (they'll decode - * back into surrogate pairs), we don't allow extended UTF-8 - * characters; they would encode to URIs which won't decode - * back because of strict UTF-8 checks in URI decoding. - * (However, we could just as well allow them here.) - */ - goto uri_error; - } else { - /* Non-BMP characters within valid UTF-8 range: encode as is. - * They'll decode back into surrogate pairs if the escaped - * output is decoded. - */ - ; - } - - len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf); - for (i = 0; i < len; i++) { - t = (duk_small_int_t) xutf8_buf[i]; - DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, - &tfm_ctx->bw, - DUK_ASC_PERCENT, - (duk_uint8_t) duk_uc_nybbles[t >> 4], - (duk_uint8_t) duk_uc_nybbles[t & 0x0f]); - } - - return; - - uri_error: - DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT); -} - -DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { - const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata; - duk_small_uint_t utf8_blen; - duk_codepoint_t min_cp; - duk_small_int_t t; /* must be signed */ - duk_small_uint_t i; - - /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH, - * percent escape path writes max two times CESU-8 encoded BMP length. - */ - DUK_BW_ENSURE(tfm_ctx->thr, - &tfm_ctx->bw, - (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ? - DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH)); - - if (cp == (duk_codepoint_t) '%') { - const duk_uint8_t *p = tfm_ctx->p; - duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */ - - DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left)); - - if (left < 2) { - goto uri_error; - } - - t = duk__decode_hex_escape(p, 2); - DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t)); - if (t < 0) { - goto uri_error; - } - - if (t < 0x80) { - if (DUK__CHECK_BITMASK(reserved_table, t)) { - /* decode '%xx' to '%xx' if decoded char in reserved set */ - DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start); - DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, - &tfm_ctx->bw, - DUK_ASC_PERCENT, - p[0], - p[1]); - } else { - DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t); - } - tfm_ctx->p += 2; - return; - } - - /* Decode UTF-8 codepoint from a sequence of hex escapes. The - * first byte of the sequence has been decoded to 't'. - * - * Note that UTF-8 validation must be strict according to the - * specification: E5.1 Section 15.1.3, decode algorithm step - * 4.d.vii.8. URIError from non-shortest encodings is also - * specifically noted in the spec. - */ - - DUK_ASSERT(t >= 0x80); - if (t < 0xc0) { - /* continuation byte */ - goto uri_error; - } else if (t < 0xe0) { - /* 110x xxxx; 2 bytes */ - utf8_blen = 2; - min_cp = 0x80L; - cp = t & 0x1f; - } else if (t < 0xf0) { - /* 1110 xxxx; 3 bytes */ - utf8_blen = 3; - min_cp = 0x800L; - cp = t & 0x0f; - } else if (t < 0xf8) { - /* 1111 0xxx; 4 bytes */ - utf8_blen = 4; - min_cp = 0x10000L; - cp = t & 0x07; - } else { - /* extended utf-8 not allowed for URIs */ - goto uri_error; - } - - if (left < utf8_blen * 3 - 1) { - /* '%xx%xx...%xx', p points to char after first '%' */ - goto uri_error; - } - - p += 3; - for (i = 1; i < utf8_blen; i++) { - /* p points to digit part ('%xy', p points to 'x') */ - t = duk__decode_hex_escape(p, 2); - DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx", - (long) i, (long) utf8_blen, (long) cp, (unsigned long) t)); - if (t < 0) { - goto uri_error; - } - if ((t & 0xc0) != 0x80) { - goto uri_error; - } - cp = (cp << 6) + (t & 0x3f); - p += 3; - } - p--; /* p overshoots */ - tfm_ctx->p = p; - - DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp, (long) min_cp)); - - if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) { - goto uri_error; - } - - /* The E5.1 algorithm checks whether or not a decoded codepoint - * is below 0x80 and perhaps may be in the "reserved" set. - * This seems pointless because the single byte UTF-8 case is - * handled separately, and non-shortest encodings are rejected. - * So, 'cp' cannot be below 0x80 here, and thus cannot be in - * the reserved set. - */ - - /* utf-8 validation ensures these */ - DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL); - - if (cp >= 0x10000L) { - cp -= 0x10000L; - DUK_ASSERT(cp < 0x100000L); - - DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L)); - DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffL) + 0xdc00L)); - } else { - DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); - } - } else { - DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); - } - return; - - uri_error: - DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT); -} - -#if defined(DUK_USE_SECTION_B) -DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { - DUK_UNREF(udata); - - DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6); - - if (cp < 0) { - goto esc_error; - } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) { - DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp); - } else if (cp < 0x100L) { - DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, - &tfm_ctx->bw, - (duk_uint8_t) DUK_ASC_PERCENT, - (duk_uint8_t) duk_uc_nybbles[cp >> 4], - (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]); - } else if (cp < 0x10000L) { - DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr, - &tfm_ctx->bw, - (duk_uint8_t) DUK_ASC_PERCENT, - (duk_uint8_t) DUK_ASC_LC_U, - (duk_uint8_t) duk_uc_nybbles[cp >> 12], - (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f], - (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f], - (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]); - } else { - /* Characters outside BMP cannot be escape()'d. We could - * encode them as surrogate pairs (for codepoints inside - * valid UTF-8 range, but not extended UTF-8). Because - * escape() and unescape() are legacy functions, we don't. - */ - goto esc_error; - } - - return; - - esc_error: - DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT); -} - -DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { - duk_small_int_t t; - - DUK_UNREF(udata); - - if (cp == (duk_codepoint_t) '%') { - const duk_uint8_t *p = tfm_ctx->p; - duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */ - - if (left >= 5 && p[0] == 'u' && - ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) { - cp = (duk_codepoint_t) t; - tfm_ctx->p += 5; - } else if (left >= 2 && - ((t = duk__decode_hex_escape(p, 2)) >= 0)) { - cp = (duk_codepoint_t) t; - tfm_ctx->p += 2; - } - } - - DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); -} -#endif /* DUK_USE_SECTION_B */ - -/* - * Eval - * - * Eval needs to handle both a "direct eval" and an "indirect eval". - * Direct eval handling needs access to the caller's activation so that its - * lexical environment can be accessed. A direct eval is only possible from - * Ecmascript code; an indirect eval call is possible also from C code. - * When an indirect eval call is made from C code, there may not be a - * calling activation at all which needs careful handling. - */ - -DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) { - duk_hstring *h; - duk_activation *act_caller; - duk_activation *act_eval; - duk_hcompfunc *func; - duk_hobject *outer_lex_env; - duk_hobject *outer_var_env; - duk_bool_t this_to_global = 1; - duk_small_uint_t comp_flags; - duk_int_t level = -2; - duk_small_uint_t call_flags; - - DUK_ASSERT(duk_get_top(thr) == 1 || duk_get_top(thr) == 2); /* 2 when called by debugger */ - DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */ - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT((thr->callstack_curr->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */ - (thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */ - - /* - * callstack_top - 1 --> this function - * callstack_top - 2 --> caller (may not exist) - * - * If called directly from C, callstack_top might be 1. If calling - * activation doesn't exist, call must be indirect. - */ - - h = duk_get_hstring_notsymbol(thr, 0); - if (!h) { - /* Symbol must be returned as is, like any non-string values. */ - return 1; /* return arg as-is */ - } - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - /* NOTE: level is used only by the debugger and should never be present - * for an Ecmascript eval(). - */ - DUK_ASSERT(level == -2); /* by default, use caller's environment */ - if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) { - level = duk_get_int(thr, 1); - } - DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */ -#endif - - /* [ source ] */ - - comp_flags = DUK_COMPILE_EVAL; - act_eval = thr->callstack_curr; /* this function */ - DUK_ASSERT(act_eval != NULL); - act_caller = duk_hthread_get_activation_for_level(thr, level); - if (act_caller != NULL) { - /* Have a calling activation, check for direct eval (otherwise - * assume indirect eval. - */ - if ((act_caller->flags & DUK_ACT_FLAG_STRICT) && - (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) { - /* Only direct eval inherits strictness from calling code - * (E5.1 Section 10.1.1). - */ - comp_flags |= DUK_COMPILE_STRICT; - } - } else { - DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0); - } - - duk_push_hstring_stridx(thr, DUK_STRIDX_INPUT); /* XXX: copy from caller? */ - duk_js_compile(thr, - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), - (duk_size_t) DUK_HSTRING_GET_BYTELEN(h), - comp_flags); - func = (duk_hcompfunc *) duk_known_hobject(thr, -1); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func)); - - /* [ source template ] */ - - /* E5 Section 10.4.2 */ - - if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) { - DUK_ASSERT(thr->callstack_top >= 2); - DUK_ASSERT(act_caller != NULL); - if (act_caller->lex_env == NULL) { - DUK_ASSERT(act_caller->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); - - /* this may have side effects, so re-lookup act */ - duk_js_init_activation_environment_records_delayed(thr, act_caller); - } - DUK_ASSERT(act_caller->lex_env != NULL); - DUK_ASSERT(act_caller->var_env != NULL); - - this_to_global = 0; - - if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) { - duk_hdecenv *new_env; - duk_hobject *act_lex_env; - - DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> " - "var_env and lex_env to a fresh env, " - "this_binding to caller's this_binding")); - - act_lex_env = act_caller->lex_env; - - new_env = duk_hdecenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); - DUK_ASSERT(new_env != NULL); - duk_push_hobject(thr, (duk_hobject *) new_env); - - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); - DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act_lex_env); - DUK_HOBJECT_INCREF_ALLOWNULL(thr, act_lex_env); - DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env)); - - outer_lex_env = (duk_hobject *) new_env; - outer_var_env = (duk_hobject *) new_env; - - duk_insert(thr, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */ - - /* compiler's responsibility */ - DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func)); - } else { - DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> " - "var_env and lex_env to caller's envs, " - "this_binding to caller's this_binding")); - - outer_lex_env = act_caller->lex_env; - outer_var_env = act_caller->var_env; - - /* compiler's responsibility */ - DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func)); - } - } else { - DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to " - "global object, this_binding to global object")); - - this_to_global = 1; - outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - } - - /* Eval code doesn't need an automatic .prototype object. */ - duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/); - - /* [ env? source template closure ] */ - - if (this_to_global) { - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL); - } else { - duk_tval *tv; - DUK_ASSERT(thr->callstack_top >= 2); - DUK_ASSERT(act_caller != NULL); - tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act_caller->bottom_byteoff - sizeof(duk_tval)); /* this is just beneath bottom */ - DUK_ASSERT(tv >= thr->valstack); - duk_push_tval(thr, tv); - } - - DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T", - (duk_heaphdr *) outer_lex_env, - (duk_heaphdr *) outer_var_env, - duk_get_tval(thr, -1))); - - /* [ env? source template closure this ] */ - - call_flags = 0; - if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) { - /* Set DIRECT_EVAL flag for the call; it's not strictly - * needed for the 'inner' eval call (the eval body) but - * current new.target implementation expects to find it - * so it can traverse direct eval chains up to the real - * calling function. - */ - call_flags |= DUK_CALL_FLAG_DIRECT_EVAL; - } - duk_handle_call_unprotected_nargs(thr, 0, call_flags); - - /* [ env? source template result ] */ - - return 1; -} - -/* - * Parsing of ints and floats - */ - -#if defined(DUK_USE_GLOBAL_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_hthread *thr) { - duk_int32_t radix; - duk_small_uint_t s2n_flags; - - DUK_ASSERT_TOP(thr, 2); - duk_to_string(thr, 0); /* Reject symbols. */ - - radix = duk_to_int32(thr, 1); - - /* While parseInt() recognizes 0xdeadbeef, it doesn't recognize - * ES2015 0o123 or 0b10001. - */ - s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | - DUK_S2N_FLAG_ALLOW_GARBAGE | - DUK_S2N_FLAG_ALLOW_PLUS | - DUK_S2N_FLAG_ALLOW_MINUS | - DUK_S2N_FLAG_ALLOW_LEADING_ZERO | - DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT; - - /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT. - * - * Don't autodetect octals (from leading zeroes), require user code to - * provide an explicit radix 8 for parsing octal. See write-up from Mozilla: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation - */ - - if (radix != 0) { - if (radix < 2 || radix > 36) { - goto ret_nan; - } - if (radix != 16) { - s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT; - } - } else { - radix = 10; - } - - duk_dup_0(thr); - duk_numconv_parse(thr, (duk_small_int_t) radix, s2n_flags); - return 1; - - ret_nan: - duk_push_nan(thr); - return 1; -} -#endif /* DUK_USE_GLOBAL_BUILTIN */ - -#if defined(DUK_USE_GLOBAL_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_hthread *thr) { - duk_small_uint_t s2n_flags; - - DUK_ASSERT_TOP(thr, 1); - duk_to_string(thr, 0); /* Reject symbols. */ - - /* XXX: check flags */ - s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | - DUK_S2N_FLAG_ALLOW_EXP | - DUK_S2N_FLAG_ALLOW_GARBAGE | - DUK_S2N_FLAG_ALLOW_PLUS | - DUK_S2N_FLAG_ALLOW_MINUS | - DUK_S2N_FLAG_ALLOW_INF | - DUK_S2N_FLAG_ALLOW_FRAC | - DUK_S2N_FLAG_ALLOW_NAKED_FRAC | - DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | - DUK_S2N_FLAG_ALLOW_LEADING_ZERO; - - duk_numconv_parse(thr, 10 /*radix*/, s2n_flags); - return 1; -} -#endif /* DUK_USE_GLOBAL_BUILTIN */ - -/* - * Number checkers - */ - -#if defined(DUK_USE_GLOBAL_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_hthread *thr) { - duk_double_t d = duk_to_number(thr, 0); - duk_push_boolean(thr, (duk_bool_t) DUK_ISNAN(d)); - return 1; -} -#endif /* DUK_USE_GLOBAL_BUILTIN */ - -#if defined(DUK_USE_GLOBAL_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_hthread *thr) { - duk_double_t d = duk_to_number(thr, 0); - duk_push_boolean(thr, (duk_bool_t) DUK_ISFINITE(d)); - return 1; -} -#endif /* DUK_USE_GLOBAL_BUILTIN */ - -/* - * URI handling - */ - -#if defined(DUK_USE_GLOBAL_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_hthread *thr) { - return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table); -} - -DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_hthread *thr) { - return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table); -} - -DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_hthread *thr) { - return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table); -} - -DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_hthread *thr) { - return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table); -} - -#if defined(DUK_USE_SECTION_B) -DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_hthread *thr) { - return duk__transform_helper(thr, duk__transform_callback_escape, (const void *) NULL); -} - -DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_hthread *thr) { - return duk__transform_helper(thr, duk__transform_callback_unescape, (const void *) NULL); -} -#endif /* DUK_USE_SECTION_B */ -#endif /* DUK_USE_GLOBAL_BUILTIN */ - -/* automatic undefs */ -#undef DUK__CHECK_BITMASK -#undef DUK__MKBITS -#line 1 "duk_bi_json.c" -/* - * JSON built-ins. - * - * See doc/json.rst. - * - * Codepoints are handled as duk_uint_fast32_t to ensure that the full - * unsigned 32-bit range is supported. This matters to e.g. JX. - * - * Input parsing doesn't do an explicit end-of-input check at all. This is - * safe: input string data is always NUL-terminated (0x00) and valid JSON - * inputs never contain plain NUL characters, so that as long as syntax checks - * are correct, we'll never read past the NUL. This approach reduces code size - * and improves parsing performance, but it's critical that syntax checks are - * indeed correct! - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_JSON_SUPPORT) - -/* - * Local defines and forward declarations. - */ - -#define DUK__JSON_DECSTR_BUFSIZE 128 -#define DUK__JSON_DECSTR_CHUNKSIZE 64 -#define DUK__JSON_ENCSTR_CHUNKSIZE 64 -#define DUK__JSON_STRINGIFY_BUFSIZE 128 -#define DUK__JSON_MAX_ESC_LEN 10 /* '\Udeadbeef' */ - -DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx); -#if defined(DUK_USE_JX) -DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx); -#endif -DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n); -DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx); -DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx); -#if defined(DUK_USE_JX) -DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx); -#endif -DUK_LOCAL_DECL void duk__dec_number(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_object(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_array(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx); -DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx); - -DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch); -DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2); -DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx); -DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h); -#if defined(DUK_USE_FASTINT) -DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p); -#endif -DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx); -DUK_LOCAL_DECL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q); -DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k); -DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str); -DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top); -DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top); -DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx); -DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx); -DUK_LOCAL_DECL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder); -DUK_LOCAL_DECL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv); -DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx); -#if defined(DUK_USE_FASTINT) -DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv); -#endif -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); -DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj); -#endif -#endif -#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) -DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); -#endif -DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth); - -/* - * Helper tables - */ - -#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH) -DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = { - /* 0x00 ... 0x7f: as is - * 0x80: escape generically - * 0x81: slow path - * 0xa0 ... 0xff: backslash + one char - */ - - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x20, 0x21, 0xa2, 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, 0xdc, 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, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81 -}; -#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ -DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = { - DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, - DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, - DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL, - DUK_ASC_LC_F, DUK_ASC_LC_R -}; -#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ - -#if defined(DUK_USE_JSON_DECSTRING_FASTPATH) -DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = { - /* 0x00: slow path - * other: as is - */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x21, 0x00, 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, 0x00, 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 -}; -#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */ - -#if defined(DUK_USE_JSON_EATWHITE_FASTPATH) -DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = { - /* 0x00: finish (non-white) - * 0x01: continue - */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */ - -#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH) -DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = { - /* 0x00: finish (not part of number) - * 0x01: continue - */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */ - -/* - * Parsing implementation. - * - * JSON lexer is now separate from duk_lexer.c because there are numerous - * small differences making it difficult to share the lexer. - * - * The parser here works with raw bytes directly; this works because all - * JSON delimiters are ASCII characters. Invalid xUTF-8 encoded values - * inside strings will be passed on without normalization; this is not a - * compliance concern because compliant inputs will always be valid - * CESU-8 encodings. - */ - -DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) { - /* Shared handler to minimize parser size. Cause will be - * hidden, unfortunately, but we'll have an offset which - * is often quite enough. - */ - DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON, - (long) (js_ctx->p - js_ctx->p_start)); -} - -DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) { - const duk_uint8_t *p; - duk_uint8_t t; - - p = js_ctx->p; - for (;;) { - DUK_ASSERT(p <= js_ctx->p_end); - t = *p; - -#if defined(DUK_USE_JSON_EATWHITE_FASTPATH) - /* This fast path is pretty marginal in practice. - * XXX: candidate for removal. - */ - DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00); /* end-of-input breaks */ - if (duk__json_eatwhite_lookup[t] == 0) { - break; - } -#else /* DUK_USE_JSON_EATWHITE_FASTPATH */ - if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) { - /* NUL also comes here. Comparison order matters, 0x20 - * is most common whitespace. - */ - break; - } -#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */ - p++; - } - js_ctx->p = p; -} - -#if defined(DUK_USE_JX) -DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) { - DUK_ASSERT(js_ctx->p <= js_ctx->p_end); - return *js_ctx->p; -} -#endif - -DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) { - DUK_ASSERT(js_ctx->p <= js_ctx->p_end); - return *js_ctx->p++; -} - -DUK_LOCAL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) { - duk__dec_eat_white(js_ctx); - return duk__dec_get(js_ctx); -} - -/* For JX, expressing the whole unsigned 32-bit range matters. */ -DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) { - duk_small_uint_t i; - duk_uint_fast32_t res = 0; - duk_uint8_t x; - duk_small_int_t t; - - for (i = 0; i < n; i++) { - /* XXX: share helper from lexer; duk_lexer.c / hexval(). */ - - x = duk__dec_get(js_ctx); - DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld", - (long) i, (long) n, (long) res, (long) x)); - - /* x == 0x00 (EOF) causes syntax_error */ - DUK_ASSERT(duk_hex_dectab[0] == -1); - t = duk_hex_dectab[x & 0xff]; - if (DUK_LIKELY(t >= 0)) { - res = (res * 16) + (duk_uint_fast32_t) t; - } else { - /* catches EOF and invalid digits */ - goto syntax_error; - } - } - - DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld", (long) res)); - return res; - - syntax_error: - duk__dec_syntax_error(js_ctx); - DUK_UNREACHABLE(); - return 0; -} - -DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) { - duk_hstring *h; - const duk_uint8_t *p; - duk_uint8_t x, y; - - /* First character has already been eaten and checked by the caller. - * We can scan until a NUL in stridx string because no built-in strings - * have internal NULs. - */ - - DUK_ASSERT_STRIDX_VALID(stridx); - h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); - DUK_ASSERT(h != NULL); - - p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1; - DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */ - - for (;;) { - x = *p; - if (x == 0) { - break; - } - y = duk__dec_get(js_ctx); - if (x != y) { - /* Catches EOF of JSON input. */ - goto syntax_error; - } - p++; - } - - return; - - syntax_error: - duk__dec_syntax_error(js_ctx); - DUK_UNREACHABLE(); -} - -DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) { - duk_uint_fast32_t cp; - - /* EOF (-1) will be cast to an unsigned value first - * and then re-cast for the switch. In any case, it - * will match the default case (syntax error). - */ - cp = (duk_uint_fast32_t) duk__dec_get(js_ctx); - switch (cp) { - case DUK_ASC_BACKSLASH: break; - case DUK_ASC_DOUBLEQUOTE: break; - case DUK_ASC_SLASH: break; - case DUK_ASC_LC_T: cp = 0x09; break; - case DUK_ASC_LC_N: cp = 0x0a; break; - case DUK_ASC_LC_R: cp = 0x0d; break; - case DUK_ASC_LC_F: cp = 0x0c; break; - case DUK_ASC_LC_B: cp = 0x08; break; - case DUK_ASC_LC_U: { - cp = duk__dec_decode_hex_escape(js_ctx, 4); - break; - } -#if defined(DUK_USE_JX) - case DUK_ASC_UC_U: { - if (js_ctx->flag_ext_custom) { - cp = duk__dec_decode_hex_escape(js_ctx, 8); - } else { - return 1; /* syntax error */ - } - break; - } - case DUK_ASC_LC_X: { - if (js_ctx->flag_ext_custom) { - cp = duk__dec_decode_hex_escape(js_ctx, 2); - } else { - return 1; /* syntax error */ - } - break; - } -#endif /* DUK_USE_JX */ - default: - /* catches EOF (0x00) */ - return 1; /* syntax error */ - } - - DUK_RAW_WRITE_XUTF8(*ext_p, cp); - - return 0; -} - -DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - duk_bufwriter_ctx bw_alloc; - duk_bufwriter_ctx *bw; - duk_uint8_t *q; - - /* '"' was eaten by caller */ - - /* Note that we currently parse -bytes-, not codepoints. - * All non-ASCII extended UTF-8 will encode to bytes >= 0x80, - * so they'll simply pass through (valid UTF-8 or not). - */ - - bw = &bw_alloc; - DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE); - q = DUK_BW_GET_PTR(js_ctx->thr, bw); - -#if defined(DUK_USE_JSON_DECSTRING_FASTPATH) - for (;;) { - duk_small_uint_t safe; - duk_uint8_t b, x; - const duk_uint8_t *p; - - /* Select a safe loop count where no output checks are - * needed assuming we won't encounter escapes. Input - * bound checks are not necessary as a NUL (guaranteed) - * will cause a SyntaxError before we read out of bounds. - */ - - safe = DUK__JSON_DECSTR_CHUNKSIZE; - - /* Ensure space for 1:1 output plus one escape. */ - q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q); - - p = js_ctx->p; /* temp copy, write back for next loop */ - for (;;) { - if (safe == 0) { - js_ctx->p = p; - break; - } - safe--; - - /* End of input (NUL) goes through slow path and causes SyntaxError. */ - DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00); - - b = *p++; - x = (duk_small_int_t) duk__json_decstr_lookup[b]; - if (DUK_LIKELY(x != 0)) { - /* Fast path, decode as is. */ - *q++ = b; - } else if (b == DUK_ASC_DOUBLEQUOTE) { - js_ctx->p = p; - goto found_quote; - } else if (b == DUK_ASC_BACKSLASH) { - /* We've ensured space for one escaped input; then - * bail out and recheck (this makes escape handling - * quite slow but it's uncommon). - */ - js_ctx->p = p; - if (duk__dec_string_escape(js_ctx, &q) != 0) { - goto syntax_error; - } - break; - } else { - js_ctx->p = p; - goto syntax_error; - } - } - } - found_quote: -#else /* DUK_USE_JSON_DECSTRING_FASTPATH */ - for (;;) { - duk_uint8_t x; - - q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q); - - x = duk__dec_get(js_ctx); - - if (x == DUK_ASC_DOUBLEQUOTE) { - break; - } else if (x == DUK_ASC_BACKSLASH) { - if (duk__dec_string_escape(js_ctx, &q) != 0) { - goto syntax_error; - } - } else if (x < 0x20) { - /* catches EOF (NUL) */ - goto syntax_error; - } else { - *q++ = (duk_uint8_t) x; - } - } -#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */ - - DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q); - (void) duk_buffer_to_string(thr, -1); /* Safe if input string is safe. */ - - /* [ ... str ] */ - - return; - - syntax_error: - duk__dec_syntax_error(js_ctx); - DUK_UNREACHABLE(); -} - -#if defined(DUK_USE_JX) -/* Decode a plain string consisting entirely of identifier characters. - * Used to parse plain keys (e.g. "foo: 123"). - */ -DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - const duk_uint8_t *p; - duk_small_int_t x; - - /* Caller has already eaten the first char so backtrack one byte. */ - - js_ctx->p--; /* safe */ - p = js_ctx->p; - - /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of - * parsing (which is correct except if there are non-shortest encodings). - * There is also no need to check explicitly for end of input buffer as - * the input is NUL padded and NUL will exit the parsing loop. - * - * Because no unescaping takes place, we can just scan to the end of the - * plain string and intern from the input buffer. - */ - - for (;;) { - x = *p; - - /* There is no need to check the first character specially here - * (i.e. reject digits): the caller only accepts valid initial - * characters and won't call us if the first character is a digit. - * This also ensures that the plain string won't be empty. - */ - - if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) { - break; - } - p++; - } - - duk_push_lstring(thr, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p)); - js_ctx->p = p; - - /* [ ... str ] */ -} -#endif /* DUK_USE_JX */ - -#if defined(DUK_USE_JX) -DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - const duk_uint8_t *p; - duk_small_int_t x; - void *voidptr; - - /* Caller has already eaten the first character ('(') which we don't need. */ - - p = js_ctx->p; - - for (;;) { - x = *p; - - /* Assume that the native representation never contains a closing - * parenthesis. - */ - - if (x == DUK_ASC_RPAREN) { - break; - } else if (x <= 0) { - /* NUL term or -1 (EOF), NUL check would suffice */ - goto syntax_error; - } - p++; - } - - /* There is no need to NUL delimit the sscanf() call: trailing garbage is - * ignored and there is always a NUL terminator which will force an error - * if no error is encountered before it. It's possible that the scan - * would scan further than between [js_ctx->p,p[ though and we'd advance - * by less than the scanned value. - * - * Because pointers are platform specific, a failure to scan a pointer - * results in a null pointer which is a better placeholder than a missing - * value or an error. - */ - - voidptr = NULL; - (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr); - duk_push_pointer(thr, voidptr); - js_ctx->p = p + 1; /* skip ')' */ - - /* [ ... ptr ] */ - - return; - - syntax_error: - duk__dec_syntax_error(js_ctx); - DUK_UNREACHABLE(); -} -#endif /* DUK_USE_JX */ - -#if defined(DUK_USE_JX) -DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - const duk_uint8_t *p; - duk_uint8_t *buf; - duk_size_t src_len; - duk_small_int_t x; - - /* Caller has already eaten the first character ('|') which we don't need. */ - - p = js_ctx->p; - - /* XXX: Would be nice to share the fast path loop from duk_hex_decode() - * and avoid creating a temporary buffer. However, there are some - * differences which prevent trivial sharing: - * - * - Pipe char detection - * - EOF detection - * - Unknown length of input and output - * - * The best approach here would be a bufwriter and a reasonaly sized - * safe inner loop (e.g. 64 output bytes at a time). - */ - - for (;;) { - x = *p; - - /* This loop intentionally does not ensure characters are valid - * ([0-9a-fA-F]) because the hex decode call below will do that. - */ - if (x == DUK_ASC_PIPE) { - break; - } else if (x <= 0) { - /* NUL term or -1 (EOF), NUL check would suffice */ - goto syntax_error; - } - p++; - } - - /* XXX: this is not very nice; unnecessary copy is made. */ - src_len = (duk_size_t) (p - js_ctx->p); - buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len); - DUK_ASSERT(buf != NULL); - DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len); - duk_hex_decode(thr, -1); - - js_ctx->p = p + 1; /* skip '|' */ - - /* [ ... buf ] */ - - return; - - syntax_error: - duk__dec_syntax_error(js_ctx); - DUK_UNREACHABLE(); -} -#endif /* DUK_USE_JX */ - -/* Parse a number, other than NaN or +/- Infinity */ -DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - const duk_uint8_t *p_start; - const duk_uint8_t *p; - duk_uint8_t x; - duk_small_uint_t s2n_flags; - - DUK_DDD(DUK_DDDPRINT("parse_number")); - - p_start = js_ctx->p; - - /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a - * string for strict number parsing. - */ - - p = js_ctx->p; - for (;;) { - x = *p; - - DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld", - (const void *) p_start, (const void *) p, - (const void *) js_ctx->p_end, (long) x)); - -#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH) - /* This fast path is pretty marginal in practice. - * XXX: candidate for removal. - */ - DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00); /* end-of-input breaks */ - if (duk__json_decnumber_lookup[x] == 0) { - break; - } -#else /* DUK_USE_JSON_DECNUMBER_FASTPATH */ - if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) || - (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E || - x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) { - /* Plus sign must be accepted for positive exponents - * (e.g. '1.5e+2'). This clause catches NULs. - */ - break; - } -#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */ - p++; /* safe, because matched (NUL causes a break) */ - } - js_ctx->p = p; - - DUK_ASSERT(js_ctx->p > p_start); - duk_push_lstring(thr, (const char *) p_start, (duk_size_t) (p - p_start)); - - s2n_flags = DUK_S2N_FLAG_ALLOW_EXP | - DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */ - DUK_S2N_FLAG_ALLOW_FRAC; - - DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T", - (duk_tval *) duk_get_tval(thr, -1))); - duk_numconv_parse(thr, 10 /*radix*/, s2n_flags); - if (duk_is_nan(thr, -1)) { - duk__dec_syntax_error(js_ctx); - } - DUK_ASSERT(duk_is_number(thr, -1)); - DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T", - (duk_tval *) duk_get_tval(thr, -1))); - - /* [ ... num ] */ -} - -DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - duk_require_stack(thr, DUK_JSON_DEC_REQSTACK); - - /* c recursion check */ - - DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */ - DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); - if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { - DUK_ERROR_RANGE(thr, DUK_STR_JSONDEC_RECLIMIT); - } - js_ctx->recursion_depth++; -} - -DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) { - /* c recursion check */ - - DUK_ASSERT(js_ctx->recursion_depth > 0); - DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); - js_ctx->recursion_depth--; -} - -DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - duk_int_t key_count; /* XXX: a "first" flag would suffice */ - duk_uint8_t x; - - DUK_DDD(DUK_DDDPRINT("parse_object")); - - duk__dec_objarr_entry(js_ctx); - - duk_push_object(thr); - - /* Initial '{' has been checked and eaten by caller. */ - - key_count = 0; - for (;;) { - x = duk__dec_get_nonwhite(js_ctx); - - DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld", - (duk_tval *) duk_get_tval(thr, -1), - (long) x, (long) key_count)); - - /* handle comma and closing brace */ - - if (x == DUK_ASC_COMMA && key_count > 0) { - /* accept comma, expect new value */ - x = duk__dec_get_nonwhite(js_ctx); - } else if (x == DUK_ASC_RCURLY) { - /* eat closing brace */ - break; - } else if (key_count == 0) { - /* accept anything, expect first value (EOF will be - * caught by key parsing below. - */ - ; - } else { - /* catches EOF (NUL) and initial comma */ - goto syntax_error; - } - - /* parse key and value */ - - if (x == DUK_ASC_DOUBLEQUOTE) { - duk__dec_string(js_ctx); -#if defined(DUK_USE_JX) - } else if (js_ctx->flag_ext_custom && - duk_unicode_is_identifier_start((duk_codepoint_t) x)) { - duk__dec_plain_string(js_ctx); -#endif - } else { - goto syntax_error; - } - - /* [ ... obj key ] */ - - x = duk__dec_get_nonwhite(js_ctx); - if (x != DUK_ASC_COLON) { - goto syntax_error; - } - - duk__dec_value(js_ctx); - - /* [ ... obj key val ] */ - - duk_xdef_prop_wec(thr, -3); - - /* [ ... obj ] */ - - key_count++; - } - - /* [ ... obj ] */ - - DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T", - (duk_tval *) duk_get_tval(thr, -1))); - - duk__dec_objarr_exit(js_ctx); - return; - - syntax_error: - duk__dec_syntax_error(js_ctx); - DUK_UNREACHABLE(); -} - -DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - duk_uarridx_t arr_idx; - duk_uint8_t x; - - DUK_DDD(DUK_DDDPRINT("parse_array")); - - duk__dec_objarr_entry(js_ctx); - - duk_push_array(thr); - - /* Initial '[' has been checked and eaten by caller. */ - - arr_idx = 0; - for (;;) { - x = duk__dec_get_nonwhite(js_ctx); - - DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld", - (duk_tval *) duk_get_tval(thr, -1), - (long) x, (long) arr_idx)); - - /* handle comma and closing bracket */ - - if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) { - /* accept comma, expect new value */ - ; - } else if (x == DUK_ASC_RBRACKET) { - /* eat closing bracket */ - break; - } else if (arr_idx == 0) { - /* accept anything, expect first value (EOF will be - * caught by duk__dec_value() below. - */ - js_ctx->p--; /* backtrack (safe) */ - } else { - /* catches EOF (NUL) and initial comma */ - goto syntax_error; - } - - /* parse value */ - - duk__dec_value(js_ctx); - - /* [ ... arr val ] */ - - duk_xdef_prop_index_wec(thr, -2, arr_idx); - arr_idx++; - } - - /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to - * set the values. - */ - - duk_set_length(thr, -1, arr_idx); - - /* [ ... arr ] */ - - DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T", - (duk_tval *) duk_get_tval(thr, -1))); - - duk__dec_objarr_exit(js_ctx); - return; - - syntax_error: - duk__dec_syntax_error(js_ctx); - DUK_UNREACHABLE(); -} - -DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - duk_uint8_t x; - - x = duk__dec_get_nonwhite(js_ctx); - - DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x)); - - /* Note: duk__dec_req_stridx() backtracks one char */ - - if (x == DUK_ASC_DOUBLEQUOTE) { - duk__dec_string(js_ctx); - } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) { -#if defined(DUK_USE_JX) - if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) { - duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */ - duk_push_number(thr, -DUK_DOUBLE_INFINITY); - } else { -#else - { /* unconditional block */ -#endif - /* We already ate 'x', so backup one byte. */ - js_ctx->p--; /* safe */ - duk__dec_number(js_ctx); - } - } else if (x == DUK_ASC_LC_T) { - duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE); - duk_push_true(thr); - } else if (x == DUK_ASC_LC_F) { - duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE); - duk_push_false(thr); - } else if (x == DUK_ASC_LC_N) { - duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL); - duk_push_null(thr); -#if defined(DUK_USE_JX) - } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) { - duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED); - duk_push_undefined(thr); - } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) { - duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN); - duk_push_nan(thr); - } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) { - duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY); - duk_push_number(thr, DUK_DOUBLE_INFINITY); - } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) { - duk__dec_pointer(js_ctx); - } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) { - duk__dec_buffer(js_ctx); -#endif - } else if (x == DUK_ASC_LCURLY) { - duk__dec_object(js_ctx); - } else if (x == DUK_ASC_LBRACKET) { - duk__dec_array(js_ctx); - } else { - /* catches EOF (NUL) */ - goto syntax_error; - } - - duk__dec_eat_white(js_ctx); - - /* [ ... val ] */ - return; - - syntax_error: - duk__dec_syntax_error(js_ctx); - DUK_UNREACHABLE(); -} - -/* Recursive value reviver, implements the Walk() algorithm. No C recursion - * check is done here because the initial parsing step will already ensure - * there is a reasonable limit on C recursion depth and hence object depth. - */ -DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - duk_hobject *h; - duk_uarridx_t i, arr_len; - - DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T", - (long) duk_get_top(thr), - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - - duk_dup_top(thr); - duk_get_prop(thr, -3); /* -> [ ... holder name val ] */ - - h = duk_get_hobject(thr, -1); - if (h != NULL) { - if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) { - arr_len = (duk_uarridx_t) duk_get_length(thr, -1); - for (i = 0; i < arr_len; i++) { - /* [ ... holder name val ] */ - - DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T", - (long) duk_get_top(thr), (long) i, (long) arr_len, - (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - - duk_dup_top(thr); - (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */ - duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */ - - if (duk_is_undefined(thr, -1)) { - duk_pop(thr); - duk_del_prop_index(thr, -1, i); - } else { - /* XXX: duk_xdef_prop_index_wec() would be more appropriate - * here but it currently makes some assumptions that might - * not hold (e.g. that previous property is not an accessor). - */ - duk_put_prop_index(thr, -2, i); - } - } - } else { - /* [ ... holder name val ] */ - duk_enum(thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); - while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) { - DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T", - (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -5), - (duk_tval *) duk_get_tval(thr, -4), (duk_tval *) duk_get_tval(thr, -3), - (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1))); - - /* [ ... holder name val enum obj_key ] */ - duk_dup_m3(thr); - duk_dup_m2(thr); - - /* [ ... holder name val enum obj_key val obj_key ] */ - duk__dec_reviver_walk(js_ctx); - - /* [ ... holder name val enum obj_key new_elem ] */ - if (duk_is_undefined(thr, -1)) { - duk_pop(thr); - duk_del_prop(thr, -3); - } else { - /* XXX: duk_xdef_prop_index_wec() would be more appropriate - * here but it currently makes some assumptions that might - * not hold (e.g. that previous property is not an accessor). - * - * Using duk_put_prop() works incorrectly with '__proto__' - * if the own property with that name has been deleted. This - * does not happen normally, but a clever reviver can trigger - * that, see complex reviver case in: test-bug-json-parse-__proto__.js. - */ - duk_put_prop(thr, -4); - } - } - duk_pop(thr); /* pop enum */ - } - } - - /* [ ... holder name val ] */ - - duk_dup(thr, js_ctx->idx_reviver); - duk_insert(thr, -4); /* -> [ ... reviver holder name val ] */ - duk_call_method(thr, 2); /* -> [ ... res ] */ - - DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T", - (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -1))); -} - -/* - * Stringify implementation. - */ - -#define DUK__EMIT_1(js_ctx,ch) duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch)) -#define DUK__EMIT_2(js_ctx,ch1,ch2) duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2)) -#define DUK__EMIT_HSTR(js_ctx,h) duk__emit_hstring((js_ctx), (h)) -#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC) -#define DUK__EMIT_CSTR(js_ctx,p) duk__emit_cstring((js_ctx), (p)) -#endif -#define DUK__EMIT_STRIDX(js_ctx,i) duk__emit_stridx((js_ctx), (i)) -#define DUK__UNEMIT_1(js_ctx) duk__unemit_1((js_ctx)) - -DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) { - DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch); -} - -DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) { - DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2); -} - -DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) { - DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h); -} - -#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) { - DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str); -} -#endif - -DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) { - duk_hstring *h; - - DUK_ASSERT_STRIDX_VALID(stridx); - h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); - DUK_ASSERT(h != NULL); - - DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h); -} - -DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) { - DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1); - DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1); -} - -#define DUK__MKESC(nybbles,esc1,esc2) \ - (((duk_uint_fast32_t) (nybbles)) << 16) | \ - (((duk_uint_fast32_t) (esc1)) << 8) | \ - ((duk_uint_fast32_t) (esc2)) - -DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) { - duk_uint_fast32_t tmp; - duk_small_uint_t dig; - - DUK_UNREF(js_ctx); - - /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */ - - /* Select appropriate escape format automatically, and set 'tmp' to a - * value encoding both the escape format character and the nybble count: - * - * (nybble_count << 16) | (escape_char1) | (escape_char2) - */ - -#if defined(DUK_USE_JX) - if (DUK_LIKELY(cp < 0x100UL)) { - if (DUK_UNLIKELY(js_ctx->flag_ext_custom != 0U)) { - tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X); - } else { - tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U); - } - } else -#endif - if (DUK_LIKELY(cp < 0x10000UL)) { - tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U); - } else { -#if defined(DUK_USE_JX) - if (DUK_LIKELY(js_ctx->flag_ext_custom != 0U)) { - tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U); - } else -#endif - { - /* In compatible mode and standard JSON mode, output - * something useful for non-BMP characters. This won't - * roundtrip but will still be more or less readable and - * more useful than an error. - */ - tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS); - } - } - - *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff); - *q++ = (duk_uint8_t) (tmp & 0xff); - - tmp = tmp >> 16; - while (tmp > 0) { - tmp--; - dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f); - *q++ = duk_lc_digits[dig]; - } - - return q; -} - -DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) { - const duk_int8_t *p, *p_start, *p_end; /* Note: intentionally signed. */ - duk_size_t k_len; - duk_codepoint_t cp; - - DUK_ASSERT(k != NULL); - - /* Accept ASCII strings which conform to identifier requirements - * as being emitted without key quotes. Since we only accept ASCII - * there's no need for actual decoding: 'p' is intentionally signed - * so that bytes >= 0x80 extend to negative values and are rejected - * as invalid identifier codepoints. - */ - - if (js_ctx->flag_avoid_key_quotes) { - k_len = DUK_HSTRING_GET_BYTELEN(k); - p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k); - p_end = p_start + k_len; - p = p_start; - - if (p == p_end) { - /* Zero length string is not accepted without quotes */ - goto quote_normally; - } - cp = (duk_codepoint_t) (*p++); - if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) { - goto quote_normally; - } - while (p < p_end) { - cp = (duk_codepoint_t) (*p++); - if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) { - goto quote_normally; - } - } - - /* This seems faster than emitting bytes one at a time and - * then potentially rewinding. - */ - DUK__EMIT_HSTR(js_ctx, k); - return; - } - - quote_normally: - duk__enc_quote_string(js_ctx, k); -} - -/* The Quote(value) operation: quote a string. - * - * Stack policy: [ ] -> [ ]. - */ - -DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) { - duk_hthread *thr = js_ctx->thr; - const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp; - duk_uint8_t *q; - duk_ucodepoint_t cp; /* typed for duk_unicode_decode_xutf8() */ - - DUK_DDD(DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str)); - - DUK_ASSERT(h_str != NULL); - p_start = DUK_HSTRING_GET_DATA(h_str); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str); - p = p_start; - - DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE); - - /* Encode string in small chunks, estimating the maximum expansion so that - * there's no need to ensure space while processing the chunk. - */ - - while (p < p_end) { - duk_size_t left, now, space; - - left = (duk_size_t) (p_end - p); - now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ? - DUK__JSON_ENCSTR_CHUNKSIZE : left); - - /* Maximum expansion per input byte is 6: - * - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6). - * - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3). - * - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5). - */ - space = now * 6; - q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space); - - p_now = p + now; - - while (p < p_now) { -#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH) - duk_uint8_t b; - - b = duk__json_quotestr_lookup[*p++]; - if (DUK_LIKELY(b < 0x80)) { - /* Most input bytes go through here. */ - *q++ = b; - } else if (b >= 0xa0) { - *q++ = DUK_ASC_BACKSLASH; - *q++ = (duk_uint8_t) (b - 0x80); - } else if (b == 0x80) { - cp = (duk_ucodepoint_t) (*(p - 1)); - q = duk__emit_esc_auto_fast(js_ctx, cp, q); - } else if (b == 0x7f && js_ctx->flag_ascii_only) { - /* 0x7F is special */ - DUK_ASSERT(b == 0x81); - cp = (duk_ucodepoint_t) 0x7f; - q = duk__emit_esc_auto_fast(js_ctx, cp, q); - } else { - DUK_ASSERT(b == 0x81); - p--; - - /* slow path is shared */ -#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ - cp = *p; - - if (DUK_LIKELY(cp <= 0x7f)) { - /* ascii fast path: avoid decoding utf-8 */ - p++; - if (cp == 0x22 || cp == 0x5c) { - /* double quote or backslash */ - *q++ = DUK_ASC_BACKSLASH; - *q++ = (duk_uint8_t) cp; - } else if (cp < 0x20) { - duk_uint_fast8_t esc_char; - - /* This approach is a bit shorter than a straight - * if-else-ladder and also a bit faster. - */ - if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) && - (esc_char = duk__json_quotestr_esc[cp]) != 0) { - *q++ = DUK_ASC_BACKSLASH; - *q++ = (duk_uint8_t) esc_char; - } else { - q = duk__emit_esc_auto_fast(js_ctx, cp, q); - } - } else if (cp == 0x7f && js_ctx->flag_ascii_only) { - q = duk__emit_esc_auto_fast(js_ctx, cp, q); - } else { - /* any other printable -> as is */ - *q++ = (duk_uint8_t) cp; - } - } else { - /* slow path is shared */ -#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ - - /* slow path decode */ - - /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly - * and go forward one byte. This is of course very lossy, but allows some kind - * of output to be produced even for internal strings which don't conform to - * XUTF-8. All standard Ecmascript strings are always CESU-8, so this behavior - * does not violate the Ecmascript specification. The behavior is applied to - * all modes, including Ecmascript standard JSON. Because the current XUTF-8 - * decoding is not very strict, this behavior only really affects initial bytes - * and truncated codepoints. - * - * Another alternative would be to scan forwards to start of next codepoint - * (or end of input) and emit just one replacement codepoint. - */ - - p_tmp = p; - if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) { - /* Decode failed. */ - cp = *p_tmp; - p = p_tmp + 1; - } - -#if defined(DUK_USE_NONSTD_JSON_ESC_U2028_U2029) - if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) { -#else - if (js_ctx->flag_ascii_only) { -#endif - q = duk__emit_esc_auto_fast(js_ctx, cp, q); - } else { - /* as is */ - DUK_RAW_WRITE_XUTF8(q, cp); - } - } - } - - DUK_BW_SET_PTR(thr, &js_ctx->bw, q); - } - - DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE); -} - -/* Encode a double (checked by caller) from stack top. Stack top may be - * replaced by serialized string but is not popped (caller does that). - */ -DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) { - duk_hthread *thr; - duk_tval *tv; - duk_double_t d; - duk_small_int_t c; - duk_small_int_t s; - duk_small_uint_t stridx; - duk_small_uint_t n2s_flags; - duk_hstring *h_str; - - DUK_ASSERT(js_ctx != NULL); - thr = js_ctx->thr; - DUK_ASSERT(thr != NULL); - - /* Caller must ensure 'tv' is indeed a double and not a fastint! */ - tv = DUK_GET_TVAL_NEGIDX(thr, -1); - DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); - d = DUK_TVAL_GET_DOUBLE(tv); - - c = (duk_small_int_t) DUK_FPCLASSIFY(d); - s = (duk_small_int_t) DUK_SIGNBIT(d); - DUK_UNREF(s); - - if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) { - DUK_ASSERT(DUK_ISFINITE(d)); - -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - /* Negative zero needs special handling in JX/JC because - * it would otherwise serialize to '0', not '-0'. - */ - if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 && - (js_ctx->flag_ext_custom_or_compatible))) { - duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_ZERO); /* '-0' */ - } else -#endif /* DUK_USE_JX || DUK_USE_JC */ - { - n2s_flags = 0; - /* [ ... number ] -> [ ... string ] */ - duk_numconv_stringify(thr, 10 /*radix*/, 0 /*digits*/, n2s_flags); - } - h_str = duk_known_hstring(thr, -1); - DUK__EMIT_HSTR(js_ctx, h_str); - return; - } - -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | - DUK_JSON_FLAG_EXT_COMPATIBLE))) { - stridx = DUK_STRIDX_LC_NULL; - } else if (c == DUK_FP_NAN) { - stridx = js_ctx->stridx_custom_nan; - } else if (s == 0) { - stridx = js_ctx->stridx_custom_posinf; - } else { - stridx = js_ctx->stridx_custom_neginf; - } -#else - stridx = DUK_STRIDX_LC_NULL; -#endif - DUK__EMIT_STRIDX(js_ctx, stridx); -} - -#if defined(DUK_USE_FASTINT) -/* Encode a fastint from duk_tval ptr, no value stack effects. */ -DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) { - duk_int64_t v; - - /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328 - * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808 - * (20 chars long). Alloc space for 64-bit range to be safe. - */ - duk_uint8_t buf[20 + 1]; - - /* Caller must ensure 'tv' is indeed a fastint! */ - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); - v = DUK_TVAL_GET_FASTINT(tv); - - /* XXX: There are no format strings in duk_config.h yet, could add - * one for formatting duk_int64_t. For now, assumes "%lld" and that - * "long long" type exists. Could also rely on C99 directly but that - * won't work for older MSVC. - */ - DUK_SPRINTF((char *) buf, "%lld", (long long) v); - DUK__EMIT_CSTR(js_ctx, (const char *) buf); -} -#endif - -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) -#if defined(DUK_USE_HEX_FASTPATH) -DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) { - duk_uint8_t *q; - duk_uint16_t *q16; - duk_small_uint_t x; - duk_size_t i, len_safe; -#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) - duk_bool_t shift_dst; -#endif - - /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2. - * For platforms where unaligned accesses are not allowed, shift 'dst' - * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result - * in place. The faster encoding loop makes up the difference. - * There's always space for one extra byte because a terminator always - * follows the hex data and that's been accounted for by the caller. - */ - -#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) - q16 = (duk_uint16_t *) (void *) dst; -#else - shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U); - if (shift_dst) { - DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1")); - q16 = (duk_uint16_t *) (void *) (dst + 1); - } else { - DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned")); - q16 = (duk_uint16_t *) (void *) dst; - } - DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0); -#endif - - len_safe = src_len & ~0x03U; - for (i = 0; i < len_safe; i += 4) { - q16[0] = duk_hex_enctab[src[i]]; - q16[1] = duk_hex_enctab[src[i + 1]]; - q16[2] = duk_hex_enctab[src[i + 2]]; - q16[3] = duk_hex_enctab[src[i + 3]]; - q16 += 4; - } - q = (duk_uint8_t *) q16; - -#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) - if (shift_dst) { - q--; - DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe); - DUK_ASSERT(dst + 2 * len_safe == q); - } -#endif - - for (; i < src_len; i++) { - x = src[i]; - *q++ = duk_lc_digits[x >> 4]; - *q++ = duk_lc_digits[x & 0x0f]; - } - - return q; -} -#else /* DUK_USE_HEX_FASTPATH */ -DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) { - const duk_uint8_t *p; - const duk_uint8_t *p_end; - duk_uint8_t *q; - duk_small_uint_t x; - - p = src; - p_end = src + src_len; - q = dst; - while (p != p_end) { - x = *p++; - *q++ = duk_lc_digits[x >> 4]; - *q++ = duk_lc_digits[x & 0x0f]; - } - - return q; -} -#endif /* DUK_USE_HEX_FASTPATH */ - -DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) { - duk_hthread *thr; - duk_uint8_t *q; - duk_size_t space; - - thr = js_ctx->thr; - - DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ - DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); - - /* Buffer values are encoded in (lowercase) hex to make the - * binary data readable. Base64 or similar would be more - * compact but less readable, and the point of JX/JC - * variants is to be as useful to a programmer as possible. - */ - - /* The #if defined() clutter here needs to handle the three - * cases: (1) JX+JC, (2) JX only, (3) JC only. - */ - - /* Note: space must cater for both JX and JC. */ - space = 9 + buf_len * 2 + 2; - DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL); - DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */ - q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space); - -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom) -#endif -#if defined(DUK_USE_JX) - { - *q++ = DUK_ASC_PIPE; - q = duk__enc_buffer_data_hex(buf_data, buf_len, q); - *q++ = DUK_ASC_PIPE; - - } -#endif -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - else -#endif -#if defined(DUK_USE_JC) - { - DUK_ASSERT(js_ctx->flag_ext_compatible); - DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */ - q += 9; - q = duk__enc_buffer_data_hex(buf_data, buf_len, q); - *q++ = DUK_ASC_DOUBLEQUOTE; - *q++ = DUK_ASC_RCURLY; - } -#endif - - DUK_BW_SET_PTR(thr, &js_ctx->bw, q); -} - -DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { - duk__enc_buffer_data(js_ctx, - (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h), - (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); -} -#endif /* DUK_USE_JX || DUK_USE_JC */ - -#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) -DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { - duk_size_t i, n; - const duk_uint8_t *buf; - duk_uint8_t *q; - - n = DUK_HBUFFER_GET_SIZE(h); - if (n == 0) { - DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY); - return; - } - - DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); - - /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18, - * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some slack. - * - * Note that because the output buffer is reallocated from time to time, - * side effects (such as finalizers) affecting the buffer 'h' must be - * disabled. This is the case in the JSON.stringify() fast path. - */ - - buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h); - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - for (i = 0; i < n; i++) { - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1); - q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32); - q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]); - DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); - } - } else { - q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw); - for (i = 0; i < n; i++) { - q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q); - q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]); - } - DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); - } - DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ - - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); - } - DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); -} -#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ - -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { - char buf[64]; /* XXX: how to figure correct size? */ - const char *fmt; - - DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ - DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); - - DUK_MEMZERO(buf, sizeof(buf)); - - /* The #if defined() clutter here needs to handle the three - * cases: (1) JX+JC, (2) JX only, (3) JC only. - */ -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom) -#endif -#if defined(DUK_USE_JX) - { - fmt = ptr ? "(%p)" : "(null)"; - } -#endif -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - else -#endif -#if defined(DUK_USE_JC) - { - DUK_ASSERT(js_ctx->flag_ext_compatible); - fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}"; - } -#endif - - /* When ptr == NULL, the format argument is unused. */ - DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */ - DUK__EMIT_CSTR(js_ctx, buf); -} -#endif /* DUK_USE_JX || DUK_USE_JC */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) { - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { - DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); - } else { - /* Handle both full and partial slice (as long as covered). */ - duk__enc_buffer_data(js_ctx, - (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj), - (duk_size_t) h_bufobj->length); - } -} -#endif /* DUK_USE_JX || DUK_USE_JC */ -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* Indent helper. Calling code relies on js_ctx->recursion_depth also being - * directly related to indent depth. - */ -#if defined(DUK_USE_PREFER_SIZE) -DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) { - DUK_ASSERT(js_ctx->h_gap != NULL); - DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */ - - DUK__EMIT_1(js_ctx, 0x0a); - while (depth-- > 0) { - DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap); - } -} -#else /* DUK_USE_PREFER_SIZE */ -DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) { - const duk_uint8_t *gap_data; - duk_size_t gap_len; - duk_size_t avail_bytes; /* bytes of indent available for copying */ - duk_size_t need_bytes; /* bytes of indent still needed */ - duk_uint8_t *p_start; - duk_uint8_t *p; - - DUK_ASSERT(js_ctx->h_gap != NULL); - DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */ - - DUK__EMIT_1(js_ctx, 0x0a); - if (DUK_UNLIKELY(depth == 0)) { - return; - } - - /* To handle deeper indents efficiently, make use of copies we've - * already emitted. In effect we can emit a sequence of 1, 2, 4, - * 8, etc copies, and then finish the last run. Byte counters - * avoid multiply with gap_len on every loop. - */ - - gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap); - gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap); - DUK_ASSERT(gap_len > 0); - - need_bytes = gap_len * depth; - p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes); - p_start = p; - - DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len); - p += gap_len; - avail_bytes = gap_len; - DUK_ASSERT(need_bytes >= gap_len); - need_bytes -= gap_len; - - while (need_bytes >= avail_bytes) { - DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes); - p += avail_bytes; - need_bytes -= avail_bytes; - avail_bytes <<= 1; - } - - DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */ - DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes); - p += need_bytes; - /*avail_bytes += need_bytes*/ - - DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p); -} -#endif /* DUK_USE_PREFER_SIZE */ - -/* Shared entry handling for object/array serialization. */ -DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) { - duk_hthread *thr = js_ctx->thr; - duk_hobject *h_target; - duk_uint_fast32_t i, n; - - *entry_top = duk_get_top(thr); - - duk_require_stack(thr, DUK_JSON_ENC_REQSTACK); - - /* Loop check using a hybrid approach: a fixed-size visited[] array - * with overflow in a loop check object. - */ - - h_target = duk_known_hobject(thr, -1); /* object or array */ - - n = js_ctx->recursion_depth; - if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) { - n = DUK_JSON_ENC_LOOPARRAY; - } - for (i = 0; i < n; i++) { - if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) { - DUK_DD(DUK_DDPRINT("slow path loop detect")); - DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT); - } - } - if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { - js_ctx->visiting[js_ctx->recursion_depth] = h_target; - } else { - duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target); - duk_dup_top(thr); /* -> [ ... voidp voidp ] */ - if (duk_has_prop(thr, js_ctx->idx_loop)) { - DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT); - } - duk_push_true(thr); /* -> [ ... voidp true ] */ - duk_put_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */ - } - - /* C recursion check. */ - - DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */ - DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); - if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { - DUK_ERROR_RANGE(thr, DUK_STR_JSONENC_RECLIMIT); - } - js_ctx->recursion_depth++; - - DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T", - (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop))); -} - -/* Shared exit handling for object/array serialization. */ -DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) { - duk_hthread *thr = js_ctx->thr; - duk_hobject *h_target; - - /* C recursion check. */ - - DUK_ASSERT(js_ctx->recursion_depth > 0); - DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); - js_ctx->recursion_depth--; - - /* Loop check. */ - - h_target = duk_known_hobject(thr, *entry_top - 1); /* original target at entry_top - 1 */ - - if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { - /* Previous entry was inside visited[], nothing to do. */ - } else { - duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target); - duk_del_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */ - } - - /* Restore stack top after unbalanced code paths. */ - duk_set_top(thr, *entry_top); - - DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T", - (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop))); -} - -/* The JO(value) operation: encode object. - * - * Stack policy: [ object ] -> [ object ]. - */ -DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - duk_hstring *h_key; - duk_idx_t entry_top; - duk_idx_t idx_obj; - duk_idx_t idx_keys; - duk_bool_t emitted; - duk_uarridx_t arr_len, i; - duk_size_t prev_size; - - DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(thr, -1))); - - duk__enc_objarr_entry(js_ctx, &entry_top); - - idx_obj = entry_top - 1; - - if (js_ctx->idx_proplist >= 0) { - idx_keys = js_ctx->idx_proplist; - } else { - /* XXX: would be nice to enumerate an object at specified index */ - duk_dup(thr, idx_obj); - (void) duk_hobject_get_enumerated_keys(thr, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */ - idx_keys = duk_require_normalize_index(thr, -1); - /* leave stack unbalanced on purpose */ - } - - DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T", - (long) idx_keys, (duk_tval *) duk_get_tval(thr, idx_keys))); - - /* Steps 8-10 have been merged to avoid a "partial" variable. */ - - DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); - - /* XXX: keys is an internal object with all keys to be processed - * in its (gapless) array part. Because nobody can touch the keys - * object, we could iterate its array part directly (keeping in mind - * that it can be reallocated). - */ - - arr_len = (duk_uarridx_t) duk_get_length(thr, idx_keys); - emitted = 0; - for (i = 0; i < arr_len; i++) { - duk_get_prop_index(thr, idx_keys, i); /* -> [ ... key ] */ - - DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T", - (duk_tval *) duk_get_tval(thr, idx_obj), - (duk_tval *) duk_get_tval(thr, -1))); - - h_key = duk_known_hstring(thr, -1); - DUK_ASSERT(h_key != NULL); - DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key)); /* proplist filtering; enum options */ - - prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw); - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); - duk__enc_key_autoquote(js_ctx, h_key); - DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE); - } else { - duk__enc_key_autoquote(js_ctx, h_key); - DUK__EMIT_1(js_ctx, DUK_ASC_COLON); - } - - /* [ ... key ] */ - - if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_obj) == 0)) { - /* Value would yield 'undefined', so skip key altogether. - * Side effects have already happened. - */ - DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size); - } else { - DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); - emitted = 1; - } - - /* [ ... ] */ - } - - if (emitted) { - DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); - DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - DUK_ASSERT(js_ctx->recursion_depth >= 1); - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U); - } - } - DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); - - duk__enc_objarr_exit(js_ctx, &entry_top); - - DUK_ASSERT_TOP(thr, entry_top); -} - -/* The JA(value) operation: encode array. - * - * Stack policy: [ array ] -> [ array ]. - */ -DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) { - duk_hthread *thr = js_ctx->thr; - duk_idx_t entry_top; - duk_idx_t idx_arr; - duk_bool_t emitted; - duk_uarridx_t i, arr_len; - - DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T", - (duk_tval *) duk_get_tval(thr, -1))); - - duk__enc_objarr_entry(js_ctx, &entry_top); - - idx_arr = entry_top - 1; - - /* Steps 8-10 have been merged to avoid a "partial" variable. */ - - DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET); - - arr_len = (duk_uarridx_t) duk_get_length(thr, idx_arr); - emitted = 0; - for (i = 0; i < arr_len; i++) { - DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld", - (duk_tval *) duk_get_tval(thr, idx_arr), - (long) i, (long) arr_len)); - - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - DUK_ASSERT(js_ctx->recursion_depth >= 1); - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); - } - - (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... key ] */ - - /* [ ... key ] */ - - if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_arr) == 0)) { - /* Value would normally be omitted, replace with 'null'. */ - DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); - } else { - ; - } - - /* [ ... ] */ - - DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); - emitted = 1; - } - - if (emitted) { - DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); - DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - DUK_ASSERT(js_ctx->recursion_depth >= 1); - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U); - } - } - DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET); - - duk__enc_objarr_exit(js_ctx, &entry_top); - - DUK_ASSERT_TOP(thr, entry_top); -} - -/* The Str(key, holder) operation. - * - * Stack policy: [ ... key ] -> [ ... ] - */ -DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) { - duk_hthread *thr = js_ctx->thr; - duk_tval *tv; - duk_tval *tv_holder; - duk_tval *tv_key; - duk_small_int_t c; - - DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T", - (long) idx_holder, (duk_tval *) duk_get_tval(thr, idx_holder), - (duk_tval *) duk_get_tval(thr, -1))); - - tv_holder = DUK_GET_TVAL_POSIDX(thr, idx_holder); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder)); - tv_key = DUK_GET_TVAL_NEGIDX(thr, -1); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key)); - DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key))); /* Caller responsible. */ - (void) duk_hobject_getprop(thr, tv_holder, tv_key); - - /* -> [ ... key val ] */ - - DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1))); - - /* Standard JSON checks for .toJSON() only for actual objects; for - * example, setting Number.prototype.toJSON and then serializing a - * number won't invoke the .toJSON() method. However, lightfuncs and - * plain buffers mimic objects so we check for their .toJSON() method. - */ - if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | - DUK_TYPE_MASK_LIGHTFUNC | - DUK_TYPE_MASK_BUFFER)) { - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_JSON); - if (duk_is_callable(thr, -1)) { /* toJSON() can also be a lightfunc */ - DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it")); - /* XXX: duk_dup_unvalidated(thr, -2) etc. */ - duk_dup_m2(thr); /* -> [ ... key val toJSON val ] */ - duk_dup_m4(thr); /* -> [ ... key val toJSON val key ] */ - duk_call_method(thr, 1); /* -> [ ... key val val' ] */ - duk_remove_m2(thr); /* -> [ ... key val' ] */ - } else { - duk_pop(thr); /* -> [ ... key val ] */ - } - } - - /* [ ... key val ] */ - - DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1))); - - if (js_ctx->h_replacer) { - /* XXX: Here a "slice copy" would be useful. */ - DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer")); - duk_push_hobject(thr, js_ctx->h_replacer); /* -> [ ... key val replacer ] */ - duk_dup(thr, idx_holder); /* -> [ ... key val replacer holder ] */ - duk_dup_m4(thr); /* -> [ ... key val replacer holder key ] */ - duk_dup_m4(thr); /* -> [ ... key val replacer holder key val ] */ - duk_call_method(thr, 2); /* -> [ ... key val val' ] */ - duk_remove_m2(thr); /* -> [ ... key val' ] */ - } - - /* [ ... key val ] */ - - DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1))); - - tv = DUK_GET_TVAL_NEGIDX(thr, -1); - if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h; - - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (DUK_HOBJECT_IS_BUFOBJ(h) && - js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE)) { - /* With JX/JC a bufferobject gets serialized specially. */ - duk_hbufobj *h_bufobj; - h_bufobj = (duk_hbufobj *) h; - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - duk__enc_bufobj(js_ctx, h_bufobj); - goto pop2_emitted; - } - /* Otherwise bufferobjects get serialized as normal objects. */ -#endif /* JX || JC */ -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); - switch (c) { - case DUK_HOBJECT_CLASS_NUMBER: { - DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()")); - duk_to_number_m1(thr); - /* The coercion potentially invokes user .valueOf() and .toString() - * but can't result in a function value because ToPrimitive() would - * reject such a result: test-dev-json-stringify-coercion-1.js. - */ - DUK_ASSERT(!duk_is_callable(thr, -1)); - break; - } - case DUK_HOBJECT_CLASS_STRING: { - DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()")); - duk_to_string(thr, -1); - /* Same coercion behavior as for Number. */ - DUK_ASSERT(!duk_is_callable(thr, -1)); - break; - } -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - case DUK_HOBJECT_CLASS_POINTER: -#endif - case DUK_HOBJECT_CLASS_BOOLEAN: { - DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value")); - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); - duk_remove_m2(thr); - break; - } - default: { - /* Normal object which doesn't get automatically coerced to a - * primitive value. Functions are checked for specially. The - * primitive value coercions for Number, String, Pointer, and - * Boolean can't result in functions so suffices to check here. - * Symbol objects are handled like plain objects (their primitive - * value is NOT looked up like for e.g. String objects). - */ - DUK_ASSERT(h != NULL); - if (DUK_HOBJECT_IS_CALLABLE(h)) { -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | - DUK_JSON_FLAG_EXT_COMPATIBLE)) { - /* We only get here when doing non-standard JSON encoding */ - DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format")); - DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); - DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); - goto pop2_emitted; - } else { - DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)")); - goto pop2_undef; - } -#else /* DUK_USE_JX || DUK_USE_JC */ - DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)")); - goto pop2_undef; -#endif /* DUK_USE_JX || DUK_USE_JC */ - } - } - } /* end switch */ - } - - /* [ ... key val ] */ - - DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1))); - - if (duk_check_type_mask(thr, -1, js_ctx->mask_for_undefined)) { - /* will result in undefined */ - DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)")); - goto pop2_undef; - } - tv = DUK_GET_TVAL_NEGIDX(thr, -1); - - switch (DUK_TVAL_GET_TAG(tv)) { -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - /* When JX/JC not in use, the type mask above will avoid this case if needed. */ - case DUK_TAG_UNDEFINED: { - DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); - break; - } -#endif - case DUK_TAG_NULL: { - DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); - break; - } - case DUK_TAG_BOOLEAN: { - DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ? - DUK_STRIDX_TRUE : DUK_STRIDX_FALSE); - break; - } -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - /* When JX/JC not in use, the type mask above will avoid this case if needed. */ - case DUK_TAG_POINTER: { - duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv)); - break; - } -#endif /* DUK_USE_JX || DUK_USE_JC */ - case DUK_TAG_STRING: { - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - goto pop2_undef; - } - duk__enc_quote_string(js_ctx, h); - break; - } - case DUK_TAG_OBJECT: { - duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - - /* Function values are handled completely above (including - * coercion results): - */ - DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h)); - - if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) { - duk__enc_array(js_ctx); - } else { - duk__enc_object(js_ctx); - } - break; - } - /* Because plain buffers mimics Uint8Array, they have enumerable - * index properties [0,byteLength[. Because JSON only serializes - * enumerable own properties, no properties can be serialized for - * plain buffers (all virtual properties are non-enumerable). However, - * there may be a .toJSON() method which was already handled above. - */ - case DUK_TAG_BUFFER: { -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); - break; - } -#endif - - /* Could implement a fastpath, but the fast path would need - * to handle realloc side effects correctly. - */ - duk_to_object(thr, -1); - duk__enc_object(js_ctx); - break; - } - case DUK_TAG_LIGHTFUNC: { -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - /* We only get here when doing non-standard JSON encoding */ - DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); - DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); -#else - /* Standard JSON omits functions */ - DUK_UNREACHABLE(); -#endif - break; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: - /* Number serialization has a significant impact relative to - * other fast path code, so careful fast path for fastints. - */ - duk__enc_fastint_tval(js_ctx, tv); - break; -#endif - default: { - /* number */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - /* XXX: A fast path for usual integers would be useful when - * fastint support is not enabled. - */ - duk__enc_double(js_ctx); - break; - } - } - -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - pop2_emitted: -#endif - duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */ - return 1; /* emitted */ - - pop2_undef: - duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */ - return 0; /* not emitted */ -} - -/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */ -DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) { - duk_small_int_t c; - - /* XXX: some kind of external internal type checker? - * - type mask; symbol flag; class mask - */ - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_STRING(tv)) { - duk_hstring *h; - h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - return 0; - } - return 1; - } else if (DUK_TVAL_IS_NUMBER(tv)) { - return 1; - } else if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h; - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); - if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) { - return 1; - } - } - - return 0; -} - -/* - * JSON.stringify() fast path - * - * Otherwise supports full JSON, JX, and JC features, but bails out on any - * possible side effect which might change the value being serialized. The - * fast path can take advantage of the fact that the value being serialized - * is unchanged so that we can walk directly through property tables etc. - */ - -#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) -DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) { - duk_uint_fast32_t i, n; - - DUK_DDD(DUK_DDDPRINT("stringify fast: %!T", tv)); - - DUK_ASSERT(js_ctx != NULL); - DUK_ASSERT(js_ctx->thr != NULL); - -#if 0 /* disabled for now */ - restart_match: -#endif - - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: { -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) { - DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); - break; - } else { - goto emit_undefined; - } -#else - goto emit_undefined; -#endif - } - case DUK_TAG_NULL: { - DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); - break; - } - case DUK_TAG_BOOLEAN: { - DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ? - DUK_STRIDX_TRUE : DUK_STRIDX_FALSE); - break; - } - case DUK_TAG_STRING: { - duk_hstring *h; - h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - goto emit_undefined; - } - duk__enc_quote_string(js_ctx, h); - break; - } - case DUK_TAG_OBJECT: { - duk_hobject *obj; - duk_tval *tv_val; - duk_bool_t emitted = 0; - duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef, - c_func, c_bufobj, c_object, c_abort; - - /* For objects JSON.stringify() only looks for own, enumerable - * properties which is nice for the fast path here. - * - * For arrays JSON.stringify() uses [[Get]] so it will actually - * inherit properties during serialization! This fast path - * supports gappy arrays as long as there's no actual inherited - * property (which might be a getter etc). - * - * Since recursion only happens for objects, we can have both - * recursion and loop checks here. We use a simple, depth-limited - * loop check in the fast path because the object-based tracking - * is very slow (when tested, it accounted for 50% of fast path - * execution time for input data with a lot of small objects!). - */ - - /* XXX: for real world code, could just ignore array inheritance - * and only look at array own properties. - */ - - /* We rely on a few object flag / class number relationships here, - * assert for them. - */ - - obj = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(obj != NULL); - DUK_ASSERT_HOBJECT_VALID(obj); - - /* Once recursion depth is increased, exit path must decrease - * it (though it's OK to abort the fast path). - */ - - DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */ - DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); - if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { - DUK_DD(DUK_DDPRINT("fast path recursion limit")); - DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT); - } - - for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) { - if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) { - DUK_DD(DUK_DDPRINT("fast path loop detect")); - DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT); - } - } - - /* Guaranteed by recursion_limit setup so we don't have to - * check twice. - */ - DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY); - js_ctx->visiting[js_ctx->recursion_depth] = obj; - js_ctx->recursion_depth++; - - /* If object has a .toJSON() property, we can't be certain - * that it wouldn't mutate any value arbitrarily, so bail - * out of the fast path. - * - * If an object is a Proxy we also can't avoid side effects - * so abandon. - */ - /* XXX: non-callable .toJSON() doesn't need to cause an abort - * but does at the moment, probably not worth fixing. - */ - if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) || - DUK_HOBJECT_IS_PROXY(obj)) { - DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path")); - goto abort_fastpath; - } - - /* We could use a switch-case for the class number but it turns out - * a small if-else ladder on class masks is better. The if-ladder - * should be in order of relevancy. - */ - - /* XXX: move masks to js_ctx? they don't change during one - * fast path invocation. - */ - DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31); -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom_or_compatible) { - c_all = DUK_HOBJECT_CMASK_ALL; - c_array = DUK_HOBJECT_CMASK_ARRAY; - c_unbox = DUK_HOBJECT_CMASK_NUMBER | - DUK_HOBJECT_CMASK_STRING | - DUK_HOBJECT_CMASK_BOOLEAN | - DUK_HOBJECT_CMASK_POINTER; /* Symbols are not unboxed. */ - c_func = DUK_HOBJECT_CMASK_FUNCTION; - c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFOBJS; - c_undef = 0; - c_abort = 0; - c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort); - } - else -#endif - { - c_all = DUK_HOBJECT_CMASK_ALL; - c_array = DUK_HOBJECT_CMASK_ARRAY; - c_unbox = DUK_HOBJECT_CMASK_NUMBER | - DUK_HOBJECT_CMASK_STRING | - DUK_HOBJECT_CMASK_BOOLEAN; /* Symbols are not unboxed. */ - c_func = 0; - c_bufobj = 0; - c_undef = DUK_HOBJECT_CMASK_FUNCTION | - DUK_HOBJECT_CMASK_POINTER; - /* As the fast path doesn't currently properly support - * duk_hbufobj virtual properties, abort fast path if - * we encounter them in plain JSON mode. - */ - c_abort = DUK_HOBJECT_CMASK_ALL_BUFOBJS; - c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort); - } - - c_bit = (duk_uint32_t) DUK_HOBJECT_GET_CLASS_MASK(obj); - if (c_bit & c_object) { - /* All other object types. */ - DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); - - /* A non-Array object should not have an array part in practice. - * But since it is supported internally (and perhaps used at some - * point), check and abandon if that's the case. - */ - if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) { - DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path")); - goto abort_fastpath; - } - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) { - duk_hstring *k; - duk_size_t prev_size; - - k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i); - if (!k) { - continue; - } - if (DUK_HSTRING_HAS_ARRIDX(k)) { - /* If an object has array index keys we would need - * to sort them into the ES2015 enumeration order to - * be consistent with the slow path. Abort the fast - * path and handle in the slow path for now. - */ - DUK_DD(DUK_DDPRINT("property key is an array index, abort fast path")); - goto abort_fastpath; - } - if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) { - continue; - } - if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) { - /* Getter might have arbitrary side effects, - * so bail out. - */ - DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path")); - goto abort_fastpath; - } - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { - continue; - } - - tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i); - - prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw); - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); - duk__enc_key_autoquote(js_ctx, k); - DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE); - } else { - duk__enc_key_autoquote(js_ctx, k); - DUK__EMIT_1(js_ctx, DUK_ASC_COLON); - } - - if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) { - DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon")); - DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size); - } else { - DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); - emitted = 1; - } - } - - /* If any non-Array value had enumerable virtual own - * properties, they should be serialized here (actually, - * before the explicit properties). Standard types don't. - */ - - if (emitted) { - DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); - DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - DUK_ASSERT(js_ctx->recursion_depth >= 1); - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U); - } - } - DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); - } else if (c_bit & c_array) { - duk_uint_fast32_t arr_len; - duk_uint_fast32_t asize; - - DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET); - - /* Assume arrays are dense in the fast path. */ - if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) { - DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path")); - goto abort_fastpath; - } - - arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length; - asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj); - /* Array part may be larger than 'length'; if so, iterate - * only up to array 'length'. Array part may also be smaller - * than 'length' in some cases. - */ - for (i = 0; i < arr_len; i++) { - duk_tval *tv_arrval; - duk_hstring *h_tmp; - duk_bool_t has_inherited; - - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); - } - - if (DUK_LIKELY(i < asize)) { - tv_arrval = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i); - if (DUK_LIKELY(!DUK_TVAL_IS_UNUSED(tv_arrval))) { - /* Expected case: element is present. */ - if (duk__json_stringify_fast_value(js_ctx, tv_arrval) == 0) { - DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); - } - goto elem_done; - } - } - - /* Gap in array; check for inherited property, - * bail out if one exists. This should be enough - * to support gappy arrays for all practical code. - */ - - h_tmp = duk_push_uint_to_hstring(js_ctx->thr, (duk_uint_t) i); - has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp); - duk_pop(js_ctx->thr); - if (has_inherited) { - DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path")); - goto abort_fastpath; - } - - /* Ordinary gap, undefined encodes to 'null' in - * standard JSON, but JX/JC use their form for - * undefined to better preserve the typing. - */ - DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path")); -#if defined(DUK_USE_JX) - DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); -#else - DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); -#endif - /* fall through */ - - elem_done: - DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); - emitted = 1; - } - - if (emitted) { - DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); - DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ - if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { - DUK_ASSERT(js_ctx->recursion_depth >= 1); - duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U); - } - } - DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET); - } else if (c_bit & c_unbox) { - /* Certain boxed types are required to go through - * automatic unboxing. Rely on internal value being - * sane (to avoid infinite recursion). - */ - DUK_ASSERT((c_bit & DUK_HOBJECT_CMASK_SYMBOL) == 0); /* Symbols are not unboxed. */ - -#if 1 - /* The code below is incorrect if .toString() or .valueOf() have - * have been overridden. The correct approach would be to look up - * the method(s) and if they resolve to the built-in function we - * can safely bypass it and look up the internal value directly. - * Unimplemented for now, abort fast path for boxed values. - */ - goto abort_fastpath; -#else /* disabled */ - /* Disabled until fixed, see above. */ - duk_tval *tv_internal; - - DUK_DD(DUK_DDPRINT("auto unboxing in fast path")); - - tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj); - DUK_ASSERT(tv_internal != NULL); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) || - DUK_TVAL_IS_NUMBER(tv_internal) || - DUK_TVAL_IS_BOOLEAN(tv_internal) || - DUK_TVAL_IS_POINTER(tv_internal)); - - tv = tv_internal; - DUK_ASSERT(js_ctx->recursion_depth > 0); - js_ctx->recursion_depth--; /* required to keep recursion depth correct */ - goto restart_match; -#endif /* disabled */ -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - } else if (c_bit & c_func) { - DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - } else if (c_bit & c_bufobj) { - duk__enc_bufobj(js_ctx, (duk_hbufobj *) obj); -#endif -#endif - } else if (c_bit & c_abort) { - DUK_DD(DUK_DDPRINT("abort fast path for unsupported type")); - goto abort_fastpath; - } else { - DUK_ASSERT((c_bit & c_undef) != 0); - - /* Must decrease recursion depth before returning. */ - DUK_ASSERT(js_ctx->recursion_depth > 0); - DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); - js_ctx->recursion_depth--; - goto emit_undefined; - } - - DUK_ASSERT(js_ctx->recursion_depth > 0); - DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); - js_ctx->recursion_depth--; - break; - } - case DUK_TAG_BUFFER: { - /* Plain buffers are treated like Uint8Arrays: they have - * enumerable indices. Other virtual properties are not - * enumerable, and inherited properties are not serialized. - * However, there can be a replacer (not relevant here) or - * a .toJSON() method (which we need to check for explicitly). - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - if (duk_hobject_hasprop_raw(js_ctx->thr, - js_ctx->thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE], - DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr))) { - DUK_DD(DUK_DDPRINT("value is a plain buffer and there's an inherited .toJSON, abort fast path")); - goto abort_fastpath; - } -#endif - -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); - break; - } -#endif - - /* Plain buffers mimic Uint8Arrays, and have enumerable index - * properties. - */ - duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv)); - break; - } - case DUK_TAG_POINTER: { -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv)); - break; - } else { - goto emit_undefined; - } -#else - goto emit_undefined; -#endif - } - case DUK_TAG_LIGHTFUNC: { - /* A lightfunc might also inherit a .toJSON() so just bail out. */ - /* XXX: Could just lookup .toJSON() and continue in fast path, - * as it would almost never be defined. - */ - DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path")); - goto abort_fastpath; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: { - /* Number serialization has a significant impact relative to - * other fast path code, so careful fast path for fastints. - */ - duk__enc_fastint_tval(js_ctx, tv); - break; - } -#endif - default: { - /* XXX: A fast path for usual integers would be useful when - * fastint support is not enabled. - */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - - /* XXX: Stack discipline is annoying, could be changed in numconv. */ - duk_push_tval(js_ctx->thr, tv); - duk__enc_double(js_ctx); - duk_pop(js_ctx->thr); - -#if 0 - /* Could also rely on native sprintf(), but it will handle - * values like NaN, Infinity, -0, exponent notation etc in - * a JSON-incompatible way. - */ - duk_double_t d; - char buf[64]; - - DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); - d = DUK_TVAL_GET_DOUBLE(tv); - DUK_SPRINTF(buf, "%lg", d); - DUK__EMIT_CSTR(js_ctx, buf); -#endif - } - } - return 1; /* not undefined */ - - emit_undefined: - return 0; /* value was undefined/unsupported */ - - abort_fastpath: - /* Error message doesn't matter: the error is ignored anyway. */ - DUK_DD(DUK_DDPRINT("aborting fast path")); - DUK_ERROR_INTERNAL(js_ctx->thr); - return 0; /* unreachable */ -} - -DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) { - duk_json_enc_ctx *js_ctx; - duk_tval *tv; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(udata != NULL); - - js_ctx = (duk_json_enc_ctx *) udata; - DUK_ASSERT(js_ctx != NULL); - - tv = DUK_GET_TVAL_NEGIDX(thr, -1); - if (duk__json_stringify_fast_value(js_ctx, tv) == 0) { - DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path")); - DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* Error message is ignored, so doesn't matter. */ - } - - return 0; -} -#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ - -/* - * Top level wrappers - */ - -DUK_INTERNAL -void duk_bi_json_parse_helper(duk_hthread *thr, - duk_idx_t idx_value, - duk_idx_t idx_reviver, - duk_small_uint_t flags) { - duk_json_dec_ctx js_ctx_alloc; - duk_json_dec_ctx *js_ctx = &js_ctx_alloc; - duk_hstring *h_text; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top = duk_get_top(thr); -#endif - - /* negative top-relative indices not allowed now */ - DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0); - DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0); - - DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld", - (duk_tval *) duk_get_tval(thr, idx_value), - (duk_tval *) duk_get_tval(thr, idx_reviver), - (unsigned long) flags, - (long) duk_get_top(thr))); - - DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc)); - js_ctx->thr = thr; -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - /* nothing now */ -#endif - js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT; - DUK_ASSERT(js_ctx->recursion_depth == 0); - - /* Flag handling currently assumes that flags are consistent. This is OK - * because the call sites are now strictly controlled. - */ - - js_ctx->flags = flags; -#if defined(DUK_USE_JX) - js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM; -#endif -#if defined(DUK_USE_JC) - js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE; -#endif -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE); -#endif - - h_text = duk_to_hstring(thr, idx_value); /* coerce in-place; rejects Symbols */ - DUK_ASSERT(h_text != NULL); - - /* JSON parsing code is allowed to read [p_start,p_end]: p_end is - * valid and points to the string NUL terminator (which is always - * guaranteed for duk_hstrings. - */ - js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text); - js_ctx->p = js_ctx->p_start; - js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) + - DUK_HSTRING_GET_BYTELEN(h_text); - DUK_ASSERT(*(js_ctx->p_end) == 0x00); - - duk__dec_value(js_ctx); /* -> [ ... value ] */ - - /* Trailing whitespace has been eaten by duk__dec_value(), so if - * we're not at end of input here, it's a SyntaxError. - */ - - if (js_ctx->p != js_ctx->p_end) { - duk__dec_syntax_error(js_ctx); - } - - if (duk_is_callable(thr, idx_reviver)) { - DUK_DDD(DUK_DDDPRINT("applying reviver: %!T", - (duk_tval *) duk_get_tval(thr, idx_reviver))); - - js_ctx->idx_reviver = idx_reviver; - - duk_push_object(thr); - duk_dup_m2(thr); /* -> [ ... val root val ] */ - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */ - duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */ - - DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - - duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */ - duk_remove_m2(thr); /* -> [ ... val' ] */ - } else { - DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T", - (duk_tval *) duk_get_tval(thr, idx_reviver))); - } - - /* Final result is at stack top. */ - - DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld", - (duk_tval *) duk_get_tval(thr, idx_value), - (duk_tval *) duk_get_tval(thr, idx_reviver), - (unsigned long) flags, - (duk_tval *) duk_get_tval(thr, -1), - (long) duk_get_top(thr))); - - DUK_ASSERT(duk_get_top(thr) == entry_top + 1); -} - -DUK_INTERNAL -void duk_bi_json_stringify_helper(duk_hthread *thr, - duk_idx_t idx_value, - duk_idx_t idx_replacer, - duk_idx_t idx_space, - duk_small_uint_t flags) { - duk_json_enc_ctx js_ctx_alloc; - duk_json_enc_ctx *js_ctx = &js_ctx_alloc; - duk_hobject *h; - duk_idx_t idx_holder; - duk_idx_t entry_top; - - /* negative top-relative indices not allowed now */ - DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0); - DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0); - DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0); - - DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld", - (duk_tval *) duk_get_tval(thr, idx_value), - (duk_tval *) duk_get_tval(thr, idx_replacer), - (duk_tval *) duk_get_tval(thr, idx_space), - (unsigned long) flags, - (long) duk_get_top(thr))); - - entry_top = duk_get_top(thr); - - /* - * Context init - */ - - DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc)); - js_ctx->thr = thr; -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - js_ctx->h_replacer = NULL; - js_ctx->h_gap = NULL; -#endif - js_ctx->idx_proplist = -1; - - /* Flag handling currently assumes that flags are consistent. This is OK - * because the call sites are now strictly controlled. - */ - - js_ctx->flags = flags; - js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY; - js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES; -#if defined(DUK_USE_JX) - js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM; -#endif -#if defined(DUK_USE_JC) - js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE; -#endif -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE); -#endif - - /* The #if defined() clutter here handles the JX/JC enable/disable - * combinations properly. - */ -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */ -#if defined(DUK_USE_JX) - if (flags & DUK_JSON_FLAG_EXT_CUSTOM) { - js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED; - js_ctx->stridx_custom_nan = DUK_STRIDX_NAN; - js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY; - js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY; - js_ctx->stridx_custom_function = - (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ? - DUK_STRIDX_JSON_EXT_FUNCTION2 : - DUK_STRIDX_JSON_EXT_FUNCTION1; - } -#endif /* DUK_USE_JX */ -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - else -#endif /* DUK_USE_JX && DUK_USE_JC */ -#if defined(DUK_USE_JC) - if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) { - js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED; - js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN; - js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF; - js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF; - js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1; - } -#endif /* DUK_USE_JC */ -#endif /* DUK_USE_JX || DUK_USE_JC */ - -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | - DUK_JSON_FLAG_EXT_COMPATIBLE)) { - DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */ - } - else -#endif /* DUK_USE_JX || DUK_USE_JC */ - { - /* Plain buffer is treated like ArrayBuffer and serialized. - * Lightfuncs are treated like objects, but JSON explicitly - * skips serializing Function objects so we can just reject - * lightfuncs here. - */ - js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED | - DUK_TYPE_MASK_POINTER | - DUK_TYPE_MASK_LIGHTFUNC; - } - - DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE); - - js_ctx->idx_loop = duk_push_bare_object(thr); - DUK_ASSERT(js_ctx->idx_loop >= 0); - - /* [ ... buf loop ] */ - - /* - * Process replacer/proplist (2nd argument to JSON.stringify) - */ - - h = duk_get_hobject(thr, idx_replacer); - if (h != NULL) { - if (DUK_HOBJECT_IS_CALLABLE(h)) { - js_ctx->h_replacer = h; - } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) { - /* Here the specification requires correct array index enumeration - * which is a bit tricky for sparse arrays (it is handled by the - * enum setup code). We now enumerate ancestors too, although the - * specification is not very clear on whether that is required. - */ - - duk_uarridx_t plist_idx = 0; - duk_small_uint_t enum_flags; - - js_ctx->idx_proplist = duk_push_array(thr); /* XXX: array internal? */ - - enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY | - DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */ - duk_enum(thr, idx_replacer, enum_flags); - while (duk_next(thr, -1 /*enum_index*/, 1 /*get_value*/)) { - /* [ ... proplist enum_obj key val ] */ - if (duk__enc_allow_into_proplist(duk_get_tval(thr, -1))) { - /* XXX: duplicates should be eliminated here */ - DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - duk_to_string(thr, -1); /* extra coercion of strings is OK */ - duk_put_prop_index(thr, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */ - plist_idx++; - duk_pop(thr); - } else { - DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - duk_pop_2(thr); - } - } - duk_pop(thr); /* pop enum */ - - /* [ ... proplist ] */ - } - } - - /* [ ... buf loop (proplist) ] */ - - /* - * Process space (3rd argument to JSON.stringify) - */ - - h = duk_get_hobject(thr, idx_space); - if (h != NULL) { - duk_small_uint_t c = DUK_HOBJECT_GET_CLASS_NUMBER(h); - if (c == DUK_HOBJECT_CLASS_NUMBER) { - duk_to_number(thr, idx_space); - } else if (c == DUK_HOBJECT_CLASS_STRING) { - duk_to_string(thr, idx_space); - } - } - - if (duk_is_number(thr, idx_space)) { - duk_small_int_t nspace; - /* spaces[] must be static to allow initializer with old compilers like BCC */ - static const char spaces[10] = { - DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, - DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, - DUK_ASC_SPACE, DUK_ASC_SPACE - }; /* XXX: helper */ - - /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */ - nspace = (duk_small_int_t) duk_to_int_clamped(thr, idx_space, 0 /*minval*/, 10 /*maxval*/); - DUK_ASSERT(nspace >= 0 && nspace <= 10); - - duk_push_lstring(thr, spaces, (duk_size_t) nspace); - js_ctx->h_gap = duk_known_hstring(thr, -1); - DUK_ASSERT(js_ctx->h_gap != NULL); - } else if (duk_is_string_notsymbol(thr, idx_space)) { - duk_dup(thr, idx_space); - duk_substring(thr, -1, 0, 10); /* clamp to 10 chars */ - js_ctx->h_gap = duk_known_hstring(thr, -1); - } else { - /* nop */ - } - - if (js_ctx->h_gap != NULL) { - /* If gap is empty, behave as if not given at all. Check - * against byte length because character length is more - * expensive. - */ - if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) { - js_ctx->h_gap = NULL; - } - } - - /* [ ... buf loop (proplist) (gap) ] */ - - /* - * Fast path: assume no mutation, iterate object property tables - * directly; bail out if that assumption doesn't hold. - */ - -#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) - if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */ - js_ctx->idx_proplist == -1) { /* proplist is very rare */ - duk_int_t pcall_rc; - duk_small_uint_t prev_ms_base_flags; - - DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path")); - - /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[] - * array so we don't need two counter checks in the fast path. The - * slow path has a much larger recursion limit which we'll use if - * necessary. - */ - DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY); - js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY; - DUK_ASSERT(js_ctx->recursion_depth == 0); - - /* Execute the fast path in a protected call. If any error is thrown, - * fall back to the slow path. This includes e.g. recursion limit - * because the fast path has a smaller recursion limit (and simpler, - * limited loop detection). - */ - - duk_dup(thr, idx_value); - - /* Must prevent finalizers which may have arbitrary side effects. */ - prev_ms_base_flags = thr->heap->ms_base_flags; - thr->heap->ms_base_flags |= - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */ - thr->heap->pf_prevent_count++; /* Prevent finalizers. */ - DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ - - pcall_rc = duk_safe_call(thr, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/); - - DUK_ASSERT(thr->heap->pf_prevent_count > 0); - thr->heap->pf_prevent_count--; - thr->heap->ms_base_flags = prev_ms_base_flags; - - if (pcall_rc == DUK_EXEC_SUCCESS) { - DUK_DD(DUK_DDPRINT("fast path successful")); - DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw); - goto replace_finished; - } - - /* We come here for actual aborts (like encountering .toJSON()) - * but also for recursion/loop errors. Bufwriter size can be - * kept because we'll probably need at least as much as we've - * allocated so far. - */ - DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead")); - DUK_BW_RESET_SIZE(thr, &js_ctx->bw); - js_ctx->recursion_depth = 0; - } -#endif - - /* - * Create wrapper object and serialize - */ - - idx_holder = duk_push_object(thr); - duk_dup(thr, idx_value); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING); - - DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, " - "proplist=%!T, gap=%!O, holder=%!T", - (unsigned long) js_ctx->flags, - (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop), - (duk_heaphdr *) js_ctx->h_replacer, - (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL), - (duk_heaphdr *) js_ctx->h_gap, - (duk_tval *) duk_get_tval(thr, -1))); - - /* serialize the wrapper with empty string key */ - - duk_push_hstring_empty(thr); - - /* [ ... buf loop (proplist) (gap) holder "" ] */ - - js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT; - DUK_ASSERT(js_ctx->recursion_depth == 0); - - if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */ - /* Result is undefined. */ - duk_push_undefined(thr); - } else { - /* Convert buffer to result string. */ - DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw); - } - - DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, " - "proplist=%!T, gap=%!O, holder=%!T", - (unsigned long) js_ctx->flags, - (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop), - (duk_heaphdr *) js_ctx->h_replacer, - (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL), - (duk_heaphdr *) js_ctx->h_gap, - (duk_tval *) duk_get_tval(thr, idx_holder))); - - /* The stack has a variable shape here, so force it to the - * desired one explicitly. - */ - -#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) - replace_finished: -#endif - duk_replace(thr, entry_top); - duk_set_top(thr, entry_top + 1); - - DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, " - "flags=0x%08lx, result=%!T, stack_top=%ld", - (duk_tval *) duk_get_tval(thr, idx_value), - (duk_tval *) duk_get_tval(thr, idx_replacer), - (duk_tval *) duk_get_tval(thr, idx_space), - (unsigned long) flags, - (duk_tval *) duk_get_tval(thr, -1), - (long) duk_get_top(thr))); - - DUK_ASSERT(duk_get_top(thr) == entry_top + 1); -} - -#if defined(DUK_USE_JSON_BUILTIN) - -/* - * Entry points - */ - -DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_hthread *thr) { - duk_bi_json_parse_helper(thr, - 0 /*idx_value*/, - 1 /*idx_replacer*/, - 0 /*flags*/); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_hthread *thr) { - duk_bi_json_stringify_helper(thr, - 0 /*idx_value*/, - 1 /*idx_replacer*/, - 2 /*idx_space*/, - 0 /*flags*/); - return 1; -} - -#endif /* DUK_USE_JSON_BUILTIN */ - -#endif /* DUK_USE_JSON_SUPPORT */ - -/* automatic undefs */ -#undef DUK__EMIT_1 -#undef DUK__EMIT_2 -#undef DUK__EMIT_CSTR -#undef DUK__EMIT_HSTR -#undef DUK__EMIT_STRIDX -#undef DUK__JSON_DECSTR_BUFSIZE -#undef DUK__JSON_DECSTR_CHUNKSIZE -#undef DUK__JSON_ENCSTR_CHUNKSIZE -#undef DUK__JSON_MAX_ESC_LEN -#undef DUK__JSON_STRINGIFY_BUFSIZE -#undef DUK__MKESC -#undef DUK__UNEMIT_1 -#line 1 "duk_bi_math.c" -/* - * Math built-ins - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_MATH_BUILTIN) - -/* - * Use static helpers which can work with math.h functions matching - * the following signatures. This is not portable if any of these math - * functions is actually a macro. - * - * Typing here is intentionally 'double' wherever values interact with - * the standard library APIs. - */ - -typedef double (*duk__one_arg_func)(double); -typedef double (*duk__two_arg_func)(double, double); - -DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk__two_arg_func min_max) { - duk_idx_t n = duk_get_top(thr); - duk_idx_t i; - duk_double_t res = initial; - duk_double_t t; - - /* - * Note: fmax() does not match the E5 semantics. E5 requires - * that if -any- input to Math.max() is a NaN, the result is a - * NaN. fmax() will return a NaN only if -both- inputs are NaN. - * Same applies to fmin(). - * - * Note: every input value must be coerced with ToNumber(), even - * if we know the result will be a NaN anyway: ToNumber() may have - * side effects for which even order of evaluation matters. - */ - - for (i = 0; i < n; i++) { - t = duk_to_number(thr, i); - if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) { - /* Note: not normalized, but duk_push_number() will normalize */ - res = (duk_double_t) DUK_DOUBLE_NAN; - } else { - res = (duk_double_t) min_max(res, (double) t); - } - } - - duk_push_number(thr, res); - return 1; -} - -DUK_LOCAL double duk__fmin_fixed(double x, double y) { - /* fmin() with args -0 and +0 is not guaranteed to return - * -0 as Ecmascript requires. - */ - if (x == 0 && y == 0) { - duk_double_union du1, du2; - du1.d = x; - du2.d = y; - - /* Already checked to be zero so these must hold, and allow us - * to check for "x is -0 or y is -0" by ORing the high parts - * for comparison. - */ - DUK_ASSERT(du1.ui[DUK_DBL_IDX_UI0] == 0 || du1.ui[DUK_DBL_IDX_UI0] == 0x80000000UL); - DUK_ASSERT(du2.ui[DUK_DBL_IDX_UI0] == 0 || du2.ui[DUK_DBL_IDX_UI0] == 0x80000000UL); - - /* XXX: what's the safest way of creating a negative zero? */ - if ((du1.ui[DUK_DBL_IDX_UI0] | du2.ui[DUK_DBL_IDX_UI0]) != 0) { - /* Enter here if either x or y (or both) is -0. */ - return -0.0; - } else { - return +0.0; - } - } - return duk_double_fmin(x, y); -} - -DUK_LOCAL double duk__fmax_fixed(double x, double y) { - /* fmax() with args -0 and +0 is not guaranteed to return - * +0 as Ecmascript requires. - */ - if (x == 0 && y == 0) { - if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) { - return +0.0; - } else { - return -0.0; - } - } - return duk_double_fmax(x, y); -} - -#if defined(DUK_USE_ES6) -DUK_LOCAL double duk__cbrt(double x) { - /* cbrt() is C99. To avoid hassling embedders with the need to provide a - * cube root function, we can get by with pow(). The result is not - * identical, but that's OK: ES2015 says it's implementation-dependent. - */ - -#if defined(DUK_CBRT) - /* cbrt() matches ES2015 requirements. */ - return DUK_CBRT(x); -#else - duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); - - /* pow() does not, however. */ - if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) { - return x; - } - if (DUK_SIGNBIT(x)) { - return -DUK_POW(-x, 1.0 / 3.0); - } else { - return DUK_POW(x, 1.0 / 3.0); - } -#endif -} - -DUK_LOCAL double duk__log2(double x) { -#if defined(DUK_LOG2) - return DUK_LOG2(x); -#else - return DUK_LOG(x) * DUK_DOUBLE_LOG2E; -#endif -} - -DUK_LOCAL double duk__log10(double x) { -#if defined(DUK_LOG10) - return DUK_LOG10(x); -#else - return DUK_LOG(x) * DUK_DOUBLE_LOG10E; -#endif -} - -DUK_LOCAL double duk__trunc(double x) { -#if defined(DUK_TRUNC) - return DUK_TRUNC(x); -#else - /* Handles -0 correctly: -0.0 matches 'x >= 0.0' but floor() - * is required to return -0 when the argument is -0. - */ - return x >= 0.0 ? DUK_FLOOR(x) : DUK_CEIL(x); -#endif -} -#endif /* DUK_USE_ES6 */ - -DUK_LOCAL double duk__round_fixed(double x) { - /* Numbers half-way between integers must be rounded towards +Infinity, - * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero - * sign must be set appropriately. E5.1 Section 15.8.2.15. - * - * Note that ANSI C round() is "round to nearest integer, away from zero", - * which is incorrect for negative values. Here we make do with floor(). - */ - - duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); - if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) { - return x; - } - - /* - * x is finite and non-zero - * - * -1.6 -> floor(-1.1) -> -2 - * -1.5 -> floor(-1.0) -> -1 (towards +Inf) - * -1.4 -> floor(-0.9) -> -1 - * -0.5 -> -0.0 (special case) - * -0.1 -> -0.0 (special case) - * +0.1 -> +0.0 (special case) - * +0.5 -> floor(+1.0) -> 1 (towards +Inf) - * +1.4 -> floor(+1.9) -> 1 - * +1.5 -> floor(+2.0) -> 2 (towards +Inf) - * +1.6 -> floor(+2.1) -> 2 - */ - - if (x >= -0.5 && x < 0.5) { - /* +0.5 is handled by floor, this is on purpose */ - if (x < 0.0) { - return -0.0; - } else { - return +0.0; - } - } - - return DUK_FLOOR(x + 0.5); -} - -/* Wrappers for calling standard math library methods. These may be required - * on platforms where one or more of the math built-ins are defined as macros - * or inline functions and are thus not suitable to be used as function pointers. - */ -#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) -DUK_LOCAL double duk__fabs(double x) { - return DUK_FABS(x); -} -DUK_LOCAL double duk__acos(double x) { - return DUK_ACOS(x); -} -DUK_LOCAL double duk__asin(double x) { - return DUK_ASIN(x); -} -DUK_LOCAL double duk__atan(double x) { - return DUK_ATAN(x); -} -DUK_LOCAL double duk__ceil(double x) { - return DUK_CEIL(x); -} -DUK_LOCAL double duk__cos(double x) { - return DUK_COS(x); -} -DUK_LOCAL double duk__exp(double x) { - return DUK_EXP(x); -} -DUK_LOCAL double duk__floor(double x) { - return DUK_FLOOR(x); -} -DUK_LOCAL double duk__log(double x) { - return DUK_LOG(x); -} -DUK_LOCAL double duk__sin(double x) { - return DUK_SIN(x); -} -DUK_LOCAL double duk__sqrt(double x) { - return DUK_SQRT(x); -} -DUK_LOCAL double duk__tan(double x) { - return DUK_TAN(x); -} -DUK_LOCAL double duk__atan2_fixed(double x, double y) { -#if defined(DUK_USE_ATAN2_WORKAROUNDS) - /* Specific fixes to common atan2() implementation issues: - * - test-bug-mingw-math-issues.js - */ - if (DUK_ISINF(x) && DUK_ISINF(y)) { - if (DUK_SIGNBIT(x)) { - if (DUK_SIGNBIT(y)) { - return -2.356194490192345; - } else { - return -0.7853981633974483; - } - } else { - if (DUK_SIGNBIT(y)) { - return 2.356194490192345; - } else { - return 0.7853981633974483; - } - } - } -#else - /* Some ISO C assumptions. */ - DUK_ASSERT(DUK_ATAN2(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY) == 0.7853981633974483); - DUK_ASSERT(DUK_ATAN2(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY) == -0.7853981633974483); - DUK_ASSERT(DUK_ATAN2(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY) == 2.356194490192345); - DUK_ASSERT(DUK_ATAN2(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY) == -2.356194490192345); -#endif - - return DUK_ATAN2(x, y); -} -#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */ - -/* order must match constants in genbuiltins.py */ -DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = { -#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) - duk__fabs, - duk__acos, - duk__asin, - duk__atan, - duk__ceil, - duk__cos, - duk__exp, - duk__floor, - duk__log, - duk__round_fixed, - duk__sin, - duk__sqrt, - duk__tan, -#if defined(DUK_USE_ES6) - duk__cbrt, - duk__log2, - duk__log10, - duk__trunc -#endif -#else /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */ - DUK_FABS, - DUK_ACOS, - DUK_ASIN, - DUK_ATAN, - DUK_CEIL, - DUK_COS, - DUK_EXP, - DUK_FLOOR, - DUK_LOG, - duk__round_fixed, - DUK_SIN, - DUK_SQRT, - DUK_TAN, -#if defined(DUK_USE_ES6) - duk__cbrt, - duk__log2, - duk__log10, - duk__trunc -#endif -#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */ -}; - -/* order must match constants in genbuiltins.py */ -DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = { -#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) - duk__atan2_fixed, - duk_js_arith_pow -#else - duk__atan2_fixed, - duk_js_arith_pow -#endif -}; - -DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_hthread *thr) { - duk_small_int_t fun_idx = duk_get_current_magic(thr); - duk__one_arg_func fun; - duk_double_t arg1; - - DUK_ASSERT(fun_idx >= 0); - DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func))); - arg1 = duk_to_number(thr, 0); - fun = duk__one_arg_funcs[fun_idx]; - duk_push_number(thr, (duk_double_t) fun((double) arg1)); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_hthread *thr) { - duk_small_int_t fun_idx = duk_get_current_magic(thr); - duk__two_arg_func fun; - duk_double_t arg1; - duk_double_t arg2; - - DUK_ASSERT(fun_idx >= 0); - DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func))); - arg1 = duk_to_number(thr, 0); /* explicit ordered evaluation to match coercion semantics */ - arg2 = duk_to_number(thr, 1); - fun = duk__two_arg_funcs[fun_idx]; - duk_push_number(thr, (duk_double_t) fun((double) arg1, (double) arg2)); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_hthread *thr) { - return duk__math_minmax(thr, -DUK_DOUBLE_INFINITY, duk__fmax_fixed); -} - -DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_hthread *thr) { - return duk__math_minmax(thr, DUK_DOUBLE_INFINITY, duk__fmin_fixed); -} - -DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_hthread *thr) { - duk_push_number(thr, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr)); - return 1; -} - -#if defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_hthread *thr) { - /* - * E6 Section 20.2.2.18: Math.hypot - * - * - If no arguments are passed, the result is +0. - * - If any argument is +inf, the result is +inf. - * - If any argument is -inf, the result is +inf. - * - If no argument is +inf or -inf, and any argument is NaN, the result is - * NaN. - * - If all arguments are either +0 or -0, the result is +0. - */ - - duk_idx_t nargs; - duk_idx_t i; - duk_bool_t found_nan; - duk_double_t max; - duk_double_t sum, summand; - duk_double_t comp, prelim; - duk_double_t t; - - nargs = duk_get_top(thr); - - /* Find the highest value. Also ToNumber() coerces. */ - max = 0.0; - found_nan = 0; - for (i = 0; i < nargs; i++) { - t = DUK_FABS(duk_to_number(thr, i)); - if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) { - found_nan = 1; - } else { - max = duk_double_fmax(max, t); - } - } - - /* Early return cases. */ - if (max == DUK_DOUBLE_INFINITY) { - duk_push_number(thr, DUK_DOUBLE_INFINITY); - return 1; - } else if (found_nan) { - duk_push_number(thr, DUK_DOUBLE_NAN); - return 1; - } else if (max == 0.0) { - duk_push_number(thr, 0.0); - /* Otherwise we'd divide by zero. */ - return 1; - } - - /* Use Kahan summation and normalize to the highest value to minimize - * floating point rounding error and avoid overflow. - * - * https://en.wikipedia.org/wiki/Kahan_summation_algorithm - */ - sum = 0.0; - comp = 0.0; - for (i = 0; i < nargs; i++) { - t = DUK_FABS(duk_get_number(thr, i)) / max; - summand = (t * t) - comp; - prelim = sum + summand; - comp = (prelim - sum) - summand; - sum = prelim; - } - - duk_push_number(thr, (duk_double_t) DUK_SQRT(sum) * max); - return 1; -} -#endif /* DUK_USE_ES6 */ - -#if defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_math_object_sign(duk_hthread *thr) { - duk_double_t d; - - d = duk_to_number(thr, 0); - if (duk_double_is_nan(d)) { - DUK_ASSERT(duk_is_nan(thr, -1)); - return 1; /* NaN input -> return NaN */ - } - if (d == 0.0) { - /* Zero sign kept, i.e. -0 -> -0, +0 -> +0. */ - return 1; - } - duk_push_int(thr, (d > 0.0 ? 1 : -1)); - return 1; -} -#endif /* DUK_USE_ES6 */ - -#if defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_math_object_clz32(duk_hthread *thr) { - duk_uint32_t x; - duk_small_uint_t i; - -#if defined(DUK_USE_PREFER_SIZE) - duk_uint32_t mask; - - x = duk_to_uint32(thr, 0); - for (i = 0, mask = 0x80000000UL; mask != 0; mask >>= 1) { - if (x & mask) { - break; - } - i++; - } - DUK_ASSERT(i <= 32); - duk_push_uint(thr, i); - return 1; -#else /* DUK_USE_PREFER_SIZE */ - i = 0; - x = duk_to_uint32(thr, 0); - if (x & 0xffff0000UL) { - x >>= 16; - } else { - i += 16; - } - if (x & 0x0000ff00UL) { - x >>= 8; - } else { - i += 8; - } - if (x & 0x000000f0UL) { - x >>= 4; - } else { - i += 4; - } - if (x & 0x0000000cUL) { - x >>= 2; - } else { - i += 2; - } - if (x & 0x00000002UL) { - x >>= 1; - } else { - i += 1; - } - if (x & 0x00000001UL) { - ; - } else { - i += 1; - } - DUK_ASSERT(i <= 32); - duk_push_uint(thr, i); - return 1; -#endif /* DUK_USE_PREFER_SIZE */ -} -#endif /* DUK_USE_ES6 */ - -#if defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_math_object_imul(duk_hthread *thr) { - duk_uint32_t x, y, z; - - x = duk_to_uint32(thr, 0); - y = duk_to_uint32(thr, 1); - z = x * y; - - /* While arguments are ToUint32() coerced and the multiplication - * is unsigned as such, the final result is curiously interpreted - * as a signed 32-bit value. - */ - duk_push_i32(thr, (duk_int32_t) z); - return 1; -} -#endif /* DUK_USE_ES6 */ - -#endif /* DUK_USE_MATH_BUILTIN */ -#line 1 "duk_bi_number.c" -/* - * Number built-ins - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_NUMBER_BUILTIN) - -DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) { - duk_hobject *h; - - /* Number built-in accepts a plain number or a Number object (whose - * internal value is operated on). Other types cause TypeError. - */ - - duk_push_this(thr); - if (duk_is_number(thr, -1)) { - DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(thr, -1))); - goto done; - } - h = duk_get_hobject(thr, -1); - if (!h || - (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) { - DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(thr, -1))); - DUK_ERROR_TYPE(thr, "number expected"); - } - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); - DUK_ASSERT(duk_is_number(thr, -1)); - DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T", - (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1))); - duk_remove_m2(thr); - - done: - return duk_get_number(thr, -1); -} - -DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_hthread *thr) { - duk_idx_t nargs; - duk_hobject *h_this; - - /* - * The Number constructor uses ToNumber(arg) for number coercion - * (coercing an undefined argument to NaN). However, if the - * argument is not given at all, +0 must be used instead. To do - * this, a vararg function is used. - */ - - nargs = duk_get_top(thr); - if (nargs == 0) { - duk_push_int(thr, 0); - } - duk_to_number(thr, 0); - duk_set_top(thr, 1); - DUK_ASSERT_TOP(thr, 1); - - if (!duk_is_constructor_call(thr)) { - return 1; - } - - /* - * E5 Section 15.7.2.1 requires that the constructed object - * must have the original Number.prototype as its internal - * prototype. However, since Number.prototype is non-writable - * and non-configurable, this doesn't have to be enforced here: - * The default object (bound to 'this') is OK, though we have - * to change its class. - * - * Internal value set to ToNumber(arg) or +0; if no arg given, - * ToNumber(undefined) = NaN, so special treatment is needed - * (above). String internal value is immutable. - */ - - /* XXX: helper */ - duk_push_this(thr); - h_this = duk_known_hobject(thr, -1); - DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER); - - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]); - DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER); - DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this)); - - duk_dup_0(thr); /* -> [ val obj val ] */ - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); - return 0; /* no return value -> don't replace created value */ -} - -DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_hthread *thr) { - (void) duk__push_this_number_plain(thr); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_hthread *thr) { - duk_small_int_t radix; - duk_small_uint_t n2s_flags; - - (void) duk__push_this_number_plain(thr); - if (duk_is_undefined(thr, 0)) { - radix = 10; - } else { - radix = (duk_small_int_t) duk_to_int_check_range(thr, 0, 2, 36); - } - DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix)); - - n2s_flags = 0; - - duk_numconv_stringify(thr, - radix /*radix*/, - 0 /*digits*/, - n2s_flags /*flags*/); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_hthread *thr) { - /* XXX: just use toString() for now; permitted although not recommended. - * nargs==1, so radix is passed to toString(). - */ - return duk_bi_number_prototype_to_string(thr); -} - -/* - * toFixed(), toExponential(), toPrecision() - */ - -/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */ - -DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) { - duk_small_int_t frac_digits; - duk_double_t d; - duk_small_int_t c; - duk_small_uint_t n2s_flags; - - frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20); - d = duk__push_this_number_plain(thr); - - c = (duk_small_int_t) DUK_FPCLASSIFY(d); - if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { - goto use_to_string; - } - - if (d >= 1.0e21 || d <= -1.0e21) { - goto use_to_string; - } - - n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT | - DUK_N2S_FLAG_FRACTION_DIGITS; - - duk_numconv_stringify(thr, - 10 /*radix*/, - frac_digits /*digits*/, - n2s_flags /*flags*/); - return 1; - - use_to_string: - DUK_ASSERT_TOP(thr, 2); - duk_to_string(thr, -1); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_hthread *thr) { - duk_bool_t frac_undefined; - duk_small_int_t frac_digits; - duk_double_t d; - duk_small_int_t c; - duk_small_uint_t n2s_flags; - - d = duk__push_this_number_plain(thr); - - frac_undefined = duk_is_undefined(thr, 0); - duk_to_int(thr, 0); /* for side effects */ - - c = (duk_small_int_t) DUK_FPCLASSIFY(d); - if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { - goto use_to_string; - } - - frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20); - - n2s_flags = DUK_N2S_FLAG_FORCE_EXP | - (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT); - - duk_numconv_stringify(thr, - 10 /*radix*/, - frac_digits + 1 /*leading digit + fractions*/, - n2s_flags /*flags*/); - return 1; - - use_to_string: - DUK_ASSERT_TOP(thr, 2); - duk_to_string(thr, -1); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) { - /* The specification has quite awkward order of coercion and - * checks for toPrecision(). The operations below are a bit - * reordered, within constraints of observable side effects. - */ - - duk_double_t d; - duk_small_int_t prec; - duk_small_int_t c; - duk_small_uint_t n2s_flags; - - DUK_ASSERT_TOP(thr, 1); - - d = duk__push_this_number_plain(thr); - if (duk_is_undefined(thr, 0)) { - goto use_to_string; - } - DUK_ASSERT_TOP(thr, 2); - - duk_to_int(thr, 0); /* for side effects */ - - c = (duk_small_int_t) DUK_FPCLASSIFY(d); - if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { - goto use_to_string; - } - - prec = (duk_small_int_t) duk_to_int_check_range(thr, 0, 1, 21); - - n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT | - DUK_N2S_FLAG_NO_ZERO_PAD; - - duk_numconv_stringify(thr, - 10 /*radix*/, - prec /*digits*/, - n2s_flags /*flags*/); - return 1; - - use_to_string: - /* Used when precision is undefined; also used for NaN (-> "NaN"), - * and +/- infinity (-> "Infinity", "-Infinity"). - */ - - DUK_ASSERT_TOP(thr, 2); - duk_to_string(thr, -1); - return 1; -} - -#endif /* DUK_USE_NUMBER_BUILTIN */ -#line 1 "duk_bi_object.c" -/* - * Object built-ins - */ - -/* #include duk_internal.h -> already included */ - -/* Needed even when Object built-in disabled. */ -DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) { - duk_tval *tv; - tv = DUK_HTHREAD_THIS_PTR(thr); - /* XXX: This is not entirely correct anymore; in ES2015 the - * default lookup should use @@toStringTag to come up with - * e.g. [object Symbol]. - */ - duk_push_class_string_tval(thr, tv); - return 1; -} - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_hthread *thr) { - duk_uint_t arg_mask; - - arg_mask = duk_get_type_mask(thr, 0); - - if (!duk_is_constructor_call(thr) && /* not a constructor call */ - ((arg_mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) == 0)) { /* and argument not null or undefined */ - duk_to_object(thr, 0); - return 1; - } - - /* Pointer and buffer primitive values are treated like other - * primitives values which have a fully fledged object counterpart: - * promote to an object value. Lightfuncs and plain buffers are - * coerced with ToObject() even they could also be returned as is. - */ - if (arg_mask & (DUK_TYPE_MASK_OBJECT | - DUK_TYPE_MASK_STRING | - DUK_TYPE_MASK_BOOLEAN | - DUK_TYPE_MASK_NUMBER | - DUK_TYPE_MASK_POINTER | - DUK_TYPE_MASK_BUFFER | - DUK_TYPE_MASK_LIGHTFUNC)) { - /* For DUK_TYPE_OBJECT the coercion is a no-op and could - * be checked for explicitly, but Object(obj) calls are - * not very common so opt for minimal footprint. - */ - duk_to_object(thr, 0); - return 1; - } - - (void) duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), - DUK_BIDX_OBJECT_PROTOTYPE); - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_hthread *thr) { - duk_idx_t nargs; - duk_int_t idx; - - nargs = duk_get_top_require_min(thr, 1 /*min_top*/); - - duk_to_object(thr, 0); - for (idx = 1; idx < nargs; idx++) { - /* E7 19.1.2.1 (step 4a) */ - if (duk_is_null_or_undefined(thr, idx)) { - continue; - } - - /* duk_enum() respects ES2015+ [[OwnPropertyKeys]] ordering, which is - * convenient here. - */ - duk_to_object(thr, idx); - duk_enum(thr, idx, DUK_ENUM_OWN_PROPERTIES_ONLY); - while (duk_next(thr, -1, 1 /*get_value*/)) { - /* [ target ... enum key value ] */ - duk_put_prop(thr, 0); - /* [ target ... enum ] */ - } - /* Could pop enumerator, but unnecessary because of duk_set_top() - * below. - */ - } - - duk_set_top(thr, 1); - return 1; -} -#endif - -#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_hthread *thr) { - DUK_ASSERT_TOP(thr, 2); - duk_push_boolean(thr, duk_samevalue(thr, 0, 1)); - return 1; -} -#endif - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_hthread *thr) { - duk_hobject *proto; - - DUK_ASSERT_TOP(thr, 2); - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - duk_hbufobj_promote_plain(thr, 0); -#endif - proto = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_NULL); - DUK_ASSERT(proto != NULL || duk_is_null(thr, 0)); - - (void) duk_push_object_helper_proto(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), - proto); - - if (!duk_is_undefined(thr, 1)) { - /* [ O Properties obj ] */ - - duk_replace(thr, 0); - - /* [ obj Properties ] */ - - /* Just call the "original" Object.defineProperties() to - * finish up. - */ - - return duk_bi_object_constructor_define_properties(thr); - } - - /* [ O Properties obj ] */ - - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_hthread *thr) { - duk_small_uint_t pass; - duk_uint_t defprop_flags; - duk_hobject *obj; - duk_idx_t idx_value; - duk_hobject *get; - duk_hobject *set; - - /* Lightfunc and plain buffer handling by ToObject() coercion. */ - obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - DUK_ASSERT(obj != NULL); - - duk_to_object(thr, 1); /* properties object */ - - DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT", - (duk_tval *) duk_get_tval(thr, 0), - (duk_tval *) duk_get_tval(thr, 1))); - - /* - * Two pass approach to processing the property descriptors. - * On first pass validate and normalize all descriptors before - * any changes are made to the target object. On second pass - * make the actual modifications to the target object. - * - * Right now we'll just use the same normalize/validate helper - * on both passes, ignoring its outputs on the first pass. - */ - - for (pass = 0; pass < 2; pass++) { - duk_set_top(thr, 2); /* -> [ hobject props ] */ - duk_enum(thr, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/); - - for (;;) { - duk_hstring *key; - - /* [ hobject props enum(props) ] */ - - duk_set_top(thr, 3); - - if (!duk_next(thr, 2, 1 /*get_value*/)) { - break; - } - - DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - - /* [ hobject props enum(props) key desc ] */ - - duk_hobject_prepare_property_descriptor(thr, - 4 /*idx_desc*/, - &defprop_flags, - &idx_value, - &get, - &set); - - /* [ hobject props enum(props) key desc [multiple values] ] */ - - if (pass == 0) { - continue; - } - - /* This allows symbols on purpose. */ - key = duk_known_hstring(thr, 3); - DUK_ASSERT(key != NULL); - - duk_hobject_define_property_helper(thr, - defprop_flags, - obj, - key, - idx_value, - get, - set, - 1 /*throw_flag*/); - } - } - - /* - * Return target object - */ - - duk_dup_0(thr); - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_hthread *thr) { - DUK_ASSERT_TOP(thr, 1); - - duk_seal_freeze_raw(thr, 0, (duk_bool_t) duk_get_current_magic(thr) /*is_freeze*/); - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_hthread *thr) { - duk_hobject *h; - duk_bool_t is_frozen; - duk_uint_t mask; - - is_frozen = (duk_bool_t) duk_get_current_magic(thr); - mask = duk_get_type_mask(thr, 0); - if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) { - DUK_ASSERT(is_frozen == 0 || is_frozen == 1); - duk_push_boolean(thr, (mask & DUK_TYPE_MASK_LIGHTFUNC) ? - 1 : /* lightfunc always frozen and sealed */ - (is_frozen ^ 1)); /* buffer sealed but not frozen (index props writable) */ - } else { - /* ES2015 Sections 19.1.2.12, 19.1.2.13: anything other than an object - * is considered to be already sealed and frozen. - */ - h = duk_get_hobject(thr, 0); - duk_push_boolean(thr, (h == NULL) || - duk_hobject_object_is_sealed_frozen_helper(thr, h, is_frozen /*is_frozen*/)); - } - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) { - DUK_ASSERT_TOP(thr, 0); - (void) duk_push_this_coercible_to_object(thr); - duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING); -#if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */ - duk_require_callable(thr, 1); -#endif - duk_dup_0(thr); /* -> [ O toString O ] */ - duk_call_method(thr, 0); /* XXX: call method tail call? */ - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_hthread *thr) { - /* For lightfuncs and plain buffers, returns Object() coerced. */ - (void) duk_push_this_coercible_to_object(thr); - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_hthread *thr) { - duk_hobject *h_v; - duk_hobject *h_obj; - - DUK_ASSERT_TOP(thr, 1); - - h_v = duk_get_hobject(thr, 0); - if (!h_v) { - duk_push_false(thr); /* XXX: tail call: return duk_push_false(thr) */ - return 1; - } - - h_obj = duk_push_this_coercible_to_object(thr); - DUK_ASSERT(h_obj != NULL); - - /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare. - * Prototype loops should cause an error to be thrown. - */ - duk_push_boolean(thr, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/)); - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_hthread *thr) { - return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, 0 /*required_desc_flags*/); -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_hthread *thr) { - return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/); -} -#endif /* DUK_USE_OBJECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) -/* Shared helper to implement Object.getPrototypeOf, - * Object.prototype.__proto__ getter, and Reflect.getPrototypeOf. - * - * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__ - */ -DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_hthread *thr) { - /* - * magic = 0: __proto__ getter - * magic = 1: Object.getPrototypeOf() - * magic = 2: Reflect.getPrototypeOf() - */ - - duk_hobject *h; - duk_hobject *proto; - duk_tval *tv; - duk_int_t magic; - - magic = duk_get_current_magic(thr); - - if (magic == 0) { - DUK_ASSERT_TOP(thr, 0); - duk_push_this_coercible_to_object(thr); - } - DUK_ASSERT(duk_get_top(thr) >= 1); - if (magic < 2) { - /* ES2015 Section 19.1.2.9, step 1 */ - duk_to_object(thr, 0); - } - tv = DUK_GET_TVAL_POSIDX(thr, 0); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_BUFFER: - proto = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; - break; - case DUK_TAG_LIGHTFUNC: - proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]; - break; - case DUK_TAG_OBJECT: - h = DUK_TVAL_GET_OBJECT(tv); - proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - break; - default: - /* This implicitly handles CheckObjectCoercible() caused - * TypeError. - */ - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - if (proto != NULL) { - duk_push_hobject(thr, proto); - } else { - duk_push_null(thr); - } - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) -/* Shared helper to implement ES2015 Object.setPrototypeOf, - * Object.prototype.__proto__ setter, and Reflect.setPrototypeOf. - * - * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__ - * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof - */ -DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) { - /* - * magic = 0: __proto__ setter - * magic = 1: Object.setPrototypeOf() - * magic = 2: Reflect.setPrototypeOf() - */ - - duk_hobject *h_obj; - duk_hobject *h_new_proto; - duk_hobject *h_curr; - duk_ret_t ret_success = 1; /* retval for success path */ - duk_uint_t mask; - duk_int_t magic; - - /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */ - magic = duk_get_current_magic(thr); - if (magic == 0) { - duk_push_this_check_object_coercible(thr); - duk_insert(thr, 0); - if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) { - return 0; - } - - /* __proto__ setter returns 'undefined' on success unlike the - * setPrototypeOf() call which returns the target object. - */ - ret_success = 0; - } else { - if (magic == 1) { - duk_require_object_coercible(thr, 0); - } else { - duk_require_hobject_accept_mask(thr, 0, - DUK_TYPE_MASK_LIGHTFUNC | - DUK_TYPE_MASK_BUFFER); - } - duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT); - } - - h_new_proto = duk_get_hobject(thr, 1); - /* h_new_proto may be NULL */ - - mask = duk_get_type_mask(thr, 0); - if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) { - duk_hobject *curr_proto; - curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ? - DUK_BIDX_FUNCTION_PROTOTYPE : - DUK_BIDX_UINT8ARRAY_PROTOTYPE]; - if (h_new_proto == curr_proto) { - goto skip; - } - goto fail_nonextensible; - } - h_obj = duk_get_hobject(thr, 0); - if (h_obj == NULL) { - goto skip; - } - DUK_ASSERT(h_obj != NULL); - - /* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */ - /* TODO: implement Proxy object support here */ - - if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) { - goto skip; - } - if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) { - goto fail_nonextensible; - } - for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) { - /* Loop prevention. */ - if (h_curr == h_obj) { - goto fail_loop; - } - } - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto); - /* fall thru */ - - skip: - duk_set_top(thr, 1); - if (magic == 2) { - duk_push_true(thr); - } - return ret_success; - - fail_nonextensible: - fail_loop: - if (magic != 2) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } else { - duk_push_false(thr); - return 1; - } -} -#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *thr) { - /* - * magic = 0: Object.defineProperty() - * magic = 1: Reflect.defineProperty() - */ - - duk_hobject *obj; - duk_hstring *key; - duk_hobject *get; - duk_hobject *set; - duk_idx_t idx_value; - duk_uint_t defprop_flags; - duk_small_uint_t magic; - duk_bool_t throw_flag; - duk_bool_t ret; - - DUK_ASSERT(thr != NULL); - - DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T", - (void *) thr, - (duk_tval *) duk_get_tval(thr, 0), - (duk_tval *) duk_get_tval(thr, 1), - (duk_tval *) duk_get_tval(thr, 2))); - - /* [ obj key desc ] */ - - magic = (duk_small_uint_t) duk_get_current_magic(thr); - - /* Lightfuncs are currently supported by coercing to a temporary - * Function object; changes will be allowed (the coerced value is - * extensible) but will be lost. Same for plain buffers. - */ - obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - DUK_ASSERT(obj != NULL); - key = duk_to_property_key_hstring(thr, 1); - (void) duk_require_hobject(thr, 2); - - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_ASSERT(duk_get_hobject(thr, 2) != NULL); - - /* - * Validate and convert argument property descriptor (an Ecmascript - * object) into a set of defprop_flags and possibly property value, - * getter, and/or setter values on the value stack. - * - * Lightfunc set/get values are coerced to full Functions. - */ - - duk_hobject_prepare_property_descriptor(thr, - 2 /*idx_desc*/, - &defprop_flags, - &idx_value, - &get, - &set); - - /* - * Use Object.defineProperty() helper for the actual operation. - */ - - DUK_ASSERT(magic == 0U || magic == 1U); - throw_flag = magic ^ 1U; - ret = duk_hobject_define_property_helper(thr, - defprop_flags, - obj, - key, - idx_value, - get, - set, - throw_flag); - - /* Ignore the normalize/validate helper outputs on the value stack, - * they're popped automatically. - */ - - if (magic == 0U) { - /* Object.defineProperty(): return target object. */ - duk_push_hobject(thr, obj); - } else { - /* Reflect.defineProperty(): return success/fail. */ - duk_push_boolean(thr, ret); - } - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_hthread *thr) { - DUK_ASSERT_TOP(thr, 2); - - /* ES2015 Section 19.1.2.6, step 1 */ - if (duk_get_current_magic(thr) == 0) { - duk_to_object(thr, 0); - } - - /* [ obj key ] */ - - duk_hobject_object_get_own_property_descriptor(thr, -2); - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_hthread *thr) { - /* - * magic = 0: Object.isExtensible() - * magic = 1: Reflect.isExtensible() - */ - - duk_hobject *h; - - if (duk_get_current_magic(thr) == 0) { - h = duk_get_hobject(thr, 0); - } else { - /* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs - * and plain buffers here because they pretend to be objects. - */ - h = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - } - - duk_push_boolean(thr, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h)); - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) -/* Shared helper for various key/symbol listings, magic: - * 0=Object.keys() - * 1=Object.getOwnPropertyNames(), - * 2=Object.getOwnPropertySymbols(), - * 3=Reflect.ownKeys() - */ -DUK_LOCAL const duk_small_uint_t duk__object_keys_enum_flags[4] = { - /* Object.keys() */ - DUK_ENUM_OWN_PROPERTIES_ONLY | - DUK_ENUM_NO_PROXY_BEHAVIOR, - - /* Object.getOwnPropertyNames() */ - DUK_ENUM_INCLUDE_NONENUMERABLE | - DUK_ENUM_OWN_PROPERTIES_ONLY | - DUK_ENUM_NO_PROXY_BEHAVIOR, - - /* Object.getOwnPropertySymbols() */ - DUK_ENUM_INCLUDE_SYMBOLS | - DUK_ENUM_OWN_PROPERTIES_ONLY | - DUK_ENUM_EXCLUDE_STRINGS | - DUK_ENUM_INCLUDE_NONENUMERABLE | - DUK_ENUM_NO_PROXY_BEHAVIOR, - - /* Reflect.ownKeys() */ - DUK_ENUM_INCLUDE_SYMBOLS | - DUK_ENUM_OWN_PROPERTIES_ONLY | - DUK_ENUM_INCLUDE_NONENUMERABLE | - DUK_ENUM_NO_PROXY_BEHAVIOR -}; - -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) { - duk_hobject *obj; -#if defined(DUK_USE_ES6_PROXY) - duk_hobject *h_proxy_target; - duk_hobject *h_proxy_handler; - duk_hobject *h_trap_result; -#endif - duk_small_uint_t enum_flags; - duk_int_t magic; - - DUK_ASSERT_TOP(thr, 1); - - magic = duk_get_current_magic(thr); - if (magic == 3) { - /* ES2015 Section 26.1.11 requires a TypeError for non-objects. Lightfuncs - * and plain buffers pretend to be objects, so accept those too. - */ - obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - } else { - /* ES2015: ToObject coerce. */ - obj = duk_to_hobject(thr, 0); - } - DUK_ASSERT(obj != NULL); - DUK_UNREF(obj); - - /* XXX: proxy chains */ - -#if defined(DUK_USE_ES6_PROXY) - /* XXX: better sharing of code between proxy target call sites */ - if (DUK_LIKELY(!duk_hobject_proxy_check(obj, - &h_proxy_target, - &h_proxy_handler))) { - goto skip_proxy; - } - - duk_push_hobject(thr, h_proxy_handler); - if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) { - /* Careful with reachability here: don't pop 'obj' before pushing - * proxy target. - */ - DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead")); - duk_pop_2(thr); - duk_push_hobject(thr, h_proxy_target); - duk_replace(thr, 0); - DUK_ASSERT_TOP(thr, 1); - goto skip_proxy; - } - - /* [ obj handler trap ] */ - duk_insert(thr, -2); - duk_push_hobject(thr, h_proxy_target); /* -> [ obj trap handler target ] */ - duk_call_method(thr, 1 /*nargs*/); /* -> [ obj trap_result ] */ - h_trap_result = duk_require_hobject(thr, -1); - DUK_UNREF(h_trap_result); - - magic = duk_get_current_magic(thr); - DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t))); - enum_flags = duk__object_keys_enum_flags[magic]; - - duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags); - return 1; - - skip_proxy: -#endif /* DUK_USE_ES6_PROXY */ - - DUK_ASSERT_TOP(thr, 1); - magic = duk_get_current_magic(thr); - DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t))); - enum_flags = duk__object_keys_enum_flags[magic]; - return duk_hobject_get_enumerated_keys(thr, enum_flags); -} -#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ - -#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_hthread *thr) { - /* - * magic = 0: Object.preventExtensions() - * magic = 1: Reflect.preventExtensions() - */ - - duk_hobject *h; - duk_uint_t mask; - duk_int_t magic; - - magic = duk_get_current_magic(thr); - - /* Silent success for lightfuncs and plain buffers always. */ - mask = DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER; - - /* Object.preventExtensions() silent success for non-object. */ - if (magic == 0) { - mask |= DUK_TYPE_MASK_UNDEFINED | - DUK_TYPE_MASK_NULL | - DUK_TYPE_MASK_BOOLEAN | - DUK_TYPE_MASK_NUMBER | - DUK_TYPE_MASK_STRING | - DUK_TYPE_MASK_POINTER; - } - - if (duk_check_type_mask(thr, 0, mask)) { - /* Not an object, already non-extensible so always success. */ - goto done; - } - h = duk_require_hobject(thr, 0); - DUK_ASSERT(h != NULL); - - DUK_HOBJECT_CLEAR_EXTENSIBLE(h); - - /* A non-extensible object cannot gain any more properties, - * so this is a good time to compact. - */ - duk_hobject_compact_props(thr, h); - - done: - if (magic == 1) { - duk_push_true(thr); - } - return 1; -} -#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ - -/* - * __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__ - */ - -#if defined(DUK_USE_ES8) -DUK_INTERNAL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_hthread *thr) { - duk_push_this(thr); - duk_insert(thr, 0); - duk_to_object(thr, 0); - duk_require_callable(thr, 2); - - /* [ ToObject(this) key getter/setter ] */ - - /* ToPropertyKey() coercion is not needed, duk_def_prop() does it. */ - duk_def_prop(thr, 0, DUK_DEFPROP_SET_ENUMERABLE | - DUK_DEFPROP_SET_CONFIGURABLE | - (duk_get_current_magic(thr) ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER)); - return 0; -} -DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr) { - duk_uint_t sanity; - - duk_push_this(thr); - duk_to_object(thr, -1); - - /* XXX: Prototype walk (with sanity) should be a core property - * operation, could add a flag to e.g. duk_get_prop_desc(). - */ - - /* ToPropertyKey() coercion is not needed, duk_get_prop_desc() does it. */ - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - while (!duk_is_undefined(thr, -1)) { - /* [ key obj ] */ - duk_dup(thr, 0); - duk_get_prop_desc(thr, 1, 0 /*flags*/); - if (!duk_is_undefined(thr, -1)) { - duk_get_prop_stridx(thr, -1, (duk_get_current_magic(thr) != 0 ? DUK_STRIDX_SET : DUK_STRIDX_GET)); - return 1; - } - duk_pop(thr); - - if (DUK_UNLIKELY(sanity-- == 0)) { - DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); - } - - duk_get_prototype(thr, -1); - duk_remove(thr, -2); - } - return 1; -} -#endif /* DUK_USE_ES8 */ -#line 1 "duk_bi_performance.c" -/* - * High resolution time API (performance.now() et al) - * - * API specification: https://encoding.spec.whatwg.org/#ap://www.w3.org/TR/hr-time/ - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_PERFORMANCE_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_performance_now(duk_hthread *thr) { - /* From API spec: - * The DOMHighResTimeStamp type is used to store a time value in - * milliseconds, measured relative from the time origin, global - * monotonic clock, or a time value that represents a duration - * between two DOMHighResTimeStamp's. - */ - duk_push_number(thr, duk_time_get_monotonic_time(thr)); - return 1; -} - -#if 0 /* Missing until semantics decided. */ -DUK_INTERNAL duk_ret_t duk_bi_performance_timeorigin_getter(duk_hthread *thr) { - /* No decision yet how to handle timeOrigins, e.g. should one be - * initialized per heap, or per global object set. See - * https://www.w3.org/TR/hr-time/#time-origin. - */ - duk_push_uint(thr, 0); - return 1; -} -#endif /* 0 */ -#endif /* DUK_USE_PERFORMANCE_BUILTIN */ -#line 1 "duk_bi_pointer.c" -/* - * Pointer built-ins - */ - -/* #include duk_internal.h -> already included */ - -/* - * Constructor - */ - -DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_hthread *thr) { - /* XXX: this behavior is quite useless now; it would be nice to be able - * to create pointer values from e.g. numbers or strings. Numbers are - * problematic on 64-bit platforms though. Hex encoded strings? - */ - if (duk_get_top(thr) == 0) { - duk_push_pointer(thr, NULL); - } else { - duk_to_pointer(thr, 0); - } - DUK_ASSERT(duk_is_pointer(thr, 0)); - duk_set_top(thr, 1); - - if (duk_is_constructor_call(thr)) { - (void) duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER), - DUK_BIDX_POINTER_PROTOTYPE); - - /* Pointer object internal value is immutable */ - duk_dup_0(thr); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); - } - /* Note: unbalanced stack on purpose */ - - return 1; -} - -/* - * toString(), valueOf() - */ - -DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr) { - duk_tval *tv; - duk_small_int_t to_string = duk_get_current_magic(thr); - - duk_push_this(thr); - tv = duk_require_tval(thr, -1); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_POINTER(tv)) { - /* nop */ - } else if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - - /* Must be a "pointer object", i.e. class "Pointer" */ - if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) { - goto type_error; - } - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); - } else { - goto type_error; - } - - if (to_string) { - duk_to_string(thr, -1); - } - return 1; - - type_error: - DUK_DCERROR_TYPE_INVALID_ARGS(thr); -} -#line 1 "duk_bi_promise.c" -/* - * Promise built-in - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_PROMISE_BUILTIN) - -DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) { - DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) { - DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) { - DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) { - DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) { - DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) { - DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; -} - -DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) { - DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; -} - -#endif /* DUK_USE_PROMISE_BUILTIN */ -#line 1 "duk_bi_proxy.c" -/* - * Proxy built-in (ES2015) - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_ES6_PROXY) -/* Post-process a Proxy ownKeys() result at stack top. Push a cleaned up - * array of valid result keys (strings or symbols). TypeError for invalid - * values. Flags are shared with duk_enum(). - */ -DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags) { - duk_uarridx_t i, len, idx; - duk_propdesc desc; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(h_proxy_target != NULL); - - len = (duk_uarridx_t) duk_get_length(thr, -1); - idx = 0; - duk_push_array(thr); - /* XXX: preallocated dense array, fill in directly */ - for (i = 0; i < len; i++) { - duk_hstring *h; - - /* [ obj trap_result res_arr ] */ - (void) duk_get_prop_index(thr, -2, i); - h = duk_get_hstring(thr, -1); - if (h == NULL) { - DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr); - } - - if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) { - /* No support for 'getOwnPropertyDescriptor' trap yet, - * so check enumerability always from target object - * descriptor. - */ - if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) { - if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) { - DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(thr, -1))); - goto skip_key; - } - } else { - DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(thr, -1))); - goto skip_key; - } - } - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - if (!(flags & DUK_ENUM_INCLUDE_SYMBOLS)) { - DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(thr, -1))); - goto skip_key; - } - if (DUK_HSTRING_HAS_HIDDEN(h) && !(flags & DUK_ENUM_INCLUDE_HIDDEN)) { - DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(thr, -1))); - goto skip_key; - } - } else { - if (flags & DUK_ENUM_EXCLUDE_STRINGS) { - DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(thr, -1))); - goto skip_key; - } - } - - /* [ obj trap_result res_arr propname ] */ - duk_put_prop_index(thr, -2, idx++); - continue; - - skip_key: - duk_pop(thr); - continue; - } - - /* XXX: Missing trap result validation for non-configurable target keys - * (must be present), for non-extensible target all target keys must be - * present and no extra keys can be present. - * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys - */ - - /* XXX: The key enumerability check should trigger the "getOwnPropertyDescriptor" - * trap which has not yet been implemented. In the absence of such a trap, - * the enumerability should be checked from the target object; this is - * handled above. - */ -} -#endif /* DUK_USE_ES6_PROXY */ - -#if defined(DUK_USE_ES6_PROXY) -DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_hthread *thr) { - DUK_ASSERT_TOP(thr, 2); /* [ target handler ] */ - - duk_require_constructor_call(thr); - duk_push_proxy(thr, 0 /*flags*/); /* [ target handler ] -> [ proxy ] */ - return 1; /* replacement */ -} -#endif /* DUK_USE_ES6_PROXY */ -#line 1 "duk_bi_reflect.c" -/* - * 'Reflect' built-in (ES2016 Section 26.1) - * http://www.ecma-international.org/ecma-262/7.0/#sec-reflect-object - * - * Many Reflect built-in functions are provided by shared helpers in - * duk_bi_object.c or duk_bi_function.c. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_REFLECT_BUILTIN) -DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_hthread *thr) { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_bool_t ret; - - DUK_ASSERT_TOP(thr, 2); - (void) duk_require_hobject(thr, 0); - (void) duk_to_string(thr, 1); - - /* [ target key ] */ - - DUK_ASSERT(thr != NULL); - tv_obj = DUK_GET_TVAL_POSIDX(thr, 0); - tv_key = DUK_GET_TVAL_POSIDX(thr, 1); - ret = duk_hobject_delprop(thr, tv_obj, tv_key, 0 /*throw_flag*/); - duk_push_boolean(thr, ret); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_idx_t nargs; - - DUK_ASSERT(thr != NULL); - nargs = duk_get_top_require_min(thr, 2 /*min_top*/); - (void) duk_require_hobject(thr, 0); - (void) duk_to_string(thr, 1); - if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) { - /* XXX: [[Get]] receiver currently unsupported */ - DUK_ERROR_UNSUPPORTED(thr); - } - - /* [ target key receiver? ...? ] */ - - tv_obj = DUK_GET_TVAL_POSIDX(thr, 0); - tv_key = DUK_GET_TVAL_POSIDX(thr, 1); - (void) duk_hobject_getprop(thr, tv_obj, tv_key); /* This could also be a duk_get_prop(). */ - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_hthread *thr) { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_bool_t ret; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT_TOP(thr, 2); - (void) duk_require_hobject(thr, 0); - (void) duk_to_string(thr, 1); - - /* [ target key ] */ - - tv_obj = DUK_GET_TVAL_POSIDX(thr, 0); - tv_key = DUK_GET_TVAL_POSIDX(thr, 1); - ret = duk_hobject_hasprop(thr, tv_obj, tv_key); - duk_push_boolean(thr, ret); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_tval *tv_val; - duk_idx_t nargs; - duk_bool_t ret; - - DUK_ASSERT(thr != NULL); - nargs = duk_get_top_require_min(thr, 3 /*min_top*/); - (void) duk_require_hobject(thr, 0); - (void) duk_to_string(thr, 1); - if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) { - /* XXX: [[Set]] receiver currently unsupported */ - DUK_ERROR_UNSUPPORTED(thr); - } - - /* [ target key value receiver? ...? ] */ - - tv_obj = DUK_GET_TVAL_POSIDX(thr, 0); - tv_key = DUK_GET_TVAL_POSIDX(thr, 1); - tv_val = DUK_GET_TVAL_POSIDX(thr, 2); - ret = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, 0 /*throw_flag*/); - duk_push_boolean(thr, ret); - return 1; -} -#endif /* DUK_USE_REFLECT_BUILTIN */ -#line 1 "duk_bi_regexp.c" -/* - * RegExp built-ins - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_REGEXP_SUPPORT) - -DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) { - duk_hobject *h; - - duk_push_this(thr); - h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP); - DUK_ASSERT(h != NULL); - DUK_UNREF(h); - duk_insert(thr, 0); /* prepend regexp to valstack 0 index */ -} - -/* XXX: much to improve (code size) */ -DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_hthread *thr) { - duk_hobject *h_pattern; - - DUK_ASSERT_TOP(thr, 2); - h_pattern = duk_get_hobject(thr, 0); - - if (!duk_is_constructor_call(thr) && - h_pattern != NULL && - DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP && - duk_is_undefined(thr, 1)) { - /* Called as a function, pattern has [[Class]] "RegExp" and - * flags is undefined -> return object as is. - */ - /* XXX: ES2015 has a NewTarget SameValue() check which is not - * yet implemented. - */ - duk_dup_0(thr); - return 1; - } - - /* Else functionality is identical for function call and constructor - * call. - */ - - if (h_pattern != NULL && - DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) { - duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_SOURCE); - if (duk_is_undefined(thr, 1)) { - /* In ES5 one would need to read the flags individually; - * in ES2015 just read .flags. - */ - duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS); - } else { - /* In ES2015 allowed; overrides argument RegExp flags. */ - duk_dup_1(thr); - } - } else { - if (duk_is_undefined(thr, 0)) { - duk_push_hstring_empty(thr); - } else { - duk_dup_0(thr); - duk_to_string(thr, -1); /* Rejects Symbols. */ - } - if (duk_is_undefined(thr, 1)) { - duk_push_hstring_empty(thr); - } else { - duk_dup_1(thr); - duk_to_string(thr, -1); /* Rejects Symbols. */ - } - - /* [ ... pattern flags ] */ - } - - DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T", - (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1))); - - /* [ ... pattern flags ] (both uncoerced) */ - - duk_to_string(thr, -2); - duk_to_string(thr, -1); - duk_regexp_compile(thr); - - /* [ ... bytecode escaped_source ] */ - - duk_regexp_create_instance(thr); - - /* [ ... RegExp ] */ - - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_hthread *thr) { - duk__get_this_regexp(thr); - - /* [ regexp input ] */ - - duk_regexp_match(thr); - - /* [ result ] */ - - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_hthread *thr) { - duk__get_this_regexp(thr); - - /* [ regexp input ] */ - - /* result object is created and discarded; wasteful but saves code space */ - duk_regexp_match(thr); - - /* [ result ] */ - - duk_push_boolean(thr, (duk_is_null(thr, -1) ? 0 : 1)); - - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) { - /* This must be generic in ES2015 and later. */ - DUK_ASSERT_TOP(thr, 0); - duk_push_this(thr); - duk_push_string(thr, "/"); - duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE); - duk_dup_m2(thr); /* another "/" */ - duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS); - duk_concat(thr, 4); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_hthread *thr) { - /* .flags is ES2015 but present even when ES2015 bindings are - * disabled because the constructor relies on it. - */ - duk_uint8_t buf[8]; /* enough for all flags + NUL */ - duk_uint8_t *p = buf; - - /* .flags is generic and works on any object. */ - duk_push_this(thr); - (void) duk_require_hobject(thr, -1); - if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL)) { - *p++ = DUK_ASC_LC_G; - } - if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_IGNORE_CASE, NULL)) { - *p++ = DUK_ASC_LC_I; - } - if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_MULTILINE, NULL)) { - *p++ = DUK_ASC_LC_M; - } - /* .unicode: to be added */ - /* .sticky: to be added */ - *p++ = DUK_ASC_NUL; - DUK_ASSERT((duk_size_t) (p - buf) <= sizeof(buf)); - - duk_push_string(thr, (const char *) buf); - return 1; -} - -/* Shared helper for providing .source, .global, .multiline, etc getters. */ -DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) { - duk_hstring *h_bc; - duk_small_uint_t re_flags; - duk_hobject *h; - duk_int_t magic; - - DUK_ASSERT_TOP(thr, 0); - - duk_push_this(thr); - h = duk_require_hobject(thr, -1); - magic = duk_get_current_magic(thr); - - if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_REGEXP) { - duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_INT_SOURCE); - duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_INT_BYTECODE); - h_bc = duk_require_hstring(thr, -1); - re_flags = (duk_small_uint_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* Safe even if h_bc length is 0 (= NUL) */ - duk_pop(thr); - } else if (h == thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]) { - /* In ES2015 and ES2016 a TypeError would be thrown here. - * However, this had real world issues so ES2017 draft - * allows RegExp.prototype specifically, returning '(?:)' - * for .source and undefined for all flags. - */ - if (magic != 16 /* .source */) { - return 0; - } - duk_push_string(thr, "(?:)"); /* .source handled by switch-case */ - re_flags = 0; - } else { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); - } - - /* [ regexp source ] */ - - switch (magic) { - case 0: { /* global */ - duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_GLOBAL)); - break; - } - case 1: { /* ignoreCase */ - duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_IGNORE_CASE)); - break; - } - case 2: { /* multiline */ - duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_MULTILINE)); - break; - } -#if 0 - /* Don't provide until implemented to avoid interfering with feature - * detection in user code. - */ - case 3: /* sticky */ - case 4: { /* unicode */ - duk_push_false(thr); - break; - } -#endif - default: { /* source */ - /* leave 'source' on top */ - break; - } - } - - return 1; -} - -#endif /* DUK_USE_REGEXP_SUPPORT */ -#line 1 "duk_bi_string.c" -/* - * String built-ins - * - * Most String built-ins must only accept strings (or String objects). - * Symbols, represented internally as strings, must be generally rejected. - * The duk_push_this_coercible_to_string() helper does this automatically. - */ - -/* XXX: There are several limitations in the current implementation for - * strings with >= 0x80000000UL characters. In some cases one would need - * to be able to represent the range [-0xffffffff,0xffffffff] and so on. - * Generally character and byte length are assumed to fit into signed 32 - * bits (< 0x80000000UL). Places with issues are not marked explicitly - * below in all cases, look for signed type usage (duk_int_t etc) for - * offsets/lengths. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_STRING_BUILTIN) - -/* - * Helpers - */ - -DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_hthread *thr, duk_idx_t idx) { - duk_hstring *h; - - if (duk_get_class_number(thr, idx) == DUK_HOBJECT_CLASS_REGEXP) { - DUK_ERROR_TYPE_INVALID_ARGS(thr); - } - h = duk_to_hstring(thr, idx); - DUK_ASSERT(h != NULL); - - return h; -} - -DUK_LOCAL duk_int_t duk__str_search_shared(duk_hthread *thr, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) { - duk_int_t cpos; - duk_int_t bpos; - const duk_uint8_t *p_start, *p_end, *p; - const duk_uint8_t *q_start; - duk_int_t q_blen; - duk_uint8_t firstbyte; - duk_uint8_t t; - - cpos = start_cpos; - - /* Empty searchstring always matches; cpos must be clamped here. - * (If q_blen were < 0 due to clamped coercion, it would also be - * caught here.) - */ - q_start = DUK_HSTRING_GET_DATA(h_search); - q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); - if (q_blen <= 0) { - return cpos; - } - DUK_ASSERT(q_blen > 0); - - bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos); - - p_start = DUK_HSTRING_GET_DATA(h_this); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); - p = p_start + bpos; - - /* This loop is optimized for size. For speed, there should be - * two separate loops, and we should ensure that memcmp() can be - * used without an extra "will searchstring fit" check. Doing - * the preconditioning for 'p' and 'p_end' is easy but cpos - * must be updated if 'p' is wound back (backward scanning). - */ - - firstbyte = q_start[0]; /* leading byte of match string */ - while (p <= p_end && p >= p_start) { - t = *p; - - /* For Ecmascript strings, this check can only match for - * initial UTF-8 bytes (not continuation bytes). For other - * strings all bets are off. - */ - - if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { - DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { - return cpos; - } - } - - /* track cpos while scanning */ - if (backwards) { - /* when going backwards, we decrement cpos 'early'; - * 'p' may point to a continuation byte of the char - * at offset 'cpos', but that's OK because we'll - * backtrack all the way to the initial byte. - */ - if ((t & 0xc0) != 0x80) { - cpos--; - } - p--; - } else { - if ((t & 0xc0) != 0x80) { - cpos++; - } - p++; - } - } - - /* Not found. Empty string case is handled specially above. */ - return -1; -} - -/* - * Constructor - */ - -DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_hthread *thr) { - duk_hstring *h; - duk_uint_t flags; - - /* String constructor needs to distinguish between an argument not given at all - * vs. given as 'undefined'. We're a vararg function to handle this properly. - */ - - /* XXX: copy current activation flags to thr, including current magic, - * is_constructor_call etc. This takes a few bytes in duk_hthread but - * makes call sites smaller (there are >30 is_constructor_call and get - * current magic call sites. - */ - - if (duk_get_top(thr) == 0) { - duk_push_hstring_empty(thr); - } else { - h = duk_to_hstring_acceptsymbol(thr, 0); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(thr))) { - duk_push_symbol_descriptive_string(thr, h); - duk_replace(thr, 0); - } - } - duk_to_string(thr, 0); /* catches symbol argument for constructor call */ - DUK_ASSERT(duk_is_string(thr, 0)); - duk_set_top(thr, 1); /* Top may be 1 or larger. */ - - if (duk_is_constructor_call(thr)) { - /* String object internal value is immutable */ - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); - duk_push_object_helper(thr, flags, DUK_BIDX_STRING_PROTOTYPE); - duk_dup_0(thr); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); - } - /* Note: unbalanced stack on purpose */ - - return 1; -} - -DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_hthread *thr, duk_bool_t nonbmp) { - duk_bufwriter_ctx bw_alloc; - duk_bufwriter_ctx *bw; - duk_idx_t i, n; - duk_ucodepoint_t cp; - - /* XXX: It would be nice to build the string directly but ToUint16() - * coercion is needed so a generic helper would not be very - * helpful (perhaps coerce the value stack first here and then - * build a string from a duk_tval number sequence in one go?). - */ - - n = duk_get_top(thr); - - bw = &bw_alloc; - DUK_BW_INIT_PUSHBUF(thr, bw, (duk_size_t) n); /* initial estimate for ASCII only codepoints */ - - for (i = 0; i < n; i++) { - /* XXX: could improve bufwriter handling to write multiple codepoints - * with one ensure call but the relative benefit would be quite small. - */ - - if (nonbmp) { - /* ES2015 requires that (1) SameValue(cp, ToInteger(cp)) and - * (2) cp >= 0 and cp <= 0x10ffff. This check does not - * implement the steps exactly but the outcome should be - * the same. - */ - duk_int32_t i32 = 0; - if (!duk_is_whole_get_int32(duk_to_number(thr, i), &i32) || - i32 < 0 || i32 > 0x10ffffL) { - DUK_DCERROR_RANGE_INVALID_ARGS(thr); - } - DUK_ASSERT(i32 >= 0 && i32 <= 0x10ffffL); - cp = (duk_ucodepoint_t) i32; - DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp); - } else { -#if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT) - /* ToUint16() coercion is mandatory in the E5.1 specification, but - * this non-compliant behavior makes more sense because we support - * non-BMP codepoints. Don't use CESU-8 because that'd create - * surrogate pairs. - */ - cp = (duk_ucodepoint_t) duk_to_uint32(thr, i); - DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp); -#else - cp = (duk_ucodepoint_t) duk_to_uint16(thr, i); - DUK_ASSERT(cp >= 0 && cp <= 0x10ffffL); - DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp); -#endif - } - } - - DUK_BW_COMPACT(thr, bw); - (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 or CESU-8 encoded. */ - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_hthread *thr) { - return duk__construct_from_codepoints(thr, 0 /*nonbmp*/); -} - -#if defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_hthread *thr) { - return duk__construct_from_codepoints(thr, 1 /*nonbmp*/); -} -#endif - -/* - * toString(), valueOf() - */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_hthread *thr) { - duk_tval *tv; - - duk_push_this(thr); - tv = duk_require_tval(thr, -1); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_STRING(tv)) { - /* return as is */ - } else if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - - /* Must be a "string object", i.e. class "String" */ - if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) { - goto type_error; - } - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); - DUK_ASSERT(duk_is_string(thr, -1)); - } else { - goto type_error; - } - - (void) duk_require_hstring_notsymbol(thr, -1); /* Reject symbols (and wrapped symbols). */ - return 1; - - type_error: - DUK_DCERROR_TYPE_INVALID_ARGS(thr); -} - -/* - * Character and charcode access - */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_hthread *thr) { - duk_int_t pos; - - /* XXX: faster implementation */ - - (void) duk_push_this_coercible_to_string(thr); - pos = duk_to_int(thr, 0); - duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) (pos + 1)); - return 1; -} - -/* Magic: 0=charCodeAt, 1=codePointAt */ -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_hthread *thr) { - duk_int_t pos; - duk_hstring *h; - duk_bool_t clamped; - duk_uint32_t cp; - duk_int_t magic; - - /* XXX: faster implementation */ - - DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(thr, 0))); - - h = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h != NULL); - - pos = duk_to_int_clamped_raw(thr, - 0 /*index*/, - 0 /*min(incl)*/, - (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, - &clamped /*out_clamped*/); -#if defined(DUK_USE_ES6) - magic = duk_get_current_magic(thr); -#else - DUK_ASSERT(duk_get_current_magic(thr) == 0); - magic = 0; -#endif - if (clamped) { - /* For out-of-bounds indices .charCodeAt() returns NaN and - * .codePointAt() returns undefined. - */ - if (magic != 0) { - return 0; - } - duk_push_nan(thr); - } else { - DUK_ASSERT(pos >= 0); - cp = (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) pos, (duk_bool_t) magic /*surrogate_aware*/); - duk_push_u32(thr, cp); - } - return 1; -} - -/* - * substring(), substr(), slice() - */ - -/* XXX: any chance of merging these three similar but still slightly - * different algorithms so that footprint would be reduced? - */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_hthread *thr) { - duk_hstring *h; - duk_int_t start_pos, end_pos; - duk_int_t len; - - h = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h != NULL); - len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); - - /* [ start end str ] */ - - start_pos = duk_to_int_clamped(thr, 0, 0, len); - if (duk_is_undefined(thr, 1)) { - end_pos = len; - } else { - end_pos = duk_to_int_clamped(thr, 1, 0, len); - } - DUK_ASSERT(start_pos >= 0 && start_pos <= len); - DUK_ASSERT(end_pos >= 0 && end_pos <= len); - - if (start_pos > end_pos) { - duk_int_t tmp = start_pos; - start_pos = end_pos; - end_pos = tmp; - } - - DUK_ASSERT(end_pos >= start_pos); - - duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos); - return 1; -} - -#if defined(DUK_USE_SECTION_B) -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_hthread *thr) { - duk_hstring *h; - duk_int_t start_pos, end_pos; - duk_int_t len; - - /* Unlike non-obsolete String calls, substr() algorithm in E5.1 - * specification will happily coerce undefined and null to strings - * ("undefined" and "null"). - */ - duk_push_this(thr); - h = duk_to_hstring_m1(thr); /* Reject Symbols. */ - DUK_ASSERT(h != NULL); - len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); - - /* [ start length str ] */ - - /* The implementation for computing of start_pos and end_pos differs - * from the standard algorithm, but is intended to result in the exactly - * same behavior. This is not always obvious. - */ - - /* combines steps 2 and 5; -len ensures max() not needed for step 5 */ - start_pos = duk_to_int_clamped(thr, 0, -len, len); - if (start_pos < 0) { - start_pos = len + start_pos; - } - DUK_ASSERT(start_pos >= 0 && start_pos <= len); - - /* combines steps 3, 6; step 7 is not needed */ - if (duk_is_undefined(thr, 1)) { - end_pos = len; - } else { - DUK_ASSERT(start_pos <= len); - end_pos = start_pos + duk_to_int_clamped(thr, 1, 0, len - start_pos); - } - DUK_ASSERT(start_pos >= 0 && start_pos <= len); - DUK_ASSERT(end_pos >= 0 && end_pos <= len); - DUK_ASSERT(end_pos >= start_pos); - - duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos); - return 1; -} -#endif /* DUK_USE_SECTION_B */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_hthread *thr) { - duk_hstring *h; - duk_int_t start_pos, end_pos; - duk_int_t len; - - h = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h != NULL); - len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); - - /* [ start end str ] */ - - start_pos = duk_to_int_clamped(thr, 0, -len, len); - if (start_pos < 0) { - start_pos = len + start_pos; - } - if (duk_is_undefined(thr, 1)) { - end_pos = len; - } else { - end_pos = duk_to_int_clamped(thr, 1, -len, len); - if (end_pos < 0) { - end_pos = len + end_pos; - } - } - DUK_ASSERT(start_pos >= 0 && start_pos <= len); - DUK_ASSERT(end_pos >= 0 && end_pos <= len); - - if (end_pos < start_pos) { - end_pos = start_pos; - } - - DUK_ASSERT(end_pos >= start_pos); - - duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos); - return 1; -} - -/* - * Case conversion - */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_hthread *thr) { - duk_small_int_t uppercase = duk_get_current_magic(thr); - - (void) duk_push_this_coercible_to_string(thr); - duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase); - return 1; -} - -/* - * indexOf() and lastIndexOf() - */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_hthread *thr) { - duk_hstring *h_this; - duk_hstring *h_search; - duk_int_t clen_this; - duk_int_t cpos; - duk_small_uint_t is_lastindexof = (duk_small_uint_t) duk_get_current_magic(thr); /* 0=indexOf, 1=lastIndexOf */ - - h_this = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h_this != NULL); - clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this); - - h_search = duk_to_hstring(thr, 0); - DUK_ASSERT(h_search != NULL); - - duk_to_number(thr, 1); - if (duk_is_nan(thr, 1) && is_lastindexof) { - /* indexOf: NaN should cause pos to be zero. - * lastIndexOf: NaN should cause pos to be +Infinity - * (and later be clamped to len). - */ - cpos = clen_this; - } else { - cpos = duk_to_int_clamped(thr, 1, 0, clen_this); - } - - cpos = duk__str_search_shared(thr, h_this, h_search, cpos, is_lastindexof /*backwards*/); - duk_push_int(thr, cpos); - return 1; -} - -/* - * replace() - */ - -/* XXX: the current implementation works but is quite clunky; it compiles - * to almost 1,4kB of x86 code so it needs to be simplified (better approach, - * shared helpers, etc). Some ideas for refactoring: - * - * - a primitive to convert a string into a regexp matcher (reduces matching - * code at the cost of making matching much slower) - * - use replace() as a basic helper for match() and split(), which are both - * much simpler - * - API call to get_prop and to_boolean - */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_hthread *thr) { - duk_hstring *h_input; - duk_hstring *h_match; - duk_hstring *h_search; - duk_hobject *h_re; - duk_bufwriter_ctx bw_alloc; - duk_bufwriter_ctx *bw; -#if defined(DUK_USE_REGEXP_SUPPORT) - duk_bool_t is_regexp; - duk_bool_t is_global; -#endif - duk_bool_t is_repl_func; - duk_uint32_t match_start_coff, match_start_boff; -#if defined(DUK_USE_REGEXP_SUPPORT) - duk_int_t match_caps; -#endif - duk_uint32_t prev_match_end_boff; - const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */ - duk_size_t tmp_sz; - - DUK_ASSERT_TOP(thr, 2); - h_input = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h_input != NULL); - - bw = &bw_alloc; - DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */ - - DUK_ASSERT_TOP(thr, 4); - - /* stack[0] = search value - * stack[1] = replace value - * stack[2] = input string - * stack[3] = result buffer - */ - - h_re = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP); - if (h_re) { -#if defined(DUK_USE_REGEXP_SUPPORT) - is_regexp = 1; - is_global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL); - - if (is_global) { - /* start match from beginning */ - duk_push_int(thr, 0); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); - } -#else /* DUK_USE_REGEXP_SUPPORT */ - DUK_DCERROR_UNSUPPORTED(thr); -#endif /* DUK_USE_REGEXP_SUPPORT */ - } else { - duk_to_string(thr, 0); /* rejects symbols */ -#if defined(DUK_USE_REGEXP_SUPPORT) - is_regexp = 0; - is_global = 0; -#endif - } - - if (duk_is_function(thr, 1)) { - is_repl_func = 1; - r_start = NULL; - r_end = NULL; - } else { - duk_hstring *h_repl; - - is_repl_func = 0; - h_repl = duk_to_hstring(thr, 1); /* reject symbols */ - DUK_ASSERT(h_repl != NULL); - r_start = DUK_HSTRING_GET_DATA(h_repl); - r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl); - } - - prev_match_end_boff = 0; - - for (;;) { - /* - * If matching with a regexp: - * - non-global RegExp: lastIndex not touched on a match, zeroed - * on a non-match - * - global RegExp: on match, lastIndex will be updated by regexp - * executor to point to next char after the matching part (so that - * characters in the matching part are not matched again) - * - * If matching with a string: - * - always non-global match, find first occurrence - * - * We need: - * - The character offset of start-of-match for the replacer function - * - The byte offsets for start-of-match and end-of-match to implement - * the replacement values $&, $`, and $', and to copy non-matching - * input string portions (including header and trailer) verbatim. - * - * NOTE: the E5.1 specification is a bit vague how the RegExp should - * behave in the replacement process; e.g. is matching done first for - * all matches (in the global RegExp case) before any replacer calls - * are made? See: test-bi-string-proto-replace.js for discussion. - */ - - DUK_ASSERT_TOP(thr, 4); - -#if defined(DUK_USE_REGEXP_SUPPORT) - if (is_regexp) { - duk_dup_0(thr); - duk_dup_2(thr); - duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */ - if (!duk_is_object(thr, -1)) { - duk_pop(thr); - break; - } - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX); - DUK_ASSERT(duk_is_number(thr, -1)); - match_start_coff = duk_get_uint(thr, -1); - duk_pop(thr); - - duk_get_prop_index(thr, -1, 0); - DUK_ASSERT(duk_is_string(thr, -1)); - h_match = duk_known_hstring(thr, -1); - duk_pop(thr); /* h_match is borrowed, remains reachable through match_obj */ - - if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) { - /* This should be equivalent to match() algorithm step 8.f.iii.2: - * detect an empty match and allow it, but don't allow it twice. - */ - duk_uint32_t last_index; - - duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); - last_index = (duk_uint32_t) duk_get_uint(thr, -1); - DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld", - (long) last_index, (long) (last_index + 1))); - duk_pop(thr); - duk_push_uint(thr, (duk_uint_t) (last_index + 1)); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); - } - - DUK_ASSERT(duk_get_length(thr, -1) <= DUK_INT_MAX); /* string limits */ - match_caps = (duk_int_t) duk_get_length(thr, -1); - } else { -#else /* DUK_USE_REGEXP_SUPPORT */ - { /* unconditionally */ -#endif /* DUK_USE_REGEXP_SUPPORT */ - const duk_uint8_t *p_start, *p_end, *p; /* input string scan */ - const duk_uint8_t *q_start; /* match string */ - duk_size_t q_blen; - -#if defined(DUK_USE_REGEXP_SUPPORT) - DUK_ASSERT(!is_global); /* single match always */ -#endif - - p_start = DUK_HSTRING_GET_DATA(h_input); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); - p = p_start; - - h_search = duk_known_hstring(thr, 0); - q_start = DUK_HSTRING_GET_DATA(h_search); - q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search); - - p_end -= q_blen; /* ensure full memcmp() fits in while */ - - match_start_coff = 0; - - while (p <= p_end) { - DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { - duk_dup_0(thr); - h_match = duk_known_hstring(thr, -1); -#if defined(DUK_USE_REGEXP_SUPPORT) - match_caps = 0; -#endif - goto found; - } - - /* track utf-8 non-continuation bytes */ - if ((p[0] & 0xc0) != 0x80) { - match_start_coff++; - } - p++; - } - - /* not found */ - break; - } - found: - - /* stack[0] = search value - * stack[1] = replace value - * stack[2] = input string - * stack[3] = result buffer - * stack[4] = regexp match OR match string - */ - - match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff); - - tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff); - DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz); - - prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match); - - if (is_repl_func) { - duk_idx_t idx_args; - duk_hstring *h_repl; - - /* regexp res_obj is at index 4 */ - - duk_dup_1(thr); - idx_args = duk_get_top(thr); - -#if defined(DUK_USE_REGEXP_SUPPORT) - if (is_regexp) { - duk_int_t idx; - duk_require_stack(thr, match_caps + 2); - for (idx = 0; idx < match_caps; idx++) { - /* match followed by capture(s) */ - duk_get_prop_index(thr, 4, (duk_uarridx_t) idx); - } - } else { -#else /* DUK_USE_REGEXP_SUPPORT */ - { /* unconditionally */ -#endif /* DUK_USE_REGEXP_SUPPORT */ - /* match == search string, by definition */ - duk_dup_0(thr); - } - duk_push_uint(thr, (duk_uint_t) match_start_coff); - duk_dup_2(thr); - - /* [ ... replacer match [captures] match_char_offset input ] */ - - duk_call(thr, duk_get_top(thr) - idx_args); - h_repl = duk_to_hstring_m1(thr); /* -> [ ... repl_value ] */ - DUK_ASSERT(h_repl != NULL); - - DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl); - - duk_pop(thr); /* repl_value */ - } else { - r = r_start; - - while (r < r_end) { - duk_int_t ch1; - duk_int_t ch2; -#if defined(DUK_USE_REGEXP_SUPPORT) - duk_int_t ch3; -#endif - duk_size_t left; - - ch1 = *r++; - if (ch1 != DUK_ASC_DOLLAR) { - goto repl_write; - } - DUK_ASSERT(r <= r_end); - left = (duk_size_t) (r_end - r); - - if (left <= 0) { - goto repl_write; - } - - ch2 = r[0]; - switch (ch2) { - case DUK_ASC_DOLLAR: { - ch1 = (1 << 8) + DUK_ASC_DOLLAR; - goto repl_write; - } - case DUK_ASC_AMP: { - DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match); - r++; - continue; - } - case DUK_ASC_GRAVE: { - tmp_sz = (duk_size_t) match_start_boff; - DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz); - r++; - continue; - } - case DUK_ASC_SINGLEQUOTE: { - duk_uint32_t match_end_boff; - - /* Use match charlen instead of bytelen, just in case the input and - * match codepoint encodings would have different lengths. - */ - /* XXX: charlen computed here, and also in char2byte helper. */ - match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, - h_input, - match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match)); - - tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff); - DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz); - r++; - continue; - } - default: { -#if defined(DUK_USE_REGEXP_SUPPORT) - duk_int_t capnum, captmp, capadv; - /* XXX: optional check, match_caps is zero if no regexp, - * so dollar will be interpreted literally anyway. - */ - - if (!is_regexp) { - goto repl_write; - } - - if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) { - goto repl_write; - } - capnum = ch2 - DUK_ASC_0; - capadv = 1; - - if (left >= 2) { - ch3 = r[1]; - if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) { - captmp = capnum * 10 + (ch3 - DUK_ASC_0); - if (captmp < match_caps) { - capnum = captmp; - capadv = 2; - } - } - } - - if (capnum > 0 && capnum < match_caps) { - DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */ - - /* regexp res_obj is at offset 4 */ - duk_get_prop_index(thr, 4, (duk_uarridx_t) capnum); - if (duk_is_string(thr, -1)) { - duk_hstring *h_tmp_str; - - h_tmp_str = duk_known_hstring(thr, -1); - - DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str); - } else { - /* undefined -> skip (replaced with empty) */ - } - duk_pop(thr); - r += capadv; - continue; - } else { - goto repl_write; - } -#else /* DUK_USE_REGEXP_SUPPORT */ - goto repl_write; /* unconditionally */ -#endif /* DUK_USE_REGEXP_SUPPORT */ - } /* default case */ - } /* switch (ch2) */ - - repl_write: - /* ch1 = (r_increment << 8) + byte */ - - DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff)); - r += ch1 >> 8; - } /* while repl */ - } /* if (is_repl_func) */ - - duk_pop(thr); /* pop regexp res_obj or match string */ - -#if defined(DUK_USE_REGEXP_SUPPORT) - if (!is_global) { -#else - { /* unconditionally; is_global==0 */ -#endif - break; - } - } - - /* trailer */ - tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff); - DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz); - - DUK_ASSERT_TOP(thr, 4); - DUK_BW_COMPACT(thr, bw); - (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */ - return 1; -} - -/* - * split() - */ - -/* XXX: very messy now, but works; clean up, remove unused variables (nomimally - * used so compiler doesn't complain). - */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_hthread *thr) { - duk_hstring *h_input; - duk_hstring *h_sep; - duk_uint32_t limit; - duk_uint32_t arr_idx; -#if defined(DUK_USE_REGEXP_SUPPORT) - duk_bool_t is_regexp; -#endif - duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */ - duk_uint32_t prev_match_end_coff, prev_match_end_boff; - duk_uint32_t match_start_boff, match_start_coff; - duk_uint32_t match_end_boff, match_end_coff; - - h_input = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h_input != NULL); - - duk_push_array(thr); - - if (duk_is_undefined(thr, 1)) { - limit = 0xffffffffUL; - } else { - limit = duk_to_uint32(thr, 1); - } - - if (limit == 0) { - return 1; - } - - /* If the separator is a RegExp, make a "clone" of it. The specification - * algorithm calls [[Match]] directly for specific indices; we emulate this - * by tweaking lastIndex and using a "force global" variant of duk_regexp_match() - * which will use global-style matching even when the RegExp itself is non-global. - */ - - if (duk_is_undefined(thr, 0)) { - /* The spec algorithm first does "R = ToString(separator)" before checking - * whether separator is undefined. Since this is side effect free, we can - * skip the ToString() here. - */ - duk_dup_2(thr); - duk_put_prop_index(thr, 3, 0); - return 1; - } else if (duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) { -#if defined(DUK_USE_REGEXP_SUPPORT) - duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR); - duk_dup_0(thr); - duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */ - duk_replace(thr, 0); - /* lastIndex is initialized to zero by new RegExp() */ - is_regexp = 1; -#else - DUK_DCERROR_UNSUPPORTED(thr); -#endif - } else { - duk_to_string(thr, 0); -#if defined(DUK_USE_REGEXP_SUPPORT) - is_regexp = 0; -#endif - } - - /* stack[0] = separator (string or regexp) - * stack[1] = limit - * stack[2] = input string - * stack[3] = result array - */ - - prev_match_end_boff = 0; - prev_match_end_coff = 0; - arr_idx = 0; - matched = 0; - - for (;;) { - /* - * The specification uses RegExp [[Match]] to attempt match at specific - * offsets. We don't have such a primitive, so we use an actual RegExp - * and tweak lastIndex. Since the RegExp may be non-global, we use a - * special variant which forces global-like behavior for matching. - */ - - DUK_ASSERT_TOP(thr, 4); - -#if defined(DUK_USE_REGEXP_SUPPORT) - if (is_regexp) { - duk_dup_0(thr); - duk_dup_2(thr); - duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */ - if (!duk_is_object(thr, -1)) { - duk_pop(thr); - break; - } - matched = 1; - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX); - DUK_ASSERT(duk_is_number(thr, -1)); - match_start_coff = duk_get_uint(thr, -1); - match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff); - duk_pop(thr); - - if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) { - /* don't allow an empty match at the end of the string */ - duk_pop(thr); - break; - } - - duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); - DUK_ASSERT(duk_is_number(thr, -1)); - match_end_coff = duk_get_uint(thr, -1); - match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff); - duk_pop(thr); - - /* empty match -> bump and continue */ - if (prev_match_end_boff == match_end_boff) { - duk_push_uint(thr, (duk_uint_t) (match_end_coff + 1)); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); - duk_pop(thr); - continue; - } - } else { -#else /* DUK_USE_REGEXP_SUPPORT */ - { /* unconditionally */ -#endif /* DUK_USE_REGEXP_SUPPORT */ - const duk_uint8_t *p_start, *p_end, *p; /* input string scan */ - const duk_uint8_t *q_start; /* match string */ - duk_size_t q_blen, q_clen; - - p_start = DUK_HSTRING_GET_DATA(h_input); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); - p = p_start + prev_match_end_boff; - - h_sep = duk_known_hstring(thr, 0); /* symbol already rejected above */ - q_start = DUK_HSTRING_GET_DATA(h_sep); - q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep); - q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep); - - p_end -= q_blen; /* ensure full memcmp() fits in while */ - - match_start_coff = prev_match_end_coff; - - if (q_blen == 0) { - /* Handle empty separator case: it will always match, and always - * triggers the check in step 13.c.iii initially. Note that we - * must skip to either end of string or start of first codepoint, - * skipping over any continuation bytes! - * - * Don't allow an empty string to match at the end of the input. - */ - - matched = 1; /* empty separator can always match */ - - match_start_coff++; - p++; - while (p < p_end) { - if ((p[0] & 0xc0) != 0x80) { - goto found; - } - p++; - } - goto not_found; - } - - DUK_ASSERT(q_blen > 0 && q_clen > 0); - while (p <= p_end) { - DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); - DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */ - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { - /* never an empty match, so step 13.c.iii can't be triggered */ - goto found; - } - - /* track utf-8 non-continuation bytes */ - if ((p[0] & 0xc0) != 0x80) { - match_start_coff++; - } - p++; - } - - not_found: - /* not found */ - break; - - found: - matched = 1; - match_start_boff = (duk_uint32_t) (p - p_start); - match_end_coff = (duk_uint32_t) (match_start_coff + q_clen); /* constrained by string length */ - match_end_boff = (duk_uint32_t) (match_start_boff + q_blen); /* ditto */ - - /* empty match (may happen with empty separator) -> bump and continue */ - if (prev_match_end_boff == match_end_boff) { - prev_match_end_boff++; - prev_match_end_coff++; - continue; - } - } /* if (is_regexp) */ - - /* stack[0] = separator (string or regexp) - * stack[1] = limit - * stack[2] = input string - * stack[3] = result array - * stack[4] = regexp res_obj (if is_regexp) - */ - - DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld", - (long) match_start_boff, (long) match_start_coff, - (long) match_end_boff, (long) match_end_coff, - (long) prev_match_end_boff, (long) prev_match_end_coff)); - - duk_push_lstring(thr, - (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff), - (duk_size_t) (match_start_boff - prev_match_end_boff)); - duk_put_prop_index(thr, 3, arr_idx); - arr_idx++; - if (arr_idx >= limit) { - goto hit_limit; - } - -#if defined(DUK_USE_REGEXP_SUPPORT) - if (is_regexp) { - duk_size_t i, len; - - len = duk_get_length(thr, 4); - for (i = 1; i < len; i++) { - DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */ - duk_get_prop_index(thr, 4, (duk_uarridx_t) i); - duk_put_prop_index(thr, 3, arr_idx); - arr_idx++; - if (arr_idx >= limit) { - goto hit_limit; - } - } - - duk_pop(thr); - /* lastIndex already set up for next match */ - } else { -#else /* DUK_USE_REGEXP_SUPPORT */ - { /* unconditionally */ -#endif /* DUK_USE_REGEXP_SUPPORT */ - /* no action */ - } - - prev_match_end_boff = match_end_boff; - prev_match_end_coff = match_end_coff; - continue; - } /* for */ - - /* Combined step 11 (empty string special case) and 14-15. */ - - DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld", - (long) prev_match_end_boff, (long) prev_match_end_coff)); - - if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) { - /* Add trailer if: - * a) non-empty input - * b) empty input and no (zero size) match found (step 11) - */ - - duk_push_lstring(thr, - (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, - (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff)); - duk_put_prop_index(thr, 3, arr_idx); - /* No arr_idx update or limit check */ - } - - return 1; - - hit_limit: -#if defined(DUK_USE_REGEXP_SUPPORT) - if (is_regexp) { - duk_pop(thr); - } -#endif - - return 1; -} - -/* - * Various - */ - -#if defined(DUK_USE_REGEXP_SUPPORT) -DUK_LOCAL void duk__to_regexp_helper(duk_hthread *thr, duk_idx_t idx, duk_bool_t force_new) { - duk_hobject *h; - - /* Shared helper for match() steps 3-4, search() steps 3-4. */ - - DUK_ASSERT(idx >= 0); - - if (force_new) { - goto do_new; - } - - h = duk_get_hobject_with_class(thr, idx, DUK_HOBJECT_CLASS_REGEXP); - if (!h) { - goto do_new; - } - return; - - do_new: - duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR); - duk_dup(thr, idx); - duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */ - duk_replace(thr, idx); -} -#endif /* DUK_USE_REGEXP_SUPPORT */ - -#if defined(DUK_USE_REGEXP_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_hthread *thr) { - /* Easiest way to implement the search required by the specification - * is to do a RegExp test() with lastIndex forced to zero. To avoid - * side effects on the argument, "clone" the RegExp if a RegExp was - * given as input. - * - * The global flag of the RegExp should be ignored; setting lastIndex - * to zero (which happens when "cloning" the RegExp) should have an - * equivalent effect. - */ - - DUK_ASSERT_TOP(thr, 1); - (void) duk_push_this_coercible_to_string(thr); /* at index 1 */ - duk__to_regexp_helper(thr, 0 /*index*/, 1 /*force_new*/); - - /* stack[0] = regexp - * stack[1] = string - */ - - /* Avoid using RegExp.prototype methods, as they're writable and - * configurable and may have been changed. - */ - - duk_dup_0(thr); - duk_dup_1(thr); /* [ ... re_obj input ] */ - duk_regexp_match(thr); /* -> [ ... res_obj ] */ - - if (!duk_is_object(thr, -1)) { - duk_push_int(thr, -1); - return 1; - } - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX); - DUK_ASSERT(duk_is_number(thr, -1)); - return 1; -} -#endif /* DUK_USE_REGEXP_SUPPORT */ - -#if defined(DUK_USE_REGEXP_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_hthread *thr) { - duk_bool_t global; - duk_int_t prev_last_index; - duk_int_t this_index; - duk_int_t arr_idx; - - DUK_ASSERT_TOP(thr, 1); - (void) duk_push_this_coercible_to_string(thr); - duk__to_regexp_helper(thr, 0 /*index*/, 0 /*force_new*/); - global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL); - DUK_ASSERT_TOP(thr, 2); - - /* stack[0] = regexp - * stack[1] = string - */ - - if (!global) { - duk_regexp_match(thr); /* -> [ res_obj ] */ - return 1; /* return 'res_obj' */ - } - - /* Global case is more complex. */ - - /* [ regexp string ] */ - - duk_push_int(thr, 0); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); - duk_push_array(thr); - - /* [ regexp string res_arr ] */ - - prev_last_index = 0; - arr_idx = 0; - - for (;;) { - DUK_ASSERT_TOP(thr, 3); - - duk_dup_0(thr); - duk_dup_1(thr); - duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */ - - if (!duk_is_object(thr, -1)) { - duk_pop(thr); - break; - } - - duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); - DUK_ASSERT(duk_is_number(thr, -1)); - this_index = duk_get_int(thr, -1); - duk_pop(thr); - - if (this_index == prev_last_index) { - this_index++; - duk_push_int(thr, this_index); - duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); - } - prev_last_index = this_index; - - duk_get_prop_index(thr, -1, 0); /* match string */ - duk_put_prop_index(thr, 2, (duk_uarridx_t) arr_idx); - arr_idx++; - duk_pop(thr); /* res_obj */ - } - - if (arr_idx == 0) { - duk_push_null(thr); - } - - return 1; /* return 'res_arr' or 'null' */ -} -#endif /* DUK_USE_REGEXP_SUPPORT */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_hthread *thr) { - /* duk_concat() coerces arguments with ToString() in correct order */ - (void) duk_push_this_coercible_to_string(thr); - duk_insert(thr, 0); /* this is relatively expensive */ - duk_concat(thr, duk_get_top(thr)); - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_hthread *thr) { - DUK_ASSERT_TOP(thr, 0); - (void) duk_push_this_coercible_to_string(thr); - duk_trim(thr, 0); - DUK_ASSERT_TOP(thr, 1); - return 1; -} - -#if defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) { - duk_hstring *h_input; - duk_size_t input_blen; - duk_size_t result_len; - duk_int_t count_signed; - duk_uint_t count; - const duk_uint8_t *src; - duk_uint8_t *buf; - duk_uint8_t *p; - duk_double_t d; -#if !defined(DUK_USE_PREFER_SIZE) - duk_size_t copy_size; - duk_uint8_t *p_end; -#endif - - DUK_ASSERT_TOP(thr, 1); - h_input = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h_input != NULL); - input_blen = DUK_HSTRING_GET_BYTELEN(h_input); - - /* Count is ToNumber() coerced; +Infinity must be always rejected - * (even if input string is zero length), as well as negative values - * and -Infinity. -Infinity doesn't require an explicit check - * because duk_get_int() clamps it to DUK_INT_MIN which gets rejected - * as a negative value (regardless of input string length). - */ - d = duk_to_number(thr, 0); - if (duk_double_is_posinf(d)) { - goto fail_range; - } - count_signed = duk_get_int(thr, 0); - if (count_signed < 0) { - goto fail_range; - } - count = (duk_uint_t) count_signed; - - /* Overflow check for result length. */ - result_len = count * input_blen; - if (count != 0 && result_len / count != input_blen) { - goto fail_range; - } - - /* Temporary fixed buffer, later converted to string. */ - buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len); - src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); - -#if defined(DUK_USE_PREFER_SIZE) - p = buf; - while (count-- > 0) { - DUK_MEMCPY((void *) p, (const void *) src, input_blen); /* copy size may be zero */ - p += input_blen; - } -#else /* DUK_USE_PREFER_SIZE */ - /* Take advantage of already copied pieces to speed up the process - * especially for small repeated strings. - */ - p = buf; - p_end = p + result_len; - copy_size = input_blen; - for (;;) { - duk_size_t remain = (duk_size_t) (p_end - p); - DUK_DDD(DUK_DDDPRINT("remain=%ld, copy_size=%ld, input_blen=%ld, result_len=%ld", - (long) remain, (long) copy_size, (long) input_blen, - (long) result_len)); - if (remain <= copy_size) { - /* If result_len is zero, this case is taken and does - * a zero size copy. - */ - DUK_MEMCPY((void *) p, (const void *) src, remain); - break; - } else { - DUK_MEMCPY((void *) p, (const void *) src, copy_size); - p += copy_size; - } - - src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */ - copy_size = (duk_size_t) (p - buf); - } -#endif /* DUK_USE_PREFER_SIZE */ - - /* XXX: It would be useful to be able to create a duk_hstring with - * a certain byte size whose data area wasn't initialized and which - * wasn't in the string table yet. This would allow a string to be - * constructed directly without a buffer temporary and when it was - * finished, it could be injected into the string table. Currently - * this isn't possible because duk_hstrings are only tracked by the - * intern table (they are not in heap_allocated). - */ - - duk_buffer_to_string(thr, -1); /* Safe if input is safe. */ - return 1; - - fail_range: - DUK_DCERROR_RANGE_INVALID_ARGS(thr); -} -#endif /* DUK_USE_ES6 */ - -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr) { - duk_hstring *h1; - duk_hstring *h2; - duk_size_t h1_len, h2_len, prefix_len; - duk_small_int_t ret = 0; - duk_small_int_t rc; - - /* The current implementation of localeCompare() is simply a codepoint - * by codepoint comparison, implemented with a simple string compare - * because UTF-8 should preserve codepoint ordering (assuming valid - * shortest UTF-8 encoding). - * - * The specification requires that the return value must be related - * to the sort order: e.g. negative means that 'this' comes before - * 'that' in sort order. We assume an ascending sort order. - */ - - /* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */ - - h1 = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h1 != NULL); - - h2 = duk_to_hstring(thr, 0); - DUK_ASSERT(h2 != NULL); - - h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1); - h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2); - prefix_len = (h1_len <= h2_len ? h1_len : h2_len); - - /* Zero size compare not an issue with DUK_MEMCMP. */ - rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1), - (const void *) DUK_HSTRING_GET_DATA(h2), - (size_t) prefix_len); - - if (rc < 0) { - ret = -1; - goto done; - } else if (rc > 0) { - ret = 1; - goto done; - } - - /* prefix matches, lengths matter now */ - if (h1_len > h2_len) { - ret = 1; - goto done; - } else if (h1_len == h2_len) { - DUK_ASSERT(ret == 0); - goto done; - } - ret = -1; - goto done; - - done: - duk_push_int(thr, (duk_int_t) ret); - return 1; -} - -#if defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *thr) { - duk_int_t magic; - duk_hstring *h; - duk_hstring *h_search; - duk_size_t blen_search; - const duk_uint8_t *p_cmp_start; - duk_bool_t result; - - h = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h != NULL); - - h_search = duk__str_tostring_notregexp(thr, 0); - DUK_ASSERT(h_search != NULL); - - magic = duk_get_current_magic(thr); - - p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); - blen_search = DUK_HSTRING_GET_BYTELEN(h_search); - - if (duk_is_undefined(thr, 1)) { - if (magic) { - p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search; - } else { - /* p_cmp_start already OK */ - } - } else { - duk_int_t len; - duk_int_t pos; - - DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX); - len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); - pos = duk_to_int_clamped(thr, 1, 0, len); - DUK_ASSERT(pos >= 0 && pos <= len); - - if (magic) { - p_cmp_start -= blen_search; /* Conceptually subtracted last, but do already here. */ - } - DUK_ASSERT(pos >= 0 && pos <= len); - - p_cmp_start += duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) pos); - } - - /* The main comparison can be done using a memcmp() rather than - * doing codepoint comparisons: for CESU-8 strings there is a - * canonical representation for every codepoint. But we do need - * to deal with the char/byte offset translation to find the - * comparison range. - */ - - result = 0; - if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) && - (duk_size_t) (p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h)) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) { - if (DUK_MEMCMP((const void *) p_cmp_start, - (const void *) DUK_HSTRING_GET_DATA(h_search), - (size_t) blen_search) == 0) { - result = 1; - } - } - - duk_push_boolean(thr, result); - return 1; -} -#endif /* DUK_USE_ES6 */ - -#if defined(DUK_USE_ES6) -DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_hthread *thr) { - duk_hstring *h; - duk_hstring *h_search; - duk_int_t len; - duk_int_t pos; - - h = duk_push_this_coercible_to_string(thr); - DUK_ASSERT(h != NULL); - - h_search = duk__str_tostring_notregexp(thr, 0); - DUK_ASSERT(h_search != NULL); - - len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); - pos = duk_to_int_clamped(thr, 1, 0, len); - DUK_ASSERT(pos >= 0 && pos <= len); - - pos = duk__str_search_shared(thr, h, h_search, pos, 0 /*backwards*/); - duk_push_boolean(thr, pos >= 0); - return 1; -} -#endif /* DUK_USE_ES6 */ -#endif /* DUK_USE_STRING_BUILTIN */ -#line 1 "duk_bi_symbol.c" -/* - * Symbol built-in - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_SYMBOL_BUILTIN) - -/* - * Constructor - */ - -DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) { - const duk_uint8_t *desc; - duk_size_t len; - duk_uint8_t *buf; - duk_uint8_t *p; - duk_int_t magic; - - magic = duk_get_current_magic(thr); - if (duk_is_undefined(thr, 0) && (magic == 0)) { - /* Symbol() accepts undefined and empty string, but they are - * treated differently. - */ - desc = NULL; - len = 0; - } else { - /* Symbol.for() coerces undefined to 'undefined' */ - desc = (const duk_uint8_t *) duk_to_lstring(thr, 0, &len); - } - - /* Maximum symbol data length: - * +1 initial byte (0x80 or 0x81) - * +len description - * +1 0xff after description, before unique suffix - * +17 autogenerated unique suffix: 'ffffffff-ffffffff' is longest - * +1 0xff after unique suffix for symbols with undefined description - */ - buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1); - p = buf + 1; - DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */ - DUK_MEMCPY((void *) p, (const void *) desc, len); - p += len; - if (magic == 0) { - /* Symbol(): create unique symbol. Use two 32-bit values - * to avoid dependency on 64-bit types and 64-bit integer - * formatting (at least for now). - */ - if (++thr->heap->sym_counter[0] == 0) { - thr->heap->sym_counter[1]++; - } - p += DUK_SPRINTF((char *) p, "\xFF" "%lx-%lx", - (unsigned long) thr->heap->sym_counter[1], - (unsigned long) thr->heap->sym_counter[0]); - if (desc == NULL) { - /* Special case for 'undefined' description, trailing - * 0xff distinguishes from empty string description, - * but needs minimal special case handling elsewhere. - */ - *p++ = 0xff; - } - buf[0] = 0x81; - } else { - /* Symbol.for(): create a global symbol */ - buf[0] = 0x80; - } - - duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf)); - DUK_DDD(DUK_DDDPRINT("created symbol: %!T", duk_get_tval(thr, -1))); - return 1; -} - -DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_hthread *thr, duk_tval *tv_arg) { - duk_tval *tv; - duk_tval tv_val; - duk_hobject *h_obj; - duk_hstring *h_str; - - DUK_ASSERT(tv_arg != NULL); - - /* XXX: add internal helper: duk_auto_unbox_tval(thr, tv, mask); */ - /* XXX: add internal helper: duk_auto_unbox(thr, tv, idx); */ - - tv = tv_arg; - if (DUK_TVAL_IS_OBJECT(tv)) { - h_obj = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h_obj != NULL); - if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_SYMBOL) { - if (!duk_hobject_get_internal_value(thr->heap, h_obj, &tv_val)) { - return NULL; - } - tv = &tv_val; - } else { - return NULL; - } - } - - if (!DUK_TVAL_IS_STRING(tv)) { - return NULL; - } - h_str = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h_str != NULL); - - /* Here symbol is more expected than not. */ - if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) { - return NULL; - } - - return h_str; -} - -DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_hthread *thr) { - duk_hstring *h_str; - - h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr)); - if (h_str == NULL) { - return DUK_RET_TYPE_ERROR; - } - - if (duk_get_current_magic(thr) == 0) { - /* .toString() */ - duk_push_symbol_descriptive_string(thr, h_str); - } else { - /* .valueOf() */ - duk_push_hstring(thr, h_str); - } - return 1; -} - -DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_hthread *thr) { - duk_hstring *h; - const duk_uint8_t *p; - - /* Argument must be a symbol but not checked here. The initial byte - * check will catch non-symbol strings. - */ - h = duk_require_hstring(thr, 0); - DUK_ASSERT(h != NULL); - - p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); - DUK_ASSERT(p != NULL); - - /* Even for zero length strings there's at least one NUL byte so - * we can safely check the initial byte. - */ - if (p[0] == 0x80) { - /* Global symbol, return its key (bytes just after the initial byte). */ - duk_push_lstring(thr, (const char *) (p + 1), (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h) - 1)); - return 1; - } else if (p[0] == 0x81 || p[0] == 0x82 || p[0] == 0xff) { - /* Local symbol or hidden symbol, return undefined. */ - return 0; - } - - /* Covers normal strings and unknown initial bytes. */ - return DUK_RET_TYPE_ERROR; -} - -DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_hthread *thr) { - duk_hstring *h_str; - - h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr)); - if (h_str == NULL) { - return DUK_RET_TYPE_ERROR; - } - duk_push_hstring(thr, h_str); - return 1; -} - -#endif /* DUK_USE_SYMBOL_BUILTIN */ -#line 1 "duk_bi_thread.c" -/* - * Thread builtins - */ - -/* #include duk_internal.h -> already included */ - -/* - * Constructor - */ - -#if defined(DUK_USE_COROUTINE_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) { - duk_hthread *new_thr; - duk_hobject *func; - - /* Check that the argument is callable; this is not 100% because we - * don't allow native functions to be a thread's initial function. - * Resume will reject such functions in any case. - */ - /* XXX: need a duk_require_func_promote_lfunc() */ - func = duk_require_hobject_promote_lfunc(thr, 0); - DUK_ASSERT(func != NULL); - duk_require_callable(thr, 0); - - duk_push_thread(thr); - new_thr = (duk_hthread *) duk_known_hobject(thr, -1); - new_thr->state = DUK_HTHREAD_STATE_INACTIVE; - - /* push initial function call to new thread stack; this is - * picked up by resume(). - */ - duk_push_hobject(new_thr, func); - - return 1; /* return thread */ -} -#endif - -/* - * Resume a thread. - * - * The thread must be in resumable state, either (a) new thread which hasn't - * yet started, or (b) a thread which has previously yielded. This method - * must be called from an Ecmascript function. - * - * Args: - * - thread - * - value - * - isError (defaults to false) - * - * Note: yield and resume handling is currently asymmetric. - */ - -#if defined(DUK_USE_COROUTINE_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_hthread *thr_resume; - duk_hobject *caller_func; - duk_small_uint_t is_error; - - DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T", - (duk_tval *) duk_get_tval(thr, 0), - (duk_tval *) duk_get_tval(thr, 1), - (duk_tval *) duk_get_tval(thr, 2))); - - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); - DUK_ASSERT(thr->heap->curr_thread == thr); - - thr_resume = duk_require_hthread(thr, 0); - is_error = (duk_small_uint_t) duk_to_boolean(thr, 2); - duk_set_top(thr, 2); - - /* [ thread value ] */ - - /* - * Thread state and calling context checks - */ - - if (thr->callstack_top < 2) { - DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)")); - goto state_error; - } - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(thr->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */ - - caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent); - if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { - DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code")); - goto state_error; - } - - /* Note: there is no requirement that: 'thr->callstack_preventcount == 1' - * like for yield. - */ - - if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE && - thr_resume->state != DUK_HTHREAD_STATE_YIELDED) { - DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED")); - goto state_error; - } - - DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE || - thr_resume->state == DUK_HTHREAD_STATE_YIELDED); - - /* Further state-dependent pre-checks */ - - if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) { - /* no pre-checks now, assume a previous yield() has left things in - * tip-top shape (longjmp handler will assert for these). - */ - } else { - duk_hobject *h_fun; - - DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE); - - /* The initial function must be an Ecmascript function (but - * can be bound). We must make sure of that before we longjmp - * because an error in the RESUME handler call processing will - * not be handled very cleanly. - */ - if ((thr_resume->callstack_top != 0) || - (thr_resume->valstack_top - thr_resume->valstack != 1)) { - goto state_error; - } - - duk_push_tval(thr, DUK_GET_TVAL_NEGIDX(thr_resume, -1)); - duk_resolve_nonbound_function(thr); - h_fun = duk_require_hobject(thr, -1); /* reject lightfuncs on purpose */ - if (!DUK_HOBJECT_IS_CALLABLE(h_fun) || !DUK_HOBJECT_IS_COMPFUNC(h_fun)) { - goto state_error; - } - duk_pop(thr); - } - - /* - * The error object has been augmented with a traceback and other - * info from its creation point -- usually another thread. The - * error handler is called here right before throwing, but it also - * runs in the resumer's thread. It might be nice to get a traceback - * from the resumee but this is not the case now. - */ - -#if defined(DUK_USE_AUGMENT_ERROR_THROW) - if (is_error) { - DUK_ASSERT_TOP(thr, 2); /* value (error) is at stack top */ - duk_err_augment_error_throw(thr); /* in resumer's context */ - } -#endif - -#if defined(DUK_USE_DEBUG) - if (is_error) { - DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T", - (duk_tval *) duk_get_tval(thr, 0), - (duk_tval *) duk_get_tval(thr, 1))); - } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) { - DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T", - (duk_tval *) duk_get_tval(thr, 0), - (duk_tval *) duk_get_tval(thr, 1))); - } else { - DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T", - (duk_tval *) duk_get_tval(thr, 0), - (duk_tval *) duk_get_tval(thr, 1))); - } -#endif - - thr->heap->lj.type = DUK_LJ_TYPE_RESUME; - - /* lj value2: thread */ - DUK_ASSERT(thr->valstack_bottom < thr->valstack_top); - DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]); /* side effects */ - - /* lj value1: value */ - DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top); - DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */ - DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1); - - thr->heap->lj.iserror = is_error; - - DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */ - duk_err_longjmp(thr); /* execution resumes in bytecode executor */ - DUK_UNREACHABLE(); - /* Never here, fall through to error (from compiler point of view). */ - - state_error: - DUK_DCERROR_TYPE_INVALID_STATE(thr); -} -#endif - -/* - * Yield the current thread. - * - * The thread must be in yieldable state: it must have a resumer, and there - * must not be any yield-preventing calls (native calls and constructor calls, - * currently) in the thread's call stack (otherwise a resume would not be - * possible later). This method must be called from an Ecmascript function. - * - * Args: - * - value - * - isError (defaults to false) - * - * Note: yield and resume handling is currently asymmetric. - */ - -#if defined(DUK_USE_COROUTINE_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) { - duk_hobject *caller_func; - duk_small_uint_t is_error; - - DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T", - (duk_tval *) duk_get_tval(thr, 0), - (duk_tval *) duk_get_tval(thr, 1))); - - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); - DUK_ASSERT(thr->heap->curr_thread == thr); - - is_error = (duk_small_uint_t) duk_to_boolean(thr, 1); - duk_set_top(thr, 1); - - /* [ value ] */ - - /* - * Thread state and calling context checks - */ - - if (!thr->resumer) { - DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer")); - goto state_error; - } - DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); - - if (thr->callstack_top < 2) { - DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)")); - goto state_error; - } - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(thr->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */ - - caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent); - if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { - DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code")); - goto state_error; - } - - DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */ - if (thr->callstack_preventcount != 1) { - /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */ - DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)", - (long) thr->callstack_preventcount)); - goto state_error; - } - - /* - * The error object has been augmented with a traceback and other - * info from its creation point -- usually the current thread. - * The error handler, however, is called right before throwing - * and runs in the yielder's thread. - */ - -#if defined(DUK_USE_AUGMENT_ERROR_THROW) - if (is_error) { - DUK_ASSERT_TOP(thr, 1); /* value (error) is at stack top */ - duk_err_augment_error_throw(thr); /* in yielder's context */ - } -#endif - -#if defined(DUK_USE_DEBUG) - if (is_error) { - DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T", - (duk_tval *) duk_get_tval(thr, 0))); - } else { - DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T", - (duk_tval *) duk_get_tval(thr, 0))); - } -#endif - - /* - * Process yield - * - * After longjmp(), processing continues in bytecode executor longjmp - * handler, which will e.g. update thr->resumer to NULL. - */ - - thr->heap->lj.type = DUK_LJ_TYPE_YIELD; - - /* lj value1: value */ - DUK_ASSERT(thr->valstack_bottom < thr->valstack_top); - DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */ - DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1); - - thr->heap->lj.iserror = is_error; - - DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */ - duk_err_longjmp(thr); /* execution resumes in bytecode executor */ - DUK_UNREACHABLE(); - /* Never here, fall through to error (from compiler point of view). */ - - state_error: - DUK_DCERROR_TYPE_INVALID_STATE(thr); -} -#endif - -#if defined(DUK_USE_COROUTINE_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_hthread *thr) { - duk_push_current_thread(thr); - return 1; -} -#endif -#line 1 "duk_bi_thrower.c" -/* - * Type error thrower, E5 Section 13.2.3. - */ - -/* #include duk_internal.h -> already included */ - -DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_hthread *thr) { - DUK_DCERROR_TYPE_INVALID_ARGS(thr); -} -#line 1 "duk_debug_fixedbuffer.c" -/* - * Fixed buffer helper useful for debugging, requires no allocation - * which is critical for debugging. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_DEBUG) - -DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) { - duk_size_t avail; - duk_size_t copylen; - - avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset)); - if (length > avail) { - copylen = avail; - fb->truncated = 1; - } else { - copylen = length; - } - DUK_MEMCPY(fb->buffer + fb->offset, buffer, copylen); - fb->offset += copylen; -} - -DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) { - duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1); -} - -DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) { - duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x)); -} - -DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) { - duk_size_t avail; - va_list ap; - - va_start(ap, fmt); - avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset)); - if (avail > 0) { - duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap); - if (res < 0) { - /* error */ - } else if ((duk_size_t) res >= avail) { - /* (maybe) truncated */ - fb->offset += avail; - if ((duk_size_t) res > avail) { - /* actual chars dropped (not just NUL term) */ - fb->truncated = 1; - } - } else { - /* normal */ - fb->offset += (duk_size_t) res; - } - } - va_end(ap); -} - -DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) { - char buf[64+1]; - duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size); - buf[sizeof(buf) - 1] = (char) 0; - duk_fb_put_cstring(fb, buf); -} - -DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) { - return (fb->offset >= fb->length); -} - -#endif /* DUK_USE_DEBUG */ -#line 1 "duk_debug_vsnprintf.c" -/* - * Custom formatter for debug printing, allowing Duktape specific data - * structures (such as tagged values and heap objects) to be printed with - * a nice format string. Because debug printing should not affect execution - * state, formatting here must be independent of execution (see implications - * below) and must not allocate memory. - * - * Custom format tags begin with a '%!' to safely distinguish them from - * standard format tags. The following conversions are supported: - * - * %!T tagged value (duk_tval *) - * %!O heap object (duk_heaphdr *) - * %!I decoded bytecode instruction - * %!C bytecode instruction opcode name (arg is long) - * - * Everything is serialized in a JSON-like manner. The default depth is one - * level, internal prototype is not followed, and internal properties are not - * serialized. The following modifiers change this behavior: - * - * @ print pointers - * # print binary representations (where applicable) - * d deep traversal of own properties (not prototype) - * p follow prototype chain (useless without 'd') - * i include internal properties (other than prototype) - * x hexdump buffers - * h heavy formatting - * - * For instance, the following serializes objects recursively, but does not - * follow the prototype chain nor print internal properties: "%!dO". - * - * Notes: - * - * * Standard snprintf return value semantics seem to vary. This - * implementation returns the number of bytes it actually wrote - * (excluding the null terminator). If retval == buffer size, - * output was truncated (except for corner cases). - * - * * Output format is intentionally different from Ecmascript - * formatting requirements, as formatting here serves debugging - * of internals. - * - * * Depth checking (and updating) is done in each type printer - * separately, to allow them to call each other freely. - * - * * Some pathological structures might take ages to print (e.g. - * self recursion with 100 properties pointing to the object - * itself). To guard against these, each printer also checks - * whether the output buffer is full; if so, early exit. - * - * * Reference loops are detected using a loop stack. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_DEBUG) - -/* #include stdio.h -> already included */ -/* #include stdarg.h -> already included */ -#include - -/* list of conversion specifiers that terminate a format tag; - * this is unfortunately guesswork. - */ -#define DUK__ALLOWED_STANDARD_SPECIFIERS "diouxXeEfFgGaAcsCSpnm" - -/* maximum length of standard format tag that we support */ -#define DUK__MAX_FORMAT_TAG_LENGTH 32 - -/* heapobj recursion depth when deep printing is selected */ -#define DUK__DEEP_DEPTH_LIMIT 8 - -/* maximum recursion depth for loop detection stacks */ -#define DUK__LOOP_STACK_DEPTH 256 - -/* must match bytecode defines now; build autogenerate? */ -DUK_LOCAL const char * const duk__bc_optab[256] = { - "LDREG", "STREG", "JUMP", "LDCONST", "LDINT", "LDINTX", "LDTHIS", "LDUNDEF", - "LDNULL", "LDTRUE", "LDFALSE", "GETVAR", "BNOT", "LNOT", "UNM", "UNP", - "EQ_RR", "EQ_CR", "EQ_RC", "EQ_CC", "NEQ_RR", "NEQ_CR", "NEQ_RC", "NEQ_CC", - "SEQ_RR", "SEQ_CR", "SEQ_RC", "SEQ_CC", "SNEQ_RR", "SNEQ_CR", "SNEQ_RC", "SNEQ_CC", - - "GT_RR", "GT_CR", "GT_RC", "GT_CC", "GE_RR", "GE_CR", "GE_RC", "GE_CC", - "LT_RR", "LT_CR", "LT_RC", "LT_CC", "LE_RR", "LE_CR", "LE_RC", "LE_CC", - "IFTRUE_R", "IFTRUE_C", "IFFALSE_R", "IFFALSE_C", "ADD_RR", "ADD_CR", "ADD_RC", "ADD_CC", - "SUB_RR", "SUB_CR", "SUB_RC", "SUB_CC", "MUL_RR", "MUL_CR", "MUL_RC", "MUL_CC", - - "DIV_RR", "DIV_CR", "DIV_RC", "DIV_CC", "MOD_RR", "MOD_CR", "MOD_RC", "MOD_CC", - "EXP_RR", "EXP_CR", "EXP_RC", "EXP_CC", "BAND_RR", "BAND_CR", "BAND_RC", "BAND_CC", - "BOR_RR", "BOR_CR", "BOR_RC", "BOR_CC", "BXOR_RR", "BXOR_CR", "BXOR_RC", "BXOR_CC", - "BASL_RR", "BASL_CR", "BASL_RC", "BASL_CC", "BLSR_RR", "BLSR_CR", "BLSR_RC", "BLSR_CC", - - "BASR_RR", "BASR_CR", "BASR_RC", "BASR_CC", "INSTOF_RR", "INSTOF_CR", "INSTOF_RC", "INSTOF_CC", - "IN_RR", "IN_CR", "IN_RC", "IN_CC", "GETPROP_RR", "GETPROP_CR", "GETPROP_RC", "GETPROP_CC", - "PUTPROP_RR", "PUTPROP_CR", "PUTPROP_RC", "PUTPROP_CC", "DELPROP_RR", "DELPROP_CR", "DELPROP_RC", "DELPROP_CC", - "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV", - - "PREINCP_RR", "PREINCP_CR", "PREINCP_RC", "PREINCP_CC", "PREDECP_RR", "PREDECP_CR", "PREDECP_RC", "PREDECP_CC", - "POSTINCP_RR", "POSTINCP_CR", "POSTINCP_RC", "POSTINCP_CC", "POSTDECP_RR", "POSTDECP_CR", "POSTDECP_RC", "POSTDECP_CC", - "DECLVAR_RR", "DECLVAR_CR", "DECLVAR_RC", "DECLVAR_CC", "REGEXP_RR", "REGEXP_RC", "REGEXP_CR", "REGEXP_CC", - "CLOSURE", "TYPEOF", "TYPEOFID", "PUTVAR", "DELVAR", "RETREG", "RETUNDEF", "RETCONST", - - "RETCONSTN", "LABEL", "ENDLABEL", "BREAK", "CONTINUE", "TRYCATCH", "ENDTRY", "ENDCATCH", - "ENDFIN", "THROW", "INVLHS", "CSREG", "CSVAR_RR", "CSVAR_CR", "CSVAR_RC", "CSVAR_CC", - "CALL0", "CALL1", "CALL2", "CALL3", "CALL4", "CALL5", "CALL6", "CALL7", - "CALL8", "CALL9", "CALL10", "CALL11", "CALL12", "CALL13", "CALL14", "CALL15", - - "NEWOBJ", "NEWARR", "MPUTOBJ", "MPUTOBJI", "INITSET", "INITGET", "MPUTARR", "MPUTARRI", - "SETALEN", "INITENUM", "NEXTENUM", "NEWTARGET", "DEBUGGER", "NOP", "INVALID", "UNUSED207", - "GETPROPC_RR", "GETPROPC_CR", "GETPROPC_RC", "GETPROPC_CC", "UNUSED212", "UNUSED213", "UNUSED214", "UNUSED215", - "UNUSED216", "UNUSED217", "UNUSED218", "UNUSED219", "UNUSED220", "UNUSED221", "UNUSED222", "UNUSED223", - - "UNUSED224", "UNUSED225", "UNUSED226", "UNUSED227", "UNUSED228", "UNUSED229", "UNUSED230", "UNUSED231", - "UNUSED232", "UNUSED233", "UNUSED234", "UNUSED235", "UNUSED236", "UNUSED237", "UNUSED238", "UNUSED239", - "UNUSED240", "UNUSED241", "UNUSED242", "UNUSED243", "UNUSED244", "UNUSED245", "UNUSED246", "UNUSED247", - "UNUSED248", "UNUSED249", "UNUSED250", "UNUSED251", "UNUSED252", "UNUSED253", "UNUSED254", "UNUSED255" -}; - -typedef struct duk__dprint_state duk__dprint_state; -struct duk__dprint_state { - duk_fixedbuffer *fb; - - /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice - * to not couple these two mechanisms unnecessarily. - */ - duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH]; - duk_int_t loop_stack_index; - duk_int_t loop_stack_limit; - - duk_int_t depth; - duk_int_t depth_limit; - - duk_bool_t pointer; - duk_bool_t heavy; - duk_bool_t binary; - duk_bool_t follow_proto; - duk_bool_t internal; - duk_bool_t hexdump; -}; - -/* helpers */ -DUK_LOCAL_DECL void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, duk_bool_t quotes); -DUK_LOCAL_DECL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h); -DUK_LOCAL_DECL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h); -DUK_LOCAL_DECL void duk__print_tval(duk__dprint_state *st, duk_tval *tv); -DUK_LOCAL_DECL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins); -DUK_LOCAL_DECL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h); -DUK_LOCAL_DECL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h); -DUK_LOCAL_DECL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h); - -DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) { - duk_fixedbuffer *fb = st->fb; - - if (st->heavy) { - duk_fb_sprintf(fb, "(%p)", (void *) h); - } - - if (!h) { - return; - } - - if (st->binary) { - duk_size_t i; - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET); - for (i = 0; i < (duk_size_t) sizeof(*h); i++) { - duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]); - } - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET); - } - -#if defined(DUK_USE_REFERENCE_COUNTING) /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */ - if (st->heavy) { - duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld," - "reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]", - (void *) DUK_HEAPHDR_GET_NEXT(NULL, h), - (void *) DUK_HEAPHDR_GET_PREV(NULL, h), - (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(h), - (unsigned long) DUK_HEAPHDR_GET_FLAGS(h), - (long) DUK_HEAPHDR_GET_TYPE(h), - (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0)); - } -#else - if (st->heavy) { - duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]", - (void *) DUK_HEAPHDR_GET_NEXT(NULL, h), - (unsigned long) DUK_HEAPHDR_GET_FLAGS(h), - (long) DUK_HEAPHDR_GET_TYPE(h), - (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0)); - } -#endif -} - -DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) { - duk_fixedbuffer *fb = st->fb; - - if (st->heavy) { - duk_fb_sprintf(fb, "(%p)", (void *) h); - } - - if (!h) { - return; - } - - if (st->binary) { - duk_size_t i; - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET); - for (i = 0; i < (duk_size_t) sizeof(*h); i++) { - duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]); - } - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET); - } - -#if defined(DUK_USE_REFERENCE_COUNTING) - if (st->heavy) { - duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]", - (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h), - (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h), - (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h), - (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0)); - } -#else - if (st->heavy) { - duk_fb_sprintf(fb, "[h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]", - (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h), - (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h), - (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0), - (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0)); - } -#endif -} - -DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_bool_t quotes) { - duk_fixedbuffer *fb = st->fb; - const duk_uint8_t *p; - const duk_uint8_t *p_end; - - /* terminal type: no depth check */ - - if (duk_fb_is_full(fb)) { - return; - } - - duk__print_shared_heaphdr_string(st, &h->hdr); - - if (!h) { - duk_fb_put_cstring(fb, "NULL"); - return; - } - - p = DUK_HSTRING_GET_DATA(h); - p_end = p + DUK_HSTRING_GET_BYTELEN(h); - - if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) { - /* If property key begins with underscore, encode it with - * forced quotes (e.g. "_Foo") to distinguish it from encoded - * internal properties (e.g. \x82Bar -> _Bar). - */ - quotes = 1; - } - - if (quotes) { - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE); - } - while (p < p_end) { - duk_uint8_t ch = *p++; - - /* two special escapes: '\' and '"', other printables as is */ - if (ch == '\\') { - duk_fb_sprintf(fb, "\\\\"); - } else if (ch == '"') { - duk_fb_sprintf(fb, "\\\""); - } else if (ch >= 0x20 && ch <= 0x7e) { - duk_fb_put_byte(fb, ch); - } else if (ch == 0x82 && !quotes) { - /* encode \x82Bar as _Bar if no quotes are - * applied, this is for readable internal keys. - */ - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE); - } else { - duk_fb_sprintf(fb, "\\x%02lx", (unsigned long) ch); - } - } - if (quotes) { - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE); - } -#if defined(DUK_USE_REFERENCE_COUNTING) - /* XXX: limit to quoted strings only, to save keys from being cluttered? */ - duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr)); -#endif -} - -#define DUK__COMMA() do { \ - if (first) { \ - first = 0; \ - } else { \ - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); \ - } \ - } while (0) - -DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) { - duk_fixedbuffer *fb = st->fb; - duk_uint_fast32_t i; - duk_tval *tv; - duk_hstring *key; - duk_bool_t first = 1; - const char *brace1 = "{"; - const char *brace2 = "}"; - duk_bool_t pushed_loopstack = 0; - - if (duk_fb_is_full(fb)) { - return; - } - - duk__print_shared_heaphdr(st, &h->hdr); - - if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) { - brace1 = "["; - brace2 = "]"; - } - - if (!h) { - duk_fb_put_cstring(fb, "NULL"); - goto finished; - } - - if (st->depth >= st->depth_limit) { - const char *subtype = "generic"; - - if (DUK_HOBJECT_IS_COMPFUNC(h)) { - subtype = "compfunc"; - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - subtype = "natfunc"; - } else if (DUK_HOBJECT_IS_THREAD(h)) { - subtype = "thread"; - } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { - subtype = "bufobj"; - } else if (DUK_HOBJECT_IS_ARRAY(h)) { - subtype = "array"; - } - duk_fb_sprintf(fb, "%sobject/%s %p%s", (const char *) brace1, subtype, (void *) h, (const char *) brace2); - return; - } - - for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) { - if (st->loop_stack[i] == h) { - duk_fb_sprintf(fb, "%sLOOP:%p%s", (const char *) brace1, (void *) h, (const char *) brace2); - return; - } - } - - /* after this, return paths should 'goto finished' for decrement */ - st->depth++; - - if (st->loop_stack_index >= st->loop_stack_limit) { - duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", (const char *) brace1, (const char *) brace2); - goto finished; - } - st->loop_stack[st->loop_stack_index++] = h; - pushed_loopstack = 1; - - /* - * Notation: double underscore used for internal properties which are not - * stored in the property allocation (e.g. '__valstack'). - */ - - duk_fb_put_cstring(fb, brace1); - - if (DUK_HOBJECT_GET_PROPS(NULL, h)) { - duk_uint32_t a_limit; - - a_limit = DUK_HOBJECT_GET_ASIZE(h); - if (st->internal) { - /* dump all allocated entries, unused entries print as 'unused', - * note that these may extend beyond current 'length' and look - * a bit funny. - */ - } else { - /* leave out trailing 'unused' elements */ - while (a_limit > 0) { - tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1); - if (!DUK_TVAL_IS_UNUSED(tv)) { - break; - } - a_limit--; - } - } - - for (i = 0; i < a_limit; i++) { - tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i); - DUK__COMMA(); - duk__print_tval(st, tv); - } - for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) { - key = DUK_HOBJECT_E_GET_KEY(NULL, h, i); - if (!key) { - continue; - } - if (!st->internal && DUK_HSTRING_HAS_HIDDEN(key)) { - continue; - } - DUK__COMMA(); - duk__print_hstring(st, key, 0); - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON); - if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) { - duk_fb_sprintf(fb, "[get:%p,set:%p]", - (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get, - (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set); - } else { - tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v; - duk__print_tval(st, tv); - } - if (st->heavy) { - duk_fb_sprintf(fb, "<%02lx>", (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i)); - } - } - } - if (st->internal) { - if (DUK_HOBJECT_IS_ARRAY(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__array:true"); - } - if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true"); - } - if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true"); - } - if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__boundfunc:true"); - } - if (DUK_HOBJECT_HAS_COMPFUNC(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__compfunc:true"); - } - if (DUK_HOBJECT_HAS_NATFUNC(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__natfunc:true"); - } - if (DUK_HOBJECT_HAS_BUFOBJ(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true"); - } - if (DUK_HOBJECT_IS_THREAD(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true"); - } - if (DUK_HOBJECT_HAS_ARRAY_PART(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true"); - } - if (DUK_HOBJECT_HAS_STRICT(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true"); - } - if (DUK_HOBJECT_HAS_NOTAIL(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__notail:true"); - } - if (DUK_HOBJECT_HAS_NEWENV(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true"); - } - if (DUK_HOBJECT_HAS_NAMEBINDING(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true"); - } - if (DUK_HOBJECT_HAS_CREATEARGS(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true"); - } - if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true"); - } - if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true"); - } - if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true"); - } - if (DUK_HOBJECT_IS_BUFOBJ(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufobj:true"); - } - if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true"); - } - } - - if (st->internal && DUK_HOBJECT_IS_ARRAY(h)) { - duk_harray *a = (duk_harray *) h; - DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) a->length); - DUK__COMMA(); duk_fb_sprintf(fb, "__length_nonwritable:%ld", (long) a->length_nonwritable); - } else if (st->internal && DUK_HOBJECT_IS_COMPFUNC(h)) { - duk_hcompfunc *f = (duk_hcompfunc *) h; - DUK__COMMA(); duk_fb_put_cstring(fb, "__data:"); - duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f)); - DUK__COMMA(); duk_fb_put_cstring(fb, "__lexenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_LEXENV(NULL, f)); - DUK__COMMA(); duk_fb_put_cstring(fb, "__varenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_VARENV(NULL, f)); - DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs); - DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld", (long) f->start_line); - DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line); -#endif - DUK__COMMA(); duk_fb_put_cstring(fb, "__data:"); - duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f)); - } else if (st->internal && DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK__COMMA(); duk_fb_sprintf(fb, "__func:"); - duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func)); - DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs); - DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic); - } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) { - duk_hdecenv *e = (duk_hdecenv *) h; - DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread); - DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap); - DUK__COMMA(); duk_fb_sprintf(fb, "__regbase_byteoff:%ld", (long) e->regbase_byteoff); - } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) { - duk_hobjenv *e = (duk_hobjenv *) h; - DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target); - DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld", (long) e->has_this); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) { - duk_hbufobj *b = (duk_hbufobj *) h; - DUK__COMMA(); duk_fb_sprintf(fb, "__buf:"); - duk__print_hbuffer(st, (duk_hbuffer *) b->buf); - DUK__COMMA(); duk_fb_sprintf(fb, "__buf_prop:"); - duk__print_hobject(st, (duk_hobject *) b->buf_prop); - DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset); - DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length); - DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift); - DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type); -#endif - } else if (st->internal && DUK_HOBJECT_IS_PROXY(h)) { - duk_hproxy *p = (duk_hproxy *) h; - DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); - duk__print_hobject(st, p->target); - DUK__COMMA(); duk_fb_sprintf(fb, "__handler:"); - duk__print_hobject(st, p->handler); - } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) { - duk_hthread *t = (duk_hthread *) h; - DUK__COMMA(); duk_fb_sprintf(fb, "__ptr_curr_pc:%p", (void *) t->ptr_curr_pc); - DUK__COMMA(); duk_fb_sprintf(fb, "__heap:%p", (void *) t->heap); - DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict); - DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state); - DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1); - DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2); - DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack); - DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack)); - DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_alloc_end:%p/%ld", (void *) t->valstack_alloc_end, (long) (t->valstack_alloc_end - t->valstack)); - DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack)); - DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack)); - DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_curr:%p", (void *) t->callstack_curr); - DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_top:%ld", (long) t->callstack_top); - DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_preventcount:%ld", (long) t->callstack_preventcount); - DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer); - DUK__COMMA(); duk_fb_sprintf(fb, "__compile_ctx:%p", (void *) t->compile_ctx); -#if defined(DUK_USE_INTERRUPT_COUNTER) - DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_counter:%ld", (long) t->interrupt_counter); - DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_init:%ld", (long) t->interrupt_init); -#endif - - /* XXX: print built-ins array? */ - - } -#if defined(DUK_USE_REFERENCE_COUNTING) - if (st->internal) { - DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h)); - } -#endif - if (st->internal) { - DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld", (long) DUK_HOBJECT_GET_CLASS_NUMBER(h)); - } - - DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p", (void *) h); /* own pointer */ - - /* prototype should be last, for readability */ - if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) { - if (st->follow_proto) { - DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h)); - } else { - DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p", (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h)); - } - } - - duk_fb_put_cstring(fb, brace2); - -#if defined(DUK_USE_HOBJECT_HASH_PART) - if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) { - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE); - for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) { - duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i); - if (i > 0) { - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); - } - if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) { - duk_fb_sprintf(fb, "u"); - } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) { - duk_fb_sprintf(fb, "d"); - } else { - duk_fb_sprintf(fb, "%ld", (long) h_idx); - } - } - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE); - } -#endif - - finished: - st->depth--; - if (pushed_loopstack) { - st->loop_stack_index--; - st->loop_stack[st->loop_stack_index] = NULL; - } -} - -DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) { - duk_fixedbuffer *fb = st->fb; - duk_size_t i, n; - duk_uint8_t *p; - - if (duk_fb_is_full(fb)) { - return; - } - - /* terminal type: no depth check */ - - if (!h) { - duk_fb_put_cstring(fb, "NULL"); - return; - } - - if (DUK_HBUFFER_HAS_DYNAMIC(h)) { - if (DUK_HBUFFER_HAS_EXTERNAL(h)) { - duk_hbuffer_external *g = (duk_hbuffer_external *) h; - duk_fb_sprintf(fb, "buffer:external:%p:%ld", - (void *) DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(NULL, g), - (long) DUK_HBUFFER_EXTERNAL_GET_SIZE(g)); - } else { - duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h; - duk_fb_sprintf(fb, "buffer:dynamic:%p:%ld", - (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(NULL, g), - (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(g)); - } - } else { - duk_fb_sprintf(fb, "buffer:fixed:%ld", (long) DUK_HBUFFER_GET_SIZE(h)); - } - -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr)); -#endif - - if (st->hexdump) { - duk_fb_sprintf(fb, "=["); - n = DUK_HBUFFER_GET_SIZE(h); - p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(NULL, h); - for (i = 0; i < n; i++) { - duk_fb_sprintf(fb, "%02lx", (unsigned long) p[i]); - } - duk_fb_sprintf(fb, "]"); - } -} - -DUK_LOCAL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) { - duk_fixedbuffer *fb = st->fb; - - if (duk_fb_is_full(fb)) { - return; - } - - if (!h) { - duk_fb_put_cstring(fb, "NULL"); - return; - } - - switch (DUK_HEAPHDR_GET_TYPE(h)) { - case DUK_HTYPE_STRING: - duk__print_hstring(st, (duk_hstring *) h, 1); - break; - case DUK_HTYPE_OBJECT: - duk__print_hobject(st, (duk_hobject *) h); - break; - case DUK_HTYPE_BUFFER: - duk__print_hbuffer(st, (duk_hbuffer *) h); - break; - default: - duk_fb_sprintf(fb, "[unknown htype %ld]", (long) DUK_HEAPHDR_GET_TYPE(h)); - break; - } -} - -DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) { - duk_fixedbuffer *fb = st->fb; - - if (duk_fb_is_full(fb)) { - return; - } - - /* depth check is done when printing an actual type */ - - if (st->heavy) { - duk_fb_sprintf(fb, "(%p)", (void *) tv); - } - - if (!tv) { - duk_fb_put_cstring(fb, "NULL"); - return; - } - - if (st->binary) { - duk_size_t i; - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET); - for (i = 0; i < (duk_size_t) sizeof(*tv); i++) { - duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)tv)[i]); - } - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET); - } - - if (st->heavy) { - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE); - } - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: { - duk_fb_put_cstring(fb, "undefined"); - break; - } - case DUK_TAG_UNUSED: { - duk_fb_put_cstring(fb, "unused"); - break; - } - case DUK_TAG_NULL: { - duk_fb_put_cstring(fb, "null"); - break; - } - case DUK_TAG_BOOLEAN: { - duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false"); - break; - } - case DUK_TAG_STRING: { - /* Note: string is a terminal heap object, so no depth check here */ - duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1); - break; - } - case DUK_TAG_OBJECT: { - duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv)); - break; - } - case DUK_TAG_BUFFER: { - duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv)); - break; - } - case DUK_TAG_POINTER: { - duk_fb_sprintf(fb, "pointer:%p", (void *) DUK_TVAL_GET_POINTER(tv)); - break; - } - case DUK_TAG_LIGHTFUNC: { - duk_c_function func; - duk_small_uint_t lf_flags; - - DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); - duk_fb_sprintf(fb, "lightfunc:"); - duk_fb_put_funcptr(fb, (duk_uint8_t *) &func, sizeof(func)); - duk_fb_sprintf(fb, ":%04lx", (long) lf_flags); - break; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - duk_fb_sprintf(fb, "%.18g_F", (double) DUK_TVAL_GET_NUMBER(tv)); - break; -#endif - default: { - /* IEEE double is approximately 16 decimal digits; print a couple extra */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - duk_fb_sprintf(fb, "%.18g", (double) DUK_TVAL_GET_NUMBER(tv)); - break; - } - } - if (st->heavy) { - duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE); - } -} - -DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) { - duk_fixedbuffer *fb = st->fb; - duk_small_int_t op; - const char *op_name; - - op = (duk_small_int_t) DUK_DEC_OP(ins); - op_name = duk__bc_optab[op]; - - /* XXX: option to fix opcode length so it lines up nicely */ - - if (op == DUK_OP_JUMP) { - duk_int_t diff1 = (duk_int_t) (DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS); /* from next pc */ - duk_int_t diff2 = diff1 + 1; /* from curr pc */ - - duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)", - (const char *) op_name, (long) diff1, - (int) (diff2 >= 0 ? '+' : '-'), /* char format: use int */ - (long) (diff2 >= 0 ? diff2 : -diff2)); - } else { - duk_fb_sprintf(fb, "%s %ld, %ld, %ld", - (const char *) op_name, (long) DUK_DEC_A(ins), - (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins)); - } -} - -DUK_LOCAL void duk__print_opcode(duk__dprint_state *st, duk_small_int_t opcode) { - duk_fixedbuffer *fb = st->fb; - - if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) { - duk_fb_sprintf(fb, "?(%ld)", (long) opcode); - } else { - duk_fb_sprintf(fb, "%s", (const char *) duk__bc_optab[opcode]); - } -} - -DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap) { - duk_fixedbuffer fb; - const char *p = format; - const char *p_end = p + DUK_STRLEN(format); - duk_int_t retval; - - DUK_MEMZERO(&fb, sizeof(fb)); - fb.buffer = (duk_uint8_t *) str; - fb.length = size; - fb.offset = 0; - fb.truncated = 0; - - while (p < p_end) { - char ch = *p++; - const char *p_begfmt = NULL; - duk_bool_t got_exclamation = 0; - duk_bool_t got_long = 0; /* %lf, %ld etc */ - duk__dprint_state st; - - if (ch != DUK_ASC_PERCENT) { - duk_fb_put_byte(&fb, (duk_uint8_t) ch); - continue; - } - - /* - * Format tag parsing. Since we don't understand all the - * possible format tags allowed, we just scan for a terminating - * specifier and keep track of relevant modifiers that we do - * understand. See man 3 printf. - */ - - DUK_MEMZERO(&st, sizeof(st)); - st.fb = &fb; - st.depth = 0; - st.depth_limit = 1; - st.loop_stack_index = 0; - st.loop_stack_limit = DUK__LOOP_STACK_DEPTH; - - p_begfmt = p - 1; - while (p < p_end) { - ch = *p++; - - if (ch == DUK_ASC_STAR) { - /* unsupported: would consume multiple args */ - goto format_error; - } else if (ch == DUK_ASC_PERCENT) { - duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT); - break; - } else if (ch == DUK_ASC_EXCLAMATION) { - got_exclamation = 1; - } else if (!got_exclamation && ch == DUK_ASC_LC_L) { - got_long = 1; - } else if (got_exclamation && ch == DUK_ASC_LC_D) { - st.depth_limit = DUK__DEEP_DEPTH_LIMIT; - } else if (got_exclamation && ch == DUK_ASC_LC_P) { - st.follow_proto = 1; - } else if (got_exclamation && ch == DUK_ASC_LC_I) { - st.internal = 1; - } else if (got_exclamation && ch == DUK_ASC_LC_X) { - st.hexdump = 1; - } else if (got_exclamation && ch == DUK_ASC_LC_H) { - st.heavy = 1; - } else if (got_exclamation && ch == DUK_ASC_ATSIGN) { - st.pointer = 1; - } else if (got_exclamation && ch == DUK_ASC_HASH) { - st.binary = 1; - } else if (got_exclamation && ch == DUK_ASC_UC_T) { - duk_tval *t = va_arg(ap, duk_tval *); - if (st.pointer && !st.heavy) { - duk_fb_sprintf(&fb, "(%p)", (void *) t); - } - duk__print_tval(&st, t); - break; - } else if (got_exclamation && ch == DUK_ASC_UC_O) { - duk_heaphdr *t = va_arg(ap, duk_heaphdr *); - if (st.pointer && !st.heavy) { - duk_fb_sprintf(&fb, "(%p)", (void *) t); - } - duk__print_heaphdr(&st, t); - break; - } else if (got_exclamation && ch == DUK_ASC_UC_I) { - duk_instr_t t = va_arg(ap, duk_instr_t); - duk__print_instr(&st, t); - break; - } else if (got_exclamation && ch == DUK_ASC_UC_C) { - long t = va_arg(ap, long); - duk__print_opcode(&st, (duk_small_int_t) t); - break; - } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) { - char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH]; - duk_size_t fmtlen; - - DUK_ASSERT(p >= p_begfmt); - fmtlen = (duk_size_t) (p - p_begfmt); - if (fmtlen >= sizeof(fmtbuf)) { - /* format is too large, abort */ - goto format_error; - } - DUK_MEMZERO(fmtbuf, sizeof(fmtbuf)); - DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen); - - /* assume exactly 1 arg, which is why '*' is forbidden; arg size still - * depends on type though. - */ - - if (ch == DUK_ASC_LC_F || ch == DUK_ASC_LC_G || ch == DUK_ASC_LC_E) { - /* %f and %lf both consume a 'long' */ - double arg = va_arg(ap, double); - duk_fb_sprintf(&fb, fmtbuf, arg); - } else if (ch == DUK_ASC_LC_D && got_long) { - /* %ld */ - long arg = va_arg(ap, long); - duk_fb_sprintf(&fb, fmtbuf, arg); - } else if (ch == DUK_ASC_LC_D) { - /* %d; only 16 bits are guaranteed */ - int arg = va_arg(ap, int); - duk_fb_sprintf(&fb, fmtbuf, arg); - } else if (ch == DUK_ASC_LC_U && got_long) { - /* %lu */ - unsigned long arg = va_arg(ap, unsigned long); - duk_fb_sprintf(&fb, fmtbuf, arg); - } else if (ch == DUK_ASC_LC_U) { - /* %u; only 16 bits are guaranteed */ - unsigned int arg = va_arg(ap, unsigned int); - duk_fb_sprintf(&fb, fmtbuf, arg); - } else if (ch == DUK_ASC_LC_X && got_long) { - /* %lx */ - unsigned long arg = va_arg(ap, unsigned long); - duk_fb_sprintf(&fb, fmtbuf, arg); - } else if (ch == DUK_ASC_LC_X) { - /* %x; only 16 bits are guaranteed */ - unsigned int arg = va_arg(ap, unsigned int); - duk_fb_sprintf(&fb, fmtbuf, arg); - } else if (ch == DUK_ASC_LC_S) { - /* %s */ - const char *arg = va_arg(ap, const char *); - if (arg == NULL) { - /* '%s' and NULL is not portable, so special case - * it for debug printing. - */ - duk_fb_sprintf(&fb, "NULL"); - } else { - duk_fb_sprintf(&fb, fmtbuf, arg); - } - } else if (ch == DUK_ASC_LC_P) { - /* %p */ - void *arg = va_arg(ap, void *); - if (arg == NULL) { - /* '%p' and NULL is portable, but special case it - * anyway to get a standard NULL marker in logs. - */ - duk_fb_sprintf(&fb, "NULL"); - } else { - duk_fb_sprintf(&fb, fmtbuf, arg); - } - } else if (ch == DUK_ASC_LC_C) { - /* '%c', passed concretely as int */ - int arg = va_arg(ap, int); - duk_fb_sprintf(&fb, fmtbuf, arg); - } else { - /* Should not happen. */ - duk_fb_sprintf(&fb, "INVALID-FORMAT(%s)", (const char *) fmtbuf); - } - break; - } else { - /* ignore */ - } - } - } - goto done; - - format_error: - duk_fb_put_cstring(&fb, "FMTERR"); - /* fall through */ - - done: - retval = (duk_int_t) fb.offset; - duk_fb_put_byte(&fb, (duk_uint8_t) 0); - - /* return total chars written excluding terminator */ - return retval; -} - -#if 0 /*unused*/ -DUK_INTERNAL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...) { - duk_int_t retval; - va_list ap; - va_start(ap, format); - retval = duk_debug_vsnprintf(str, size, format, ap); - va_end(ap); - return retval; -} -#endif - -/* Formatting function pointers is tricky: there is no standard pointer for - * function pointers and the size of a function pointer may depend on the - * specific pointer type. This helper formats a function pointer based on - * its memory layout to get something useful on most platforms. - */ -DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size) { - duk_size_t i; - duk_uint8_t *p = (duk_uint8_t *) buf; - duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1); - - DUK_MEMZERO(buf, buf_size); - - for (i = 0; i < fptr_size; i++) { - duk_int_t left = (duk_int_t) (p_end - p); - duk_uint8_t ch; - if (left <= 0) { - break; - } - - /* Quite approximate but should be useful for little and big endian. */ -#if defined(DUK_USE_INTEGER_BE) - ch = fptr[i]; -#else - ch = fptr[fptr_size - 1 - i]; -#endif - p += DUK_SNPRINTF((char *) p, (duk_size_t) left, "%02lx", (unsigned long) ch); - } -} - -#endif /* DUK_USE_DEBUG */ - -/* automatic undefs */ -#undef DUK__ALLOWED_STANDARD_SPECIFIERS -#undef DUK__COMMA -#undef DUK__DEEP_DEPTH_LIMIT -#undef DUK__LOOP_STACK_DEPTH -#undef DUK__MAX_FORMAT_TAG_LENGTH -#line 1 "duk_debugger.c" -/* - * Duktape debugger - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - -/* - * Assert helpers - */ - -#if defined(DUK_USE_ASSERTIONS) -#define DUK__DBG_TPORT_ENTER() do { \ - DUK_ASSERT(heap->dbg_calling_transport == 0); \ - heap->dbg_calling_transport = 1; \ - } while (0) -#define DUK__DBG_TPORT_EXIT() do { \ - DUK_ASSERT(heap->dbg_calling_transport == 1); \ - heap->dbg_calling_transport = 0; \ - } while (0) -#else -#define DUK__DBG_TPORT_ENTER() do {} while (0) -#define DUK__DBG_TPORT_EXIT() do {} while (0) -#endif - -/* - * Helper structs - */ - -typedef union { - void *p; - duk_uint_t b[1]; - /* Use b[] to access the size of the union, which is strictly not - * correct. Can't use fixed size unless there's feature detection - * for pointer byte size. - */ -} duk__ptr_union; - -/* - * Detach handling - */ - -#define DUK__SET_CONN_BROKEN(thr,reason) do { \ - /* For now shared handler is fine. */ \ - duk__debug_do_detach1((thr)->heap, (reason)); \ - } while (0) - -DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) { - /* Can be called multiple times with no harm. Mark the transport - * bad (dbg_read_cb == NULL) and clear state except for the detached - * callback and the udata field. The detached callback is delayed - * to the message loop so that it can be called between messages; - * this avoids corner cases related to immediate debugger reattach - * inside the detached callback. - */ - - if (heap->dbg_detaching) { - DUK_D(DUK_DPRINT("debugger already detaching, ignore detach1")); - return; - } - - DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken")); - - heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */ - - if (heap->dbg_write_cb != NULL) { - duk_hthread *thr; - - thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); - - duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING); - duk_debug_write_int(thr, reason); - duk_debug_write_eom(thr); - } - - heap->dbg_read_cb = NULL; - heap->dbg_write_cb = NULL; - heap->dbg_peek_cb = NULL; - heap->dbg_read_flush_cb = NULL; - heap->dbg_write_flush_cb = NULL; - heap->dbg_request_cb = NULL; - /* heap->dbg_detached_cb: keep */ - /* heap->dbg_udata: keep */ - /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */ - heap->dbg_state_dirty = 0; - heap->dbg_force_restart = 0; - heap->dbg_pause_flags = 0; - heap->dbg_pause_act = NULL; - heap->dbg_pause_startline = 0; - heap->dbg_have_next_byte = 0; - duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */ - heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */ - - /* Ensure there are no stale active breakpoint pointers. - * Breakpoint list is currently kept - we could empty it - * here but we'd need to handle refcounts correctly, and - * we'd need a 'thr' reference for that. - * - * XXX: clear breakpoint on either attach or detach? - */ - heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; -} - -DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) { - duk_debug_detached_function detached_cb; - void *detached_udata; - duk_hthread *thr; - - thr = heap->heap_thread; - if (thr == NULL) { - DUK_ASSERT(heap->dbg_detached_cb == NULL); - return; - } - - /* Safe to call multiple times. */ - - detached_cb = heap->dbg_detached_cb; - detached_udata = heap->dbg_udata; - heap->dbg_detached_cb = NULL; - heap->dbg_udata = NULL; - - if (detached_cb) { - /* Careful here: state must be wiped before the call - * so that we can cleanly handle a re-attach from - * inside the callback. - */ - DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb")); - detached_cb(thr, detached_udata); - } - - heap->dbg_detaching = 0; -} - -DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) { - duk__debug_do_detach1(heap, 0); - duk__debug_do_detach2(heap); -} - -/* Called on a read/write error: NULL all callbacks except the detached - * callback so that we never accidentally call them after a read/write - * error has been indicated. This is especially important for the transport - * I/O callbacks to fulfill guaranteed callback semantics. - */ -DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) { - duk_heap *heap; - - DUK_ASSERT(thr != NULL); - - heap = thr->heap; - DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached")); - heap->dbg_read_cb = NULL; - heap->dbg_write_cb = NULL; /* this is especially critical to avoid another write call in detach1() */ - heap->dbg_peek_cb = NULL; - heap->dbg_read_flush_cb = NULL; - heap->dbg_write_flush_cb = NULL; - heap->dbg_request_cb = NULL; - /* keep heap->dbg_detached_cb */ -} - -/* - * Pause handling - */ - -DUK_LOCAL void duk__debug_set_pause_state(duk_hthread *thr, duk_heap *heap, duk_small_uint_t pause_flags) { - duk_uint_fast32_t line; - - line = duk_debug_curr_line(thr); - if (line == 0) { - /* No line info for current function. */ - duk_small_uint_t updated_flags; - - updated_flags = pause_flags & ~(DUK_PAUSE_FLAG_LINE_CHANGE); - DUK_D(DUK_DPRINT("no line info for current activation, disable line-based pause flags: 0x%08lx -> 0x%08lx", - (long) pause_flags, (long) updated_flags)); - pause_flags = updated_flags; - } - - heap->dbg_pause_flags = pause_flags; - heap->dbg_pause_act = thr->callstack_curr; - heap->dbg_pause_startline = (duk_uint32_t) line; - heap->dbg_state_dirty = 1; - - DUK_D(DUK_DPRINT("set state for automatic pause triggers, flags=0x%08lx, act=%p, startline=%ld", - (long) heap->dbg_pause_flags, (void *) heap->dbg_pause_act, - (long) heap->dbg_pause_startline)); -} - -/* - * Debug connection peek and flush primitives - */ - -DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) { - duk_heap *heap; - duk_bool_t ret; - - DUK_ASSERT(thr != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - if (heap->dbg_read_cb == NULL) { - DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)")); - return 0; - } - if (heap->dbg_peek_cb == NULL) { - DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)")); - return 0; - } - - DUK__DBG_TPORT_ENTER(); - ret = (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0); - DUK__DBG_TPORT_EXIT(); - return ret; -} - -DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) { - duk_heap *heap; - - DUK_ASSERT(thr != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - if (heap->dbg_read_cb == NULL) { - DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore")); - return; - } - if (heap->dbg_read_flush_cb == NULL) { - DUK_DD(DUK_DDPRINT("no read flush callback, ignore")); - return; - } - - DUK__DBG_TPORT_ENTER(); - heap->dbg_read_flush_cb(heap->dbg_udata); - DUK__DBG_TPORT_EXIT(); -} - -DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) { - duk_heap *heap; - - DUK_ASSERT(thr != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - if (heap->dbg_read_cb == NULL) { - DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore")); - return; - } - if (heap->dbg_write_flush_cb == NULL) { - DUK_DD(DUK_DDPRINT("no write flush callback, ignore")); - return; - } - - DUK__DBG_TPORT_ENTER(); - heap->dbg_write_flush_cb(heap->dbg_udata); - DUK__DBG_TPORT_EXIT(); -} - -/* - * Debug connection skip primitives - */ - -/* Skip fully. */ -DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) { - duk_uint8_t dummy[64]; - duk_size_t now; - - DUK_ASSERT(thr != NULL); - - while (length > 0) { - now = (length > sizeof(dummy) ? sizeof(dummy) : length); - duk_debug_read_bytes(thr, dummy, now); - length -= now; - } -} - -DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - - (void) duk_debug_read_byte(thr); -} - -/* - * Debug connection read primitives - */ - -/* Peek ahead in the stream one byte. */ -DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) { - /* It is important not to call this if the last byte read was an EOM. - * Reading ahead in this scenario would cause unnecessary blocking if - * another message is not available. - */ - - duk_uint8_t x; - - x = duk_debug_read_byte(thr); - thr->heap->dbg_have_next_byte = 1; - thr->heap->dbg_next_byte = x; - return x; -} - -/* Read fully. */ -DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) { - duk_heap *heap; - duk_uint8_t *p; - duk_size_t left; - duk_size_t got; - - DUK_ASSERT(thr != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - if (heap->dbg_read_cb == NULL) { - DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length)); - goto fail; - } - - /* NOTE: length may be zero */ - p = data; - if (length >= 1 && heap->dbg_have_next_byte) { - heap->dbg_have_next_byte = 0; - *p++ = heap->dbg_next_byte; - } - for (;;) { - left = (duk_size_t) ((data + length) - p); - if (left == 0) { - break; - } - DUK_ASSERT(heap->dbg_read_cb != NULL); - DUK_ASSERT(left >= 1); -#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE) - left = 1; -#endif - DUK__DBG_TPORT_ENTER(); - got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left); - DUK__DBG_TPORT_EXIT(); - - if (got == 0 || got > left) { - DUK_D(DUK_DPRINT("connection error during read, return zero data")); - duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */ - DUK__SET_CONN_BROKEN(thr, 1); - goto fail; - } - p += got; - } - return; - - fail: - DUK_MEMZERO((void *) data, (size_t) length); -} - -DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) { - duk_uint8_t x; - - x = 0; /* just in case callback is broken and won't write 'x' */ - duk_debug_read_bytes(thr, &x, 1); - return x; -} - -DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) { - duk_uint8_t buf[4]; - - DUK_ASSERT(thr != NULL); - - duk_debug_read_bytes(thr, buf, 4); - return ((duk_uint32_t) buf[0] << 24) | - ((duk_uint32_t) buf[1] << 16) | - ((duk_uint32_t) buf[2] << 8) | - (duk_uint32_t) buf[3]; -} - -DUK_LOCAL duk_int32_t duk__debug_read_int32_raw(duk_hthread *thr) { - return (duk_int32_t) duk__debug_read_uint32_raw(thr); -} - -DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) { - duk_uint8_t buf[2]; - - DUK_ASSERT(thr != NULL); - - duk_debug_read_bytes(thr, buf, 2); - return ((duk_uint16_t) buf[0] << 8) | - (duk_uint16_t) buf[1]; -} - -DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) { - duk_small_uint_t x; - duk_small_uint_t t; - - DUK_ASSERT(thr != NULL); - - x = duk_debug_read_byte(thr); - if (x >= 0xc0) { - t = duk_debug_read_byte(thr); - return (duk_int32_t) (((x - 0xc0) << 8) + t); - } else if (x >= 0x80) { - return (duk_int32_t) (x - 0x80); - } else if (x == DUK_DBG_IB_INT4) { - return (duk_int32_t) duk__debug_read_uint32_raw(thr); - } - - DUK_D(DUK_DPRINT("debug connection error: failed to decode int")); - DUK__SET_CONN_BROKEN(thr, 1); - return 0; -} - -DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) { - duk_uint8_t buf[31]; - duk_uint8_t *p; - - if (len <= sizeof(buf)) { - duk_debug_read_bytes(thr, buf, (duk_size_t) len); - duk_push_lstring(thr, (const char *) buf, (duk_size_t) len); - } else { - p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */ - DUK_ASSERT(p != NULL); - duk_debug_read_bytes(thr, p, (duk_size_t) len); - (void) duk_buffer_to_string(thr, -1); /* Safety relies on debug client, which is OK. */ - } - - return duk_require_hstring(thr, -1); -} - -DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) { - duk_small_uint_t x; - duk_uint32_t len; - - DUK_ASSERT(thr != NULL); - - x = duk_debug_read_byte(thr); - if (x >= 0x60 && x <= 0x7f) { - /* For short strings, use a fixed temp buffer. */ - len = (duk_uint32_t) (x - 0x60); - } else if (x == DUK_DBG_IB_STR2) { - len = (duk_uint32_t) duk__debug_read_uint16_raw(thr); - } else if (x == DUK_DBG_IB_STR4) { - len = (duk_uint32_t) duk__debug_read_uint32_raw(thr); - } else { - goto fail; - } - - return duk__debug_read_hstring_raw(thr, len); - - fail: - DUK_D(DUK_DPRINT("debug connection error: failed to decode int")); - DUK__SET_CONN_BROKEN(thr, 1); - duk_push_hstring_empty(thr); /* always push some string */ - return duk_require_hstring(thr, -1); -} - -DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) { - duk_uint8_t *p; - - p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */ - DUK_ASSERT(p != NULL); - duk_debug_read_bytes(thr, p, (duk_size_t) len); - - return duk_require_hbuffer(thr, -1); -} - -DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) { - duk_small_uint_t x; - duk__ptr_union pu; - - DUK_ASSERT(thr != NULL); - - x = duk_debug_read_byte(thr); - if (x != sizeof(pu)) { - goto fail; - } - duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu)); -#if defined(DUK_USE_INTEGER_LE) - duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu)); -#endif - return (void *) pu.p; - - fail: - DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer")); - DUK__SET_CONN_BROKEN(thr, 1); - return (void *) NULL; -} - -DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) { - duk_double_union du; - - DUK_ASSERT(sizeof(du.uc) == 8); - duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc)); - DUK_DBLUNION_DOUBLE_NTOH(&du); - return du.d; -} - -#if 0 -DUK_INTERNAL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr) { - duk_small_uint_t x; - - DUK_ASSERT(thr != NULL); - - x = duk_debug_read_byte(thr); - if (x != DUK_DBG_IB_HEAPPTR) { - goto fail; - } - - return (duk_heaphdr *) duk__debug_read_pointer_raw(thr); - - fail: - DUK_D(DUK_DPRINT("debug connection error: failed to decode heapptr")); - DUK__SET_CONN_BROKEN(thr, 1); - return NULL; -} -#endif - -DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) { - duk_small_uint_t x; - - DUK_ASSERT(thr != NULL); - - x = duk_debug_read_byte(thr); - switch (x) { - case DUK_DBG_IB_OBJECT: - case DUK_DBG_IB_POINTER: - case DUK_DBG_IB_HEAPPTR: - /* Accept any pointer-like value; for 'object' dvalue, read - * and ignore the class number. - */ - if (x == DUK_DBG_IB_OBJECT) { - duk_debug_skip_byte(thr); - } - break; - default: - goto fail; - } - - return (duk_heaphdr *) duk__debug_read_pointer_raw(thr); - - fail: - DUK_D(DUK_DPRINT("debug connection error: failed to decode any pointer (object, pointer, heapptr)")); - DUK__SET_CONN_BROKEN(thr, 1); - return NULL; -} - -DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) { - duk_uint8_t x; - duk_uint_t t; - duk_uint32_t len; - - DUK_ASSERT(thr != NULL); - - x = duk_debug_read_byte(thr); - - if (x >= 0xc0) { - t = (duk_uint_t) (x - 0xc0); - t = (t << 8) + duk_debug_read_byte(thr); - duk_push_uint(thr, (duk_uint_t) t); - goto return_ptr; - } - if (x >= 0x80) { - duk_push_uint(thr, (duk_uint_t) (x - 0x80)); - goto return_ptr; - } - if (x >= 0x60) { - len = (duk_uint32_t) (x - 0x60); - duk__debug_read_hstring_raw(thr, len); - goto return_ptr; - } - - switch (x) { - case DUK_DBG_IB_INT4: { - duk_int32_t i = duk__debug_read_int32_raw(thr); - duk_push_i32(thr, i); - break; - } - case DUK_DBG_IB_STR4: { - len = duk__debug_read_uint32_raw(thr); - duk__debug_read_hstring_raw(thr, len); - break; - } - case DUK_DBG_IB_STR2: { - len = duk__debug_read_uint16_raw(thr); - duk__debug_read_hstring_raw(thr, len); - break; - } - case DUK_DBG_IB_BUF4: { - len = duk__debug_read_uint32_raw(thr); - duk__debug_read_hbuffer_raw(thr, len); - break; - } - case DUK_DBG_IB_BUF2: { - len = duk__debug_read_uint16_raw(thr); - duk__debug_read_hbuffer_raw(thr, len); - break; - } - case DUK_DBG_IB_UNDEFINED: { - duk_push_undefined(thr); - break; - } - case DUK_DBG_IB_NULL: { - duk_push_null(thr); - break; - } - case DUK_DBG_IB_TRUE: { - duk_push_true(thr); - break; - } - case DUK_DBG_IB_FALSE: { - duk_push_false(thr); - break; - } - case DUK_DBG_IB_NUMBER: { - duk_double_t d; - d = duk__debug_read_double_raw(thr); - duk_push_number(thr, d); - break; - } - case DUK_DBG_IB_OBJECT: { - duk_heaphdr *h; - duk_debug_skip_byte(thr); - h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr); - duk_push_heapptr(thr, (void *) h); - break; - } - case DUK_DBG_IB_POINTER: { - void *ptr; - ptr = duk__debug_read_pointer_raw(thr); - duk_push_pointer(thr, ptr); - break; - } - case DUK_DBG_IB_LIGHTFUNC: { - /* XXX: Not needed for now, so not implemented. Note that - * function pointers may have different size/layout than - * a void pointer. - */ - DUK_D(DUK_DPRINT("reading lightfunc values unimplemented")); - goto fail; - } - case DUK_DBG_IB_HEAPPTR: { - duk_heaphdr *h; - h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr); - duk_push_heapptr(thr, (void *) h); - break; - } - case DUK_DBG_IB_UNUSED: /* unused: not accepted in inbound messages */ - default: - goto fail; - } - - return_ptr: - return DUK_GET_TVAL_NEGIDX(thr, -1); - - fail: - DUK_D(DUK_DPRINT("debug connection error: failed to decode tval")); - DUK__SET_CONN_BROKEN(thr, 1); - return NULL; -} - -/* - * Debug connection write primitives - */ - -/* Write fully. */ -DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) { - duk_heap *heap; - const duk_uint8_t *p; - duk_size_t left; - duk_size_t got; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(length == 0 || data != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - if (heap->dbg_write_cb == NULL) { - DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore", (long) length)); - return; - } - if (length == 0) { - /* Avoid doing an actual write callback with length == 0, - * because that's reserved for a write flush. - */ - return; - } - DUK_ASSERT(data != NULL); - - p = data; - for (;;) { - left = (duk_size_t) ((data + length) - p); - if (left == 0) { - break; - } - DUK_ASSERT(heap->dbg_write_cb != NULL); - DUK_ASSERT(left >= 1); -#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE) - left = 1; -#endif - DUK__DBG_TPORT_ENTER(); - got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left); - DUK__DBG_TPORT_EXIT(); - - if (got == 0 || got > left) { - duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */ - DUK_D(DUK_DPRINT("connection error during write")); - DUK__SET_CONN_BROKEN(thr, 1); - return; - } - p += got; - } -} - -DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) { - duk_debug_write_bytes(thr, (const duk_uint8_t *) &x, 1); -} - -DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) { - duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED); -} - -DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) { - duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED); -} - -#if defined(DUK_USE_DEBUGGER_INSPECT) -DUK_INTERNAL void duk_debug_write_null(duk_hthread *thr) { - duk_debug_write_byte(thr, DUK_DBG_IB_NULL); -} -#endif - -DUK_INTERNAL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val) { - duk_debug_write_byte(thr, val ? DUK_DBG_IB_TRUE : DUK_DBG_IB_FALSE); -} - -/* Write signed 32-bit integer. */ -DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) { - duk_uint8_t buf[5]; - duk_size_t len; - - DUK_ASSERT(thr != NULL); - - if (x >= 0 && x <= 0x3fL) { - buf[0] = (duk_uint8_t) (0x80 + x); - len = 1; - } else if (x >= 0 && x <= 0x3fffL) { - buf[0] = (duk_uint8_t) (0xc0 + (x >> 8)); - buf[1] = (duk_uint8_t) (x & 0xff); - len = 2; - } else { - /* Signed integers always map to 4 bytes now. */ - buf[0] = (duk_uint8_t) DUK_DBG_IB_INT4; - buf[1] = (duk_uint8_t) ((x >> 24) & 0xff); - buf[2] = (duk_uint8_t) ((x >> 16) & 0xff); - buf[3] = (duk_uint8_t) ((x >> 8) & 0xff); - buf[4] = (duk_uint8_t) (x & 0xff); - len = 5; - } - duk_debug_write_bytes(thr, buf, len); -} - -/* Write unsigned 32-bit integer. */ -DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) { - /* The debugger protocol doesn't support a plain integer encoding for - * the full 32-bit unsigned range (only 32-bit signed). For now, - * unsigned 32-bit values simply written as signed ones. This is not - * a concrete issue except for 32-bit heaphdr fields. Proper solutions - * would be to (a) write such integers as IEEE doubles or (b) add an - * unsigned 32-bit dvalue. - */ - if (x >= 0x80000000UL) { - DUK_D(DUK_DPRINT("writing unsigned integer 0x%08lx as signed integer", - (long) x)); - } - duk_debug_write_int(thr, (duk_int32_t) x); -} - -DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) { - duk_uint8_t buf[5]; - duk_size_t buflen; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(length == 0 || data != NULL); - - if (length <= 0x1fUL && marker_base == DUK_DBG_IB_STR4) { - /* For strings, special form for short lengths. */ - buf[0] = (duk_uint8_t) (0x60 + length); - buflen = 1; - } else if (length <= 0xffffUL) { - buf[0] = (duk_uint8_t) (marker_base + 1); - buf[1] = (duk_uint8_t) (length >> 8); - buf[2] = (duk_uint8_t) (length & 0xff); - buflen = 3; - } else { - buf[0] = (duk_uint8_t) marker_base; - buf[1] = (duk_uint8_t) (length >> 24); - buf[2] = (duk_uint8_t) ((length >> 16) & 0xff); - buf[3] = (duk_uint8_t) ((length >> 8) & 0xff); - buf[4] = (duk_uint8_t) (length & 0xff); - buflen = 5; - } - - duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen); - duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length); -} - -DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) { - duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_STR4); -} - -DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) { - DUK_ASSERT(thr != NULL); - - duk_debug_write_string(thr, - data, - data ? DUK_STRLEN(data) : 0); -} - -DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) { - DUK_ASSERT(thr != NULL); - - /* XXX: differentiate null pointer from empty string? */ - duk_debug_write_string(thr, - (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL), - (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0)); -} - -DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) { - duk_debug_write_hstring(thr, duk_safe_to_hstring(thr, -1)); -} - -DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) { - duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_BUF4); -} - -DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) { - DUK_ASSERT(thr != NULL); - - duk_debug_write_buffer(thr, - (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL), - (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0)); -} - -DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) { - duk_uint8_t buf[2]; - duk__ptr_union pu; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16); - /* ptr may be NULL */ - - buf[0] = ibyte; - buf[1] = sizeof(pu); - duk_debug_write_bytes(thr, buf, 2); - pu.p = (void *) ptr; -#if defined(DUK_USE_INTEGER_LE) - duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu)); -#endif - duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu)); -} - -DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) { - duk__debug_write_pointer_raw(thr, ptr, DUK_DBG_IB_POINTER); -} - -#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT) -DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) { - duk__debug_write_pointer_raw(thr, (void *) h, DUK_DBG_IB_HEAPPTR); -} -#endif /* DUK_USE_DEBUGGER_DUMPHEAP || DUK_USE_DEBUGGER_INSPECT */ - -DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) { - duk_uint8_t buf[3]; - duk__ptr_union pu; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16); - DUK_ASSERT(obj != NULL); - - buf[0] = DUK_DBG_IB_OBJECT; - buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj); - buf[2] = sizeof(pu); - duk_debug_write_bytes(thr, buf, 3); - pu.p = (void *) obj; -#if defined(DUK_USE_INTEGER_LE) - duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu)); -#endif - duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu)); -} - -DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) { - duk_c_function lf_func; - duk_small_uint_t lf_flags; - duk_uint8_t buf[4]; - duk_double_union du1; - duk_double_union du2; - duk_int32_t i32; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: - duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED); - break; - case DUK_TAG_UNUSED: - duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED); - break; - case DUK_TAG_NULL: - duk_debug_write_byte(thr, DUK_DBG_IB_NULL); - break; - case DUK_TAG_BOOLEAN: - DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 || - DUK_TVAL_GET_BOOLEAN(tv) == 1); - duk_debug_write_boolean(thr, DUK_TVAL_GET_BOOLEAN(tv)); - break; - case DUK_TAG_POINTER: - duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv)); - break; - case DUK_TAG_LIGHTFUNC: - DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags); - buf[0] = DUK_DBG_IB_LIGHTFUNC; - buf[1] = (duk_uint8_t) (lf_flags >> 8); - buf[2] = (duk_uint8_t) (lf_flags & 0xff); - buf[3] = sizeof(lf_func); - duk_debug_write_bytes(thr, buf, 4); - duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func)); - break; - case DUK_TAG_STRING: - duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv)); - break; - case DUK_TAG_OBJECT: - duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv)); - break; - case DUK_TAG_BUFFER: - duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv)); - break; -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: - /* Numbers are normalized to big (network) endian. We can - * (but are not required) to use integer dvalues when there's - * no loss of precision. - * - * XXX: share check with other code; this check is slow but - * reliable and doesn't require careful exponent/mantissa - * mask tricks as in the fastint downgrade code. - */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - du1.d = DUK_TVAL_GET_NUMBER(tv); - i32 = (duk_int32_t) du1.d; - du2.d = (duk_double_t) i32; - - DUK_DD(DUK_DDPRINT("i32=%ld du1=%02x%02x%02x%02x%02x%02x%02x%02x " - "du2=%02x%02x%02x%02x%02x%02x%02x%02x", - (long) i32, - (unsigned int) du1.uc[0], (unsigned int) du1.uc[1], - (unsigned int) du1.uc[2], (unsigned int) du1.uc[3], - (unsigned int) du1.uc[4], (unsigned int) du1.uc[5], - (unsigned int) du1.uc[6], (unsigned int) du1.uc[7], - (unsigned int) du2.uc[0], (unsigned int) du2.uc[1], - (unsigned int) du2.uc[2], (unsigned int) du2.uc[3], - (unsigned int) du2.uc[4], (unsigned int) du2.uc[5], - (unsigned int) du2.uc[6], (unsigned int) du2.uc[7])); - - if (DUK_MEMCMP((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) { - duk_debug_write_int(thr, i32); - } else { - DUK_DBLUNION_DOUBLE_HTON(&du1); - duk_debug_write_byte(thr, DUK_DBG_IB_NUMBER); - duk_debug_write_bytes(thr, (const duk_uint8_t *) du1.uc, sizeof(du1.uc)); - } - } -} - -#if defined(DUK_USE_DEBUGGER_DUMPHEAP) -/* Variant for writing duk_tvals so that any heap allocated values are - * written out as tagged heap pointers. - */ -DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) { - if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - duk_debug_write_heapptr(thr, h); - } else { - duk_debug_write_tval(thr, tv); - } -} -#endif /* DUK_USE_DEBUGGER_DUMPHEAP */ - -/* - * Debug connection message write helpers - */ - -#if 0 /* unused */ -DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) { - duk_debug_write_byte(thr, DUK_DBG_IB_REQUEST); - duk_debug_write_int(thr, command); -} -#endif - -DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) { - duk_debug_write_byte(thr, DUK_DBG_IB_REPLY); -} - -DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) { - /* Allow NULL 'msg' */ - duk_debug_write_byte(thr, DUK_DBG_IB_ERROR); - duk_debug_write_int(thr, (duk_int32_t) err_code); - duk_debug_write_cstring(thr, msg); - duk_debug_write_eom(thr); -} - -DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) { - duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY); - duk_debug_write_int(thr, (duk_int32_t) command); -} - -DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) { - duk_debug_write_byte(thr, DUK_DBG_IB_EOM); - - /* As an initial implementation, write flush after every EOM (and the - * version identifier). A better implementation would flush only when - * Duktape is finished processing messages so that a flush only happens - * after all outbound messages are finished on that occasion. - */ - duk_debug_write_flush(thr); -} - -/* - * Status message and helpers - */ - -DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) { - duk_activation *act; - duk_uint_fast32_t line; - duk_uint_fast32_t pc; - - act = thr->callstack_curr; - if (act == NULL) { - return 0; - } - - /* We're conceptually between two opcodes; act->pc indicates the next - * instruction to be executed. This is usually the correct pc/line to - * indicate in Status. (For the 'debugger' statement this now reports - * the pc/line after the debugger statement because the debugger opcode - * has already been executed.) - */ - - pc = duk_hthread_get_act_curr_pc(thr, act); - - /* XXX: this should be optimized to be a raw query and avoid valstack - * operations if possible. - */ - duk_push_tval(thr, &act->tv_func); - line = duk_hobject_pc2line_query(thr, -1, pc); - duk_pop(thr); - return line; -} - -DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) { - duk_activation *act; - - duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS); - duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0)); - - act = thr->callstack_curr; - if (act == NULL) { - duk_debug_write_undefined(thr); - duk_debug_write_undefined(thr); - duk_debug_write_int(thr, 0); - duk_debug_write_int(thr, 0); - } else { - duk_push_tval(thr, &act->tv_func); - duk_get_prop_string(thr, -1, "fileName"); - duk__debug_write_hstring_safe_top(thr); - duk_get_prop_string(thr, -2, "name"); - duk__debug_write_hstring_safe_top(thr); - duk_pop_3(thr); - /* Report next pc/line to be executed. */ - duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr)); - duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act)); - } - - duk_debug_write_eom(thr); -} - -#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) -DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) { - /* - * NFY EOM - */ - - duk_activation *act; - duk_uint32_t pc; - - DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */ - - duk_debug_write_notify(thr, DUK_DBG_CMD_THROW); - duk_debug_write_int(thr, (duk_int32_t) fatal); - - /* Report thrown value to client coerced to string */ - duk_dup_top(thr); - duk__debug_write_hstring_safe_top(thr); - duk_pop(thr); - - if (duk_is_error(thr, -1)) { - /* Error instance, use augmented error data directly */ - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME); - duk__debug_write_hstring_safe_top(thr); - duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER); - duk_debug_write_uint(thr, duk_get_uint(thr, -1)); - duk_pop_2(thr); - } else { - /* For anything other than an Error instance, we calculate the - * error location directly from the current activation if one - * exists. - */ - act = thr->callstack_curr; - if (act != NULL) { - duk_push_tval(thr, &act->tv_func); - duk_get_prop_string(thr, -1, "fileName"); - duk__debug_write_hstring_safe_top(thr); - pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr, act); - duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(thr, -2, pc)); - duk_pop_2(thr); - } else { - /* Can happen if duk_throw() is called on an empty - * callstack. - */ - duk_debug_write_cstring(thr, ""); - duk_debug_write_uint(thr, 0); - } - } - - duk_debug_write_eom(thr); -} -#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY */ - -/* - * Debug message processing - */ - -/* Skip dvalue. */ -DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) { - duk_uint8_t x; - duk_uint32_t len; - - x = duk_debug_read_byte(thr); - - if (x >= 0xc0) { - duk_debug_skip_byte(thr); - return 0; - } - if (x >= 0x80) { - return 0; - } - if (x >= 0x60) { - duk_debug_skip_bytes(thr, (duk_size_t) (x - 0x60)); - return 0; - } - switch(x) { - case DUK_DBG_IB_EOM: - return 1; /* Return 1: got EOM */ - case DUK_DBG_IB_REQUEST: - case DUK_DBG_IB_REPLY: - case DUK_DBG_IB_ERROR: - case DUK_DBG_IB_NOTIFY: - break; - case DUK_DBG_IB_INT4: - (void) duk__debug_read_uint32_raw(thr); - break; - case DUK_DBG_IB_STR4: - case DUK_DBG_IB_BUF4: - len = duk__debug_read_uint32_raw(thr); - duk_debug_skip_bytes(thr, len); - break; - case DUK_DBG_IB_STR2: - case DUK_DBG_IB_BUF2: - len = duk__debug_read_uint16_raw(thr); - duk_debug_skip_bytes(thr, len); - break; - case DUK_DBG_IB_UNUSED: - case DUK_DBG_IB_UNDEFINED: - case DUK_DBG_IB_NULL: - case DUK_DBG_IB_TRUE: - case DUK_DBG_IB_FALSE: - break; - case DUK_DBG_IB_NUMBER: - duk_debug_skip_bytes(thr, 8); - break; - case DUK_DBG_IB_OBJECT: - duk_debug_skip_byte(thr); - len = duk_debug_read_byte(thr); - duk_debug_skip_bytes(thr, len); - break; - case DUK_DBG_IB_POINTER: - case DUK_DBG_IB_HEAPPTR: - len = duk_debug_read_byte(thr); - duk_debug_skip_bytes(thr, len); - break; - case DUK_DBG_IB_LIGHTFUNC: - duk_debug_skip_bytes(thr, 2); - len = duk_debug_read_byte(thr); - duk_debug_skip_bytes(thr, len); - break; - default: - goto fail; - } - - return 0; - - fail: - DUK__SET_CONN_BROKEN(thr, 1); - return 1; /* Pretend like we got EOM */ -} - -/* Skip dvalues to EOM. */ -DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) { - for (;;) { - if (duk__debug_skip_dvalue(thr)) { - break; - } - } -} - -/* Read and validate a call stack index. If index is invalid, write out an - * error message and return zero. - */ -DUK_LOCAL duk_int32_t duk__debug_read_validate_csindex(duk_hthread *thr) { - duk_int32_t level; - level = duk_debug_read_int(thr); - if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) { - duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index"); - return 0; /* zero indicates failure */ - } - return level; -} - -/* Read a call stack index and lookup the corresponding duk_activation. - * If index is invalid, write out an error message and return NULL. - */ -DUK_LOCAL duk_activation *duk__debug_read_level_get_activation(duk_hthread *thr) { - duk_activation *act; - duk_int32_t level; - - level = duk_debug_read_int(thr); - act = duk_hthread_get_activation_for_level(thr, level); - if (act == NULL) { - duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index"); - } - return act; -} - -/* - * Simple commands - */ - -DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) { - DUK_UNREF(heap); - DUK_D(DUK_DPRINT("debug command Version")); - - duk_debug_write_reply(thr); - duk_debug_write_int(thr, DUK_VERSION); - duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE); - duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO); -#if defined(DUK_USE_DOUBLE_LE) - duk_debug_write_int(thr, 1); -#elif defined(DUK_USE_DOUBLE_ME) - duk_debug_write_int(thr, 2); -#elif defined(DUK_USE_DOUBLE_BE) - duk_debug_write_int(thr, 3); -#else - duk_debug_write_int(thr, 0); -#endif - duk_debug_write_int(thr, (duk_int_t) sizeof(void *)); - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) { - DUK_UNREF(heap); - DUK_D(DUK_DPRINT("debug command TriggerStatus")); - - duk_debug_write_reply(thr); - duk_debug_write_eom(thr); - heap->dbg_state_dirty = 1; -} - -DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) { - DUK_D(DUK_DPRINT("debug command Pause")); - duk_debug_set_paused(heap); - duk_debug_write_reply(thr); - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) { - duk_small_uint_t pause_flags; - - DUK_D(DUK_DPRINT("debug command Resume")); - - duk_debug_clear_paused(heap); - - pause_flags = 0; -#if 0 /* manual testing */ - pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE; - pause_flags |= DUK_PAUSE_FLAG_CAUGHT_ERROR; - pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR; -#endif -#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR; -#endif - - duk__debug_set_pause_state(thr, heap, pause_flags); - - duk_debug_write_reply(thr); - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) { - duk_small_uint_t pause_flags; - - DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd)); - - if (cmd == DUK_DBG_CMD_STEPINTO) { - pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE | - DUK_PAUSE_FLAG_FUNC_ENTRY | - DUK_PAUSE_FLAG_FUNC_EXIT; - } else if (cmd == DUK_DBG_CMD_STEPOVER) { - pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE | - DUK_PAUSE_FLAG_FUNC_EXIT; - } else { - DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT); - pause_flags = DUK_PAUSE_FLAG_FUNC_EXIT; - } -#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR; -#endif - - /* If current activation doesn't have line information, line-based - * pause flags are automatically disabled. As a result, e.g. - * StepInto will then pause on (native) function entry or exit. - */ - duk_debug_clear_paused(heap); - duk__debug_set_pause_state(thr, heap, pause_flags); - - duk_debug_write_reply(thr); - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) { - duk_small_int_t i; - - DUK_D(DUK_DPRINT("debug command ListBreak")); - duk_debug_write_reply(thr); - for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) { - duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename); - duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line); - } - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) { - duk_hstring *filename; - duk_uint32_t linenumber; - duk_small_int_t idx; - - DUK_UNREF(heap); - - filename = duk_debug_read_hstring(thr); - linenumber = (duk_uint32_t) duk_debug_read_int(thr); - DUK_D(DUK_DPRINT("debug command AddBreak: %!O:%ld", (duk_hobject *) filename, (long) linenumber)); - idx = duk_debug_add_breakpoint(thr, filename, linenumber); - if (idx >= 0) { - duk_debug_write_reply(thr); - duk_debug_write_int(thr, (duk_int32_t) idx); - duk_debug_write_eom(thr); - } else { - duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint"); - } -} - -DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) { - duk_small_uint_t idx; - - DUK_UNREF(heap); - - DUK_D(DUK_DPRINT("debug command DelBreak")); - idx = (duk_small_uint_t) duk_debug_read_int(thr); - if (duk_debug_remove_breakpoint(thr, idx)) { - duk_debug_write_reply(thr); - duk_debug_write_eom(thr); - } else { - duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index"); - } -} - -DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) { - duk_activation *act; - duk_hstring *str; - duk_bool_t rc; - - DUK_UNREF(heap); - DUK_D(DUK_DPRINT("debug command GetVar")); - - act = duk__debug_read_level_get_activation(thr); - if (act == NULL) { - return; - } - str = duk_debug_read_hstring(thr); /* push to stack */ - DUK_ASSERT(str != NULL); - - rc = duk_js_getvar_activation(thr, act, str, 0); - - duk_debug_write_reply(thr); - if (rc) { - duk_debug_write_int(thr, 1); - DUK_ASSERT(duk_get_tval(thr, -2) != NULL); - duk_debug_write_tval(thr, duk_get_tval(thr, -2)); - } else { - duk_debug_write_int(thr, 0); - duk_debug_write_unused(thr); - } - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) { - duk_activation *act; - duk_hstring *str; - duk_tval *tv; - - DUK_UNREF(heap); - DUK_D(DUK_DPRINT("debug command PutVar")); - - act = duk__debug_read_level_get_activation(thr); - if (act == NULL) { - return; - } - str = duk_debug_read_hstring(thr); /* push to stack */ - DUK_ASSERT(str != NULL); - tv = duk_debug_read_tval(thr); - if (tv == NULL) { - /* detached */ - return; - } - - duk_js_putvar_activation(thr, act, str, tv, 0); - - /* XXX: Current putvar implementation doesn't have a success flag, - * add one and send to debug client? - */ - duk_debug_write_reply(thr); - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) { - duk_hthread *curr_thr = thr; - duk_activation *curr_act; - duk_uint_fast32_t pc; - duk_uint_fast32_t line; - - DUK_ASSERT(thr != NULL); - DUK_UNREF(heap); - - duk_debug_write_reply(thr); - while (curr_thr != NULL) { - for (curr_act = curr_thr->callstack_curr; curr_act != NULL; curr_act = curr_act->parent) { - /* PC/line semantics here are: - * - For callstack top we're conceptually between two - * opcodes and current PC indicates next line to - * execute, so report that (matches Status). - * - For other activations we're conceptually still - * executing the instruction at PC-1, so report that - * (matches error stacktrace behavior). - * - See: https://github.com/svaarala/duktape/issues/281 - */ - - /* XXX: optimize to use direct reads, i.e. avoid - * value stack operations. - */ - duk_push_tval(thr, &curr_act->tv_func); - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME); - duk__debug_write_hstring_safe_top(thr); - duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME); - duk__debug_write_hstring_safe_top(thr); - pc = duk_hthread_get_act_curr_pc(thr, curr_act); - if (curr_act != curr_thr->callstack_curr && pc > 0) { - pc--; - } - line = duk_hobject_pc2line_query(thr, -3, pc); - duk_debug_write_uint(thr, (duk_uint32_t) line); - duk_debug_write_uint(thr, (duk_uint32_t) pc); - duk_pop_3(thr); - } - curr_thr = curr_thr->resumer; - } - /* SCANBUILD: warning about 'thr' potentially being NULL here, - * warning is incorrect because thr != NULL always here. - */ - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) { - duk_activation *act; - duk_hstring *varname; - - DUK_UNREF(heap); - - act = duk__debug_read_level_get_activation(thr); - if (act == NULL) { - return; - } - - duk_debug_write_reply(thr); - - /* XXX: several nice-to-have improvements here: - * - Use direct reads avoiding value stack operations - * - Avoid triggering getters, indicate getter values to debug client - * - If side effects are possible, add error catching - */ - - duk_push_tval(thr, &act->tv_func); - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VARMAP); - if (duk_is_object(thr, -1)) { - duk_enum(thr, -1, 0 /*enum_flags*/); - while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) { - varname = duk_known_hstring(thr, -1); - - duk_js_getvar_activation(thr, act, varname, 0 /*throw_flag*/); - /* [ ... func varmap enum key value this ] */ - duk_debug_write_hstring(thr, duk_get_hstring(thr, -3)); - duk_debug_write_tval(thr, duk_get_tval(thr, -2)); - duk_pop_3(thr); /* -> [ ... func varmap enum ] */ - } - } else { - DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore")); - } - - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) { - duk_small_uint_t call_flags; - duk_int_t call_ret; - duk_small_int_t eval_err; - duk_bool_t direct_eval; - duk_int32_t level; - duk_idx_t idx_func; - - DUK_UNREF(heap); - - DUK_D(DUK_DPRINT("debug command Eval")); - - /* The eval code is executed within the lexical environment of a specified - * activation. For now, use global object eval() function, with the eval - * considered a 'direct call to eval'. - * - * Callstack index for debug commands only affects scope -- the callstack - * as seen by, e.g. Duktape.act() will be the same regardless. - */ - - /* nargs == 2 so we can pass a callstack index to eval(). */ - idx_func = duk_get_top(thr); - duk_push_c_function(thr, duk_bi_global_object_eval, 2 /*nargs*/); - duk_push_undefined(thr); /* 'this' binding shouldn't matter here */ - - /* Read callstack index, if non-null. */ - if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) { - direct_eval = 0; - level = -1; /* Not needed, but silences warning. */ - (void) duk_debug_read_byte(thr); - } else { - direct_eval = 1; - level = duk__debug_read_validate_csindex(thr); - if (level == 0) { - return; - } - } - - DUK_ASSERT(!direct_eval || - (level < 0 && -level <= (duk_int32_t) thr->callstack_top)); - - (void) duk_debug_read_hstring(thr); - if (direct_eval) { - duk_push_int(thr, level - 1); /* compensate for eval() call */ - } - - /* [ ... eval "eval" eval_input level? ] */ - - call_flags = 0; - if (direct_eval) { - duk_activation *act; - duk_hobject *fun; - - act = duk_hthread_get_activation_for_level(thr, level); - if (act != NULL) { - fun = DUK_ACT_GET_FUNC(act); - if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(fun)) { - /* Direct eval requires that there's a current - * activation and it is an Ecmascript function. - * When Eval is executed from e.g. cooperate API - * call we'll need to do an indirect eval instead. - */ - call_flags |= DUK_CALL_FLAG_DIRECT_EVAL; - } - } - } - - call_ret = duk_pcall_method_flags(thr, duk_get_top(thr) - (idx_func + 2), call_flags); - - if (call_ret == DUK_EXEC_SUCCESS) { - eval_err = 0; - /* Use result value as is. */ - } else { - /* For errors a string coerced result is most informative - * right now, as the debug client doesn't have the capability - * to traverse the error object. - */ - eval_err = 1; - duk_safe_to_string(thr, -1); - } - - /* [ ... result ] */ - - duk_debug_write_reply(thr); - duk_debug_write_int(thr, (duk_int32_t) eval_err); - DUK_ASSERT(duk_get_tval(thr, -1) != NULL); - duk_debug_write_tval(thr, duk_get_tval(thr, -1)); - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) { - DUK_UNREF(heap); - DUK_D(DUK_DPRINT("debug command Detach")); - - duk_debug_write_reply(thr); - duk_debug_write_eom(thr); - - DUK_D(DUK_DPRINT("debug connection detached, mark broken")); - DUK__SET_CONN_BROKEN(thr, 0); /* not an error */ -} - -DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) { - duk_idx_t old_top; - - DUK_D(DUK_DPRINT("debug command AppRequest")); - - old_top = duk_get_top(thr); /* save stack top */ - - if (heap->dbg_request_cb != NULL) { - duk_idx_t nrets; - duk_idx_t nvalues = 0; - duk_idx_t top, idx; - - /* Read tvals from the message and push them onto the valstack, - * then call the request callback to process the request. - */ - while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) { - duk_tval *tv; - if (!duk_check_stack(thr, 1)) { - DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)")); - goto fail; - } - tv = duk_debug_read_tval(thr); /* push to stack */ - if (tv == NULL) { - /* detached */ - return; - } - nvalues++; - } - DUK_ASSERT(duk_get_top(thr) == old_top + nvalues); - - /* Request callback should push values for reply to client onto valstack */ - DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld", - (long) nvalues, (long) old_top, (long) duk_get_top(thr))); - nrets = heap->dbg_request_cb(thr, heap->dbg_udata, nvalues); - DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld", - (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(thr))); - if (nrets >= 0) { - DUK_ASSERT(duk_get_top(thr) >= old_top + nrets); - if (duk_get_top(thr) < old_top + nrets) { - DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, " - "top=%ld < old_top=%ld + nrets=%ld; " - "this might mean it's unsafe to continue!", - (long) duk_get_top(thr), (long) old_top, (long) nrets)); - goto fail; - } - - /* Reply with tvals pushed by request callback */ - duk_debug_write_byte(thr, DUK_DBG_IB_REPLY); - top = duk_get_top(thr); - for (idx = top - nrets; idx < top; idx++) { - duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(thr, idx)); - } - duk_debug_write_eom(thr); - } else { - DUK_ASSERT(duk_get_top(thr) >= old_top + 1); - if (duk_get_top(thr) < old_top + 1) { - DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration")); - goto fail; - } - duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(thr, -1)); - } - - duk_set_top(thr, old_top); /* restore stack top */ - } else { - DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported")); - duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target"); - } - - return; - - fail: - duk_set_top(thr, old_top); /* restore stack top */ - DUK__SET_CONN_BROKEN(thr, 1); -} - -/* - * DumpHeap command - */ - -#if defined(DUK_USE_DEBUGGER_DUMPHEAP) -/* XXX: this has some overlap with object inspection; remove this and make - * DumpHeap return lists of heapptrs instead? - */ -DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) { - DUK_UNREF(heap); - - duk_debug_write_heapptr(thr, hdr); - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr)); - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr)); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr)); -#else - duk_debug_write_int(thr, (duk_int32_t) -1); -#endif - - switch (DUK_HEAPHDR_GET_TYPE(hdr)) { - case DUK_HTYPE_STRING: { - duk_hstring *h = (duk_hstring *) hdr; - - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_BYTELEN(h)); - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_CHARLEN(h)); - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); - duk_debug_write_hstring(thr, h); - break; - } - case DUK_HTYPE_OBJECT: { - duk_hobject *h = (duk_hobject *) hdr; - duk_hstring *k; - duk_uint_fast32_t i; - - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h)); - duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h)); - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h)); - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h)); - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h)); - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i)); - k = DUK_HOBJECT_E_GET_KEY(heap, h, i); - duk_debug_write_heapptr(thr, (duk_heaphdr *) k); - if (k == NULL) { - duk_debug_write_int(thr, 0); /* isAccessor */ - duk_debug_write_unused(thr); - continue; - } - if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) { - duk_debug_write_int(thr, 1); /* isAccessor */ - duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get); - duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set); - } else { - duk_debug_write_int(thr, 0); /* isAccessor */ - - duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v); - } - } - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { - /* Note: array dump will include elements beyond - * 'length'. - */ - duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); - } - break; - } - case DUK_HTYPE_BUFFER: { - duk_hbuffer *h = (duk_hbuffer *) hdr; - - duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h)); - duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); - break; - } - default: { - DUK_D(DUK_DPRINT("invalid htype: %d", (int) DUK_HEAPHDR_GET_TYPE(hdr))); - } - } -} - -DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) { - duk_heaphdr *hdr; - - hdr = heap->heap_allocated; - while (hdr != NULL) { - duk__debug_dump_heaphdr(thr, heap, hdr); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} - -DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) { - duk_uint32_t i; - duk_hstring *h; - - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_STRTAB_PTRCOMP) - h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; -#endif - while (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - h = h->hdr.h_next; - } - } -} - -DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) { - DUK_D(DUK_DPRINT("debug command DumpHeap")); - - duk_debug_write_reply(thr); - duk__debug_dump_heap_allocated(thr, heap); - duk__debug_dump_strtab(thr, heap); - duk_debug_write_eom(thr); -} -#endif /* DUK_USE_DEBUGGER_DUMPHEAP */ - -DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) { - duk_activation *act; - duk_hcompfunc *fun = NULL; - duk_size_t i, n; - duk_tval *tv; - duk_hobject **fn; - duk_int32_t level = -1; - duk_uint8_t ibyte; - - DUK_UNREF(heap); - - DUK_D(DUK_DPRINT("debug command GetBytecode")); - - ibyte = duk_debug_peek_byte(thr); - if (ibyte != DUK_DBG_IB_EOM) { - tv = duk_debug_read_tval(thr); - if (tv == NULL) { - /* detached */ - return; - } - if (DUK_TVAL_IS_OBJECT(tv)) { - /* tentative, checked later */ - fun = (duk_hcompfunc *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(fun != NULL); - } else if (DUK_TVAL_IS_NUMBER(tv)) { - level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv); - } else { - DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!T", tv)); - goto fail_args; - } - } - - if (fun == NULL) { - act = duk_hthread_get_activation_for_level(thr, level); - if (act == NULL) { - goto fail_index; - } - fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); - } - - if (fun == NULL || !DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)) { - DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O", fun)); - goto fail_args; - } - DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)); - - duk_debug_write_reply(thr); - n = DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap, fun); - duk_debug_write_int(thr, (duk_int32_t) n); - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, fun); - for (i = 0; i < n; i++) { - duk_debug_write_tval(thr, tv); - tv++; - } - n = DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap, fun); - duk_debug_write_int(thr, (duk_int32_t) n); - fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, fun); - for (i = 0; i < n; i++) { - duk_debug_write_hobject(thr, *fn); - fn++; - } - duk_debug_write_string(thr, - (const char *) DUK_HCOMPFUNC_GET_CODE_BASE(heap, fun), - (duk_size_t) DUK_HCOMPFUNC_GET_CODE_SIZE(heap, fun)); - duk_debug_write_eom(thr); - return; - - fail_args: - duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument"); - return; - - fail_index: - duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index"); - return; -} - -/* - * Object inspection commands: GetHeapObjInfo, GetObjPropDesc, - * GetObjPropDescRange - */ - -#if defined(DUK_USE_DEBUGGER_INSPECT) - -#if 0 /* pruned */ -DUK_LOCAL const char * const duk__debug_getinfo_heaphdr_keys[] = { - "reachable", - "temproot", - "finalizable", - "finalized", - "readonly" - /* NULL not needed here */ -}; -DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = { - DUK_HEAPHDR_FLAG_REACHABLE, - DUK_HEAPHDR_FLAG_TEMPROOT, - DUK_HEAPHDR_FLAG_FINALIZABLE, - DUK_HEAPHDR_FLAG_FINALIZED, - DUK_HEAPHDR_FLAG_READONLY, - 0 /* terminator */ -}; -#endif -DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = { -#if 0 - "arridx", - "symbol", - "hidden", - "reserved_word", - "strict_reserved_word", - "eval_or_arguments", -#endif - "extdata" - /* NULL not needed here */ -}; -DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = { -#if 0 - DUK_HSTRING_FLAG_ARRIDX, - DUK_HSTRING_FLAG_SYMBOL, - DUK_HSTRING_FLAG_HIDDEN, - DUK_HSTRING_FLAG_RESERVED_WORD, - DUK_HSTRING_FLAG_STRICT_RESERVED_WORD, - DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS, -#endif - DUK_HSTRING_FLAG_EXTDATA, - 0 /* terminator */ -}; -DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = { - "extensible", - "constructable", - "callable", - "boundfunc", - "compfunc", - "natfunc", - "bufobj", - "fastrefs", - "array_part", - "strict", - "notail", - "newenv", - "namebinding", - "createargs", - "have_finalizer", - "exotic_array", - "exotic_stringobj", - "exotic_arguments", - "exotic_proxyobj", - "special_call" - /* NULL not needed here */ -}; -DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = { - DUK_HOBJECT_FLAG_EXTENSIBLE, - DUK_HOBJECT_FLAG_CONSTRUCTABLE, - DUK_HOBJECT_FLAG_CALLABLE, - DUK_HOBJECT_FLAG_BOUNDFUNC, - DUK_HOBJECT_FLAG_COMPFUNC, - DUK_HOBJECT_FLAG_NATFUNC, - DUK_HOBJECT_FLAG_BUFOBJ, - DUK_HOBJECT_FLAG_FASTREFS, - DUK_HOBJECT_FLAG_ARRAY_PART, - DUK_HOBJECT_FLAG_STRICT, - DUK_HOBJECT_FLAG_NOTAIL, - DUK_HOBJECT_FLAG_NEWENV, - DUK_HOBJECT_FLAG_NAMEBINDING, - DUK_HOBJECT_FLAG_CREATEARGS, - DUK_HOBJECT_FLAG_HAVE_FINALIZER, - DUK_HOBJECT_FLAG_EXOTIC_ARRAY, - DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ, - DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS, - DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ, - DUK_HOBJECT_FLAG_SPECIAL_CALL, - 0 /* terminator */ -}; -DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = { - "dynamic", - "external" - /* NULL not needed here */ -}; -DUK_LOCAL duk_uint_t duk__debug_getinfo_hbuffer_masks[] = { - DUK_HBUFFER_FLAG_DYNAMIC, - DUK_HBUFFER_FLAG_EXTERNAL, - 0 /* terminator */ -}; - -DUK_LOCAL void duk__debug_getinfo_flags_key(duk_hthread *thr, const char *key) { - duk_debug_write_uint(thr, 0); - duk_debug_write_cstring(thr, key); -} - -DUK_LOCAL void duk__debug_getinfo_prop_uint(duk_hthread *thr, const char *key, duk_uint_t val) { - duk_debug_write_uint(thr, 0); - duk_debug_write_cstring(thr, key); - duk_debug_write_uint(thr, val); -} - -DUK_LOCAL void duk__debug_getinfo_prop_int(duk_hthread *thr, const char *key, duk_int_t val) { - duk_debug_write_uint(thr, 0); - duk_debug_write_cstring(thr, key); - duk_debug_write_int(thr, val); -} - -DUK_LOCAL void duk__debug_getinfo_prop_bool(duk_hthread *thr, const char *key, duk_bool_t val) { - duk_debug_write_uint(thr, 0); - duk_debug_write_cstring(thr, key); - duk_debug_write_boolean(thr, val); -} - -DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const * keys, duk_uint_t *masks, duk_uint_t flags) { - const char *key; - duk_uint_t mask; - - for (;;) { - mask = *masks++; - if (mask == 0) { - break; - } - key = *keys++; - DUK_ASSERT(key != NULL); - - DUK_DD(DUK_DDPRINT("inspect bitmask: key=%s, mask=0x%08lx, flags=0x%08lx", key, (unsigned long) mask, (unsigned long) flags)); - duk__debug_getinfo_prop_bool(thr, key, flags & mask); - } -} - -/* Inspect a property using a virtual index into a conceptual property list - * consisting of (1) all array part items from [0,a_size[ (even when above - * .length) and (2) all entry part items from [0,e_next[. Unused slots are - * indicated using dvalue 'unused'. - */ -DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap, duk_hobject *h_obj, duk_uint_t idx) { - duk_uint_t a_size; - duk_tval *tv; - duk_hstring *h_key; - duk_hobject *h_getset; - duk_uint_t flags; - - DUK_UNREF(heap); - - a_size = DUK_HOBJECT_GET_ASIZE(h_obj); - if (idx < a_size) { - duk_debug_write_uint(thr, DUK_PROPDESC_FLAGS_WEC); - duk_debug_write_uint(thr, idx); - tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, h_obj, idx); - duk_debug_write_tval(thr, tv); - return 1; - } - - idx -= a_size; - if (idx >= DUK_HOBJECT_GET_ENEXT(h_obj)) { - return 0; - } - - h_key = DUK_HOBJECT_E_GET_KEY(heap, h_obj, idx); - if (h_key == NULL) { - duk_debug_write_uint(thr, 0); - duk_debug_write_null(thr); - duk_debug_write_unused(thr); - return 1; - } - - flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx); - if (DUK_HSTRING_HAS_SYMBOL(h_key)) { - flags |= DUK_DBG_PROPFLAG_SYMBOL; - } - if (DUK_HSTRING_HAS_HIDDEN(h_key)) { - flags |= DUK_DBG_PROPFLAG_HIDDEN; - } - duk_debug_write_uint(thr, flags); - duk_debug_write_hstring(thr, h_key); - if (flags & DUK_PROPDESC_FLAG_ACCESSOR) { - h_getset = DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h_obj, idx); - if (h_getset) { - duk_debug_write_hobject(thr, h_getset); - } else { - duk_debug_write_null(thr); - } - h_getset = DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h_obj, idx); - if (h_getset) { - duk_debug_write_hobject(thr, h_getset); - } else { - duk_debug_write_null(thr); - } - } else { - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h_obj, idx); - duk_debug_write_tval(thr, tv); - } - return 1; -} - -DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *heap) { - duk_heaphdr *h; - - DUK_D(DUK_DPRINT("debug command GetHeapObjInfo")); - DUK_UNREF(heap); - - DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1); - DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1); - DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1); - - h = duk_debug_read_any_ptr(thr); - if (!h) { - duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target"); - return; - } - - duk_debug_write_reply(thr); - - /* As with all inspection code, we rely on the debug client providing - * a valid, non-stale pointer: there's no portable way to safely - * validate the pointer here. - */ - - duk__debug_getinfo_flags_key(thr, "heapptr"); - duk_debug_write_heapptr(thr, h); - - /* XXX: comes out as signed now */ - duk__debug_getinfo_prop_uint(thr, "heaphdr_flags", (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h)); - duk__debug_getinfo_prop_uint(thr, "heaphdr_type", (duk_uint_t) DUK_HEAPHDR_GET_TYPE(h)); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__debug_getinfo_prop_uint(thr, "refcount", (duk_uint_t) DUK_HEAPHDR_GET_REFCOUNT(h)); -#endif -#if 0 /* pruned */ - duk__debug_getinfo_bitmask(thr, - duk__debug_getinfo_heaphdr_keys, - duk__debug_getinfo_heaphdr_masks, - DUK_HEAPHDR_GET_FLAGS_RAW(h)); -#endif - - switch (DUK_HEAPHDR_GET_TYPE(h)) { - case DUK_HTYPE_STRING: { - duk_hstring *h_str; - - h_str = (duk_hstring *) h; - duk__debug_getinfo_bitmask(thr, - duk__debug_getinfo_hstring_keys, - duk__debug_getinfo_hstring_masks, - DUK_HEAPHDR_GET_FLAGS_RAW(h)); - duk__debug_getinfo_prop_uint(thr, "bytelen", (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "charlen", (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "hash", (duk_uint_t) DUK_HSTRING_GET_HASH(h_str)); - duk__debug_getinfo_flags_key(thr, "data"); - duk_debug_write_hstring(thr, h_str); - break; - } - case DUK_HTYPE_OBJECT: { - duk_hobject *h_obj; - duk_hobject *h_proto; - - h_obj = (duk_hobject *) h; - h_proto = DUK_HOBJECT_GET_PROTOTYPE(heap, h_obj); - - /* duk_hobject specific fields. */ - duk__debug_getinfo_bitmask(thr, - duk__debug_getinfo_hobject_keys, - duk__debug_getinfo_hobject_masks, - DUK_HEAPHDR_GET_FLAGS_RAW(h)); - duk__debug_getinfo_prop_uint(thr, "class_number", DUK_HOBJECT_GET_CLASS_NUMBER(h_obj)); - duk__debug_getinfo_flags_key(thr, "class_name"); - duk_debug_write_hstring(thr, DUK_HOBJECT_GET_CLASS_STRING(heap, h_obj)); - duk__debug_getinfo_flags_key(thr, "prototype"); - if (h_proto != NULL) { - duk_debug_write_hobject(thr, h_proto); - } else { - duk_debug_write_null(thr); - } - duk__debug_getinfo_flags_key(thr, "props"); - duk_debug_write_pointer(thr, (void *) DUK_HOBJECT_GET_PROPS(heap, h_obj)); - duk__debug_getinfo_prop_uint(thr, "e_size", (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj)); - duk__debug_getinfo_prop_uint(thr, "e_next", (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj)); - duk__debug_getinfo_prop_uint(thr, "a_size", (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj)); - duk__debug_getinfo_prop_uint(thr, "h_size", (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj)); - - if (DUK_HOBJECT_IS_ARRAY(h_obj)) { - duk_harray *h_arr; - h_arr = (duk_harray *) h_obj; - - duk__debug_getinfo_prop_uint(thr, "length", (duk_uint_t) h_arr->length); - duk__debug_getinfo_prop_bool(thr, "length_nonwritable", h_arr->length_nonwritable); - } - - if (DUK_HOBJECT_IS_NATFUNC(h_obj)) { - duk_hnatfunc *h_fun; - h_fun = (duk_hnatfunc *) h_obj; - - duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs); - duk__debug_getinfo_prop_int(thr, "magic", h_fun->magic); - duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATFUNC_NARGS_VARARGS); - /* Native function pointer may be different from a void pointer, - * and we serialize it from memory directly now (no byte swapping etc). - */ - duk__debug_getinfo_flags_key(thr, "funcptr"); - duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func)); - } - - if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { - duk_hcompfunc *h_fun; - duk_hbuffer *h_buf; - duk_hobject *h_lexenv; - duk_hobject *h_varenv; - h_fun = (duk_hcompfunc *) h_obj; - - duk__debug_getinfo_prop_int(thr, "nregs", h_fun->nregs); - duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs); - - duk__debug_getinfo_flags_key(thr, "lex_env"); - h_lexenv = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, h_fun); - if (h_lexenv != NULL) { - duk_debug_write_hobject(thr, h_lexenv); - } else { - duk_debug_write_null(thr); - } - duk__debug_getinfo_flags_key(thr, "var_env"); - h_varenv = DUK_HCOMPFUNC_GET_VARENV(thr->heap, h_fun); - if (h_varenv != NULL) { - duk_debug_write_hobject(thr, h_varenv); - } else { - duk_debug_write_null(thr); - } - - duk__debug_getinfo_prop_uint(thr, "start_line", h_fun->start_line); - duk__debug_getinfo_prop_uint(thr, "end_line", h_fun->end_line); - h_buf = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun); - if (h_buf != NULL) { - duk__debug_getinfo_flags_key(thr, "data"); - duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf); - } - } - - if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) { - duk_hboundfunc *h_bfun; - h_bfun = (duk_hboundfunc *) h_obj; - - duk__debug_getinfo_flags_key(thr, "target"); - duk_debug_write_tval(thr, &h_bfun->target); - duk__debug_getinfo_flags_key(thr, "this_binding"); - duk_debug_write_tval(thr, &h_bfun->this_binding); - duk__debug_getinfo_flags_key(thr, "nargs"); - duk_debug_write_int(thr, h_bfun->nargs); - /* h_bfun->args not exposed now */ - } - - if (DUK_HOBJECT_IS_THREAD(h_obj)) { - /* XXX: Currently no inspection of threads, e.g. value stack, call - * stack, catch stack, etc. - */ - duk_hthread *h_thr; - h_thr = (duk_hthread *) h_obj; - DUK_UNREF(h_thr); - } - - if (DUK_HOBJECT_IS_DECENV(h_obj)) { - duk_hdecenv *h_env; - h_env = (duk_hdecenv *) h_obj; - - duk__debug_getinfo_flags_key(thr, "thread"); - duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread)); - duk__debug_getinfo_flags_key(thr, "varmap"); - duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap)); - duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase_byteoff); - } - - if (DUK_HOBJECT_IS_OBJENV(h_obj)) { - duk_hobjenv *h_env; - h_env = (duk_hobjenv *) h_obj; - - duk__debug_getinfo_flags_key(thr, "target"); - duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target)); - duk__debug_getinfo_prop_bool(thr, "has_this", h_env->has_this); - } - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { - duk_hbufobj *h_bufobj; - h_bufobj = (duk_hbufobj *) h_obj; - - duk__debug_getinfo_prop_uint(thr, "slice_offset", h_bufobj->offset); - duk__debug_getinfo_prop_uint(thr, "slice_length", h_bufobj->length); - duk__debug_getinfo_prop_uint(thr, "elem_shift", (duk_uint_t) h_bufobj->shift); - duk__debug_getinfo_prop_uint(thr, "elem_type", (duk_uint_t) h_bufobj->elem_type); - duk__debug_getinfo_prop_bool(thr, "is_typedarray", (duk_uint_t) h_bufobj->is_typedarray); - if (h_bufobj->buf != NULL) { - duk__debug_getinfo_flags_key(thr, "buffer"); - duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf); - } - } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - break; - } - case DUK_HTYPE_BUFFER: { - duk_hbuffer *h_buf; - - h_buf = (duk_hbuffer *) h; - duk__debug_getinfo_bitmask(thr, - duk__debug_getinfo_hbuffer_keys, - duk__debug_getinfo_hbuffer_masks, - DUK_HEAPHDR_GET_FLAGS_RAW(h)); - duk__debug_getinfo_prop_uint(thr, "size", (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf)); - duk__debug_getinfo_flags_key(thr, "dataptr"); - duk_debug_write_pointer(thr, (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf)); - duk__debug_getinfo_flags_key(thr, "data"); - duk_debug_write_hbuffer(thr, h_buf); /* tolerates NULL h_buf */ - break; - } - default: { - /* Since we already started writing the reply, just emit nothing. */ - DUK_D(DUK_DPRINT("inspect target pointer has invalid heaphdr type")); - } - } - - duk_debug_write_eom(thr); -} - -DUK_LOCAL void duk__debug_handle_get_obj_prop_desc(duk_hthread *thr, duk_heap *heap) { - duk_heaphdr *h; - duk_hobject *h_obj; - duk_hstring *h_key; - duk_propdesc desc; - - DUK_D(DUK_DPRINT("debug command GetObjPropDesc")); - DUK_UNREF(heap); - - h = duk_debug_read_any_ptr(thr); - if (!h) { - duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target"); - return; - } - h_key = duk_debug_read_hstring(thr); - if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT || h_key == NULL) { - goto fail_args; - } - h_obj = (duk_hobject *) h; - - if (duk_hobject_get_own_propdesc(thr, h_obj, h_key, &desc, 0 /*flags*/)) { - duk_int_t virtual_idx; - duk_bool_t rc; - - /* To use the shared helper need the virtual index. */ - DUK_ASSERT(desc.e_idx >= 0 || desc.a_idx >= 0); - virtual_idx = (desc.a_idx >= 0 ? desc.a_idx : - (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj) + desc.e_idx); - - duk_debug_write_reply(thr); - rc = duk__debug_getprop_index(thr, heap, h_obj, (duk_uint_t) virtual_idx); - DUK_ASSERT(rc == 1); - DUK_UNREF(rc); - duk_debug_write_eom(thr); - } else { - duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "not found"); - } - return; - - fail_args: - duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args"); -} - -DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_heap *heap) { - duk_heaphdr *h; - duk_hobject *h_obj; - duk_uint_t idx, idx_start, idx_end; - - DUK_D(DUK_DPRINT("debug command GetObjPropDescRange")); - DUK_UNREF(heap); - - h = duk_debug_read_any_ptr(thr); - idx_start = (duk_uint_t) duk_debug_read_int(thr); - idx_end = (duk_uint_t) duk_debug_read_int(thr); - if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) { - goto fail_args; - } - h_obj = (duk_hobject *) h; - - /* The index range space is conceptually the array part followed by the - * entry part. Unlike normal enumeration all slots are exposed here as - * is and return 'unused' if the slots are not in active use. In particular - * the array part is included for the full a_size regardless of what the - * array .length is. - */ - - duk_debug_write_reply(thr); - for (idx = idx_start; idx < idx_end; idx++) { - if (!duk__debug_getprop_index(thr, heap, h_obj, idx)) { - break; - } - } - duk_debug_write_eom(thr); - return; - - fail_args: - duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args"); -} - -#endif /* DUK_USE_DEBUGGER_INSPECT */ - -/* - * Process incoming debug requests - * - * Individual request handlers can push temporaries on the value stack and - * rely on duk__debug_process_message() to restore the value stack top - * automatically. - */ - -/* Process one debug message. Automatically restore value stack top to its - * entry value, so that individual message handlers don't need exact value - * stack handling which is convenient. - */ -DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) { - duk_heap *heap; - duk_uint8_t x; - duk_int32_t cmd; - duk_idx_t entry_top; - - DUK_ASSERT(thr != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - entry_top = duk_get_top(thr); - - x = duk_debug_read_byte(thr); - switch (x) { - case DUK_DBG_IB_REQUEST: { - cmd = duk_debug_read_int(thr); - switch (cmd) { - case DUK_DBG_CMD_BASICINFO: { - duk__debug_handle_basic_info(thr, heap); - break; - } - case DUK_DBG_CMD_TRIGGERSTATUS: { - duk__debug_handle_trigger_status(thr, heap); - break; - } - case DUK_DBG_CMD_PAUSE: { - duk__debug_handle_pause(thr, heap); - break; - } - case DUK_DBG_CMD_RESUME: { - duk__debug_handle_resume(thr, heap); - break; - } - case DUK_DBG_CMD_STEPINTO: - case DUK_DBG_CMD_STEPOVER: - case DUK_DBG_CMD_STEPOUT: { - duk__debug_handle_step(thr, heap, cmd); - break; - } - case DUK_DBG_CMD_LISTBREAK: { - duk__debug_handle_list_break(thr, heap); - break; - } - case DUK_DBG_CMD_ADDBREAK: { - duk__debug_handle_add_break(thr, heap); - break; - } - case DUK_DBG_CMD_DELBREAK: { - duk__debug_handle_del_break(thr, heap); - break; - } - case DUK_DBG_CMD_GETVAR: { - duk__debug_handle_get_var(thr, heap); - break; - } - case DUK_DBG_CMD_PUTVAR: { - duk__debug_handle_put_var(thr, heap); - break; - } - case DUK_DBG_CMD_GETCALLSTACK: { - duk__debug_handle_get_call_stack(thr, heap); - break; - } - case DUK_DBG_CMD_GETLOCALS: { - duk__debug_handle_get_locals(thr, heap); - break; - } - case DUK_DBG_CMD_EVAL: { - duk__debug_handle_eval(thr, heap); - break; - } - case DUK_DBG_CMD_DETACH: { - /* The actual detached_cb call is postponed to message loop so - * we don't need any special precautions here (just skip to EOM - * on the already closed connection). - */ - duk__debug_handle_detach(thr, heap); - break; - } -#if defined(DUK_USE_DEBUGGER_DUMPHEAP) - case DUK_DBG_CMD_DUMPHEAP: { - duk__debug_handle_dump_heap(thr, heap); - break; - } -#endif /* DUK_USE_DEBUGGER_DUMPHEAP */ - case DUK_DBG_CMD_GETBYTECODE: { - duk__debug_handle_get_bytecode(thr, heap); - break; - } - case DUK_DBG_CMD_APPREQUEST: { - duk__debug_handle_apprequest(thr, heap); - break; - } -#if defined(DUK_USE_DEBUGGER_INSPECT) - case DUK_DBG_CMD_GETHEAPOBJINFO: { - duk__debug_handle_get_heap_obj_info(thr, heap); - break; - } - case DUK_DBG_CMD_GETOBJPROPDESC: { - duk__debug_handle_get_obj_prop_desc(thr, heap); - break; - } - case DUK_DBG_CMD_GETOBJPROPDESCRANGE: { - duk__debug_handle_get_obj_prop_desc_range(thr, heap); - break; - } -#endif /* DUK_USE_DEBUGGER_INSPECT */ - default: { - DUK_D(DUK_DPRINT("debug command unsupported: %d", (int) cmd)); - duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command"); - } - } /* switch cmd */ - break; - } - case DUK_DBG_IB_REPLY: { - DUK_D(DUK_DPRINT("debug reply, skipping")); - break; - } - case DUK_DBG_IB_ERROR: { - DUK_D(DUK_DPRINT("debug error, skipping")); - break; - } - case DUK_DBG_IB_NOTIFY: { - DUK_D(DUK_DPRINT("debug notify, skipping")); - break; - } - default: { - DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x)); - goto fail; - } - } /* switch initial byte */ - - DUK_ASSERT(duk_get_top(thr) >= entry_top); - duk_set_top(thr, entry_top); - duk__debug_skip_to_eom(thr); - return; - - fail: - DUK_ASSERT(duk_get_top(thr) >= entry_top); - duk_set_top(thr, entry_top); - DUK__SET_CONN_BROKEN(thr, 1); - return; -} - -DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) { - if (thr->heap->dbg_read_cb != NULL && thr->heap->dbg_state_dirty) { - duk_debug_send_status(thr); - thr->heap->dbg_state_dirty = 0; - } -} - -DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) { -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top; -#endif - duk_bool_t retval = 0; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(thr); -#endif - - DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld", - thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block, - (long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing)); - DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(thr))); - - /* thr->heap->dbg_detaching may be != 0 if a debugger write outside - * the message loop caused a transport error and detach1() to run. - */ - DUK_ASSERT(thr->heap->dbg_detaching == 0 || thr->heap->dbg_detaching == 1); - DUK_ASSERT(thr->heap->dbg_processing == 0); - thr->heap->dbg_processing = 1; - - /* Ensure dirty state causes a Status even if never process any - * messages. This is expected by the bytecode executor when in - * the running state. - */ - duk__check_resend_status(thr); - - for (;;) { - /* Process messages until we're no longer paused or we peek - * and see there's nothing to read right now. - */ - DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(thr))); - DUK_ASSERT(thr->heap->dbg_processing == 1); - - while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) { - /* Detach is pending; can be triggered from outside the - * debugger loop (e.g. Status notify write error) or by - * previous message handling. Call detached callback - * here, in a controlled state, to ensure a possible - * reattach inside the detached_cb is handled correctly. - * - * Recheck for detach in a while loop: an immediate - * reattach involves a call to duk_debugger_attach() - * which writes a debugger handshake line immediately - * inside the API call. If the transport write fails - * for that handshake, we can immediately end up in a - * "transport broken, detaching" case several times here. - * Loop back until we're either cleanly attached or - * fully detached. - * - * NOTE: Reset dbg_processing = 1 forcibly, in case we - * re-attached; duk_debugger_attach() sets dbg_processing - * to 0 at the moment. - */ - - DUK_D(DUK_DPRINT("detach pending (dbg_read_cb == NULL, dbg_detaching != 0), call detach2")); - - duk__debug_do_detach2(thr->heap); - thr->heap->dbg_processing = 1; /* may be set to 0 by duk_debugger_attach() inside callback */ - - DUK_D(DUK_DPRINT("after detach2 (and possible reattach): dbg_read_cb=%s, dbg_detaching=%ld", - thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) thr->heap->dbg_detaching)); - } - DUK_ASSERT(thr->heap->dbg_detaching == 0); /* true even with reattach */ - DUK_ASSERT(thr->heap->dbg_processing == 1); /* even after a detach and possible reattach */ - - if (thr->heap->dbg_read_cb == NULL) { - DUK_D(DUK_DPRINT("debug connection broken (and not detaching), stop processing messages")); - break; - } - - if (!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || no_block) { - if (!duk_debug_read_peek(thr)) { - /* Note: peek cannot currently trigger a detach - * so the dbg_detaching == 0 assert outside the - * loop is correct. - */ - DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing messages")); - break; - } - DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it")); - } else { - DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary")); - } - - duk__check_resend_status(thr); - duk__debug_process_message(thr); - duk__check_resend_status(thr); - - retval = 1; /* processed one or more messages */ - } - - DUK_ASSERT(thr->heap->dbg_detaching == 0); - DUK_ASSERT(thr->heap->dbg_processing == 1); - thr->heap->dbg_processing = 0; - - /* As an initial implementation, read flush after exiting the message - * loop. If transport is broken, this is a no-op (with debug logs). - */ - duk_debug_read_flush(thr); /* this cannot initiate a detach */ - DUK_ASSERT(thr->heap->dbg_detaching == 0); - - DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(thr))); - -#if defined(DUK_USE_ASSERTIONS) - /* Easy to get wrong, so assert for it. */ - DUK_ASSERT(entry_top == duk_get_top(thr)); -#endif - - return retval; -} - -/* - * Halt execution helper - */ - -/* Halt execution and enter a debugger message loop until execution is resumed - * by the client. PC for the current activation may be temporarily decremented - * so that the "current" instruction will be shown by the client. This helper - * is callable from anywhere, also outside bytecode executor. - */ - -DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) { - duk_activation *act; - duk_hcompfunc *fun; - duk_instr_t *old_pc = NULL; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(duk_debug_is_attached(thr->heap)); - DUK_ASSERT(thr->heap->dbg_processing == 0); - DUK_ASSERT(!duk_debug_is_paused(thr->heap)); - - duk_debug_set_paused(thr->heap); - - act = thr->callstack_curr; - - /* NOTE: act may be NULL if an error is thrown outside of any activation, - * which may happen in the case of, e.g. syntax errors. - */ - - /* Decrement PC if that was requested, this requires a PC sync. */ - if (act != NULL) { - duk_hthread_sync_currpc(thr); - old_pc = act->curr_pc; - fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); - - /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is - * guaranteed to be a non-NULL Ecmascript function. - */ - DUK_ASSERT(act->curr_pc == NULL || - (fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun))); - if (use_prev_pc && - act->curr_pc != NULL && - act->curr_pc > DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, fun)) { - act->curr_pc--; - } - } - - /* Process debug messages until we are no longer paused. */ - - /* NOTE: This is a bit fragile. It's important to ensure that - * duk_debug_process_messages() never throws an error or - * act->curr_pc will never be reset. - */ - - thr->heap->dbg_state_dirty = 1; - while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) { - DUK_ASSERT(duk_debug_is_attached(thr->heap)); - DUK_ASSERT(thr->heap->dbg_processing == 0); - duk_debug_process_messages(thr, 0 /*no_block*/); - } - - /* XXX: Decrementing and restoring act->curr_pc works now, but if the - * debugger message loop gains the ability to adjust the current PC - * (e.g. a forced jump) restoring the PC here will break. Another - * approach would be to use a state flag for the "decrement 1 from - * topmost activation's PC" and take it into account whenever dealing - * with PC values. - */ - if (act != NULL) { - act->curr_pc = old_pc; /* restore PC */ - } -} - -/* - * Breakpoint management - */ - -DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) { - duk_heap *heap; - duk_breakpoint *b; - - /* Caller must trigger recomputation of active breakpoint list. To - * ensure stale values are not used if that doesn't happen, clear the - * active breakpoint list here. - */ - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(filename != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) { - DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used", - (duk_heaphdr *) filename, (long) line)); - return -1; - } - heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; - b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++); - b->filename = filename; - b->line = line; - DUK_HSTRING_INCREF(thr, filename); - - return (duk_small_int_t) (heap->dbg_breakpoint_count - 1); /* index */ -} - -DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) { - duk_heap *heap; - duk_hstring *h; - duk_breakpoint *b; - duk_size_t move_size; - - /* Caller must trigger recomputation of active breakpoint list. To - * ensure stale values are not used if that doesn't happen, clear the - * active breakpoint list here. - */ - - DUK_ASSERT(thr != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - DUK_ASSERT(duk_debug_is_attached(thr->heap)); - DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */ - - if (breakpoint_index >= heap->dbg_breakpoint_count) { - DUK_D(DUK_DPRINT("invalid breakpoint index: %ld", (long) breakpoint_index)); - return 0; - } - b = heap->dbg_breakpoints + breakpoint_index; - - h = b->filename; - DUK_ASSERT(h != NULL); - - move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1); - if (move_size > 0) { - DUK_MEMMOVE((void *) b, - (const void *) (b + 1), - (size_t) move_size); - } - heap->dbg_breakpoint_count--; - heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; - - DUK_HSTRING_DECREF(thr, h); /* side effects */ - DUK_UNREF(h); /* w/o refcounting */ - - /* Breakpoint entries above the used area are left as garbage. */ - - return 1; -} - -/* - * Misc state management - */ - -DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) { - return (heap->dbg_read_cb != NULL); -} - -DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) { - return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0); -} - -DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) { - if (duk_debug_is_paused(heap)) { - DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring")); - } else { - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); - heap->dbg_state_dirty = 1; - duk_debug_clear_pause_state(heap); - DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */ - heap->ms_running = 1; /* prevent mark-and-sweep, prevent refzero queueing */ - heap->ms_prevent_count++; - DUK_ASSERT(heap->ms_prevent_count != 0); /* Wrap. */ - DUK_ASSERT(heap->heap_thread != NULL); - } -} - -DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) { - if (duk_debug_is_paused(heap)) { - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); - heap->dbg_state_dirty = 1; - duk_debug_clear_pause_state(heap); - DUK_ASSERT(heap->ms_running == 1); - DUK_ASSERT(heap->ms_prevent_count > 0); - heap->ms_prevent_count--; - heap->ms_running = 0; - DUK_ASSERT(heap->heap_thread != NULL); - } else { - DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring")); - } -} - -DUK_INTERNAL void duk_debug_clear_pause_state(duk_heap *heap) { - heap->dbg_pause_flags = 0; - heap->dbg_pause_act = NULL; - heap->dbg_pause_startline = 0; -} - -#else /* DUK_USE_DEBUGGER_SUPPORT */ - -/* No debugger support. */ - -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -/* automatic undefs */ -#undef DUK__DBG_TPORT_ENTER -#undef DUK__DBG_TPORT_EXIT -#undef DUK__SET_CONN_BROKEN -#line 1 "duk_error_augment.c" -/* - * Augmenting errors at their creation site and their throw site. - * - * When errors are created, traceback data is added by built-in code - * and a user error handler (if defined) can process or replace the - * error. Similarly, when errors are thrown, a user error handler - * (if defined) can process or replace the error. - * - * Augmentation and other processing at error creation time is nice - * because an error is only created once, but it may be thrown and - * rethrown multiple times. User error handler registered for processing - * an error at its throw site must be careful to handle rethrowing in - * a useful manner. - * - * Error augmentation may throw an internal error (e.g. alloc error). - * - * Ecmascript allows throwing any values, so all values cannot be - * augmented. Currently, the built-in augmentation at error creation - * only augments error values which are Error instances (= have the - * built-in Error.prototype in their prototype chain) and are also - * extensible. User error handlers have no limitations in this respect. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Helper for calling a user error handler. - * - * 'thr' must be the currently active thread; the error handler is called - * in its context. The valstack of 'thr' must have the error value on - * top, and will be replaced by another error value based on the return - * value of the error handler. - * - * The helper calls duk_handle_call() recursively in protected mode. - * Before that call happens, no longjmps should happen; as a consequence, - * we must assume that the valstack contains enough temporary space for - * arguments and such. - * - * While the error handler runs, any errors thrown will not trigger a - * recursive error handler call (this is implemented using a heap level - * flag which will "follow" through any coroutines resumed inside the - * error handler). If the error handler is not callable or throws an - * error, the resulting error replaces the original error (for Duktape - * internal errors, duk_error_throw.c further substitutes this error with - * a DoubleError which is not ideal). This would be easy to change and - * even signal to the caller. - * - * The user error handler is stored in 'Duktape.errCreate' or - * 'Duktape.errThrow' depending on whether we're augmenting the error at - * creation or throw time. There are several alternatives to this approach, - * see doc/error-objects.rst for discussion. - * - * Note: since further longjmp()s may occur while calling the error handler - * (for many reasons, e.g. a labeled 'break' inside the handler), the - * caller can make no assumptions on the thr->heap->lj state after the - * call (this affects especially duk_error_throw.c). This is not an issue - * as long as the caller writes to the lj state only after the error handler - * finishes. - */ - -#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE) -DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) { - duk_tval *tv_hnd; - duk_int_t rc; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT_STRIDX_VALID(stridx_cb); - - if (thr->heap->augmenting_error) { - DUK_D(DUK_DPRINT("recursive call to error augmentation, ignore")); - return; - } - - /* - * Check whether or not we have an error handler. - * - * We must be careful of not triggering an error when looking up the - * property. For instance, if the property is a getter, we don't want - * to call it, only plain values are allowed. The value, if it exists, - * is not checked. If the value is not a function, a TypeError happens - * when it is called and that error replaces the original one. - */ - - DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */ - - /* [ ... errval ] */ - - if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) { - /* When creating built-ins, some of the built-ins may not be set - * and we want to tolerate that when throwing errors. - */ - DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring")); - return; - } - tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->heap, - thr->builtins[DUK_BIDX_DUKTAPE], - DUK_HTHREAD_GET_STRING(thr, stridx_cb)); - if (tv_hnd == NULL) { - DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T", - (duk_tval *) tv_hnd)); - return; - } - DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T", - (duk_tval *) tv_hnd)); - duk_push_tval(thr, tv_hnd); - - /* [ ... errval errhandler ] */ - - duk_insert(thr, -2); /* -> [ ... errhandler errval ] */ - duk_push_undefined(thr); - duk_insert(thr, -2); /* -> [ ... errhandler undefined(= this) errval ] */ - - /* [ ... errhandler undefined errval ] */ - - /* - * heap->augmenting_error prevents recursive re-entry and also causes - * call handling to use a larger (but not unbounded) call stack limit - * for the duration of error augmentation. - * - * We ignore errors now: a success return and an error value both - * replace the original error value. (This would be easy to change.) - */ - - DUK_ASSERT(thr->heap->augmenting_error == 0); - thr->heap->augmenting_error = 1; - - rc = duk_pcall_method(thr, 1); - DUK_UNREF(rc); /* no need to check now: both success and error are OK */ - - DUK_ASSERT(thr->heap->augmenting_error == 1); - thr->heap->augmenting_error = 0; - - /* [ ... errval ] */ -} -#endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */ - -/* - * Add ._Tracedata to an error on the stack top. - */ - -#if defined(DUK_USE_TRACEBACKS) -DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) { - duk_activation *act; - duk_int_t depth; - duk_int_t arr_size; - duk_tval *tv; - duk_hstring *s; - duk_uint32_t u32; - duk_double_t d; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr_callstack != NULL); - - /* [ ... error ] */ - - /* - * The traceback format is pretty arcane in an attempt to keep it compact - * and cheap to create. It may change arbitrarily from version to version. - * It should be decoded/accessed through version specific accessors only. - * - * See doc/error-objects.rst. - */ - - DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T", - (duk_tval *) duk_get_tval(thr, -1))); - - /* Preallocate array to correct size, so that we can just write out - * the _Tracedata values into the array part. - */ - act = thr->callstack_curr; - depth = DUK_USE_TRACEBACK_DEPTH; - DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */ - if (depth > (duk_int_t) thr_callstack->callstack_top) { - depth = (duk_int_t) thr_callstack->callstack_top; - } - if (depth > 0) { - if (flags & DUK_AUGMENT_FLAG_SKIP_ONE) { - DUK_ASSERT(act != NULL); - act = act->parent; - depth--; - } - } - arr_size = depth * 2; - if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { - arr_size += 2; - } - if (c_filename) { - /* We need the C filename to be interned before getting the - * array part pointer to avoid any GC interference while the - * array part is populated. - */ - duk_push_string(thr, c_filename); - arr_size += 2; - } - - /* XXX: uninitialized would be OK */ - DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items", (long) arr_size)); - tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) arr_size); - DUK_ASSERT(arr_size == 0 || tv != NULL); - - /* Compiler SyntaxErrors (and other errors) come first, and are - * blamed by default (not flagged "noblame"). - */ - if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { - s = thr->compile_ctx->h_filename; - DUK_TVAL_SET_STRING(tv, s); - DUK_HSTRING_INCREF(thr, s); - tv++; - - u32 = (duk_uint32_t) thr->compile_ctx->curr_token.start_line; /* (flags<<32) + (line), flags = 0 */ - DUK_TVAL_SET_U32(tv, u32); - tv++; - } - - /* Filename/line from C macros (__FILE__, __LINE__) are added as an - * entry with a special format: (string, number). The number contains - * the line and flags. - */ - - /* [ ... error c_filename? arr ] */ - - if (c_filename) { - DUK_ASSERT(DUK_TVAL_IS_STRING(thr->valstack_top - 2)); - s = DUK_TVAL_GET_STRING(thr->valstack_top - 2); /* interned c_filename */ - DUK_ASSERT(s != NULL); - DUK_TVAL_SET_STRING(tv, s); - DUK_HSTRING_INCREF(thr, s); - tv++; - - d = ((flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) + - (duk_double_t) c_line; - DUK_TVAL_SET_DOUBLE(tv, d); - tv++; - } - - /* Traceback depth doesn't take into account the filename/line - * special handling above (intentional). - */ - for (; depth-- > 0; act = act->parent) { - duk_uint32_t pc; - duk_tval *tv_src; - - /* [... arr] */ - - DUK_ASSERT(act != NULL); /* depth check above, assumes book-keeping is correct */ - DUK_ASSERT_DISABLE(act->pc >= 0); /* unsigned */ - - /* Add function object. */ - tv_src = &act->tv_func; /* object (function) or lightfunc */ - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src)); - DUK_TVAL_SET_TVAL(tv, tv_src); - DUK_TVAL_INCREF(thr, tv); - tv++; - - /* Add a number containing: pc, activation flags. - * - * PC points to next instruction, find offending PC. Note that - * PC == 0 for native code. - */ - pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr_callstack, act); - DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */ - DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ - d = ((duk_double_t) act->flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc; - DUK_TVAL_SET_DOUBLE(tv, d); - tv++; - } - -#if defined(DUK_USE_ASSERTIONS) - { - duk_harray *a; - a = (duk_harray *) duk_known_hobject(thr, -1); - DUK_ASSERT(a != NULL); - DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length); - DUK_ASSERT(a->length == (duk_uint32_t) arr_size); - } -#endif - - /* [ ... error c_filename? arr ] */ - - if (c_filename) { - duk_remove_m2(thr); - } - - /* [ ... error arr ] */ - - duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */ -} -#endif /* DUK_USE_TRACEBACKS */ - -/* - * Add .fileName and .lineNumber to an error on the stack top. - */ - -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) && !defined(DUK_USE_TRACEBACKS) -DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) { -#if defined(DUK_USE_ASSERTIONS) - duk_int_t entry_top; -#endif - -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(thr); -#endif - - /* - * If tracebacks are disabled, 'fileName' and 'lineNumber' are added - * as plain own properties. Since Error.prototype has accessors of - * the same name, we need to define own properties directly (cannot - * just use e.g. duk_put_prop_stridx). Existing properties are not - * overwritten in case they already exist. - */ - - if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { - /* Compiler SyntaxError (or other error) gets the primary blame. - * Currently no flag to prevent blaming. - */ - duk_push_uint(thr, (duk_uint_t) thr->compile_ctx->curr_token.start_line); - duk_push_hstring(thr, thr->compile_ctx->h_filename); - } else if (c_filename && (flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) == 0) { - /* C call site gets blamed next, unless flagged not to do so. - * XXX: file/line is disabled in minimal builds, so disable this - * too when appropriate. - */ - duk_push_int(thr, c_line); - duk_push_string(thr, c_filename); - } else { - /* Finally, blame the innermost callstack entry which has a - * .fileName property. - */ - duk_small_uint_t depth; - duk_uint32_t ecma_line; - duk_activation *act; - - DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */ - depth = DUK_USE_TRACEBACK_DEPTH; - if (depth > thr_callstack->callstack_top) { - depth = thr_callstack->callstack_top; - } - for (act = thr_callstack->callstack_curr; depth-- > 0; act = act->parent) { - duk_hobject *func; - duk_uint32_t pc; - - DUK_ASSERT(act != NULL); - func = DUK_ACT_GET_FUNC(act); - if (func == NULL) { - /* Lightfunc, not blamed now. */ - continue; - } - - /* PC points to next instruction, find offending PC, - * PC == 0 for native code. - */ - pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */ - DUK_UNREF(pc); - DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */ - DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ - act = NULL; /* invalidated by pushes, so get out of the way */ - - duk_push_hobject(thr, func); - - /* [ ... error func ] */ - - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME); - if (!duk_is_string_notsymbol(thr, -1)) { - duk_pop_2(thr); - continue; - } - - /* [ ... error func fileName ] */ - - ecma_line = 0; -#if defined(DUK_USE_PC2LINE) - if (DUK_HOBJECT_IS_COMPFUNC(func)) { - ecma_line = duk_hobject_pc2line_query(thr, -2, (duk_uint_fast32_t) pc); - } else { - /* Native function, no relevant lineNumber. */ - } -#endif /* DUK_USE_PC2LINE */ - duk_push_u32(thr, ecma_line); - - /* [ ... error func fileName lineNumber ] */ - - duk_replace(thr, -3); - - /* [ ... error lineNumber fileName ] */ - goto define_props; - } - - /* No activation matches, use undefined for both .fileName and - * .lineNumber (matches what we do with a _Tracedata based - * no-match lookup. - */ - duk_push_undefined(thr); - duk_push_undefined(thr); - } - - define_props: - /* [ ... error lineNumber fileName ] */ -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(duk_get_top(thr) == entry_top + 2); -#endif - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE); -} -#endif /* DUK_USE_AUGMENT_ERROR_CREATE && !DUK_USE_TRACEBACKS */ - -/* - * Add line number to a compiler error. - */ - -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) -DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) { - - /* Append a "(line NNN)" to the "message" property of any error - * thrown during compilation. Usually compilation errors are - * SyntaxErrors but they can also be out-of-memory errors and - * the like. - */ - - /* [ ... error ] */ - - DUK_ASSERT(duk_is_object(thr, -1)); - - if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) { - return; - } - - DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T", - (duk_tval *) duk_get_tval(thr, -1))); - - if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_MESSAGE)) { - duk_push_sprintf(thr, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line); - duk_concat(thr, 2); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE); - } else { - duk_pop(thr); - } - - DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T", - (duk_tval *) duk_get_tval(thr, -1))); -} -#endif /* DUK_USE_AUGMENT_ERROR_CREATE */ - -/* - * Augment an error being created using Duktape specific properties - * like _Tracedata or .fileName/.lineNumber. - */ - -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) -DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_hobject *obj, duk_small_uint_t flags) { -#if defined(DUK_USE_ASSERTIONS) - duk_int_t entry_top; -#endif - -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(thr); -#endif - DUK_ASSERT(obj != NULL); - - DUK_UNREF(obj); /* unreferenced w/o tracebacks */ - - duk__add_compiler_error_line(thr); - -#if defined(DUK_USE_TRACEBACKS) - /* If tracebacks are enabled, the '_Tracedata' property is the only - * thing we need: 'fileName' and 'lineNumber' are virtual properties - * which use '_Tracedata'. - */ - if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) { - DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it")); - } else { - duk__add_traceback(thr, thr_callstack, c_filename, c_line, flags); - } -#else - /* Without tracebacks the concrete .fileName and .lineNumber need - * to be added directly. - */ - duk__add_fileline(thr, thr_callstack, c_filename, c_line, flags); -#endif - -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(duk_get_top(thr) == entry_top); -#endif -} -#endif /* DUK_USE_AUGMENT_ERROR_CREATE */ - -/* - * Augment an error at creation time with _Tracedata/fileName/lineNumber - * and allow a user error handler (if defined) to process/replace the error. - * The error to be augmented is at the stack top. - * - * thr: thread containing the error value - * thr_callstack: thread which should be used for generating callstack etc. - * c_filename: C __FILE__ related to the error - * c_line: C __LINE__ related to the error - * flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE: - * if true, don't fileName/line as error source, otherwise use traceback - * (needed because user code filename/line are reported but internal ones - * are not) - */ - -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) -DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) { - duk_hobject *obj; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr_callstack != NULL); - - /* [ ... error ] */ - - /* - * Criteria for augmenting: - * - * - augmentation enabled in build (naturally) - * - error value internal prototype chain contains the built-in - * Error prototype object (i.e. 'val instanceof Error') - * - * Additional criteria for built-in augmenting: - * - * - error value is an extensible object - */ - - obj = duk_get_hobject(thr, -1); - if (!obj) { - DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment")); - return; - } - if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) { - /* If the value has a prototype loop, it's critical not to - * throw here. Instead, assume the value is not to be - * augmented. - */ - DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment")); - return; - } - if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) { - DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment")); - duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, obj, flags); - } else { - DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment")); - } - - /* [ ... error ] */ - -#if defined(DUK_USE_ERRCREATE) - duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE); -#endif -} -#endif /* DUK_USE_AUGMENT_ERROR_CREATE */ - -/* - * Augment an error at throw time; allow a user error handler (if defined) - * to process/replace the error. The error to be augmented is at the - * stack top. - */ - -#if defined(DUK_USE_AUGMENT_ERROR_THROW) -DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) { -#if defined(DUK_USE_ERRTHROW) - duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW); -#endif /* DUK_USE_ERRTHROW */ -} -#endif /* DUK_USE_AUGMENT_ERROR_THROW */ -#line 1 "duk_error_longjmp.c" -/* - * Do a longjmp call, calling the fatal error handler if no - * catchpoint exists. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_PREFER_SIZE) -DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) { - (void) duk_fatal(thr, "uncaught error"); -} -#endif - -#if 0 -DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) { - const char *summary; - char buf[DUK_USE_FATAL_MAXLEN]; - - summary = duk_push_string_tval_readable(thr, &thr->heap->lj.value1); - DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary); - buf[sizeof(buf) - 1] = (char) 0; - (void) duk_fatal(thr, (const char *) buf); -} -#endif - -#if !defined(DUK_USE_PREFER_SIZE) -DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) { - const char *summary; - char buf[DUK_USE_FATAL_MAXLEN]; - - summary = duk_push_string_tval_readable_error(thr, &thr->heap->lj.value1); - DUK_ASSERT(summary != NULL); - DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary); - buf[sizeof(buf) - 1] = (char) 0; - (void) duk_fatal(thr, (const char *) buf); -} -#endif - -DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - - DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T", - (int) thr->heap->lj.type, (int) thr->heap->lj.iserror, - &thr->heap->lj.value1, &thr->heap->lj.value2)); - - /* Prevent finalizer execution during error handling. All error - * handling sites will process pending finalizers once error handling - * is complete and we're ready for the side effects. Does not prevent - * refzero freeing or mark-and-sweep during error handling. - * - * NOTE: when we come here some calling code may have used DECREF - * NORZ macros without an explicit DUK_REFZERO_CHECK_xxx() call. - * We don't want to do it here because it would just check for - * pending finalizers and we prevent that explicitly. Instead, - * the error catcher will run the finalizers once error handling - * is complete. - */ - - DUK_ASSERT_LJSTATE_SET(thr->heap); - - thr->heap->pf_prevent_count++; - DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ - -#if defined(DUK_USE_ASSERTIONS) - /* XXX: set this immediately when longjmp state is set */ - DUK_ASSERT(thr->heap->error_not_allowed == 0); /* Detect error within critical section. */ - thr->heap->error_not_allowed = 1; -#endif - - DUK_DD(DUK_DDPRINT("about to longjmp, pf_prevent_count=%ld", (long) thr->heap->pf_prevent_count)); - -#if !defined(DUK_USE_CPP_EXCEPTIONS) - /* If we don't have a jmpbuf_ptr, there is little we can do except - * cause a fatal error. The caller's expectation is that we never - * return. - * - * With C++ exceptions we now just propagate an uncaught error - * instead of invoking the fatal error handler. Because there's - * a dummy jmpbuf for C++ exceptions now, this could be changed. - */ - if (!thr->heap->lj.jmpbuf_ptr) { - DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T", - (int) thr->heap->lj.type, (int) thr->heap->lj.iserror, - &thr->heap->lj.value1, &thr->heap->lj.value2)); - -#if defined(DUK_USE_PREFER_SIZE) - duk__uncaught_minimal(thr); -#else - duk__uncaught_error_aware(thr); -#endif - DUK_UNREACHABLE(); - } -#endif /* DUK_USE_CPP_EXCEPTIONS */ - -#if defined(DUK_USE_CPP_EXCEPTIONS) - { - duk_internal_exception exc; /* dummy */ - throw exc; - } -#else /* DUK_USE_CPP_EXCEPTIONS */ - DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb); -#endif /* DUK_USE_CPP_EXCEPTIONS */ - - DUK_UNREACHABLE(); -} -#line 1 "duk_error_misc.c" -/* - * Error helpers - */ - -/* #include duk_internal.h -> already included */ - -/* - * Helper to walk the thread chain and see if there is an active error - * catcher. Protected calls or finally blocks aren't considered catching. - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) { - /* As noted above, a protected API call won't be counted as a - * catcher. This is usually convenient, e.g. in the case of a top- - * level duk_pcall(), but may not always be desirable. Perhaps add - * an argument to treat them as catchers? - */ - - duk_activation *act; - duk_catcher *cat; - - DUK_ASSERT(thr != NULL); - - for (; thr != NULL; thr = thr->resumer) { - for (act = thr->callstack_curr; act != NULL; act = act->parent) { - for (cat = act->cat; cat != NULL; cat = cat->parent) { - if (DUK_CAT_HAS_CATCH_ENABLED(cat)) { - return 1; /* all we need to know */ - } - } - } - } - return 0; -} -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -/* - * Get prototype object for an integer error code. - */ - -DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) { - switch (code) { - case DUK_ERR_EVAL_ERROR: - return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]; - case DUK_ERR_RANGE_ERROR: - return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]; - case DUK_ERR_REFERENCE_ERROR: - return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]; - case DUK_ERR_SYNTAX_ERROR: - return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]; - case DUK_ERR_TYPE_ERROR: - return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]; - case DUK_ERR_URI_ERROR: - return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]; - case DUK_ERR_ERROR: - default: - return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]; - } -} - -/* - * Helper for debugger throw notify and pause-on-uncaught integration. - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { - duk_bool_t uncaught; - duk_tval *tv_obj; - - /* If something is thrown with the debugger attached and nobody will - * catch it, execution is paused before the longjmp, turning over - * control to the debug client. This allows local state to be examined - * before the stack is unwound. Errors are not intercepted when debug - * message loop is active (e.g. for Eval). - */ - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - - /* XXX: Allow customizing the pause and notify behavior at runtime - * using debugger runtime flags. For now the behavior is fixed using - * config options. - */ - - if (!duk_debug_is_attached(thr->heap) || - thr->heap->dbg_processing || - thr->heap->lj.type != DUK_LJ_TYPE_THROW || - thr->heap->creating_error) { - DUK_D(DUK_DPRINT("skip debugger error integration; not attached, debugger processing, not THROW, or error thrown while creating error")); - return; - } - - /* Don't intercept a DoubleError, we may have caused the initial double - * fault and attempting to intercept it will cause us to be called - * recursively and exhaust the C stack. (This should no longer happen - * for the initial throw because DoubleError path doesn't do a debugger - * integration check, but it might happen for rethrows.) - */ - tv_obj = &thr->heap->lj.value1; - if (DUK_TVAL_IS_OBJECT(tv_obj) && DUK_TVAL_GET_OBJECT(tv_obj) == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("built-in DoubleError instance (re)thrown, not intercepting")); - return; - } - - uncaught = !duk__have_active_catcher(thr); - - /* Debugger code expects the value at stack top. This also serves - * as a backup: we need to store/restore the longjmp state because - * when the debugger is paused Eval commands may be executed and - * they can arbitrarily clobber the longjmp state. - */ - duk_push_tval(thr, tv_obj); - - /* Store and reset longjmp state. */ - DUK_ASSERT_LJSTATE_SET(thr->heap); - DUK_TVAL_DECREF_NORZ(thr, tv_obj); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); /* Always for THROW type. */ - DUK_TVAL_SET_UNDEFINED(tv_obj); - thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN; - DUK_ASSERT_LJSTATE_UNSET(thr->heap); - -#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) - /* Report it to the debug client */ - DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); - duk_debug_send_throw(thr, uncaught); -#endif - - if (uncaught) { - if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_UNCAUGHT_ERROR) { - DUK_D(DUK_DPRINT("PAUSE TRIGGERED by uncaught error")); - duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); - } - } else { - if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_CAUGHT_ERROR) { - DUK_D(DUK_DPRINT("PAUSE TRIGGERED by caught error")); - duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); - } - } - - /* Restore longjmp state. */ - DUK_ASSERT_LJSTATE_UNSET(thr->heap); - thr->heap->lj.type = DUK_LJ_TYPE_THROW; - tv_obj = DUK_GET_TVAL_NEGIDX(thr, -1); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, tv_obj); - DUK_TVAL_INCREF(thr, tv_obj); - DUK_ASSERT_LJSTATE_SET(thr->heap); - - duk_pop(thr); -} -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -/* - * Helpers for setting up heap longjmp state. - */ - -DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val) { - duk_heap *heap; - - DUK_ASSERT(thr != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - DUK_ASSERT(tv_val != NULL); - - DUK_ASSERT_LJSTATE_UNSET(heap); - - heap->lj.type = lj_type; - DUK_TVAL_SET_TVAL(&heap->lj.value1, tv_val); - DUK_TVAL_INCREF(thr, tv_val); - - DUK_ASSERT_LJSTATE_SET(heap); -} -#line 1 "duk_error_throw.c" -/* - * Create and throw an Ecmascript error object based on a code and a message. - * - * Used when we throw errors internally. Ecmascript generated error objects - * are created by Ecmascript code, and the throwing is handled by the bytecode - * executor. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Create and throw an error (originating from Duktape internally) - * - * Push an error object on top of the stack, possibly throw augmenting - * the error, and finally longjmp. - * - * If an error occurs while we're dealing with the current error, we might - * enter an infinite recursion loop. This is prevented by detecting a - * "double fault" through the heap->creating_error flag; the recursion - * then stops at the second level. - */ - -#if defined(DUK_USE_VERBOSE_ERRORS) -DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) { -#else -DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) { -#endif -#if defined(DUK_USE_VERBOSE_ERRORS) - DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld", - (long) code, (const char *) msg, - (const char *) filename, (long) line)); -#else - DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code)); -#endif - - DUK_ASSERT(thr != NULL); - - /* Even though nested call is possible because we throw an error when - * trying to create an error, the potential errors must happen before - * the longjmp state is configured. - */ - DUK_ASSERT_LJSTATE_UNSET(thr->heap); - - /* Sync so that augmentation sees up-to-date activations, NULL - * thr->ptr_curr_pc so that it's not used if side effects occur - * in augmentation or longjmp handling. - */ - duk_hthread_sync_and_null_currpc(thr); - - /* - * Create and push an error object onto the top of stack. - * The error is potentially augmented before throwing. - * - * If a "double error" occurs, use a fixed error instance - * to avoid further trouble. - */ - - if (thr->heap->creating_error) { - duk_tval tv_val; - duk_hobject *h_err; - - thr->heap->creating_error = 0; - - h_err = thr->builtins[DUK_BIDX_DOUBLE_ERROR]; - if (h_err != NULL) { - DUK_D(DUK_DPRINT("double fault detected -> use built-in fixed 'double error' instance")); - DUK_TVAL_SET_OBJECT(&tv_val, h_err); - } else { - DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance " - "-> use the error code as a number")); - DUK_TVAL_SET_I32(&tv_val, (duk_int32_t) code); - } - - duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, &tv_val); - - /* No augmentation to avoid any allocations or side effects. */ - } else { - /* Prevent infinite recursion. Extra call stack and C - * recursion headroom (see GH-191) is added for augmentation. - * That is now signalled by heap->augmenting error and taken - * into account in call handling without an explicit limit bump. - */ - thr->heap->creating_error = 1; - - duk_require_stack(thr, 1); - - /* XXX: usually unnecessary '%s' formatting here, but cannot - * use 'msg' as a format string directly. - */ -#if defined(DUK_USE_VERBOSE_ERRORS) - duk_push_error_object_raw(thr, - code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, - filename, - line, - "%s", - (const char *) msg); -#else - duk_push_error_object_raw(thr, - code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, - NULL, - 0, - NULL); -#endif - - /* Note that an alloc error may happen during error augmentation. - * This may happen both when the original error is an alloc error - * and when it's something else. Because any error in augmentation - * must be handled correctly anyway, there's no special check for - * avoiding it for alloc errors (this differs from Duktape 1.x). - */ -#if defined(DUK_USE_AUGMENT_ERROR_THROW) - DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)", - (duk_tval *) duk_get_tval(thr, -1))); - duk_err_augment_error_throw(thr); -#endif - - duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1)); - thr->heap->creating_error = 0; - - /* Error is now created and we assume no errors can occur any - * more. Check for debugger Throw integration only when the - * error is complete. If we enter debugger message loop, - * creating_error must be 0 so that errors can be thrown in - * the paused state, e.g. in Eval commands. - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_err_check_debugger_integration(thr); -#endif - } - - /* - * Finally, longjmp - */ - - DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)", - (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2)); - - duk_err_longjmp(thr); - DUK_UNREACHABLE(); -} - -/* - * Helper for C function call negative return values. - */ - -DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(rc < 0); - - /* - * The __FILE__ and __LINE__ information is intentionally not used in the - * creation of the error object, as it isn't useful in the tracedata. The - * tracedata still contains the function which returned the negative return - * code, and having the file/line of this function isn't very useful. - * - * The error messages for DUK_RET_xxx shorthand are intentionally very - * minimal: they're only really useful for low memory targets. - */ - - duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)", (long) rc); - DUK_UNREACHABLE(); -} -#line 1 "duk_hbuffer_alloc.c" -/* - * duk_hbuffer allocation and freeing. - */ - -/* #include duk_internal.h -> already included */ - -/* Allocate a new duk_hbuffer of a certain type and return a pointer to it - * (NULL on error). Write buffer data pointer to 'out_bufdata' (only if - * allocation successful). - */ -DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) { - duk_hbuffer *res = NULL; - duk_size_t header_size; - duk_size_t alloc_size; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(out_bufdata != NULL); - - DUK_DDD(DUK_DDDPRINT("allocate hbuffer")); - - /* Size sanity check. Should not be necessary because caller is - * required to check this, but we don't want to cause a segfault - * if the size wraps either in duk_size_t computation or when - * storing the size in a 16-bit field. - */ - if (size > DUK_HBUFFER_MAX_BYTELEN) { - DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size)); - return NULL; /* no need to write 'out_bufdata' */ - } - - if (flags & DUK_BUF_FLAG_EXTERNAL) { - header_size = sizeof(duk_hbuffer_external); - alloc_size = sizeof(duk_hbuffer_external); - } else if (flags & DUK_BUF_FLAG_DYNAMIC) { - header_size = sizeof(duk_hbuffer_dynamic); - alloc_size = sizeof(duk_hbuffer_dynamic); - } else { - header_size = sizeof(duk_hbuffer_fixed); - alloc_size = sizeof(duk_hbuffer_fixed) + size; - DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */ - } - - res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size); - if (DUK_UNLIKELY(res == NULL)) { - goto alloc_error; - } - - /* zero everything unless requested not to do so */ -#if defined(DUK_USE_ZERO_BUFFER_DATA) - DUK_MEMZERO((void *) res, - (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size); -#else - DUK_MEMZERO((void *) res, header_size); -#endif - - if (flags & DUK_BUF_FLAG_EXTERNAL) { - duk_hbuffer_external *h; - h = (duk_hbuffer_external *) res; - DUK_UNREF(h); - *out_bufdata = NULL; -#if defined(DUK_USE_EXPLICIT_NULL_INIT) -#if defined(DUK_USE_HEAPPTR16) -/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */ -#else - DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL); -#endif -#endif - DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL); - } else if (flags & DUK_BUF_FLAG_DYNAMIC) { - duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res; - void *ptr; - - if (size > 0) { - DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */ - DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer")); -#if defined(DUK_USE_ZERO_BUFFER_DATA) - ptr = DUK_ALLOC_ZEROED(heap, size); -#else - ptr = DUK_ALLOC(heap, size); -#endif - if (DUK_UNLIKELY(ptr == NULL)) { - /* Because size > 0, NULL check is correct */ - goto alloc_error; - } - *out_bufdata = ptr; - - DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr); - } else { - *out_bufdata = NULL; -#if defined(DUK_USE_EXPLICIT_NULL_INIT) -#if defined(DUK_USE_HEAPPTR16) -/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */ -#else - DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL); -#endif -#endif - DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL); - } - } else { - *out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1); - } - - DUK_HBUFFER_SET_SIZE(res, size); - - DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER); - if (flags & DUK_BUF_FLAG_DYNAMIC) { - DUK_HBUFFER_SET_DYNAMIC(res); - if (flags & DUK_BUF_FLAG_EXTERNAL) { - DUK_HBUFFER_SET_EXTERNAL(res); - } - } else { - DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); - } - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr); - - DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res)); - return res; - - alloc_error: - DUK_DD(DUK_DDPRINT("hbuffer allocation failed")); - - DUK_FREE(heap, res); - return NULL; /* no need to write 'out_bufdata' */ -} - -/* For indirect allocs. */ - -DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) { - duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud; - DUK_UNREF(heap); - return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf); -} -#line 1 "duk_hbuffer_ops.c" -/* - * duk_hbuffer operations such as resizing and inserting/appending data to - * a dynamic buffer. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Resizing - */ - -DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) { - void *res; - duk_size_t prev_size; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(buf != NULL); - DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf)); - DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf)); - - /* - * Maximum size check - */ - - if (new_size > DUK_HBUFFER_MAX_BYTELEN) { - DUK_ERROR_RANGE(thr, "buffer too long"); - } - - /* - * Note: use indirect realloc variant just in case mark-and-sweep - * (finalizers) might resize this same buffer during garbage - * collection. - */ - - res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size); - if (DUK_LIKELY(res != NULL || new_size == 0)) { - /* 'res' may be NULL if new allocation size is 0. */ - - DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld", - (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf), - (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf), - (void *) res, - (long) new_size)); - - /* - * The entire allocated buffer area, regardless of actual used - * size, is kept zeroed in resizes for simplicity. If the buffer - * is grown, zero the new part. - */ - - prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf); - if (new_size > prev_size) { - DUK_ASSERT(new_size - prev_size > 0); -#if defined(DUK_USE_ZERO_BUFFER_DATA) - DUK_MEMZERO((void *) ((char *) res + prev_size), - (duk_size_t) (new_size - prev_size)); -#endif - } - - DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size); - DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res); - } else { - DUK_ERROR_ALLOC_FAILED(thr); - } - - DUK_ASSERT(res != NULL || new_size == 0); -} - -DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(buf != NULL); - DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf)); - DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf)); - - duk_hbuffer_resize(thr, buf, 0); -} -/* #include duk_internal.h -> already included */ -#line 2 "duk_hbufobj_misc.c" - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len) { - duk_uint_t buf_size; - duk_uint_t buf_avail; - - DUK_ASSERT(h_bufobj != NULL); - DUK_ASSERT(h_bufobj->buf != NULL); - - buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf); - if (h_bufobj->offset > buf_size) { - /* Slice starting point is beyond current length. */ - return 0; - } - buf_avail = buf_size - h_bufobj->offset; - - return buf_avail >= len ? len : buf_avail; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#line 1 "duk_heap_alloc.c" -/* - * duk_heap allocation and freeing. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_ROM_STRINGS) -/* Fixed seed value used with ROM strings. */ -#define DUK__FIXED_HASH_SEED 0xabcd1234 -#endif - -/* - * Free a heap object. - * - * Free heap object and its internal (non-heap) pointers. Assumes that - * caller has removed the object from heap allocated list or the string - * intern table, and any weak references (which strings may have) have - * been already dealt with. - */ - -DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) { - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h)); - - if (DUK_HOBJECT_IS_COMPFUNC(h)) { - duk_hcompfunc *f = (duk_hcompfunc *) h; - DUK_UNREF(f); - /* Currently nothing to free; 'data' is a heap object */ - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* Currently nothing to free */ - } else if (DUK_HOBJECT_IS_THREAD(h)) { - duk_hthread *t = (duk_hthread *) h; - duk_activation *act; - - DUK_FREE(heap, t->valstack); - - /* Don't free h->resumer because it exists in the heap. - * Callstack entries also contain function pointers which - * are not freed for the same reason. They are decref - * finalized and the targets are freed if necessary based - * on their refcount (or reachability). - */ - for (act = t->callstack_curr; act != NULL;) { - duk_activation *act_next; - duk_catcher *cat; - - for (cat = act->cat; cat != NULL;) { - duk_catcher *cat_next; - - cat_next = cat->parent; - DUK_FREE(heap, (void *) cat); - cat = cat_next; - } - - act_next = act->parent; - DUK_FREE(heap, (void *) act); - act = act_next; - } - - /* XXX: with 'caller' property the callstack would need - * to be unwound to update the 'caller' properties of - * functions in the callstack. - */ - } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { - duk_hboundfunc *f = (duk_hboundfunc *) h; - - DUK_FREE(heap, f->args); - } - - DUK_FREE(heap, (void *) h); -} - -DUK_INTERNAL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h) { - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) { - duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h; - DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g))); - DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)); - } - DUK_FREE(heap, (void *) h); -} - -DUK_INTERNAL void duk_free_hstring(duk_heap *heap, duk_hstring *h) { - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - DUK_UNREF(heap); - DUK_UNREF(h); - -#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE) - if (DUK_HSTRING_HAS_EXTDATA(h)) { - DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p", - h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h))); - DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)); - } -#endif - DUK_FREE(heap, (void *) h); -} - -DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) { - DUK_ASSERT(heap); - DUK_ASSERT(hdr); - - DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr))); - - switch (DUK_HEAPHDR_GET_TYPE(hdr)) { - case DUK_HTYPE_STRING: - duk_free_hstring(heap, (duk_hstring *) hdr); - break; - case DUK_HTYPE_OBJECT: - duk_free_hobject(heap, (duk_hobject *) hdr); - break; - default: - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER); - duk_free_hbuffer(heap, (duk_hbuffer *) hdr); - } - -} - -/* - * Free the heap. - * - * Frees heap-related non-heap-tracked allocations such as the - * string intern table; then frees the heap allocated objects; - * and finally frees the heap structure itself. Reference counts - * and GC markers are ignored (and not updated) in this process, - * and finalizers won't be called. - * - * The heap pointer and heap object pointers must not be used - * after this call. - */ - -#if defined(DUK_USE_CACHE_ACTIVATION) -DUK_LOCAL duk_size_t duk__heap_free_activation_freelist(duk_heap *heap) { - duk_activation *act; - duk_activation *act_next; - duk_size_t count_act = 0; - - for (act = heap->activation_free; act != NULL;) { - act_next = act->parent; - DUK_FREE(heap, (void *) act); - act = act_next; -#if defined(DUK_USE_DEBUG) - count_act++; -#endif - } - heap->activation_free = NULL; /* needed when called from mark-and-sweep */ - return count_act; -} -#endif /* DUK_USE_CACHE_ACTIVATION */ - -#if defined(DUK_USE_CACHE_CATCHER) -DUK_LOCAL duk_size_t duk__heap_free_catcher_freelist(duk_heap *heap) { - duk_catcher *cat; - duk_catcher *cat_next; - duk_size_t count_cat = 0; - - for (cat = heap->catcher_free; cat != NULL;) { - cat_next = cat->parent; - DUK_FREE(heap, (void *) cat); - cat = cat_next; -#if defined(DUK_USE_DEBUG) - count_cat++; -#endif - } - heap->catcher_free = NULL; /* needed when called from mark-and-sweep */ - - return count_cat; -} -#endif /* DUK_USE_CACHE_CATCHER */ - -DUK_INTERNAL void duk_heap_free_freelists(duk_heap *heap) { - duk_size_t count_act = 0; - duk_size_t count_cat = 0; - -#if defined(DUK_USE_CACHE_ACTIVATION) - count_act = duk__heap_free_activation_freelist(heap); -#endif -#if defined(DUK_USE_CACHE_CATCHER) - count_cat = duk__heap_free_catcher_freelist(heap); -#endif - DUK_UNREF(heap); - DUK_UNREF(count_act); - DUK_UNREF(count_cat); - - DUK_D(DUK_DPRINT("freed %ld activation freelist entries, %ld catcher freelist entries", - (long) count_act, (long) count_cat)); -} - -DUK_LOCAL void duk__free_allocated(duk_heap *heap) { - duk_heaphdr *curr; - duk_heaphdr *next; - - curr = heap->heap_allocated; - while (curr) { - /* We don't log or warn about freeing zero refcount objects - * because they may happen with finalizer processing. - */ - - DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO", - (duk_heaphdr *) curr)); - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - duk_heap_free_heaphdr_raw(heap, curr); - curr = next; - } -} - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) { - duk_heaphdr *curr; - duk_heaphdr *next; - - curr = heap->finalize_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO", - (duk_heaphdr *) curr)); - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - duk_heap_free_heaphdr_raw(heap, curr); - curr = next; - } -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -DUK_LOCAL void duk__free_stringtable(duk_heap *heap) { - /* strings are only tracked by stringtable */ - duk_heap_strtable_free(heap); -} - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) { - duk_heaphdr *curr; - duk_uint_t round_no; - duk_size_t count_all; - duk_size_t count_finalized; - duk_size_t curr_limit; - - DUK_ASSERT(heap != NULL); - -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */ -#endif - DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep last pass */ - - if (heap->heap_thread == NULL) { - /* May happen when heap allocation fails right off. There - * cannot be any finalizable objects in this case. - */ - DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects")); - return; - } - - /* Prevent finalize_list processing and mark-and-sweep entirely. - * Setting ms_running = 1 also prevents refzero handling from moving - * objects away from the heap_allocated list (the flag name is a bit - * misleading here). - */ - DUK_ASSERT(heap->pf_prevent_count == 0); - heap->pf_prevent_count = 1; - DUK_ASSERT(heap->ms_running == 0); - heap->ms_running = 1; - DUK_ASSERT(heap->ms_prevent_count == 0); - heap->ms_prevent_count = 1; /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */ - - curr_limit = 0; /* suppress warning, not used */ - for (round_no = 0; ; round_no++) { - curr = heap->heap_allocated; - count_all = 0; - count_finalized = 0; - while (curr) { - count_all++; - if (DUK_HEAPHDR_IS_OBJECT(curr)) { - /* Only objects in heap_allocated may have finalizers. Check that - * the object itself has a _Finalizer property (own or inherited) - * so that we don't execute finalizers for e.g. Proxy objects. - */ - DUK_ASSERT(curr != NULL); - - if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) { - if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) { - DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */ - duk_heap_run_finalizer(heap, (duk_hobject *) curr); - count_finalized++; - } - } - } - curr = DUK_HEAPHDR_GET_NEXT(heap, curr); - } - - /* Each round of finalizer execution may spawn new finalizable objects - * which is normal behavior for some applications. Allow multiple - * rounds of finalization, but use a shrinking limit based on the - * first round to detect the case where a runaway finalizer creates - * an unbounded amount of new finalizable objects. Finalizer rescue - * is not supported: the semantics are unclear because most of the - * objects being finalized here are already reachable. The finalizer - * is given a boolean to indicate that rescue is not possible. - * - * See discussion in: https://github.com/svaarala/duktape/pull/473 - */ - - if (round_no == 0) { - /* Cannot wrap: each object is at least 8 bytes so count is - * at most 1/8 of that. - */ - curr_limit = count_all * 2; - } else { - curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */ - } - DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld", - (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit)); - - if (count_finalized == 0) { - DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished")); - break; - } - if (count_finalized >= curr_limit) { - DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers")); - break; - } - } - - DUK_ASSERT(heap->ms_running == 1); - heap->ms_running = 0; - DUK_ASSERT(heap->pf_prevent_count == 1); - heap->pf_prevent_count = 0; -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -DUK_INTERNAL void duk_heap_free(duk_heap *heap) { - DUK_D(DUK_DPRINT("free heap: %p", (void *) heap)); - -#if defined(DUK_USE_DEBUG) - duk_heap_strtable_dump(heap); -#endif - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - /* Detach a debugger if attached (can be called multiple times) - * safely. - */ - /* XXX: Add a flag to reject an attempt to re-attach? Otherwise - * the detached callback may immediately reattach. - */ - duk_debug_do_detach(heap); -#endif - - /* Execute finalizers before freeing the heap, even for reachable - * objects. This gives finalizers the chance to free any native - * resources like file handles, allocations made outside Duktape, - * etc. This is quite tricky to get right, so that all finalizer - * guarantees are honored. - * - * Run mark-and-sweep a few times just in case (unreachable object - * finalizers run already here). The last round must rescue objects - * from the previous round without running any more finalizers. This - * ensures rescued objects get their FINALIZED flag cleared so that - * their finalizer is called once more in forced finalization to - * satisfy finalizer guarantees. However, we don't want to run any - * more finalizers because that'd required one more loop, and so on. - * - * XXX: this perhaps requires an execution time limit. - */ - DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); - DUK_ASSERT(heap->pf_skip_finalizers == 0); - DUK_D(DUK_DPRINT("forced gc #1 in heap destruction")); - duk_heap_mark_and_sweep(heap, 0); - DUK_D(DUK_DPRINT("forced gc #2 in heap destruction")); - duk_heap_mark_and_sweep(heap, 0); - DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)")); - heap->pf_skip_finalizers = 1; - duk_heap_mark_and_sweep(heap, 0); /* Skip finalizers; queue finalizable objects to heap_allocated. */ - - /* There are never objects in refzero_list at this point, or at any - * point beyond a DECREF (even a DECREF_NORZ). Since Duktape 2.1 - * refzero_list processing is side effect free, so it is always - * processed to completion by a DECREF initially triggering a zero - * refcount. - */ -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ -#endif -#if defined(DUK_USE_FINALIZER_SUPPORT) - DUK_ASSERT(heap->finalize_list == NULL); /* Last mark-and-sweep with skip_finalizers. */ -#endif - -#if defined(DUK_USE_FINALIZER_SUPPORT) - DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects")); - DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* Rescue no longer supported. */ - duk__free_run_finalizers(heap); -#endif /* DUK_USE_FINALIZER_SUPPORT */ - - /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object - * are on the heap allocated list. - */ - - DUK_D(DUK_DPRINT("freeing temporary freelists")); - duk_heap_free_freelists(heap); - - DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap)); - duk__free_allocated(heap); - -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ -#endif - -#if defined(DUK_USE_FINALIZER_SUPPORT) - DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p", (void *) heap)); - duk__free_finalize_list(heap); -#endif - - DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap)); - duk__free_stringtable(heap); - - DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap)); - heap->free_func(heap->heap_udata, heap); -} - -/* - * Allocate a heap. - * - * String table is initialized with built-in strings from genbuiltins.py, - * either by dynamically creating the strings or by referring to ROM strings. - */ - -#if defined(DUK_USE_ROM_STRINGS) -DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) { -#if defined(DUK_USE_ASSERTIONS) - duk_small_uint_t i; -#endif - - DUK_UNREF(heap); - - /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted - * so nothing to initialize for strs[]. - */ - -#if defined(DUK_USE_ASSERTIONS) - for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) { - const duk_hstring *h; - duk_uint32_t hash; - - h = duk_rom_strings_lookup[i]; - while (h != NULL) { - hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); - DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx", - (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); - DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); - - h = (const duk_hstring *) h->hdr.h_next; - } - } -#endif - return 1; -} -#else /* DUK_USE_ROM_STRINGS */ - -DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) { - duk_bitdecoder_ctx bd_ctx; - duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */ - duk_small_uint_t i; - - DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); - bd->data = (const duk_uint8_t *) duk_strings_data; - bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH; - - for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { - duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN]; - duk_small_uint_t len; - duk_hstring *h; - - len = duk_bd_decode_bitpacked_string(bd, tmp); - - /* No need to length check string: it will never exceed even - * the 16-bit length maximum. - */ - DUK_ASSERT(len <= 0xffffUL); - DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i)); - h = duk_heap_strtable_intern(heap, tmp, len); - if (!h) { - goto failed; - } - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); - - /* Special flags checks. Since these strings are always - * reachable and a string cannot appear twice in the string - * table, there's no need to check/set these flags elsewhere. - * The 'internal' flag is set by string intern code. - */ - if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) { - DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h); - } - if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) { - DUK_HSTRING_SET_RESERVED_WORD(h); - if (i >= DUK_STRIDX_START_STRICT_RESERVED) { - DUK_HSTRING_SET_STRICT_RESERVED_WORD(h); - } - } - - DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h)); - - /* XXX: The incref macro takes a thread pointer but doesn't - * use it right now. - */ - DUK_HSTRING_INCREF(_never_referenced_, h); - -#if defined(DUK_USE_HEAPPTR16) - heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#else - heap->strs[i] = h; -#endif - } - - return 1; - - failed: - return 0; -} -#endif /* DUK_USE_ROM_STRINGS */ - -DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) { - duk_hthread *thr; - - DUK_D(DUK_DPRINT("heap init: alloc heap thread")); - thr = duk_hthread_alloc_unchecked(heap, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (thr == NULL) { - DUK_D(DUK_DPRINT("failed to alloc heap_thread")); - return 0; - } - thr->state = DUK_HTHREAD_STATE_INACTIVE; -#if defined(DUK_USE_ROM_STRINGS) - /* No strs[] pointer. */ -#else /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_HEAPPTR16) - thr->strs16 = heap->strs16; -#else - thr->strs = heap->strs; -#endif -#endif /* DUK_USE_ROM_STRINGS */ - - heap->heap_thread = thr; - DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */ - - /* 'thr' is now reachable */ - - DUK_D(DUK_DPRINT("heap init: init heap thread stacks")); - if (!duk_hthread_init_stacks(heap, thr)) { - return 0; - } - - /* XXX: this may now fail, and is not handled correctly */ - duk_hthread_create_builtin_objects(thr); - - /* default prototype */ - DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]); - - return 1; -} - -#if defined(DUK_USE_DEBUG) -#define DUK__DUMPSZ(t) do { \ - DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \ - } while (0) - -/* These is not 100% because format would need to be non-portable "long long". - * Also print out as doubles to catch cases where the "long" type is not wide - * enough; the limits will then not be printed accurately but the magnitude - * will be correct. - */ -#define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \ - DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \ - (long) (a), (long) (b), \ - (double) (a), (double) (b))); \ - } while (0) -#define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \ - DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \ - (unsigned long) (a), (unsigned long) (b), \ - (double) (a), (double) (b))); \ - } while (0) -#define DUK__DUMPLM_SIGNED(t) do { \ - DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \ - } while (0) -#define DUK__DUMPLM_UNSIGNED(t) do { \ - DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \ - } while (0) - -DUK_LOCAL void duk__dump_type_sizes(void) { - DUK_D(DUK_DPRINT("sizeof()")); - - /* basic platform types */ - DUK__DUMPSZ(char); - DUK__DUMPSZ(short); - DUK__DUMPSZ(int); - DUK__DUMPSZ(long); - DUK__DUMPSZ(double); - DUK__DUMPSZ(void *); - DUK__DUMPSZ(size_t); - - /* basic types from duk_features.h */ - DUK__DUMPSZ(duk_uint8_t); - DUK__DUMPSZ(duk_int8_t); - DUK__DUMPSZ(duk_uint16_t); - DUK__DUMPSZ(duk_int16_t); - DUK__DUMPSZ(duk_uint32_t); - DUK__DUMPSZ(duk_int32_t); - DUK__DUMPSZ(duk_uint64_t); - DUK__DUMPSZ(duk_int64_t); - DUK__DUMPSZ(duk_uint_least8_t); - DUK__DUMPSZ(duk_int_least8_t); - DUK__DUMPSZ(duk_uint_least16_t); - DUK__DUMPSZ(duk_int_least16_t); - DUK__DUMPSZ(duk_uint_least32_t); - DUK__DUMPSZ(duk_int_least32_t); -#if defined(DUK_USE_64BIT_OPS) - DUK__DUMPSZ(duk_uint_least64_t); - DUK__DUMPSZ(duk_int_least64_t); -#endif - DUK__DUMPSZ(duk_uint_fast8_t); - DUK__DUMPSZ(duk_int_fast8_t); - DUK__DUMPSZ(duk_uint_fast16_t); - DUK__DUMPSZ(duk_int_fast16_t); - DUK__DUMPSZ(duk_uint_fast32_t); - DUK__DUMPSZ(duk_int_fast32_t); -#if defined(DUK_USE_64BIT_OPS) - DUK__DUMPSZ(duk_uint_fast64_t); - DUK__DUMPSZ(duk_int_fast64_t); -#endif - DUK__DUMPSZ(duk_uintptr_t); - DUK__DUMPSZ(duk_intptr_t); - DUK__DUMPSZ(duk_uintmax_t); - DUK__DUMPSZ(duk_intmax_t); - DUK__DUMPSZ(duk_double_t); - - /* important chosen base types */ - DUK__DUMPSZ(duk_int_t); - DUK__DUMPSZ(duk_uint_t); - DUK__DUMPSZ(duk_int_fast_t); - DUK__DUMPSZ(duk_uint_fast_t); - DUK__DUMPSZ(duk_small_int_t); - DUK__DUMPSZ(duk_small_uint_t); - DUK__DUMPSZ(duk_small_int_fast_t); - DUK__DUMPSZ(duk_small_uint_fast_t); - - /* some derived types */ - DUK__DUMPSZ(duk_codepoint_t); - DUK__DUMPSZ(duk_ucodepoint_t); - DUK__DUMPSZ(duk_idx_t); - DUK__DUMPSZ(duk_errcode_t); - DUK__DUMPSZ(duk_uarridx_t); - - /* tval */ - DUK__DUMPSZ(duk_double_union); - DUK__DUMPSZ(duk_tval); - - /* structs from duk_forwdecl.h */ - DUK__DUMPSZ(duk_jmpbuf); /* just one 'int' for C++ exceptions */ - DUK__DUMPSZ(duk_heaphdr); - DUK__DUMPSZ(duk_heaphdr_string); - DUK__DUMPSZ(duk_hstring); - DUK__DUMPSZ(duk_hstring_external); - DUK__DUMPSZ(duk_hobject); - DUK__DUMPSZ(duk_harray); - DUK__DUMPSZ(duk_hcompfunc); - DUK__DUMPSZ(duk_hnatfunc); - DUK__DUMPSZ(duk_hdecenv); - DUK__DUMPSZ(duk_hobjenv); - DUK__DUMPSZ(duk_hthread); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - DUK__DUMPSZ(duk_hbufobj); -#endif - DUK__DUMPSZ(duk_hproxy); - DUK__DUMPSZ(duk_hbuffer); - DUK__DUMPSZ(duk_hbuffer_fixed); - DUK__DUMPSZ(duk_hbuffer_dynamic); - DUK__DUMPSZ(duk_hbuffer_external); - DUK__DUMPSZ(duk_propaccessor); - DUK__DUMPSZ(duk_propvalue); - DUK__DUMPSZ(duk_propdesc); - DUK__DUMPSZ(duk_heap); - DUK__DUMPSZ(duk_activation); - DUK__DUMPSZ(duk_catcher); - DUK__DUMPSZ(duk_strcache); - DUK__DUMPSZ(duk_ljstate); - DUK__DUMPSZ(duk_fixedbuffer); - DUK__DUMPSZ(duk_bitdecoder_ctx); - DUK__DUMPSZ(duk_bitencoder_ctx); - DUK__DUMPSZ(duk_token); - DUK__DUMPSZ(duk_re_token); - DUK__DUMPSZ(duk_lexer_point); - DUK__DUMPSZ(duk_lexer_ctx); - DUK__DUMPSZ(duk_compiler_instr); - DUK__DUMPSZ(duk_compiler_func); - DUK__DUMPSZ(duk_compiler_ctx); - DUK__DUMPSZ(duk_re_matcher_ctx); - DUK__DUMPSZ(duk_re_compiler_ctx); -} -DUK_LOCAL void duk__dump_type_limits(void) { - DUK_D(DUK_DPRINT("limits")); - - /* basic types */ - DUK__DUMPLM_SIGNED(INT8); - DUK__DUMPLM_UNSIGNED(UINT8); - DUK__DUMPLM_SIGNED(INT_FAST8); - DUK__DUMPLM_UNSIGNED(UINT_FAST8); - DUK__DUMPLM_SIGNED(INT_LEAST8); - DUK__DUMPLM_UNSIGNED(UINT_LEAST8); - DUK__DUMPLM_SIGNED(INT16); - DUK__DUMPLM_UNSIGNED(UINT16); - DUK__DUMPLM_SIGNED(INT_FAST16); - DUK__DUMPLM_UNSIGNED(UINT_FAST16); - DUK__DUMPLM_SIGNED(INT_LEAST16); - DUK__DUMPLM_UNSIGNED(UINT_LEAST16); - DUK__DUMPLM_SIGNED(INT32); - DUK__DUMPLM_UNSIGNED(UINT32); - DUK__DUMPLM_SIGNED(INT_FAST32); - DUK__DUMPLM_UNSIGNED(UINT_FAST32); - DUK__DUMPLM_SIGNED(INT_LEAST32); - DUK__DUMPLM_UNSIGNED(UINT_LEAST32); -#if defined(DUK_USE_64BIT_OPS) - DUK__DUMPLM_SIGNED(INT64); - DUK__DUMPLM_UNSIGNED(UINT64); - DUK__DUMPLM_SIGNED(INT_FAST64); - DUK__DUMPLM_UNSIGNED(UINT_FAST64); - DUK__DUMPLM_SIGNED(INT_LEAST64); - DUK__DUMPLM_UNSIGNED(UINT_LEAST64); -#endif - DUK__DUMPLM_SIGNED(INTPTR); - DUK__DUMPLM_UNSIGNED(UINTPTR); - DUK__DUMPLM_SIGNED(INTMAX); - DUK__DUMPLM_UNSIGNED(UINTMAX); - - /* derived types */ - DUK__DUMPLM_SIGNED(INT); - DUK__DUMPLM_UNSIGNED(UINT); - DUK__DUMPLM_SIGNED(INT_FAST); - DUK__DUMPLM_UNSIGNED(UINT_FAST); - DUK__DUMPLM_SIGNED(SMALL_INT); - DUK__DUMPLM_UNSIGNED(SMALL_UINT); - DUK__DUMPLM_SIGNED(SMALL_INT_FAST); - DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST); -} - -DUK_LOCAL void duk__dump_misc_options(void) { - DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION)); - DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE)); - DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING)); - DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING)); - DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING)); - DUK_D(DUK_DPRINT("debug level: %ld", (long) DUK_USE_DEBUG_LEVEL)); -#if defined(DUK_USE_PACKED_TVAL) - DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes")); -#else - DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no")); -#endif -#if defined(DUK_USE_VARIADIC_MACROS) - DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes")); -#else - DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no")); -#endif -#if defined(DUK_USE_INTEGER_LE) - DUK_D(DUK_DPRINT("integer endianness: little")); -#elif defined(DUK_USE_INTEGER_ME) - DUK_D(DUK_DPRINT("integer endianness: mixed")); -#elif defined(DUK_USE_INTEGER_BE) - DUK_D(DUK_DPRINT("integer endianness: big")); -#else - DUK_D(DUK_DPRINT("integer endianness: ???")); -#endif -#if defined(DUK_USE_DOUBLE_LE) - DUK_D(DUK_DPRINT("IEEE double endianness: little")); -#elif defined(DUK_USE_DOUBLE_ME) - DUK_D(DUK_DPRINT("IEEE double endianness: mixed")); -#elif defined(DUK_USE_DOUBLE_BE) - DUK_D(DUK_DPRINT("IEEE double endianness: big")); -#else - DUK_D(DUK_DPRINT("IEEE double endianness: ???")); -#endif -} -#endif /* DUK_USE_DEBUG */ - -DUK_INTERNAL -duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, - duk_realloc_function realloc_func, - duk_free_function free_func, - void *heap_udata, - duk_fatal_function fatal_func) { - duk_heap *res = NULL; - duk_uint32_t st_initsize; - - DUK_D(DUK_DPRINT("allocate heap")); - - /* - * Random config sanity asserts - */ - - DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64); - - DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0); - DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0); - DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1); /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */ - - /* - * Debug dump type sizes - */ - -#if defined(DUK_USE_DEBUG) - duk__dump_misc_options(); - duk__dump_type_sizes(); - duk__dump_type_limits(); -#endif - - /* - * If selftests enabled, run them as early as possible. - */ - -#if defined(DUK_USE_SELF_TESTS) - DUK_D(DUK_DPRINT("run self tests")); - if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) { - fatal_func(heap_udata, "self test(s) failed"); - } - DUK_D(DUK_DPRINT("self tests passed")); -#endif - - /* - * Important assert-like checks that should be enabled even - * when assertions are otherwise not enabled. - */ - -#if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE) - /* Can't check sizeof() using preprocessor so explicit check. - * This will be optimized away in practice; unfortunately a - * warning is generated on some compilers as a result. - */ -#if defined(DUK_USE_PACKED_TVAL) - if (sizeof(duk_tval) != 8) { -#else - if (sizeof(duk_tval) != 16) { -#endif - fatal_func(heap_udata, "sizeof(duk_tval) not 8 or 16, cannot use DUK_USE_EXEC_REGCONST_OPTIMIZE option"); - } -#endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */ - - /* - * Computed values (e.g. INFINITY) - */ - -#if defined(DUK_USE_COMPUTED_NAN) - do { - /* Workaround for some exotic platforms where NAN is missing - * and the expression (0.0 / 0.0) does NOT result in a NaN. - * Such platforms use the global 'duk_computed_nan' which must - * be initialized at runtime. Use 'volatile' to ensure that - * the compiler will actually do the computation and not try - * to do constant folding which might result in the original - * problem. - */ - volatile double dbl1 = 0.0; - volatile double dbl2 = 0.0; - duk_computed_nan = dbl1 / dbl2; - } while (0); -#endif - -#if defined(DUK_USE_COMPUTED_INFINITY) - do { - /* Similar workaround for INFINITY. */ - volatile double dbl1 = 1.0; - volatile double dbl2 = 0.0; - duk_computed_infinity = dbl1 / dbl2; - } while (0); -#endif - - /* - * Allocate heap struct - * - * Use a raw call, all macros expect the heap to be initialized - */ - -#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1) - goto failed; -#endif - DUK_D(DUK_DPRINT("alloc duk_heap object")); - res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap)); - if (!res) { - goto failed; - } - - /* - * Zero the struct, and start initializing roughly in order - */ - - DUK_MEMZERO(res, sizeof(*res)); -#if defined(DUK_USE_ASSERTIONS) - res->heap_initializing = 1; -#endif - - /* explicit NULL inits */ -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - res->heap_udata = NULL; - res->heap_allocated = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - res->refzero_list = NULL; -#endif -#if defined(DUK_USE_FINALIZER_SUPPORT) - res->finalize_list = NULL; -#if defined(DUK_USE_ASSERTIONS) - res->currently_finalizing = NULL; -#endif -#endif -#if defined(DUK_USE_CACHE_ACTIVATION) - res->activation_free = NULL; -#endif -#if defined(DUK_USE_CACHE_CATCHER) - res->catcher_free = NULL; -#endif - res->heap_thread = NULL; - res->curr_thread = NULL; - res->heap_object = NULL; -#if defined(DUK_USE_STRTAB_PTRCOMP) - res->strtable16 = NULL; -#else - res->strtable = NULL; -#endif -#if defined(DUK_USE_ROM_STRINGS) - /* no res->strs[] */ -#else /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_HEAPPTR16) - /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */ -#else - { - duk_small_uint_t i; - for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { - res->strs[i] = NULL; - } - } -#endif -#endif /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - res->dbg_read_cb = NULL; - res->dbg_write_cb = NULL; - res->dbg_peek_cb = NULL; - res->dbg_read_flush_cb = NULL; - res->dbg_write_flush_cb = NULL; - res->dbg_request_cb = NULL; - res->dbg_udata = NULL; - res->dbg_pause_act = NULL; -#endif -#endif /* DUK_USE_EXPLICIT_NULL_INIT */ - - res->alloc_func = alloc_func; - res->realloc_func = realloc_func; - res->free_func = free_func; - res->heap_udata = heap_udata; - res->fatal_func = fatal_func; - - /* XXX: for now there's a pointer packing zero assumption, i.e. - * NULL <=> compressed pointer 0. If this is removed, may need - * to precompute e.g. null16 here. - */ - - /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */ - - /* Prevent mark-and-sweep and finalizer execution until heap is completely - * initialized. - */ - DUK_ASSERT(res->ms_prevent_count == 0); - DUK_ASSERT(res->pf_prevent_count == 0); - res->ms_prevent_count = 1; - res->pf_prevent_count = 1; - DUK_ASSERT(res->ms_running == 0); - - res->call_recursion_depth = 0; - res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT; - - /* XXX: use the pointer as a seed for now: mix in time at least */ - - /* The casts through duk_intptr_t is to avoid the following GCC warning: - * - * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] - * - * This still generates a /Wp64 warning on VS2010 when compiling for x86. - */ -#if defined(DUK_USE_ROM_STRINGS) - /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */ - DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED)); - res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED; -#else /* DUK_USE_ROM_STRINGS */ - res->hash_seed = (duk_uint32_t) (duk_intptr_t) res; -#if !defined(DUK_USE_STRHASH_DENSE) - res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */ -#endif -#endif /* DUK_USE_ROM_STRINGS */ - -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - res->lj.jmpbuf_ptr = NULL; -#endif - DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ - DUK_ASSERT(res->lj.iserror == 0); - DUK_TVAL_SET_UNDEFINED(&res->lj.value1); - DUK_TVAL_SET_UNDEFINED(&res->lj.value2); - - DUK_ASSERT_LJSTATE_UNSET(res); - - /* - * Init stringtable: fixed variant - */ - - st_initsize = DUK_USE_STRTAB_MINSIZE; -#if defined(DUK_USE_STRTAB_PTRCOMP) - res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize); - if (res->strtable16 == NULL) { - goto failed; - } -#else - res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize); - if (res->strtable == NULL) { - goto failed; - } -#endif - res->st_size = st_initsize; - res->st_mask = st_initsize - 1; -#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE) - DUK_ASSERT(res->st_count == 0); -#endif - -#if defined(DUK_USE_STRTAB_PTRCOMP) - /* zero assumption */ - DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * st_initsize); -#else -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - { - duk_small_uint_t i; - for (i = 0; i < st_initsize; i++) { - res->strtable[i] = NULL; - } - } -#else - DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * st_initsize); -#endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_PTRCOMP */ - - /* - * Init stringcache - */ - -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - { - duk_small_uint_t i; - for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - res->strcache[i].h = NULL; - } - } -#endif - - /* XXX: error handling is incomplete. It would be cleanest if - * there was a setjmp catchpoint, so that all init code could - * freely throw errors. If that were the case, the return code - * passing here could be removed. - */ - - /* - * Init built-in strings - */ - -#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2) - goto failed; -#endif - DUK_D(DUK_DPRINT("heap init: initialize heap strings")); - if (!duk__init_heap_strings(res)) { - goto failed; - } - - /* - * Init the heap thread - */ - -#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3) - goto failed; -#endif - DUK_D(DUK_DPRINT("heap init: initialize heap thread")); - if (!duk__init_heap_thread(res)) { - goto failed; - } - - /* - * Init the heap object - */ - -#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4) - goto failed; -#endif - DUK_D(DUK_DPRINT("heap init: initialize heap object")); - DUK_ASSERT(res->heap_thread != NULL); - res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); - if (res->heap_object == NULL) { - goto failed; - } - DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object); - - /* - * Odds and ends depending on the heap thread - */ - -#if !defined(DUK_USE_GET_RANDOM_DOUBLE) -#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS) - res->rnd_state = (duk_uint32_t) duk_time_get_ecmascript_time(res->heap_thread); - duk_util_tinyrandom_prepare_seed(res->heap_thread); -#else - res->rnd_state[0] = (duk_uint64_t) duk_time_get_ecmascript_time(res->heap_thread); - DUK_ASSERT(res->rnd_state[1] == 0); /* Not filled here, filled in by seed preparation. */ -#if 0 /* Manual test values matching misc/xoroshiro128plus_test.c. */ - res->rnd_state[0] = DUK_U64_CONSTANT(0xdeadbeef12345678); - res->rnd_state[1] = DUK_U64_CONSTANT(0xcafed00d12345678); -#endif - duk_util_tinyrandom_prepare_seed(res->heap_thread); - /* Mix in heap pointer: this ensures that if two Duktape heaps are - * created on the same millisecond, they get a different PRNG - * sequence (unless e.g. virtual memory addresses cause also the - * heap object pointer to be the same). - */ - { - duk_uint64_t tmp_u64; - tmp_u64 = 0; - DUK_MEMCPY((void *) &tmp_u64, - (const void *) &res, - (size_t) (sizeof(void *) >= sizeof(duk_uint64_t) ? sizeof(duk_uint64_t) : sizeof(void *))); - res->rnd_state[1] ^= tmp_u64; - } - do { - duk_small_uint_t i; - for (i = 0; i < 10; i++) { - /* Throw away a few initial random numbers just in - * case. Probably unnecessary due to SplitMix64 - * preparation. - */ - (void) duk_util_tinyrandom_get_double(res->heap_thread); - } - } while (0); -#endif -#endif - - /* - * Allow finalizer and mark-and-sweep processing. - */ - - DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing")); - DUK_ASSERT(res->ms_prevent_count == 1); - DUK_ASSERT(res->pf_prevent_count == 1); - res->ms_prevent_count = 0; - res->pf_prevent_count = 0; - DUK_ASSERT(res->ms_running == 0); -#if defined(DUK_USE_ASSERTIONS) - res->heap_initializing = 0; -#endif - - /* - * All done. - */ - - DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res)); - return res; - - failed: - DUK_D(DUK_DPRINT("heap allocation failed")); - - if (res != NULL) { - /* Assumes that allocated pointers and alloc funcs are valid - * if res exists. - */ - DUK_ASSERT(res->ms_prevent_count == 1); - DUK_ASSERT(res->pf_prevent_count == 1); - DUK_ASSERT(res->ms_running == 0); - if (res->heap_thread != NULL) { - res->ms_prevent_count = 0; - res->pf_prevent_count = 0; - } -#if defined(DUK_USE_ASSERTIONS) - res->heap_initializing = 0; -#endif - - DUK_ASSERT(res->alloc_func != NULL); - DUK_ASSERT(res->realloc_func != NULL); - DUK_ASSERT(res->free_func != NULL); - duk_heap_free(res); - } - - return NULL; -} - -/* automatic undefs */ -#undef DUK__DUMPLM_SIGNED -#undef DUK__DUMPLM_SIGNED_RAW -#undef DUK__DUMPLM_UNSIGNED -#undef DUK__DUMPLM_UNSIGNED_RAW -#undef DUK__DUMPSZ -#undef DUK__FIXED_HASH_SEED -#line 1 "duk_heap_finalize.c" -/* - * Finalizer handling. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) - -/* - * Fake torture finalizer. - */ - -#if defined(DUK_USE_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_hthread *thr) { - DUK_DD(DUK_DDPRINT("fake global torture finalizer executed")); - - /* Require a lot of stack to force a value stack grow/shrink. */ - duk_require_stack(thr, 100000); - - /* Force a reallocation with pointer change for value stack - * to maximize side effects. - */ - duk_hthread_valstack_torture_realloc(thr); - - /* Inner function call, error throw. */ - duk_eval_string_noresult(thr, - "(function dummy() {\n" - " dummy.prototype = null; /* break reference loop */\n" - " try {\n" - " throw 'fake-finalizer-dummy-error';\n" - " } catch (e) {\n" - " void e;\n" - " }\n" - "})()"); - - /* The above creates garbage (e.g. a function instance). Because - * the function/prototype reference loop is broken, it gets collected - * immediately by DECREF. If Function.prototype has a _Finalizer - * property (happens in some test cases), the garbage gets queued to - * finalize_list. This still won't cause an infinite loop because - * the torture finalizer is called once per finalize_list run and - * the garbage gets handled in the same run. (If the garbage needs - * mark-and-sweep collection, an infinite loop might ensue.) - */ - return 0; -} - -DUK_LOCAL void duk__run_global_torture_finalizer(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - - /* Avoid fake finalization when callstack limit is near. Otherwise - * a callstack limit error will be created, then refzero'ed. The - * +5 headroom is conservative. - */ - if (thr->heap->call_recursion_depth + 5 >= thr->heap->call_recursion_limit || - thr->callstack_top + 5 >= DUK_USE_CALLSTACK_LIMIT) { - DUK_D(DUK_DPRINT("skip global torture finalizer, too little headroom for call recursion or call stack size")); - return; - } - - /* Run fake finalizer. Avoid creating unnecessary garbage. */ - duk_push_c_function(thr, duk__fake_global_finalizer, 0 /*nargs*/); - (void) duk_pcall(thr, 0 /*nargs*/); - duk_pop(thr); -} -#endif /* DUK_USE_FINALIZER_TORTURE */ - -/* - * Process the finalize_list to completion. - * - * An object may be placed on finalize_list by either refcounting or - * mark-and-sweep. The refcount of objects placed by refcounting will be - * zero; the refcount of objects placed by mark-and-sweep is > 0. In both - * cases the refcount is bumped by 1 artificially so that a REFZERO event - * can never happen while an object is waiting for finalization. Without - * this bump a REFZERO could now happen because user code may call - * duk_push_heapptr() and then pop a value even when it's on finalize_list. - * - * List processing assumes refcounts are kept up-to-date at all times, so - * that once the finalizer returns, a zero refcount is a reliable reason to - * free the object immediately rather than place it back to the heap. This - * is the case because we run outside of refzero_list processing so that - * DECREF cascades are handled fully inline. - * - * For mark-and-sweep queued objects (had_zero_refcount false) the object - * may be freed immediately if its refcount is zero after the finalizer call - * (i.e. finalizer removed the reference loop for the object). If not, the - * next mark-and-sweep will collect the object unless it has become reachable - * (i.e. rescued) by that time and its refcount hasn't fallen to zero before - * that. Mark-and-sweep detects these objects because their FINALIZED flag - * is set. - * - * There's an inherent limitation for mark-and-sweep finalizer rescuing: an - * object won't get refinalized if (1) it's rescued, but (2) becomes - * unreachable before mark-and-sweep has had time to notice it. The next - * mark-and-sweep round simply doesn't have any information of whether the - * object has been unreachable the whole time or not (the only way to get - * that information would be a mark-and-sweep pass for *every finalized - * object*). This is awkward for the application because the mark-and-sweep - * round is not generally visible or under full application control. - * - * For refcount queued objects (had_zero_refcount true) the object is either - * immediately freed or rescued, and waiting for a mark-and-sweep round is not - * necessary (or desirable); FINALIZED is cleared when a rescued object is - * queued back to heap_allocated. The object is eligible for finalization - * again (either via refcounting or mark-and-sweep) immediately after being - * rescued. If a refcount finalized object is placed into an unreachable - * reference loop by its finalizer, it will get collected by mark-and-sweep - * and currently the finalizer will execute again. - * - * There's a special case where: - * - * - Mark-and-sweep queues an object to finalize_list for finalization. - * - The finalizer is executed, FINALIZED is set, and object is queued - * back to heap_allocated, waiting for a new mark-and-sweep round. - * - The object's refcount drops to zero before mark-and-sweep has a - * chance to run another round and make a rescue/free decision. - * - * This is now handled by refzero code: if an object has a finalizer but - * FINALIZED is already set, the object is freed without finalizer processing. - * The outcome is the same as if mark-and-sweep was executed at that point; - * mark-and-sweep would also free the object without another finalizer run. - * This could also be changed so that the refzero-triggered finalizer *IS* - * executed: being refzero collected implies someone has operated on the - * object so it hasn't been totally unreachable the whole time. This would - * risk a finalizer loop however. - */ - -DUK_INTERNAL void duk_heap_process_finalize_list(duk_heap *heap) { - duk_heaphdr *curr; -#if defined(DUK_USE_DEBUG) - duk_size_t count = 0; -#endif - - DUK_DDD(DUK_DDDPRINT("duk_heap_process_finalize_list: %p", (void *) heap)); - - if (heap->pf_prevent_count != 0) { - DUK_DDD(DUK_DDDPRINT("skip finalize_list processing: pf_prevent_count != 0")); - return; - } - - /* Heap alloc prevents mark-and-sweep before heap_thread is ready. */ - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); - DUK_ASSERT(heap->heap_thread->valstack != NULL); -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(heap->refzero_list == NULL); -#endif - - DUK_ASSERT(heap->pf_prevent_count == 0); - heap->pf_prevent_count = 1; - - /* Mark-and-sweep no longer needs to be prevented when running - * finalizers: mark-and-sweep skips any rescue decisions if there - * are any objects in finalize_list when mark-and-sweep is entered. - * This protects finalized objects from incorrect rescue decisions - * caused by finalize_list being a reachability root and only - * partially processed. Freeing decisions are not postponed. - */ - - /* When finalizer torture is enabled, make a fake finalizer call with - * maximum side effects regardless of whether finalize_list is empty. - */ -#if defined(DUK_USE_FINALIZER_TORTURE) - duk__run_global_torture_finalizer(heap->heap_thread); -#endif - - /* Process finalize_list until it becomes empty. There's currently no - * protection against a finalizer always creating more garbage. - */ - while ((curr = heap->finalize_list) != NULL) { -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_bool_t queue_back; -#endif - - DUK_DD(DUK_DDPRINT("processing finalize_list entry: %p -> %!iO", (void *) curr, curr)); - - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* Only objects have finalizers. */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr)); - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); /* All objects on finalize_list will have this flag (except object being finalized right now). */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); /* Queueing code ensures. */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* ROM objects never get freed (or finalized). */ - -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(heap->currently_finalizing == NULL); - heap->currently_finalizing = curr; -#endif - - /* Clear FINALIZABLE for object being finalized, so that - * duk_push_heapptr() can properly ignore the object. - */ - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - - if (DUK_LIKELY(!heap->pf_skip_finalizers)) { - /* Run the finalizer, duk_heap_run_finalizer() sets - * and checks for FINALIZED to prevent the finalizer - * from executing multiple times per finalization cycle. - * (This safeguard shouldn't be actually needed anymore). - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_bool_t had_zero_refcount; -#endif - - /* The object's refcount is >0 throughout so it won't be - * refzero processed prematurely. - */ -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); - had_zero_refcount = (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1); /* Preincremented on finalize_list insert. */ -#endif - - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - duk_heap_run_finalizer(heap, (duk_hobject *) curr); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr)); - /* XXX: assert that object is still in finalize_list - * when duk_push_heapptr() allows automatic rescue. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_DD(DUK_DDPRINT("refcount after finalizer (includes bump): %ld", (long) DUK_HEAPHDR_GET_REFCOUNT(curr))); - if (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1) { /* Only artificial bump in refcount? */ -#if defined(DUK_USE_DEBUG) - if (had_zero_refcount) { - DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (refcount queued)")); - } else { - DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (mark-and-sweep queued)")); - } -#endif - queue_back = 0; - } else -#endif - { -#if defined(DUK_USE_REFERENCE_COUNTING) - queue_back = 1; - if (had_zero_refcount) { - /* When finalization is triggered - * by refzero and we queue the object - * back, clear FINALIZED right away - * so that the object can be refinalized - * immediately if necessary. - */ - DUK_HEAPHDR_CLEAR_FINALIZED(curr); - } -#endif - } - } else { - /* Used during heap destruction: don't actually run finalizers - * because we're heading into forced finalization. Instead, - * queue finalizable objects back to the heap_allocated list. - */ - DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing")); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); -#if defined(DUK_USE_REFERENCE_COUNTING) - queue_back = 1; -#endif - } - - /* Dequeue object from finalize_list. Note that 'curr' may no - * longer be finalize_list head because new objects may have - * been queued to the list. As a result we can't optimize for - * the single-linked heap case and must scan the list for - * removal, typically the scan is very short however. - */ - DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap, curr); - - /* Queue back to heap_allocated or free immediately. */ -#if defined(DUK_USE_REFERENCE_COUNTING) - if (queue_back) { - /* FINALIZED is only cleared if object originally - * queued for finalization by refcounting. For - * mark-and-sweep FINALIZED is left set, so that - * next mark-and-sweep round can make a rescue/free - * decision. - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); - DUK_HEAPHDR_PREDEC_REFCOUNT(curr); /* Remove artificial refcount bump. */ - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); - } else { - /* No need to remove the refcount bump here. */ - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */ - DUK_DD(DUK_DDPRINT("refcount finalize after finalizer call: %!O", curr)); - duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr); - duk_free_hobject(heap, (duk_hobject *) curr); - DUK_DD(DUK_DDPRINT("freed hobject after finalization: %p", (void *) curr)); - } -#else /* DUK_USE_REFERENCE_COUNTING */ - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); -#endif /* DUK_USE_REFERENCE_COUNTING */ - -#if defined(DUK_USE_DEBUG) - count++; -#endif - -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(heap->currently_finalizing != NULL); - heap->currently_finalizing = NULL; -#endif - } - - /* finalize_list will always be processed completely. */ - DUK_ASSERT(heap->finalize_list == NULL); - -#if 0 - /* While NORZ macros are used above, this is unnecessary because the - * only pending side effects are now finalizers, and finalize_list is - * empty. - */ - DUK_REFZERO_CHECK_SLOW(heap->heap_thread); -#endif - - /* Prevent count may be bumped while finalizers run, but should always - * be reliably unbumped by the time we get here. - */ - DUK_ASSERT(heap->pf_prevent_count == 1); - heap->pf_prevent_count = 0; - -#if defined(DUK_USE_DEBUG) - DUK_DD(DUK_DDPRINT("duk_heap_process_finalize_list: %ld finalizers called", (long) count)); -#endif -} - -/* - * Run an duk_hobject finalizer. Must never throw an uncaught error - * (but may throw caught errors). - * - * There is no return value. Any return value or error thrown by - * the finalizer is ignored (although errors are debug logged). - * - * Notes: - * - * - The finalizer thread 'top' assertions are there because it is - * critical that strict stack policy is observed (i.e. no cruft - * left on the finalizer stack). - */ - -DUK_LOCAL duk_ret_t duk__finalize_helper(duk_hthread *thr, void *udata) { - DUK_ASSERT(thr != NULL); - DUK_UNREF(udata); - - DUK_DDD(DUK_DDDPRINT("protected finalization helper running")); - - /* [... obj] */ - - /* _Finalizer property is read without checking if the value is - * callable or even exists. This is intentional, and handled - * by throwing an error which is caught by the safe call wrapper. - * - * XXX: Finalizer lookup should traverse the prototype chain (to allow - * inherited finalizers) but should not invoke accessors or proxy object - * behavior. At the moment this lookup will invoke proxy behavior, so - * caller must ensure that this function is not called if the target is - * a Proxy. - */ - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ - duk_dup_m2(thr); - duk_push_boolean(thr, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); - DUK_DDD(DUK_DDDPRINT("calling finalizer")); - duk_call(thr, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */ - DUK_DDD(DUK_DDDPRINT("finalizer returned successfully")); - return 0; - - /* Note: we rely on duk_safe_call() to fix up the stack for the caller, - * so we don't need to pop stuff here. There is no return value; - * caller determines rescued status based on object refcount. - */ -} - -DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) { - duk_hthread *thr; - duk_ret_t rc; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top; -#endif - - DUK_DD(DUK_DDPRINT("running duk_hobject finalizer for object: %p", (void *) obj)); - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); - thr = heap->heap_thread; - DUK_ASSERT(obj != NULL); - DUK_ASSERT_VALSTACK_SPACE(heap->heap_thread, 1); - -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(thr); -#endif - /* - * Get and call the finalizer. All of this must be wrapped - * in a protected call, because even getting the finalizer - * may trigger an error (getter may throw one, for instance). - */ - - /* ROM objects could inherit a finalizer, but they are never deemed - * unreachable by mark-and-sweep, and their refcount never falls to 0. - */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); - - /* Duktape 2.1: finalize_list never contains objects with FINALIZED - * set, so no need to check here. - */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)); -#if 0 - if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) { - DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj)); - return; - } -#endif - DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */ - -#if defined(DUK_USE_ES6_PROXY) - if (DUK_HOBJECT_IS_PROXY(obj)) { - /* This may happen if duk_set_finalizer() or Duktape.fin() is - * called for a Proxy object. In such cases the fast finalizer - * flag will be set on the Proxy, not the target, and neither - * will be finalized. - */ - DUK_D(DUK_DPRINT("object is a Proxy, skip finalizer call")); - return; - } -#endif /* DUK_USE_ES6_PROXY */ - - duk_push_hobject(thr, obj); /* this also increases refcount by one */ - rc = duk_safe_call(thr, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ - DUK_ASSERT_TOP(thr, entry_top + 2); /* duk_safe_call discipline */ - - if (rc != DUK_EXEC_SUCCESS) { - /* Note: we ask for one return value from duk_safe_call to get this - * error debugging here. - */ - DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T", - (void *) obj, (duk_tval *) duk_get_tval(thr, -1))); - } - duk_pop_2(thr); /* -> [...] */ - - DUK_ASSERT_TOP(thr, entry_top); -} - -#else /* DUK_USE_FINALIZER_SUPPORT */ - -/* nothing */ - -#endif /* DUK_USE_FINALIZER_SUPPORT */ -#line 1 "duk_heap_hashstring.c" -/* - * String hash computation (interning). - * - * String hashing is performance critical because a string hash is computed - * for all new strings which are candidates to be added to the string table. - * However, strings actually added to the string table go through a codepoint - * length calculation which dominates performance because it goes through - * every byte of the input string (but only for strings added). - * - * The string hash algorithm should be fast, but on the other hand provide - * good enough hashes to ensure both string table and object property table - * hash tables work reasonably well (i.e., there aren't too many collisions - * with real world inputs). Unless the hash is cryptographic, it's always - * possible to craft inputs with maximal hash collisions. - * - * NOTE: The hash algorithms must match tools/dukutil.py:duk_heap_hashstring() - * for ROM string support! - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_STRHASH_DENSE) -/* Constants for duk_hashstring(). */ -#define DUK__STRHASH_SHORTSTRING 4096L -#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L) -#define DUK__STRHASH_BLOCKSIZE 256L - -DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) { - duk_uint32_t hash; - - /* Use Murmurhash2 directly for short strings, and use "block skipping" - * for long strings: hash an initial part and then sample the rest of - * the string with reasonably sized chunks. An initial offset for the - * sampling is computed based on a hash of the initial part of the string; - * this is done to (usually) avoid the case where all long strings have - * certain offset ranges which are never sampled. - * - * Skip should depend on length and bound the total time to roughly - * logarithmic. With current values: - * - * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing - * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing - * - * XXX: It would be better to compute the skip offset more "smoothly" - * instead of having a few boundary values. - */ - - /* note: mixing len into seed improves hashing when skipping */ - duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len); - - if (len <= DUK__STRHASH_SHORTSTRING) { - hash = duk_util_hashbytes(str, len, str_seed); - } else { - duk_size_t off; - duk_size_t skip; - - if (len <= DUK__STRHASH_MEDIUMSTRING) { - skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE); - } else { - skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE); - } - - hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed); - off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256; - - /* XXX: inefficient loop */ - while (off < len) { - duk_size_t left = len - off; - duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left); - hash ^= duk_util_hashbytes(str + off, now, str_seed); - off += skip; - } - } - -#if defined(DUK_USE_STRHASH16) - /* Truncate to 16 bits here, so that a computed hash can be compared - * against a hash stored in a 16-bit field. - */ - hash &= 0x0000ffffUL; -#endif - return hash; -} -#else /* DUK_USE_STRHASH_DENSE */ -DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) { - duk_uint32_t hash; - duk_size_t step; - duk_size_t off; - - /* Slightly modified "Bernstein hash" from: - * - * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx - * - * Modifications: string skipping and reverse direction similar to - * Lua 5.1.5, and different hash initializer. - * - * The reverse direction ensures last byte it always included in the - * hash which is a good default as changing parts of the string are - * more often in the suffix than in the prefix. - */ - - hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */ - step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1; - for (off = len; off >= step; off -= step) { - DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */ - hash = (hash * 33) + str[off - 1]; - } - -#if defined(DUK_USE_STRHASH16) - /* Truncate to 16 bits here, so that a computed hash can be compared - * against a hash stored in a 16-bit field. - */ - hash &= 0x0000ffffUL; -#endif - return hash; -} -#endif /* DUK_USE_STRHASH_DENSE */ - -/* automatic undefs */ -#undef DUK__STRHASH_BLOCKSIZE -#undef DUK__STRHASH_MEDIUMSTRING -#undef DUK__STRHASH_SHORTSTRING -#line 1 "duk_heap_markandsweep.c" -/* - * Mark-and-sweep garbage collection. - */ - -/* #include duk_internal.h -> already included */ - -DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h); -DUK_LOCAL_DECL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h); -DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv); -DUK_LOCAL_DECL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count); - -/* - * Marking functions for heap types: mark children recursively. - */ - -DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) { - DUK_UNREF(heap); - DUK_UNREF(h); - - DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h)); - DUK_ASSERT(h); - - /* nothing to process */ -} - -DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) { - duk_uint_fast32_t i; - - DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h)); - - DUK_ASSERT(h); - - /* XXX: use advancing pointers instead of index macros -> faster and smaller? */ - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { - duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i); - if (key == NULL) { - continue; - } - duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) key); - if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) { - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get); - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set); - } else { - duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v); - } - } - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { - duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); - } - - /* Hash part is a 'weak reference' and does not contribute. */ - - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); - - /* Fast path for objects which don't have a subclass struct, or have a - * subclass struct but nothing that needs marking in the subclass struct. - */ - if (DUK_HOBJECT_HAS_FASTREFS(h)) { - DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h)); - return; - } - DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h)); - - /* XXX: reorg, more common first */ - if (DUK_HOBJECT_IS_COMPFUNC(h)) { - duk_hcompfunc *f = (duk_hcompfunc *) h; - duk_tval *tv, *tv_end; - duk_hobject **fn, **fn_end; - - DUK_ASSERT_HCOMPFUNC_VALID(f); - - /* 'data' is reachable through every compiled function which - * contains a reference. - */ - - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_DATA(heap, f)); - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f)); - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f)); - - if (DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL) { - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f); - tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f); - while (tv < tv_end) { - duk__mark_tval(heap, tv); - tv++; - } - - fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f); - fn_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f); - while (fn < fn_end) { - duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) *fn); - fn++; - } - } else { - /* May happen in some out-of-memory corner cases. */ - DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking")); - } - } else if (DUK_HOBJECT_IS_DECENV(h)) { - duk_hdecenv *e = (duk_hdecenv *) h; - DUK_ASSERT_HDECENV_VALID(e); - duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread); - duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap); - } else if (DUK_HOBJECT_IS_OBJENV(h)) { - duk_hobjenv *e = (duk_hobjenv *) h; - DUK_ASSERT_HOBJENV_VALID(e); - duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) e->target); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { - duk_hbufobj *b = (duk_hbufobj *) h; - DUK_ASSERT_HBUFOBJ_VALID(b); - duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf); - duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop); -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { - duk_hboundfunc *f = (duk_hboundfunc *) h; - DUK_ASSERT_HBOUNDFUNC_VALID(f); - duk__mark_tval(heap, &f->target); - duk__mark_tval(heap, &f->this_binding); - duk__mark_tvals(heap, f->args, f->nargs); -#if defined(DUK_USE_ES6_PROXY) - } else if (DUK_HOBJECT_IS_PROXY(h)) { - duk_hproxy *p = (duk_hproxy *) h; - DUK_ASSERT_HPROXY_VALID(p); - duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->target); - duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->handler); -#endif /* DUK_USE_ES6_PROXY */ - } else if (DUK_HOBJECT_IS_THREAD(h)) { - duk_hthread *t = (duk_hthread *) h; - duk_activation *act; - duk_tval *tv; - - DUK_ASSERT_HTHREAD_VALID(t); - - tv = t->valstack; - while (tv < t->valstack_top) { - duk__mark_tval(heap, tv); - tv++; - } - - for (act = t->callstack_curr; act != NULL; act = act->parent) { - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act)); - duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env); - duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env); -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller); -#endif -#if 0 /* nothing now */ - for (cat = act->cat; cat != NULL; cat = cat->parent) { - } -#endif - } - - duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer); - - for (i = 0; i < DUK_NUM_BUILTINS; i++) { - duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]); - } - } else { - /* We may come here if the object should have a FASTREFS flag - * but it's missing for some reason. Assert for never getting - * here; however, other than performance, this is harmless. - */ - DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h)); - DUK_ASSERT(0); - } -} - -/* Mark any duk_heaphdr type. Recursion tracking happens only here. */ -DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) { - DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld", - (void *) h, - (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1))); - - /* XXX: add non-null variant? */ - if (h == NULL) { - return; - } - - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h) || DUK_HEAPHDR_HAS_REACHABLE(h)); - -#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) - if (!DUK_HEAPHDR_HAS_READONLY(h)) { - h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */ - } -#endif - if (DUK_HEAPHDR_HAS_REACHABLE(h)) { - DUK_DDD(DUK_DDDPRINT("already marked reachable, skip")); - return; - } -#if defined(DUK_USE_ROM_OBJECTS) - /* READONLY objects always have REACHABLE set, so the check above - * will prevent READONLY objects from being marked here. - */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h)); -#endif - - DUK_HEAPHDR_SET_REACHABLE(h); - - if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { - DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h)); - DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap); - DUK_HEAPHDR_SET_TEMPROOT(h); - return; - } - - heap->ms_recursion_depth++; - DUK_ASSERT(heap->ms_recursion_depth != 0); /* Wrap. */ - - switch (DUK_HEAPHDR_GET_TYPE(h)) { - case DUK_HTYPE_STRING: - duk__mark_hstring(heap, (duk_hstring *) h); - break; - case DUK_HTYPE_OBJECT: - duk__mark_hobject(heap, (duk_hobject *) h); - break; - case DUK_HTYPE_BUFFER: - /* nothing to mark */ - break; - default: - DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h))); - DUK_UNREACHABLE(); - } - - DUK_ASSERT(heap->ms_recursion_depth > 0); - heap->ms_recursion_depth--; -} - -DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) { - DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv)); - if (tv == NULL) { - return; - } - if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - duk_heaphdr *h; - h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - duk__mark_heaphdr_nonnull(heap, h); - } -} - -DUK_LOCAL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count) { - DUK_ASSERT(count == 0 || tv != NULL); - - while (count-- > 0) { - if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - duk_heaphdr *h; - h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - duk__mark_heaphdr_nonnull(heap, h); - } - tv++; - } -} - -/* Mark any duk_heaphdr type, caller guarantees a non-NULL pointer. */ -DUK_LOCAL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h) { - /* For now, just call the generic handler. Change when call sites - * are changed too. - */ - duk__mark_heaphdr(heap, h); -} - -/* - * Mark the heap. - */ - -DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) { - duk_small_uint_t i; - - DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap)); - - duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread); - duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object); - - for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { - duk_hstring *h = DUK_HEAP_GET_STRING(heap, i); - duk__mark_heaphdr(heap, (duk_heaphdr *) h); - } - - duk__mark_tval(heap, &heap->lj.value1); - duk__mark_tval(heap, &heap->lj.value2); - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - for (i = 0; i < heap->dbg_breakpoint_count; i++) { - duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename); - } -#endif -} - -/* - * Mark unreachable, finalizable objects. - * - * Such objects will be moved aside and their finalizers run later. They - * have to be treated as reachability roots for their properties etc to - * remain allocated. This marking is only done for unreachable values which - * would be swept later. - * - * Objects are first marked FINALIZABLE and only then marked as reachability - * roots; otherwise circular references might be handled inconsistently. - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) { - duk_heaphdr *hdr; - duk_size_t count_finalizable = 0; - - DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap)); - - DUK_ASSERT(heap->heap_thread != NULL); - - hdr = heap->heap_allocated; - while (hdr != NULL) { - /* A finalizer is looked up from the object and up its - * prototype chain (which allows inherited finalizers). - * The finalizer is checked for using a duk_hobject flag - * which is kept in sync with the presence and callability - * of a _Finalizer hidden symbol. - */ - - if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) && - DUK_HEAPHDR_IS_OBJECT(hdr) && - !DUK_HEAPHDR_HAS_FINALIZED(hdr) && - DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) { - /* heaphdr: - * - is not reachable - * - is an object - * - is not a finalized object waiting for rescue/keep decision - * - has a finalizer - */ - - DUK_DD(DUK_DDPRINT("unreachable heap object will be " - "finalized -> mark as finalizable " - "and treat as a reachability root: %p", - (void *) hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); - DUK_HEAPHDR_SET_FINALIZABLE(hdr); - count_finalizable++; - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - - if (count_finalizable == 0) { - return; - } - - DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable", - (long) count_finalizable)); - - hdr = heap->heap_allocated; - while (hdr != NULL) { - if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) { - duk__mark_heaphdr_nonnull(heap, hdr); - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - - /* Caller will finish the marking process if we hit a recursion limit. */ -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* - * Mark objects on finalize_list. - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) { - duk_heaphdr *hdr; -#if defined(DUK_USE_DEBUG) - duk_size_t count_finalize_list = 0; -#endif - - DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap)); - - hdr = heap->finalize_list; - while (hdr != NULL) { - duk__mark_heaphdr_nonnull(heap, hdr); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); -#if defined(DUK_USE_DEBUG) - count_finalize_list++; -#endif - } - -#if defined(DUK_USE_DEBUG) - if (count_finalize_list > 0) { - DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)", - (long) count_finalize_list)); - } -#endif -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* - * Fallback marking handler if recursion limit is reached. - * - * Iterates 'temproots' until recursion limit is no longer hit. Temproots - * can be in heap_allocated or finalize_list; refzero_list is now always - * empty for mark-and-sweep. A temproot may occur in finalize_list now if - * there are objects on the finalize_list and user code creates a reference - * from an object in heap_allocated to the object in finalize_list (which is - * now allowed), and it happened to coincide with the recursion depth limit. - * - * This is a slow scan, but guarantees that we finish with a bounded C stack. - * - * Note that nodes may have been marked as temproots before this scan begun, - * OR they may have been marked during the scan (as we process nodes - * recursively also during the scan). This is intended behavior. - */ - -#if defined(DUK_USE_DEBUG) -DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) { -#else -DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) { -#endif - DUK_ASSERT(hdr != NULL); - - if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) { - DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr)); - return; - } - - DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr)); - DUK_HEAPHDR_CLEAR_TEMPROOT(hdr); - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* Done so that duk__mark_heaphdr() works correctly. */ -#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) - hdr->h_assert_refcount--; /* Same node visited twice. */ -#endif - duk__mark_heaphdr_nonnull(heap, hdr); - -#if defined(DUK_USE_DEBUG) - (*count)++; -#endif -} - -DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) { - duk_heaphdr *hdr; -#if defined(DUK_USE_DEBUG) - duk_size_t count; -#endif - - DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap)); - - while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) { - DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots")); - -#if defined(DUK_USE_DEBUG) - count = 0; -#endif - DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap); - - hdr = heap->heap_allocated; - while (hdr) { -#if defined(DUK_USE_DEBUG) - duk__handle_temproot(heap, hdr, &count); -#else - duk__handle_temproot(heap, hdr); -#endif - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - -#if defined(DUK_USE_FINALIZER_SUPPORT) - hdr = heap->finalize_list; - while (hdr) { -#if defined(DUK_USE_DEBUG) - duk__handle_temproot(heap, hdr, &count); -#else - duk__handle_temproot(heap, hdr); -#endif - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -#endif - -#if defined(DUK_USE_DEBUG) - DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count)); -#endif - } -} - -/* - * Finalize refcounts for heap elements just about to be freed. - * This must be done for all objects before freeing to avoid any - * stale pointer dereferences. - * - * Note that this must deduce the set of objects to be freed - * identically to duk__sweep_heap(). - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_ASSERT(heap->heap_thread != NULL); - - DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p", (void *) heap)); - - hdr = heap->heap_allocated; - while (hdr) { - if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) { - /* - * Unreachable object about to be swept. Finalize target refcounts - * (objects which the unreachable object points to) without doing - * refzero processing. Recursive decrefs are also prevented when - * refzero processing is disabled. - * - * Value cannot be a finalizable object, as they have been made - * temporarily reachable for this round. - */ - - DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr)); - - /* Finalize using heap->heap_thread; DECREF has a - * suppress check for mark-and-sweep which is based - * on heap->ms_running. - */ - duk_heaphdr_refcount_finalize_norz(heap, hdr); - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* - * Clear (reachable) flags of finalize_list. - * - * We could mostly do in the sweep phase when we move objects from the - * heap into the finalize_list. However, if a finalizer run is skipped - * during a mark-and-sweep, the objects on the finalize_list will be marked - * reachable during the next mark-and-sweep. Since they're already on the - * finalize_list, no-one will be clearing their REACHABLE flag so we do it - * here. (This now overlaps with the sweep handling in a harmless way.) - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap)); - - hdr = heap->finalize_list; - while (hdr) { - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \ - (heap->currently_finalizing == hdr)); -#endif - /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* - * Sweep stringtable. - */ - -DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) { - duk_hstring *h; - duk_hstring *prev; - duk_uint32_t i; -#if defined(DUK_USE_DEBUG) - duk_size_t count_free = 0; -#endif - duk_size_t count_keep = 0; - - DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - -#if defined(DUK_USE_STRTAB_PTRCOMP) - if (heap->strtable16 == NULL) { -#else - if (heap->strtable == NULL) { -#endif - goto done; - } - - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_STRTAB_PTRCOMP) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; -#endif - prev = NULL; - while (h != NULL) { - duk_hstring *next; - next = h->hdr.h_next; - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - count_keep++; - prev = h; - } else { -#if defined(DUK_USE_DEBUG) - count_free++; -#endif - -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - - /* Deal with weak references first. */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - - /* Remove the string from the string table. */ - duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev); - - /* Free inner references (these exist e.g. when external - * strings are enabled) and the struct itself. - */ - duk_free_hstring(heap, (duk_hstring *) h); - - /* Don't update 'prev'; it should be last string kept. */ - } - - h = next; - } - } - - done: -#if defined(DUK_USE_DEBUG) - DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", - (long) count_free, (long) count_keep)); -#endif - *out_count_keep = count_keep; -} - -/* - * Sweep heap. - */ - -DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_small_uint_t flags, duk_size_t *out_count_keep) { - duk_heaphdr *prev; /* last element that was left in the heap */ - duk_heaphdr *curr; - duk_heaphdr *next; -#if defined(DUK_USE_DEBUG) - duk_size_t count_free = 0; - duk_size_t count_finalize = 0; - duk_size_t count_rescue = 0; -#endif - duk_size_t count_keep = 0; - - DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap)); - - prev = NULL; - curr = heap->heap_allocated; - heap->heap_allocated = NULL; - while (curr) { - /* Strings and ROM objects are never placed on the heap allocated list. */ - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); - - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - - if (DUK_HEAPHDR_HAS_REACHABLE(curr)) { - /* - * Reachable object: - * - If FINALIZABLE -> actually unreachable (but marked - * artificially reachable), queue to finalize_list. - * - If !FINALIZABLE but FINALIZED -> rescued after - * finalizer execution. - * - Otherwise just a normal, reachable object. - * - * Objects which are kept are queued to heap_allocated - * tail (we're essentially filtering heap_allocated in - * practice). - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) - if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p", (void *) curr)); - -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HEAPHDR_PREINC_REFCOUNT(curr); /* Bump refcount so that refzero never occurs when pending a finalizer call. */ -#endif - DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr); -#if defined(DUK_USE_DEBUG) - count_finalize++; -#endif - } - else -#endif /* DUK_USE_FINALIZER_SUPPORT */ - { - if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - - if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) { - DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO", curr)); - count_keep++; - } else { - DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p", (void *) curr)); -#if defined(DUK_USE_FINALIZER_SUPPORT) - DUK_HEAPHDR_CLEAR_FINALIZED(curr); -#endif -#if defined(DUK_USE_DEBUG) - count_rescue++; -#endif - } - } else { - DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO", curr)); - count_keep++; - } - - if (prev != NULL) { - DUK_ASSERT(heap->heap_allocated != NULL); - DUK_HEAPHDR_SET_NEXT(heap, prev, curr); - } else { - DUK_ASSERT(heap->heap_allocated == NULL); - heap->heap_allocated = curr; - } -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - DUK_HEAPHDR_SET_PREV(heap, curr, prev); -#endif - DUK_ASSERT_HEAPHDR_LINKS(heap, prev); - DUK_ASSERT_HEAPHDR_LINKS(heap, curr); - prev = curr; - } - - /* - * Shrink check for value stacks here. We're inside - * ms_prevent_count protection which prevents recursive - * mark-and-sweep and refzero finalizers, so there are - * no side effects that would affect the heap lists. - */ - if (DUK_HEAPHDR_IS_OBJECT(curr) && DUK_HOBJECT_IS_THREAD((duk_hobject *) curr)) { - duk_hthread *thr_curr = (duk_hthread *) curr; - DUK_DD(DUK_DDPRINT("value stack shrink check for thread: %!O", curr)); - duk_valstack_shrink_check_nothrow(thr_curr, flags & DUK_MS_FLAG_EMERGENCY /*snug*/); - } - - DUK_HEAPHDR_CLEAR_REACHABLE(curr); - /* Keep FINALIZED if set, used if rescue decisions are postponed. */ - /* Keep FINALIZABLE for objects on finalize_list. */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); - } else { - /* - * Unreachable object: - * - If FINALIZED, object was finalized but not - * rescued. This doesn't affect freeing. - * - Otherwise normal unreachable object. - * - * There's no guard preventing a FINALIZED object - * from being freed while finalizers execute: the - * artificial finalize_list reachability roots can't - * cause an incorrect free decision (but can cause - * an incorrect rescue decision). - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Non-zero refcounts should not happen because we refcount - * finalize all unreachable objects which should cancel out - * refcounts (even for cycles). - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0); -#endif - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - -#if defined(DUK_USE_DEBUG) - if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p", (void *) curr)); - } else { - DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p", (void *) curr)); - } - -#endif - - /* Note: object cannot be a finalizable unreachable object, as - * they have been marked temporarily reachable for this round, - * and are handled above. - */ - -#if defined(DUK_USE_DEBUG) - count_free++; -#endif - - /* Weak refs should be handled here, but no weak refs for - * any non-string objects exist right now. - */ - - /* Free object and all auxiliary (non-heap) allocs. */ - duk_heap_free_heaphdr_raw(heap, curr); - } - - curr = next; - } - - if (prev != NULL) { - DUK_HEAPHDR_SET_NEXT(heap, prev, NULL); - } - DUK_ASSERT_HEAPHDR_LINKS(heap, prev); - -#if defined(DUK_USE_DEBUG) - DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization", - (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize)); -#endif - *out_count_keep = count_keep; -} - -/* - * Object compaction. - * - * Compaction is assumed to never throw an error. - */ - -DUK_LOCAL int duk__protected_compact_object(duk_hthread *thr, void *udata) { - duk_hobject *obj; - /* XXX: for threads, compact stacks? */ - - DUK_UNREF(udata); - obj = duk_known_hobject(thr, -1); - duk_hobject_compact_props(thr, obj); - return 0; -} - -#if defined(DUK_USE_DEBUG) -DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start, duk_size_t *p_count_check, duk_size_t *p_count_compact, duk_size_t *p_count_bytes_saved) { -#else -DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) { -#endif - duk_heaphdr *curr; -#if defined(DUK_USE_DEBUG) - duk_size_t old_size, new_size; -#endif - duk_hobject *obj; - - DUK_UNREF(heap); - - curr = start; - while (curr) { - DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr)); - - if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) { - goto next; - } - obj = (duk_hobject *) curr; - -#if defined(DUK_USE_DEBUG) - old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), - DUK_HOBJECT_GET_ASIZE(obj), - DUK_HOBJECT_GET_HSIZE(obj)); -#endif - - DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj)); - duk_push_hobject(thr, obj); - /* XXX: disable error handlers for duration of compaction? */ - duk_safe_call(thr, duk__protected_compact_object, NULL, 1, 0); - -#if defined(DUK_USE_DEBUG) - new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), - DUK_HOBJECT_GET_ASIZE(obj), - DUK_HOBJECT_GET_HSIZE(obj)); -#endif - -#if defined(DUK_USE_DEBUG) - (*p_count_compact)++; - (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size); -#endif - - next: - curr = DUK_HEAPHDR_GET_NEXT(heap, curr); -#if defined(DUK_USE_DEBUG) - (*p_count_check)++; -#endif - } -} - -DUK_LOCAL void duk__compact_objects(duk_heap *heap) { - /* XXX: which lists should participate? to be finalized? */ -#if defined(DUK_USE_DEBUG) - duk_size_t count_check = 0; - duk_size_t count_compact = 0; - duk_size_t count_bytes_saved = 0; -#endif - - DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap)); - - DUK_ASSERT(heap->heap_thread != NULL); - -#if defined(DUK_USE_DEBUG) - duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); -#if defined(DUK_USE_FINALIZER_SUPPORT) - duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); -#endif -#else - duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated); -#if defined(DUK_USE_FINALIZER_SUPPORT) - duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list); -#endif -#endif -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ -#endif - -#if defined(DUK_USE_DEBUG) - DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction", - (long) count_check, (long) count_compact, (long) count_bytes_saved)); -#endif -} - -/* - * Assertion helpers. - */ - -#if defined(DUK_USE_ASSERTIONS) -DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - hdr = heap->heap_allocated; - while (hdr) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - /* may have FINALIZED */ - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ -#endif -} - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) { - duk_heaphdr *hdr = heap->heap_allocated; - while (hdr) { - /* Cannot really assert much w.r.t. refcounts now. */ - - if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 && - DUK_HEAPHDR_HAS_FINALIZED(hdr)) { - /* An object may be in heap_allocated list with a zero - * refcount if it has just been finalized and is waiting - * to be collected by the next cycle. - * (This doesn't currently happen however.) - */ - } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) { - /* An object may be in heap_allocated list with a zero - * refcount also if it is a temporary object created - * during debugger paused state. It will get collected - * by mark-and-sweep based on its reachability status - * (presumably not reachable because refcount is 0). - */ - } - DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(hdr) >= 0); /* Unsigned. */ - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} - -DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) { - duk_heaphdr *curr; - duk_uint32_t i; - - for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { - curr->h_assert_refcount = 0; - } -#if defined(DUK_USE_FINALIZER_SUPPORT) - for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { - curr->h_assert_refcount = 0; - } -#endif -#if defined(DUK_USE_REFERENCE_COUNTING) - for (curr = heap->refzero_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { - curr->h_assert_refcount = 0; - } -#endif - - for (i = 0; i < heap->st_size; i++) { - duk_hstring *h; - -#if defined(DUK_USE_STRTAB_PTRCOMP) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; -#endif - while (h != NULL) { - ((duk_heaphdr *) h)->h_assert_refcount = 0; - h = h->hdr.h_next; - } - } -} - -DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) { - duk_bool_t count_ok; - - /* The refcount check only makes sense for reachable objects on - * heap_allocated or string table, after the sweep phase. Prior to - * sweep phase refcounts will include references that are not visible - * via reachability roots. - * - * Because we're called after the sweep phase, all heap objects on - * heap_allocated are reachable. REACHABLE flags have already been - * cleared so we can't check them. - */ - - /* ROM objects have intentionally incorrect refcount (1), but we won't - * check them. - */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); - - count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == hdr->h_assert_refcount); - if (!count_ok) { - DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO", - (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr), - (long) hdr->h_assert_refcount, hdr)); - DUK_ASSERT(0); - } -} - -DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) { - duk_heaphdr *curr; - duk_uint32_t i; - - for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { - duk__check_refcount_heaphdr(curr); - } -#if defined(DUK_USE_FINALIZER_SUPPORT) - for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { - duk__check_refcount_heaphdr(curr); - } -#endif - - for (i = 0; i < heap->st_size; i++) { - duk_hstring *h; - -#if defined(DUK_USE_STRTAB_PTRCOMP) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; -#endif - while (h != NULL) { - duk__check_refcount_heaphdr((duk_heaphdr *) h); - h = h->hdr.h_next; - } - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ - -/* - * Stats dump. - */ - -#if defined(DUK_USE_DEBUG) -DUK_LOCAL void duk__dump_stats(duk_heap *heap) { - DUK_D(DUK_DPRINT("stats executor: opcodes=%ld, interrupt=%ld, throw=%ld", - (long) heap->stats_exec_opcodes, (long) heap->stats_exec_interrupt, - (long) heap->stats_exec_throw)); - DUK_D(DUK_DPRINT("stats call: all=%ld, tailcall=%ld, ecmatoecma=%ld", - (long) heap->stats_call_all, (long) heap->stats_call_tailcall, - (long) heap->stats_call_ecmatoecma)); - DUK_D(DUK_DPRINT("stats safecall: all=%ld, nothrow=%ld, throw=%ld", - (long) heap->stats_safecall_all, (long) heap->stats_safecall_nothrow, - (long) heap->stats_safecall_throw)); - DUK_D(DUK_DPRINT("stats mark-and-sweep: try_count=%ld, skip_count=%ld, emergency_count=%ld", - (long) heap->stats_ms_try_count, (long) heap->stats_ms_skip_count, - (long) heap->stats_ms_emergency_count)); - DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, resize_check=%ld, resize_grow=%ld, resize_shrink=%ld", - (long) heap->stats_strtab_intern_hit, (long) heap->stats_strtab_intern_miss, - (long) heap->stats_strtab_resize_check, (long) heap->stats_strtab_resize_grow, - (long) heap->stats_strtab_resize_shrink)); - DUK_D(DUK_DPRINT("stats object: realloc_props=%ld, abandon_array=%ld", - (long) heap->stats_object_realloc_props, (long) heap->stats_object_abandon_array)); - DUK_D(DUK_DPRINT("stats getownpropdesc: count=%ld, hit=%ld, miss=%ld", - (long) heap->stats_getownpropdesc_count, (long) heap->stats_getownpropdesc_hit, - (long) heap->stats_getownpropdesc_miss)); - DUK_D(DUK_DPRINT("stats getpropdesc: count=%ld, hit=%ld, miss=%ld", - (long) heap->stats_getpropdesc_count, (long) heap->stats_getpropdesc_hit, - (long) heap->stats_getpropdesc_miss)); - DUK_D(DUK_DPRINT("stats getprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, " - "bufferidx=%ld, bufferlen=%ld, stringidx=%ld, stringlen=%ld, " - "proxy=%ld, arguments=%ld", - (long) heap->stats_getprop_all, (long) heap->stats_getprop_arrayidx, - (long) heap->stats_getprop_bufobjidx, (long) heap->stats_getprop_bufferidx, - (long) heap->stats_getprop_bufferlen, (long) heap->stats_getprop_stringidx, - (long) heap->stats_getprop_stringlen, (long) heap->stats_getprop_proxy, - (long) heap->stats_getprop_arguments)); - DUK_D(DUK_DPRINT("stats putprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, " - "bufferidx=%ld, proxy=%ld", - (long) heap->stats_putprop_all, (long) heap->stats_putprop_arrayidx, - (long) heap->stats_putprop_bufobjidx, (long) heap->stats_putprop_bufferidx, - (long) heap->stats_putprop_proxy)); - DUK_D(DUK_DPRINT("stats getvar: all=%ld", - (long) heap->stats_getvar_all)); - DUK_D(DUK_DPRINT("stats putvar: all=%ld", - (long) heap->stats_putvar_all)); -} -#endif /* DUK_USE_DEBUG */ - -/* - * Main mark-and-sweep function. - * - * 'flags' represents the features requested by the caller. The current - * heap->ms_base_flags is ORed automatically into the flags; the base flags - * mask typically prevents certain mark-and-sweep operation to avoid trouble. - */ - -DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { - duk_size_t count_keep_obj; - duk_size_t count_keep_str; -#if defined(DUK_USE_VOLUNTARY_GC) - duk_size_t tmp; -#endif - - DUK_STATS_INC(heap, stats_ms_try_count); -#if defined(DUK_USE_DEBUG) - if (flags & DUK_MS_FLAG_EMERGENCY) { - DUK_STATS_INC(heap, stats_ms_emergency_count); - } -#endif - - /* If debugger is paused, garbage collection is disabled by default. - * This is achieved by bumping ms_prevent_count when becoming paused. - */ - DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0); - - /* Prevention/recursion check as soon as possible because we may - * be called a number of times when voluntary mark-and-sweep is - * pending. - */ - if (heap->ms_prevent_count != 0) { - DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep")); - DUK_STATS_INC(heap, stats_ms_skip_count); - return; - } - DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */ - - /* Heap_thread is used during mark-and-sweep for refcount finalization - * (it's also used for finalizer execution once mark-and-sweep is - * complete). Heap allocation code ensures heap_thread is set and - * properly initialized before setting ms_prevent_count to 0. - */ - DUK_ASSERT(heap->heap_thread != NULL); - DUK_ASSERT(heap->heap_thread->valstack != NULL); - - DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx", - (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags))); - - flags |= heap->ms_base_flags; -#if defined(DUK_USE_FINALIZER_SUPPORT) - if (heap->finalize_list != NULL) { - flags |= DUK_MS_FLAG_POSTPONE_RESCUE; - } -#endif - - /* - * Assertions before - */ - -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(heap->ms_prevent_count == 0); - DUK_ASSERT(heap->ms_running == 0); - DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap)); - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->ms_recursion_depth == 0); - duk__assert_heaphdr_flags(heap); -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: heap->refzero_free_running may be true; a refcount - * finalizer may trigger a mark-and-sweep. - */ - duk__assert_valid_refcounts(heap); -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ - - /* - * Begin - */ - - DUK_ASSERT(heap->ms_prevent_count == 0); - DUK_ASSERT(heap->ms_running == 0); - heap->ms_prevent_count = 1; - heap->ms_running = 1; - - /* - * Free activation/catcher freelists on every mark-and-sweep for now. - * This is an initial rough draft; ideally we'd keep count of the - * freelist size and free only excess entries. - */ - - DUK_D(DUK_DPRINT("freeing temporary freelists")); - duk_heap_free_freelists(heap); - - /* - * Mark roots, hoping that recursion limit is not normally hit. - * If recursion limit is hit, run additional reachability rounds - * starting from "temproots" until marking is complete. - * - * Marking happens in two phases: first we mark actual reachability - * roots (and run "temproots" to complete the process). Then we - * check which objects are unreachable and are finalizable; such - * objects are marked as FINALIZABLE and marked as reachability - * (and "temproots" is run again to complete the process). - * - * The heap finalize_list must also be marked as a reachability root. - * There may be objects on the list from a previous round if the - * previous run had finalizer skip flag. - */ - -#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) - duk__clear_assert_refcounts(heap); -#endif - duk__mark_roots_heap(heap); /* Mark main reachability roots. */ -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ -#endif - duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) - duk__mark_finalizable(heap); /* Mark finalizable as reachability roots. */ - duk__mark_finalize_list(heap); /* Mark finalizer work list as reachability roots. */ -#endif - duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ - - /* - * Sweep garbage and remove marking flags, and move objects with - * finalizers to the finalizer work list. - * - * Objects to be swept need to get their refcounts finalized before - * they are swept. In other words, their target object refcounts - * need to be decreased. This has to be done before freeing any - * objects to avoid decref'ing dangling pointers (which may happen - * even without bugs, e.g. with reference loops) - * - * Because strings don't point to other heap objects, similar - * finalization is not necessary for strings. - */ - - /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__finalize_refcounts(heap); -#endif - duk__sweep_heap(heap, flags, &count_keep_obj); - duk__sweep_stringtable(heap, &count_keep_str); -#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) - duk__check_assert_refcounts(heap); -#endif -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ -#endif -#if defined(DUK_USE_FINALIZER_SUPPORT) - duk__clear_finalize_list_flags(heap); -#endif - - /* - * Object compaction (emergency only). - * - * Object compaction is a separate step after sweeping, as there is - * more free memory for it to work with. Also, currently compaction - * may insert new objects into the heap allocated list and the string - * table which we don't want to do during a sweep (the reachability - * flags of such objects would be incorrect). The objects inserted - * are currently: - * - * - a temporary duk_hbuffer for a new properties allocation - * - if array part is abandoned, string keys are interned - * - * The object insertions go to the front of the list, so they do not - * cause an infinite loop (they are not compacted). - */ - - if ((flags & DUK_MS_FLAG_EMERGENCY) && - !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) { - duk__compact_objects(heap); - } - - /* - * String table resize check. - * - * This is mainly useful in emergency GC: if the string table load - * factor is really low for some reason, we can shrink the string - * table to a smaller size and free some memory in the process. - * Only execute in emergency GC. String table has internal flags - * to protect against recursive resizing if this mark-and-sweep pass - * was triggered by a string table resize. - */ - - if (flags & DUK_MS_FLAG_EMERGENCY) { - DUK_D(DUK_DPRINT("stringtable resize check in emergency gc")); - duk_heap_strtable_force_resize(heap); - } - - /* - * Finish - */ - - DUK_ASSERT(heap->ms_prevent_count == 1); - heap->ms_prevent_count = 0; - DUK_ASSERT(heap->ms_running == 1); - heap->ms_running = 0; - - /* - * Assertions after - */ - -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(heap->ms_prevent_count == 0); - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->ms_recursion_depth == 0); - duk__assert_heaphdr_flags(heap); -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: heap->refzero_free_running may be true; a refcount - * finalizer may trigger a mark-and-sweep. - */ - duk__assert_valid_refcounts(heap); -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ - - /* - * Reset trigger counter - */ - -#if defined(DUK_USE_VOLUNTARY_GC) - tmp = (count_keep_obj + count_keep_str) / 256; - heap->ms_trigger_counter = (duk_int_t) ( - (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) + - DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD); - DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld", - (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter)); -#else - DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger", - (long) count_keep_obj, (long) count_keep_str)); -#endif - - /* - * Stats dump - */ - -#if defined(DUK_USE_DEBUG) - duk__dump_stats(heap); -#endif - - /* - * Finalize objects in the finalization work list. Finalized - * objects are queued back to heap_allocated with FINALIZED set. - * - * Since finalizers may cause arbitrary side effects, they are - * prevented e.g. during string table and object property allocation - * resizing using heap->pf_prevent_count. In this case the objects - * remain in the finalization work list after mark-and-sweep exits - * and they may be finalized on the next pass or any DECREF checking - * for finalize_list. - * - * As of Duktape 2.1 finalization happens outside mark-and-sweep - * protection. Mark-and-sweep is allowed while the finalize_list - * is being processed, but no rescue decisions are done while the - * process is on-going. This avoids incorrect rescue decisions - * if an object is considered reachable (and thus rescued) because - * of a reference via finalize_list (which is considered a reachability - * root). When finalize_list is being processed, reachable objects - * with FINALIZED set will just keep their FINALIZED flag for later - * mark-and-sweep processing. - * - * This could also be handled (a bit better) by having a more refined - * notion of reachability for rescue/free decisions. - * - * XXX: avoid finalizer execution when doing emergency GC? - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) - /* Attempt to process finalize_list, pf_prevent_count check - * is inside the target. - */ - duk_heap_process_finalize_list(heap); -#endif /* DUK_USE_FINALIZER_SUPPORT */ -} -#line 1 "duk_heap_memory.c" -/* - * Memory allocation handling. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Voluntary GC check - */ - -#if defined(DUK_USE_VOLUNTARY_GC) -DUK_LOCAL DUK_INLINE void duk__check_voluntary_gc(duk_heap *heap) { - if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) { -#if defined(DUK_USE_DEBUG) - if (heap->ms_prevent_count == 0) { - DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); - } else { - DUK_DD(DUK_DDPRINT("gc blocked -> skip voluntary mark-and-sweep now")); - } -#endif - - /* Prevention checks in the call target handle cases where - * voluntary GC is not allowed. The voluntary GC trigger - * counter is only rewritten if mark-and-sweep actually runs. - */ - duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_VOLUNTARY /*flags*/); - } -} -#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { duk__check_voluntary_gc((heap)); } while (0) -#else -#define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */ -#endif /* DUK_USE_VOLUNTARY_GC */ - -/* - * Allocate memory with garbage collection - */ - -DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) { - void *res; - duk_small_int_t i; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT_DISABLE(size >= 0); - - /* - * Voluntary periodic GC (if enabled) - */ - - DUK__VOLUNTARY_PERIODIC_GC(heap); - - /* - * First attempt - */ - -#if defined(DUK_USE_GC_TORTURE) - /* Simulate alloc failure on every alloc, except when mark-and-sweep - * is running. - */ - if (heap->ms_prevent_count == 0) { - DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails")); - res = NULL; - DUK_UNREF(res); - goto skip_attempt; - } -#endif - res = heap->alloc_func(heap->heap_udata, size); - if (DUK_LIKELY(res || size == 0)) { - /* For zero size allocations NULL is allowed. */ - return res; - } -#if defined(DUK_USE_GC_TORTURE) - skip_attempt: -#endif - - DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry")); - -#if 0 - /* - * Avoid a GC if GC is already running. This can happen at a late - * stage in a GC when we try to e.g. resize the stringtable - * or compact objects. - * - * NOTE: explicit handling isn't actually be needed: if the GC is - * not allowed, duk_heap_mark_and_sweep() will reject it for every - * attempt in the loop below, resulting in a NULL same as here. - */ - - if (heap->ms_prevent_count != 0) { - DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size)); - return NULL; - } -#endif - - /* - * Retry with several GC attempts. Initial attempts are made without - * emergency mode; later attempts use emergency mode which minimizes - * memory allocations forcibly. - */ - - for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { - duk_small_uint_t flags; - - flags = 0; - if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { - flags |= DUK_MS_FLAG_EMERGENCY; - } - - duk_heap_mark_and_sweep(heap, flags); - - res = heap->alloc_func(heap->heap_udata, size); - if (res) { - DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld", - (long) (i + 1), (long) size)); - return res; - } - } - - DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size)); - return NULL; -} - -DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) { - void *res; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT_DISABLE(size >= 0); - - res = DUK_ALLOC(heap, size); - if (DUK_LIKELY(res != NULL)) { - /* assume memset with zero size is OK */ - DUK_MEMZERO(res, size); - } - return res; -} - -DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) { - void *res; - - DUK_ASSERT(thr != NULL); - res = duk_heap_mem_alloc(thr->heap, size); - if (DUK_LIKELY(res != NULL || size == 0)) { - return res; - } - DUK_ERROR_ALLOC_FAILED(thr); - return NULL; -} - -DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) { - void *res; - - DUK_ASSERT(thr != NULL); - res = duk_heap_mem_alloc_zeroed(thr->heap, size); - if (DUK_LIKELY(res != NULL || size == 0)) { - return res; - } - DUK_ERROR_ALLOC_FAILED(thr); - return NULL; -} - -/* - * Reallocate memory with garbage collection - */ - -DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) { - void *res; - duk_small_int_t i; - - DUK_ASSERT(heap != NULL); - /* ptr may be NULL */ - DUK_ASSERT_DISABLE(newsize >= 0); - - /* - * Voluntary periodic GC (if enabled) - */ - - DUK__VOLUNTARY_PERIODIC_GC(heap); - - /* - * First attempt - */ - -#if defined(DUK_USE_GC_TORTURE) - /* Simulate alloc failure on every realloc, except when mark-and-sweep - * is running. - */ - if (heap->ms_prevent_count == 0) { - DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails")); - res = NULL; - DUK_UNREF(res); - goto skip_attempt; - } -#endif - res = heap->realloc_func(heap->heap_udata, ptr, newsize); - if (DUK_LIKELY(res || newsize == 0)) { - /* For zero size allocations NULL is allowed. */ - return res; - } -#if defined(DUK_USE_GC_TORTURE) - skip_attempt: -#endif - - DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry")); - -#if 0 - /* - * Avoid a GC if GC is already running. See duk_heap_mem_alloc(). - */ - - if (heap->ms_prevent_count != 0) { - DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize)); - return NULL; - } -#endif - - /* - * Retry with several GC attempts. Initial attempts are made without - * emergency mode; later attempts use emergency mode which minimizes - * memory allocations forcibly. - */ - - for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { - duk_small_uint_t flags; - - flags = 0; - if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { - flags |= DUK_MS_FLAG_EMERGENCY; - } - - duk_heap_mark_and_sweep(heap, flags); - - res = heap->realloc_func(heap->heap_udata, ptr, newsize); - if (res || newsize == 0) { - DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld", - (long) (i + 1), (long) newsize)); - return res; - } - } - - DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize)); - return NULL; -} - -/* - * Reallocate memory with garbage collection, using a callback to provide - * the current allocated pointer. This variant is used when a mark-and-sweep - * (e.g. finalizers) might change the original pointer. - */ - -DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { - void *res; - duk_small_int_t i; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT_DISABLE(newsize >= 0); - - /* - * Voluntary periodic GC (if enabled) - */ - - DUK__VOLUNTARY_PERIODIC_GC(heap); - - /* - * First attempt - */ - -#if defined(DUK_USE_GC_TORTURE) - /* Simulate alloc failure on every realloc, except when mark-and-sweep - * is running. - */ - if (heap->ms_prevent_count == 0) { - DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails")); - res = NULL; - DUK_UNREF(res); - goto skip_attempt; - } -#endif - res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); - if (DUK_LIKELY(res || newsize == 0)) { - /* For zero size allocations NULL is allowed. */ - return res; - } -#if defined(DUK_USE_GC_TORTURE) - skip_attempt: -#endif - - DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry")); - -#if 0 - /* - * Avoid a GC if GC is already running. See duk_heap_mem_alloc(). - */ - - if (heap->ms_prevent_count != 0) { - DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize)); - return NULL; - } -#endif - - /* - * Retry with several GC attempts. Initial attempts are made without - * emergency mode; later attempts use emergency mode which minimizes - * memory allocations forcibly. - */ - - for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { - duk_small_uint_t flags; - -#if defined(DUK_USE_DEBUG) - void *ptr_pre; - void *ptr_post; -#endif - -#if defined(DUK_USE_DEBUG) - ptr_pre = cb(heap, ud); -#endif - flags = 0; - if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { - flags |= DUK_MS_FLAG_EMERGENCY; - } - - duk_heap_mark_and_sweep(heap, flags); -#if defined(DUK_USE_DEBUG) - ptr_post = cb(heap, ud); - if (ptr_pre != ptr_post) { - DUK_DD(DUK_DDPRINT("realloc base pointer changed by mark-and-sweep: %p -> %p", - (void *) ptr_pre, (void *) ptr_post)); - } -#endif - - /* Note: key issue here is to re-lookup the base pointer on every attempt. - * The pointer being reallocated may change after every mark-and-sweep. - */ - - res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); - if (res || newsize == 0) { - DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld", - (long) (i + 1), (long) newsize)); - return res; - } - } - - DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize)); - return NULL; -} - -/* - * Free memory - */ - -DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) { - DUK_ASSERT(heap != NULL); - /* ptr may be NULL */ - - /* Must behave like a no-op with NULL and any pointer returned from - * malloc/realloc with zero size. - */ - heap->free_func(heap->heap_udata, ptr); - - /* Never perform a GC (even voluntary) in a memory free, otherwise - * all call sites doing frees would need to deal with the side effects. - * No need to update voluntary GC counter either. - */ -} - -/* automatic undefs */ -#undef DUK__VOLUNTARY_PERIODIC_GC -#line 1 "duk_heap_misc.c" -/* - * Support functions for duk_heap. - */ - -/* #include duk_internal.h -> already included */ - -DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { - duk_heaphdr *root; - - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); - - root = heap->heap_allocated; -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - if (root != NULL) { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL); - DUK_HEAPHDR_SET_PREV(heap, root, hdr); - } - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); -#endif - DUK_HEAPHDR_SET_NEXT(heap, hdr, root); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, root); - heap->heap_allocated = hdr; -} - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { - duk_heaphdr *prev; - duk_heaphdr *next; - - /* Strings are in string table. */ - DUK_ASSERT(hdr != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); - - /* Target 'hdr' must be in heap_allocated (not e.g. finalize_list). - * If not, heap lists will become corrupted so assert early for it. - */ -#if defined(DUK_USE_ASSERTIONS) - { - duk_heaphdr *tmp; - for (tmp = heap->heap_allocated; tmp != NULL; tmp = DUK_HEAPHDR_GET_NEXT(heap, tmp)) { - if (tmp == hdr) { - break; - } - } - DUK_ASSERT(tmp == hdr); - } -#endif - - /* Read/write only once to minimize pointer compression calls. */ - prev = DUK_HEAPHDR_GET_PREV(heap, hdr); - next = DUK_HEAPHDR_GET_NEXT(heap, hdr); - - if (prev != NULL) { - DUK_ASSERT(heap->heap_allocated != hdr); - DUK_HEAPHDR_SET_NEXT(heap, prev, next); - } else { - DUK_ASSERT(heap->heap_allocated == hdr); - heap->heap_allocated = next; - } - if (next != NULL) { - DUK_HEAPHDR_SET_PREV(heap, next, prev); - } else { - ; - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr) { - duk_heaphdr *root; - - root = heap->finalize_list; -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); - if (root != NULL) { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL); - DUK_HEAPHDR_SET_PREV(heap, root, hdr); - } -#endif - DUK_HEAPHDR_SET_NEXT(heap, hdr, root); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, root); - heap->finalize_list = hdr; -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr) { -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - duk_heaphdr *next; - duk_heaphdr *prev; - - next = DUK_HEAPHDR_GET_NEXT(heap, hdr); - prev = DUK_HEAPHDR_GET_PREV(heap, hdr); - if (next != NULL) { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, next) == hdr); - DUK_HEAPHDR_SET_PREV(heap, next, prev); - } - if (prev == NULL) { - DUK_ASSERT(hdr == heap->finalize_list); - heap->finalize_list = next; - } else { - DUK_ASSERT(hdr != heap->finalize_list); - DUK_HEAPHDR_SET_NEXT(heap, prev, next); - } -#else - duk_heaphdr *next; - duk_heaphdr *curr; - - /* Random removal is expensive: we need to locate the previous element - * because we don't have a 'prev' pointer. - */ - curr = heap->finalize_list; - if (curr == hdr) { - heap->finalize_list = DUK_HEAPHDR_GET_NEXT(heap, curr); - } else { - DUK_ASSERT(hdr != heap->finalize_list); - for (;;) { - DUK_ASSERT(curr != NULL); /* Caller responsibility. */ - - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - if (next == hdr) { - next = DUK_HEAPHDR_GET_NEXT(heap, hdr); - DUK_HEAPHDR_SET_NEXT(heap, curr, next); - break; - } - } - } -#endif -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -#if defined(DUK_USE_ASSERTIONS) -DUK_INTERNAL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr) { - duk_heaphdr *curr; - DUK_ASSERT(heap != NULL); - - for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { - if (curr == ptr) { - return 1; - } - } - return 0; -} -#endif /* DUK_USE_ASSERTIONS */ - -#if defined(DUK_USE_INTERRUPT_COUNTER) -DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) { - duk_hthread *curr_thr; - - DUK_ASSERT(heap != NULL); - - if (new_thr != NULL) { - curr_thr = heap->curr_thread; - if (curr_thr == NULL) { - /* For initial entry use default value; zero forces an - * interrupt before executing the first insturction. - */ - DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter")); - new_thr->interrupt_counter = 0; - new_thr->interrupt_init = 0; - } else { - /* Copy interrupt counter/init value state to new thread (if any). - * It's OK for new_thr to be the same as curr_thr. - */ -#if defined(DUK_USE_DEBUG) - if (new_thr != curr_thr) { - DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter")); - } -#endif - new_thr->interrupt_counter = curr_thr->interrupt_counter; - new_thr->interrupt_init = curr_thr->interrupt_init; - } - } else { - DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes")); - } - - heap->curr_thread = new_thr; /* may be NULL */ -} -#endif /* DUK_USE_INTERRUPT_COUNTER */ -#line 1 "duk_heap_refcount.c" -/* - * Reference counting implementation. - * - * INCREF/DECREF, finalization and freeing of objects whose refcount reaches - * zero (refzero). These operations are very performance sensitive, so - * various small tricks are used in an attempt to maximize speed. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - -#if !defined(DUK_USE_DOUBLE_LINKED_HEAP) -#error internal error, reference counting requires a double linked heap -#endif - -/* - * Heap object refcount finalization. - * - * When an object is about to be freed, all other objects it refers to must - * be decref'd. Refcount finalization does NOT free the object or its inner - * allocations (mark-and-sweep shares these helpers), it just manipulates - * the refcounts. - * - * Note that any of the DECREFs may cause a refcount to drop to zero. If so, - * the object won't be refzero processed inline, but will just be queued to - * refzero_list and processed by an earlier caller working on refzero_list, - * eliminating C recursion from even long refzero cascades. If refzero - * finalization is triggered by mark-and-sweep, refzero conditions are ignored - * (objects are not even queued to refzero_list) because mark-and-sweep deals - * with them; refcounts are still updated so that they remain in sync with - * actual references. - */ - -DUK_LOCAL void duk__decref_tvals_norz(duk_hthread *thr, duk_tval *tv, duk_idx_t count) { - DUK_ASSERT(count == 0 || tv != NULL); - - while (count-- > 0) { - DUK_TVAL_DECREF_NORZ(thr, tv); - tv++; - } -} - -DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h) { - duk_hthread *thr; - duk_uint_fast32_t i; - duk_uint_fast32_t n; - duk_propvalue *p_val; - duk_tval *p_tv; - duk_hstring **p_key; - duk_uint8_t *p_flag; - duk_hobject *h_proto; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); - DUK_ASSERT(h); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT); - - thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); - - p_key = DUK_HOBJECT_E_GET_KEY_BASE(heap, h); - p_val = DUK_HOBJECT_E_GET_VALUE_BASE(heap, h); - p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(heap, h); - n = DUK_HOBJECT_GET_ENEXT(h); - while (n-- > 0) { - duk_hstring *key; - - key = p_key[n]; - if (DUK_UNLIKELY(key == NULL)) { - continue; - } - DUK_HSTRING_DECREF_NORZ(thr, key); - if (DUK_UNLIKELY(p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR)) { - duk_hobject *h_getset; - h_getset = p_val[n].a.get; - DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset)); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset); - h_getset = p_val[n].a.set; - DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset)); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset); - } else { - duk_tval *tv_val; - tv_val = &p_val[n].v; - DUK_TVAL_DECREF_NORZ(thr, tv_val); - } - } - - p_tv = DUK_HOBJECT_A_GET_BASE(heap, h); - n = DUK_HOBJECT_GET_ASIZE(h); - while (n-- > 0) { - duk_tval *tv_val; - tv_val = p_tv + n; - DUK_TVAL_DECREF_NORZ(thr, tv_val); - } - - /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */ - - h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(heap, h); - DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto)); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto); - - /* XXX: Object subclass tests are quite awkward at present, ideally - * we should be able to switch-case here with a dense index (subtype - * number or something). For now, fast path plain objects and arrays - * and bit test the rest individually. - */ - - if (DUK_HOBJECT_HAS_FASTREFS(h)) { - /* Plain object or array, nothing more to do. While a - * duk_harray has additional fields, none of them need - * DECREF updates. - */ - DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h)); - return; - } - DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h)); - - /* Slow path: special object, start bit checks from most likely. */ - - /* XXX: reorg, more common first */ - if (DUK_HOBJECT_IS_COMPFUNC(h)) { - duk_hcompfunc *f = (duk_hcompfunc *) h; - duk_tval *tv, *tv_end; - duk_hobject **funcs, **funcs_end; - - DUK_ASSERT_HCOMPFUNC_VALID(f); - - if (DUK_LIKELY(DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL)) { - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f); - tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f); - while (tv < tv_end) { - DUK_TVAL_DECREF_NORZ(thr, tv); - tv++; - } - - funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f); - funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f); - while (funcs < funcs_end) { - duk_hobject *h_func; - h_func = *funcs; - DUK_ASSERT(h_func != NULL); - DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_func)); - DUK_HCOMPFUNC_DECREF_NORZ(thr, (duk_hcompfunc *) h_func); - funcs++; - } - } else { - /* May happen in some out-of-memory corner cases. */ - DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref")); - } - - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(heap, f)); - } else if (DUK_HOBJECT_IS_DECENV(h)) { - duk_hdecenv *e = (duk_hdecenv *) h; - DUK_ASSERT_HDECENV_VALID(e); - DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, e->thread); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, e->varmap); - } else if (DUK_HOBJECT_IS_OBJENV(h)) { - duk_hobjenv *e = (duk_hobjenv *) h; - DUK_ASSERT_HOBJENV_VALID(e); - DUK_ASSERT(e->target != NULL); /* Required for object environments. */ - DUK_HOBJECT_DECREF_NORZ(thr, e->target); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { - duk_hbufobj *b = (duk_hbufobj *) h; - DUK_ASSERT_HBUFOBJ_VALID(b); - DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop); -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { - duk_hboundfunc *f = (duk_hboundfunc *) h; - DUK_ASSERT_HBOUNDFUNC_VALID(f); - DUK_TVAL_DECREF_NORZ(thr, &f->target); - DUK_TVAL_DECREF_NORZ(thr, &f->this_binding); - duk__decref_tvals_norz(thr, f->args, f->nargs); -#if defined(DUK_USE_ES6_PROXY) - } else if (DUK_HOBJECT_IS_PROXY(h)) { - duk_hproxy *p = (duk_hproxy *) h; - DUK_ASSERT_HPROXY_VALID(p); - DUK_HOBJECT_DECREF_NORZ(thr, p->target); - DUK_HOBJECT_DECREF_NORZ(thr, p->handler); -#endif /* DUK_USE_ES6_PROXY */ - } else if (DUK_HOBJECT_IS_THREAD(h)) { - duk_hthread *t = (duk_hthread *) h; - duk_activation *act; - duk_tval *tv; - - DUK_ASSERT_HTHREAD_VALID(t); - - tv = t->valstack; - while (tv < t->valstack_top) { - DUK_TVAL_DECREF_NORZ(thr, tv); - tv++; - } - - for (act = t->callstack_curr; act != NULL; act = act->parent) { - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) DUK_ACT_GET_FUNC(act)); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->var_env); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->lex_env); -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->prev_caller); -#endif -#if 0 /* nothing now */ - for (cat = act->cat; cat != NULL; cat = cat->parent) { - } -#endif - } - - - for (i = 0; i < DUK_NUM_BUILTINS; i++) { - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) t->builtins[i]); - } - - DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, (duk_hthread *) t->resumer); - } else { - /* We may come here if the object should have a FASTREFS flag - * but it's missing for some reason. Assert for never getting - * here; however, other than performance, this is harmless. - */ - DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h)); - DUK_ASSERT(0); - } -} - -DUK_INTERNAL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr) { - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); - DUK_ASSERT(hdr != NULL); - - if (DUK_HEAPHDR_IS_OBJECT(hdr)) { - duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) hdr); - } - /* DUK_HTYPE_BUFFER: nothing to finalize */ - /* DUK_HTYPE_STRING: nothing to finalize */ -} - -/* - * Refzero processing for duk_hobject: queue a refzero'ed object to either - * finalize_list or refzero_list and process the relevent list(s) if - * necessary. - * - * Refzero_list is single linked, with only 'prev' pointers set and valid. - * All 'next' pointers are intentionally left as garbage. This doesn't - * matter because refzero_list is processed to completion before any other - * code (like mark-and-sweep) might walk the list. - * - * In more detail: - * - * - On first insert refzero_list is NULL and the new object becomes the - * first and only element on the list; duk__refcount_free_pending() is - * called and it starts processing the list from the initial element, - * i.e. the list tail. - * - * - As each object is refcount finalized, new objects may be queued to - * refzero_list head. Their 'next' pointers are left as garbage, but - * 'prev' points are set correctly, with the element at refzero_list - * having a NULL 'prev' pointer. The fact that refzero_list is non-NULL - * is used to reject (1) recursive duk__refcount_free_pending() and - * (2) finalize_list processing calls. - * - * - When we're done with the current object, read its 'prev' pointer and - * free the object. If 'prev' is NULL, we've reached head of list and are - * done: set refzero_list to NULL and process pending finalizers. Otherwise - * continue processing the list. - * - * A refzero cascade is free of side effects because it only involves - * queueing more objects and freeing memory; finalizer execution is blocked - * in the code path queueing objects to finalize_list. As a result the - * initial refzero call (which triggers duk__refcount_free_pending()) must - * check finalize_list so that finalizers are executed snappily. - * - * If finalize_list processing starts first, refzero may occur while we're - * processing finalizers. That's fine: that particular refzero cascade is - * handled to completion without side effects. Once the cascade is complete, - * we'll run pending finalizers but notice that we're already doing that and - * return. - * - * This could be expanded to allow incremental freeing: just bail out - * early and resume at a future alloc/decref/refzero. However, if that - * were done, the list structure would need to be kept consistent at all - * times, mark-and-sweep would need to handle refzero_list, etc. - */ - -DUK_LOCAL void duk__refcount_free_pending(duk_heap *heap) { - duk_heaphdr *curr; -#if defined(DUK_USE_DEBUG) - duk_int_t count = 0; -#endif - - DUK_ASSERT(heap != NULL); - - curr = heap->refzero_list; - DUK_ASSERT(curr != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, curr) == NULL); /* We're called on initial insert only. */ - /* curr->next is GARBAGE. */ - - do { - duk_heaphdr *prev; - - DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr)); - -#if defined(DUK_USE_DEBUG) - count++; -#endif - - DUK_ASSERT(curr != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */ - /* FINALIZED may be set; don't care about flags here. */ - - /* Refcount finalize 'curr'. Refzero_list must be non-NULL - * here to prevent recursive entry to duk__refcount_free_pending(). - */ - DUK_ASSERT(heap->refzero_list != NULL); - duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr); - - prev = DUK_HEAPHDR_GET_PREV(heap, curr); - DUK_ASSERT((prev == NULL && heap->refzero_list == curr) || \ - (prev != NULL && heap->refzero_list != curr)); - /* prev->next is intentionally not updated and is garbage. */ - - duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */ - - curr = prev; - } while (curr != NULL); - - heap->refzero_list = NULL; - - DUK_DD(DUK_DDPRINT("refzero processed %ld objects", (long) count)); -} - -DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hobject(duk_heap *heap, duk_hobject *obj, duk_bool_t skip_free_pending) { - duk_heaphdr *hdr; - duk_heaphdr *root; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) obj) == DUK_HTYPE_OBJECT); - - hdr = (duk_heaphdr *) obj; - - /* Refzero'd objects must be in heap_allocated. They can't be in - * finalize_list because all objects on finalize_list have an - * artificial +1 refcount bump. - */ -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(duk_heap_in_heap_allocated(heap, (duk_heaphdr *) obj)); -#endif - - DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, hdr); - -#if defined(DUK_USE_FINALIZER_SUPPORT) - /* This finalizer check MUST BE side effect free. It should also be - * as fast as possible because it's applied to every object freed. - */ - if (DUK_UNLIKELY(DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr) != 0U)) { - /* Special case: FINALIZED may be set if mark-and-sweep queued - * object for finalization, the finalizer was executed (and - * FINALIZED set), mark-and-sweep hasn't yet processed the - * object again, but its refcount drops to zero. Free without - * running the finalizer again. - */ - if (DUK_HEAPHDR_HAS_FINALIZED(hdr)) { - DUK_D(DUK_DPRINT("refzero'd object has finalizer and FINALIZED is set -> free")); - } else { - /* Set FINALIZABLE flag so that all objects on finalize_list - * will have it set and are thus detectable based on the - * flag alone. - */ - DUK_HEAPHDR_SET_FINALIZABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Bump refcount on finalize_list insert so that a - * refzero can never occur when an object is waiting - * for its finalizer call. Refzero might otherwise - * now happen because we allow duk_push_heapptr() for - * objects pending finalization. - */ - DUK_HEAPHDR_PREINC_REFCOUNT(hdr); -#endif - DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, hdr); - - /* Process finalizers unless skipping is explicitly - * requested (NORZ) or refzero_list is being processed - * (avoids side effects during a refzero cascade). - * If refzero_list is processed, the initial refzero - * call will run pending finalizers when refzero_list - * is done. - */ - if (!skip_free_pending && heap->refzero_list == NULL) { - duk_heap_process_finalize_list(heap); - } - return; - } - } -#endif /* DUK_USE_FINALIZER_SUPPORT */ - - /* No need to finalize, free object via refzero_list. */ - - root = heap->refzero_list; - - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); - /* 'next' is left as GARBAGE. */ - heap->refzero_list = hdr; - - if (root == NULL) { - /* Object is now queued. Refzero_list was NULL so - * no-one is currently processing it; do it here. - * With refzero processing just doing a cascade of - * free calls, we can process it directly even when - * NORZ macros are used: there are no side effects. - */ - duk__refcount_free_pending(heap); - DUK_ASSERT(heap->refzero_list == NULL); - - /* Process finalizers only after the entire cascade - * is finished. In most cases there's nothing to - * finalize, so fast path check to avoid a call. - */ -#if defined(DUK_USE_FINALIZER_SUPPORT) - if (!skip_free_pending && DUK_UNLIKELY(heap->finalize_list != NULL)) { - duk_heap_process_finalize_list(heap); - } -#endif - } else { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL); - DUK_HEAPHDR_SET_PREV(heap, root, hdr); - - /* Object is now queued. Because refzero_list was - * non-NULL, it's already being processed by someone - * in the C call stack, so we're done. - */ - } -} - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL DUK_ALWAYS_INLINE void duk_refzero_check_fast(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */ - - if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { - duk_heap_process_finalize_list(thr->heap); - } -} - -DUK_INTERNAL void duk_refzero_check_slow(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */ - - if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { - duk_heap_process_finalize_list(thr->heap); - } -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* - * Refzero processing for duk_hstring. - */ - -DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hstring(duk_heap *heap, duk_hstring *str) { - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); - DUK_ASSERT(str != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) str) == DUK_HTYPE_STRING); - - duk_heap_strcache_string_remove(heap, str); - duk_heap_strtable_unlink(heap, str); - duk_free_hstring(heap, str); -} - -/* - * Refzero processing for duk_hbuffer. - */ - -DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hbuffer(duk_heap *heap, duk_hbuffer *buf) { - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); - DUK_ASSERT(buf != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) buf) == DUK_HTYPE_BUFFER); - - DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, (duk_heaphdr *) buf); - duk_free_hbuffer(heap, buf); -} - -/* - * Incref and decref functions. - * - * Decref may trigger immediate refzero handling, which may free and finalize - * an arbitrary number of objects (a "DECREF cascade"). - * - * Refzero handling is skipped entirely if (1) mark-and-sweep is running or - * (2) execution is paused in the debugger. The objects are left in the heap, - * and will be freed by mark-and-sweep or eventual heap destruction. - * - * This is necessary during mark-and-sweep because refcounts are also updated - * during the sweep phase (otherwise objects referenced by a swept object - * would have incorrect refcounts) which then calls here. This could be - * avoided by using separate decref macros in mark-and-sweep; however, - * mark-and-sweep also calls finalizers which would use the ordinary decref - * macros anyway. - * - * We can't process refzeros (= free objects) when the debugger is running - * as the debugger might make an object unreachable but still continue - * inspecting it (or even cause it to be pushed back). So we must rely on - * mark-and-sweep to collect them. - * - * The DUK__RZ_SUPPRESS_CHECK() condition is also used in heap destruction - * when running finalizers for remaining objects: the flag prevents objects - * from being moved around in heap linked lists while that's being done. - * - * The suppress condition is important to performance. - */ - -#define DUK__RZ_SUPPRESS_ASSERT1() do { \ - DUK_ASSERT(thr != NULL); \ - DUK_ASSERT(thr->heap != NULL); \ - /* When mark-and-sweep runs, heap_thread must exist. */ \ - DUK_ASSERT(thr->heap->ms_running == 0 || thr->heap->heap_thread != NULL); \ - /* When mark-and-sweep runs, the 'thr' argument always matches heap_thread. \ - * This could be used to e.g. suppress check against 'thr' directly (and \ - * knowing it would be heap_thread); not really used now. \ - */ \ - DUK_ASSERT(thr->heap->ms_running == 0 || thr == thr->heap->heap_thread); \ - /* We may be called when the heap is initializing and we process \ - * refzeros normally, but mark-and-sweep and finalizers are prevented \ - * if that's the case. \ - */ \ - DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->ms_prevent_count > 0); \ - DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->pf_prevent_count > 0); \ - } while (0) - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -#define DUK__RZ_SUPPRESS_ASSERT2() do { \ - /* When debugger is paused, ms_running is set. */ \ - DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->ms_running != 0); \ - } while (0) -#define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0) -#else -#define DUK__RZ_SUPPRESS_ASSERT2() do { } while (0) -#define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0) -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -#define DUK__RZ_SUPPRESS_CHECK() do { \ - DUK__RZ_SUPPRESS_ASSERT1(); \ - DUK__RZ_SUPPRESS_ASSERT2(); \ - if (DUK_UNLIKELY(DUK__RZ_SUPPRESS_COND())) { \ - DUK_DDD(DUK_DDDPRINT("refzero handling suppressed (not even queued) when mark-and-sweep running, object: %p", (void *) h)); \ - return; \ - } \ - } while (0) - -#define DUK__RZ_STRING() do { \ - duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \ - } while (0) -#define DUK__RZ_BUFFER() do { \ - duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \ - } while (0) -#define DUK__RZ_OBJECT() do { \ - duk__refcount_refzero_hobject(heap, (duk_hobject *) h, skip_free_pending); \ - } while (0) - -/* XXX: test the effect of inlining here vs. NOINLINE in refzero helpers */ -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -#define DUK__RZ_INLINE DUK_ALWAYS_INLINE -#else -#define DUK__RZ_INLINE /*nop*/ -#endif - -DUK_LOCAL DUK__RZ_INLINE void duk__hstring_refzero_helper(duk_hthread *thr, duk_hstring *h) { - duk_heap *heap; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(h != NULL); - heap = thr->heap; - - DUK__RZ_SUPPRESS_CHECK(); - DUK__RZ_STRING(); -} - -DUK_LOCAL DUK__RZ_INLINE void duk__hbuffer_refzero_helper(duk_hthread *thr, duk_hbuffer *h) { - duk_heap *heap; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(h != NULL); - heap = thr->heap; - - DUK__RZ_SUPPRESS_CHECK(); - DUK__RZ_BUFFER(); -} - -DUK_LOCAL DUK__RZ_INLINE void duk__hobject_refzero_helper(duk_hthread *thr, duk_hobject *h, duk_bool_t skip_free_pending) { - duk_heap *heap; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(h != NULL); - heap = thr->heap; - - DUK__RZ_SUPPRESS_CHECK(); - DUK__RZ_OBJECT(); -} - -DUK_LOCAL DUK__RZ_INLINE void duk__heaphdr_refzero_helper(duk_hthread *thr, duk_heaphdr *h, duk_bool_t skip_free_pending) { - duk_heap *heap; - duk_small_uint_t htype; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(h != NULL); - heap = thr->heap; - - htype = (duk_small_uint_t) DUK_HEAPHDR_GET_TYPE(h); - DUK__RZ_SUPPRESS_CHECK(); - - switch (htype) { - case DUK_HTYPE_STRING: - /* Strings have no internal references but do have "weak" - * references in the string cache. Also note that strings - * are not on the heap_allocated list like other heap - * elements. - */ - - DUK__RZ_STRING(); - break; - - case DUK_HTYPE_OBJECT: - /* Objects have internal references. Must finalize through - * the "refzero" work list. - */ - - DUK__RZ_OBJECT(); - break; - - default: - /* Buffers have no internal references. However, a dynamic - * buffer has a separate allocation for the buffer. This is - * freed by duk_heap_free_heaphdr_raw(). - */ - - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_BUFFER); - DUK__RZ_BUFFER(); - break; - } -} - -DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) { - duk__heaphdr_refzero_helper(thr, h, 0 /*skip_free_pending*/); -} - -DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) { - duk__heaphdr_refzero_helper(thr, h, 1 /*skip_free_pending*/); -} - -DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { - duk__hstring_refzero_helper(thr, h); -} - -DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { - duk__hbuffer_refzero_helper(thr, h); -} - -DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h) { - duk__hobject_refzero_helper(thr, h, 0 /*skip_free_pending*/); -} - -DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) { - duk__hobject_refzero_helper(thr, h, 1 /*skip_free_pending*/); -} - -#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL void duk_tval_incref(duk_tval *tv) { - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT_DISABLE(h->h_refcount >= 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) != 0); /* No wrapping. */ - } -} - -DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1); -#if 0 - if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) { - return; - } - duk_heaphdr_refzero(thr, h); -#else - duk_heaphdr_decref(thr, h); -#endif - } -} - -DUK_INTERNAL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1); -#if 0 - if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) { - return; - } - duk_heaphdr_refzero_norz(thr, h); -#else - duk_heaphdr_decref_norz(thr, h); -#endif - } -} -#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */ - -#define DUK__DECREF_ASSERTS() do { \ - DUK_ASSERT(thr != NULL); \ - DUK_ASSERT(thr->heap != NULL); \ - DUK_ASSERT(h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((duk_heaphdr *) h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) >= 1); \ - } while (0) -#if defined(DUK_USE_ROM_OBJECTS) -#define DUK__INCREF_SHARED() do { \ - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \ - return; \ - } \ - DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \ - } while (0) -#define DUK__DECREF_SHARED() do { \ - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \ - return; \ - } \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \ - return; \ - } \ - } while (0) -#else -#define DUK__INCREF_SHARED() do { \ - DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \ - } while (0) -#define DUK__DECREF_SHARED() do { \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \ - return; \ - } \ - } while (0) -#endif - -#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -/* This will in practice be inlined because it's just an INC instructions - * and a bit test + INC when ROM objects are enabled. - */ -DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) { - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); - - DUK__INCREF_SHARED(); -} - -DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) { - DUK__DECREF_ASSERTS(); - DUK__DECREF_SHARED(); - duk_heaphdr_refzero(thr, h); - - /* Forced mark-and-sweep when GC torture enabled; this could happen - * on any DECREF (but not DECREF_NORZ). - */ - DUK_GC_TORTURE(thr->heap); -} -DUK_INTERNAL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h) { - DUK__DECREF_ASSERTS(); - DUK__DECREF_SHARED(); - duk_heaphdr_refzero_norz(thr, h); -} -#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */ - -#if 0 /* Not needed. */ -DUK_INTERNAL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h) { - DUK__DECREF_ASSERTS(); - DUK__DECREF_SHARED(); - duk_hstring_refzero(thr, h); -} -DUK_INTERNAL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h) { - DUK__DECREF_ASSERTS(); - DUK__DECREF_SHARED(); - duk_hstring_refzero_norz(thr, h); -} -DUK_INTERNAL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h) { - DUK__DECREF_ASSERTS(); - DUK__DECREF_SHARED(); - duk_hbuffer_refzero(thr, h); -} -DUK_INTERNAL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h) { - DUK__DECREF_ASSERTS(); - DUK__DECREF_SHARED(); - duk_hbuffer_refzero_norz(thr, h); -} -DUK_INTERNAL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h) { - DUK__DECREF_ASSERTS(); - DUK__DECREF_SHARED(); - duk_hobject_refzero(thr, h); -} -DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) { - DUK__DECREF_ASSERTS(); - DUK__DECREF_SHARED(); - duk_hobject_refzero_norz(thr, h); -} -#endif - -#else /* DUK_USE_REFERENCE_COUNTING */ - -/* no refcounting */ - -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* automatic undefs */ -#undef DUK__DECREF_ASSERTS -#undef DUK__DECREF_SHARED -#undef DUK__INCREF_SHARED -#undef DUK__RZ_BUFFER -#undef DUK__RZ_INLINE -#undef DUK__RZ_OBJECT -#undef DUK__RZ_STRING -#undef DUK__RZ_SUPPRESS_ASSERT1 -#undef DUK__RZ_SUPPRESS_ASSERT2 -#undef DUK__RZ_SUPPRESS_CHECK -#undef DUK__RZ_SUPPRESS_COND -#line 1 "duk_heap_stringcache.c" -/* - * String cache. - * - * Provides a cache to optimize indexed string lookups. The cache keeps - * track of (byte offset, char offset) states for a fixed number of strings. - * Otherwise we'd need to scan from either end of the string, as we store - * strings in (extended) UTF-8. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Delete references to given hstring from the heap string cache. - * - * String cache references are 'weak': they are not counted towards - * reference counts, nor serve as roots for mark-and-sweep. When an - * object is about to be freed, such references need to be removed. - */ - -DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) { - duk_small_int_t i; - for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - duk_strcache *c = heap->strcache + i; - if (c->h == h) { - DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p", - (void *) h, (void *) heap)); - c->h = NULL; - - /* XXX: the string shouldn't appear twice, but we now loop to the - * end anyway; if fixed, add a looping assertion to ensure there - * is no duplicate. - */ - } - } -} - -/* - * String scanning helpers - * - * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are - * considered to contribute a character. This must match how string - * character length is computed. - */ - -DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) { - while (n > 0) { - for (;;) { - p++; - if (p >= q) { - return NULL; - } - if ((*p & 0xc0) != 0x80) { - break; - } - } - n--; - } - return p; -} - -DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) { - while (n > 0) { - for (;;) { - p--; - if (p < q) { - return NULL; - } - if ((*p & 0xc0) != 0x80) { - break; - } - } - n--; - } - return p; -} - -/* - * Convert char offset to byte offset - * - * Avoid using the string cache if possible: for ASCII strings byte and - * char offsets are equal and for short strings direct scanning may be - * better than using the string cache (which may evict a more important - * entry). - * - * Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t). - * Better typing might be to use duk_size_t. - * - * Caller should ensure 'char_offset' is within the string bounds [0,charlen] - * (endpoint is inclusive). If this is not the case, no memory unsafe - * behavior will happen but an error will be thrown. - */ - -DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) { - duk_heap *heap; - duk_strcache *sce; - duk_uint_fast32_t byte_offset; - duk_small_int_t i; - duk_bool_t use_cache; - duk_uint_fast32_t dist_start, dist_end, dist_sce; - duk_uint_fast32_t char_length; - const duk_uint8_t *p_start; - const duk_uint8_t *p_end; - const duk_uint8_t *p_found; - - /* - * For ASCII strings, the answer is simple. - */ - - if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) { - return char_offset; - } - - char_length = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h); - DUK_ASSERT(char_offset <= char_length); - - if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) { - /* Must recheck because the 'is ascii' flag may be set - * lazily. Alternatively, we could just compare charlen - * to bytelen. - */ - return char_offset; - } - - /* - * For non-ASCII strings, we need to scan forwards or backwards - * from some starting point. The starting point may be the start - * or end of the string, or some cached midpoint in the string - * cache. - * - * For "short" strings we simply scan without checking or updating - * the cache. For longer strings we check and update the cache as - * necessary, inserting a new cache entry if none exists. - */ - - DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld", - (void *) h, (long) char_offset, - (long) DUK_HSTRING_GET_CHARLEN(h), - (long) DUK_HSTRING_GET_BYTELEN(h))); - - heap = thr->heap; - sce = NULL; - use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); - - if (use_cache) { -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):")); - for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - duk_strcache *c = heap->strcache + i; - DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld", - (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx)); - } -#endif - - for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - duk_strcache *c = heap->strcache + i; - - if (c->h == h) { - sce = c; - break; - } - } - } - - /* - * Scan from shortest distance: - * - start of string - * - end of string - * - cache entry (if exists) - */ - - DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset); - dist_start = char_offset; - dist_end = char_length - char_offset; - dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */ - - p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); - p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h)); - p_found = NULL; - - if (sce) { - if (char_offset >= sce->cidx) { - dist_sce = char_offset - sce->cidx; - if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) { - DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, " - "dist_start=%ld, dist_end=%ld, dist_sce=%ld => " - "scan forwards from sce", - (long) use_cache, (void *) (sce ? sce->h : NULL), - (sce ? (long) sce->cidx : (long) -1), - (sce ? (long) sce->bidx : (long) -1), - (long) dist_start, (long) dist_end, (long) dist_sce)); - - p_found = duk__scan_forwards(p_start + sce->bidx, - p_end, - dist_sce); - goto scan_done; - } - } else { - dist_sce = sce->cidx - char_offset; - if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) { - DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, " - "dist_start=%ld, dist_end=%ld, dist_sce=%ld => " - "scan backwards from sce", - (long) use_cache, (void *) (sce ? sce->h : NULL), - (sce ? (long) sce->cidx : (long) -1), - (sce ? (long) sce->bidx : (long) -1), - (long) dist_start, (long) dist_end, (long) dist_sce)); - - p_found = duk__scan_backwards(p_start + sce->bidx, - p_start, - dist_sce); - goto scan_done; - } - } - } - - /* no sce, or sce scan not best */ - - if (dist_start <= dist_end) { - DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, " - "dist_start=%ld, dist_end=%ld, dist_sce=%ld => " - "scan forwards from string start", - (long) use_cache, (void *) (sce ? sce->h : NULL), - (sce ? (long) sce->cidx : (long) -1), - (sce ? (long) sce->bidx : (long) -1), - (long) dist_start, (long) dist_end, (long) dist_sce)); - - p_found = duk__scan_forwards(p_start, - p_end, - dist_start); - } else { - DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, " - "dist_start=%ld, dist_end=%ld, dist_sce=%ld => " - "scan backwards from string end", - (long) use_cache, (void *) (sce ? sce->h : NULL), - (sce ? (long) sce->cidx : (long) -1), - (sce ? (long) sce->bidx : (long) -1), - (long) dist_start, (long) dist_end, (long) dist_sce)); - - p_found = duk__scan_backwards(p_end, - p_start, - dist_end); - } - - scan_done: - - if (DUK_UNLIKELY(p_found == NULL)) { - /* Scan error: this shouldn't normally happen; it could happen if - * string is not valid UTF-8 data, and clen/blen are not consistent - * with the scanning algorithm. - */ - goto scan_error; - } - - DUK_ASSERT(p_found >= p_start); - DUK_ASSERT(p_found <= p_end); /* may be equal */ - byte_offset = (duk_uint32_t) (p_found - p_start); - - DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld", - (void *) h, (long) char_offset, (long) byte_offset)); - - /* - * Update cache entry (allocating if necessary), and move the - * cache entry to the first place (in an "LRU" policy). - */ - - if (use_cache) { - /* update entry, allocating if necessary */ - if (!sce) { - sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1; /* take last entry */ - sce->h = h; - } - DUK_ASSERT(sce != NULL); - sce->bidx = (duk_uint32_t) (p_found - p_start); - sce->cidx = (duk_uint32_t) char_offset; - - /* LRU: move our entry to first */ - if (sce > &heap->strcache[0]) { - /* - * A C - * B A - * C <- sce ==> B - * D D - */ - duk_strcache tmp; - - tmp = *sce; - DUK_MEMMOVE((void *) (&heap->strcache[1]), - (const void *) (&heap->strcache[0]), - (size_t) (((char *) sce) - ((char *) &heap->strcache[0]))); - heap->strcache[0] = tmp; - - /* 'sce' points to the wrong entry here, but is no longer used */ - } -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):")); - for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - duk_strcache *c = heap->strcache + i; - DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld", - (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx)); - } -#endif - } - - return byte_offset; - - scan_error: - DUK_ERROR_INTERNAL(thr); - return 0; -} -#line 1 "duk_heap_stringtable.c" -/* - * Heap string table handling, string interning. - */ - -/* #include duk_internal.h -> already included */ - -/* Resize checks not needed if minsize == maxsize, typical for low memory - * targets. - */ -#define DUK__STRTAB_RESIZE_CHECK -#if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE) -#undef DUK__STRTAB_RESIZE_CHECK -#endif - -#if defined(DUK_USE_STRTAB_PTRCOMP) -#define DUK__HEAPPTR_ENC16(heap,ptr) DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr)) -#define DUK__HEAPPTR_DEC16(heap,val) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val)) -#define DUK__GET_STRTABLE(heap) ((heap)->strtable16) -#else -#define DUK__HEAPPTR_ENC16(heap,ptr) (ptr) -#define DUK__HEAPPTR_DEC16(heap,val) (val) -#define DUK__GET_STRTABLE(heap) ((heap)->strtable) -#endif - -#define DUK__STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ - -/* - * Debug dump stringtable. - */ - -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) { -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *strtable; -#else - duk_hstring **strtable; -#endif - duk_uint32_t i; - duk_hstring *h; - duk_size_t count_total = 0; - duk_size_t count_chain; - duk_size_t count_chain_min = DUK_SIZE_MAX; - duk_size_t count_chain_max = 0; - duk_size_t count_len[8]; /* chain lengths from 0 to 7 */ - - if (heap == NULL) { - DUK_D(DUK_DPRINT("string table, heap=NULL")); - return; - } - - strtable = DUK__GET_STRTABLE(heap); - if (strtable == NULL) { - DUK_D(DUK_DPRINT("string table, strtab=NULL")); - return; - } - - DUK_MEMZERO((void *) count_len, sizeof(count_len)); - for (i = 0; i < heap->st_size; i++) { - h = DUK__HEAPPTR_DEC16(heap, strtable[i]); - count_chain = 0; - while (h != NULL) { - count_chain++; - h = h->hdr.h_next; - } - if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) { - count_len[count_chain]++; - } - count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max); - count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min); - count_total += count_chain; - } - - DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: " - "counts: %lu %lu %lu %lu %lu %lu %lu %lu ...", - (void *) heap->strtable, (unsigned long) count_total, - (unsigned long) count_chain_min, (unsigned long) count_chain_max, - (double) count_total / (double) heap->st_size, - (unsigned long) count_len[0], (unsigned long) count_len[1], - (unsigned long) count_len[2], (unsigned long) count_len[3], - (unsigned long) count_len[4], (unsigned long) count_len[5], - (unsigned long) count_len[6], (unsigned long) count_len[7])); -} -#endif /* DUK_USE_DEBUG */ - -/* - * Assertion helper to ensure strtable is populated correctly. - */ - -#if defined(DUK_USE_ASSERTIONS) -DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) { -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *strtable; -#else - duk_hstring **strtable; -#endif - duk_uint32_t i; - duk_hstring *h; - duk_size_t count = 0; - - DUK_ASSERT(heap != NULL); - - strtable = DUK__GET_STRTABLE(heap); - if (strtable != NULL) { - DUK_ASSERT(heap->st_size != 0); - DUK_ASSERT(heap->st_mask == heap->st_size - 1); - - for (i = 0; i < heap->st_size; i++) { - h = DUK__HEAPPTR_DEC16(heap, strtable[i]); - while (h != NULL) { - DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); - count++; - h = h->hdr.h_next; - } - } - } else { - DUK_ASSERT(heap->st_size == 0); - DUK_ASSERT(heap->st_mask == 0); - } - -#if defined(DUK__STRTAB_RESIZE_CHECK) - DUK_ASSERT(count == (duk_size_t) heap->st_count); -#endif -} -#endif /* DUK_USE_ASSERTIONS */ - -/* - * Allocate and initialize a duk_hstring. - * - * Returns a NULL if allocation or initialization fails for some reason. - * - * The string won't be inserted into the string table and isn't tracked in - * any way (link pointers will be NULL). The caller must place the string - * into the string table without any risk of a longjmp, otherwise the string - * is leaked. - */ - -DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap, - const duk_uint8_t *str, - duk_uint32_t blen, - duk_uint32_t strhash, - const duk_uint8_t *extdata) { - duk_hstring *res; - const duk_uint8_t *data; -#if !defined(DUK_USE_HSTRING_ARRIDX) - duk_uarridx_t dummy; -#endif - - DUK_ASSERT(heap != NULL); - DUK_UNREF(extdata); - -#if defined(DUK_USE_STRLEN16) - /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */ - if (blen > 0xffffUL) { - DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern")); - goto alloc_error; - } -#endif - - /* XXX: Memzeroing the allocated structure is not really necessary - * because we could just initialize all fields explicitly (almost - * all fields are initialized explicitly anyway). - */ -#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) - if (extdata) { - res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external)); - if (DUK_UNLIKELY(res == NULL)) { - goto alloc_error; - } - DUK_MEMZERO(res, sizeof(duk_hstring_external)); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); -#endif - DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA); - - DUK_ASSERT(extdata[blen] == 0); /* Application responsibility. */ - data = extdata; - ((duk_hstring_external *) res)->extdata = extdata; - } else -#endif /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */ - { - duk_uint8_t *data_tmp; - - /* NUL terminate for convenient C access */ - DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen); /* No wrap, limits ensure. */ - res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1); - if (DUK_UNLIKELY(res == NULL)) { - goto alloc_error; - } - DUK_MEMZERO(res, sizeof(duk_hstring)); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); -#endif - DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); - - data_tmp = (duk_uint8_t *) (res + 1); - DUK_MEMCPY(data_tmp, str, blen); - data_tmp[blen] = (duk_uint8_t) 0; - data = (const duk_uint8_t *) data_tmp; - } - - DUK_HSTRING_SET_BYTELEN(res, blen); - DUK_HSTRING_SET_HASH(res, strhash); - - DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res)); -#if defined(DUK_USE_HSTRING_ARRIDX) - res->arridx = duk_js_to_arrayindex_string(data, blen); - if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) { -#else - dummy = duk_js_to_arrayindex_string(data, blen); - if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) { -#endif - /* Array index strings cannot be symbol strings, - * and they're always pure ASCII so blen == clen. - */ - DUK_HSTRING_SET_ARRIDX(res); - DUK_HSTRING_SET_ASCII(res); - DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen); - } else { - /* Because 'data' is NUL-terminated, we don't need a - * blen > 0 check here. For NUL (0x00) the symbol - * checks will be false. - */ - if (DUK_UNLIKELY(data[0] >= 0x80U)) { - if (data[0] <= 0x81) { - DUK_HSTRING_SET_SYMBOL(res); - } else if (data[0] == 0x82U || data[0] == 0xffU) { - DUK_HSTRING_SET_HIDDEN(res); - DUK_HSTRING_SET_SYMBOL(res); - } - } - - /* Using an explicit 'ASCII' flag has larger footprint (one call site - * only) but is quite useful for the case when there's no explicit - * 'clen' in duk_hstring. - * - * The flag is set lazily for RAM strings. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); - -#if defined(DUK_USE_HSTRING_LAZY_CLEN) - /* Charlen initialized to 0, updated on-the-fly. */ -#else - duk_hstring_init_charlen(res); /* Also sets ASCII flag. */ -#endif - } - - DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld", - (unsigned long) DUK_HSTRING_GET_HASH(res), - (long) DUK_HSTRING_GET_BYTELEN(res), - (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0), - (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0))); - - DUK_ASSERT(res != NULL); - return res; - - alloc_error: - return NULL; -} - -/* - * Grow strtable allocation in-place. - */ - -#if defined(DUK__STRTAB_RESIZE_CHECK) -DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) { - duk_uint32_t new_st_size; - duk_uint32_t old_st_size; - duk_uint32_t i; - duk_hstring *h; - duk_hstring *next; - duk_hstring *prev; -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *new_ptr; - duk_uint16_t *new_ptr_high; -#else - duk_hstring **new_ptr; - duk_hstring **new_ptr_high; -#endif - - DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->st_resizing == 1); - DUK_ASSERT(heap->st_size >= 2); - DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ - DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); - - DUK_STATS_INC(heap, stats_strtab_resize_grow); - - new_st_size = heap->st_size << 1U; - DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */ - - /* Reallocate the strtable first and then work in-place to rehash - * strings. We don't need an indirect allocation here: even if GC - * is triggered to satisfy the allocation, recursive strtable resize - * is prevented by flags. This is also why we don't need to use - * DUK_REALLOC_INDIRECT(). - */ - -#if defined(DUK_USE_STRTAB_PTRCOMP) - new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); -#else - new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); -#endif - if (DUK_UNLIKELY(new_ptr == NULL)) { - /* If realloc fails we can continue normally: the string table - * won't "fill up" although chains will gradually get longer. - * When string insertions continue, we'll quite soon try again - * with no special handling. - */ - DUK_D(DUK_DPRINT("string table grow failed, ignoring")); - return; - } -#if defined(DUK_USE_STRTAB_PTRCOMP) - heap->strtable16 = new_ptr; -#else - heap->strtable = new_ptr; -#endif - - /* Rehash a single bucket into two separate ones. When we grow - * by x2 the highest 'new' bit determines whether a string remains - * in its old position (bit is 0) or goes to a new one (bit is 1). - */ - - old_st_size = heap->st_size; - new_ptr_high = new_ptr + old_st_size; - for (i = 0; i < old_st_size; i++) { - duk_hstring *new_root; - duk_hstring *new_root_high; - - h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]); - new_root = h; - new_root_high = NULL; - - prev = NULL; - while (h != NULL) { - duk_uint32_t mask; - - DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); - next = h->hdr.h_next; - - /* Example: if previous size was 256, previous mask is 0xFF - * and size is 0x100 which corresponds to the new bit that - * comes into play. - */ - DUK_ASSERT(heap->st_mask == old_st_size - 1); - mask = old_st_size; - if (DUK_HSTRING_GET_HASH(h) & mask) { - if (prev != NULL) { - prev->hdr.h_next = h->hdr.h_next; - } else { - DUK_ASSERT(h == new_root); - new_root = h->hdr.h_next; - } - - h->hdr.h_next = new_root_high; - new_root_high = h; - } else { - prev = h; - } - h = next; - } - - new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root); - new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high); - } - - heap->st_size = new_st_size; - heap->st_mask = new_st_size - 1; - -#if defined(DUK_USE_ASSERTIONS) - duk__strtable_assert_checks(heap); -#endif -} -#endif /* DUK__STRTAB_RESIZE_CHECK */ - -/* - * Shrink strtable allocation in-place. - */ - -#if defined(DUK__STRTAB_RESIZE_CHECK) -DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) { - duk_uint32_t new_st_size; - duk_uint32_t i; - duk_hstring *h; - duk_hstring *other; - duk_hstring *root; -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *old_ptr; - duk_uint16_t *old_ptr_high; - duk_uint16_t *new_ptr; -#else - duk_hstring **old_ptr; - duk_hstring **old_ptr_high; - duk_hstring **new_ptr; -#endif - - DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->st_resizing == 1); - DUK_ASSERT(heap->st_size >= 2); - DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ - DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); - - DUK_STATS_INC(heap, stats_strtab_resize_shrink); - - new_st_size = heap->st_size >> 1U; - - /* Combine two buckets into a single one. When we shrink, one hash - * bit (highest) disappears. - */ - old_ptr = DUK__GET_STRTABLE(heap); - old_ptr_high = old_ptr + new_st_size; - for (i = 0; i < new_st_size; i++) { - h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]); - other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]); - - if (h == NULL) { - /* First chain is empty, so use second one as is. */ - root = other; - } else { - /* Find end of first chain, and link in the second. */ - root = h; - while (h->hdr.h_next != NULL) { - h = h->hdr.h_next; - } - h->hdr.h_next = other; - } - - old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root); - } - - heap->st_size = new_st_size; - heap->st_mask = new_st_size - 1; - - /* The strtable is now consistent and we can realloc safely. Even - * if side effects cause string interning or removal the strtable - * updates are safe. Recursive resize has been prevented by caller. - * This is also why we don't need to use DUK_REALLOC_INDIRECT(). - * - * We assume a realloc() to a smaller size is guaranteed to succeed. - * It would be relatively straightforward to handle the error by - * essentially performing a "grow" step to recover. - */ - -#if defined(DUK_USE_STRTAB_PTRCOMP) - new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); - DUK_ASSERT(new_ptr != NULL); - heap->strtable16 = new_ptr; -#else - new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); - DUK_ASSERT(new_ptr != NULL); - heap->strtable = new_ptr; -#endif - -#if defined(DUK_USE_ASSERTIONS) - duk__strtable_assert_checks(heap); -#endif -} -#endif /* DUK__STRTAB_RESIZE_CHECK */ - -/* - * Grow/shrink check. - */ - -#if defined(DUK__STRTAB_RESIZE_CHECK) -DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) { - duk_uint32_t load_factor; /* fixed point */ - - DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_STRTAB_PTRCOMP) - DUK_ASSERT(heap->strtable16 != NULL); -#else - DUK_ASSERT(heap->strtable != NULL); -#endif - - DUK_STATS_INC(heap, stats_strtab_resize_check); - - /* Prevent recursive resizing. */ - if (DUK_UNLIKELY(heap->st_resizing != 0U)) { - DUK_D(DUK_DPRINT("prevent recursive strtable resize")); - return; - } - - heap->st_resizing = 1; - - DUK_ASSERT(heap->st_size >= 16U); - DUK_ASSERT((heap->st_size >> 4U) >= 1); - load_factor = heap->st_count / (heap->st_size >> 4U); - - DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)", - (unsigned long) heap->st_size, (unsigned long) heap->st_count, - (unsigned long) load_factor, - (double) heap->st_count / (double) heap->st_size)); - - if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) { - if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) { - DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size")); - } else { - DUK_D(DUK_DPRINT("grow string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); -#if defined(DUK_USE_DEBUG) - duk_heap_strtable_dump(heap); -#endif - duk__strtable_grow_inplace(heap); - } - } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) { - if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) { - DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size")); - } else { - DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); -#if defined(DUK_USE_DEBUG) - duk_heap_strtable_dump(heap); -#endif - duk__strtable_shrink_inplace(heap); - } - } else { - DUK_DD(DUK_DDPRINT("no need for strtable resize")); - } - - heap->st_resizing = 0; -} -#endif /* DUK__STRTAB_RESIZE_CHECK */ - -/* - * Torture grow/shrink: unconditionally grow and shrink back. - */ - -#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) -DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) { - duk_uint32_t old_st_size; - - DUK_ASSERT(heap != NULL); - - old_st_size = heap->st_size; - if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) { - return; - } - - heap->st_resizing = 1; - duk__strtable_grow_inplace(heap); - if (heap->st_size > old_st_size) { - duk__strtable_shrink_inplace(heap); - } - heap->st_resizing = 0; -} -#endif /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */ - -/* - * Raw intern; string already checked not to be present. - */ - -DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_hstring *res; - const duk_uint8_t *extdata; -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *slot; -#else - duk_hstring **slot; -#endif - - DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf", - (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash, - (unsigned long) heap->st_size, (unsigned long) heap->st_count, - (double) heap->st_count / (double) heap->st_size)); - - DUK_ASSERT(heap != NULL); - - /* Prevent any side effects on the string table and the caller provided - * str/blen arguments while interning is in progress. For example, if - * the caller provided str/blen from a dynamic buffer, a finalizer - * might resize or modify that dynamic buffer, invalidating the call - * arguments. - * - * While finalizers must be prevented, mark-and-sweep itself is fine. - * Recursive string table resize is prevented explicitly here. - */ - - heap->pf_prevent_count++; - DUK_ASSERT(heap->pf_prevent_count != 0); /* Wrap. */ - -#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) - duk__strtable_resize_torture(heap); -#endif - - /* String table grow/shrink check. Because of chaining (and no - * accumulation issues as with hash probe chains and DELETED - * markers) there's never a mandatory need to resize right now. - * Check for the resize only periodically, based on st_count - * bit pattern. Because string table removal doesn't do a shrink - * check, we do that also here. - * - * Do the resize and possible grow/shrink before the new duk_hstring - * has been allocated. Otherwise we may trigger a GC when the result - * duk_hstring is not yet strongly referenced. - */ - -#if defined(DUK__STRTAB_RESIZE_CHECK) - if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) { - duk__strtable_resize_check(heap); - } -#endif - - /* External string check (low memory optimization). */ - -#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) - extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); -#else - extdata = (const duk_uint8_t *) NULL; -#endif - - /* Allocate and initialize string, not yet linked. This may cause a - * GC which may cause other strings to be interned and inserted into - * the string table before we insert our string. Finalizer execution - * is disabled intentionally to avoid a finalizer from e.g. resizing - * a buffer used as a data area for 'str'. - */ - - res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata); - - /* Allow side effects again: GC must be avoided until duk_hstring - * result (if successful) has been INCREF'd. - */ - DUK_ASSERT(heap->pf_prevent_count > 0); - heap->pf_prevent_count--; - - /* Alloc error handling. */ - - if (DUK_UNLIKELY(res == NULL)) { -#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) - if (extdata != NULL) { - DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata); - } -#endif - return NULL; - } - - /* Insert into string table. */ - -#if defined(DUK_USE_STRTAB_PTRCOMP) - slot = heap->strtable16 + (strhash & heap->st_mask); -#else - slot = heap->strtable + (strhash & heap->st_mask); -#endif - DUK_ASSERT(res->hdr.h_next == NULL); /* This is the case now, but unnecessary zeroing/NULLing. */ - res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot); - *slot = DUK__HEAPPTR_ENC16(heap, res); - - /* Update string count only for successful inserts. */ - -#if defined(DUK__STRTAB_RESIZE_CHECK) - heap->st_count++; -#endif - - /* The duk_hstring is in the string table but is not yet strongly - * reachable. Calling code MUST NOT make any allocations or other - * side effects before the duk_hstring has been INCREF'd and made - * reachable. - */ - - return res; -} - -/* - * Intern a string from str/blen, returning either an existing duk_hstring - * or adding a new one into the string table. The input string does -not- - * need to be NUL terminated. - * - * The input 'str' argument may point to a Duktape managed data area such as - * the data area of a dynamic buffer. It's crucial to avoid any side effects - * that might affect the data area (e.g. resize the dynamic buffer, or write - * to the buffer) before the string is fully interned. - */ - -#if defined(DUK_USE_ROM_STRINGS) -DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) { - duk_size_t lookup_hash; - duk_hstring *curr; - - DUK_ASSERT(heap != NULL); - DUK_UNREF(heap); - - lookup_hash = (blen << 4); - if (blen > 0) { - lookup_hash += str[0]; - } - lookup_hash &= 0xff; - - curr = DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]); - while (curr != NULL) { - if (strhash == DUK_HSTRING_GET_HASH(curr) && - blen == DUK_HSTRING_GET_BYTELEN(curr) && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) { - DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", - curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr))); - return curr; - } - curr = curr->hdr.h_next; - } - - return NULL; -} -#endif /* DUK_USE_ROM_STRINGS */ - -DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { - duk_uint32_t strhash; - duk_hstring *h; - - DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu", (void *) heap, (const void *) str, (unsigned long) blen)); - - /* Preliminaries. */ - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(blen == 0 || str != NULL); - DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */ - strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); - - /* String table lookup. */ - - DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); - DUK_ASSERT(heap->st_size > 0); - DUK_ASSERT(heap->st_size == heap->st_mask + 1); -#if defined(DUK_USE_STRTAB_PTRCOMP) - h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]); -#else - h = heap->strtable[strhash & heap->st_mask]; -#endif - while (h != NULL) { - if (DUK_HSTRING_GET_HASH(h) == strhash && - DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - /* Found existing entry. */ - DUK_STATS_INC(heap, stats_strtab_intern_hit); - return h; - } - h = h->hdr.h_next; - } - - /* ROM table lookup. Because this lookup is slower, do it only after - * RAM lookup. This works because no ROM string is ever interned into - * the RAM string table. - */ - -#if defined(DUK_USE_ROM_STRINGS) - h = duk__strtab_romstring_lookup(heap, str, blen, strhash); - if (h != NULL) { - DUK_STATS_INC(heap, stats_strtab_intern_hit); - return h; - } -#endif - - /* Not found in string table; insert. */ - - DUK_STATS_INC(heap, stats_strtab_intern_miss); - h = duk__strtable_do_intern(heap, str, blen, strhash); - return h; /* may be NULL */ -} - -/* - * Intern a string from u32. - */ - -/* XXX: Could arrange some special handling because we know that the result - * will have an arridx flag and an ASCII flag, won't need a clen check, etc. - */ - -DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) { - duk_uint8_t buf[DUK__STRTAB_U32_MAX_STRLEN]; - duk_uint8_t *p; - - DUK_ASSERT(heap != NULL); - - /* This is smaller and faster than a %lu sprintf. */ - p = buf + sizeof(buf); - do { - p--; - *p = duk_lc_digits[val % 10]; - val = val / 10; - } while (val != 0); /* For val == 0, emit exactly one '0'. */ - DUK_ASSERT(p >= buf); - - return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p)); -} - -/* - * Checked convenience variants. - * - * XXX: Because the main use case is for the checked variants, make them the - * main functionality and provide a safe variant separately (it is only needed - * during heap init). The problem with that is that longjmp state and error - * creation must already be possible to throw. - */ - -DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { - duk_hstring *res; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(blen == 0 || str != NULL); - - res = duk_heap_strtable_intern(thr->heap, str, blen); - if (DUK_UNLIKELY(res == NULL)) { - DUK_ERROR_ALLOC_FAILED(thr); - } - return res; -} - -DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { - duk_hstring *res; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - - res = duk_heap_strtable_intern_u32(thr->heap, val); - if (DUK_UNLIKELY(res == NULL)) { - DUK_ERROR_ALLOC_FAILED(thr); - } - return res; -} - -/* - * Remove (unlink) a string from the string table. - * - * Just unlinks the duk_hstring, leaving link pointers as garbage. - * Caller must free the string itself. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -/* Unlink without a 'prev' pointer. */ -DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) { -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *slot; -#else - duk_hstring **slot; -#endif - duk_hstring *other; - duk_hstring *prev; - - DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx", - (void *) heap, (void *) h, - (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), - (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - -#if defined(DUK__STRTAB_RESIZE_CHECK) - DUK_ASSERT(heap->st_count > 0); - heap->st_count--; -#endif - -#if defined(DUK_USE_STRTAB_PTRCOMP) - slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); -#else - slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); -#endif - other = DUK__HEAPPTR_DEC16(heap, *slot); - DUK_ASSERT(other != NULL); /* At least argument string is in the chain. */ - - prev = NULL; - while (other != h) { - prev = other; - other = other->hdr.h_next; - DUK_ASSERT(other != NULL); /* We'll eventually find 'h'. */ - } - if (prev != NULL) { - /* Middle of list. */ - prev->hdr.h_next = h->hdr.h_next; - } else { - /* Head of list. */ - *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); - } - - /* There's no resize check on a string free. The next string - * intern will do one. - */ -} -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* Unlink with a 'prev' pointer. */ -DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) { -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *slot; -#else - duk_hstring **slot; -#endif - - DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx", - (void *) heap, (void *) prev, (void *) h, - (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), - (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - DUK_ASSERT(prev == NULL || prev->hdr.h_next == h); - -#if defined(DUK__STRTAB_RESIZE_CHECK) - DUK_ASSERT(heap->st_count > 0); - heap->st_count--; -#endif - - if (prev != NULL) { - /* Middle of list. */ - prev->hdr.h_next = h->hdr.h_next; - } else { - /* Head of list. */ -#if defined(DUK_USE_STRTAB_PTRCOMP) - slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); -#else - slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); -#endif - DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h); - *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); - } -} - -/* - * Force string table resize check in mark-and-sweep. - */ - -DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) { - /* Does only one grow/shrink step if needed. The heap->st_resizing - * flag protects against recursive resizing. - */ - - DUK_ASSERT(heap != NULL); - DUK_UNREF(heap); - -#if defined(DUK__STRTAB_RESIZE_CHECK) -#if defined(DUK_USE_STRTAB_PTRCOMP) - if (heap->strtable16 != NULL) { -#else - if (heap->strtable != NULL) { -#endif - duk__strtable_resize_check(heap); - } -#endif -} - -/* - * Free strings in the string table and the string table itself. - */ - -DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) { -#if defined(DUK_USE_STRTAB_PTRCOMP) - duk_uint16_t *strtable; - duk_uint16_t *st; -#else - duk_hstring **strtable; - duk_hstring **st; -#endif - duk_hstring *h; - - DUK_ASSERT(heap != NULL); - -#if defined(DUK_USE_ASSERTIONS) - duk__strtable_assert_checks(heap); -#endif - - /* Strtable can be NULL if heap init fails. However, in that case - * heap->st_size is 0, so strtable == strtable_end and we skip the - * loop without a special check. - */ - strtable = DUK__GET_STRTABLE(heap); - st = strtable + heap->st_size; - DUK_ASSERT(strtable != NULL || heap->st_size == 0); - - while (strtable != st) { - --st; - h = DUK__HEAPPTR_DEC16(heap, *st); - while (h) { - duk_hstring *h_next; - h_next = h->hdr.h_next; - - /* Strings may have inner refs (extdata) in some cases. */ - duk_free_hstring(heap, h); - - h = h_next; - } - } - - DUK_FREE(heap, strtable); -} - -/* automatic undefs */ -#undef DUK__GET_STRTABLE -#undef DUK__HEAPPTR_DEC16 -#undef DUK__HEAPPTR_ENC16 -#undef DUK__STRTAB_U32_MAX_STRLEN -#line 1 "duk_hobject_alloc.c" -/* - * Hobject allocation. - * - * Provides primitive allocation functions for all object types (plain object, - * compiled function, native function, thread). The object return is not yet - * in "heap allocated" list and has a refcount of zero, so caller must careful. - */ - -/* XXX: In most cases there's no need for plain allocation without pushing - * to the value stack. Maybe rework contract? - */ - -/* #include duk_internal.h -> already included */ - -/* - * Helpers. - */ - -DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_uint_t hobject_flags, duk_hobject *obj) { - DUK_ASSERT(obj != NULL); - /* Zeroed by caller. */ - - obj->hdr.h_flags = hobject_flags | DUK_HTYPE_OBJECT; - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(&obj->hdr) == DUK_HTYPE_OBJECT); /* Assume zero shift. */ - -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - DUK_HOBJECT_SET_PROTOTYPE(heap, obj, NULL); - DUK_HOBJECT_SET_PROPS(heap, obj, NULL); -#endif -#if defined(DUK_USE_HEAPPTR16) - /* Zero encoded pointer is required to match NULL. */ - DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL); -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL); -#endif -#endif - DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr); - - /* obj->props is intentionally left as NULL, and duk_hobject_props.c must deal - * with this properly. This is intentional: empty objects consume a minimum - * amount of memory. Further, an initial allocation might fail and cause - * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet. - */ -} - -DUK_LOCAL void *duk__hobject_alloc_init(duk_hthread *thr, duk_uint_t hobject_flags, duk_size_t size) { - void *res; - - res = (void *) DUK_ALLOC_CHECKED_ZEROED(thr, size); - DUK_ASSERT(res != NULL); - duk__init_object_parts(thr->heap, hobject_flags, (duk_hobject *) res); - return res; -} - -/* - * Allocate an duk_hobject. - * - * The allocated object has no allocation for properties; the caller may - * want to force a resize if a desired size is known. - * - * The allocated object has zero reference count and is not reachable. - * The caller MUST make the object reachable and increase its reference - * count before invoking any operation that might require memory allocation. - */ - -DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) { - duk_hobject *res; - - DUK_ASSERT(heap != NULL); - - /* different memory layout, alloc size, and init */ - DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0); - DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0); - DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_BOUNDFUNC) == 0); - - res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject)); - if (DUK_UNLIKELY(res == NULL)) { - return NULL; - } - DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); - - duk__init_object_parts(heap, hobject_flags, res); - - DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); - return res; -} - -DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hobject *res; - - res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject)); - return res; -} - -DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hcompfunc *res; - - res = (duk_hcompfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hcompfunc)); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) -#if defined(DUK_USE_HEAPPTR16) - /* NULL pointer is required to encode to zero, so memset is enough. */ -#else - res->data = NULL; - res->funcs = NULL; - res->bytecode = NULL; -#endif - res->lex_env = NULL; - res->var_env = NULL; -#endif - - return res; -} - -DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hnatfunc *res; - - res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc)); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - res->func = NULL; -#endif - - return res; -} - -DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_hboundfunc *res; - - res = (duk_hboundfunc *) DUK_ALLOC(heap, sizeof(duk_hboundfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hboundfunc)); - - duk__init_object_parts(heap, hobject_flags, &res->obj); - - DUK_TVAL_SET_UNDEFINED(&res->target); - DUK_TVAL_SET_UNDEFINED(&res->this_binding); - -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - res->args = NULL; -#endif - - return res; -} - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hbufobj *res; - - res = (duk_hbufobj *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hbufobj)); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - res->buf = NULL; - res->buf_prop = NULL; -#endif - - DUK_ASSERT_HBUFOBJ_VALID(res); - return res; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* Allocate a new thread. - * - * Leaves the built-ins array uninitialized. The caller must either - * initialize a new global context or share existing built-ins from - * another thread. - */ -DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) { - duk_hthread *res; - - res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread)); - if (DUK_UNLIKELY(res == NULL)) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hthread)); - - duk__init_object_parts(heap, hobject_flags, &res->obj); - -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - res->ptr_curr_pc = NULL; - res->heap = NULL; - res->valstack = NULL; - res->valstack_end = NULL; - res->valstack_alloc_end = NULL; - res->valstack_bottom = NULL; - res->valstack_top = NULL; - res->callstack_curr = NULL; - res->resumer = NULL; - res->compile_ctx = NULL, -#if defined(DUK_USE_HEAPPTR16) - res->strs16 = NULL; -#else - res->strs = NULL; -#endif - { - duk_small_uint_t i; - for (i = 0; i < DUK_NUM_BUILTINS; i++) { - res->builtins[i] = NULL; - } - } -#endif - /* When nothing is running, API calls are in non-strict mode. */ - DUK_ASSERT(res->strict == 0); - - res->heap = heap; - - /* XXX: Any reason not to merge duk_hthread_alloc.c here? */ - return res; -} - -DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hthread *res; - - res = duk_hthread_alloc_unchecked(thr->heap, hobject_flags); - if (res == NULL) { - DUK_ERROR_ALLOC_FAILED(thr); - } - return res; -} - -DUK_INTERNAL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_harray *res; - - res = (duk_harray *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_harray)); - - DUK_ASSERT(res->length == 0); - - return res; -} - -DUK_INTERNAL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hdecenv *res; - - res = (duk_hdecenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hdecenv)); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - res->thread = NULL; - res->varmap = NULL; -#endif - - DUK_ASSERT(res->thread == NULL); - DUK_ASSERT(res->varmap == NULL); - DUK_ASSERT(res->regbase_byteoff == 0); - - return res; -} - -DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hobjenv *res; - - res = (duk_hobjenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobjenv)); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - res->target = NULL; -#endif - - DUK_ASSERT(res->target == NULL); - - return res; -} - -DUK_INTERNAL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hproxy *res; - - res = (duk_hproxy *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hproxy)); - - /* Leave ->target and ->handler uninitialized, as caller will always - * explicitly initialize them before any side effects are possible. - */ - - return res; -} -#line 1 "duk_hobject_enum.c" -/* - * Object enumeration support. - * - * Creates an internal enumeration state object to be used e.g. with for-in - * enumeration. The state object contains a snapshot of target object keys - * and internal control state for enumeration. Enumerator flags allow caller - * to e.g. request internal/non-enumerable properties, and to enumerate only - * "own" properties. - * - * Also creates the result value for e.g. Object.keys() based on the same - * internal structure. - * - * This snapshot-based enumeration approach is used to simplify enumeration: - * non-snapshot-based approaches are difficult to reconcile with mutating - * the enumeration target, running multiple long-lived enumerators at the - * same time, garbage collection details, etc. The downside is that the - * enumerator object is memory inefficient especially for iterating arrays. - */ - -/* #include duk_internal.h -> already included */ - -/* XXX: identify enumeration target with an object index (not top of stack) */ - -/* First enumerated key index in enumerator object, must match exactly the - * number of control properties inserted to the enumerator. - */ -#define DUK__ENUM_START_INDEX 2 - -/* Current implementation suffices for ES2015 for now because there's no symbol - * sorting, so commented out for now. - */ - -/* - * Helper to sort enumeration keys using a callback for pairwise duk_hstring - * comparisons. The keys are in the enumeration object entry part, starting - * from DUK__ENUM_START_INDEX, and the entry part is dense. Entry part values - * are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true, "2" -> true, - * so it suffices to just switch keys without switching values. - * - * ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects: - * (1) array indices in ascending order, - * (2) non-array-index keys in insertion order, and - * (3) symbols in insertion order. - * http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys. - * - * This rule is applied to "own properties" at each inheritance level; - * non-duplicate parent keys always follow child keys. For example, - * an inherited array index will enumerate -after- a symbol in the - * child. - * - * Insertion sort is used because (1) it's simple and compact, (2) works - * in-place, (3) minimizes operations if data is already nearly sorted, - * (4) doesn't reorder elements considered equal. - * http://en.wikipedia.org/wiki/Insertion_sort - */ - -/* Sort key, must hold array indices, "not array index" marker, and one more - * higher value for symbols. - */ -#if !defined(DUK_USE_SYMBOL_BUILTIN) -typedef duk_uint32_t duk__sort_key_t; -#elif defined(DUK_USE_64BIT_OPS) -typedef duk_uint64_t duk__sort_key_t; -#else -typedef duk_double_t duk__sort_key_t; -#endif - -/* Get sort key for a duk_hstring. */ -DUK_LOCAL duk__sort_key_t duk__hstring_sort_key(duk_hstring *x) { - duk__sort_key_t val; - - /* For array indices [0,0xfffffffe] use the array index as is. - * For strings, use 0xffffffff, the marker 'arridx' already in - * duk_hstring. For symbols, any value above 0xffffffff works, - * as long as it is the same for all symbols; currently just add - * the masked flag field into the arridx temporary. - */ - DUK_ASSERT(x != NULL); - DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(x) || DUK_HSTRING_GET_ARRIDX_FAST(x) == DUK_HSTRING_NO_ARRAY_INDEX); - - val = (duk__sort_key_t) DUK_HSTRING_GET_ARRIDX_FAST(x); - -#if defined(DUK_USE_SYMBOL_BUILTIN) - val = val + (duk__sort_key_t) (DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) x) & DUK_HSTRING_FLAG_SYMBOL); -#endif - - return (duk__sort_key_t) val; -} - -/* Insert element 'b' after element 'a'? */ -DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk__sort_key_t val_b) { - duk__sort_key_t val_a; - - DUK_ASSERT(a != NULL); - DUK_ASSERT(b != NULL); - DUK_UNREF(b); /* Not actually needed now, val_b suffices. */ - - val_a = duk__hstring_sort_key(a); - - if (val_a > val_b) { - return 0; - } else { - return 1; - } -} - -DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk_int_fast32_t idx_start, duk_int_fast32_t idx_end) { - duk_hstring **keys; - duk_int_fast32_t idx; - - DUK_ASSERT(h_obj != NULL); - DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX); - DUK_ASSERT(idx_end >= idx_start); - DUK_UNREF(thr); - - if (idx_end <= idx_start + 1) { - return; /* Zero or one element(s). */ - } - - keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj); - - for (idx = idx_start + 1; idx < idx_end; idx++) { - duk_hstring *h_curr; - duk_int_fast32_t idx_insert; - duk__sort_key_t val_curr; - - h_curr = keys[idx]; - DUK_ASSERT(h_curr != NULL); - - /* Scan backwards for insertion place. This works very well - * when the elements are nearly in order which is the common - * (and optimized for) case. - */ - - val_curr = duk__hstring_sort_key(h_curr); /* Remains same during scanning. */ - for (idx_insert = idx - 1; idx_insert >= idx_start; idx_insert--) { - duk_hstring *h_insert; - h_insert = keys[idx_insert]; - DUK_ASSERT(h_insert != NULL); - - if (duk__sort_compare_es6(h_insert, h_curr, val_curr)) { - break; - } - } - /* If we're out of indices, idx_insert == idx_start - 1 and idx_insert++ - * brings us back to idx_start. - */ - idx_insert++; - DUK_ASSERT(idx_insert >= 0 && idx_insert <= idx); - - /* .-- p_insert .-- p_curr - * v v - * | ... | insert | ... | curr - */ - - /* This could also done when the keys are in order, i.e. - * idx_insert == idx. The result would be an unnecessary - * memmove() but we use an explicit check because the keys - * are very often in order already. - */ - if (idx != idx_insert) { - DUK_MEMMOVE((void *) (keys + idx_insert + 1), - (const void *) (keys + idx_insert), - ((size_t) (idx - idx_insert) * sizeof(duk_hstring *))); - keys[idx_insert] = h_curr; - } - } -} - -/* - * Create an internal enumerator object E, which has its keys ordered - * to match desired enumeration ordering. Also initialize internal control - * properties for enumeration. - * - * Note: if an array was used to hold enumeration keys instead, an array - * scan would be needed to eliminate duplicates found in the prototype chain. - */ - -DUK_LOCAL void duk__add_enum_key(duk_hthread *thr, duk_hstring *k) { - /* 'k' may be unreachable on entry so must push without any - * potential for GC. - */ - duk_push_hstring(thr, k); - duk_push_true(thr); - duk_put_prop(thr, -3); -} - -DUK_LOCAL void duk__add_enum_key_stridx(duk_hthread *thr, duk_small_uint_t stridx) { - duk__add_enum_key(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); -} - -DUK_INTERNAL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags) { - duk_hobject *enum_target; - duk_hobject *curr; - duk_hobject *res; -#if defined(DUK_USE_ES6_PROXY) - duk_hobject *h_proxy_target; - duk_hobject *h_proxy_handler; - duk_hobject *h_trap_result; -#endif - duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */ - duk_uint_fast32_t sort_start_index; - - DUK_ASSERT(thr != NULL); - - enum_target = duk_require_hobject(thr, -1); - DUK_ASSERT(enum_target != NULL); - - duk_push_bare_object(thr); - res = duk_known_hobject(thr, -1); - - /* [enum_target res] */ - - /* Target must be stored so that we can recheck whether or not - * keys still exist when we enumerate. This is not done if the - * enumeration result comes from a proxy trap as there is no - * real object to check against. - */ - duk_push_hobject(thr, enum_target); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_TARGET); - - /* Initialize index so that we skip internal control keys. */ - duk_push_int(thr, DUK__ENUM_START_INDEX); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT); - - /* - * Proxy object handling - */ - -#if defined(DUK_USE_ES6_PROXY) - if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) { - goto skip_proxy; - } - if (DUK_LIKELY(!duk_hobject_proxy_check(enum_target, - &h_proxy_target, - &h_proxy_handler))) { - goto skip_proxy; - } - - /* XXX: share code with Object.keys() Proxy handling */ - - /* In ES2015 for-in invoked the "enumerate" trap; in ES2016 "enumerate" - * has been obsoleted and "ownKeys" is used instead. - */ - DUK_DDD(DUK_DDDPRINT("proxy enumeration")); - duk_push_hobject(thr, h_proxy_handler); - if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) { - /* No need to replace the 'enum_target' value in stack, only the - * enum_target reference. This also ensures that the original - * enum target is reachable, which keeps the proxy and the proxy - * target reachable. We do need to replace the internal _Target. - */ - DUK_DDD(DUK_DDDPRINT("no ownKeys trap, enumerate proxy target instead")); - DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target)); - enum_target = h_proxy_target; - - duk_push_hobject(thr, enum_target); /* -> [ ... enum_target res handler undefined target ] */ - duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_INT_TARGET); - - duk_pop_2(thr); /* -> [ ... enum_target res ] */ - goto skip_proxy; - } - - /* [ ... enum_target res handler trap ] */ - duk_insert(thr, -2); - duk_push_hobject(thr, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */ - duk_call_method(thr, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */ - h_trap_result = duk_require_hobject(thr, -1); - DUK_UNREF(h_trap_result); - - duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags); - /* -> [ ... enum_target res trap_result keys_array ] */ - - /* Copy cleaned up trap result keys into the enumerator object. */ - /* XXX: result is a dense array; could make use of that. */ - DUK_ASSERT(duk_is_array(thr, -1)); - len = (duk_uint_fast32_t) duk_get_length(thr, -1); - for (i = 0; i < len; i++) { - (void) duk_get_prop_index(thr, -1, (duk_uarridx_t) i); - DUK_ASSERT(duk_is_string(thr, -1)); /* postprocess cleaned up */ - /* [ ... enum_target res trap_result keys_array val ] */ - duk_push_true(thr); - /* [ ... enum_target res trap_result keys_array val true ] */ - duk_put_prop(thr, -5); - } - /* [ ... enum_target res trap_result keys_array ] */ - duk_pop_2(thr); - duk_remove_m2(thr); - - /* [ ... res ] */ - - /* The internal _Target property is kept pointing to the original - * enumeration target (the proxy object), so that the enumerator - * 'next' operation can read property values if so requested. The - * fact that the _Target is a proxy disables key existence check - * during enumeration. - */ - DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O", (duk_heaphdr *) res)); - goto compact_and_return; - - skip_proxy: -#endif /* DUK_USE_ES6_PROXY */ - - curr = enum_target; - sort_start_index = DUK__ENUM_START_INDEX; - DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(res) == DUK__ENUM_START_INDEX); - while (curr) { - duk_uint_fast32_t sort_end_index; -#if !defined(DUK_USE_PREFER_SIZE) - duk_bool_t need_sort = 0; -#endif - - /* Enumeration proceeds by inheritance level. Virtual - * properties need to be handled specially, followed by - * array part, and finally entry part. - * - * If there are array index keys in the entry part or any - * other risk of the ES2015 [[OwnPropertyKeys]] order being - * violated, need_sort is set and an explicit ES2015 sort is - * done for the inheritance level. - */ - - /* XXX: inheriting from proxy */ - - /* - * Virtual properties. - * - * String and buffer indices are virtual and always enumerable, - * 'length' is virtual and non-enumerable. Array and arguments - * object props have special behavior but are concrete. - * - * String and buffer objects don't have an array part so as long - * as virtual array index keys are enumerated first, we don't - * need to set need_sort. - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) || DUK_HOBJECT_IS_BUFOBJ(curr)) { -#else - if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) { -#endif - duk_bool_t have_length = 1; - - /* String and buffer enumeration behavior is identical now, - * so use shared handler. - */ - if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) { - duk_hstring *h_val; - h_val = duk_hobject_get_internal_value_string(thr->heap, curr); - DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */ - len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val); - } -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - else { - duk_hbufobj *h_bufobj; - DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(curr)); - h_bufobj = (duk_hbufobj *) curr; - - if (h_bufobj == NULL || !h_bufobj->is_typedarray) { - /* Zero length seems like a good behavior for neutered buffers. - * ArrayBuffer (non-view) and DataView don't have index properties - * or .length property. - */ - len = 0; - have_length = 0; - } else { - /* There's intentionally no check for - * current underlying buffer length. - */ - len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift); - } - } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - - for (i = 0; i < len; i++) { - duk_hstring *k; - - /* This is a bit fragile: the string is not - * reachable until it is pushed by the helper. - */ - k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i); - DUK_ASSERT(k); - - duk__add_enum_key(thr, k); - - /* [enum_target res] */ - } - - /* 'length' and other virtual properties are not - * enumerable, but are included if non-enumerable - * properties are requested. - */ - - if (have_length && (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) { - duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH); - } - } - - /* - * Array part - */ - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) { - duk_hstring *k; - duk_tval *tv; - - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i); - if (DUK_TVAL_IS_UNUSED(tv)) { - continue; - } - k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i); /* Fragile reachability. */ - DUK_ASSERT(k); - - duk__add_enum_key(thr, k); - - /* [enum_target res] */ - } - - if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(curr)) { - /* Array .length comes after numeric indices. */ - if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) { - duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH); - } - } - - /* - * Entries part - */ - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) { - duk_hstring *k; - - k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i); - if (!k) { - continue; - } - if (!(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) && - !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) { - continue; - } - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { - if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) && - DUK_HSTRING_HAS_HIDDEN(k)) { - continue; - } - if (!(enum_flags & DUK_ENUM_INCLUDE_SYMBOLS)) { - continue; - } -#if !defined(DUK_USE_PREFER_SIZE) - need_sort = 1; -#endif - } else { - DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(k)); /* would also have symbol flag */ - if (enum_flags & DUK_ENUM_EXCLUDE_STRINGS) { - continue; - } - } - if (DUK_HSTRING_HAS_ARRIDX(k)) { - /* This in currently only possible if the - * object has no array part: the array part - * is exhaustive when it is present. - */ -#if !defined(DUK_USE_PREFER_SIZE) - need_sort = 1; -#endif - } else { - if (enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) { - continue; - } - } - - DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) || - !DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v)); - - duk__add_enum_key(thr, k); - - /* [enum_target res] */ - } - - /* Sort enumerated keys according to ES2015 requirements for - * the "inheritance level" just processed. This is far from - * optimal, ES2015 semantics could be achieved more efficiently - * by handling array index string keys (and symbol keys) - * specially above in effect doing the sort inline. - * - * Skip the sort if array index sorting is requested because - * we must consider all keys, also inherited, so an explicit - * sort is done for the whole result after we're done with the - * prototype chain. - * - * Also skip the sort if need_sort == 0, i.e. we know for - * certain that the enumerated order is already correct. - */ - sort_end_index = DUK_HOBJECT_GET_ENEXT(res); - - if (!(enum_flags & DUK_ENUM_SORT_ARRAY_INDICES)) { -#if defined(DUK_USE_PREFER_SIZE) - duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index); -#else - if (need_sort) { - DUK_DDD(DUK_DDDPRINT("need to sort")); - duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index); - } else { - DUK_DDD(DUK_DDDPRINT("no need to sort")); - } -#endif - } - - sort_start_index = sort_end_index; - - if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) { - break; - } - - curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } - - /* [enum_target res] */ - - duk_remove_m2(thr); - - /* [res] */ - - if (enum_flags & DUK_ENUM_SORT_ARRAY_INDICES) { - /* Some E5/E5.1 algorithms require that array indices are iterated - * in a strictly ascending order. This is the case for e.g. - * Array.prototype.forEach() and JSON.stringify() PropertyList - * handling. The caller can request an explicit sort in these - * cases. - */ - - /* Sort to ES2015 order which works for pure array incides but - * also for mixed keys. - */ - duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) DUK__ENUM_START_INDEX, (duk_int_fast32_t) DUK_HOBJECT_GET_ENEXT(res)); - } - -#if defined(DUK_USE_ES6_PROXY) - compact_and_return: -#endif - /* compact; no need to seal because object is internal */ - duk_hobject_compact_props(thr, res); - - DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(thr, -1))); -} - -/* - * Returns non-zero if a key and/or value was enumerated, and: - * - * [enum] -> [key] (get_value == 0) - * [enum] -> [key value] (get_value == 1) - * - * Returns zero without pushing anything on the stack otherwise. - */ -DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value) { - duk_hobject *e; - duk_hobject *enum_target; - duk_hstring *res = NULL; - duk_uint_fast32_t idx; - duk_bool_t check_existence; - - DUK_ASSERT(thr != NULL); - - /* [... enum] */ - - e = duk_require_hobject(thr, -1); - - /* XXX use get tval ptr, more efficient */ - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_NEXT); - idx = (duk_uint_fast32_t) duk_require_uint(thr, -1); - duk_pop(thr); - DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx)); - - /* Enumeration keys are checked against the enumeration target (to see - * that they still exist). In the proxy enumeration case _Target will - * be the proxy, and checking key existence against the proxy is not - * required (or sensible, as the keys may be fully virtual). - */ - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TARGET); - enum_target = duk_require_hobject(thr, -1); - DUK_ASSERT(enum_target != NULL); -#if defined(DUK_USE_ES6_PROXY) - check_existence = (!DUK_HOBJECT_IS_PROXY(enum_target)); -#else - check_existence = 1; -#endif - duk_pop(thr); /* still reachable */ - - DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT", - (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(thr, -1))); - - /* no array part */ - for (;;) { - duk_hstring *k; - - if (idx >= DUK_HOBJECT_GET_ENEXT(e)) { - DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements")); - break; - } - - /* we know these because enum objects are internally created */ - k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx); - DUK_ASSERT(k != NULL); - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx)); - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v)); - - idx++; - - /* recheck that the property still exists */ - if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) { - DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip")); - continue; - } - - DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O", (duk_heaphdr *) k)); - res = k; - break; - } - - DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx)); - - duk_push_u32(thr, (duk_uint32_t) idx); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT); - - /* [... enum] */ - - if (res) { - duk_push_hstring(thr, res); - if (get_value) { - duk_push_hobject(thr, enum_target); - duk_dup_m2(thr); /* -> [... enum key enum_target key] */ - duk_get_prop(thr, -2); /* -> [... enum key enum_target val] */ - duk_remove_m2(thr); /* -> [... enum key val] */ - duk_remove(thr, -3); /* -> [... key val] */ - } else { - duk_remove_m2(thr); /* -> [... key] */ - } - return 1; - } else { - duk_pop(thr); /* -> [...] */ - return 0; - } -} - -/* - * Get enumerated keys in an Ecmascript array. Matches Object.keys() behavior - * described in E5 Section 15.2.3.14. - */ - -DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags) { - duk_hobject *e; - duk_hstring **keys; - duk_tval *tv; - duk_uint_fast32_t count; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(duk_get_hobject(thr, -1) != NULL); - - /* Create a temporary enumerator to get the (non-duplicated) key list; - * the enumerator state is initialized without being needed, but that - * has little impact. - */ - - duk_hobject_enumerator_create(thr, enum_flags); - e = duk_known_hobject(thr, -1); - - /* [enum_target enum res] */ - - /* Create dense result array to exact size. */ - DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(e) >= DUK__ENUM_START_INDEX); - count = (duk_uint32_t) (DUK_HOBJECT_GET_ENEXT(e) - DUK__ENUM_START_INDEX); - - /* XXX: uninit would be OK */ - tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count); - DUK_ASSERT(count == 0 || tv != NULL); - - /* Fill result array, no side effects. */ - - keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, e); - keys += DUK__ENUM_START_INDEX; - - while (count-- > 0) { - duk_hstring *k; - - k = *keys++; - DUK_ASSERT(k != NULL); /* enumerator must have no keys deleted */ - - DUK_TVAL_SET_STRING(tv, k); - tv++; - DUK_HSTRING_INCREF(thr, k); - } - - /* [enum_target enum res] */ - duk_remove_m2(thr); - - /* [enum_target res] */ - - return 1; /* return 1 to allow callers to tail call */ -} - -/* automatic undefs */ -#undef DUK__ENUM_START_INDEX -#line 1 "duk_hobject_misc.c" -/* - * Misc support functions - */ - -/* #include duk_internal.h -> already included */ - -DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) { - duk_uint_t sanity; - - DUK_ASSERT(thr != NULL); - - /* False if the object is NULL or the prototype 'p' is NULL. - * In particular, false if both are NULL (don't compare equal). - */ - if (h == NULL || p == NULL) { - return 0; - } - - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - do { - if (h == p) { - return 1; - } - - if (sanity-- == 0) { - if (ignore_loop) { - break; - } else { - DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); - } - } - h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - } while (h); - - return 0; -} - -DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) { -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_hobject *tmp; - - DUK_ASSERT(h); - tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p); - DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */ - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); -#else - DUK_ASSERT(h); - DUK_UNREF(thr); - DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p); -#endif -} -#line 1 "duk_hobject_pc2line.c" -/* - * Helpers for creating and querying pc2line debug data, which - * converts a bytecode program counter to a source line number. - * - * The run-time pc2line data is bit-packed, and documented in: - * - * doc/function-objects.rst - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_PC2LINE) - -/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */ -DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) { - duk_hbuffer_dynamic *h_buf; - duk_bitencoder_ctx be_ctx_alloc; - duk_bitencoder_ctx *be_ctx = &be_ctx_alloc; - duk_uint32_t *hdr; - duk_size_t new_size; - duk_uint_fast32_t num_header_entries; - duk_uint_fast32_t curr_offset; - duk_int_fast32_t curr_line, next_line, diff_line; - duk_uint_fast32_t curr_pc; - duk_uint_fast32_t hdr_index; - - DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH); - - num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP; - curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2); - - duk_push_dynamic_buffer(thr, (duk_size_t) curr_offset); - h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1); - DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)); - - hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf); - DUK_ASSERT(hdr != NULL); - hdr[0] = (duk_uint32_t) length; /* valid pc range is [0, length[ */ - - curr_pc = 0U; - while (curr_pc < length) { - new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH); - duk_hbuffer_resize(thr, h_buf, new_size); - - hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf); - DUK_ASSERT(hdr != NULL); - DUK_ASSERT(curr_pc < length); - hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2; - curr_line = (duk_int_fast32_t) instrs[curr_pc].line; - hdr[hdr_index + 0] = (duk_uint32_t) curr_line; - hdr[hdr_index + 1] = (duk_uint32_t) curr_offset; - -#if 0 - DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld", - (long) (curr_pc / DUK_PC2LINE_SKIP), - (long) curr_pc, - (long) hdr[hdr_index + 0], - (long) hdr[hdr_index + 1])); -#endif - - DUK_MEMZERO(be_ctx, sizeof(*be_ctx)); - be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset; - be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH; - - for (;;) { - curr_pc++; - if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) || /* end of diff run */ - (curr_pc >= length) ) { /* end of bytecode */ - break; - } - DUK_ASSERT(curr_pc < length); - next_line = (duk_int32_t) instrs[curr_pc].line; - diff_line = next_line - curr_line; - -#if 0 - DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld", - (long) curr_line, (long) next_line, (long) diff_line)); -#endif - - if (diff_line == 0) { - /* 0 */ - duk_be_encode(be_ctx, 0, 1); - } else if (diff_line >= 1 && diff_line <= 4) { - /* 1 0 <2 bits> */ - duk_be_encode(be_ctx, (duk_uint32_t) ((0x02 << 2) + (diff_line - 1)), 4); - } else if (diff_line >= -0x80 && diff_line <= 0x7f) { - /* 1 1 0 <8 bits> */ - DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff); - duk_be_encode(be_ctx, (duk_uint32_t) ((0x06 << 8) + (diff_line + 0x80)), 11); - } else { - /* 1 1 1 <32 bits> - * Encode in two parts to avoid bitencode 24-bit limitation - */ - duk_be_encode(be_ctx, (duk_uint32_t) ((0x07 << 16) + ((next_line >> 16) & 0xffff)), 19); - duk_be_encode(be_ctx, (duk_uint32_t) (next_line & 0xffff), 16); - } - - curr_line = next_line; - } - - duk_be_finish(be_ctx); - DUK_ASSERT(!be_ctx->truncated); - - /* be_ctx->offset == length of encoded bitstream */ - curr_offset += (duk_uint_fast32_t) be_ctx->offset; - } - - /* compact */ - new_size = (duk_size_t) curr_offset; - duk_hbuffer_resize(thr, h_buf, new_size); - - (void) duk_to_fixed_buffer(thr, -1, NULL); - - DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT", - (long) length, (long) new_size, (double) new_size * 8.0 / (double) length, - (duk_tval *) duk_get_tval(thr, -1))); -} - -/* PC is unsigned. If caller does PC arithmetic and gets a negative result, - * it will map to a large PC which is out of bounds and causes a zero to be - * returned. - */ -DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) { - duk_bitdecoder_ctx bd_ctx_alloc; - duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc; - duk_uint32_t *hdr; - duk_uint_fast32_t start_offset; - duk_uint_fast32_t pc_limit; - duk_uint_fast32_t hdr_index; - duk_uint_fast32_t pc_base; - duk_uint_fast32_t n; - duk_uint_fast32_t curr_line; - - DUK_ASSERT(buf != NULL); - DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf)); - DUK_UNREF(thr); - - /* - * Use the index in the header to find the right starting point - */ - - hdr_index = pc / DUK_PC2LINE_SKIP; - pc_base = hdr_index * DUK_PC2LINE_SKIP; - n = pc - pc_base; - - if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) { - DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header")); - goto pc2line_error; - } - - hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf); - pc_limit = hdr[0]; - if (pc >= pc_limit) { - /* Note: pc is unsigned and cannot be negative */ - DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)", - (long) pc, (long) pc_limit)); - goto pc2line_error; - } - - curr_line = hdr[1 + hdr_index * 2]; - start_offset = hdr[1 + hdr_index * 2 + 1]; - if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) { - DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)", - (long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf))); - goto pc2line_error; - } - - /* - * Iterate the bitstream (line diffs) until PC is reached - */ - - DUK_MEMZERO(bd_ctx, sizeof(*bd_ctx)); - bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset; - bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset); - -#if 0 - DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld", - (long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset)); -#endif - - while (n > 0) { -#if 0 - DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld", (long) n, (long) curr_line)); -#endif - - if (duk_bd_decode_flag(bd_ctx)) { - if (duk_bd_decode_flag(bd_ctx)) { - if (duk_bd_decode_flag(bd_ctx)) { - /* 1 1 1 <32 bits> */ - duk_uint_fast32_t t; - t = duk_bd_decode(bd_ctx, 16); /* workaround: max nbits = 24 now */ - t = (t << 16) + duk_bd_decode(bd_ctx, 16); - curr_line = t; - } else { - /* 1 1 0 <8 bits> */ - duk_uint_fast32_t t; - t = duk_bd_decode(bd_ctx, 8); - curr_line = curr_line + t - 0x80; - } - } else { - /* 1 0 <2 bits> */ - duk_uint_fast32_t t; - t = duk_bd_decode(bd_ctx, 2); - curr_line = curr_line + t + 1; - } - } else { - /* 0: no change */ - } - - n--; - } - - DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line)); - return curr_line; - - pc2line_error: - DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc)); - return 0; -} - -DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc) { - duk_hbuffer_fixed *pc2line; - duk_uint_fast32_t line; - - /* XXX: now that pc2line is used by the debugger quite heavily in - * checked execution, this should be optimized to avoid value stack - * and perhaps also implement some form of pc2line caching (see - * future work in debugger.rst). - */ - - duk_get_prop_stridx(thr, idx_func, DUK_STRIDX_INT_PC2LINE); - pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(thr, -1); - if (pc2line != NULL) { - DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line)); - line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc); - } else { - line = 0; - } - duk_pop(thr); - - return line; -} - -#endif /* DUK_USE_PC2LINE */ -#line 1 "duk_hobject_props.c" -/* - * duk_hobject property access functionality. - * - * This is very central functionality for size, performance, and compliance. - * It is also rather intricate; see hobject-algorithms.rst for discussion on - * the algorithms and memory-management.rst for discussion on refcounts and - * side effect issues. - * - * Notes: - * - * - It might be tempting to assert "refcount nonzero" for objects - * being operated on, but that's not always correct: objects with - * a zero refcount may be operated on by the refcount implementation - * (finalization) for instance. Hence, no refcount assertions are made. - * - * - Many operations (memory allocation, identifier operations, etc) - * may cause arbitrary side effects (e.g. through GC and finalization). - * These side effects may invalidate duk_tval pointers which point to - * areas subject to reallocation (like value stack). Heap objects - * themselves have stable pointers. Holding heap object pointers or - * duk_tval copies is not problematic with respect to side effects; - * care must be taken when holding and using argument duk_tval pointers. - * - * - If a finalizer is executed, it may operate on the the same object - * we're currently dealing with. For instance, the finalizer might - * delete a certain property which has already been looked up and - * confirmed to exist. Ideally finalizers would be disabled if GC - * happens during property access. At the moment property table realloc - * disables finalizers, and all DECREFs may cause arbitrary changes so - * handle DECREF carefully. - * - * - The order of operations for a DECREF matters. When DECREF is executed, - * the entire object graph must be consistent; note that a refzero may - * lead to a mark-and-sweep through a refcount finalizer. Use NORZ macros - * and an explicit DUK_REFZERO_CHECK_xxx() if achieving correct order is hard. - */ - -/* - * XXX: array indices are mostly typed as duk_uint32_t here; duk_uarridx_t - * might be more appropriate. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Local defines - */ - -#define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX - -/* Marker values for hash part. */ -#define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED -#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED - -/* Valstack space that suffices for all local calls, excluding any recursion - * into Ecmascript or Duktape/C calls (Proxy, getters, etc). - */ -#define DUK__VALSTACK_SPACE 10 - -/* Valstack space allocated especially for proxy lookup which does a - * recursive property lookup. - */ -#define DUK__VALSTACK_PROXY_LOOKUP 20 - -/* - * Local prototypes - */ - -DUK_LOCAL_DECL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc); -DUK_LOCAL_DECL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag); -DUK_LOCAL_DECL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc); - -DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr, duk_hobject *obj, duk_uint32_t old_len, duk_uint32_t new_len, duk_bool_t force_flag, duk_uint32_t *out_result_len); -DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj); - -DUK_LOCAL_DECL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags); -DUK_LOCAL_DECL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags); - -/* - * Misc helpers - */ - -/* Convert a duk_tval number (caller checks) to a 32-bit index. Returns - * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array - * index. - */ -/* XXX: for fastints, could use a variant which assumes a double duk_tval - * (and doesn't need to check for fastint again). - */ -DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) { - duk_double_t dbl; - duk_uint32_t idx; - - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - - /* -0 is accepted here as index 0 because ToString(-0) == "0" which is - * in canonical form and thus an array index. - */ - dbl = DUK_TVAL_GET_NUMBER(tv); - idx = (duk_uint32_t) dbl; - if ((duk_double_t) idx == dbl) { - /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF, - * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX. - */ - return idx; - } - return DUK__NO_ARRAY_INDEX; -} - -#if defined(DUK_USE_FASTINT) -/* Convert a duk_tval fastint (caller checks) to a 32-bit index. */ -DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) { - duk_int64_t t; - - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); - - t = DUK_TVAL_GET_FASTINT(tv); - if (((duk_uint64_t) t & ~DUK_U64_CONSTANT(0xffffffff)) != 0) { - /* Catches >0x100000000 and negative values. */ - return DUK__NO_ARRAY_INDEX; - } - - /* If the value happens to be 0xFFFFFFFF, it's not a valid array index - * but will then match DUK__NO_ARRAY_INDEX. - */ - return (duk_uint32_t) t; -} -#endif /* DUK_USE_FASTINT */ - -/* Convert a duk_tval on the value stack (in a trusted index we don't validate) - * to a string or symbol using ES2015 ToPropertyKey(): - * http://www.ecma-international.org/ecma-262/6.0/#sec-topropertykey. - * - * Also check if it's a valid array index and return that (or DUK__NO_ARRAY_INDEX - * if not). - */ -DUK_LOCAL duk_uint32_t duk__to_property_key(duk_hthread *thr, duk_idx_t idx, duk_hstring **out_h) { - duk_uint32_t arr_idx; - duk_hstring *h; - duk_tval *tv_dst; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(out_h != NULL); - DUK_ASSERT(duk_is_valid_index(thr, idx)); - DUK_ASSERT(idx < 0); - - /* XXX: The revised ES2015 ToPropertyKey() handling (ES5.1 was just - * ToString()) involves a ToPrimitive(), a symbol check, and finally - * a ToString(). Figure out the best way to have a good fast path - * but still be compliant and share code. - */ - - tv_dst = DUK_GET_TVAL_NEGIDX(thr, idx); /* intentionally unvalidated */ - if (DUK_TVAL_IS_STRING(tv_dst)) { - /* Most important path: strings and plain symbols are used as - * is. For symbols the array index check below is unnecessary - * (they're never valid array indices) but checking that the - * string is a symbol would make the plain string path slower - * unnecessarily. - */ - h = DUK_TVAL_GET_STRING(tv_dst); - } else { - h = duk_to_property_key_hstring(thr, idx); - } - DUK_ASSERT(h != NULL); - *out_h = h; - - arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h); - return arr_idx; -} - -DUK_LOCAL duk_uint32_t duk__push_tval_to_property_key(duk_hthread *thr, duk_tval *tv_key, duk_hstring **out_h) { - duk_push_tval(thr, tv_key); /* XXX: could use an unsafe push here */ - return duk__to_property_key(thr, -1, out_h); -} - -/* String is an own (virtual) property of a plain buffer. */ -DUK_LOCAL duk_bool_t duk__key_is_plain_buf_ownprop(duk_hthread *thr, duk_hbuffer *buf, duk_hstring *key, duk_uint32_t arr_idx) { - DUK_UNREF(thr); - - /* Virtual index properties. Checking explicitly for - * 'arr_idx != DUK__NO_ARRAY_INDEX' is not necessary - * because DUK__NO_ARRAY_INDEXi is always larger than - * maximum allowed buffer size. - */ - DUK_ASSERT(DUK__NO_ARRAY_INDEX >= DUK_HBUFFER_GET_SIZE(buf)); - if (arr_idx < DUK_HBUFFER_GET_SIZE(buf)) { - return 1; - } - - /* Other virtual properties. */ - return (key == DUK_HTHREAD_STRING_LENGTH(thr)); -} - -/* - * Helpers for managing property storage size - */ - -/* Get default hash part size for a certain entry part size. */ -#if defined(DUK_USE_HOBJECT_HASH_PART) -DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) { - DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - - if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { - duk_uint32_t res; - duk_uint32_t tmp; - - /* Hash size should be 2^N where N is chosen so that 2^N is - * larger than e_size. Extra shifting is used to ensure hash - * is relatively sparse. - */ - tmp = e_size; - res = 2; /* Result will be 2 ** (N + 1). */ - while (tmp >= 0x40) { - tmp >>= 6; - res <<= 6; - } - while (tmp != 0) { - tmp >>= 1; - res <<= 1; - } - DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES); /* Won't wrap, even shifted by 2. */ - DUK_ASSERT(res > e_size); - return res; - } else { - return 0; - } -} -#endif /* USE_PROP_HASH_PART */ - -/* Get minimum entry part growth for a certain size. */ -DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) { - duk_uint32_t res; - - DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - - res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR; - DUK_ASSERT(res >= 1); /* important for callers */ - return res; -} - -/* Get minimum array part growth for a certain size. */ -DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) { - duk_uint32_t res; - - DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES); - - res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR; - DUK_ASSERT(res >= 1); /* important for callers */ - return res; -} - -/* Count actually used entry part entries (non-NULL keys). */ -DUK_LOCAL duk_uint32_t duk__count_used_e_keys(duk_hthread *thr, duk_hobject *obj) { - duk_uint_fast32_t i; - duk_uint_fast32_t n = 0; - duk_hstring **e; - - DUK_ASSERT(obj != NULL); - DUK_UNREF(thr); - - e = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, obj); - for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { - if (*e++) { - n++; - } - } - return (duk_uint32_t) n; -} - -/* Count actually used array part entries and array minimum size. - * NOTE: 'out_min_size' can be computed much faster by starting from the - * end and breaking out early when finding first used entry, but this is - * not needed now. - */ -DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) { - duk_uint_fast32_t i; - duk_uint_fast32_t used = 0; - duk_uint_fast32_t highest_idx = (duk_uint_fast32_t) -1; /* see below */ - duk_tval *a; - - DUK_ASSERT(obj != NULL); - DUK_ASSERT(out_used != NULL); - DUK_ASSERT(out_min_size != NULL); - DUK_UNREF(thr); - - a = DUK_HOBJECT_A_GET_BASE(thr->heap, obj); - for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { - duk_tval *tv = a++; - if (!DUK_TVAL_IS_UNUSED(tv)) { - used++; - highest_idx = i; - } - } - - /* Initial value for highest_idx is -1 coerced to unsigned. This - * is a bit odd, but (highest_idx + 1) will then wrap to 0 below - * for out_min_size as intended. - */ - - *out_used = (duk_uint32_t) used; - *out_min_size = (duk_uint32_t) (highest_idx + 1); /* 0 if no used entries */ -} - -/* Check array density and indicate whether or not the array part should be abandoned. */ -DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) { - /* - * Array abandon check; abandon if: - * - * new_used / new_size < limit - * new_used < limit * new_size || limit is 3 bits fixed point - * new_used < limit' / 8 * new_size || *8 - * 8*new_used < limit' * new_size || :8 - * new_used < limit' * (new_size / 8) - * - * Here, new_used = a_used, new_size = a_size. - * - * Note: some callers use approximate values for a_used and/or a_size - * (e.g. dropping a '+1' term). This doesn't affect the usefulness - * of the check, but may confuse debugging. - */ - - return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3)); -} - -/* Fast check for extending array: check whether or not a slow density check is required. */ -DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) { - /* - * In a fast check we assume old_size equals old_used (i.e., existing - * array is fully dense). - * - * Slow check if: - * - * (new_size - old_size) / old_size > limit - * new_size - old_size > limit * old_size - * new_size > (1 + limit) * old_size || limit' is 3 bits fixed point - * new_size > (1 + (limit' / 8)) * old_size || * 8 - * 8 * new_size > (8 + limit') * old_size || : 8 - * new_size > (8 + limit') * (old_size / 8) - * new_size > limit'' * (old_size / 8) || limit'' = 9 -> max 25% increase - * arr_idx + 1 > limit'' * (old_size / 8) - * - * This check doesn't work well for small values, so old_size is rounded - * up for the check (and the '+ 1' of arr_idx can be ignored in practice): - * - * arr_idx > limit'' * ((old_size + 7) / 8) - */ - - return (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); -} - -/* - * Proxy helpers - */ - -#if defined(DUK_USE_ES6_PROXY) -DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) { - duk_hproxy *h_proxy; - - DUK_ASSERT(obj != NULL); - DUK_ASSERT(out_target != NULL); - DUK_ASSERT(out_handler != NULL); - - /* Caller doesn't need to check exotic proxy behavior (but does so for - * some fast paths). - */ - if (DUK_LIKELY(!DUK_HOBJECT_IS_PROXY(obj))) { - return 0; - } - h_proxy = (duk_hproxy *) obj; - DUK_ASSERT_HPROXY_VALID(h_proxy); - - DUK_ASSERT(h_proxy->handler != NULL); - DUK_ASSERT(h_proxy->target != NULL); - *out_handler = h_proxy->handler; - *out_target = h_proxy->target; - - return 1; -} -#endif /* DUK_USE_ES6_PROXY */ - -/* Get Proxy target object. If the argument is not a Proxy, return it as is. - * If a Proxy is revoked, an error is thrown. - */ -#if defined(DUK_USE_ES6_PROXY) -DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj) { - DUK_ASSERT(obj != NULL); - - /* Resolve Proxy targets until Proxy chain ends. No explicit check for - * a Proxy loop: user code cannot create such a loop (it would only be - * possible by editing duk_hproxy references directly). - */ - - while (DUK_HOBJECT_IS_PROXY(obj)) { - duk_hproxy *h_proxy; - - h_proxy = (duk_hproxy *) obj; - DUK_ASSERT_HPROXY_VALID(h_proxy); - obj = h_proxy->target; - DUK_ASSERT(obj != NULL); - } - - DUK_ASSERT(obj != NULL); - return obj; -} -#endif /* DUK_USE_ES6_PROXY */ - -#if defined(DUK_USE_ES6_PROXY) -DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, duk_small_uint_t stridx_trap, duk_tval *tv_key, duk_hobject **out_target) { - duk_hobject *h_handler; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(tv_key != NULL); - DUK_ASSERT(out_target != NULL); - - if (!duk_hobject_proxy_check(obj, out_target, &h_handler)) { - return 0; - } - DUK_ASSERT(*out_target != NULL); - DUK_ASSERT(h_handler != NULL); - - /* XXX: At the moment Duktape accesses internal keys like _Finalizer using a - * normal property set/get which would allow a proxy handler to interfere with - * such behavior and to get access to internal key strings. This is not a problem - * as such because internal key strings can be created in other ways too (e.g. - * through buffers). The best fix is to change Duktape internal lookups to - * skip proxy behavior. Until that, internal property accesses bypass the - * proxy and are applied to the target (as if the handler did not exist). - * This has some side effects, see test-bi-proxy-internal-keys.js. - */ - - if (DUK_TVAL_IS_STRING(tv_key)) { - duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key); - DUK_ASSERT(h_key != NULL); - if (DUK_HSTRING_HAS_HIDDEN(h_key)) { - /* Symbol accesses must go through proxy lookup in ES2015. - * Hidden symbols behave like Duktape 1.x internal keys - * and currently won't. - */ - DUK_DDD(DUK_DDDPRINT("hidden key, skip proxy handler and apply to target")); - return 0; - } - } - - /* The handler is looked up with a normal property lookup; it may be an - * accessor or the handler object itself may be a proxy object. If the - * handler is a proxy, we need to extend the valstack as we make a - * recursive proxy check without a function call in between (in fact - * there is no limit to the potential recursion here). - * - * (For sanity, proxy creation rejects another proxy object as either - * the handler or the target at the moment so recursive proxy cases - * are not realized now.) - */ - - /* XXX: C recursion limit if proxies are allowed as handler/target values */ - - duk_require_stack(thr, DUK__VALSTACK_PROXY_LOOKUP); - duk_push_hobject(thr, h_handler); - if (duk_get_prop_stridx_short(thr, -1, stridx_trap)) { - /* -> [ ... handler trap ] */ - duk_insert(thr, -2); /* -> [ ... trap handler ] */ - - /* stack prepped for func call: [ ... trap handler ] */ - return 1; - } else { - duk_pop_2_unsafe(thr); - return 0; - } -} -#endif /* DUK_USE_ES6_PROXY */ - -/* - * Reallocate property allocation, moving properties to the new allocation. - * - * Includes key compaction, rehashing, and can also optionally abandon - * the array part, 'migrating' array entries into the beginning of the - * new entry part. - * - * There is no support for in-place reallocation or just compacting keys - * without resizing the property allocation. This is intentional to keep - * code size minimal, but would be useful future work. - * - * The implementation is relatively straightforward, except for the array - * abandonment process. Array abandonment requires that new string keys - * are interned, which may trigger GC. All keys interned so far must be - * reachable for GC at all times and correctly refcounted for; valstack is - * used for that now. - * - * Also, a GC triggered during this reallocation process must not interfere - * with the object being resized. This is currently controlled by preventing - * finalizers (as they may affect ANY object) and object compaction in - * mark-and-sweep. It would suffice to protect only this particular object - * from compaction, however. DECREF refzero cascades are side effect free - * and OK. - * - * Note: because we need to potentially resize the valstack (as part - * of abandoning the array part), any tval pointers to the valstack - * will become invalid after this call. - */ - -DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr, - duk_hobject *obj, - duk_uint32_t new_e_size, - duk_uint32_t new_a_size, - duk_uint32_t new_h_size, - duk_bool_t abandon_array) { - duk_small_uint_t prev_ms_base_flags; - duk_uint32_t new_alloc_size; - duk_uint32_t new_e_size_adjusted; - duk_uint8_t *new_p; - duk_hstring **new_e_k; - duk_propvalue *new_e_pv; - duk_uint8_t *new_e_f; - duk_tval *new_a; - duk_uint32_t *new_h; - duk_uint32_t new_e_next; - duk_uint_fast32_t i; - duk_size_t array_copy_size; -#if defined(DUK_USE_ASSERTIONS) - duk_bool_t prev_error_not_allowed; -#endif - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0)); - DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size); /* required to guarantee success of rehashing, - * intentionally use unadjusted new_e_size - */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_STATS_INC(thr->heap, stats_object_realloc_props); - - /* - * Pre resize assertions. - */ - -#if defined(DUK_USE_ASSERTIONS) - /* XXX: pre-checks (such as no duplicate keys) */ -#endif - - /* - * For property layout 1, tweak e_size to ensure that the whole entry - * part (key + val + flags) is a suitable multiple for alignment - * (platform specific). - * - * Property layout 2 does not require this tweaking and is preferred - * on low RAM platforms requiring alignment. - */ - -#if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3) - DUK_DDD(DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %ld", (long) new_e_size)); - new_e_size_adjusted = new_e_size; -#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1) - DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size)); - new_e_size_adjusted = new_e_size; -#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8)) - new_e_size_adjusted = (new_e_size + (duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U) & - (~((duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U)); - DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld", - (long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted)); - DUK_ASSERT(new_e_size_adjusted >= new_e_size); -#else -#error invalid hobject layout defines -#endif - - /* - * Debug logging after adjustment. - */ - - DUK_DDD(DUK_DDDPRINT("attempt to resize hobject %p props (%ld -> %ld bytes), from {p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld} to " - "{e_size=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld", - (void *) obj, - (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), - DUK_HOBJECT_GET_ASIZE(obj), - DUK_HOBJECT_GET_HSIZE(obj)), - (long) DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size), - (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj), - (long) DUK_HOBJECT_GET_ESIZE(obj), - (long) DUK_HOBJECT_GET_ENEXT(obj), - (long) DUK_HOBJECT_GET_ASIZE(obj), - (long) DUK_HOBJECT_GET_HSIZE(obj), - (long) new_e_size_adjusted, - (long) new_a_size, - (long) new_h_size, - (long) abandon_array, - (long) new_e_size)); - - /* - * Property count check. This is the only point where we ensure that - * we don't get more (allocated) property space that we can handle. - * There aren't hard limits as such, but some algorithms may fail - * if we get too close to the 4G property limit. - * - * Since this works based on allocation size (not actually used size), - * the limit is a bit approximate but good enough in practice. - */ - - if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) { - DUK_ERROR_ALLOC_FAILED(thr); - } - - /* - * Compute new alloc size and alloc new area. - * - * The new area is not tracked in the heap at all, so it's critical - * we get to free/keep it in a controlled manner. - */ - -#if defined(DUK_USE_ASSERTIONS) - /* Whole path must be error throw free, but we may be called from - * within error handling so can't assert for error_not_allowed == 0. - */ - prev_error_not_allowed = thr->heap->error_not_allowed; - thr->heap->error_not_allowed = 1; -#endif - prev_ms_base_flags = thr->heap->ms_base_flags; - thr->heap->ms_base_flags |= - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact the current object (all objects really). */ - thr->heap->pf_prevent_count++; /* Avoid finalizers. */ - DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ - - new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size); - DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size)); - if (new_alloc_size == 0) { - DUK_ASSERT(new_e_size_adjusted == 0); - DUK_ASSERT(new_a_size == 0); - DUK_ASSERT(new_h_size == 0); - new_p = NULL; - } else { - /* Alloc may trigger mark-and-sweep but no compaction, and - * cannot throw. - */ -#if 0 /* XXX: inject test */ - if (1) { - new_p = NULL; - goto alloc_failed; - } -#endif - new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size); - if (new_p == NULL) { - /* NULL always indicates alloc failure because - * new_alloc_size > 0. - */ - goto alloc_failed; - } - } - - /* Set up pointers to the new property area: this is hidden behind a macro - * because it is memory layout specific. - */ - DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h, - new_e_size_adjusted, new_a_size, new_h_size); - DUK_UNREF(new_h); /* happens when hash part dropped */ - new_e_next = 0; - - /* if new_p == NULL, all of these pointers are NULL */ - DUK_ASSERT((new_p != NULL) || - (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL && - new_a == NULL && new_h == NULL)); - - DUK_DDD(DUK_DDDPRINT("new alloc size %ld, new_e_k=%p, new_e_pv=%p, new_e_f=%p, new_a=%p, new_h=%p", - (long) new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f, - (void *) new_a, (void *) new_h)); - - /* - * Migrate array part to start of entries if requested. - * - * Note: from an enumeration perspective the order of entry keys matters. - * Array keys should appear wherever they appeared before the array abandon - * operation. (This no longer matters much because keys are ES2015 sorted.) - */ - - if (abandon_array) { - /* Assuming new_a_size == 0, and that entry part contains - * no conflicting keys, refcounts do not need to be adjusted for - * the values, as they remain exactly the same. - * - * The keys, however, need to be interned, incref'd, and be - * reachable for GC. Any intern attempt may trigger a GC and - * claim any non-reachable strings, so every key must be reachable - * at all times. Refcounts must be correct to satisfy refcount - * assertions. - * - * A longjmp must not occur here, as the new_p allocation would - * leak. Refcounts would come out correctly as the interned - * strings are valstack tracked. - */ - DUK_ASSERT(new_a_size == 0); - - DUK_STATS_INC(thr->heap, stats_object_abandon_array); - - for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { - duk_tval *tv1; - duk_tval *tv2; - duk_hstring *key; - - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - - tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); - if (DUK_TVAL_IS_UNUSED(tv1)) { - continue; - } - - DUK_ASSERT(new_p != NULL && new_e_k != NULL && - new_e_pv != NULL && new_e_f != NULL); - - /* - * Intern key via the valstack to ensure reachability behaves - * properly. We must avoid longjmp's here so use non-checked - * primitives. - * - * Note: duk_check_stack() potentially reallocs the valstack, - * invalidating any duk_tval pointers to valstack. Callers - * must be careful. - */ - -#if 0 /* XXX: inject test */ - if (1) { - goto abandon_error; - } -#endif - /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which - * is generous. - */ - if (!duk_check_stack(thr, 1)) { - goto abandon_error; - } - DUK_ASSERT_VALSTACK_SPACE(thr, 1); - key = duk_heap_strtable_intern_u32(thr->heap, (duk_uint32_t) i); - if (key == NULL) { - goto abandon_error; - } - duk_push_hstring(thr, key); /* keep key reachable for GC etc; guaranteed not to fail */ - - /* Key is now reachable in the valstack, don't INCREF - * the new allocation yet (we'll steal the refcounts - * from the value stack once all keys are done). - */ - - new_e_k[new_e_next] = key; - tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */ - DUK_TVAL_SET_TVAL(tv2, tv1); - new_e_f[new_e_next] = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_ENUMERABLE | - DUK_PROPDESC_FLAG_CONFIGURABLE; - new_e_next++; - - /* Note: new_e_next matches pushed temp key count, and nothing can - * fail above between the push and this point. - */ - } - - /* Steal refcounts from value stack. */ - DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next)); - duk_pop_n_nodecref_unsafe(thr, (duk_idx_t) new_e_next); - } - - /* - * Copy keys and values in the entry part (compacting them at the same time). - */ - - for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { - duk_hstring *key; - - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - - key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); - if (key == NULL) { - continue; - } - - DUK_ASSERT(new_p != NULL && new_e_k != NULL && - new_e_pv != NULL && new_e_f != NULL); - - new_e_k[new_e_next] = key; - new_e_pv[new_e_next] = DUK_HOBJECT_E_GET_VALUE(thr->heap, obj, i); - new_e_f[new_e_next] = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i); - new_e_next++; - } - /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */ - - /* - * Copy array elements to new array part. If the new array part is - * larger, initialize the unused entries as UNUSED because they are - * GC reachable. - */ - -#if defined(DUK_USE_ASSERTIONS) - /* Caller must have decref'd values above new_a_size (if that is necessary). */ - if (!abandon_array) { - for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { - duk_tval *tv; - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); - DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); - } - } -#endif - if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { - array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj); - } else { - array_copy_size = sizeof(duk_tval) * new_a_size; - } - if (array_copy_size > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(new_a != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); - DUK_MEMCPY((void *) new_a, - (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), - array_copy_size); - } - for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { - duk_tval *tv = &new_a[i]; - DUK_TVAL_SET_UNUSED(tv); - } - - /* - * Rebuild the hash part always from scratch (guaranteed to finish - * as long as caller gave consistent parameters). - * - * Any resize of hash part requires rehashing. In addition, by rehashing - * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical - * to ensuring the hash part never fills up. - */ - -#if defined(DUK_USE_HOBJECT_HASH_PART) - if (new_h_size == 0) { - DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); - } else { - duk_uint32_t mask; - - DUK_ASSERT(new_h != NULL); - - /* fill new_h with u32 0xff = UNUSED */ - DUK_ASSERT(new_h_size > 0); - DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size); - - DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */ - - mask = new_h_size - 1; - for (i = 0; i < new_e_next; i++) { - duk_hstring *key = new_e_k[i]; - duk_uint32_t j, step; - - DUK_ASSERT(key != NULL); - j = DUK_HSTRING_GET_HASH(key) & mask; - step = 1; /* Cache friendly but clustering prone. */ - - for (;;) { - DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */ - if (new_h[j] == DUK__HASH_UNUSED) { - DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i)); - new_h[j] = (duk_uint32_t) i; - break; - } - DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step)); - j = (j + step) & mask; - - /* Guaranteed to finish (hash is larger than #props). */ - } - } - } -#endif /* DUK_USE_HOBJECT_HASH_PART */ - - /* - * Nice debug log. - */ - - DUK_DD(DUK_DDPRINT("resized hobject %p props (%ld -> %ld bytes), from {p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld} to " - "{p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld", - (void *) obj, - (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), - DUK_HOBJECT_GET_ASIZE(obj), - DUK_HOBJECT_GET_HSIZE(obj)), - (long) new_alloc_size, - (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj), - (long) DUK_HOBJECT_GET_ESIZE(obj), - (long) DUK_HOBJECT_GET_ENEXT(obj), - (long) DUK_HOBJECT_GET_ASIZE(obj), - (long) DUK_HOBJECT_GET_HSIZE(obj), - (void *) new_p, - (long) new_e_size_adjusted, - (long) new_e_next, - (long) new_a_size, - (long) new_h_size, - (long) abandon_array, - (long) new_e_size)); - - /* - * All done, switch properties ('p') allocation to new one. - */ - - DUK_FREE_CHECKED(thr, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */ - DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p); - DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted); - DUK_HOBJECT_SET_ENEXT(obj, new_e_next); - DUK_HOBJECT_SET_ASIZE(obj, new_a_size); - DUK_HOBJECT_SET_HSIZE(obj, new_h_size); - - /* Clear array part flag only after switching. */ - if (abandon_array) { - DUK_HOBJECT_CLEAR_ARRAY_PART(obj); - } - - DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj)); - - DUK_ASSERT(thr->heap->pf_prevent_count > 0); - thr->heap->pf_prevent_count--; - thr->heap->ms_base_flags = prev_ms_base_flags; -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(thr->heap->error_not_allowed == 1); - thr->heap->error_not_allowed = prev_error_not_allowed; -#endif - - /* - * Post resize assertions. - */ - -#if defined(DUK_USE_ASSERTIONS) - /* XXX: post-checks (such as no duplicate keys) */ -#endif - return; - - /* - * Abandon array failed. We don't need to DECREF anything - * because the references in the new allocation are not - * INCREF'd until abandon is complete. The string interned - * keys are on the value stack and are handled normally by - * unwind. - */ - - abandon_error: - alloc_failed: - DUK_D(DUK_DPRINT("object property table resize failed")); - - DUK_FREE_CHECKED(thr, new_p); /* OK for NULL. */ - - thr->heap->pf_prevent_count--; - thr->heap->ms_base_flags = prev_ms_base_flags; -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(thr->heap->error_not_allowed == 1); - thr->heap->error_not_allowed = prev_error_not_allowed; -#endif - - DUK_ERROR_ALLOC_FAILED(thr); -} - -/* - * Helpers to resize properties allocation on specific needs. - */ - -DUK_INTERNAL void duk_hobject_resize_entrypart(duk_hthread *thr, - duk_hobject *obj, - duk_uint32_t new_e_size) { - duk_uint32_t old_e_size; - duk_uint32_t new_a_size; - duk_uint32_t new_h_size; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - - old_e_size = DUK_HOBJECT_GET_ESIZE(obj); - if (old_e_size > new_e_size) { - new_e_size = old_e_size; - } -#if defined(DUK_USE_HOBJECT_HASH_PART) - new_h_size = duk__get_default_h_size(new_e_size); -#else - new_h_size = 0; -#endif - new_a_size = DUK_HOBJECT_GET_ASIZE(obj); - - duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0); -} - -#if 0 /*unused */ -DUK_INTERNAL void duk_hobject_resize_arraypart(duk_hthread *thr, - duk_hobject *obj, - duk_uint32_t new_a_size) { - duk_uint32_t old_a_size; - duk_uint32_t new_e_size; - duk_uint32_t new_h_size; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - - if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) { - return; - } - old_a_size = DUK_HOBJECT_GET_ASIZE(obj); - if (old_a_size > new_a_size) { - new_a_size = old_a_size; - } - new_e_size = DUK_HOBJECT_GET_ESIZE(obj); - new_h_size = DUK_HOBJECT_GET_HSIZE(obj); - - duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0); -} -#endif - -/* Grow entry part allocation for one additional entry. */ -DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) { - duk_uint32_t old_e_used; /* actually used, non-NULL entries */ - duk_uint32_t new_e_size; - duk_uint32_t new_a_size; - duk_uint32_t new_h_size; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - - /* Duktape 0.11.0 and prior tried to optimize the resize by not - * counting the number of actually used keys prior to the resize. - * This worked mostly well but also caused weird leak-like behavior - * as in: test-bug-object-prop-alloc-unbounded.js. So, now we count - * the keys explicitly to compute the new entry part size. - */ - - old_e_used = duk__count_used_e_keys(thr, obj); - new_e_size = old_e_used + duk__get_min_grow_e(old_e_used); -#if defined(DUK_USE_HOBJECT_HASH_PART) - new_h_size = duk__get_default_h_size(new_e_size); -#else - new_h_size = 0; -#endif - new_a_size = DUK_HOBJECT_GET_ASIZE(obj); - DUK_ASSERT(new_e_size >= old_e_used + 1); /* duk__get_min_grow_e() is always >= 1 */ - - duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0); -} - -/* Grow array part for a new highest array index. */ -DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) { - duk_uint32_t new_e_size; - duk_uint32_t new_a_size; - duk_uint32_t new_h_size; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(highest_arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)); - - /* minimum new length is highest_arr_idx + 1 */ - - new_e_size = DUK_HOBJECT_GET_ESIZE(obj); - new_h_size = DUK_HOBJECT_GET_HSIZE(obj); - new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx); - DUK_ASSERT(new_a_size >= highest_arr_idx + 1); /* duk__get_min_grow_a() is always >= 1 */ - - duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0); -} - -/* Abandon array part, moving array entries into entries part. - * This requires a props resize, which is a heavy operation. - * We also compact the entries part while we're at it, although - * this is not strictly required. - */ -DUK_LOCAL void duk__abandon_array_checked(duk_hthread *thr, duk_hobject *obj) { - duk_uint32_t new_e_size; - duk_uint32_t new_a_size; - duk_uint32_t new_h_size; - duk_uint32_t e_used; /* actually used, non-NULL keys */ - duk_uint32_t a_used; - duk_uint32_t a_size; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - - e_used = duk__count_used_e_keys(thr, obj); - duk__compute_a_stats(thr, obj, &a_used, &a_size); - - /* - * Must guarantee all actually used array entries will fit into - * new entry part. Add one growth step to ensure we don't run out - * of space right away. - */ - - new_e_size = e_used + a_used; - new_e_size = new_e_size + duk__get_min_grow_e(new_e_size); - new_a_size = 0; -#if defined(DUK_USE_HOBJECT_HASH_PART) - new_h_size = duk__get_default_h_size(new_e_size); -#else - new_h_size = 0; -#endif - - DUK_DD(DUK_DDPRINT("abandon array part for hobject %p, " - "array stats before: e_used=%ld, a_used=%ld, a_size=%ld; " - "resize to e_size=%ld, a_size=%ld, h_size=%ld", - (void *) obj, (long) e_used, (long) a_used, (long) a_size, - (long) new_e_size, (long) new_a_size, (long) new_h_size)); - - duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1); -} - -/* - * Compact an object. Minimizes allocation size for objects which are - * not likely to be extended. This is useful for internal and non- - * extensible objects, but can also be called for non-extensible objects. - * May abandon the array part if it is computed to be too sparse. - * - * This call is relatively expensive, as it needs to scan both the - * entries and the array part. - * - * The call may fail due to allocation error. - */ - -DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) { - duk_uint32_t e_size; /* currently used -> new size */ - duk_uint32_t a_size; /* currently required */ - duk_uint32_t a_used; /* actually used */ - duk_uint32_t h_size; - duk_bool_t abandon_array; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - -#if defined(DUK_USE_ROM_OBJECTS) - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { - DUK_DD(DUK_DDPRINT("ignore attempt to compact a rom object")); - return; - } -#endif - - e_size = duk__count_used_e_keys(thr, obj); - duk__compute_a_stats(thr, obj, &a_used, &a_size); - - DUK_DD(DUK_DDPRINT("compacting hobject, used e keys %ld, used a keys %ld, min a size %ld, " - "resized array density would be: %ld/%ld = %lf", - (long) e_size, (long) a_used, (long) a_size, - (long) a_used, (long) a_size, - (double) a_used / (double) a_size)); - - if (duk__abandon_array_density_check(a_used, a_size)) { - DUK_DD(DUK_DDPRINT("decided to abandon array during compaction, a_used=%ld, a_size=%ld", - (long) a_used, (long) a_size)); - abandon_array = 1; - e_size += a_used; - a_size = 0; - } else { - DUK_DD(DUK_DDPRINT("decided to keep array during compaction")); - abandon_array = 0; - } - -#if defined(DUK_USE_HOBJECT_HASH_PART) - if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { - h_size = duk__get_default_h_size(e_size); - } else { - h_size = 0; - } -#else - h_size = 0; -#endif - - DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld", - (long) e_size, (long) a_size, (long) h_size, (long) abandon_array)); - - duk_hobject_realloc_props(thr, obj, e_size, a_size, h_size, abandon_array); -} - -/* - * Find an existing key from entry part either by linear scan or by - * using the hash index (if it exists). - * - * Sets entry index (and possibly the hash index) to output variables, - * which allows the caller to update the entry and hash entries in-place. - * If entry is not found, both values are set to -1. If entry is found - * but there is no hash part, h_idx is set to -1. - */ - -DUK_INTERNAL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) { - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_ASSERT(e_idx != NULL); - DUK_ASSERT(h_idx != NULL); - DUK_UNREF(heap); - - if (DUK_LIKELY(DUK_HOBJECT_GET_HSIZE(obj) == 0)) - { - /* Linear scan: more likely because most objects are small. - * This is an important fast path. - * - * XXX: this might be worth inlining for property lookups. - */ - duk_uint_fast32_t i; - duk_uint_fast32_t n; - duk_hstring **h_keys_base; - DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using linear scan for lookup")); - - h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(heap, obj); - n = DUK_HOBJECT_GET_ENEXT(obj); - for (i = 0; i < n; i++) { - if (h_keys_base[i] == key) { - *e_idx = (duk_int_t) i; - *h_idx = -1; - return 1; - } - } - } -#if defined(DUK_USE_HOBJECT_HASH_PART) - else - { - /* hash lookup */ - duk_uint32_t n; - duk_uint32_t i, step; - duk_uint32_t *h_base; - duk_uint32_t mask; - - DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup")); - - h_base = DUK_HOBJECT_H_GET_BASE(heap, obj); - n = DUK_HOBJECT_GET_HSIZE(obj); - mask = n - 1; - i = DUK_HSTRING_GET_HASH(key) & mask; - step = 1; /* Cache friendly but clustering prone. */ - - for (;;) { - duk_uint32_t t; - - DUK_ASSERT_DISABLE(i >= 0); /* unsigned */ - DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj)); - t = h_base[i]; - DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED || - (t < DUK_HOBJECT_GET_ESIZE(obj))); /* t >= 0 always true, unsigned */ - - if (t == DUK__HASH_UNUSED) { - break; - } else if (t == DUK__HASH_DELETED) { - DUK_DDD(DUK_DDDPRINT("lookup miss (deleted) i=%ld, t=%ld", - (long) i, (long) t)); - } else { - DUK_ASSERT(t < DUK_HOBJECT_GET_ESIZE(obj)); - if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) { - DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p", - (long) i, (long) t, (void *) key)); - *e_idx = (duk_int_t) t; - *h_idx = (duk_int_t) i; - return 1; - } - DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld", - (long) i, (long) t)); - } - i = (i + step) & mask; - - /* Guaranteed to finish (hash is larger than #props). */ - } - } -#endif /* DUK_USE_HOBJECT_HASH_PART */ - - /* Not found, leave e_idx and h_idx unset. */ - return 0; -} - -/* For internal use: get non-accessor entry value */ -DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key) { - duk_int_t e_idx; - duk_int_t h_idx; - - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_UNREF(heap); - - if (duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx)) { - DUK_ASSERT(e_idx >= 0); - if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) { - return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx); - } - } - return NULL; -} - -/* For internal use: get non-accessor entry value and attributes */ -DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs) { - duk_int_t e_idx; - duk_int_t h_idx; - - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_ASSERT(out_attrs != NULL); - DUK_UNREF(heap); - - if (duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx)) { - DUK_ASSERT(e_idx >= 0); - if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) { - *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx); - return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx); - } - } - /* If not found, out_attrs is left unset. */ - return NULL; -} - -/* For internal use: get array part value */ -DUK_INTERNAL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i) { - duk_tval *tv; - - DUK_ASSERT(obj != NULL); - DUK_UNREF(heap); - - if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) { - return NULL; - } - if (i >= DUK_HOBJECT_GET_ASIZE(obj)) { - return NULL; - } - tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, obj, i); - return tv; -} - -/* - * Allocate and initialize a new entry, resizing the properties allocation - * if necessary. Returns entry index (e_idx) or throws an error if alloc fails. - * - * Sets the key of the entry (increasing the key's refcount), and updates - * the hash part if it exists. Caller must set value and flags, and update - * the entry value refcount. A decref for the previous value is not necessary. - */ - -DUK_LOCAL duk_int_t duk__hobject_alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) { - duk_uint32_t idx; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj)); - -#if defined(DUK_USE_ASSERTIONS) - /* key must not already exist in entry part */ - { - duk_uint_fast32_t i; - for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { - DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != key); - } - } -#endif - - if (DUK_HOBJECT_GET_ENEXT(obj) >= DUK_HOBJECT_GET_ESIZE(obj)) { - /* only need to guarantee 1 more slot, but allocation growth is in chunks */ - DUK_DDD(DUK_DDDPRINT("entry part full, allocate space for one more entry")); - duk__grow_props_for_new_entry_item(thr, obj); - } - DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) < DUK_HOBJECT_GET_ESIZE(obj)); - idx = DUK_HOBJECT_POSTINC_ENEXT(obj); - - /* previous value is assumed to be garbage, so don't touch it */ - DUK_HOBJECT_E_SET_KEY(thr->heap, obj, idx, key); - DUK_HSTRING_INCREF(thr, key); - -#if defined(DUK_USE_HOBJECT_HASH_PART) - if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) { - duk_uint32_t n, mask; - duk_uint32_t i, step; - duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj); - - n = DUK_HOBJECT_GET_HSIZE(obj); - mask = n - 1; - i = DUK_HSTRING_GET_HASH(key) & mask; - step = 1; /* Cache friendly but clustering prone. */ - - for (;;) { - duk_uint32_t t = h_base[i]; - if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) { - DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() inserted key into hash part, %ld -> %ld", - (long) i, (long) idx)); - DUK_ASSERT_DISABLE(i >= 0); /* unsigned */ - DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj)); - DUK_ASSERT_DISABLE(idx >= 0); - DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj)); - h_base[i] = idx; - break; - } - DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() miss %ld", (long) i)); - i = (i + step) & mask; - - /* Guaranteed to finish (hash is larger than #props). */ - } - } -#endif /* DUK_USE_HOBJECT_HASH_PART */ - - /* Note: we could return the hash index here too, but it's not - * needed right now. - */ - - DUK_ASSERT_DISABLE(idx >= 0); - DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj)); - DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj)); - return (duk_int_t) idx; -} - -/* - * Object internal value - * - * Returned value is guaranteed to be reachable / incref'd, caller does not need - * to incref OR decref. No proxies or accessors are invoked, no prototype walk. - */ - -DUK_INTERNAL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv_out) { - duk_int_t e_idx; - duk_int_t h_idx; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(tv_out != NULL); - - /* Always in entry part, no need to look up parents etc. */ - if (duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx)) { - DUK_ASSERT(e_idx >= 0); - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)); - DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx)); - return 1; - } - DUK_TVAL_SET_UNDEFINED(tv_out); - return 0; -} - -DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) { - duk_tval tv; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(obj != NULL); - - /* This is not strictly necessary, but avoids compiler warnings; e.g. - * gcc won't reliably detect that no uninitialized data is read below. - */ - DUK_MEMZERO((void *) &tv, sizeof(duk_tval)); - - if (duk_hobject_get_internal_value(heap, obj, &tv)) { - duk_hstring *h; - DUK_ASSERT(DUK_TVAL_IS_STRING(&tv)); - h = DUK_TVAL_GET_STRING(&tv); - /* No explicit check for string vs. symbol, accept both. */ - return h; - } - - return NULL; -} - -/* - * Arguments handling helpers (argument map mainly). - * - * An arguments object has exotic behavior for some numeric indices. - * Accesses may translate to identifier operations which may have - * arbitrary side effects (potentially invalidating any duk_tval - * pointers). - */ - -/* Lookup 'key' from arguments internal 'map', perform a variable lookup - * if mapped, and leave the result on top of stack (and return non-zero). - * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]]. - */ -DUK_LOCAL -duk_bool_t duk__lookup_arguments_map(duk_hthread *thr, - duk_hobject *obj, - duk_hstring *key, - duk_propdesc *temp_desc, - duk_hobject **out_map, - duk_hobject **out_varenv) { - duk_hobject *map; - duk_hobject *varenv; - duk_bool_t rc; - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_DDD(DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p " - "(obj -> %!O, key -> %!O)", - (void *) thr, (void *) obj, (void *) key, (void *) temp_desc, - (duk_heaphdr *) obj, (duk_heaphdr *) key)); - - if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { - DUK_DDD(DUK_DDDPRINT("-> no 'map'")); - return 0; - } - - map = duk_require_hobject(thr, -1); - DUK_ASSERT(map != NULL); - duk_pop_unsafe(thr); /* map is reachable through obj */ - - if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { - DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map")); - return 0; - } - - /* [... varname] */ - DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T", - (duk_tval *) duk_get_tval(thr, -1))); - DUK_ASSERT(duk_is_string(thr, -1)); /* guaranteed when building arguments */ - - /* get varenv for varname (callee's declarative lexical environment) */ - rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE); - DUK_UNREF(rc); - DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */ - varenv = duk_require_hobject(thr, -1); - DUK_ASSERT(varenv != NULL); - duk_pop_unsafe(thr); /* varenv remains reachable through 'obj' */ - - DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv)); - - /* success: leave varname in stack */ - *out_map = map; - *out_varenv = varenv; - return 1; /* [... varname] */ -} - -/* Lookup 'key' from arguments internal 'map', and leave replacement value - * on stack top if mapped (and return non-zero). - * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]). - */ -DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) { - duk_hobject *map; - duk_hobject *varenv; - duk_hstring *varname; - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) { - DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic get behavior")); - return 0; - } - - /* [... varname] */ - - varname = duk_require_hstring(thr, -1); - DUK_ASSERT(varname != NULL); - duk_pop_unsafe(thr); /* varname is still reachable */ - - DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; " - "key=%!O, varname=%!O", - (duk_heaphdr *) key, - (duk_heaphdr *) varname)); - - (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/); - - /* [... value this_binding] */ - - duk_pop_unsafe(thr); - - /* leave result on stack top */ - return 1; -} - -/* Lookup 'key' from arguments internal 'map', perform a variable write if mapped. - * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]). - * Assumes stack top contains 'put' value (which is NOT popped). - */ -DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag) { - duk_hobject *map; - duk_hobject *varenv; - duk_hstring *varname; - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) { - DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic put behavior")); - return; - } - - /* [... put_value varname] */ - - varname = duk_require_hstring(thr, -1); - DUK_ASSERT(varname != NULL); - duk_pop_unsafe(thr); /* varname is still reachable */ - - DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; " - "key=%!O, varname=%!O, value=%!T", - (duk_heaphdr *) key, - (duk_heaphdr *) varname, - (duk_tval *) duk_require_tval(thr, -1))); - - /* [... put_value] */ - - /* - * Note: although arguments object variable mappings are only established - * for non-strict functions (and a call to a non-strict function created - * the arguments object in question), an inner strict function may be doing - * the actual property write. Hence the throw_flag applied here comes from - * the property write call. - */ - - duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, -1), throw_flag); - - /* [... put_value] */ -} - -/* Lookup 'key' from arguments internal 'map', delete mapping if found. - * Used in E5 Section 10.6 algorithm for [[Delete]]. Note that the - * variable/argument itself (where the map points) is not deleted. - */ -DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) { - duk_hobject *map; - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { - DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior")); - return; - } - - map = duk_require_hobject(thr, -1); - DUK_ASSERT(map != NULL); - duk_pop_unsafe(thr); /* map is reachable through obj */ - - DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result", - (duk_heaphdr *) key)); - - /* Note: no recursion issue, we can trust 'map' to behave */ - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(map)); - DUK_DDD(DUK_DDDPRINT("map before deletion: %!O", (duk_heaphdr *) map)); - (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */ - DUK_DDD(DUK_DDDPRINT("map after deletion: %!O", (duk_heaphdr *) map)); -} - -/* - * Ecmascript compliant [[GetOwnProperty]](P), for internal use only. - * - * If property is found: - * - Fills descriptor fields to 'out_desc' - * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the - * property onto the stack ('undefined' for accessor properties). - * - Returns non-zero - * - * If property is not found: - * - 'out_desc' is left in untouched state (possibly garbage) - * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE - * set) - * - Returns zero - * - * Notes: - * - * - Getting a property descriptor may cause an allocation (and hence - * GC) to take place, hence reachability and refcount of all related - * values matter. Reallocation of value stack, properties, etc may - * invalidate many duk_tval pointers (concretely, those which reside - * in memory areas subject to reallocation). However, heap object - * pointers are never affected (heap objects have stable pointers). - * - * - The value of a plain property is always reachable and has a non-zero - * reference count. - * - * - The value of a virtual property is not necessarily reachable from - * elsewhere and may have a refcount of zero. Hence we push it onto - * the valstack for the caller, which ensures it remains reachable - * while it is needed. - * - * - There are no virtual accessor properties. Hence, all getters and - * setters are always related to concretely stored properties, which - * ensures that the get/set functions in the resulting descriptor are - * reachable and have non-zero refcounts. Should there be virtual - * accessor properties later, this would need to change. - */ - -DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags) { - duk_tval *tv; - - DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, " - "arr_idx=%ld (obj -> %!O, key -> %!O)", - (void *) thr, (void *) obj, (void *) key, (void *) out_desc, - (long) flags, (long) arr_idx, - (duk_heaphdr *) obj, (duk_heaphdr *) key)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_ASSERT(out_desc != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_STATS_INC(thr->heap, stats_getownpropdesc_count); - - /* Each code path returning 1 (= found) must fill in all the output - * descriptor fields. We don't do it beforehand because it'd be - * unnecessary work if the property isn't found and would happen - * multiple times for an inheritance chain. - */ - DUK_ASSERT_SET_GARBAGE(out_desc, sizeof(*out_desc)); -#if 0 - out_desc->flags = 0; - out_desc->get = NULL; - out_desc->set = NULL; - out_desc->e_idx = -1; - out_desc->h_idx = -1; - out_desc->a_idx = -1; -#endif - - /* - * Try entries part first because it's the common case. - * - * Array part lookups are usually handled by the array fast path, and - * are not usually inherited. Array and entry parts never contain the - * same keys so the entry part vs. array part order doesn't matter. - */ - - if (duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx)) { - duk_int_t e_idx = out_desc->e_idx; - DUK_ASSERT(out_desc->e_idx >= 0); - out_desc->a_idx = -1; - out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx); - out_desc->get = NULL; - out_desc->set = NULL; - if (DUK_UNLIKELY(out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR)) { - DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part")); - out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx); - out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx); - if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { - /* a dummy undefined value is pushed to make valstack - * behavior uniform for caller - */ - duk_push_undefined(thr); - } - } else { - DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part")); - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx); - if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { - duk_push_tval(thr, tv); - } - } - goto prop_found; - } - - /* - * Try array part. - */ - - if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) { - if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) { - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx); - if (!DUK_TVAL_IS_UNUSED(tv)) { - DUK_DDD(DUK_DDDPRINT("-> found in array part")); - if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { - duk_push_tval(thr, tv); - } - /* implicit attributes */ - out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_CONFIGURABLE | - DUK_PROPDESC_FLAG_ENUMERABLE; - out_desc->get = NULL; - out_desc->set = NULL; - out_desc->e_idx = -1; - out_desc->h_idx = -1; - out_desc->a_idx = (duk_int_t) arr_idx; /* XXX: limit 2G due to being signed */ - goto prop_found; - } - } - } - - DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property")); - - /* - * Not found as a concrete property, check for virtual properties. - */ - - if (!DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(obj)) { - /* Quick skip. */ - goto prop_not_found; - } - - if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { - duk_harray *a; - - DUK_DDD(DUK_DDDPRINT("array object exotic property get for key: %!O, arr_idx: %ld", - (duk_heaphdr *) key, (long) arr_idx)); - - a = (duk_harray *) obj; - DUK_ASSERT_HARRAY_VALID(a); - - if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior")); - - if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { - duk_push_uint(thr, (duk_uint_t) a->length); - } - out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; - if (DUK_HARRAY_LENGTH_WRITABLE(a)) { - out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE; - } - out_desc->get = NULL; - out_desc->set = NULL; - out_desc->e_idx = -1; - out_desc->h_idx = -1; - out_desc->a_idx = -1; - - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); - goto prop_found_noexotic; /* cannot be arguments exotic */ - } - } else if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) { - DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld", - (duk_heaphdr *) key, (long) arr_idx)); - - /* XXX: charlen; avoid multiple lookups? */ - - if (arr_idx != DUK__NO_ARRAY_INDEX) { - duk_hstring *h_val; - - DUK_DDD(DUK_DDDPRINT("array index exists")); - - h_val = duk_hobject_get_internal_value_string(thr->heap, obj); - DUK_ASSERT(h_val); - if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) { - DUK_DDD(DUK_DDDPRINT("-> found, array index inside string")); - if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { - duk_push_hstring(thr, h_val); - duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */ - } - out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */ - DUK_PROPDESC_FLAG_VIRTUAL; - out_desc->get = NULL; - out_desc->set = NULL; - out_desc->e_idx = -1; - out_desc->h_idx = -1; - out_desc->a_idx = -1; - - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); - goto prop_found_noexotic; /* cannot be arguments exotic */ - } else { - /* index is above internal string length -> property is fully normal */ - DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property")); - } - } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - duk_hstring *h_val; - - DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior")); - - h_val = duk_hobject_get_internal_value_string(thr->heap, obj); - DUK_ASSERT(h_val != NULL); - if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { - duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val)); - } - out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */ - out_desc->get = NULL; - out_desc->set = NULL; - out_desc->e_idx = -1; - out_desc->h_idx = -1; - out_desc->a_idx = -1; - - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); - goto prop_found_noexotic; /* cannot be arguments exotic */ - } - } -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - else if (DUK_HOBJECT_IS_BUFOBJ(obj)) { - duk_hbufobj *h_bufobj; - duk_uint_t byte_off; - duk_small_uint_t elem_size; - - h_bufobj = (duk_hbufobj *) obj; - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - DUK_DDD(DUK_DDDPRINT("bufobj property get for key: %!O, arr_idx: %ld", - (duk_heaphdr *) key, (long) arr_idx)); - - if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { - DUK_DDD(DUK_DDDPRINT("array index exists")); - - /* Careful with wrapping: arr_idx upshift may easily wrap, whereas - * length downshift won't. - */ - if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) { - byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */ - elem_size = (duk_small_uint_t) (1U << h_bufobj->shift); - if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { - duk_uint8_t *data; - - if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) { - data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off; - duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size); - } else { - DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)")); - duk_push_uint(thr, 0); - } - } - out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_VIRTUAL; - if (DUK_HOBJECT_GET_CLASS_NUMBER(obj) != DUK_HOBJECT_CLASS_ARRAYBUFFER) { - /* ArrayBuffer indices are non-standard and are - * non-enumerable to avoid their serialization. - */ - out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE; - } - out_desc->get = NULL; - out_desc->set = NULL; - out_desc->e_idx = -1; - out_desc->h_idx = -1; - out_desc->a_idx = -1; - - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); - goto prop_found_noexotic; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */ - } else { - /* index is above internal buffer length -> property is fully normal */ - DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property")); - } - } else if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { - DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior")); - - if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { - /* Length in elements: take into account shift, but - * intentionally don't check the underlying buffer here. - */ - duk_push_uint(thr, h_bufobj->length >> h_bufobj->shift); - } - out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; - out_desc->get = NULL; - out_desc->set = NULL; - out_desc->e_idx = -1; - out_desc->h_idx = -1; - out_desc->a_idx = -1; - - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); - goto prop_found_noexotic; /* cannot be arguments exotic */ - } - } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - - /* Array properties have exotic behavior but they are concrete, - * so no special handling here. - * - * Arguments exotic behavior (E5 Section 10.6, [[GetOwnProperty]] - * is only relevant as a post-check implemented below; hence no - * check here. - */ - - /* - * Not found as concrete or virtual. - */ - - prop_not_found: - DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)")); - DUK_STATS_INC(thr->heap, stats_getownpropdesc_miss); - return 0; - - /* - * Found. - * - * Arguments object has exotic post-processing, see E5 Section 10.6, - * description of [[GetOwnProperty]] variant for arguments. - */ - - prop_found: - DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior")); - - /* Notes: - * - Only numbered indices are relevant, so arr_idx fast reject is good - * (this is valid unless there are more than 4**32-1 arguments). - * - Since variable lookup has no side effects, this can be skipped if - * DUK_GETDESC_FLAG_PUSH_VALUE is not set. - */ - - if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) && - arr_idx != DUK__NO_ARRAY_INDEX && - (flags & DUK_GETDESC_FLAG_PUSH_VALUE))) { - duk_propdesc temp_desc; - - /* Magically bound variable cannot be an accessor. However, - * there may be an accessor property (or a plain property) in - * place with magic behavior removed. This happens e.g. when - * a magic property is redefined with defineProperty(). - * Cannot assert for "not accessor" here. - */ - - /* replaces top of stack with new value if necessary */ - DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0); - - /* This can perform a variable lookup but only into a declarative - * environment which has no side effects. - */ - if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) { - DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - /* [... old_result result] -> [... result] */ - duk_remove_m2(thr); - } - } - - prop_found_noexotic: - DUK_STATS_INC(thr->heap, stats_getownpropdesc_hit); - return 1; -} - -DUK_INTERNAL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_ASSERT(out_desc != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - return duk__get_own_propdesc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, flags); -} - -/* - * Ecmascript compliant [[GetProperty]](P), for internal use only. - * - * If property is found: - * - Fills descriptor fields to 'out_desc' - * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the - * property onto the stack ('undefined' for accessor properties). - * - Returns non-zero - * - * If property is not found: - * - 'out_desc' is left in untouched state (possibly garbage) - * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE - * set) - * - Returns zero - * - * May cause arbitrary side effects and invalidate (most) duk_tval - * pointers. - */ - -DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags) { - duk_hobject *curr; - duk_uint32_t arr_idx; - duk_uint_t sanity; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_ASSERT(out_desc != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_STATS_INC(thr->heap, stats_getpropdesc_count); - - arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key); - - DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, " - "arr_idx=%ld (obj -> %!O, key -> %!O)", - (void *) thr, (void *) obj, (void *) key, (void *) out_desc, - (long) flags, (long) arr_idx, - (duk_heaphdr *) obj, (duk_heaphdr *) key)); - - curr = obj; - DUK_ASSERT(curr != NULL); - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - do { - if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) { - /* stack contains value (if requested), 'out_desc' is set */ - DUK_STATS_INC(thr->heap, stats_getpropdesc_hit); - return 1; - } - - /* not found in 'curr', next in prototype chain; impose max depth */ - if (DUK_UNLIKELY(sanity-- == 0)) { - if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) { - /* treat like property not found */ - break; - } else { - DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); - } - } - curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr != NULL); - - /* out_desc is left untouched (possibly garbage), caller must use return - * value to determine whether out_desc can be looked up - */ - - DUK_STATS_INC(thr->heap, stats_getpropdesc_miss); - return 0; -} - -/* - * Shallow fast path checks for accessing array elements with numeric - * indices. The goal is to try to avoid coercing an array index to an - * (interned) string for the most common lookups, in particular, for - * standard Array objects. - * - * Interning is avoided but only for a very narrow set of cases: - * - Object has array part, index is within array allocation, and - * value is not unused (= key exists) - * - Object has no interfering exotic behavior (e.g. arguments or - * string object exotic behaviors interfere, array exotic - * behavior does not). - * - * Current shortcoming: if key does not exist (even if it is within - * the array allocation range) a slow path lookup with interning is - * always required. This can probably be fixed so that there is a - * quick fast path for non-existent elements as well, at least for - * standard Array objects. - */ - -#if defined(DUK_USE_ARRAY_PROP_FASTPATH) -DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) { - duk_tval *tv; - duk_uint32_t idx; - - DUK_UNREF(thr); - - if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) && - !DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) && - !DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) && - !DUK_HOBJECT_IS_BUFOBJ(obj) && - !DUK_HOBJECT_IS_PROXY(obj))) { - /* Must have array part and no conflicting exotic behaviors. - * Doesn't need to have array special behavior, e.g. Arguments - * object has array part. - */ - return NULL; - } - - /* Arrays never have other exotic behaviors. */ - - DUK_DDD(DUK_DDDPRINT("fast path attempt (no exotic string/arguments/buffer " - "behavior, object has array part)")); - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_key)) { - idx = duk__tval_fastint_to_arr_idx(tv_key); - } else -#endif - if (DUK_TVAL_IS_DOUBLE(tv_key)) { - idx = duk__tval_number_to_arr_idx(tv_key); - } else { - DUK_DDD(DUK_DDDPRINT("key is not a number")); - return NULL; - } - - /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which - * is 0xffffffffUL. We don't need to check for that explicitly - * because 0xffffffffUL will never be inside object 'a_size'. - */ - - if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { - DUK_DDD(DUK_DDDPRINT("key is not an array index or outside array part")); - return NULL; - } - DUK_ASSERT(idx != 0xffffffffUL); - DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX); - - /* XXX: for array instances we could take a shortcut here and assume - * Array.prototype doesn't contain an array index property. - */ - - DUK_DDD(DUK_DDDPRINT("key is a valid array index and inside array part")); - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx); - if (!DUK_TVAL_IS_UNUSED(tv)) { - DUK_DDD(DUK_DDDPRINT("-> fast path successful")); - return tv; - } - - DUK_DDD(DUK_DDDPRINT("fast path attempt failed, fall back to slow path")); - return NULL; -} - -DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) { - duk_tval *tv; - duk_harray *a; - duk_uint32_t idx; - duk_uint32_t old_len, new_len; - - if (!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) && - DUK_HOBJECT_HAS_ARRAY_PART(obj) && - DUK_HOBJECT_HAS_EXTENSIBLE(obj))) { - return 0; - } - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures */ - - a = (duk_harray *) obj; - DUK_ASSERT_HARRAY_VALID(a); - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_key)) { - idx = duk__tval_fastint_to_arr_idx(tv_key); - } else -#endif - if (DUK_TVAL_IS_DOUBLE(tv_key)) { - idx = duk__tval_number_to_arr_idx(tv_key); - } else { - DUK_DDD(DUK_DDDPRINT("key is not a number")); - return 0; - } - - /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which - * is 0xffffffffUL. We don't need to check for that explicitly - * because 0xffffffffUL will never be inside object 'a_size'. - */ - - if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { /* for resizing of array part, use slow path */ - return 0; - } - DUK_ASSERT(idx != 0xffffffffUL); - DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX); - - old_len = a->length; - - if (idx >= old_len) { - DUK_DDD(DUK_DDDPRINT("write new array entry requires length update " - "(arr_idx=%ld, old_len=%ld)", - (long) idx, (long) old_len)); - if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) { - /* The correct behavior here is either a silent error - * or a TypeError, depending on strictness. Fall back - * to the slow path to handle the situation. - */ - return 0; - } - new_len = idx + 1; - - ((duk_harray *) obj)->length = new_len; - } - - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx); - DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */ - - DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld", (long) idx)); - return 1; -} -#endif /* DUK_USE_ARRAY_PROP_FASTPATH */ - -/* - * Fast path for bufobj getprop/putprop - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) { - duk_uint32_t idx; - duk_hbufobj *h_bufobj; - duk_uint_t byte_off; - duk_small_uint_t elem_size; - duk_uint8_t *data; - - if (!DUK_HOBJECT_IS_BUFOBJ(obj)) { - return 0; - } - h_bufobj = (duk_hbufobj *) obj; - if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { - return 0; - } - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_key)) { - idx = duk__tval_fastint_to_arr_idx(tv_key); - } else -#endif - if (DUK_TVAL_IS_DOUBLE(tv_key)) { - idx = duk__tval_number_to_arr_idx(tv_key); - } else { - return 0; - } - - /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which - * is 0xffffffffUL. We don't need to check for that explicitly - * because 0xffffffffUL will never be inside bufobj length. - */ - - /* Careful with wrapping (left shifting idx would be unsafe). */ - if (idx >= (h_bufobj->length >> h_bufobj->shift)) { - return 0; - } - DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX); - - byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */ - elem_size = (duk_small_uint_t) (1U << h_bufobj->shift); - - if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) { - data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off; - duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size); - } else { - DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)")); - duk_push_uint(thr, 0); - } - - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) { - duk_uint32_t idx; - duk_hbufobj *h_bufobj; - duk_uint_t byte_off; - duk_small_uint_t elem_size; - duk_uint8_t *data; - - if (!(DUK_HOBJECT_IS_BUFOBJ(obj) && - DUK_TVAL_IS_NUMBER(tv_val))) { - return 0; - } - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufobjs now */ - - h_bufobj = (duk_hbufobj *) obj; - if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { - return 0; - } - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_key)) { - idx = duk__tval_fastint_to_arr_idx(tv_key); - } else -#endif - if (DUK_TVAL_IS_DOUBLE(tv_key)) { - idx = duk__tval_number_to_arr_idx(tv_key); - } else { - return 0; - } - - /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which - * is 0xffffffffUL. We don't need to check for that explicitly - * because 0xffffffffUL will never be inside bufobj length. - */ - - /* Careful with wrapping (left shifting idx would be unsafe). */ - if (idx >= (h_bufobj->length >> h_bufobj->shift)) { - return 0; - } - DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX); - - byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */ - elem_size = (duk_small_uint_t) (1U << h_bufobj->shift); - - /* Value is required to be a number in the fast path so there - * are no side effects in write coercion. - */ - duk_push_tval(thr, tv_val); - DUK_ASSERT(duk_is_number(thr, -1)); - - if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) { - data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off; - duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size); - } else { - DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)")); - } - - duk_pop_unsafe(thr); - return 1; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * GETPROP: Ecmascript property read. - */ - -DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) { - duk_tval tv_obj_copy; - duk_tval tv_key_copy; - duk_hobject *curr = NULL; - duk_hstring *key = NULL; - duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX; - duk_propdesc desc; - duk_uint_t sanity; - - DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)", - (void *) thr, (void *) tv_obj, (void *) tv_key, - (duk_tval *) tv_obj, (duk_tval *) tv_key)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(tv_obj != NULL); - DUK_ASSERT(tv_key != NULL); - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_STATS_INC(thr->heap, stats_getprop_all); - - /* - * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of - * them being invalidated by a valstack resize. - * - * XXX: this is now an overkill for many fast paths. Rework this - * to be faster (although switching to a valstack discipline might - * be a better solution overall). - */ - - DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj); - DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key); - tv_obj = &tv_obj_copy; - tv_key = &tv_key_copy; - - /* - * Coercion and fast path processing - */ - - switch (DUK_TVAL_GET_TAG(tv_obj)) { - case DUK_TAG_UNDEFINED: - case DUK_TAG_NULL: { - /* Note: unconditional throw */ - DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject")); -#if defined(DUK_USE_PARANOID_ERRORS) - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); -#else - DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s", - duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); -#endif - return 0; - } - - case DUK_TAG_BOOLEAN: { - DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype")); - curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]; - break; - } - - case DUK_TAG_STRING: { - duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); - duk_int_t pop_count; - - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - /* Symbols (ES2015 or hidden) don't have virtual properties. */ - DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype")); - curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; - break; - } - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_key)) { - arr_idx = duk__tval_fastint_to_arr_idx(tv_key); - DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path fastint; arr_idx %ld", (long) arr_idx)); - pop_count = 0; - } else -#endif - if (DUK_TVAL_IS_NUMBER(tv_key)) { - arr_idx = duk__tval_number_to_arr_idx(tv_key); - DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx)); - pop_count = 0; - } else { - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after " - "coercion key is %!T, arr_idx %ld", - (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); - pop_count = 1; - } - - if (arr_idx != DUK__NO_ARRAY_INDEX && - arr_idx < DUK_HSTRING_GET_CHARLEN(h)) { - duk_pop_n_unsafe(thr, pop_count); - duk_push_hstring(thr, h); - duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */ - - DUK_STATS_INC(thr->heap, stats_getprop_stringidx); - DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length " - "after coercion -> return char)", - (duk_tval *) duk_get_tval(thr, -1))); - return 1; - } - - if (pop_count == 0) { - /* This is a pretty awkward control flow, but we need to recheck the - * key coercion here. - */ - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after " - "coercion key is %!T, arr_idx %ld", - (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); - } - - if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - duk_pop_unsafe(thr); /* [key] -> [] */ - duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */ - - DUK_STATS_INC(thr->heap, stats_getprop_stringlen); - DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> " - "return string length)", - (duk_tval *) duk_get_tval(thr, -1))); - return 1; - } - - DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype")); - curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE]; - goto lookup; /* avoid double coercion */ - } - - case DUK_TAG_OBJECT: { -#if defined(DUK_USE_ARRAY_PROP_FASTPATH) - duk_tval *tmp; -#endif - - curr = DUK_TVAL_GET_OBJECT(tv_obj); - DUK_ASSERT(curr != NULL); - - /* XXX: array .length fast path (important in e.g. loops)? */ - -#if defined(DUK_USE_ARRAY_PROP_FASTPATH) - tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key); - if (tmp) { - duk_push_tval(thr, tmp); - - DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part " - "fast path)", - (duk_tval *) duk_get_tval(thr, -1))); - DUK_STATS_INC(thr->heap, stats_getprop_arrayidx); - return 1; - } -#endif - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) { - /* Read value pushed on stack. */ - DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufobj " - "fast path)", - (duk_tval *) duk_get_tval(thr, -1))); - DUK_STATS_INC(thr->heap, stats_getprop_bufobjidx); - return 1; - } -#endif - -#if defined(DUK_USE_ES6_PROXY) - if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(curr))) { - duk_hobject *h_target; - - if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) { - /* -> [ ... trap handler ] */ - DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key)); - DUK_STATS_INC(thr->heap, stats_getprop_proxy); - duk_push_hobject(thr, h_target); /* target */ - duk_push_tval(thr, tv_key); /* P */ - duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */ - duk_call_method(thr, 3 /*nargs*/); - - /* Target object must be checked for a conflicting - * non-configurable property. - */ - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - - if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { - duk_tval *tv_hook = duk_require_tval(thr, -3); /* value from hook */ - duk_tval *tv_targ = duk_require_tval(thr, -1); /* value from target */ - duk_bool_t datadesc_reject; - duk_bool_t accdesc_reject; - - DUK_DDD(DUK_DDDPRINT("proxy 'get': target has matching property %!O, check for " - "conflicting property; tv_hook=%!T, tv_targ=%!T, desc.flags=0x%08lx, " - "desc.get=%p, desc.set=%p", - (duk_heaphdr *) key, (duk_tval *) tv_hook, (duk_tval *) tv_targ, - (unsigned long) desc.flags, - (void *) desc.get, (void *) desc.set)); - - datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) && - !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && - !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) && - !duk_js_samevalue(tv_hook, tv_targ); - accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) && - !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && - (desc.get == NULL) && - !DUK_TVAL_IS_UNDEFINED(tv_hook); - if (datadesc_reject || accdesc_reject) { - DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); - } - - duk_pop_2_unsafe(thr); - } else { - duk_pop_unsafe(thr); - } - return 1; /* return value */ - } - - curr = h_target; /* resume lookup from target */ - DUK_TVAL_SET_OBJECT(tv_obj, curr); - } -#endif /* DUK_USE_ES6_PROXY */ - - if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) { - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - - DUK_STATS_INC(thr->heap, stats_getprop_arguments); - if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) { - DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, " - "key matches magically bound property -> skip standard " - "Get with replacement value)", - (duk_tval *) duk_get_tval(thr, -1))); - - /* no need for 'caller' post-check, because 'key' must be an array index */ - - duk_remove_m2(thr); /* [key result] -> [result] */ - return 1; - } - - goto lookup; /* avoid double coercion */ - } - break; - } - - /* Buffer has virtual properties similar to string, but indexed values - * are numbers, not 1-byte buffers/strings which would perform badly. - */ - case DUK_TAG_BUFFER: { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj); - duk_int_t pop_count; - - /* - * Because buffer values are often looped over, a number fast path - * is important. - */ - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_key)) { - arr_idx = duk__tval_fastint_to_arr_idx(tv_key); - DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx)); - pop_count = 0; - } - else -#endif - if (DUK_TVAL_IS_NUMBER(tv_key)) { - arr_idx = duk__tval_number_to_arr_idx(tv_key); - DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx)); - pop_count = 0; - } else { - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after " - "coercion key is %!T, arr_idx %ld", - (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); - pop_count = 1; - } - - if (arr_idx != DUK__NO_ARRAY_INDEX && - arr_idx < DUK_HBUFFER_GET_SIZE(h)) { - duk_pop_n_unsafe(thr, pop_count); - duk_push_uint(thr, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]); - DUK_STATS_INC(thr->heap, stats_getprop_bufferidx); - DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length " - "after coercion -> return byte as number)", - (duk_tval *) duk_get_tval(thr, -1))); - return 1; - } - - if (pop_count == 0) { - /* This is a pretty awkward control flow, but we need to recheck the - * key coercion here. - */ - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after " - "coercion key is %!T, arr_idx %ld", - (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); - } - - if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - duk_pop_unsafe(thr); /* [key] -> [] */ - duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */ - DUK_STATS_INC(thr->heap, stats_getprop_bufferlen); - - DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' " - "after coercion -> return buffer length)", - (duk_tval *) duk_get_tval(thr, -1))); - return 1; - } - - DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype")); - curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; - goto lookup; /* avoid double coercion */ - } - - case DUK_TAG_POINTER: { - DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype")); - curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE]; - break; - } - - case DUK_TAG_LIGHTFUNC: { - /* Lightfuncs inherit getter .name and .length from %NativeFunctionPrototype%. */ - DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype")); - curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE]; - break; - } - -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: { - /* number */ - DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype")); - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_obj)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj)); - curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]; - break; - } - } - - /* key coercion (unless already coerced above) */ - DUK_ASSERT(key == NULL); - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - /* - * Property lookup - */ - - lookup: - /* [key] (coerced) */ - DUK_ASSERT(curr != NULL); - DUK_ASSERT(key != NULL); - - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - do { - if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { - goto next_in_chain; - } - - if (desc.get != NULL) { - /* accessor with defined getter */ - DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0); - - duk_pop_unsafe(thr); /* [key undefined] -> [key] */ - duk_push_hobject(thr, desc.get); - duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */ -#if defined(DUK_USE_NONSTD_GETTER_KEY_ARGUMENT) - duk_dup_m3(thr); - duk_call_method(thr, 1); /* [key getter this key] -> [key retval] */ -#else - duk_call_method(thr, 0); /* [key getter this] -> [key retval] */ -#endif - } else { - /* [key value] or [key undefined] */ - - /* data property or accessor without getter */ - DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) || - (desc.get == NULL)); - - /* if accessor without getter, return value is undefined */ - DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) || - duk_is_undefined(thr, -1)); - - /* Note: for an accessor without getter, falling through to - * check for "caller" exotic behavior is unnecessary as - * "undefined" will never activate the behavior. But it does - * no harm, so we'll do it anyway. - */ - } - - goto found; /* [key result] */ - - next_in_chain: - /* XXX: option to pretend property doesn't exist if sanity limit is - * hit might be useful. - */ - if (DUK_UNLIKELY(sanity-- == 0)) { - DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); - } - curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr != NULL); - - /* - * Not found - */ - - duk_to_undefined(thr, -1); /* [key] -> [undefined] (default value) */ - - DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(thr, -1))); - return 0; - - /* - * Found; post-processing (Function and arguments objects) - */ - - found: - /* [key result] */ - -#if !defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - /* Special behavior for 'caller' property of (non-bound) function objects - * and non-strict Arguments objects: if 'caller' -value- (!) is a strict - * mode function, throw a TypeError (E5 Sections 15.3.5.4, 10.6). - * Quite interestingly, a non-strict function with no formal arguments - * will get an arguments object -without- special 'caller' behavior! - * - * The E5.1 spec is a bit ambiguous if this special behavior applies when - * a bound function is the base value (not the 'caller' value): Section - * 15.3.4.5 (describing bind()) states that [[Get]] for bound functions - * matches that of Section 15.3.5.4 ([[Get]] for Function instances). - * However, Section 13.3.5.4 has "NOTE: Function objects created using - * Function.prototype.bind use the default [[Get]] internal method." - * The current implementation assumes this means that bound functions - * should not have the special [[Get]] behavior. - * - * The E5.1 spec is also a bit unclear if the TypeError throwing is - * applied if the 'caller' value is a strict bound function. The - * current implementation will throw even for both strict non-bound - * and strict bound functions. - * - * See test-dev-strict-func-as-caller-prop-value.js for quite extensive - * tests. - * - * This exotic behavior is disabled when the non-standard 'caller' property - * is enabled, as it conflicts with the free use of 'caller'. - */ - if (key == DUK_HTHREAD_STRING_CALLER(thr) && - DUK_TVAL_IS_OBJECT(tv_obj)) { - duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj); - DUK_ASSERT(orig != NULL); - - if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) || - DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) { - duk_hobject *h; - - /* XXX: The TypeError is currently not applied to bound - * functions because the 'strict' flag is not copied by - * bind(). This may or may not be correct, the specification - * only refers to the value being a "strict mode Function - * object" which is ambiguous. - */ - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(orig)); - - h = duk_get_hobject(thr, -1); /* NULL if not an object */ - if (h && - DUK_HOBJECT_IS_FUNCTION(h) && - DUK_HOBJECT_HAS_STRICT(h)) { - /* XXX: sufficient to check 'strict', assert for 'is function' */ - DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ); - } - } - } -#endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */ - - duk_remove_m2(thr); /* [key result] -> [result] */ - - DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(thr, -1))); - return 1; -} - -/* - * HASPROP: Ecmascript property existence check ("in" operator). - * - * Interestingly, the 'in' operator does not do any coercion of - * the target object. - */ - -DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) { - duk_tval tv_key_copy; - duk_hobject *obj; - duk_hstring *key; - duk_uint32_t arr_idx; - duk_bool_t rc; - duk_propdesc desc; - - DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)", - (void *) thr, (void *) tv_obj, (void *) tv_key, - (duk_tval *) tv_obj, (duk_tval *) tv_key)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(tv_obj != NULL); - DUK_ASSERT(tv_key != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key); - tv_key = &tv_key_copy; - - /* - * The 'in' operator requires an object as its right hand side, - * throwing a TypeError unconditionally if this is not the case. - * - * However, lightfuncs need to behave like fully fledged objects - * here to be maximally transparent, so we need to handle them - * here. Same goes for plain buffers which behave like ArrayBuffers. - */ - - /* XXX: Refactor key coercion so that it's only called once. It can't - * be trivially lifted here because the object must be type checked - * first. - */ - - if (DUK_TVAL_IS_OBJECT(tv_obj)) { - obj = DUK_TVAL_GET_OBJECT(tv_obj); - DUK_ASSERT(obj != NULL); - - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - } else if (DUK_TVAL_IS_BUFFER(tv_obj)) { - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - if (duk__key_is_plain_buf_ownprop(thr, DUK_TVAL_GET_BUFFER(tv_obj), key, arr_idx)) { - rc = 1; - goto pop_and_return; - } - obj = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; - } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) { - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - - /* If not found, resume existence check from %NativeFunctionPrototype%. - * We can just substitute the value in this case; nothing will - * need the original base value (as would be the case with e.g. - * setters/getters. - */ - obj = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE]; - } else { - /* Note: unconditional throw */ - DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject")); - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); - } - - /* XXX: fast path for arrays? */ - - DUK_ASSERT(key != NULL); - DUK_ASSERT(obj != NULL); - DUK_UNREF(arr_idx); - -#if defined(DUK_USE_ES6_PROXY) - if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) { - duk_hobject *h_target; - duk_bool_t tmp_bool; - - /* XXX: the key in 'key in obj' is string coerced before we're called - * (which is the required behavior in E5/E5.1/E6) so the key is a string - * here already. - */ - - if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) { - /* [ ... key trap handler ] */ - DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key)); - duk_push_hobject(thr, h_target); /* target */ - duk_push_tval(thr, tv_key); /* P */ - duk_call_method(thr, 2 /*nargs*/); - tmp_bool = duk_to_boolean(thr, -1); - if (!tmp_bool) { - /* Target object must be checked for a conflicting - * non-configurable property. - */ - - if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ - DUK_DDD(DUK_DDDPRINT("proxy 'has': target has matching property %!O, check for " - "conflicting property; desc.flags=0x%08lx, " - "desc.get=%p, desc.set=%p", - (duk_heaphdr *) key, (unsigned long) desc.flags, - (void *) desc.get, (void *) desc.set)); - /* XXX: Extensibility check for target uses IsExtensible(). If we - * implemented the isExtensible trap and didn't reject proxies as - * proxy targets, it should be respected here. - */ - if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */ - DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */ - DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); - } - } - } - - duk_pop_2_unsafe(thr); /* [ key trap_result ] -> [] */ - return tmp_bool; - } - - obj = h_target; /* resume check from proxy target */ - } -#endif /* DUK_USE_ES6_PROXY */ - - /* XXX: inline into a prototype walking loop? */ - - rc = duk__get_propdesc(thr, obj, key, &desc, 0 /*flags*/); /* don't push value */ - /* fall through */ - - pop_and_return: - duk_pop_unsafe(thr); /* [ key ] -> [] */ - return rc; -} - -/* - * HASPROP variant used internally. - * - * This primitive must never throw an error, callers rely on this. - * In particular, don't throw an error for prototype loops; instead, - * pretend like the property doesn't exist if a prototype sanity limit - * is reached. - * - * Does not implement proxy behavior: if applied to a proxy object, - * returns key existence on the proxy object itself. - */ - -DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) { - duk_propdesc dummy; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - return duk__get_propdesc(thr, obj, key, &dummy, DUK_GETDESC_FLAG_IGNORE_PROTOLOOP); /* don't push value */ -} - -/* - * Helper: handle Array object 'length' write which automatically - * deletes properties, see E5 Section 15.4.5.1, step 3. This is - * quite tricky to get right. - * - * Used by duk_hobject_putprop(). - */ - -/* Coerce a new .length candidate to a number and check that it's a valid - * .length. - */ -DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tval *tv) { - duk_uint32_t res; - duk_double_t d; - -#if !defined(DUK_USE_PREFER_SIZE) -#if defined(DUK_USE_FASTINT) - /* When fastints are enabled, the most interesting case is assigning - * a fastint to .length (e.g. arr.length = 0). - */ - if (DUK_TVAL_IS_FASTINT(tv)) { - /* Very common case. */ - duk_int64_t fi; - fi = DUK_TVAL_GET_FASTINT(tv); - if (fi < 0 || fi > DUK_I64_CONSTANT(0xffffffff)) { - goto fail_range; - } - return (duk_uint32_t) fi; - } -#else /* DUK_USE_FASTINT */ - /* When fastints are not enabled, the most interesting case is any - * number. - */ - if (DUK_TVAL_IS_DOUBLE(tv)) { - d = DUK_TVAL_GET_NUMBER(tv); - } -#endif /* DUK_USE_FASTINT */ - else -#endif /* !DUK_USE_PREFER_SIZE */ - { - /* In all other cases, and when doing a size optimized build, - * fall back to the comprehensive handler. - */ - d = duk_js_tonumber(thr, tv); - } - - /* Refuse to update an Array's 'length' to a value outside the - * 32-bit range. Negative zero is accepted as zero. - */ - res = (duk_uint32_t) d; - if ((duk_double_t) res != d) { - goto fail_range; - } - - return res; - - fail_range: - DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH); - return 0; /* unreachable */ -} - -/* Delete elements required by a smaller length, taking into account - * potentially non-configurable elements. Returns non-zero if all - * elements could be deleted, and zero if all or some elements could - * not be deleted. Also writes final "target length" to 'out_result_len'. - * This is the length value that should go into the 'length' property - * (must be set by the caller). Never throws an error. - */ -DUK_LOCAL -duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr, - duk_hobject *obj, - duk_uint32_t old_len, - duk_uint32_t new_len, - duk_bool_t force_flag, - duk_uint32_t *out_result_len) { - duk_uint32_t target_len; - duk_uint_fast32_t i; - duk_uint32_t arr_idx; - duk_hstring *key; - duk_tval *tv; - duk_bool_t rc; - - DUK_DDD(DUK_DDDPRINT("new array length smaller than old (%ld -> %ld), " - "probably need to remove elements", - (long) old_len, (long) new_len)); - - /* - * New length is smaller than old length, need to delete properties above - * the new length. - * - * If array part exists, this is straightforward: array entries cannot - * be non-configurable so this is guaranteed to work. - * - * If array part does not exist, array-indexed values are scattered - * in the entry part, and some may not be configurable (preventing length - * from becoming lower than their index + 1). To handle the algorithm - * in E5 Section 15.4.5.1, step l correctly, we scan the entire property - * set twice. - */ - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(new_len < old_len); - DUK_ASSERT(out_result_len != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); - DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj)); - - if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) { - /* - * All defined array-indexed properties are in the array part - * (we assume the array part is comprehensive), and all array - * entries are writable, configurable, and enumerable. Thus, - * nothing can prevent array entries from being deleted. - */ - - DUK_DDD(DUK_DDDPRINT("have array part, easy case")); - - if (old_len < DUK_HOBJECT_GET_ASIZE(obj)) { - /* XXX: assertion that entries >= old_len are already unused */ - i = old_len; - } else { - i = DUK_HOBJECT_GET_ASIZE(obj); - } - DUK_ASSERT(i <= DUK_HOBJECT_GET_ASIZE(obj)); - - while (i > new_len) { - i--; - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); - DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */ - } - - *out_result_len = new_len; - return 1; - } else { - /* - * Entries part is a bit more complex. - */ - - /* Stage 1: find highest preventing non-configurable entry (if any). - * When forcing, ignore non-configurability. - */ - - DUK_DDD(DUK_DDDPRINT("no array part, slow case")); - - DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 1: find target_len " - "(highest preventing non-configurable entry (if any))")); - - target_len = new_len; - if (force_flag) { - DUK_DDD(DUK_DDDPRINT("array length write, no array part; force flag -> skip stage 1")); - goto skip_stage1; - } - for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { - key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); - if (!key) { - DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i)); - continue; - } - if (!DUK_HSTRING_HAS_ARRIDX(key)) { - DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i)); - continue; - } - - DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */ - arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); - DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); - DUK_ASSERT(arr_idx < old_len); /* consistency requires this */ - - if (arr_idx < new_len) { - DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below new_len", - (long) i, (long) arr_idx)); - continue; - } - if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)) { - DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is a relevant array index %ld, but configurable", - (long) i, (long) arr_idx)); - continue; - } - - /* relevant array index is non-configurable, blocks write */ - if (arr_idx >= target_len) { - DUK_DDD(DUK_DDDPRINT("entry at index %ld has arr_idx %ld, is not configurable, " - "update target_len %ld -> %ld", - (long) i, (long) arr_idx, (long) target_len, - (long) (arr_idx + 1))); - target_len = arr_idx + 1; - } - } - skip_stage1: - - /* stage 2: delete configurable entries above target length */ - - DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld, target_len=%ld", - (long) old_len, (long) new_len, (long) target_len)); - - DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 2: remove " - "entries >= target_len")); - - for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { - key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); - if (!key) { - DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i)); - continue; - } - if (!DUK_HSTRING_HAS_ARRIDX(key)) { - DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i)); - continue; - } - - DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */ - arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); - DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); - DUK_ASSERT(arr_idx < old_len); /* consistency requires this */ - - if (arr_idx < target_len) { - DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below target_len", - (long) i, (long) arr_idx)); - continue; - } - DUK_ASSERT(force_flag || DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)); /* stage 1 guarantees */ - - DUK_DDD(DUK_DDDPRINT("delete entry index %ld: key is array index %ld", - (long) i, (long) arr_idx)); - - /* - * Slow delete, but we don't care as we're already in a very slow path. - * The delete always succeeds: key has no exotic behavior, property - * is configurable, and no resize occurs. - */ - rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0); - DUK_UNREF(rc); - DUK_ASSERT(rc != 0); - } - - /* stage 3: update length (done by caller), decide return code */ - - DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)")); - - *out_result_len = target_len; - - if (target_len == new_len) { - DUK_DDD(DUK_DDDPRINT("target_len matches new_len, return success")); - return 1; - } - DUK_DDD(DUK_DDDPRINT("target_len does not match new_len (some entry prevented " - "full length adjustment), return error")); - return 0; - } - - DUK_UNREACHABLE(); -} - -/* XXX: is valstack top best place for argument? */ -DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) { - duk_harray *a; - duk_uint32_t old_len; - duk_uint32_t new_len; - duk_uint32_t result_len; - duk_bool_t rc; - - DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, " - "new val: %!T", - (duk_tval *) duk_get_tval(thr, -1))); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); - DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj)); - a = (duk_harray *) obj; - DUK_ASSERT_HARRAY_VALID(a); - - DUK_ASSERT(duk_is_valid_index(thr, -1)); - - /* - * Get old and new length - */ - - old_len = a->length; - new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1)); - DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len)); - - /* - * Writability check - */ - - if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) { - DUK_DDD(DUK_DDDPRINT("length is not writable, fail")); - return 0; - } - - /* - * New length not lower than old length => no changes needed - * (not even array allocation). - */ - - if (new_len >= old_len) { - DUK_DDD(DUK_DDDPRINT("new length is same or higher than old length, just update length, no deletions")); - a->length = new_len; - return 1; - } - - DUK_DDD(DUK_DDDPRINT("new length is lower than old length, probably must delete entries")); - - /* - * New length lower than old length => delete elements, then - * update length. - * - * Note: even though a bunch of elements have been deleted, the 'desc' is - * still valid as properties haven't been resized (and entries compacted). - */ - - rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len); - DUK_ASSERT(result_len >= new_len && result_len <= old_len); - - a->length = result_len; - - /* XXX: shrink array allocation or entries compaction here? */ - - return rc; -} - -/* - * PUTPROP: Ecmascript property write. - * - * Unlike Ecmascript primitive which returns nothing, returns 1 to indicate - * success and 0 to indicate failure (assuming throw is not set). - * - * This is an extremely tricky function. Some examples: - * - * * Currently a decref may trigger a GC, which may compact an object's - * property allocation. Consequently, any entry indices (e_idx) will - * be potentially invalidated by a decref. - * - * * Exotic behaviors (strings, arrays, arguments object) require, - * among other things: - * - * - Preprocessing before and postprocessing after an actual property - * write. For example, array index write requires pre-checking the - * array 'length' property for access control, and may require an - * array 'length' update after the actual write has succeeded (but - * not if it fails). - * - * - Deletion of multiple entries, as a result of array 'length' write. - * - * * Input values are taken as pointers which may point to the valstack. - * If valstack is resized because of the put (this may happen at least - * when the array part is abandoned), the pointers can be invalidated. - * (We currently make a copy of all of the input values to avoid issues.) - */ - -DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag) { - duk_tval tv_obj_copy; - duk_tval tv_key_copy; - duk_tval tv_val_copy; - duk_hobject *orig = NULL; /* NULL if tv_obj is primitive */ - duk_hobject *curr; - duk_hstring *key = NULL; - duk_propdesc desc; - duk_tval *tv; - duk_uint32_t arr_idx; - duk_bool_t rc; - duk_int_t e_idx; - duk_uint_t sanity; - duk_uint32_t new_array_length = 0; /* 0 = no update */ - - DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld " - "(obj -> %!T, key -> %!T, val -> %!T)", - (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val, - (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(tv_obj != NULL); - DUK_ASSERT(tv_key != NULL); - DUK_ASSERT(tv_val != NULL); - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - DUK_STATS_INC(thr->heap, stats_putprop_all); - - /* - * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of - * them being invalidated by a valstack resize. - * - * XXX: this is an overkill for some paths, so optimize this later - * (or maybe switch to a stack arguments model entirely). - */ - - DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj); - DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key); - DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val); - tv_obj = &tv_obj_copy; - tv_key = &tv_key_copy; - tv_val = &tv_val_copy; - - /* - * Coercion and fast path processing. - */ - - switch (DUK_TVAL_GET_TAG(tv_obj)) { - case DUK_TAG_UNDEFINED: - case DUK_TAG_NULL: { - /* Note: unconditional throw */ - DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)", - (duk_tval *) tv_obj)); -#if defined(DUK_USE_PARANOID_ERRORS) - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); -#else - DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s", - duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); -#endif - return 0; - } - - case DUK_TAG_BOOLEAN: { - DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype")); - curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]; - break; - } - - case DUK_TAG_STRING: { - duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); - - /* - * Note: currently no fast path for array index writes. - * They won't be possible anyway as strings are immutable. - */ - - DUK_ASSERT(key == NULL); - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - /* Symbols (ES2015 or hidden) don't have virtual properties. */ - curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; - goto lookup; - } - - if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - goto fail_not_writable; - } - - if (arr_idx != DUK__NO_ARRAY_INDEX && - arr_idx < DUK_HSTRING_GET_CHARLEN(h)) { - goto fail_not_writable; - } - - DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype")); - curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE]; - goto lookup; /* avoid double coercion */ - } - - case DUK_TAG_OBJECT: { - orig = DUK_TVAL_GET_OBJECT(tv_obj); - DUK_ASSERT(orig != NULL); - -#if defined(DUK_USE_ROM_OBJECTS) - /* With this check in place fast paths won't need read-only - * object checks. This is technically incorrect if there are - * setters that cause no writes to ROM objects, but current - * built-ins don't have such setters. - */ - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) { - DUK_DD(DUK_DDPRINT("attempt to putprop on read-only target object")); - goto fail_not_writable_no_pop; /* Must avoid duk_pop() in exit path */ - } -#endif - - /* The fast path for array property put is not fully compliant: - * If one places conflicting number-indexed properties into - * Array.prototype (for example, a non-writable Array.prototype[7]) - * the fast path will incorrectly ignore them. - * - * This fast path could be made compliant by falling through - * to the slow path if the previous value was UNUSED. This would - * also remove the need to check for extensibility. Right now a - * non-extensible array is slower than an extensible one as far - * as writes are concerned. - * - * The fast path behavior is documented in more detail here: - * tests/ecmascript/test-misc-array-fast-write.js - */ - - /* XXX: array .length? */ - -#if defined(DUK_USE_ARRAY_PROP_FASTPATH) - if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val) != 0) { - DUK_DDD(DUK_DDDPRINT("array fast path success")); - DUK_STATS_INC(thr->heap, stats_putprop_arrayidx); - return 1; - } -#endif - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) { - DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufobj fast path")); - DUK_STATS_INC(thr->heap, stats_putprop_bufobjidx); - return 1; - } -#endif - -#if defined(DUK_USE_ES6_PROXY) - if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(orig))) { - duk_hobject *h_target; - duk_bool_t tmp_bool; - - if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) { - /* -> [ ... trap handler ] */ - DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key)); - DUK_STATS_INC(thr->heap, stats_putprop_proxy); - duk_push_hobject(thr, h_target); /* target */ - duk_push_tval(thr, tv_key); /* P */ - duk_push_tval(thr, tv_val); /* V */ - duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */ - duk_call_method(thr, 4 /*nargs*/); - tmp_bool = duk_to_boolean(thr, -1); - duk_pop_nodecref_unsafe(thr); - if (!tmp_bool) { - goto fail_proxy_rejected; - } - - /* Target object must be checked for a conflicting - * non-configurable property. - */ - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - - if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { - duk_tval *tv_targ = duk_require_tval(thr, -1); - duk_bool_t datadesc_reject; - duk_bool_t accdesc_reject; - - DUK_DDD(DUK_DDDPRINT("proxy 'set': target has matching property %!O, check for " - "conflicting property; tv_val=%!T, tv_targ=%!T, desc.flags=0x%08lx, " - "desc.get=%p, desc.set=%p", - (duk_heaphdr *) key, (duk_tval *) tv_val, (duk_tval *) tv_targ, - (unsigned long) desc.flags, - (void *) desc.get, (void *) desc.set)); - - datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) && - !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && - !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) && - !duk_js_samevalue(tv_val, tv_targ); - accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) && - !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && - (desc.set == NULL); - if (datadesc_reject || accdesc_reject) { - DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); - } - - duk_pop_2_unsafe(thr); - } else { - duk_pop_unsafe(thr); - } - return 1; /* success */ - } - - orig = h_target; /* resume write to target */ - DUK_TVAL_SET_OBJECT(tv_obj, orig); - } -#endif /* DUK_USE_ES6_PROXY */ - - curr = orig; - break; - } - - case DUK_TAG_BUFFER: { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj); - duk_int_t pop_count = 0; - - /* - * Because buffer values may be looped over and read/written - * from, an array index fast path is important. - */ - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_key)) { - arr_idx = duk__tval_fastint_to_arr_idx(tv_key); - DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx)); - pop_count = 0; - } else -#endif - if (DUK_TVAL_IS_NUMBER(tv_key)) { - arr_idx = duk__tval_number_to_arr_idx(tv_key); - DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx)); - pop_count = 0; - } else { - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after " - "coercion key is %!T, arr_idx %ld", - (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); - pop_count = 1; - } - - if (arr_idx != DUK__NO_ARRAY_INDEX && - arr_idx < DUK_HBUFFER_GET_SIZE(h)) { - duk_uint8_t *data; - DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx)); - data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); - - /* XXX: duk_to_int() ensures we'll get 8 lowest bits as - * as input is within duk_int_t range (capped outside it). - */ -#if defined(DUK_USE_FASTINT) - /* Buffer writes are often integers. */ - if (DUK_TVAL_IS_FASTINT(tv_val)) { - data[arr_idx] = (duk_uint8_t) DUK_TVAL_GET_FASTINT_U32(tv_val); - } - else -#endif - { - duk_push_tval(thr, tv_val); - data[arr_idx] = (duk_uint8_t) duk_to_uint32(thr, -1); - pop_count++; - } - - duk_pop_n_unsafe(thr, pop_count); - DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)")); - DUK_STATS_INC(thr->heap, stats_putprop_bufferidx); - return 1; - } - - if (pop_count == 0) { - /* This is a pretty awkward control flow, but we need to recheck the - * key coercion here. - */ - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after " - "coercion key is %!T, arr_idx %ld", - (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); - } - - if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - goto fail_not_writable; - } - - DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype")); - curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; - goto lookup; /* avoid double coercion */ - } - - case DUK_TAG_POINTER: { - DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype")); - curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE]; - break; - } - - case DUK_TAG_LIGHTFUNC: { - /* Lightfuncs have no own properties and are considered non-extensible. - * However, the write may be captured by an inherited setter which - * means we can't stop the lookup here. - */ - DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype")); - curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE]; - break; - } - -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: { - /* number */ - DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype")); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj)); - curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]; - break; - } - } - - DUK_ASSERT(key == NULL); - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - - lookup: - - /* - * Check whether the property already exists in the prototype chain. - * Note that the actual write goes into the original base object - * (except if an accessor property captures the write). - */ - - /* [key] */ - - DUK_ASSERT(curr != NULL); - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - do { - if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ - goto next_in_chain; - } - - if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) { - /* - * Found existing accessor property (own or inherited). - * Call setter with 'this' set to orig, and value as the only argument. - * Setter calls are OK even for ROM objects. - * - * Note: no exotic arguments object behavior, because [[Put]] never - * calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b). - */ - - duk_hobject *setter; - - DUK_DD(DUK_DDPRINT("put to an own or inherited accessor, calling setter")); - - setter = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, curr, desc.e_idx); - if (!setter) { - goto fail_no_setter; - } - duk_push_hobject(thr, setter); - duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */ - duk_push_tval(thr, tv_val); /* [key setter this val] */ -#if defined(DUK_USE_NONSTD_SETTER_KEY_ARGUMENT) - duk_dup_m4(thr); - duk_call_method(thr, 2); /* [key setter this val key] -> [key retval] */ -#else - duk_call_method(thr, 1); /* [key setter this val] -> [key retval] */ -#endif - duk_pop_unsafe(thr); /* ignore retval -> [key] */ - goto success_no_arguments_exotic; - } - - if (orig == NULL) { - /* - * Found existing own or inherited plain property, but original - * base is a primitive value. - */ - DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object")); - goto fail_base_primitive; - } - - if (curr != orig) { - /* - * Found existing inherited plain property. - * Do an access control check, and if OK, write - * new property to 'orig'. - */ - if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) { - DUK_DD(DUK_DDPRINT("found existing inherited plain property, but original object is not extensible")); - goto fail_not_extensible; - } - if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) { - DUK_DD(DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable")); - goto fail_not_writable; - } - DUK_DD(DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable")); - goto create_new; - } else { - /* - * Found existing own (non-inherited) plain property. - * Do an access control check and update in place. - */ - - if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) { - DUK_DD(DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable")); - goto fail_not_writable; - } - if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) { - DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable")); - - if (DUK_HOBJECT_IS_ARRAY(curr)) { - /* - * Write to 'length' of an array is a very complex case - * handled in a helper which updates both the array elements - * and writes the new 'length'. The write may result in an - * unconditional RangeError or a partial write (indicated - * by a return code). - * - * Note: the helper has an unnecessary writability check - * for 'length', we already know it is writable. - */ - DUK_ASSERT(key == DUK_HTHREAD_STRING_LENGTH(thr)); /* only virtual array property */ - - DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper")); - - /* XXX: the helper currently assumes stack top contains new - * 'length' value and the whole calling convention is not very - * compatible with what we need. - */ - - duk_push_tval(thr, tv_val); /* [key val] */ - rc = duk__handle_put_array_length(thr, orig); - duk_pop_unsafe(thr); /* [key val] -> [key] */ - if (!rc) { - goto fail_array_length_partial; - } - - /* key is 'length', cannot match argument exotic behavior */ - goto success_no_arguments_exotic; - } -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - else if (DUK_HOBJECT_IS_BUFOBJ(curr)) { - duk_hbufobj *h_bufobj; - duk_uint_t byte_off; - duk_small_uint_t elem_size; - - h_bufobj = (duk_hbufobj *) curr; - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object")); - - /* Careful with wrapping: arr_idx upshift may easily wrap, whereas - * length downshift won't. - */ - if (arr_idx < (h_bufobj->length >> h_bufobj->shift) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { - duk_uint8_t *data; - DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx)); - - DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */ - byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */ - elem_size = (duk_small_uint_t) (1U << h_bufobj->shift); - - /* Coerce to number before validating pointers etc so that the - * number coercions in duk_hbufobj_validated_write() are - * guaranteed to be side effect free and not invalidate the - * pointer checks we do here. - */ - duk_push_tval(thr, tv_val); - (void) duk_to_number_m1(thr); - - if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) { - data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off; - duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size); - } else { - DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)")); - } - duk_pop_unsafe(thr); - goto success_no_arguments_exotic; - } - } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - - DUK_D(DUK_DPRINT("should not happen, key %!O", key)); - goto fail_internal; /* should not happen */ - } - DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable")); - goto update_old; - } - DUK_UNREACHABLE(); - - next_in_chain: - /* XXX: option to pretend property doesn't exist if sanity limit is - * hit might be useful. - */ - if (DUK_UNLIKELY(sanity-- == 0)) { - DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); - } - curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr != NULL); - - /* - * Property not found in prototype chain. - */ - - DUK_DDD(DUK_DDDPRINT("property not found in prototype chain")); - - if (orig == NULL) { - DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object")); - goto fail_base_primitive; - } - - if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) { - DUK_DD(DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible")); - goto fail_not_extensible; - } - - goto create_new; - - update_old: - - /* - * Update an existing property of the base object. - */ - - /* [key] */ - - DUK_DDD(DUK_DDDPRINT("update an existing property of the original object")); - - DUK_ASSERT(orig != NULL); -#if defined(DUK_USE_ROM_OBJECTS) - /* This should not happen because DUK_TAG_OBJECT case checks - * for this already, but check just in case. - */ - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) { - goto fail_not_writable; - } -#endif - - /* Although there are writable virtual properties (e.g. plain buffer - * and buffer object number indices), they are handled before we come - * here. - */ - DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0); - DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0); - - /* Array own property .length is handled above. */ - DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr))); - - if (desc.e_idx >= 0) { - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx); - DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv)); - DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; e_idx may be invalidated */ - /* don't touch property attributes or hash part */ - DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT", - (long) desc.e_idx, (duk_tval *) tv)); - } else { - /* Note: array entries are always writable, so the writability check - * above is pointless for them. The check could be avoided with some - * refactoring but is probably not worth it. - */ - - DUK_ASSERT(desc.a_idx >= 0); - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx); - DUK_DDD(DUK_DDDPRINT("previous array value: %!iT", (duk_tval *) tv)); - DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; a_idx may be invalidated */ - DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT", - (long) desc.a_idx, (duk_tval *) tv)); - } - - /* Regardless of whether property is found in entry or array part, - * it may have arguments exotic behavior (array indices may reside - * in entry part for abandoned / non-existent array parts). - */ - goto success_with_arguments_exotic; - - create_new: - - /* - * Create a new property in the original object. - * - * Exotic properties need to be reconsidered here from a write - * perspective (not just property attributes perspective). - * However, the property does not exist in the object already, - * so this limits the kind of exotic properties that apply. - */ - - /* [key] */ - - DUK_DDD(DUK_DDDPRINT("create new property to original object")); - - DUK_ASSERT(orig != NULL); - - /* Array own property .length is handled above. */ - DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr))); - -#if defined(DUK_USE_ROM_OBJECTS) - /* This should not happen because DUK_TAG_OBJECT case checks - * for this already, but check just in case. - */ - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) { - goto fail_not_writable; - } -#endif - - /* Not possible because array object 'length' is present - * from its creation and cannot be deleted, and is thus - * caught as an existing property above. - */ - DUK_ASSERT(!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) && - key == DUK_HTHREAD_STRING_LENGTH(thr))); - - if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) && - arr_idx != DUK__NO_ARRAY_INDEX) { - /* automatic length update */ - duk_uint32_t old_len; - duk_harray *a; - - a = (duk_harray *) orig; - DUK_ASSERT_HARRAY_VALID(a); - - old_len = a->length; - - if (arr_idx >= old_len) { - DUK_DDD(DUK_DDDPRINT("write new array entry requires length update " - "(arr_idx=%ld, old_len=%ld)", - (long) arr_idx, (long) old_len)); - - if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) { - DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable")); - goto fail_not_writable; - } - - /* Note: actual update happens once write has been completed - * without error below. The write should always succeed - * from a specification viewpoint, but we may e.g. run out - * of memory. It's safer in this order. - */ - - DUK_ASSERT(arr_idx != 0xffffffffUL); - new_array_length = arr_idx + 1; /* flag for later write */ - } else { - DUK_DDD(DUK_DDDPRINT("write new array entry does not require length update " - "(arr_idx=%ld, old_len=%ld)", - (long) arr_idx, (long) old_len)); - } - } - - /* write_to_array_part: */ - - /* - * Write to array part? - * - * Note: array abandonding requires a property resize which uses - * 'rechecks' valstack for temporaries and may cause any existing - * valstack pointers to be invalidated. To protect against this, - * tv_obj, tv_key, and tv_val are copies of the original inputs. - */ - - if (arr_idx != DUK__NO_ARRAY_INDEX && - DUK_HOBJECT_HAS_ARRAY_PART(orig)) { - if (arr_idx < DUK_HOBJECT_GET_ASIZE(orig)) { - goto no_array_growth; - } - - /* - * Array needs to grow, but we don't want it becoming too sparse. - * If it were to become sparse, abandon array part, moving all - * array entries into the entries part (for good). - * - * Since we don't keep track of actual density (used vs. size) of - * the array part, we need to estimate somehow. The check is made - * in two parts: - * - * - Check whether the resize need is small compared to the - * current size (relatively); if so, resize without further - * checking (essentially we assume that the original part is - * "dense" so that the result would be dense enough). - * - * - Otherwise, compute the resize using an actual density - * measurement based on counting the used array entries. - */ - - DUK_DDD(DUK_DDDPRINT("write to new array requires array resize, decide whether to do a " - "fast resize without abandon check (arr_idx=%ld, old_size=%ld)", - (long) arr_idx, (long) DUK_HOBJECT_GET_ASIZE(orig))); - - if (duk__abandon_array_slow_check_required(arr_idx, DUK_HOBJECT_GET_ASIZE(orig))) { - duk_uint32_t old_used; - duk_uint32_t old_size; - - DUK_DDD(DUK_DDDPRINT("=> fast check is NOT OK, do slow check for array abandon")); - - duk__compute_a_stats(thr, orig, &old_used, &old_size); - - DUK_DDD(DUK_DDDPRINT("abandon check, array stats: old_used=%ld, old_size=%ld, arr_idx=%ld", - (long) old_used, (long) old_size, (long) arr_idx)); - - /* Note: intentionally use approximations to shave a few instructions: - * a_used = old_used (accurate: old_used + 1) - * a_size = arr_idx (accurate: arr_idx + 1) - */ - if (duk__abandon_array_density_check(old_used, arr_idx)) { - DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, " - "decided to abandon array part (would become too sparse)")); - - /* abandoning requires a props allocation resize and - * 'rechecks' the valstack, invalidating any existing - * valstack value pointers! - */ - duk__abandon_array_checked(thr, orig); - DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig)); - - goto write_to_entry_part; - } - - DUK_DDD(DUK_DDDPRINT("=> decided to keep array part")); - } else { - DUK_DDD(DUK_DDDPRINT("=> fast resize is OK")); - } - - DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, " - "decided to extend current allocation")); - - duk__grow_props_for_array_item(thr, orig, arr_idx); - - no_array_growth: - - /* Note: assume array part is comprehensive, so that either - * the write goes to the array part, or we've abandoned the - * array above (and will not come here). - */ - - DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(orig)); - DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(orig)); - - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, arr_idx); - /* prev value must be unused, no decref */ - DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); - DUK_TVAL_SET_TVAL(tv, tv_val); - DUK_TVAL_INCREF(thr, tv); - DUK_DD(DUK_DDPRINT("put to new array entry: %ld -> %!T", - (long) arr_idx, (duk_tval *) tv)); - - /* Note: array part values are [[Writable]], [[Enumerable]], - * and [[Configurable]] which matches the required attributes - * here. - */ - goto entry_updated; - } - - write_to_entry_part: - - /* - * Write to entry part - */ - - /* entry allocation updates hash part and increases the key - * refcount; may need a props allocation resize but doesn't - * 'recheck' the valstack. - */ - e_idx = duk__hobject_alloc_entry_checked(thr, orig, key); - DUK_ASSERT(e_idx >= 0); - - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx); - /* prev value can be garbage, no decref */ - DUK_TVAL_SET_TVAL(tv, tv_val); - DUK_TVAL_INCREF(thr, tv); - DUK_HOBJECT_E_SET_FLAGS(thr->heap, orig, e_idx, DUK_PROPDESC_FLAGS_WEC); - goto entry_updated; - - entry_updated: - - /* - * Possible pending array length update, which must only be done - * if the actual entry write succeeded. - */ - - if (new_array_length > 0) { - /* Note: zero works as a "no update" marker because the new length - * can never be zero after a new property is written. - */ - - DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig)); - - DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld", - (long) new_array_length)); - - ((duk_harray *) orig)->length = new_array_length; - } - - /* - * Arguments exotic behavior not possible for new properties: all - * magically bound properties are initially present in the arguments - * object, and if they are deleted, the binding is also removed from - * parameter map. - */ - - goto success_no_arguments_exotic; - - success_with_arguments_exotic: - - /* - * Arguments objects have exotic [[DefineOwnProperty]] which updates - * the internal 'map' of arguments for writes to currently mapped - * arguments. More conretely, writes to mapped arguments generate - * a write to a bound variable. - * - * The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing - * data properties and new properties, but not for existing accessors. - * Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we - * have a Desc with 'Value' (and possibly other properties too), and - * we end up in step 5.b.i. - */ - - if (arr_idx != DUK__NO_ARRAY_INDEX && - DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) { - /* Note: only numbered indices are relevant, so arr_idx fast reject - * is good (this is valid unless there are more than 4**32-1 arguments). - */ - - DUK_DDD(DUK_DDDPRINT("putprop successful, arguments exotic behavior needed")); - - /* Note: we can reuse 'desc' here */ - - /* XXX: top of stack must contain value, which helper doesn't touch, - * rework to use tv_val directly? - */ - - duk_push_tval(thr, tv_val); - (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag); - duk_pop_unsafe(thr); - } - /* fall thru */ - - success_no_arguments_exotic: - /* shared exit path now */ - DUK_DDD(DUK_DDDPRINT("result: success")); - duk_pop_unsafe(thr); /* remove key */ - return 1; - -#if defined(DUK_USE_ES6_PROXY) - fail_proxy_rejected: - DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects")); - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); - } - /* Note: no key on stack */ - return 0; -#endif - - fail_base_primitive: - DUK_DDD(DUK_DDDPRINT("result: error, base primitive")); - if (throw_flag) { -#if defined(DUK_USE_PARANOID_ERRORS) - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); -#else - DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s", - duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); -#endif - } - duk_pop_unsafe(thr); /* remove key */ - return 0; - - fail_not_extensible: - DUK_DDD(DUK_DDDPRINT("result: error, not extensible")); - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE); - } - duk_pop_unsafe(thr); /* remove key */ - return 0; - - fail_not_writable: - DUK_DDD(DUK_DDDPRINT("result: error, not writable")); - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE); - } - duk_pop_unsafe(thr); /* remove key */ - return 0; - -#if defined(DUK_USE_ROM_OBJECTS) - fail_not_writable_no_pop: - DUK_DDD(DUK_DDDPRINT("result: error, not writable")); - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE); - } - return 0; -#endif - - fail_array_length_partial: - DUK_DD(DUK_DDPRINT("result: error, array length write only partially successful")); - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); - } - duk_pop_unsafe(thr); /* remove key */ - return 0; - - fail_no_setter: - DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter")); - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED); - } - duk_pop_unsafe(thr); /* remove key */ - return 0; - - fail_internal: - DUK_DDD(DUK_DDDPRINT("result: error, internal")); - if (throw_flag) { - DUK_ERROR_INTERNAL(thr); - } - duk_pop_unsafe(thr); /* remove key */ - return 0; -} - -/* - * Ecmascript compliant [[Delete]](P, Throw). - */ - -DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) { - duk_propdesc desc; - duk_tval *tv; - duk_uint32_t arr_idx; - duk_bool_t throw_flag; - duk_bool_t force_flag; - - throw_flag = (flags & DUK_DELPROP_FLAG_THROW); - force_flag = (flags & DUK_DELPROP_FLAG_FORCE); - - DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)", - (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag, - (duk_heaphdr *) obj, (duk_heaphdr *) key)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key); - - /* 0 = don't push current value */ - if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ - DUK_DDD(DUK_DDDPRINT("property not found, succeed always")); - goto success; - } - -#if defined(DUK_USE_ROM_OBJECTS) - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { - DUK_DD(DUK_DDPRINT("attempt to delprop on read-only target object")); - goto fail_not_configurable; - } -#endif - - if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0 && !force_flag) { - goto fail_not_configurable; - } - if (desc.a_idx < 0 && desc.e_idx < 0) { - /* Currently there are no deletable virtual properties, but - * with force_flag we might attempt to delete one. - */ - DUK_DD(DUK_DDPRINT("delete failed: property found, force flag, but virtual (and implicitly non-configurable)")); - goto fail_virtual; - } - - if (desc.a_idx >= 0) { - DUK_ASSERT(desc.e_idx < 0); - - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx); - DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */ - goto success; - } else { - DUK_ASSERT(desc.a_idx < 0); - - /* remove hash entry (no decref) */ -#if defined(DUK_USE_HOBJECT_HASH_PART) - if (desc.h_idx >= 0) { - duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj); - - DUK_DDD(DUK_DDDPRINT("removing hash entry at h_idx %ld", (long) desc.h_idx)); - DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) > 0); - DUK_ASSERT((duk_uint32_t) desc.h_idx < DUK_HOBJECT_GET_HSIZE(obj)); - h_base[desc.h_idx] = DUK__HASH_DELETED; - } else { - DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0); - } -#else - DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0); -#endif - - /* Remove value. This requires multiple writes so avoid side - * effects via no-refzero macros so that e_idx is not - * invalidated. - */ - DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p", - (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx))); - DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx)); - if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) { - duk_hobject *tmp; - - tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx); - DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL); - DUK_UNREF(tmp); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); - - tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx); - DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL); - DUK_UNREF(tmp); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); - } else { - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx); - DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); - } -#if 0 - /* Not strictly necessary because if key == NULL, flag MUST be ignored. */ - DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0); -#endif - - /* Remove key. */ - DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p", - (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx))); - DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx)); - DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)); - DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL); - DUK_HSTRING_DECREF_NORZ(thr, key); - - /* Trigger refzero side effects only when we're done as a - * finalizer might operate on the object and affect the - * e_idx we're supposed to use. - */ - DUK_REFZERO_CHECK_SLOW(thr); - goto success; - } - - DUK_UNREACHABLE(); - - success: - /* - * Argument exotic [[Delete]] behavior (E5 Section 10.6) is - * a post-check, keeping arguments internal 'map' in sync with - * any successful deletes (note that property does not need to - * exist for delete to 'succeed'). - * - * Delete key from 'map'. Since 'map' only contains array index - * keys, we can use arr_idx for a fast skip. - */ - - DUK_DDD(DUK_DDDPRINT("delete successful, check for arguments exotic behavior")); - - if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) { - /* Note: only numbered indices are relevant, so arr_idx fast reject - * is good (this is valid unless there are more than 4**32-1 arguments). - */ - - DUK_DDD(DUK_DDDPRINT("delete successful, arguments exotic behavior needed")); - - /* Note: we can reuse 'desc' here */ - (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc); - } - - DUK_DDD(DUK_DDDPRINT("delete successful")); - return 1; - - fail_virtual: /* just use the same "not configurable" error message */ - fail_not_configurable: - DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable")); - - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); - } - return 0; -} - -/* - * DELPROP: Ecmascript property deletion. - */ - -DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) { - duk_hstring *key = NULL; -#if defined(DUK_USE_ES6_PROXY) - duk_propdesc desc; -#endif - duk_int_t entry_top; - duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX; - duk_bool_t rc; - - DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)", - (void *) thr, (void *) tv_obj, (void *) tv_key, - (duk_tval *) tv_obj, (duk_tval *) tv_key)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(tv_obj != NULL); - DUK_ASSERT(tv_key != NULL); - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - /* Storing the entry top is cheaper here to ensure stack is correct at exit, - * as there are several paths out. - */ - entry_top = duk_get_top(thr); - - if (DUK_TVAL_IS_UNDEFINED(tv_obj) || - DUK_TVAL_IS_NULL(tv_obj)) { - DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject")); - goto fail_invalid_base_uncond; - } - - duk_push_tval(thr, tv_obj); - duk_push_tval(thr, tv_key); - - tv_obj = DUK_GET_TVAL_NEGIDX(thr, -2); - if (DUK_TVAL_IS_OBJECT(tv_obj)) { - duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj); - DUK_ASSERT(obj != NULL); - -#if defined(DUK_USE_ES6_PROXY) - if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) { - duk_hobject *h_target; - duk_bool_t tmp_bool; - - /* Note: proxy handling must happen before key is string coerced. */ - - if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) { - /* -> [ ... obj key trap handler ] */ - DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key)); - duk_push_hobject(thr, h_target); /* target */ - duk_dup_m4(thr); /* P */ - duk_call_method(thr, 2 /*nargs*/); - tmp_bool = duk_to_boolean(thr, -1); - duk_pop_nodecref_unsafe(thr); - if (!tmp_bool) { - goto fail_proxy_rejected; /* retval indicates delete failed */ - } - - /* Target object must be checked for a conflicting - * non-configurable property. - */ - tv_key = DUK_GET_TVAL_NEGIDX(thr, -1); - arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); - DUK_ASSERT(key != NULL); - - if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ - duk_small_int_t desc_reject; - - DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for " - "conflicting property; desc.flags=0x%08lx, " - "desc.get=%p, desc.set=%p", - (duk_heaphdr *) key, (unsigned long) desc.flags, - (void *) desc.get, (void *) desc.set)); - - desc_reject = !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE); - if (desc_reject) { - /* unconditional */ - DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); - } - } - rc = 1; /* success */ - goto done_rc; - } - - obj = h_target; /* resume delete to target */ - } -#endif /* DUK_USE_ES6_PROXY */ - - arr_idx = duk__to_property_key(thr, -1, &key); - DUK_ASSERT(key != NULL); - - rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0); - goto done_rc; - } else if (DUK_TVAL_IS_STRING(tv_obj)) { - /* String has .length and array index virtual properties - * which can't be deleted. No need for a symbol check; - * no offending virtual symbols exist. - */ - /* XXX: unnecessary string coercion for array indices, - * intentional to keep small. - */ - duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); - DUK_ASSERT(h != NULL); - - arr_idx = duk__to_property_key(thr, -1, &key); - DUK_ASSERT(key != NULL); - - if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - goto fail_not_configurable; - } - - if (arr_idx != DUK__NO_ARRAY_INDEX && - arr_idx < DUK_HSTRING_GET_CHARLEN(h)) { - goto fail_not_configurable; - } - } else if (DUK_TVAL_IS_BUFFER(tv_obj)) { - /* XXX: unnecessary string coercion for array indices, - * intentional to keep small; some overlap with string - * handling. - */ - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj); - DUK_ASSERT(h != NULL); - - arr_idx = duk__to_property_key(thr, -1, &key); - DUK_ASSERT(key != NULL); - - if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - goto fail_not_configurable; - } - - if (arr_idx != DUK__NO_ARRAY_INDEX && - arr_idx < DUK_HBUFFER_GET_SIZE(h)) { - goto fail_not_configurable; - } - } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) { - /* Lightfunc has no virtual properties since Duktape 2.2 - * so success. Still must coerce key for side effects. - */ - - arr_idx = duk__to_property_key(thr, -1, &key); - DUK_ASSERT(key != NULL); - DUK_UNREF(key); - } - - /* non-object base, no offending virtual property */ - rc = 1; - goto done_rc; - - done_rc: - duk_set_top_unsafe(thr, entry_top); - return rc; - - fail_invalid_base_uncond: - /* Note: unconditional throw */ - DUK_ASSERT(duk_get_top(thr) == entry_top); -#if defined(DUK_USE_PARANOID_ERRORS) - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); -#else - DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s", - duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); -#endif - return 0; - -#if defined(DUK_USE_ES6_PROXY) - fail_proxy_rejected: - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); - } - duk_set_top_unsafe(thr, entry_top); - return 0; -#endif - - fail_not_configurable: - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); - } - duk_set_top_unsafe(thr, entry_top); - return 0; -} - -/* - * Internal helper to define a property with specific flags, ignoring - * normal semantics such as extensibility, write protection etc. - * Overwrites any existing value and attributes unless caller requests - * that value only be updated if it doesn't already exists. - * - * Does not support: - * - virtual properties (error if write attempted) - * - getter/setter properties (error if write attempted) - * - non-default (!= WEC) attributes for array entries (error if attempted) - * - array abandoning: if array part exists, it is always extended - * - array 'length' updating - * - * Stack: [... in_val] -> [] - * - * Used for e.g. built-in initialization and environment record - * operations. - */ - -DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) { - duk_propdesc desc; - duk_uint32_t arr_idx; - duk_int_t e_idx; - duk_tval *tv1 = NULL; - duk_tval *tv2 = NULL; - duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK; /* mask out flags not actually stored */ - - DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T", - (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key, - (unsigned long) flags, (duk_tval *) duk_get_tval(thr, -1))); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - DUK_ASSERT(duk_is_valid_index(thr, -1)); /* contains value */ - - arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); - - if (duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ - if (desc.e_idx >= 0) { - if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) { - DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> skip as requested")); - goto pop_exit; - } - DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> update value and attributes")); - if (DUK_UNLIKELY(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx))) { - DUK_D(DUK_DPRINT("existing property is an accessor, not supported")); - goto error_internal; - } - - DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, propflags); - tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx); - } else if (desc.a_idx >= 0) { - if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) { - DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> skip as requested")); - goto pop_exit; - } - DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)")); - if (propflags != DUK_PROPDESC_FLAGS_WEC) { - DUK_D(DUK_DPRINT("existing property in array part, but propflags not WEC (0x%02lx)", - (unsigned long) propflags)); - goto error_internal; - } - - tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx); - } else { - if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) { - DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested")); - goto pop_exit; - } - if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { - duk_uint32_t new_len; -#if defined(DUK_USE_DEBUG) - duk_uint32_t prev_len; - prev_len = ((duk_harray *) obj)->length; -#endif - new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1)); - ((duk_harray *) obj)->length = new_len; - DUK_D(DUK_DPRINT("internal define property for array .length: %ld -> %ld", - (long) prev_len, (long) ((duk_harray *) obj)->length)); - goto pop_exit; - } - DUK_DD(DUK_DDPRINT("property already exists but is virtual -> failure")); - goto error_virtual; - } - - goto write_value; - } - - if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) { - if (arr_idx != DUK__NO_ARRAY_INDEX) { - DUK_DDD(DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)")); - DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC); - - /* always grow the array, no sparse / abandon support here */ - if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) { - duk__grow_props_for_array_item(thr, obj, arr_idx); - } - - DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj)); - tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx); - goto write_value; - } - } - - DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes")); - e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); /* increases key refcount */ - DUK_ASSERT(e_idx >= 0); - DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags); - tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx); - /* new entry: previous value is garbage; set to undefined to share write_value */ - DUK_TVAL_SET_UNDEFINED(tv1); - goto write_value; - - write_value: - /* tv1 points to value storage */ - - tv2 = duk_require_tval(thr, -1); /* late lookup, avoid side effects */ - DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T", - (duk_tval *) tv1, (duk_tval *) tv2)); - - DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ - goto pop_exit; - - pop_exit: - duk_pop_unsafe(thr); /* remove in_val */ - return; - - error_virtual: /* share error message */ - error_internal: - DUK_ERROR_INTERNAL(thr); - return; -} - -/* - * Fast path for defining array indexed values without interning the key. - * This is used by e.g. code for Array prototype and traceback creation so - * must avoid interning. - */ - -DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) { - duk_hstring *key; - duk_tval *tv1, *tv2; - - DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, " - "arr_idx=%ld, flags=0x%02lx, val=%!T", - (void *) thr, obj, (long) arr_idx, (unsigned long) flags, - (duk_tval *) duk_get_tval(thr, -1))); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); - - if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && - arr_idx != DUK__NO_ARRAY_INDEX && - flags == DUK_PROPDESC_FLAGS_WEC) { - DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0); /* covered by comparison */ - - DUK_DDD(DUK_DDDPRINT("define property to array part (property may or may not exist yet)")); - - /* always grow the array, no sparse / abandon support here */ - if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) { - duk__grow_props_for_array_item(thr, obj, arr_idx); - } - - DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj)); - tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx); - tv2 = duk_require_tval(thr, -1); - - DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ - - duk_pop_unsafe(thr); /* [ ...val ] -> [ ... ] */ - return; - } - - DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path")); - - key = duk_push_uint_to_hstring(thr, (duk_uint_t) arr_idx); - DUK_ASSERT(key != NULL); - duk_insert(thr, -2); /* [ ... val key ] -> [ ... key val ] */ - - duk_hobject_define_property_internal(thr, obj, key, flags); - - duk_pop_unsafe(thr); /* [ ... key ] -> [ ... ] */ -} - -/* - * Internal helpers for managing object 'length' - */ - -DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) { - duk_double_t val; - - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(obj != NULL); - - /* Fast path for Arrays. */ - if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { - return ((duk_harray *) obj)->length; - } - - /* Slow path, .length can be e.g. accessor, obj can be a Proxy, etc. */ - duk_push_hobject(thr, obj); - duk_push_hstring_stridx(thr, DUK_STRIDX_LENGTH); - (void) duk_hobject_getprop(thr, - DUK_GET_TVAL_NEGIDX(thr, -2), - DUK_GET_TVAL_NEGIDX(thr, -1)); - val = duk_to_number_m1(thr); - duk_pop_3_unsafe(thr); - - /* This isn't part of Ecmascript semantics; return a value within - * duk_size_t range, or 0 otherwise. - */ - if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) { - return (duk_size_t) val; - } - return 0; -} - -/* - * Fast finalizer check for an object. Walks the prototype chain, checking - * for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept - * in sync with the actual property when setting/removing the finalizer. - */ - -#if defined(DUK_USE_HEAPPTR16) -DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) { -#else -DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) { -#endif - duk_uint_t sanity; - - DUK_ASSERT(obj != NULL); - - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - do { - if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) { - return 1; - } - if (DUK_UNLIKELY(sanity-- == 0)) { - DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false")); - return 0; - } -#if defined(DUK_USE_HEAPPTR16) - DUK_ASSERT(heap != NULL); - obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj); -#else - obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj); /* 'heap' arg ignored */ -#endif - } while (obj != NULL); - - return 0; -} - -/* - * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4) - * - * [ ... key ] -> [ ... desc/undefined ] - */ - -DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx) { - duk_hobject *obj; - duk_hstring *key; - duk_propdesc pd; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - - obj = duk_require_hobject_promote_mask(thr, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - key = duk_to_property_key_hstring(thr, -1); - DUK_ASSERT(key != NULL); - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - if (!duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE)) { - duk_push_undefined(thr); - duk_remove_m2(thr); - return; - } - - duk_push_object(thr); - - /* [ ... key value desc ] */ - - if (DUK_PROPDESC_IS_ACCESSOR(&pd)) { - /* If a setter/getter is missing (undefined), the descriptor must - * still have the property present with the value 'undefined'. - */ - if (pd.get) { - duk_push_hobject(thr, pd.get); - } else { - duk_push_undefined(thr); - } - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_GET); - if (pd.set) { - duk_push_hobject(thr, pd.set); - } else { - duk_push_undefined(thr); - } - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_SET); - } else { - duk_dup_m2(thr); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_VALUE); - duk_push_boolean(thr, DUK_PROPDESC_IS_WRITABLE(&pd)); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_WRITABLE); - } - duk_push_boolean(thr, DUK_PROPDESC_IS_ENUMERABLE(&pd)); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_ENUMERABLE); - duk_push_boolean(thr, DUK_PROPDESC_IS_CONFIGURABLE(&pd)); - duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_CONFIGURABLE); - - /* [ ... key value desc ] */ - - duk_replace(thr, -3); - duk_pop_unsafe(thr); /* -> [ ... desc ] */ -} - -/* - * NormalizePropertyDescriptor() related helper. - * - * Internal helper which validates and normalizes a property descriptor - * represented as an Ecmascript object (e.g. argument to defineProperty()). - * The output of this conversion is a set of defprop_flags and possibly - * some values pushed on the value stack to (1) ensure borrowed pointers - * remain valid, and (2) avoid unnecessary pops for footprint reasons. - * Caller must manage stack top carefully because the number of values - * pushed depends on the input property descriptor. - * - * The original descriptor object must not be altered in the process. - */ - -/* XXX: very basic optimization -> duk_get_prop_stridx_top */ - -DUK_INTERNAL -void duk_hobject_prepare_property_descriptor(duk_hthread *thr, - duk_idx_t idx_in, - duk_uint_t *out_defprop_flags, - duk_idx_t *out_idx_value, - duk_hobject **out_getter, - duk_hobject **out_setter) { - duk_idx_t idx_value = -1; - duk_hobject *getter = NULL; - duk_hobject *setter = NULL; - duk_bool_t is_data_desc = 0; - duk_bool_t is_acc_desc = 0; - duk_uint_t defprop_flags = 0; - - DUK_ASSERT(out_defprop_flags != NULL); - DUK_ASSERT(out_idx_value != NULL); - DUK_ASSERT(out_getter != NULL); - DUK_ASSERT(out_setter != NULL); - DUK_ASSERT(idx_in <= 0x7fffL); /* short variants would be OK, but not used to avoid shifts */ - - /* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */ - idx_in = duk_require_normalize_index(thr, idx_in); - (void) duk_require_hobject(thr, idx_in); - - /* The coercion order must match the ToPropertyDescriptor() algorithm - * so that side effects in coercion happen in the correct order. - * (This order also happens to be compatible with duk_def_prop(), - * although it doesn't matter in practice.) - */ - - if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_VALUE)) { - is_data_desc = 1; - defprop_flags |= DUK_DEFPROP_HAVE_VALUE; - idx_value = duk_get_top_index(thr); - } - - if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) { - is_data_desc = 1; - if (duk_to_boolean(thr, -1)) { - defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE; - } else { - defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE; - } - } - - if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_GET)) { - duk_tval *tv = duk_require_tval(thr, -1); - duk_hobject *h_get; - - if (DUK_TVAL_IS_UNDEFINED(tv)) { - /* undefined is accepted */ - DUK_ASSERT(getter == NULL); - } else { - /* NOTE: lightfuncs are coerced to full functions because - * lightfuncs don't fit into a property value slot. This - * has some side effects, see test-dev-lightfunc-accessor.js. - */ - h_get = duk_get_hobject_promote_lfunc(thr, -1); - if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) { - goto type_error; - } - getter = h_get; - } - is_acc_desc = 1; - defprop_flags |= DUK_DEFPROP_HAVE_GETTER; - } - - if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_SET)) { - duk_tval *tv = duk_require_tval(thr, -1); - duk_hobject *h_set; - - if (DUK_TVAL_IS_UNDEFINED(tv)) { - /* undefined is accepted */ - DUK_ASSERT(setter == NULL); - } else { - /* NOTE: lightfuncs are coerced to full functions because - * lightfuncs don't fit into a property value slot. This - * has some side effects, see test-dev-lightfunc-accessor.js. - */ - h_set = duk_get_hobject_promote_lfunc(thr, -1); - if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) { - goto type_error; - } - setter = h_set; - } - is_acc_desc = 1; - defprop_flags |= DUK_DEFPROP_HAVE_SETTER; - } - - if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_ENUMERABLE)) { - if (duk_to_boolean(thr, -1)) { - defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE; - } else { - defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE; - } - } - - if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_CONFIGURABLE)) { - if (duk_to_boolean(thr, -1)) { - defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE; - } else { - defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE; - } - } - - if (is_data_desc && is_acc_desc) { - goto type_error; - } - - *out_defprop_flags = defprop_flags; - *out_idx_value = idx_value; - *out_getter = getter; - *out_setter = setter; - - /* [ ... [multiple values] ] */ - return; - - type_error: - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR); -} - -/* - * Object.defineProperty() related helper (E5 Section 15.2.3.6). - * Also handles ES2015 Reflect.defineProperty(). - * - * Inlines all [[DefineOwnProperty]] exotic behaviors. - * - * Note: Ecmascript compliant [[DefineOwnProperty]](P, Desc, Throw) is not - * implemented directly, but Object.defineProperty() serves its purpose. - * We don't need the [[DefineOwnProperty]] internally and we don't have a - * property descriptor with 'missing values' so it's easier to avoid it - * entirely. - * - * Note: this is only called for actual objects, not primitive values. - * This must support virtual properties for full objects (e.g. Strings) - * but not for plain values (e.g. strings). Lightfuncs, even though - * primitive in a sense, are treated like objects and accepted as target - * values. - */ - -/* XXX: this is a major target for size optimization */ -DUK_INTERNAL -duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr, - duk_uint_t defprop_flags, - duk_hobject *obj, - duk_hstring *key, - duk_idx_t idx_value, - duk_hobject *get, - duk_hobject *set, - duk_bool_t throw_flag) { - duk_uint32_t arr_idx; - duk_tval tv; - duk_bool_t has_enumerable; - duk_bool_t has_configurable; - duk_bool_t has_writable; - duk_bool_t has_value; - duk_bool_t has_get; - duk_bool_t has_set; - duk_bool_t is_enumerable; - duk_bool_t is_configurable; - duk_bool_t is_writable; - duk_bool_t force_flag; - duk_small_uint_t new_flags; - duk_propdesc curr; - duk_uint32_t arridx_new_array_length; /* != 0 => post-update for array 'length' (used when key is an array index) */ - duk_uint32_t arrlen_old_len; - duk_uint32_t arrlen_new_len; - duk_bool_t pending_write_protect; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT(key != NULL); - /* idx_value may be < 0 (no value), set and get may be NULL */ - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - - /* All the flags fit in 16 bits, so will fit into duk_bool_t. */ - - has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE); - has_enumerable = (defprop_flags & DUK_DEFPROP_HAVE_ENUMERABLE); - has_configurable = (defprop_flags & DUK_DEFPROP_HAVE_CONFIGURABLE); - has_value = (defprop_flags & DUK_DEFPROP_HAVE_VALUE); - has_get = (defprop_flags & DUK_DEFPROP_HAVE_GETTER); - has_set = (defprop_flags & DUK_DEFPROP_HAVE_SETTER); - is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE); - is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE); - is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE); - force_flag = (defprop_flags & DUK_DEFPROP_FORCE); - - arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); - - arridx_new_array_length = 0; - pending_write_protect = 0; - arrlen_old_len = 0; - arrlen_new_len = 0; - - DUK_DDD(DUK_DDDPRINT("has_enumerable=%ld is_enumerable=%ld " - "has_configurable=%ld is_configurable=%ld " - "has_writable=%ld is_writable=%ld " - "has_value=%ld value=%!T " - "has_get=%ld get=%p=%!O " - "has_set=%ld set=%p=%!O " - "arr_idx=%ld throw_flag=!%ld", - (long) has_enumerable, (long) is_enumerable, - (long) has_configurable, (long) is_configurable, - (long) has_writable, (long) is_writable, - (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(thr, idx_value) : NULL), - (long) has_get, (void *) get, (duk_heaphdr *) get, - (long) has_set, (void *) set, (duk_heaphdr *) set, - (long) arr_idx, (long) throw_flag)); - - /* - * Array exotic behaviors can be implemented at this point. The local variables - * are essentially a 'value copy' of the input descriptor (Desc), which is modified - * by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1). - */ - - if (!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { - goto skip_array_exotic; - } - - if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { - duk_harray *a; - - /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */ - if (!has_value) { - DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior")); - goto skip_array_exotic; - } - - DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', value present in descriptor -> exotic behavior")); - - /* - * Get old and new length - */ - - a = (duk_harray *) obj; - DUK_ASSERT_HARRAY_VALID(a); - arrlen_old_len = a->length; - - DUK_ASSERT(idx_value >= 0); - arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(thr, idx_value)); - duk_push_u32(thr, arrlen_new_len); - duk_replace(thr, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */ - - DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len)); - - if (arrlen_new_len >= arrlen_old_len) { - /* standard behavior, step 3.f.i */ - DUK_DDD(DUK_DDDPRINT("new length is same or higher as previous => standard behavior")); - goto skip_array_exotic; - } - DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior")); - - /* XXX: consolidated algorithm step 15.f -> redundant? */ - if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) { - /* Array .length is always non-configurable; if it's also - * non-writable, don't allow it to be written. - */ - goto fail_not_configurable; - } - - /* steps 3.h and 3.i */ - if (has_writable && !is_writable) { - DUK_DDD(DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect")); - is_writable = 1; - pending_write_protect = 1; - } - - /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */ - } else if (arr_idx != DUK__NO_ARRAY_INDEX) { - /* XXX: any chance of unifying this with the 'length' key handling? */ - - /* E5 Section 15.4.5.1, step 4 */ - duk_uint32_t old_len; - duk_harray *a; - - a = (duk_harray *) obj; - DUK_ASSERT_HARRAY_VALID(a); - - old_len = a->length; - - if (arr_idx >= old_len) { - DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update " - "(arr_idx=%ld, old_len=%ld)", - (long) arr_idx, (long) old_len)); - - if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) { - /* Array .length is always non-configurable, so - * if it's also non-writable, don't allow a value - * write. With force flag allow writing. - */ - goto fail_not_configurable; - } - - /* actual update happens once write has been completed without - * error below. - */ - DUK_ASSERT(arr_idx != 0xffffffffUL); - arridx_new_array_length = arr_idx + 1; - } else { - DUK_DDD(DUK_DDDPRINT("defineProperty does not require length update " - "(arr_idx=%ld, old_len=%ld) -> standard behavior", - (long) arr_idx, (long) old_len)); - } - } - skip_array_exotic: - - /* XXX: There is currently no support for writing buffer object - * indexed elements here. Attempt to do so will succeed and - * write a concrete property into the buffer object. This should - * be fixed at some point but because buffers are a custom feature - * anyway, this is relatively unimportant. - */ - - /* - * Actual Object.defineProperty() default algorithm. - */ - - /* - * First check whether property exists; if not, simple case. This covers - * steps 1-4. - */ - - if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE)) { - DUK_DDD(DUK_DDDPRINT("property does not exist")); - - if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj) && !force_flag) { - goto fail_not_extensible; - } - -#if defined(DUK_USE_ROM_OBJECTS) - /* ROM objects are never extensible but force flag may - * allow us to come here anyway. - */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj) || !DUK_HOBJECT_HAS_EXTENSIBLE(obj)); - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { - DUK_D(DUK_DPRINT("attempt to define property on a read-only target object")); - goto fail_not_configurable; - } -#endif - - /* XXX: share final setting code for value and flags? difficult because - * refcount code is different. Share entry allocation? But can't allocate - * until array index checked. - */ - - /* steps 4.a and 4.b are tricky */ - if (has_set || has_get) { - duk_int_t e_idx; - - DUK_DDD(DUK_DDDPRINT("create new accessor property")); - - DUK_ASSERT(has_set || set == NULL); - DUK_ASSERT(has_get || get == NULL); - DUK_ASSERT(!has_value); - DUK_ASSERT(!has_writable); - - new_flags = DUK_PROPDESC_FLAG_ACCESSOR; /* defaults, E5 Section 8.6.1, Table 7 */ - if (has_enumerable && is_enumerable) { - new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE; - } - if (has_configurable && is_configurable) { - new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; - } - - if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) { - DUK_DDD(DUK_DDDPRINT("accessor cannot go to array part, abandon array")); - duk__abandon_array_checked(thr, obj); - } - - /* write to entry part */ - e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); - DUK_ASSERT(e_idx >= 0); - - DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get); - DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set); - DUK_HOBJECT_INCREF_ALLOWNULL(thr, get); - DUK_HOBJECT_INCREF_ALLOWNULL(thr, set); - - DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags); - goto success_exotics; - } else { - duk_int_t e_idx; - duk_tval *tv2; - - DUK_DDD(DUK_DDDPRINT("create new data property")); - - DUK_ASSERT(!has_set); - DUK_ASSERT(!has_get); - - new_flags = 0; /* defaults, E5 Section 8.6.1, Table 7 */ - if (has_writable && is_writable) { - new_flags |= DUK_PROPDESC_FLAG_WRITABLE; - } - if (has_enumerable && is_enumerable) { - new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE; - } - if (has_configurable && is_configurable) { - new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; - } - if (has_value) { - duk_tval *tv_tmp = duk_require_tval(thr, idx_value); - DUK_TVAL_SET_TVAL(&tv, tv_tmp); - } else { - DUK_TVAL_SET_UNDEFINED(&tv); /* default value */ - } - - if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) { - if (new_flags == DUK_PROPDESC_FLAGS_WEC) { -#if 0 - DUK_DDD(DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part")); - /* may become sparse...*/ -#endif - /* XXX: handling for array part missing now; this doesn't affect - * compliance but causes array entry writes using defineProperty() - * to always abandon array part. - */ - } - DUK_DDD(DUK_DDDPRINT("new data property cannot go to array part, abandon array")); - duk__abandon_array_checked(thr, obj); - /* fall through */ - } - - /* write to entry part */ - e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); - DUK_ASSERT(e_idx >= 0); - tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx); - DUK_TVAL_SET_TVAL(tv2, &tv); - DUK_TVAL_INCREF(thr, tv2); - - DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags); - goto success_exotics; - } - DUK_UNREACHABLE(); - } - - /* we currently assume virtual properties are not configurable (as none of them are) */ - DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)); - - /* [obj key desc value get set curr_value] */ - - /* - * Property already exists. Steps 5-6 detect whether any changes need - * to be made. - */ - - if (has_enumerable) { - if (is_enumerable) { - if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) { - goto need_check; - } - } else { - if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) { - goto need_check; - } - } - } - if (has_configurable) { - if (is_configurable) { - if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) { - goto need_check; - } - } else { - if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) { - goto need_check; - } - } - } - if (has_value) { - duk_tval *tmp1; - duk_tval *tmp2; - - /* attempt to change from accessor to data property */ - if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { - goto need_check; - } - - tmp1 = duk_require_tval(thr, -1); /* curr value */ - tmp2 = duk_require_tval(thr, idx_value); /* new value */ - if (!duk_js_samevalue(tmp1, tmp2)) { - goto need_check; - } - } - if (has_writable) { - /* attempt to change from accessor to data property */ - if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { - goto need_check; - } - - if (is_writable) { - if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) { - goto need_check; - } - } else { - if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) { - goto need_check; - } - } - } - if (has_set) { - if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { - if (set != curr.set) { - goto need_check; - } - } else { - goto need_check; - } - } - if (has_get) { - if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { - if (get != curr.get) { - goto need_check; - } - } else { - goto need_check; - } - } - - /* property exists, either 'desc' is empty, or all values - * match (SameValue) - */ - goto success_no_exotics; - - need_check: - - /* - * Some change(s) need to be made. Steps 7-11. - */ - - /* shared checks for all descriptor types */ - if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { - if (has_configurable && is_configurable) { - goto fail_not_configurable; - } - if (has_enumerable) { - if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) { - if (!is_enumerable) { - goto fail_not_configurable; - } - } else { - if (is_enumerable) { - goto fail_not_configurable; - } - } - } - } - - /* Virtual properties don't have backing so they can't mostly be - * edited. Some virtual properties are, however, writable: for - * example, virtual index properties of buffer objects and Array - * instance .length. These are not configurable so the checks - * above mostly cover attempts to change them, except when the - * duk_def_prop() call is used with DUK_DEFPROP_FORCE; even in - * that case we can't forcibly change the property attributes - * because they don't have concrete backing. - */ - - /* XXX: for ROM objects too it'd be best if value modify was - * allowed if the value matches SameValue. - */ - /* Reject attempt to change a read-only object. */ -#if defined(DUK_USE_ROM_OBJECTS) - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { - DUK_DD(DUK_DDPRINT("attempt to define property on read-only target object")); - goto fail_not_configurable; - } -#endif - - /* descriptor type specific checks */ - if (has_set || has_get) { - /* IsAccessorDescriptor(desc) == true */ - DUK_ASSERT(!has_writable); - DUK_ASSERT(!has_value); - - if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { - /* curr and desc are accessors */ - if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { - if (has_set && set != curr.set) { - goto fail_not_configurable; - } - if (has_get && get != curr.get) { - goto fail_not_configurable; - } - } - } else { - duk_bool_t rc; - duk_tval *tv1; - - /* curr is data, desc is accessor */ - if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { - goto fail_not_configurable; - } - - DUK_DDD(DUK_DDDPRINT("convert property to accessor property")); - if (curr.a_idx >= 0) { - DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup")); - duk__abandon_array_checked(thr, obj); - duk_pop_unsafe(thr); /* remove old value */ - rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE); - DUK_UNREF(rc); - DUK_ASSERT(rc != 0); - DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0); - } - if (curr.e_idx < 0) { - DUK_ASSERT(curr.a_idx < 0 && curr.e_idx < 0); - goto fail_virtual; /* safeguard for virtual property */ - } - - DUK_ASSERT(curr.e_idx >= 0); - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); - - tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx); - DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv1); /* XXX: just decref */ - - DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL); - DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL); - DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx); - DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, curr.e_idx); - - DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx", - (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx))); - /* Update curr.flags; faster than a re-lookup. */ - curr.flags &= ~DUK_PROPDESC_FLAG_WRITABLE; - curr.flags |= DUK_PROPDESC_FLAG_ACCESSOR; - } - } else if (has_value || has_writable) { - /* IsDataDescriptor(desc) == true */ - DUK_ASSERT(!has_set); - DUK_ASSERT(!has_get); - - if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { - duk_hobject *tmp; - - /* curr is accessor, desc is data */ - if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { - goto fail_not_configurable; - } - - /* curr is accessor -> cannot be in array part. */ - DUK_ASSERT(curr.a_idx < 0); - if (curr.e_idx < 0) { - goto fail_virtual; /* safeguard; no virtual accessors now */ - } - - DUK_DDD(DUK_DDDPRINT("convert property to data property")); - - DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); - tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx); - DUK_UNREF(tmp); - DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); - tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx); - DUK_UNREF(tmp); - DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); - - DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx)); - DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx); - DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(thr->heap, obj, curr.e_idx); - - DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx", - (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx))); - - /* Update curr.flags; faster than a re-lookup. */ - curr.flags &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ACCESSOR); - } else { - /* curr and desc are data */ - if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { - if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) { - goto fail_not_configurable; - } - /* Note: changing from writable to non-writable is OK */ - if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) { - duk_tval *tmp1 = duk_require_tval(thr, -1); /* curr value */ - duk_tval *tmp2 = duk_require_tval(thr, idx_value); /* new value */ - if (!duk_js_samevalue(tmp1, tmp2)) { - goto fail_not_configurable; - } - } - } - } - } else { - /* IsGenericDescriptor(desc) == true; this means in practice that 'desc' - * only has [[Enumerable]] or [[Configurable]] flag updates, which are - * allowed at this point. - */ - - DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set); - } - - /* - * Start doing property attributes updates. Steps 12-13. - * - * Start by computing new attribute flags without writing yet. - * Property type conversion is done above if necessary. - */ - - new_flags = curr.flags; - - if (has_enumerable) { - if (is_enumerable) { - new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE; - } else { - new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE; - } - } - if (has_configurable) { - if (is_configurable) { - new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; - } else { - new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE; - } - } - if (has_writable) { - if (is_writable) { - new_flags |= DUK_PROPDESC_FLAG_WRITABLE; - } else { - new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE; - } - } - - /* XXX: write protect after flag? -> any chance of handling it here? */ - - DUK_DDD(DUK_DDDPRINT("new flags that we want to write: 0x%02lx", - (unsigned long) new_flags)); - - /* - * Check whether we need to abandon an array part (if it exists) - */ - - if (curr.a_idx >= 0) { - duk_bool_t rc; - - DUK_ASSERT(curr.e_idx < 0); - - if (new_flags == DUK_PROPDESC_FLAGS_WEC) { - duk_tval *tv1, *tv2; - - DUK_DDD(DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place")); - - DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC); /* must have been, since in array part */ - DUK_ASSERT(!has_set); - DUK_ASSERT(!has_get); - DUK_ASSERT(idx_value >= 0); /* must be: if attributes match and we get here the value must differ (otherwise no change) */ - - tv2 = duk_require_tval(thr, idx_value); - tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx); - DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate a_idx */ - goto success_exotics; - } - - DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup")); - duk__abandon_array_checked(thr, obj); - duk_pop_unsafe(thr); /* remove old value */ - rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE); - DUK_UNREF(rc); - DUK_ASSERT(rc != 0); - DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0); - } - - DUK_DDD(DUK_DDDPRINT("updating existing property in entry part")); - - /* Array case is handled comprehensively above: either in entry - * part or a virtual property. - */ - DUK_ASSERT(curr.a_idx < 0); - - DUK_DDD(DUK_DDDPRINT("update existing property attributes")); - if (curr.e_idx >= 0) { - DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags); - } else { - /* For Array .length the only allowed transition is for .length - * to become non-writable. - */ - if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { - duk_harray *a; - a = (duk_harray *) obj; - DUK_DD(DUK_DDPRINT("Object.defineProperty() attribute update for duk_harray .length -> %02lx", (unsigned long) new_flags)); - DUK_ASSERT_HARRAY_VALID(a); - if ((new_flags & DUK_PROPDESC_FLAGS_EC) != (curr.flags & DUK_PROPDESC_FLAGS_EC)) { - DUK_D(DUK_DPRINT("Object.defineProperty() attempt to change virtual array .length enumerable or configurable attribute, fail")); - goto fail_virtual; - } - if (new_flags & DUK_PROPDESC_FLAG_WRITABLE) { - DUK_HARRAY_SET_LENGTH_WRITABLE(a); - } else { - DUK_HARRAY_SET_LENGTH_NONWRITABLE(a); - } - } - } - - if (has_set) { - duk_hobject *tmp; - - /* Virtual properties are non-configurable but with a 'force' - * flag we might come here so check explicitly for virtual. - */ - if (curr.e_idx < 0) { - goto fail_virtual; - } - - DUK_DDD(DUK_DDDPRINT("update existing property setter")); - DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); - - tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx); - DUK_UNREF(tmp); - DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set); - DUK_HOBJECT_INCREF_ALLOWNULL(thr, set); - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */ - } - if (has_get) { - duk_hobject *tmp; - - if (curr.e_idx < 0) { - goto fail_virtual; - } - - DUK_DDD(DUK_DDDPRINT("update existing property getter")); - DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); - - tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx); - DUK_UNREF(tmp); - DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get); - DUK_HOBJECT_INCREF_ALLOWNULL(thr, get); - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */ - } - if (has_value) { - duk_tval *tv1, *tv2; - - DUK_DDD(DUK_DDDPRINT("update existing property value")); - - if (curr.e_idx >= 0) { - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); - tv2 = duk_require_tval(thr, idx_value); - tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx); - DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate e_idx */ - } else { - DUK_ASSERT(curr.a_idx < 0); /* array part case handled comprehensively previously */ - - DUK_DD(DUK_DDPRINT("Object.defineProperty(), value update for virtual property")); - /* XXX: Uint8Array and other typed array virtual writes not currently - * handled. - */ - if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { - duk_harray *a; - a = (duk_harray *) obj; - DUK_DD(DUK_DDPRINT("Object.defineProperty() value update for duk_harray .length -> %ld", (long) arrlen_new_len)); - DUK_ASSERT_HARRAY_VALID(a); - a->length = arrlen_new_len; - } else { - goto fail_virtual; /* should not happen */ - } - } - } - - /* - * Standard algorithm succeeded without errors, check for exotic post-behaviors. - * - * Arguments exotic behavior in E5 Section 10.6 occurs after the standard - * [[DefineOwnProperty]] has completed successfully. - * - * Array exotic behavior in E5 Section 15.4.5.1 is implemented partly - * prior to the default [[DefineOwnProperty]], but: - * - for an array index key (e.g. "10") the final 'length' update occurs here - * - for 'length' key the element deletion and 'length' update occurs here - */ - - success_exotics: - - /* curr.a_idx or curr.e_idx may have been invalidated by side effects - * above. - */ - - /* [obj key desc value get set curr_value] */ - - if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { - duk_harray *a; - - a = (duk_harray *) obj; - DUK_ASSERT_HARRAY_VALID(a); - - if (arridx_new_array_length > 0) { - /* - * Note: zero works as a "no update" marker because the new length - * can never be zero after a new property is written. - */ - - /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */ - - DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld", - (long) arridx_new_array_length)); - - a->length = arridx_new_array_length; - } - - if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) { - /* - * E5 Section 15.4.5.1, steps 3.k - 3.n. The order at the end combines - * the error case 3.l.iii and the success case 3.m-3.n. - */ - - /* XXX: investigate whether write protect can be handled above, if we - * just update length here while ignoring its protected status - */ - - duk_uint32_t result_len; - duk_bool_t rc; - - DUK_DDD(DUK_DDDPRINT("defineProperty successful, key is 'length', exotic array behavior, " - "doing array element deletion and length update")); - - rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, force_flag, &result_len); - - /* update length (curr points to length, and we assume it's still valid) */ - DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len); - - a->length = result_len; - - if (pending_write_protect) { - DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)")); - DUK_HARRAY_SET_LENGTH_NONWRITABLE(a); - } - - /* XXX: shrink array allocation or entries compaction here? */ - if (!rc) { - DUK_DD(DUK_DDPRINT("array length write only partially successful")); - goto fail_not_configurable; - } - } - } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) { - duk_hobject *map; - duk_hobject *varenv; - - DUK_ASSERT(arridx_new_array_length == 0); - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); /* traits are separate; in particular, arguments not an array */ - - map = NULL; - varenv = NULL; - if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) { - goto success_no_exotics; - } - DUK_ASSERT(map != NULL); - DUK_ASSERT(varenv != NULL); - - /* [obj key desc value get set curr_value varname] */ - - if (has_set || has_get) { - /* = IsAccessorDescriptor(Desc) */ - DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' " - "changed to an accessor, delete arguments binding")); - - (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */ - } else { - /* Note: this order matters (final value before deleting map entry must be done) */ - DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', " - "check for value update / binding deletion")); - - if (has_value) { - duk_hstring *varname; - - DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', " - "update bound value (variable/argument)")); - - varname = duk_require_hstring(thr, -1); - DUK_ASSERT(varname != NULL); - - DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; " - "key=%!O, varname=%!O, value=%!T", - (duk_heaphdr *) key, - (duk_heaphdr *) varname, - (duk_tval *) duk_require_tval(thr, idx_value))); - - /* strict flag for putvar comes from our caller (currently: fixed) */ - duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, idx_value), 1 /*throw_flag*/); - } - if (has_writable && !is_writable) { - DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', " - "changed to non-writable, delete arguments binding")); - - (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */ - } - } - - /* 'varname' is in stack in this else branch, leaving an unbalanced stack below, - * but this doesn't matter now. - */ - } - - success_no_exotics: - /* Some code paths use NORZ macros for simplicity, ensure refzero - * handling is completed. - */ - DUK_REFZERO_CHECK_SLOW(thr); - return 1; - - fail_not_extensible: - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE); - } - return 0; - - fail_virtual: /* just use the same "not configurable" error message" */ - fail_not_configurable: - if (throw_flag) { - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); - } - return 0; -} - -/* - * Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable(). - */ - -DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags) { - duk_hstring *h_v; - duk_hobject *h_obj; - duk_propdesc desc; - duk_bool_t ret; - - /* coercion order matters */ - h_v = duk_to_hstring_acceptsymbol(thr, 0); - DUK_ASSERT(h_v != NULL); - - h_obj = duk_push_this_coercible_to_object(thr); - DUK_ASSERT(h_obj != NULL); - - ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */ - - duk_push_boolean(thr, ret && ((desc.flags & required_desc_flags) == required_desc_flags)); - return 1; -} - -/* - * Object.seal() and Object.freeze() (E5 Sections 15.2.3.8 and 15.2.3.9) - * - * Since the algorithms are similar, a helper provides both functions. - * Freezing is essentially sealing + making plain properties non-writable. - * - * Note: virtual (non-concrete) properties which are non-configurable but - * writable would pose some problems, but such properties do not currently - * exist (all virtual properties are non-configurable and non-writable). - * If they did exist, the non-configurability does NOT prevent them from - * becoming non-writable. However, this change should be recorded somehow - * so that it would turn up (e.g. when getting the property descriptor), - * requiring some additional flags in the object. - */ - -DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze) { - duk_uint_fast32_t i; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(obj != NULL); - - DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); - -#if defined(DUK_USE_ROM_OBJECTS) - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { - DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject")); - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); - } -#endif - - /* - * Abandon array part because all properties must become non-configurable. - * Note that this is now done regardless of whether this is always the case - * (skips check, but performance problem if caller would do this many times - * for the same object; not likely). - */ - - duk__abandon_array_checked(thr, obj); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) == 0); - - for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { - duk_uint8_t *fp; - - /* since duk__abandon_array_checked() causes a resize, there should be no gaps in keys */ - DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != NULL); - - /* avoid multiple computations of flags address; bypasses macros */ - fp = DUK_HOBJECT_E_GET_FLAGS_PTR(thr->heap, obj, i); - if (is_freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) { - *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE); - } else { - *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE; - } - } - - DUK_HOBJECT_CLEAR_EXTENSIBLE(obj); - - /* no need to compact since we already did that in duk__abandon_array_checked() - * (regardless of whether an array part existed or not. - */ - - return; -} - -/* - * Object.isSealed() and Object.isFrozen() (E5 Sections 15.2.3.11, 15.2.3.13) - * - * Since the algorithms are similar, a helper provides both functions. - * Freezing is essentially sealing + making plain properties non-writable. - * - * Note: all virtual (non-concrete) properties are currently non-configurable - * and non-writable (and there are no accessor virtual properties), so they don't - * need to be considered here now. - */ - -DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) { - duk_uint_fast32_t i; - - DUK_ASSERT(obj != NULL); - DUK_UNREF(thr); - - /* Note: no allocation pressure, no need to check refcounts etc */ - - /* must not be extensible */ - if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) { - return 0; - } - - /* all virtual properties are non-configurable and non-writable */ - - /* entry part must not contain any configurable properties, or - * writable properties (if is_frozen). - */ - for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { - duk_small_uint_t flags; - - if (!DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i)) { - continue; - } - - /* avoid multiple computations of flags address; bypasses macros */ - flags = (duk_small_uint_t) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i); - - if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) { - return 0; - } - if (is_frozen && - !(flags & DUK_PROPDESC_FLAG_ACCESSOR) && - (flags & DUK_PROPDESC_FLAG_WRITABLE)) { - return 0; - } - } - - /* array part must not contain any non-unused properties, as they would - * be configurable and writable. - */ - for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { - duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); - if (!DUK_TVAL_IS_UNUSED(tv)) { - return 0; - } - } - - return 1; -} - -/* - * Object.preventExtensions() and Object.isExtensible() (E5 Sections 15.2.3.10, 15.2.3.13) - * - * Not needed, implemented by macros DUK_HOBJECT_{HAS,CLEAR,SET}_EXTENSIBLE - * and the Object built-in bindings. - */ - -/* automatic undefs */ -#undef DUK__HASH_DELETED -#undef DUK__HASH_UNUSED -#undef DUK__NO_ARRAY_INDEX -#undef DUK__VALSTACK_PROXY_LOOKUP -#undef DUK__VALSTACK_SPACE -#line 1 "duk_hstring_misc.c" -/* - * Misc support functions - */ - -/* #include duk_internal.h -> already included */ - -/* - * duk_hstring charCodeAt, with and without surrogate awareness - */ - -DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware) { - duk_uint32_t boff; - const duk_uint8_t *p, *p_start, *p_end; - duk_ucodepoint_t cp1; - duk_ucodepoint_t cp2; - - /* Caller must check character offset to be inside the string. */ - DUK_ASSERT(thr != NULL); - DUK_ASSERT(h != NULL); - DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */ - DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); - - boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos); - DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O", - (long) pos, (long) boff, (duk_heaphdr *) h)); - DUK_ASSERT_DISABLE(boff >= 0); - DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h)); - - p_start = DUK_HSTRING_GET_DATA(h); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h); - p = p_start + boff; - DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p", - (const void *) p_start, (const void *) p_end, - (const void *) p)); - - /* For invalid UTF-8 (never happens for standard Ecmascript strings) - * return U+FFFD replacement character. - */ - if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp1)) { - if (surrogate_aware && cp1 >= 0xd800UL && cp1 <= 0xdbffUL) { - /* The decode helper is memory safe even if 'cp1' was - * decoded at the end of the string and 'p' is no longer - * within string memory range. - */ - cp2 = 0; /* If call fails, this is left untouched and won't match cp2 check. */ - (void) duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp2); - if (cp2 >= 0xdc00UL && cp2 <= 0xdfffUL) { - cp1 = (duk_ucodepoint_t) (((cp1 - 0xd800UL) << 10) + (cp2 - 0xdc00UL) + 0x10000UL); - } - } - } else { - cp1 = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; - } - - return cp1; -} - -/* - * duk_hstring charlen, when lazy charlen disabled - */ - -#if !defined(DUK_USE_HSTRING_LAZY_CLEN) -#if !defined(DUK_USE_HSTRING_CLEN) -#error non-lazy duk_hstring charlen but DUK_USE_HSTRING_CLEN not set -#endif -DUK_INTERNAL void duk_hstring_init_charlen(duk_hstring *h) { - duk_uint32_t clen; - - DUK_ASSERT(h != NULL); - DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(h)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); - - clen = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); -#if defined(DUK_USE_STRLEN16) - DUK_ASSERT(clen <= 0xffffUL); /* Bytelength checked during interning. */ - h->clen16 = (duk_uint16_t) clen; -#else - h->clen = (duk_uint32_t) clen; -#endif - if (DUK_LIKELY(clen == DUK_HSTRING_GET_BYTELEN(h))) { - DUK_HSTRING_SET_ASCII(h); - } -} - -DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { -#if defined(DUK_USE_STRLEN16) - return h->clen16; -#else - return h->clen; -#endif -} -#endif /* !DUK_USE_HSTRING_LAZY_CLEN */ - -/* - * duk_hstring charlen, when lazy charlen enabled - */ - -#if defined(DUK_USE_HSTRING_LAZY_CLEN) -#if defined(DUK_USE_HSTRING_CLEN) -DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { - duk_size_t res; - - DUK_ASSERT(h->clen == 0); /* Checked by caller. */ - -#if defined(DUK_USE_ROM_STRINGS) - /* ROM strings have precomputed clen, but if the computed clen is zero - * we can still come here and can't write anything. - */ - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { - return 0; - } -#endif - - res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); -#if defined(DUK_USE_STRLEN16) - DUK_ASSERT(res <= 0xffffUL); /* Bytelength checked during interning. */ - h->clen16 = (duk_uint16_t) res; -#else - h->clen = (duk_uint32_t) res; -#endif - if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { - DUK_HSTRING_SET_ASCII(h); - } - return res; -} -#else /* DUK_USE_HSTRING_CLEN */ -DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { - if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) { - /* Most practical strings will go here. */ - return DUK_HSTRING_GET_BYTELEN(h); - } else { - /* ASCII flag is lazy, so set it here. */ - duk_size_t res; - - /* XXX: here we could use the strcache to speed up the - * computation (matters for 'i < str.length' loops). - */ - - res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); - -#if defined(DUK_USE_ROM_STRINGS) - if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { - /* For ROM strings, can't write anything; ASCII flag - * is preset so we don't need to update it. - */ - return res; - } -#endif - if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { - DUK_HSTRING_SET_ASCII(h); - } - return res; - } -} -#endif /* DUK_USE_HSTRING_CLEN */ - -#if defined(DUK_USE_HSTRING_CLEN) -DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { -#if defined(DUK_USE_STRLEN16) - if (DUK_LIKELY(h->clen16 != 0)) { - return h->clen16; - } -#else - if (DUK_LIKELY(h->clen != 0)) { - return h->clen; - } -#endif - return duk__hstring_get_charlen_slowpath(h); -} -#else /* DUK_USE_HSTRING_CLEN */ -DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { - /* Always use slow path. */ - return duk__hstring_get_charlen_slowpath(h); -} -#endif /* DUK_USE_HSTRING_CLEN */ -#endif /* DUK_USE_HSTRING_LAZY_CLEN */ - -/* - * Compare duk_hstring to an ASCII cstring. - */ - -DUK_INTERNAL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr) { - duk_size_t len; - - DUK_ASSERT(h != NULL); - DUK_ASSERT(cstr != NULL); - - len = DUK_STRLEN(cstr); - if (len != DUK_HSTRING_GET_BYTELEN(h)) { - return 0; - } - if (DUK_MEMCMP((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) { - return 1; - } - return 0; -} -#line 1 "duk_hthread_alloc.c" -/* - * duk_hthread allocation and freeing. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Allocate initial stacks for a thread. Note that 'thr' must be reachable - * as a garbage collection may be triggered by the allocation attempts. - * Returns zero (without leaking memory) if init fails. - */ - -DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) { - duk_size_t alloc_size; - duk_size_t i; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->valstack == NULL); - DUK_ASSERT(thr->valstack_end == NULL); - DUK_ASSERT(thr->valstack_alloc_end == NULL); - DUK_ASSERT(thr->valstack_bottom == NULL); - DUK_ASSERT(thr->valstack_top == NULL); - DUK_ASSERT(thr->callstack_curr == NULL); - - /* valstack */ - DUK_ASSERT(DUK_VALSTACK_API_ENTRY_MINIMUM <= DUK_VALSTACK_INITIAL_SIZE); - alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE; - thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size); - if (!thr->valstack) { - goto fail; - } - DUK_MEMZERO(thr->valstack, alloc_size); - thr->valstack_end = thr->valstack + DUK_VALSTACK_API_ENTRY_MINIMUM; - thr->valstack_alloc_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE; - thr->valstack_bottom = thr->valstack; - thr->valstack_top = thr->valstack; - - for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) { - DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]); - } - - return 1; - - fail: - DUK_FREE(heap, thr->valstack); - DUK_ASSERT(thr->callstack_curr == NULL); - - thr->valstack = NULL; - return 0; -} - -/* For indirect allocs. */ - -DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) { - duk_hthread *thr = (duk_hthread *) ud; - DUK_UNREF(heap); - return (void *) thr->valstack; -} -#line 1 "duk_hthread_builtins.c" -/* - * Initialize built-in objects. Current thread must have a valstack - * and initialization errors may longjmp, so a setjmp() catch point - * must exist. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Encoding constants, must match genbuiltins.py - */ - -#define DUK__PROP_FLAGS_BITS 3 -#define DUK__LENGTH_PROP_BITS 3 -#define DUK__NARGS_BITS 3 -#define DUK__PROP_TYPE_BITS 3 - -#define DUK__NARGS_VARARGS_MARKER 0x07 - -#define DUK__PROP_TYPE_DOUBLE 0 -#define DUK__PROP_TYPE_STRING 1 -#define DUK__PROP_TYPE_STRIDX 2 -#define DUK__PROP_TYPE_BUILTIN 3 -#define DUK__PROP_TYPE_UNDEFINED 4 -#define DUK__PROP_TYPE_BOOLEAN_TRUE 5 -#define DUK__PROP_TYPE_BOOLEAN_FALSE 6 -#define DUK__PROP_TYPE_ACCESSOR 7 - -/* - * Create built-in objects by parsing an init bitstream generated - * by genbuiltins.py. - */ - -#if defined(DUK_USE_ROM_OBJECTS) -#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT) -DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) { - duk_hobject *h_global; -#if defined(DUK_USE_ROM_GLOBAL_CLONE) - duk_hobject *h_oldglobal; - duk_uint8_t *props; - duk_size_t alloc_size; -#endif - duk_hobject *h_objenv; - - /* XXX: refactor into internal helper, duk_clone_hobject() */ - -#if defined(DUK_USE_ROM_GLOBAL_INHERIT) - /* Inherit from ROM-based global object: less RAM usage, less transparent. */ - h_global = duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_GLOBAL); - DUK_ASSERT(h_global != NULL); -#elif defined(DUK_USE_ROM_GLOBAL_CLONE) - /* Clone the properties of the ROM-based global object to create a - * fully RAM-based global object. Uses more memory than the inherit - * model but more compliant. - */ - h_global = duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_OBJECT_PROTOTYPE); - DUK_ASSERT(h_global != NULL); - h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL]; - DUK_ASSERT(h_oldglobal != NULL); - - /* Copy the property table verbatim; this handles attributes etc. - * For ROM objects it's not necessary (or possible) to update - * refcounts so leave them as is. - */ - alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal); - DUK_ASSERT(alloc_size > 0); - props = DUK_ALLOC_CHECKED(thr, alloc_size); - DUK_ASSERT(props != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL); - DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size); - - /* XXX: keep property attributes or tweak them here? - * Properties will now be non-configurable even when they're - * normally configurable for the global object. - */ - - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL); - DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props); - DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal)); - DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal)); - DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal)); - DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal)); -#else -#error internal error in config defines -#endif - - duk_hobject_compact_props(thr, h_global); - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */ - thr->builtins[DUK_BIDX_GLOBAL] = h_global; - DUK_HOBJECT_INCREF(thr, h_global); - DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global)); - - /* Create a fresh object environment for the global scope. This is - * needed so that the global scope points to the newly created RAM-based - * global object. - */ - h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); - DUK_ASSERT(h_objenv != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL); - duk_push_hobject(thr, h_objenv); - - DUK_ASSERT(h_global != NULL); - ((duk_hobjenv *) h_objenv)->target = h_global; - DUK_HOBJECT_INCREF(thr, h_global); - DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0); - - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */ - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv; - DUK_HOBJECT_INCREF(thr, h_objenv); - DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv)); - - DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) h_objenv); - - duk_pop_2(thr); /* Pop global object and global env. */ -} -#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */ - -DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { - /* Setup builtins from ROM objects. All heaps/threads will share - * the same readonly objects. - */ - duk_small_uint_t i; - - for (i = 0; i < DUK_NUM_BUILTINS; i++) { - duk_hobject *h; - h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]); - DUK_ASSERT(h != NULL); - thr->builtins[i] = h; - } - -#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT) - /* By default the global object is read-only which is often much - * more of an issue than having read-only built-in objects (like - * RegExp, Date, etc). Use a RAM-based copy of the global object - * and the global environment object for convenience. - */ - duk__duplicate_ram_global_object(thr); -#endif -} -#else /* DUK_USE_ROM_OBJECTS */ -DUK_LOCAL void duk__push_stridx(duk_hthread *thr, duk_bitdecoder_ctx *bd) { - duk_small_uint_t n; - - n = (duk_small_uint_t) duk_bd_decode_varuint(bd); - DUK_ASSERT_DISABLE(n >= 0); /* unsigned */ - DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS); - duk_push_hstring_stridx(thr, n); -} -DUK_LOCAL void duk__push_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) { - /* XXX: built-ins data could provide a maximum length that is - * actually needed; bitpacked max length is now 256 bytes. - */ - duk_uint8_t tmp[DUK_BD_BITPACKED_STRING_MAXLEN]; - duk_small_uint_t len; - - len = duk_bd_decode_bitpacked_string(bd, tmp); - duk_push_lstring(thr, (const char *) tmp, (duk_size_t) len); -} -DUK_LOCAL void duk__push_stridx_or_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) { - duk_small_uint_t n; - - n = (duk_small_uint_t) duk_bd_decode_varuint(bd); - if (n == 0) { - duk__push_string(thr, bd); - } else { - n--; - DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS); - duk_push_hstring_stridx(thr, n); - } -} -DUK_LOCAL void duk__push_double(duk_hthread *thr, duk_bitdecoder_ctx *bd) { - duk_double_union du; - duk_small_uint_t i; - - for (i = 0; i < 8; i++) { - /* Encoding endianness must match target memory layout, - * build scripts and genbuiltins.py must ensure this. - */ - du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8); - } - - duk_push_number(thr, du.d); /* push operation normalizes NaNs */ -} - -DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { - duk_bitdecoder_ctx bd_ctx; - duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */ - duk_hobject *h; - duk_small_uint_t i, j; - - DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS)); - - DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); - bd->data = (const duk_uint8_t *) duk_builtins_data; - bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH; - - /* - * First create all built-in bare objects on the empty valstack. - * - * Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value - * stack indices matching their eventual thr->builtins[] index. - * - * Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS] - * will exist on the value stack during init but won't be placed - * into thr->builtins[]. These are objects referenced in some way - * from thr->builtins[] roots but which don't need to be indexed by - * Duktape through thr->builtins[] (e.g. user custom objects). - * - * Internal prototypes will be incorrect (NULL) at this stage. - */ - - duk_require_stack(thr, DUK_NUM_ALL_BUILTINS); - - DUK_DD(DUK_DDPRINT("create empty built-ins")); - DUK_ASSERT_TOP(thr, 0); - for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { - duk_small_uint_t class_num; - duk_small_int_t len = -1; /* must be signed */ - - class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd); - len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); - - if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { - duk_small_uint_t natidx; - duk_small_int_t c_nargs; /* must hold DUK_VARARGS */ - duk_c_function c_func; - duk_int16_t magic; - - DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len)); - DUK_ASSERT(len >= 0); - - natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd); - DUK_ASSERT(natidx != 0); - c_func = duk_bi_native_functions[natidx]; - DUK_ASSERT(c_func != NULL); - - c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/); - if (c_nargs == DUK__NARGS_VARARGS_MARKER) { - c_nargs = DUK_VARARGS; - } - - /* XXX: set magic directly here? (it could share the c_nargs arg) */ - (void) duk_push_c_function_builtin(thr, c_func, c_nargs); - h = duk_known_hobject(thr, -1); - - /* Currently all built-in native functions are strict. - * duk_push_c_function() now sets strict flag, so - * assert for it. - */ - DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h)); - - /* XXX: function properties */ - - duk__push_stridx_or_string(thr, bd); -#if defined(DUK_USE_FUNC_NAME_PROPERTY) - duk_xdef_prop_stridx_short(thr, - -2, - DUK_STRIDX_NAME, - DUK_PROPDESC_FLAGS_C); -#else - duk_pop(thr); /* Not very ideal but good enough for now. */ -#endif - - /* Almost all global level Function objects are constructable - * but not all: Function.prototype is a non-constructable, - * callable Function. - */ - if (duk_bd_decode_flag(bd)) { - DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h)); - } else { - DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h); - } - - /* Cast converts magic to 16-bit signed value */ - magic = (duk_int16_t) duk_bd_decode_varuint(bd); - ((duk_hnatfunc *) h)->magic = magic; - } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) { - duk_push_array(thr); - } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) { - duk_hobjenv *env; - duk_hobject *global; - - DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV); - DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL); - - env = duk_hobjenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); - DUK_ASSERT(env->target == NULL); - duk_push_hobject(thr, (duk_hobject *) env); - - global = duk_known_hobject(thr, DUK_BIDX_GLOBAL); - DUK_ASSERT(global != NULL); - env->target = global; - DUK_HOBJECT_INCREF(thr, global); - DUK_ASSERT(env->has_this == 0); - - DUK_ASSERT_HOBJENV_VALID(env); - } else { - DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV); - - (void) duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_EXTENSIBLE, - -1); /* no prototype or class yet */ - - } - - h = duk_known_hobject(thr, -1); - DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num); - - if (i < DUK_NUM_BUILTINS) { - thr->builtins[i] = h; - DUK_HOBJECT_INCREF(thr, &h->hdr); - } - - if (len >= 0) { - /* In ES2015+ built-in function object .length property - * has property attributes C (configurable only): - * http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-standard-built-in-objects - * - * Array.prototype remains an Array instance in ES2015+ - * and its length has attributes W (writable only). - * Because .length is now virtual for duk_harray, it is - * not encoded explicitly in init data. - */ - - DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY); /* .length is virtual */ - duk_push_int(thr, len); - duk_xdef_prop_stridx_short(thr, - -2, - DUK_STRIDX_LENGTH, - DUK_PROPDESC_FLAGS_C); - } - - /* enable exotic behaviors last */ - - if (class_num == DUK_HOBJECT_CLASS_ARRAY) { - DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)); /* set by duk_push_array() */ - } - if (class_num == DUK_HOBJECT_CLASS_STRING) { - DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h); - } - - /* some assertions */ - - DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h)); - /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */ - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h)); - DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h)); - /* DUK_HOBJECT_FLAG_NATFUNC varies */ - DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h)); - DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY); - /* DUK_HOBJECT_FLAG_STRICT varies */ - DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */ - DUK_HOBJECT_HAS_NEWENV(h)); - DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); - DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); - /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */ - /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */ - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)); - - DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len)); - } - - /* - * Then decode the builtins init data (see genbuiltins.py) to - * init objects. Internal prototypes are set at this stage, - * with thr->builtins[] populated. - */ - - DUK_DD(DUK_DDPRINT("initialize built-in object properties")); - for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { - duk_small_uint_t t; - duk_small_uint_t num; - - DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i)); - h = duk_known_hobject(thr, (duk_idx_t) i); - - t = (duk_small_uint_t) duk_bd_decode_varuint(bd); - if (t > 0) { - t--; - DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t)); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(thr, (duk_idx_t) t)); - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - /* Standard native built-ins cannot inherit from - * %NativeFunctionPrototype%, they are required to - * inherit from Function.prototype directly. - */ - DUK_ASSERT(thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE] != NULL); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); - } - - t = (duk_small_uint_t) duk_bd_decode_varuint(bd); - if (t > 0) { - /* 'prototype' property for all built-in objects (which have it) has attributes: - * [[Writable]] = false, - * [[Enumerable]] = false, - * [[Configurable]] = false - */ - t--; - DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t)); - duk_dup(thr, (duk_idx_t) t); - duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_NONE); - } - - t = (duk_small_uint_t) duk_bd_decode_varuint(bd); - if (t > 0) { - /* 'constructor' property for all built-in objects (which have it) has attributes: - * [[Writable]] = true, - * [[Enumerable]] = false, - * [[Configurable]] = true - */ - t--; - DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t)); - duk_dup(thr, (duk_idx_t) t); - duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); - } - - /* normal valued properties */ - num = (duk_small_uint_t) duk_bd_decode_varuint(bd); - DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num)); - for (j = 0; j < num; j++) { - duk_small_uint_t defprop_flags; - - duk__push_stridx_or_string(thr, bd); - - /* - * Property attribute defaults are defined in E5 Section 15 (first - * few pages); there is a default for all properties and a special - * default for 'length' properties. Variation from the defaults is - * signaled using a single flag bit in the bitstream. - */ - - if (duk_bd_decode_flag(bd)) { - defprop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS); - } else { - defprop_flags = DUK_PROPDESC_FLAGS_WC; - } - defprop_flags |= DUK_DEFPROP_FORCE | - DUK_DEFPROP_HAVE_VALUE | - DUK_DEFPROP_HAVE_WRITABLE | - DUK_DEFPROP_HAVE_ENUMERABLE | - DUK_DEFPROP_HAVE_CONFIGURABLE; /* Defaults for data properties. */ - - /* The writable, enumerable, configurable flags in prop_flags - * match both duk_def_prop() and internal property flags. - */ - DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE); - DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE); - DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE); - - t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS); - - DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld", - (long) i, (long) j, duk_get_tval(thr, -1), (unsigned long) defprop_flags, (long) t)); - - switch (t) { - case DUK__PROP_TYPE_DOUBLE: { - duk__push_double(thr, bd); - break; - } - case DUK__PROP_TYPE_STRING: { - duk__push_string(thr, bd); - break; - } - case DUK__PROP_TYPE_STRIDX: { - duk__push_stridx(thr, bd); - break; - } - case DUK__PROP_TYPE_BUILTIN: { - duk_small_uint_t bidx; - - bidx = (duk_small_uint_t) duk_bd_decode_varuint(bd); - duk_dup(thr, (duk_idx_t) bidx); - break; - } - case DUK__PROP_TYPE_UNDEFINED: { - duk_push_undefined(thr); - break; - } - case DUK__PROP_TYPE_BOOLEAN_TRUE: { - duk_push_true(thr); - break; - } - case DUK__PROP_TYPE_BOOLEAN_FALSE: { - duk_push_false(thr); - break; - } - case DUK__PROP_TYPE_ACCESSOR: { - duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode_varuint(bd); - duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode_varuint(bd); - duk_small_uint_t accessor_magic = (duk_small_uint_t) duk_bd_decode_varuint(bd); - duk_c_function c_func_getter; - duk_c_function c_func_setter; - - DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx", - (long) i, duk_get_tval(thr, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) defprop_flags)); - - c_func_getter = duk_bi_native_functions[natidx_getter]; - if (c_func_getter != NULL) { - duk_push_c_function_builtin_noconstruct(thr, c_func_getter, 0); /* always 0 args */ - duk_set_magic(thr, -1, (duk_int_t) accessor_magic); - defprop_flags |= DUK_DEFPROP_HAVE_GETTER; - } - c_func_setter = duk_bi_native_functions[natidx_setter]; - if (c_func_setter != NULL) { - duk_push_c_function_builtin_noconstruct(thr, c_func_setter, 1); /* always 1 arg */ - duk_set_magic(thr, -1, (duk_int_t) accessor_magic); - defprop_flags |= DUK_DEFPROP_HAVE_SETTER; - } - - /* Writable flag doesn't make sense for an accessor. */ - DUK_ASSERT((defprop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */ - - defprop_flags &= ~(DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE); - defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE; - break; - } - default: { - /* exhaustive */ - DUK_UNREACHABLE(); - } - } - - duk_def_prop(thr, (duk_idx_t) i, defprop_flags); - DUK_ASSERT_TOP(thr, DUK_NUM_ALL_BUILTINS); - } - - /* native function properties */ - num = (duk_small_uint_t) duk_bd_decode_varuint(bd); - DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num)); - for (j = 0; j < num; j++) { - duk_hstring *h_key; - duk_small_uint_t natidx; - duk_int_t c_nargs; /* must hold DUK_VARARGS */ - duk_small_uint_t c_length; - duk_int16_t magic; - duk_c_function c_func; - duk_hnatfunc *h_func; -#if defined(DUK_USE_LIGHTFUNC_BUILTINS) - duk_small_int_t lightfunc_eligible; -#endif - - duk__push_stridx_or_string(thr, bd); - h_key = duk_known_hstring(thr, -1); - DUK_UNREF(h_key); - natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd); - - c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS); - c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_uint32_t) c_length /*def_value*/); - if (c_nargs == DUK__NARGS_VARARGS_MARKER) { - c_nargs = DUK_VARARGS; - } - - c_func = duk_bi_native_functions[natidx]; - - DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld", - (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length, - (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs))); - - /* Cast converts magic to 16-bit signed value */ - magic = (duk_int16_t) duk_bd_decode_varuint(bd); - -#if defined(DUK_USE_LIGHTFUNC_BUILTINS) - lightfunc_eligible = - ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) && - (c_length <= DUK_LFUNC_LENGTH_MAX) && - (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX); - - /* These functions have trouble working as lightfuncs. - * Some of them have specific asserts and some may have - * additional properties (e.g. 'require.id' may be written). - */ - if (c_func == duk_bi_global_object_eval) { - lightfunc_eligible = 0; - } -#if defined(DUK_USE_COROUTINE_SUPPORT) - if (c_func == duk_bi_thread_yield || - c_func == duk_bi_thread_resume) { - lightfunc_eligible = 0; - } -#endif - if (c_func == duk_bi_function_prototype_call || - c_func == duk_bi_function_prototype_apply || - c_func == duk_bi_reflect_apply || - c_func == duk_bi_reflect_construct) { - lightfunc_eligible = 0; - } - - if (lightfunc_eligible) { - duk_tval tv_lfunc; - duk_small_uint_t lf_nargs = (duk_small_uint_t) (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs); - duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs); - DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags); - duk_push_tval(thr, &tv_lfunc); - DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(thr, -1))); - goto lightfunc_skip; - } - - DUK_D(DUK_DPRINT("built-in function NOT ELIGIBLE as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic)); -#endif /* DUK_USE_LIGHTFUNC_BUILTINS */ - - /* [ (builtin objects) name ] */ - - duk_push_c_function_builtin_noconstruct(thr, c_func, c_nargs); - h_func = duk_known_hnatfunc(thr, -1); - DUK_UNREF(h_func); - - /* XXX: add into init data? */ - - /* Special call handling, not described in init data. */ - if (c_func == duk_bi_global_object_eval || - c_func == duk_bi_function_prototype_call || - c_func == duk_bi_function_prototype_apply || - c_func == duk_bi_reflect_apply || - c_func == duk_bi_reflect_construct) { - DUK_HOBJECT_SET_SPECIAL_CALL((duk_hobject *) h_func); - } - - /* Currently all built-in native functions are strict. - * This doesn't matter for many functions, but e.g. - * String.prototype.charAt (and other string functions) - * rely on being strict so that their 'this' binding is - * not automatically coerced. - */ - DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func); - - /* No built-in functions are constructable except the top - * level ones (Number, etc). - */ - DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func)); - - /* XXX: any way to avoid decoding magic bit; there are quite - * many function properties and relatively few with magic values. - */ - h_func->magic = magic; - - /* [ (builtin objects) name func ] */ - - duk_push_uint(thr, c_length); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); - - duk_dup_m2(thr); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); - - /* XXX: other properties of function instances; 'arguments', 'caller'. */ - - DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T", - (long) i, (long) j, (duk_tval *) duk_get_tval(thr, -1))); - - /* [ (builtin objects) name func ] */ - - /* - * The default property attributes are correct for all - * function valued properties of built-in objects now. - */ - -#if defined(DUK_USE_LIGHTFUNC_BUILTINS) - lightfunc_skip: -#endif - - /* XXX: So far all ES builtins are 'wc' but e.g. - * performance.now() should be 'wec'. - */ - duk_xdef_prop(thr, (duk_idx_t) i, DUK_PROPDESC_FLAGS_WC); - - /* [ (builtin objects) ] */ - } - } - - /* - * Special post-tweaks, for cases not covered by the init data format. - * - * - Set Date.prototype.toGMTString to Date.prototype.toUTCString. - * toGMTString is required to have the same Function object as - * toUTCString in E5 Section B.2.6. Note that while Smjs respects - * this, V8 does not (the Function objects are distinct). - * - * - Make DoubleError non-extensible. - * - * - Add info about most important effective compile options to Duktape. - * - * - Possibly remove some properties (values or methods) which are not - * desirable with current feature options but are not currently - * conditional in init data. - */ - -#if defined(DUK_USE_DATE_BUILTIN) - duk_get_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING); - duk_xdef_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC); -#endif - - h = duk_known_hobject(thr, DUK_BIDX_DOUBLE_ERROR); - DUK_HOBJECT_CLEAR_EXTENSIBLE(h); - -#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY) - DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features")); - (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW); -#endif - -#if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF) - DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features")); - (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW); -#endif - - /* XXX: relocate */ - duk_push_string(thr, - /* Endianness indicator */ -#if defined(DUK_USE_INTEGER_LE) - "l" -#elif defined(DUK_USE_INTEGER_BE) - "b" -#elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */ - "m" -#else - "?" -#endif -#if defined(DUK_USE_DOUBLE_LE) - "l" -#elif defined(DUK_USE_DOUBLE_BE) - "b" -#elif defined(DUK_USE_DOUBLE_ME) - "m" -#else - "?" -#endif - " " - /* Packed or unpacked tval */ -#if defined(DUK_USE_PACKED_TVAL) - "p" -#else - "u" -#endif -#if defined(DUK_USE_FASTINT) - "f" -#endif - " " - /* Low memory options */ -#if defined(DUK_USE_STRTAB_PTRCOMP) - "s" -#endif -#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16) - "n" -#endif -#if defined(DUK_USE_HEAPPTR16) - "h" -#endif -#if defined(DUK_USE_DATAPTR16) - "d" -#endif -#if defined(DUK_USE_FUNCPTR16) - "f" -#endif -#if defined(DUK_USE_REFCOUNT16) - "R" -#endif -#if defined(DUK_USE_STRHASH16) - "H" -#endif -#if defined(DUK_USE_STRLEN16) - "S" -#endif -#if defined(DUK_USE_BUFLEN16) - "B" -#endif -#if defined(DUK_USE_OBJSIZES16) - "O" -#endif -#if defined(DUK_USE_LIGHTFUNC_BUILTINS) - "L" -#endif -#if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS) - /* XXX: This won't be shown in practice now - * because this code is not run when builtins - * are in ROM. - */ - "Z" -#endif - " " - /* Object property allocation layout */ -#if defined(DUK_USE_HOBJECT_LAYOUT_1) - "p1" -#elif defined(DUK_USE_HOBJECT_LAYOUT_2) - "p2" -#elif defined(DUK_USE_HOBJECT_LAYOUT_3) - "p3" -#else - "p?" -#endif - " " - /* Alignment guarantee */ -#if (DUK_USE_ALIGN_BY == 4) - "a4" -#elif (DUK_USE_ALIGN_BY == 8) - "a8" -#elif (DUK_USE_ALIGN_BY == 1) - "a1" -#else -#error invalid DUK_USE_ALIGN_BY -#endif - " " - /* Architecture, OS, and compiler strings */ - DUK_USE_ARCH_STRING - " " - DUK_USE_OS_STRING - " " - DUK_USE_COMPILER_STRING); - duk_xdef_prop_stridx_short(thr, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC); - - /* - * Since built-ins are not often extended, compact them. - */ - - DUK_DD(DUK_DDPRINT("compact built-ins")); - for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { - duk_hobject_compact_props(thr, duk_known_hobject(thr, (duk_idx_t) i)); - } - - DUK_D(DUK_DPRINT("INITBUILTINS END")); - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) - for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { - DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO", - (long) i, (duk_heaphdr *) duk_require_hobject(thr, i))); - } -#endif - - /* - * Pop built-ins from stack: they are now INCREF'd and - * reachable from the builtins[] array or indirectly - * through builtins[]. - */ - - duk_set_top(thr, 0); - DUK_ASSERT_TOP(thr, 0); -} -#endif /* DUK_USE_ROM_OBJECTS */ - -DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) { - duk_small_uint_t i; - - for (i = 0; i < DUK_NUM_BUILTINS; i++) { - thr_to->builtins[i] = thr_from->builtins[i]; - DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */ - } -} - -/* automatic undefs */ -#undef DUK__LENGTH_PROP_BITS -#undef DUK__NARGS_BITS -#undef DUK__NARGS_VARARGS_MARKER -#undef DUK__PROP_FLAGS_BITS -#undef DUK__PROP_TYPE_ACCESSOR -#undef DUK__PROP_TYPE_BITS -#undef DUK__PROP_TYPE_BOOLEAN_FALSE -#undef DUK__PROP_TYPE_BOOLEAN_TRUE -#undef DUK__PROP_TYPE_BUILTIN -#undef DUK__PROP_TYPE_DOUBLE -#undef DUK__PROP_TYPE_STRIDX -#undef DUK__PROP_TYPE_STRING -#undef DUK__PROP_TYPE_UNDEFINED -#line 1 "duk_hthread_misc.c" -/* - * Thread support. - */ - -/* #include duk_internal.h -> already included */ - -DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - - while (thr->callstack_curr != NULL) { - duk_hthread_activation_unwind_norz(thr); - } - - thr->valstack_bottom = thr->valstack; - duk_set_top(thr, 0); /* unwinds valstack, updating refcounts */ - - thr->state = DUK_HTHREAD_STATE_TERMINATED; - - /* Here we could remove references to built-ins, but it may not be - * worth the effort because built-ins are quite likely to be shared - * with another (unterminated) thread, and terminated threads are also - * usually garbage collected quite quickly. - * - * We could also shrink the value stack here, but that also may not - * be worth the effort for the same reason. - */ - - DUK_REFZERO_CHECK_SLOW(thr); -} - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) { - duk_instr_t *bcode; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(act != NULL); - DUK_UNREF(thr); - - /* XXX: store 'bcode' pointer to activation for faster lookup? */ - if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) { - bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func)); - return (duk_uint_fast32_t) (act->curr_pc - bcode); - } - return 0; -} -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) { - duk_instr_t *bcode; - duk_uint_fast32_t ret; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(act != NULL); - DUK_UNREF(thr); - - if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) { - bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func)); - ret = (duk_uint_fast32_t) (act->curr_pc - bcode); - if (ret > 0) { - ret--; - } - return ret; - } - return 0; -} - -/* Write bytecode executor's curr_pc back to topmost activation (if any). */ -DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) { - duk_activation *act; - - DUK_ASSERT(thr != NULL); - - if (thr->ptr_curr_pc != NULL) { - /* ptr_curr_pc != NULL only when bytecode executor is active. */ - DUK_ASSERT(thr->callstack_top > 0); - DUK_ASSERT(thr->callstack_curr != NULL); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - act->curr_pc = *thr->ptr_curr_pc; - } -} - -DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) { - duk_activation *act; - - DUK_ASSERT(thr != NULL); - - if (thr->ptr_curr_pc != NULL) { - /* ptr_curr_pc != NULL only when bytecode executor is active. */ - DUK_ASSERT(thr->callstack_top > 0); - DUK_ASSERT(thr->callstack_curr != NULL); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - act->curr_pc = *thr->ptr_curr_pc; - thr->ptr_curr_pc = NULL; - } -} -#line 1 "duk_hthread_stacks.c" -/* - * Thread stack (mainly call stack) primitives: allocation of activations, - * unwinding catchers and activations, etc. - * - * Value stack handling is a part of the API implementation. - */ - -/* #include duk_internal.h -> already included */ - -/* Unwind the topmost catcher of the current activation (caller must check that - * both exist) without side effects. - */ -DUK_INTERNAL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act) { - duk_catcher *cat; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(act != NULL); - DUK_ASSERT(act->cat != NULL); /* caller must check */ - cat = act->cat; - DUK_ASSERT(cat != NULL); - - DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is done)", (void *) cat)); - - if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) { - duk_hobject *env; - - env = act->lex_env; /* current lex_env of the activation (created for catcher) */ - DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */ - act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */ - DUK_HOBJECT_INCREF(thr, act->lex_env); - DUK_HOBJECT_DECREF_NORZ(thr, env); - - /* There is no need to decref anything else than 'env': if 'env' - * becomes unreachable, refzero will handle decref'ing its prototype. - */ - } - - act->cat = cat->parent; - duk_hthread_catcher_free(thr, cat); -} - -/* Same as above, but caller is certain no catcher-related lexenv may exist. */ -DUK_INTERNAL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act) { - duk_catcher *cat; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(act != NULL); - DUK_ASSERT(act->cat != NULL); /* caller must check */ - cat = act->cat; - DUK_ASSERT(cat != NULL); - - DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is not done)", (void *) cat)); - - DUK_ASSERT(!DUK_CAT_HAS_LEXENV_ACTIVE(cat)); - - act->cat = cat->parent; - duk_hthread_catcher_free(thr, cat); -} - -DUK_LOCAL -#if defined(DUK_USE_CACHE_CATCHER) -DUK_NOINLINE -#endif -duk_catcher *duk__hthread_catcher_alloc_slow(duk_hthread *thr) { - duk_catcher *cat; - - cat = (duk_catcher *) DUK_ALLOC_CHECKED(thr, sizeof(duk_catcher)); - DUK_ASSERT(cat != NULL); - return cat; -} - -#if defined(DUK_USE_CACHE_CATCHER) -DUK_INTERNAL DUK_INLINE duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) { - duk_catcher *cat; - - DUK_ASSERT(thr != NULL); - - cat = thr->heap->catcher_free; - if (DUK_LIKELY(cat != NULL)) { - thr->heap->catcher_free = cat->parent; - return cat; - } - - return duk__hthread_catcher_alloc_slow(thr); -} -#else /* DUK_USE_CACHE_CATCHER */ -DUK_INTERNAL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) { - return duk__hthread_catcher_alloc_slow(thr); -} -#endif /* DUK_USE_CACHE_CATCHER */ - -DUK_INTERNAL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(cat != NULL); - -#if defined(DUK_USE_CACHE_CATCHER) - /* Unconditional caching for now; freed in mark-and-sweep. */ - cat->parent = thr->heap->catcher_free; - thr->heap->catcher_free = cat; -#else - DUK_FREE_CHECKED(thr, (void *) cat); -#endif -} - -DUK_LOCAL -#if defined(DUK_USE_CACHE_ACTIVATION) -DUK_NOINLINE -#endif -duk_activation *duk__hthread_activation_alloc_slow(duk_hthread *thr) { - duk_activation *act; - - act = (duk_activation *) DUK_ALLOC_CHECKED(thr, sizeof(duk_activation)); - DUK_ASSERT(act != NULL); - return act; -} - -#if defined(DUK_USE_CACHE_ACTIVATION) -DUK_INTERNAL DUK_INLINE duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) { - duk_activation *act; - - DUK_ASSERT(thr != NULL); - - act = thr->heap->activation_free; - if (DUK_LIKELY(act != NULL)) { - thr->heap->activation_free = act->parent; - return act; - } - - return duk__hthread_activation_alloc_slow(thr); -} -#else /* DUK_USE_CACHE_ACTIVATION */ -DUK_INTERNAL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) { - return duk__hthread_activation_alloc_slow(thr); -} -#endif /* DUK_USE_CACHE_ACTIVATION */ - - -DUK_INTERNAL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(act != NULL); - -#if defined(DUK_USE_CACHE_ACTIVATION) - /* Unconditional caching for now; freed in mark-and-sweep. */ - act->parent = thr->heap->activation_free; - thr->heap->activation_free = act; -#else - DUK_FREE_CHECKED(thr, (void *) act); -#endif -} - -/* Internal helper: process the unwind for the topmost activation of a thread, - * but leave the duk_activation in place for possible tailcall reuse. - */ -DUK_LOCAL void duk__activation_unwind_nofree_norz(duk_hthread *thr) { -#if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_heap *heap; -#endif - duk_activation *act; - duk_hobject *func; - duk_hobject *tmp; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->callstack_curr != NULL); /* caller must check */ - DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - /* With lightfuncs, act 'func' may be NULL. */ - - /* With duk_activation records allocated separately, 'act' is a stable - * pointer and not affected by side effects. - */ - -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - /* - * Restore 'caller' property for non-strict callee functions. - */ - - func = DUK_ACT_GET_FUNC(act); - if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) { - duk_tval *tv_caller; - duk_tval tv_tmp; - duk_hobject *h_tmp; - - tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr)); - - /* The act->prev_caller should only be set if the entry for 'caller' - * exists (as it is only set in that case, and the property is not - * configurable), but handle all the cases anyway. - */ - - if (tv_caller) { - DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller); - if (act->prev_caller) { - /* Just transfer the refcount from act->prev_caller to tv_caller, - * so no need for a refcount update. This is the expected case. - */ - DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller); - act->prev_caller = NULL; - } else { - DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */ - DUK_ASSERT(act->prev_caller == NULL); - } - DUK_TVAL_DECREF_NORZ(thr, &tv_tmp); - } else { - h_tmp = act->prev_caller; - if (h_tmp) { - act->prev_caller = NULL; - DUK_HOBJECT_DECREF_NORZ(thr, h_tmp); - } - } - DUK_ASSERT(act->prev_caller == NULL); - } -#endif - - /* - * Unwind debugger state. If we unwind while stepping - * (for any step type), pause execution. This is the - * only place explicitly handling a step out. - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - heap = thr->heap; - if (heap->dbg_pause_act == thr->callstack_curr) { - if (heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_EXIT) { - DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function exit")); - duk_debug_set_paused(heap); - } else { - DUK_D(DUK_DPRINT("unwound past dbg_pause_act, set to NULL")); - heap->dbg_pause_act = NULL; /* avoid stale pointers */ - } - DUK_ASSERT(heap->dbg_pause_act == NULL); - } -#endif - - /* - * Unwind catchers. - * - * Since there are no references in the catcher structure, - * unwinding is quite simple. The only thing we need to - * look out for is popping a possible lexical environment - * established for an active catch clause. - */ - - while (act->cat != NULL) { - duk_hthread_catcher_unwind_norz(thr, act); - } - - /* - * Close environment record(s) if they exist. - * - * Only variable environments are closed. If lex_env != var_env, it - * cannot currently contain any register bound declarations. - * - * Only environments created for a NEWENV function are closed. If an - * environment is created for e.g. an eval call, it must not be closed. - */ - - func = DUK_ACT_GET_FUNC(act); - if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) { - DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation")); - goto skip_env_close; - } - /* func is NULL for lightfunc */ - - /* Catch sites are required to clean up their environments - * in FINALLY part before propagating, so this should - * always hold here. - */ - DUK_ASSERT(act->lex_env == act->var_env); - - /* XXX: Closing the environment record copies values from registers - * into the scope object. It's side effect free as such, but may - * currently run out of memory which causes an error throw. This is - * an actual sandboxing problem for error unwinds, and needs to be - * fixed e.g. by preallocating the scope property slots. - */ - if (act->var_env != NULL) { - DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O", - (void *) act->var_env, (duk_heaphdr *) act->var_env)); - duk_js_close_environment_record(thr, act->var_env); - } - - skip_env_close: - - /* - * Update preventcount - */ - - if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) { - DUK_ASSERT(thr->callstack_preventcount >= 1); - thr->callstack_preventcount--; - } - - /* - * Reference count updates, using NORZ macros so we don't - * need to handle side effects. - * - * duk_activation pointers like act->var_env are intentionally - * left as garbage and not NULLed. Without side effects they - * can't be used when the values are dangling/garbage. - */ - - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env); - tmp = DUK_ACT_GET_FUNC(act); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); - DUK_UNREF(tmp); -} - -/* Unwind topmost duk_activation of a thread, caller must ensure that an - * activation exists. The call is side effect free, except that scope - * closure may currently throw an out-of-memory error. - */ -DUK_INTERNAL void duk_hthread_activation_unwind_norz(duk_hthread *thr) { - duk_activation *act; - - duk__activation_unwind_nofree_norz(thr); - - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack_curr; - thr->callstack_curr = act->parent; - thr->callstack_top--; - - /* Ideally we'd restore value stack reserve here to caller's value. - * This doesn't work for current unwind call sites however, because - * the current (unwound) value stack top may be above the reserve. - * Thus value stack reserve is restored by the call sites. - */ - - /* XXX: inline for performance builds? */ - duk_hthread_activation_free(thr, act); - - /* We could clear the book-keeping variables like retval_byteoff for - * the topmost activation, but don't do so now as it's not necessary. - */ -} - -DUK_INTERNAL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr) { - duk__activation_unwind_nofree_norz(thr); -} - -/* Get duk_activation for given callstack level or NULL if level is invalid - * or deeper than the call stack. Level -1 refers to current activation, -2 - * to its caller, etc. Starting from Duktape 2.2 finding the activation is - * a linked list scan which gets more expensive the deeper the lookup is. - */ -DUK_INTERNAL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level) { - duk_activation *act; - - if (level >= 0) { - return NULL; - } - act = thr->callstack_curr; - for (;;) { - if (act == NULL) { - return act; - } - if (level == -1) { - return act; - } - level++; - act = act->parent; - } - /* never here */ -} - -#if defined(DUK_USE_FINALIZER_TORTURE) -DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) { - duk_size_t alloc_size; - duk_tval *new_ptr; - duk_ptrdiff_t alloc_end_off; - duk_ptrdiff_t end_off; - duk_ptrdiff_t bottom_off; - duk_ptrdiff_t top_off; - - if (thr->valstack == NULL) { - DUK_D(DUK_DPRINT("skip valstack torture realloc, valstack is NULL")); - return; - } - - alloc_end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack); - end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); - bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); - top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack); - alloc_size = (duk_size_t) alloc_end_off; - if (alloc_size == 0) { - DUK_D(DUK_DPRINT("skip valstack torture realloc, alloc_size is zero")); - return; - } - - /* Use DUK_ALLOC_RAW() to avoid side effects. */ - new_ptr = (duk_tval *) DUK_ALLOC_RAW(thr->heap, alloc_size); - if (new_ptr != NULL) { - DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size); - DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size); - DUK_FREE_CHECKED(thr, (void *) thr->valstack); - thr->valstack = new_ptr; - thr->valstack_alloc_end = (duk_tval *) ((duk_uint8_t *) new_ptr + alloc_end_off); - thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off); - thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off); - thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off); - } else { - DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore")); - } -} -#endif /* DUK_USE_FINALIZER_TORTURE */ -#line 1 "duk_js_arith.c" -/* - * Shared helpers for arithmetic operations - */ - -/* #include duk_internal.h -> already included */ - -/* Ecmascript modulus ('%') does not match IEEE 754 "remainder" operation - * (implemented by remainder() in C99) but does seem to match ANSI C fmod(). - * Compare E5 Section 11.5.3 and "man fmod". - */ -DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) { -#if defined(DUK_USE_POW_WORKAROUNDS) - /* Specific fixes to common fmod() implementation issues: - * - test-bug-mingw-math-issues.js - */ - if (DUK_ISINF(d2)) { - if (DUK_ISINF(d1)) { - return DUK_DOUBLE_NAN; - } else { - return d1; - } - } else if (d1 == 0.0) { - /* d1 +/-0 is returned as is (preserving sign) except when - * d2 is zero or NaN. - */ - if (d2 == 0.0 || DUK_ISNAN(d2)) { - return DUK_DOUBLE_NAN; - } else { - return d1; - } - } -#else - /* Some ISO C assumptions. */ - DUK_ASSERT(DUK_FMOD(1.0, DUK_DOUBLE_INFINITY) == 1.0); - DUK_ASSERT(DUK_FMOD(-1.0, DUK_DOUBLE_INFINITY) == -1.0); - DUK_ASSERT(DUK_FMOD(1.0, -DUK_DOUBLE_INFINITY) == 1.0); - DUK_ASSERT(DUK_FMOD(-1.0, -DUK_DOUBLE_INFINITY) == -1.0); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY))); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY))); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY))); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY))); - DUK_ASSERT(DUK_FMOD(0.0, 1.0) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, 1.0)) == 0); - DUK_ASSERT(DUK_FMOD(-0.0, 1.0) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, 1.0)) != 0); - DUK_ASSERT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0); - DUK_ASSERT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY)) != 0); - DUK_ASSERT(DUK_FMOD(0.0, -DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0); - DUK_ASSERT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY)) != 0); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, 0.0))); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, 0.0))); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, -0.0))); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, -0.0))); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, DUK_DOUBLE_NAN))); - DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, DUK_DOUBLE_NAN))); -#endif - - return (duk_double_t) DUK_FMOD((double) d1, (double) d2); -} - -/* Shared helper for Math.pow() and exponentiation operator. */ -DUK_INTERNAL double duk_js_arith_pow(double x, double y) { - /* The ANSI C pow() semantics differ from Ecmascript. - * - * E.g. when x==1 and y is +/- infinite, the Ecmascript required - * result is NaN, while at least Linux pow() returns 1. - */ - - duk_small_int_t cx, cy, sx; - - DUK_UNREF(cx); - DUK_UNREF(sx); - cy = (duk_small_int_t) DUK_FPCLASSIFY(y); - - if (cy == DUK_FP_NAN) { - goto ret_nan; - } - if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) { - goto ret_nan; - } - -#if defined(DUK_USE_POW_WORKAROUNDS) - /* Specific fixes to common pow() implementation issues: - * - test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) - * - test-bug-mingw-math-issues.js - */ - cx = (duk_small_int_t) DUK_FPCLASSIFY(x); - if (cx == DUK_FP_ZERO && y < 0.0) { - sx = (duk_small_int_t) DUK_SIGNBIT(x); - if (sx == 0) { - /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow() - * returns -Infinity instead when y is <0 and finite. The - * if-clause also catches y == -Infinity (which works even - * without the fix). - */ - return DUK_DOUBLE_INFINITY; - } else { - /* Math.pow(-0,y) where y<0 should be: - * - -Infinity if y<0 and an odd integer - * - Infinity if y<0 but not an odd integer - * NetBSD pow() returns -Infinity for all finite y<0. The - * if-clause also catches y == -Infinity (which works even - * without the fix). - */ - - /* fmod() return value has same sign as input (negative) so - * the result here will be in the range ]-2,0], -1 indicates - * odd. If x is -Infinity, NaN is returned and the odd check - * always concludes "not odd" which results in desired outcome. - */ - double tmp = DUK_FMOD(y, 2); - if (tmp == -1.0) { - return -DUK_DOUBLE_INFINITY; - } else { - /* Not odd, or y == -Infinity */ - return DUK_DOUBLE_INFINITY; - } - } - } else if (cx == DUK_FP_NAN) { - if (y == 0.0) { - /* NaN ** +/- 0 should always be 1, but is NaN on - * at least some Cygwin/MinGW versions. - */ - return 1.0; - } - } -#else - /* Some ISO C assumptions. */ - DUK_ASSERT(DUK_POW(DUK_DOUBLE_NAN, 0.0) == 1.0); - DUK_ASSERT(DUK_ISINF(DUK_POW(0.0, -1.0)) && DUK_SIGNBIT(DUK_POW(0.0, -1.0)) == 0); - DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -2.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -2.0)) == 0); - DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -3.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -3.0)) != 0); -#endif - - return DUK_POW(x, y); - - ret_nan: - return DUK_DOUBLE_NAN; -} -#line 1 "duk_js_call.c" -/* - * Call handling. - * - * duk_handle_call_unprotected(): - * - * - Unprotected call to Ecmascript or Duktape/C function, from native - * code or bytecode executor. - * - * - Also handles Ecma-to-Ecma calls which reuses a currently running - * executor instance to avoid native recursion. Call setup is done - * normally, but just before calling the bytecode executor a special - * return code is used to indicate that a calling executor is reused. - * - * - Also handles tailcalls, i.e. reuse of current duk_activation. - * - * - Also handles setup for initial Duktape.Thread.resume(). - * - * duk_handle_safe_call(): - * - * - Protected C call within current activation. - * - * setjmp() and local variables have a nasty interaction, see execution.rst; - * non-volatile locals modified after setjmp() call are not guaranteed to - * keep their value and can cause compiler or compiler version specific - * difficult to replicate issues. - * - * See 'execution.rst'. - */ - -/* #include duk_internal.h -> already included */ - -/* XXX: heap->error_not_allowed for success path too? */ - -/* - * Limit check helpers. - */ - -/* Allow headroom for calls during error augmentation (see GH-191). - * We allow space for 10 additional recursions, with one extra - * for, e.g. a print() call at the deepest level, and an extra - * +1 for protected call wrapping. - */ -#define DUK__AUGMENT_CALL_RELAX_COUNT (10 + 2) - -DUK_LOCAL DUK_NOINLINE void duk__call_c_recursion_limit_check_slowpath(duk_hthread *thr) { - /* When augmenting an error, the effective limit is a bit higher. - * Check for it only if the fast path check fails. - */ -#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE) - if (thr->heap->augmenting_error) { - if (thr->heap->call_recursion_depth < thr->heap->call_recursion_limit + DUK__AUGMENT_CALL_RELAX_COUNT) { - DUK_D(DUK_DPRINT("C recursion limit reached but augmenting error and within relaxed limit")); - return; - } - } -#endif - - DUK_D(DUK_DPRINT("call prevented because C recursion limit reached")); - DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT); -} - -DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_c_recursion_limit_check(duk_hthread *thr) { - DUK_ASSERT(thr->heap->call_recursion_depth >= 0); - DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit); - - /* This check is forcibly inlined because it's very cheap and almost - * always passes. The slow path is forcibly noinline. - */ - if (DUK_LIKELY(thr->heap->call_recursion_depth < thr->heap->call_recursion_limit)) { - return; - } - - duk__call_c_recursion_limit_check_slowpath(thr); -} - -DUK_LOCAL DUK_NOINLINE void duk__call_callstack_limit_check_slowpath(duk_hthread *thr) { - /* When augmenting an error, the effective limit is a bit higher. - * Check for it only if the fast path check fails. - */ -#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE) - if (thr->heap->augmenting_error) { - if (thr->callstack_top < DUK_USE_CALLSTACK_LIMIT + DUK__AUGMENT_CALL_RELAX_COUNT) { - DUK_D(DUK_DPRINT("call stack limit reached but augmenting error and within relaxed limit")); - return; - } - } -#endif - - /* XXX: error message is a bit misleading: we reached a recursion - * limit which is also essentially the same as a C callstack limit - * (except perhaps with some relaxed threading assumptions). - */ - DUK_D(DUK_DPRINT("call prevented because call stack limit reached")); - DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT); -} - -DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_callstack_limit_check(duk_hthread *thr) { - /* This check is forcibly inlined because it's very cheap and almost - * always passes. The slow path is forcibly noinline. - */ - if (DUK_LIKELY(thr->callstack_top < DUK_USE_CALLSTACK_LIMIT)) { - return; - } - - duk__call_callstack_limit_check_slowpath(thr); -} - -/* - * Interrupt counter fixup (for development only). - */ - -#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) -DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) { - /* Currently the bytecode executor and executor interrupt - * instruction counts are off because we don't execute the - * interrupt handler when we're about to exit from the initial - * user call into Duktape. - * - * If we were to execute the interrupt handler here, the counts - * would match. You can enable this block manually to check - * that this is the case. - */ - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - -#if defined(DUK_USE_INTERRUPT_DEBUG_FIXUP) - if (entry_curr_thread == NULL) { - thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter; - thr->heap->inst_count_interrupt += thr->interrupt_init; - DUK_DD(DUK_DDPRINT("debug test: updated interrupt count on exit to " - "user code, instruction counts: executor=%ld, interrupt=%ld", - (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt)); - DUK_ASSERT(thr->heap->inst_count_exec == thr->heap->inst_count_interrupt); - } -#else - DUK_UNREF(thr); - DUK_UNREF(entry_curr_thread); -#endif -} -#endif - -/* - * Arguments object creation. - * - * Creating arguments objects involves many small details, see E5 Section - * 10.6 for the specific requirements. Much of the arguments object exotic - * behavior is implemented in duk_hobject_props.c, and is enabled by the - * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS. - */ - -DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr, - duk_hobject *func, - duk_hobject *varenv, - duk_idx_t idx_args) { - duk_hobject *arg; /* 'arguments' */ - duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */ - duk_idx_t i_arg; - duk_idx_t i_map; - duk_idx_t i_mappednames; - duk_idx_t i_formals; - duk_idx_t i_argbase; - duk_idx_t n_formals; - duk_idx_t idx; - duk_idx_t num_stack_args; - duk_bool_t need_map; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(func != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func)); - DUK_ASSERT(varenv != NULL); - - /* [ ... func this arg1(@idx_args) ... argN envobj ] - * [ arg1(@idx_args) ... argN envobj ] (for tailcalls) - */ - - need_map = 0; - - i_argbase = idx_args; - num_stack_args = duk_get_top(thr) - i_argbase - 1; - DUK_ASSERT(i_argbase >= 0); - DUK_ASSERT(num_stack_args >= 0); - - duk_push_hobject(thr, func); - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FORMALS); - formals = duk_get_hobject(thr, -1); - if (formals) { - n_formals = (duk_idx_t) duk_get_length(thr, -1); - } else { - /* This shouldn't happen without tampering of internal - * properties: if a function accesses 'arguments', _Formals - * is kept. Check for the case anyway in case internal - * properties have been modified manually. - */ - DUK_D(DUK_DPRINT("_Formals is undefined when creating arguments, use n_formals == 0")); - n_formals = 0; - } - duk_remove_m2(thr); /* leave formals on stack for later use */ - i_formals = duk_require_top_index(thr); - - DUK_ASSERT(n_formals >= 0); - DUK_ASSERT(formals != NULL || n_formals == 0); - - DUK_DDD(DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%ld", - (duk_heaphdr *) func, (duk_heaphdr *) formals, - (long) n_formals)); - - /* [ ... formals ] */ - - /* - * Create required objects: - * - 'arguments' object: array-like, but not an array - * - 'map' object: internal object, tied to 'arguments' - * - 'mappedNames' object: temporary value used during construction - */ - - arg = duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_FLAG_ARRAY_PART | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS), - DUK_BIDX_OBJECT_PROTOTYPE); - DUK_ASSERT(arg != NULL); - (void) duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), - -1); /* no prototype */ - (void) duk_push_object_helper(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_FASTREFS | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), - -1); /* no prototype */ - i_arg = duk_get_top(thr) - 3; - i_map = i_arg + 1; - i_mappednames = i_arg + 2; - - /* [ ... formals arguments map mappedNames ] */ - - DUK_DDD(DUK_DDDPRINT("created arguments related objects: " - "arguments at index %ld -> %!O " - "map at index %ld -> %!O " - "mappednames at index %ld -> %!O", - (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg), - (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map), - (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames))); - - /* - * Init arguments properties, map, etc. - */ - - duk_push_int(thr, num_stack_args); - duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC); - - /* - * Init argument related properties. - */ - - /* step 11 */ - idx = num_stack_args - 1; - while (idx >= 0) { - DUK_DDD(DUK_DDDPRINT("arg idx %ld, argbase=%ld, argidx=%ld", - (long) idx, (long) i_argbase, (long) (i_argbase + idx))); - - DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx)); - duk_dup(thr, i_argbase + idx); - duk_xdef_prop_index_wec(thr, i_arg, (duk_uarridx_t) idx); - DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx)); - - /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */ - if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) { - DUK_ASSERT(formals != NULL); - - DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)", - (long) idx, (long) n_formals)); - - duk_get_prop_index(thr, i_formals, (duk_uarridx_t) idx); - DUK_ASSERT(duk_is_string(thr, -1)); - - duk_dup_top(thr); /* [ ... name name ] */ - - if (!duk_has_prop(thr, i_mappednames)) { - /* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping - * differs from the reference model - */ - - /* [ ... name ] */ - - need_map = 1; - - DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld", - (const char *) duk_get_string(thr, -1), - (long) idx)); - duk_dup_top(thr); /* name */ - (void) duk_push_uint_to_hstring(thr, (duk_uint_t) idx); /* index */ - duk_xdef_prop_wec(thr, i_mappednames); /* out of spec, must be configurable */ - - DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s", - (long) idx, - duk_get_string(thr, -1))); - duk_dup_top(thr); /* name */ - duk_xdef_prop_index_wec(thr, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */ - } else { - /* duk_has_prop() popped the second 'name' */ - } - - /* [ ... name ] */ - duk_pop(thr); /* pop 'name' */ - } - - idx--; - } - - DUK_DDD(DUK_DDDPRINT("actual arguments processed")); - - /* step 12 */ - if (need_map) { - DUK_DDD(DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object")); - - /* should never happen for a strict callee */ - DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func)); - - duk_dup(thr, i_map); - duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */ - - /* The variable environment for magic variable bindings needs to be - * given by the caller and recorded in the arguments object. - * - * See E5 Section 10.6, the creation of setters/getters. - * - * The variable environment also provides access to the callee, so - * an explicit (internal) callee property is not needed. - */ - - duk_push_hobject(thr, varenv); - duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */ - } - - /* steps 13-14 */ - if (DUK_HOBJECT_HAS_STRICT(func)) { - /* Callee/caller are throwers and are not deletable etc. They - * could be implemented as virtual properties, but currently - * there is no support for virtual properties which are accessors - * (only plain virtual properties). This would not be difficult - * to change in duk_hobject_props, but we can make the throwers - * normal, concrete properties just as easily. - * - * Note that the specification requires that the *same* thrower - * built-in object is used here! See E5 Section 10.6 main - * algoritm, step 14, and Section 13.2.3 which describes the - * thrower. See test case test-arguments-throwers.js. - */ - - DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers")); - - duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLER); - duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLEE); - } else { - DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value")); - duk_push_hobject(thr, func); - duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC); - } - - /* set exotic behavior only after we're done */ - if (need_map) { - /* Exotic behaviors are only enabled for arguments objects - * which have a parameter map (see E5 Section 10.6 main - * algorithm, step 12). - * - * In particular, a non-strict arguments object with no - * mapped formals does *NOT* get exotic behavior, even - * for e.g. "caller" property. This seems counterintuitive - * but seems to be the case. - */ - - /* cannot be strict (never mapped variables) */ - DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func)); - - DUK_DDD(DUK_DDDPRINT("enabling exotic behavior for arguments object")); - DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(arg); - } else { - DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object")); - } - - DUK_DDD(DUK_DDDPRINT("final arguments related objects: " - "arguments at index %ld -> %!O " - "map at index %ld -> %!O " - "mappednames at index %ld -> %!O", - (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg), - (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map), - (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames))); - - /* [ args(n) envobj formals arguments map mappednames ] */ - - duk_pop_2(thr); - duk_remove_m2(thr); - - /* [ args(n) envobj arguments ] */ -} - -/* Helper for creating the arguments object and adding it to the env record - * on top of the value stack. - */ -DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr, - duk_hobject *func, - duk_hobject *env, - duk_idx_t idx_args) { - DUK_DDD(DUK_DDDPRINT("creating arguments object for function call")); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(func != NULL); - DUK_ASSERT(env != NULL); - DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func)); - - /* [ ... arg1 ... argN envobj ] */ - - duk__create_arguments_object(thr, - func, - env, - idx_args); - - /* [ ... arg1 ... argN envobj argobj ] */ - - duk_xdef_prop_stridx_short(thr, - -2, - DUK_STRIDX_LC_ARGUMENTS, - DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */ - DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */ - /* [ ... arg1 ... argN envobj ] */ -} - -/* - * Helpers for constructor call handling. - * - * There are two [[Construct]] operations in the specification: - * - * - E5 Section 13.2.2: for Function objects - * - E5 Section 15.3.4.5.2: for "bound" Function objects - * - * The chain of bound functions is resolved in Section 15.3.4.5.2, - * with arguments "piling up" until the [[Construct]] internal - * method is called on the final, actual Function object. Note - * that the "prototype" property is looked up *only* from the - * final object, *before* calling the constructor. - * - * Since Duktape 2.2 bound functions are represented with the - * duk_hboundfunc internal type, and bound function chains are - * collapsed when a bound function is created. As a result, the - * direct target of a duk_hboundfunc is always non-bound and the - * this/argument lists have been resolved. - * - * When constructing new Array instances, an unnecessary object is - * created and discarded now: the standard [[Construct]] creates an - * object, and calls the Array constructor. The Array constructor - * returns an Array instance, which is used as the result value for - * the "new" operation; the object created before the Array constructor - * call is discarded. - * - * This would be easy to fix, e.g. by knowing that the Array constructor - * will always create a replacement object and skip creating the fallback - * object in that case. - */ - -/* Update default instance prototype for constructor call. */ -DUK_LOCAL void duk__update_default_instance_proto(duk_hthread *thr, duk_idx_t idx_func) { - duk_hobject *proto; - duk_hobject *fallback; - - DUK_ASSERT(duk_is_constructable(thr, idx_func)); - - duk_get_prop_stridx_short(thr, idx_func, DUK_STRIDX_PROTOTYPE); - proto = duk_get_hobject(thr, -1); - if (proto == NULL) { - DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object " - "-> leave standard Object prototype as fallback prototype")); - } else { - DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value " - "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto)); - /* Original fallback (default instance) is untouched when - * resolving bound functions etc. - */ - fallback = duk_known_hobject(thr, idx_func + 1); - DUK_ASSERT(fallback != NULL); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto); - } - duk_pop(thr); -} - -/* Postprocess: return value special handling, error augmentation. */ -DUK_INTERNAL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant) { - /* Use either fallback (default instance) or retval depending - * on retval type. Needs to be called before unwind because - * the default instance is read from the current (immutable) - * 'this' binding. - * - * For Proxy 'construct' calls the return value must be an - * Object (we accept object-like values like buffers and - * lightfuncs too). If not, TypeError. - */ - if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | - DUK_TYPE_MASK_BUFFER | - DUK_TYPE_MASK_LIGHTFUNC)) { - DUK_DDD(DUK_DDDPRINT("replacement value")); - } else { - if (DUK_UNLIKELY(proxy_invariant != 0U)) { - /* Proxy 'construct' return value invariant violated. */ - DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr); - } - /* XXX: direct value stack access */ - duk_pop(thr); - duk_push_this(thr); - } - -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) - /* Augment created errors upon creation, not when they are thrown or - * rethrown. __FILE__ and __LINE__ are not desirable here; the call - * stack reflects the caller which is correct. Skip topmost, unwound - * activation when creating a traceback. If thr->ptr_curr_pc was != - * NULL we'd need to sync the current PC so that the traceback comes - * out right; however it is always synced here so just assert for it. - */ - DUK_ASSERT(thr->ptr_curr_pc == NULL); - duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE | - DUK_AUGMENT_FLAG_SKIP_ONE); -#endif -} - -/* - * Helper for handling a bound function when a call is being made. - * - * Assumes that bound function chains have been "collapsed" so that either - * the target is non-bound or there is one bound function that points to a - * nonbound target. - * - * Prepends the bound arguments to the value stack (at idx_func + 2). - * The 'this' binding is also updated if necessary (at idx_func + 1). - * Note that for constructor calls the 'this' binding is never updated by - * [[BoundThis]]. - */ - -DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr, - duk_idx_t idx_func, - duk_bool_t is_constructor_call) { - duk_tval *tv_func; - duk_hobject *func; - duk_idx_t len; - - DUK_ASSERT(thr != NULL); - - /* On entry, item at idx_func is a bound, non-lightweight function, - * but we don't rely on that below. - */ - - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - - tv_func = duk_require_tval(thr, idx_func); - DUK_ASSERT(tv_func != NULL); - - if (DUK_TVAL_IS_OBJECT(tv_func)) { - func = DUK_TVAL_GET_OBJECT(tv_func); - - /* XXX: separate helper function, out of fast path? */ - if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) { - duk_hboundfunc *h_bound; - duk_tval *tv_args; - duk_tval *tv_gap; - - h_bound = (duk_hboundfunc *) func; - tv_args = h_bound->args; - len = h_bound->nargs; - DUK_ASSERT(len == 0 || tv_args != NULL); - - DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p: %!T", - (void *) DUK_TVAL_GET_OBJECT(tv_func), tv_func)); - - /* [ ... func this arg1 ... argN ] */ - - if (is_constructor_call) { - /* See: tests/ecmascript/test-spec-bound-constructor.js */ - DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding")); - } else { - /* XXX: duk_replace_tval */ - duk_push_tval(thr, &h_bound->this_binding); - duk_replace(thr, idx_func + 1); /* idx_this = idx_func + 1 */ - } - - /* [ ... func this arg1 ... argN ] */ - - duk_require_stack(thr, len); - - tv_gap = duk_reserve_gap(thr, idx_func + 2, len); - duk_copy_tvals_incref(thr, tv_gap, tv_args, (duk_size_t) len); - - /* [ ... func this arg1 ... argN ] */ - - duk_push_tval(thr, &h_bound->target); - duk_replace(thr, idx_func); /* replace in stack */ - - DUK_DDD(DUK_DDDPRINT("bound function handled, idx_func=%ld, curr func=%!T", - (long) idx_func, duk_get_tval(thr, idx_func))); - } - } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) { - /* Lightweight function: never bound, so terminate. */ - ; - } else { - /* Shouldn't happen, so ugly error is enough. */ - DUK_ERROR_INTERNAL(thr); - } - - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - - DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(thr, idx_func))); - -#if defined(DUK_USE_ASSERTIONS) - tv_func = duk_require_tval(thr, idx_func); - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func)); - if (DUK_TVAL_IS_OBJECT(tv_func)) { - func = DUK_TVAL_GET_OBJECT(tv_func); - DUK_ASSERT(func != NULL); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func) || - DUK_HOBJECT_HAS_NATFUNC(func)); - } -#endif -} - -/* - * Helper for inline handling of .call(), .apply(), and .construct(). - */ - -DUK_LOCAL duk_bool_t duk__handle_specialfuncs_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hobject *func, duk_small_uint_t *call_flags, duk_bool_t first) { -#if defined(DUK_USE_ASSERTIONS) - duk_c_function natfunc; -#endif - duk_tval *tv_args; - - DUK_ASSERT(func != NULL); - DUK_ASSERT((*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0); /* Caller. */ - -#if defined(DUK_USE_ASSERTIONS) - natfunc = ((duk_hnatfunc *) func)->func; - DUK_ASSERT(natfunc != NULL); -#endif - - /* On every round of function resolution at least target function and - * 'this' binding are set. We can assume that here, and must guarantee - * it on exit. Value stack reserve is extended for bound function and - * .apply() unpacking so we don't need to extend it here when we need a - * few slots. - */ - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - - /* Handle native 'eval' specially. A direct eval check is only made - * for the first resolution attempt; e.g. a bound eval call is -not- - * a direct eval call. - */ - if (DUK_UNLIKELY(((duk_hnatfunc *) func)->magic == 15)) { - /* For now no special handling except for direct eval - * detection. - */ - DUK_ASSERT(((duk_hnatfunc *) func)->func == duk_bi_global_object_eval); - if (first && (*call_flags & DUK_CALL_FLAG_CALLED_AS_EVAL)) { - *call_flags = (*call_flags & ~DUK_CALL_FLAG_CALLED_AS_EVAL) | DUK_CALL_FLAG_DIRECT_EVAL; - } - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - return 1; /* stop resolving */ - } - - /* Handle special functions based on the DUK_HOBJECT_FLAG_SPECIAL_CALL - * flag; their magic value is used for switch-case. - * - * NOTE: duk_unpack_array_like() reserves value stack space - * for the result values (unlike most other value stack calls). - */ - switch (((duk_hnatfunc *) func)->magic) { - case 0: { /* 0=Function.prototype.call() */ - /* Value stack: - * idx_func + 0: Function.prototype.call() [removed] - * idx_func + 1: this binding for .call (target function) - * idx_func + 2: 1st argument to .call, desired 'this' binding - * idx_func + 3: 2nd argument to .call, desired 1st argument for ultimate target - * ... - * - * Remove idx_func + 0 to get: - * idx_func + 0: target function - * idx_func + 1: this binding - * idx_func + 2: call arguments - * ... - */ - DUK_ASSERT(natfunc == duk_bi_function_prototype_call); - duk_remove_unsafe(thr, idx_func); - tv_args = thr->valstack_bottom + idx_func + 2; - if (thr->valstack_top < tv_args) { - DUK_ASSERT(tv_args <= thr->valstack_end); - thr->valstack_top = tv_args; /* at least target function and 'this' binding present */ - } - break; - } - case 1: { /* 1=Function.prototype.apply() */ - /* Value stack: - * idx_func + 0: Function.prototype.apply() [removed] - * idx_func + 1: this binding for .apply (target function) - * idx_func + 2: 1st argument to .apply, desired 'this' binding - * idx_func + 3: 2nd argument to .apply, argArray - * [anything after this MUST be ignored] - * - * Remove idx_func + 0 and unpack the argArray to get: - * idx_func + 0: target function - * idx_func + 1: this binding - * idx_func + 2: call arguments - * ... - */ - DUK_ASSERT(natfunc == duk_bi_function_prototype_apply); - duk_remove_unsafe(thr, idx_func); - goto apply_shared; - } -#if defined(DUK_USE_REFLECT_BUILTIN) - case 2: { /* 2=Reflect.apply() */ - /* Value stack: - * idx_func + 0: Reflect.apply() [removed] - * idx_func + 1: this binding for .apply (ignored, usually Reflect) [removed] - * idx_func + 2: 1st argument to .apply, target function - * idx_func + 3: 2nd argument to .apply, desired 'this' binding - * idx_func + 4: 3rd argument to .apply, argArray - * [anything after this MUST be ignored] - * - * Remove idx_func + 0 and idx_func + 1, and unpack the argArray to get: - * idx_func + 0: target function - * idx_func + 1: this binding - * idx_func + 2: call arguments - * ... - */ - DUK_ASSERT(natfunc == duk_bi_reflect_apply); - duk_remove_n_unsafe(thr, idx_func, 2); - goto apply_shared; - } - case 3: { /* 3=Reflect.construct() */ - /* Value stack: - * idx_func + 0: Reflect.construct() [removed] - * idx_func + 1: this binding for .construct (ignored, usually Reflect) [removed] - * idx_func + 2: 1st argument to .construct, target function - * idx_func + 3: 2nd argument to .construct, argArray - * idx_func + 4: 3rd argument to .construct, newTarget - * [anything after this MUST be ignored] - * - * Remove idx_func + 0 and idx_func + 1, unpack the argArray, - * and insert default instance (prototype not yet updated), to get: - * idx_func + 0: target function - * idx_func + 1: this binding (default instance) - * idx_func + 2: constructor call arguments - * ... - * - * Call flags must be updated to reflect the fact that we're - * now dealing with a constructor call, and e.g. the 'this' - * binding cannot be overwritten if the target is bound. - * - * newTarget is checked but not yet passed onwards. - */ - - duk_idx_t top; - - DUK_ASSERT(natfunc == duk_bi_reflect_construct); - *call_flags |= DUK_CALL_FLAG_CONSTRUCT; - duk_remove_n_unsafe(thr, idx_func, 2); - top = duk_get_top(thr); - if (!duk_is_constructable(thr, idx_func)) { - /* Target constructability must be checked before - * unpacking argArray (which may cause side effects). - * Just return; caller will throw the error. - */ - duk_set_top_unsafe(thr, idx_func + 2); /* satisfy asserts */ - break; - } - duk_push_object(thr); - duk_insert(thr, idx_func + 1); /* default instance */ - - /* [ ... func default_instance argArray newTarget? ] */ - - top = duk_get_top(thr); - if (top < idx_func + 3) { - /* argArray is a mandatory argument for Reflect.construct(). */ - DUK_ERROR_TYPE_INVALID_ARGS(thr); - } - if (top > idx_func + 3) { - if (!duk_strict_equals(thr, idx_func, idx_func + 3)) { - /* XXX: [[Construct]] newTarget currently unsupported */ - DUK_ERROR_UNSUPPORTED(thr); - } - duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */ - } - DUK_ASSERT(duk_get_top(thr) == idx_func + 3); - DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2)); - (void) duk_unpack_array_like(thr, idx_func + 2); /* XXX: should also remove target to be symmetric with duk_pack()? */ - duk_remove(thr, idx_func + 2); - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - break; - } -#endif /* DUK_USE_REFLECT_BUILTIN */ - default: { - DUK_ASSERT(0); - DUK_UNREACHABLE(); - } - } - - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - return 0; /* keep resolving */ - - apply_shared: - tv_args = thr->valstack_bottom + idx_func + 2; - if (thr->valstack_top <= tv_args) { - DUK_ASSERT(tv_args <= thr->valstack_end); - thr->valstack_top = tv_args; /* at least target func and 'this' binding present */ - /* No need to check for argArray. */ - } else { - DUK_ASSERT(duk_get_top(thr) >= idx_func + 3); /* idx_func + 2 covered above */ - if (thr->valstack_top > tv_args + 1) { - duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */ - } - DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2)); - if (!duk_is_callable(thr, idx_func)) { - /* Avoid unpack side effects if the target isn't callable. - * Calling code will throw the actual error. - */ - } else { - (void) duk_unpack_array_like(thr, idx_func + 2); - duk_remove(thr, idx_func + 2); - } - } - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - return 0; /* keep resolving */ -} - -/* - * Helper for Proxy handling. - */ - -#if defined(DUK_USE_ES6_PROXY) -DUK_LOCAL void duk__handle_proxy_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hproxy *h_proxy, duk_small_uint_t *call_flags) { - duk_bool_t rc; - - /* Value stack: - * idx_func + 0: Proxy object - * idx_func + 1: this binding for call - * idx_func + 2: 1st argument for call - * idx_func + 3: 2nd argument for call - * ... - * - * If Proxy doesn't have a trap for the call ('apply' or 'construct'), - * replace Proxy object with target object. - * - * If we're dealing with a normal call and the Proxy has an 'apply' - * trap, manipulate value stack to: - * - * idx_func + 0: trap - * idx_func + 1: Proxy's handler - * idx_func + 2: Proxy's target - * idx_func + 3: this binding for call (from idx_func + 1) - * idx_func + 4: call arguments packed to an array - * - * If we're dealing with a constructor call and the Proxy has a - * 'construct' trap, manipulate value stack to: - * - * idx_func + 0: trap - * idx_func + 1: Proxy's handler - * idx_func + 2: Proxy's target - * idx_func + 3: call arguments packed to an array - * idx_func + 4: newTarget == Proxy object here - * - * As we don't yet have proper newTarget support, the newTarget at - * idx_func + 3 is just the original constructor being called, i.e. - * the Proxy object (not the target). Note that the default instance - * (original 'this' binding) is dropped and ignored. - */ - - duk_push_hobject(thr, h_proxy->handler); - rc = duk_get_prop_stridx_short(thr, -1, (*call_flags & DUK_CALL_FLAG_CONSTRUCT) ? DUK_STRIDX_CONSTRUCT : DUK_STRIDX_APPLY); - if (rc == 0) { - /* Not found, continue to target. If this is a construct - * call, update default instance prototype using the Proxy, - * not the target. - */ - if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) { - if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) { - *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED; - duk__update_default_instance_proto(thr, idx_func); - } - } - duk_pop_2(thr); - duk_push_hobject(thr, h_proxy->target); - duk_replace(thr, idx_func); - return; - } - - /* Here we must be careful not to replace idx_func while - * h_proxy is still needed, otherwise h_proxy may become - * dangling. This could be improved e.g. using a - * duk_pack_slice() with a freeform slice. - */ - - /* Here: - * idx_func + 0: Proxy object - * idx_func + 1: this binding for call - * idx_func + 2: 1st argument for call - * idx_func + 3: 2nd argument for call - * ... - * idx_func + N: handler - * idx_func + N + 1: trap - */ - - duk_insert(thr, idx_func + 1); - duk_insert(thr, idx_func + 2); - duk_push_hobject(thr, h_proxy->target); - duk_insert(thr, idx_func + 3); - duk_pack(thr, duk_get_top(thr) - (idx_func + 5)); - - /* Here: - * idx_func + 0: Proxy object - * idx_func + 1: trap - * idx_func + 2: Proxy's handler - * idx_func + 3: Proxy's target - * idx_func + 4: this binding for call - * idx_func + 5: arguments array - */ - DUK_ASSERT(duk_get_top(thr) == idx_func + 6); - - if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) { - *call_flags |= DUK_CALL_FLAG_CONSTRUCT_PROXY; /* Enable 'construct' trap return invariant check. */ - *call_flags &= ~(DUK_CALL_FLAG_CONSTRUCT); /* Resume as non-constructor call to the trap. */ - - /* 'apply' args: target, thisArg, argArray - * 'construct' args: target, argArray, newTarget - */ - duk_remove(thr, idx_func + 4); - duk_push_hobject(thr, (duk_hobject *) h_proxy); - } - - /* Finalize value stack layout by removing Proxy reference. */ - duk_remove(thr, idx_func); - h_proxy = NULL; /* invalidated */ - DUK_ASSERT(duk_get_top(thr) == idx_func + 5); -} -#endif /* DUK_USE_ES6_PROXY */ - -/* - * Helper for setting up var_env and lex_env of an activation, - * assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag. - */ - -DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr, - duk_hobject *func, - duk_activation *act) { - duk_hcompfunc *f; - duk_hobject *h_lex; - duk_hobject *h_var; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(func != NULL); - DUK_ASSERT(act != NULL); - DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func)); - DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func)); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(func)); - DUK_UNREF(thr); - - f = (duk_hcompfunc *) func; - h_lex = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f); - h_var = DUK_HCOMPFUNC_GET_VARENV(thr->heap, f); - DUK_ASSERT(h_lex != NULL); /* Always true for closures (not for templates) */ - DUK_ASSERT(h_var != NULL); - act->lex_env = h_lex; - act->var_env = h_var; - DUK_HOBJECT_INCREF(thr, h_lex); - DUK_HOBJECT_INCREF(thr, h_var); -} - -/* - * Helper for updating callee 'caller' property. - */ - -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) -DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) { - duk_tval *tv_caller; - duk_hobject *h_tmp; - duk_activation *act_callee; - duk_activation *act_caller; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(func != NULL); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound chain resolved */ - DUK_ASSERT(thr->callstack_top >= 1); - - if (DUK_HOBJECT_HAS_STRICT(func)) { - /* Strict functions don't get their 'caller' updated. */ - return; - } - - DUK_ASSERT(thr->callstack_top > 0); - act_callee = thr->callstack_curr; - DUK_ASSERT(act_callee != NULL); - act_caller = (thr->callstack_top >= 2 ? act_callee->parent : NULL); - - /* XXX: check .caller writability? */ - - /* Backup 'caller' property and update its value. */ - tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr)); - if (tv_caller) { - /* If caller is global/eval code, 'caller' should be set to - * 'null'. - * - * XXX: there is no exotic flag to infer this correctly now. - * The NEWENV flag is used now which works as intended for - * everything (global code, non-strict eval code, and functions) - * except strict eval code. Bound functions are never an issue - * because 'func' has been resolved to a non-bound function. - */ - - if (act_caller != NULL) { - /* act_caller->func may be NULL in some finalization cases, - * just treat like we don't know the caller. - */ - if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) { - /* Setting to NULL causes 'caller' to be set to - * 'null' as desired. - */ - act_caller = NULL; - } - } - - if (DUK_TVAL_IS_OBJECT(tv_caller)) { - h_tmp = DUK_TVAL_GET_OBJECT(tv_caller); - DUK_ASSERT(h_tmp != NULL); - act_callee->prev_caller = h_tmp; - - /* Previous value doesn't need refcount changes because its ownership - * is transferred to prev_caller. - */ - - if (act_caller != NULL) { - DUK_ASSERT(act_caller->func != NULL); - DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func); - DUK_TVAL_INCREF(thr, tv_caller); - } else { - DUK_TVAL_SET_NULL(tv_caller); /* no incref */ - } - } else { - /* 'caller' must only take on 'null' or function value */ - DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller)); - DUK_ASSERT(act_callee->prev_caller == NULL); - if (act_caller != NULL && act_caller->func) { - /* Tolerate act_caller->func == NULL which happens in - * some finalization cases; treat like unknown caller. - */ - DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func); - DUK_TVAL_INCREF(thr, tv_caller); - } else { - DUK_TVAL_SET_NULL(tv_caller); /* no incref */ - } - } - } -} -#endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */ - -/* - * Shared helpers for resolving the final, non-bound target function of the - * call and the effective 'this' binding. Resolves bound functions and - * applies .call(), .apply(), and .construct() inline. - * - * Proxy traps are also handled inline so that if the target is a Proxy with - * a 'call' or 'construct' trap, the trap handler is called with a modified - * argument list. - * - * Once the bound function / .call() / .apply() / .construct() sequence has - * been resolved, the value at idx_func + 1 may need coercion described in - * E5 Section 10.4.3. - * - * A call that begins as a non-constructor call may be converted into a - * constructor call during the resolution process if Reflect.construct() - * is invoked. This is handled by updating the caller's call_flags. - * - * For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume - * that the caller has provided the correct 'this' binding explicitly - * when calling, i.e.: - * - * - global code: this=global object - * - direct eval: this=copy from eval() caller's this binding - * - other eval: this=global object - * - * The 'this' coercion may cause a recursive function call with arbitrary - * side effects, because ToObject() may be called. - */ - -DUK_LOCAL DUK_INLINE void duk__coerce_nonstrict_this_binding(duk_hthread *thr, duk_idx_t idx_this) { - duk_tval *tv_this; - duk_hobject *obj_global; - - tv_this = thr->valstack_bottom + idx_this; - switch (DUK_TVAL_GET_TAG(tv_this)) { - case DUK_TAG_OBJECT: - DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly")); - break; - case DUK_TAG_UNDEFINED: - case DUK_TAG_NULL: - DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object")); - obj_global = thr->builtins[DUK_BIDX_GLOBAL]; - /* XXX: avoid this check somehow */ - if (DUK_LIKELY(obj_global != NULL)) { - DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */ - DUK_TVAL_SET_OBJECT(tv_this, obj_global); - DUK_HOBJECT_INCREF(thr, obj_global); - } else { - /* This may only happen if built-ins are being "torn down". - * This behavior is out of specification scope. - */ - DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead")); - DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */ - DUK_TVAL_SET_UNDEFINED(tv_this); /* nothing to incref */ - } - break; - default: - /* Plain buffers and lightfuncs are object coerced. Lightfuncs - * very rarely come here however, because the call target would - * need to be a non-strict non-lightfunc (lightfuncs are considered - * strict) with an explicit lightfunc 'this' binding. - */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this)); - DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)")); - duk_to_object(thr, idx_this); /* may have side effects */ - break; - } -} - -DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__resolve_target_fastpath_check(duk_hthread *thr, duk_idx_t idx_func, duk_hobject **out_func, duk_small_uint_t call_flags) { -#if defined(DUK_USE_PREFER_SIZE) - DUK_UNREF(thr); - DUK_UNREF(idx_func); - DUK_UNREF(out_func); - DUK_UNREF(call_flags); -#else /* DUK_USE_PREFER_SIZE */ - duk_tval *tv_func; - duk_hobject *func; - - if (DUK_UNLIKELY(call_flags & DUK_CALL_FLAG_CONSTRUCT)) { - return 0; - } - - tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func); - DUK_ASSERT(tv_func != NULL); - - if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv_func))) { - func = DUK_TVAL_GET_OBJECT(tv_func); - if (DUK_HOBJECT_IS_CALLABLE(func) && - !DUK_HOBJECT_HAS_BOUNDFUNC(func) && - !DUK_HOBJECT_HAS_SPECIAL_CALL(func)) { - *out_func = func; - - if (DUK_HOBJECT_HAS_STRICT(func)) { - /* Strict function: no 'this' coercion. */ - return 1; - } - - duk__coerce_nonstrict_this_binding(thr, idx_func + 1); - return 1; - } - } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) { - *out_func = NULL; - - /* Lightfuncs are considered strict, so 'this' binding is - * used as is. They're never bound, always constructable, - * and never special functions. - */ - return 1; - } -#endif /* DUK_USE_PREFER_SIZE */ - return 0; /* let slow path deal with it */ -} - -DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *thr, - duk_idx_t idx_func, - duk_small_uint_t *call_flags) { - duk_tval *tv_func; - duk_hobject *func; - duk_bool_t first; - - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - - for (first = 1;; first = 0) { - DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); - - tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func); - DUK_ASSERT(tv_func != NULL); - - if (DUK_TVAL_IS_OBJECT(tv_func)) { - func = DUK_TVAL_GET_OBJECT(tv_func); - - if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) { - if (DUK_UNLIKELY(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func))) { - goto not_constructable; - } - } else { - if (DUK_UNLIKELY(!DUK_HOBJECT_IS_CALLABLE(func))) { - goto not_callable; - } - } - - if (DUK_LIKELY(!DUK_HOBJECT_HAS_BOUNDFUNC(func) && - !DUK_HOBJECT_HAS_SPECIAL_CALL(func) && - !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func))) { - /* Common case, so test for using a single bitfield test. - * Break out to handle this coercion etc. - */ - break; - } - - /* XXX: could set specialcall for boundfuncs too, simplify check above */ - - if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) { - DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_CALL(func)); - DUK_ASSERT(!DUK_HOBJECT_IS_NATFUNC(func)); - - /* Callable/constructable flags are the same - * for the bound function and its target, so - * we don't need to check them here, we can - * check them from the target only. - */ - duk__handle_bound_chain_for_call(thr, idx_func, *call_flags & DUK_CALL_FLAG_CONSTRUCT); - - DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(thr, idx_func)) || - DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(thr, idx_func))); - } else { - DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_CALL(func)); - -#if defined(DUK_USE_ES6_PROXY) - if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func)) { - /* If no trap, resume processing from Proxy trap. - * If trap exists, helper converts call into a trap - * call; this may change a constructor call into a - * normal (non-constructor) trap call. We must - * continue processing even when a trap is found as - * the trap may be bound. - */ - duk__handle_proxy_for_call(thr, idx_func, (duk_hproxy *) func, call_flags); - } - else -#endif - { - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func)); - DUK_ASSERT(DUK_HOBJECT_HAS_CALLABLE(func)); - DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func)); - /* Constructable check already done above. */ - - if (duk__handle_specialfuncs_for_call(thr, idx_func, func, call_flags, first) != 0) { - /* Encountered native eval call, normal call - * context. Break out, handle this coercion etc. - */ - break; - } - } - } - /* Retry loop. */ - } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) { - /* Lightfuncs are: - * - Always strict, so no 'this' coercion. - * - Always callable. - * - Always constructable. - * - Never specialfuncs. - */ - func = NULL; - goto finished; - } else { - goto not_callable; - } - } - - DUK_ASSERT(func != NULL); - - if (!DUK_HOBJECT_HAS_STRICT(func)) { - /* Non-strict target needs 'this' coercion. - * This has potential side effects invalidating - * 'tv_func'. - */ - duk__coerce_nonstrict_this_binding(thr, idx_func + 1); - } - if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) { - if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) { - *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED; - duk__update_default_instance_proto(thr, idx_func); - } - } - - finished: - -#if defined(DUK_USE_ASSERTIONS) - { - duk_tval *tv_tmp; - - tv_tmp = duk_get_tval(thr, idx_func); - DUK_ASSERT(tv_tmp != NULL); - - DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_tmp) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_tmp))) || - DUK_TVAL_IS_LIGHTFUNC(tv_tmp)); - DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); - DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) || - DUK_HOBJECT_IS_NATFUNC(func))); - DUK_ASSERT(func == NULL || (DUK_HOBJECT_HAS_CONSTRUCTABLE(func) || - (*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0)); - } -#endif - - return func; - - not_callable: - DUK_ASSERT(tv_func != NULL); - -#if defined(DUK_USE_VERBOSE_ERRORS) - /* GETPROPC delayed error handling: when target is not callable, - * GETPROPC replaces idx_func+0 with an Error (non-callable) with - * a hidden Symbol to signify it's to be thrown as is here. The - * hidden Symbol is only checked as an own property, not inherited - * (which would be dangerous). - */ - if (DUK_TVAL_IS_OBJECT(tv_func)) { - if (duk_hobject_find_existing_entry_tval_ptr(thr->heap, DUK_TVAL_GET_OBJECT(tv_func), DUK_HTHREAD_STRING_INT_TARGET(thr)) != NULL) { - duk_push_tval(thr, tv_func); - (void) duk_throw(thr); - } - } -#endif - -#if defined(DUK_USE_VERBOSE_ERRORS) -#if defined(DUK_USE_PARANOID_ERRORS) - DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_get_type_name(thr, idx_func)); -#else - DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(thr, tv_func)); -#endif -#else - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); -#endif - DUK_UNREACHABLE(); - return NULL; /* never executed */ - - not_constructable: - /* For now GETPROPC delayed error not needed for constructor calls. */ -#if defined(DUK_USE_VERBOSE_ERRORS) -#if defined(DUK_USE_PARANOID_ERRORS) - DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(thr, idx_func)); -#else - DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_tval_readable(thr, tv_func)); -#endif -#else - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE); -#endif - DUK_UNREACHABLE(); - return NULL; /* never executed */ -} - -/* - * Manipulate value stack so that exactly 'num_stack_rets' return - * values are at 'idx_retbase' in every case, assuming there are - * 'rc' return values on top of stack. - * - * This is a bit tricky, because the called C function operates in - * the same activation record and may have e.g. popped the stack - * empty (below idx_retbase). - */ - -DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) { - duk_idx_t idx_rcbase; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(idx_retbase >= 0); - DUK_ASSERT(num_stack_rets >= 0); - DUK_ASSERT(num_actual_rets >= 0); - - idx_rcbase = duk_get_top(thr) - num_actual_rets; /* base of known return values */ - if (DUK_UNLIKELY(idx_rcbase < 0)) { - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC); - } - - DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: " - "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld", - (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(thr), - (long) idx_retbase, (long) idx_rcbase)); - - DUK_ASSERT(idx_rcbase >= 0); /* caller must check */ - - /* Space for num_stack_rets was reserved before the safe call. - * Because value stack reserve cannot shrink except in call returns, - * the reserve is still in place. Adjust valstack, carefully - * ensuring we don't overstep the reserve. - */ - - /* Match idx_rcbase with idx_retbase so that the return values - * start at the correct index. - */ - if (idx_rcbase > idx_retbase) { - duk_idx_t count = idx_rcbase - idx_retbase; - - DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals " - "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase)); - - /* Remove values between irc_rcbase (start of intended return - * values) and idx_retbase to lower return values to idx_retbase. - */ - DUK_ASSERT(count > 0); - duk_remove_n(thr, idx_retbase, count); /* may be NORZ */ - } else { - duk_idx_t count = idx_retbase - idx_rcbase; - - DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals " - "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase)); - - /* Insert 'undefined' at idx_rcbase (start of intended return - * values) to lift return values to idx_retbase. - */ - DUK_ASSERT(count >= 0); - DUK_ASSERT(thr->valstack_end - thr->valstack_top >= count); /* reserve cannot shrink */ - duk_insert_undefined_n(thr, idx_rcbase, count); - } - - /* Chop extra retvals away / extend with undefined. */ - duk_set_top_unsafe(thr, idx_retbase + num_stack_rets); -} - -/* - * Activation setup for tailcalls and non-tailcalls. - */ - -#if defined(DUK_USE_TAILCALL) -DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr, - duk_small_uint_t call_flags, - duk_idx_t idx_func, - duk_hobject *func, - duk_size_t entry_valstack_bottom_byteoff, - duk_size_t entry_valstack_end_byteoff, - duk_idx_t *out_nargs, - duk_idx_t *out_nregs, - duk_size_t *out_vs_min_bytes, - duk_activation **out_act) { - duk_activation *act; - duk_tval *tv1, *tv2; - duk_idx_t idx_args; - duk_small_uint_t flags1, flags2; -#if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_activation *prev_pause_act; -#endif - - DUK_UNREF(entry_valstack_end_byteoff); - - /* Tailcall cannot be flagged to resume calls, and a - * previous frame must exist. - */ - DUK_ASSERT(thr->callstack_top >= 1); - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - *out_act = act; - - if (func == NULL || !DUK_HOBJECT_IS_COMPFUNC(func)) { - DUK_DDD(DUK_DDDPRINT("tail call prevented by target not being ecma function")); - return 0; - } - if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) { - DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENT_YIELD")); - return 0; - } - /* Tailcall is only allowed if current and candidate - * function have identical return value handling. There - * are three possible return value handling cases: - * 1. Normal function call, no special return value handling. - * 2. Constructor call, return value replacement object check. - * 3. Proxy 'construct' trap call, return value invariant check. - */ - flags1 = (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT) ? 1 : 0) -#if defined(DUK_USE_ES6_PROXY) - | (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) ? 2 : 0) -#endif - ; - flags2 = (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) ? 1 : 0) -#if defined(DUK_USE_ES6_PROXY) - | (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) ? 2 : 0); -#endif - ; - if (flags1 != flags2) { - DUK_DDD(DUK_DDDPRINT("tail call prevented by incompatible return value handling")); - return 0; - } - DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT) && (call_flags & DUK_CALL_FLAG_CONSTRUCT)) || - (!(act->flags & DUK_ACT_FLAG_CONSTRUCT) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT))); - DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)) || - (!(act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY))); - if (DUK_HOBJECT_HAS_NOTAIL(func)) { - /* See: test-bug-tailcall-preventyield-assert.c. */ - DUK_DDD(DUK_DDDPRINT("tail call prevented by function having a notail flag")); - return 0; - } - - /* - * Tailcall handling - * - * Although the callstack entry is reused, we need to explicitly unwind - * the current activation (or simulate an unwind). In particular, the - * current activation must be closed, otherwise something like - * test-bug-reduce-judofyr.js results. Also catchers need to be unwound - * because there may be non-error-catching label entries in valid tail calls. - * - * Special attention is needed for debugger and pause behavior when - * reusing an activation. - * - Disable StepOut processing for the activation unwind because - * we reuse the activation, see: - * https://github.com/svaarala/duktape/issues/1684. - * - Disable line change pause flag permanently (if set) because - * it would no longer be relevant, see: - * https://github.com/svaarala/duktape/issues/1726. - * - Check for function entry (e.g. StepInto) pause flag here, because - * the executor pause check won't trigger due to shared activation, see: - * https://github.com/svaarala/duktape/issues/1726. - */ - - DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld", - (long) (thr->callstack_top - 1))); - - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); - DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func)); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func)); - DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0); - DUK_ASSERT(call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA); - - /* Unwind the topmost callstack entry before reusing it. This - * also unwinds the catchers related to the topmost entry. - */ - DUK_ASSERT(thr->callstack_top > 0); - DUK_ASSERT(thr->callstack_curr != NULL); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - prev_pause_act = thr->heap->dbg_pause_act; - thr->heap->dbg_pause_act = NULL; - thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE; - if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) { - DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry (tailcall)")); - duk_debug_set_paused(thr->heap); - } -#endif - duk_hthread_activation_unwind_reuse_norz(thr); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - thr->heap->dbg_pause_act = prev_pause_act; -#endif - DUK_ASSERT(act == thr->callstack_curr); - - /* XXX: We could restore the caller's value stack reserve - * here, as if we did an actual unwind-and-call. Without - * the restoration, value stack reserve may remain higher - * than would otherwise be possible until we return to a - * non-tailcall. - */ - - /* Then reuse the unwound activation. */ - act->cat = NULL; - act->var_env = NULL; - act->lex_env = NULL; - DUK_ASSERT(func != NULL); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func)); - act->func = func; /* don't want an intermediate exposed state with func == NULL */ -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - act->prev_caller = NULL; -#endif - /* don't want an intermediate exposed state with invalid pc */ - act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - act->prev_line = 0; -#endif - DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */ - DUK_HOBJECT_INCREF(thr, func); - - act->flags = DUK_ACT_FLAG_TAILCALLED; - if (DUK_HOBJECT_HAS_STRICT(func)) { - act->flags |= DUK_ACT_FLAG_STRICT; - } - if (call_flags & DUK_CALL_FLAG_CONSTRUCT) { - act->flags |= DUK_ACT_FLAG_CONSTRUCT; - } -#if defined(DUK_USE_ES6_PROXY) - if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) { - act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY; - } -#endif - - DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */ - DUK_ASSERT(act->var_env == NULL); - DUK_ASSERT(act->lex_env == NULL); - act->bottom_byteoff = entry_valstack_bottom_byteoff; /* tail call -> reuse current "frame" */ -#if 0 - /* Topmost activation retval_byteoff is considered garbage, no need to init. */ - act->retval_byteoff = 0; -#endif - /* Filled in when final reserve is known, dummy value doesn't matter - * even in error unwind because reserve_byteoff is only used when - * returning to -this- activation. - */ - act->reserve_byteoff = 0; - - /* - * Manipulate valstack so that args are on the current bottom and the - * previous caller's 'this' binding (which is the value preceding the - * current bottom) is replaced with the new 'this' binding: - * - * [ ... this_old | (crud) func this_new arg1 ... argN ] - * --> [ ... this_new | arg1 ... argN ] - * - * For tail calling to work properly, the valstack bottom must not grow - * here; otherwise crud would accumulate on the valstack. - */ - - tv1 = thr->valstack_bottom - 1; - tv2 = thr->valstack_bottom + idx_func + 1; - DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */ - DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top); - DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ - - idx_args = idx_func + 2; - duk_remove_n(thr, 0, idx_args); /* may be NORZ */ - - idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */ - idx_args = 0; - - *out_nargs = ((duk_hcompfunc *) func)->nargs; - *out_nregs = ((duk_hcompfunc *) func)->nregs; - DUK_ASSERT(*out_nregs >= 0); - DUK_ASSERT(*out_nregs >= *out_nargs); - *out_vs_min_bytes = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA); - - -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) -#if defined(DUK_USE_TAILCALL) -#error incorrect options: tail calls enabled with function caller property -#endif - /* XXX: This doesn't actually work properly for tail calls, so - * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY - * is in use. - */ - duk__update_func_caller_prop(thr, func); -#endif - - /* [ ... this_new | arg1 ... argN ] */ - - return 1; -} -#endif /* DUK_USE_TAILCALL */ - -DUK_LOCAL void duk__call_setup_act_not_tailcall(duk_hthread *thr, - duk_small_uint_t call_flags, - duk_idx_t idx_func, - duk_hobject *func, - duk_size_t entry_valstack_bottom_byteoff, - duk_size_t entry_valstack_end_byteoff, - duk_idx_t *out_nargs, - duk_idx_t *out_nregs, - duk_size_t *out_vs_min_bytes, - duk_activation **out_act) { - duk_activation *act; - duk_activation *new_act; - - DUK_UNREF(entry_valstack_end_byteoff); - - DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld", - (long) (thr->callstack_top))); - - duk__call_callstack_limit_check(thr); - new_act = duk_hthread_activation_alloc(thr); - DUK_ASSERT(new_act != NULL); - - act = thr->callstack_curr; - if (act != NULL) { - /* - * Update return value stack index of current activation (if any). - * - * Although it might seem this is not necessary (bytecode executor - * does this for Ecmascript-to-Ecmascript calls; other calls are - * handled here), this turns out to be necessary for handling yield - * and resume. For them, an Ecmascript-to-native call happens, and - * the Ecmascript call's retval_byteoff must be set for things to work. - */ - - act->retval_byteoff = entry_valstack_bottom_byteoff + (duk_size_t) idx_func * sizeof(duk_tval); - } - - new_act->parent = act; - thr->callstack_curr = new_act; - thr->callstack_top++; - act = new_act; - *out_act = act; - - DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */ - DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); - - act->cat = NULL; - - act->flags = 0; - if (call_flags & DUK_CALL_FLAG_CONSTRUCT) { - act->flags |= DUK_ACT_FLAG_CONSTRUCT; - } -#if defined(DUK_USE_ES6_PROXY) - if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) { - act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY; - } -#endif - if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) { - act->flags |= DUK_ACT_FLAG_DIRECT_EVAL; - } - - /* start of arguments: idx_func + 2. */ - act->func = func; /* NULL for lightfunc */ - if (DUK_LIKELY(func != NULL)) { - DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */ - if (DUK_HOBJECT_HAS_STRICT(func)) { - act->flags |= DUK_ACT_FLAG_STRICT; - } - if (DUK_HOBJECT_IS_COMPFUNC(func)) { - *out_nargs = ((duk_hcompfunc *) func)->nargs; - *out_nregs = ((duk_hcompfunc *) func)->nregs; - DUK_ASSERT(*out_nregs >= 0); - DUK_ASSERT(*out_nregs >= *out_nargs); - *out_vs_min_bytes = entry_valstack_bottom_byteoff + - sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA); - } else { - /* True because of call target lookup checks. */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func)); - - *out_nargs = ((duk_hnatfunc *) func)->nargs; - *out_nregs = *out_nargs; - if (*out_nargs >= 0) { - *out_vs_min_bytes = entry_valstack_bottom_byteoff + - sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); - } else { - /* Vararg function. */ - duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack)); - *out_vs_min_bytes = valstack_top_byteoff + - sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); - } - } - } else { - duk_small_uint_t lf_flags; - duk_tval *tv_func; - - act->flags |= DUK_ACT_FLAG_STRICT; - - tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func); - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func)); - DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */ - - lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func); - *out_nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags); - if (*out_nargs != DUK_LFUNC_NARGS_VARARGS) { - *out_vs_min_bytes = entry_valstack_bottom_byteoff + - sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nargs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); - } else { - duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack)); - *out_vs_min_bytes = valstack_top_byteoff + - sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); - *out_nargs = -1; /* vararg */ - } - *out_nregs = *out_nargs; - } - - act->var_env = NULL; - act->lex_env = NULL; -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - act->prev_caller = NULL; -#endif - act->curr_pc = NULL; -#if defined(DUK_USE_DEBUGGER_SUPPORT) - act->prev_line = 0; -#endif - act->bottom_byteoff = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) idx_func + 2U); -#if 0 - act->retval_byteoff = 0; /* topmost activation retval_byteoff is considered garbage, no need to init */ -#endif - /* Filled in when final reserve is known, dummy value doesn't matter - * even in error unwind because reserve_byteoff is only used when - * returning to -this- activation. - */ - act->reserve_byteoff = 0; /* filled in by caller */ - - /* XXX: Is this INCREF necessary? 'func' is always a borrowed - * reference reachable through the value stack? If changed, stack - * unwind code also needs to be fixed to match. - */ - DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */ - -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - if (func) { - duk__update_func_caller_prop(thr, func); - } -#endif -} - -/* - * Environment setup. - */ - -DUK_LOCAL void duk__call_env_setup(duk_hthread *thr, duk_hobject *func, duk_activation *act, duk_idx_t idx_args) { - duk_hobject *env; - - DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function has already been resolved */ - - if (DUK_LIKELY(func != NULL)) { - if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) { - if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) { - /* Use a new environment but there's no 'arguments' object; - * delayed environment initialization. This is the most - * common case. - */ - DUK_ASSERT(act->lex_env == NULL); - DUK_ASSERT(act->var_env == NULL); - } else { - /* Use a new environment and there's an 'arguments' object. - * We need to initialize it right now. - */ - - /* third arg: absolute index (to entire valstack) of bottom_byteoff of new activation */ - env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff); - DUK_ASSERT(env != NULL); - - /* [ ... func this arg1 ... argN envobj ] */ - - DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func)); - duk__handle_createargs_for_call(thr, func, env, idx_args); - - /* [ ... func this arg1 ... argN envobj ] */ - - act->lex_env = env; - act->var_env = env; - DUK_HOBJECT_INCREF(thr, env); - DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */ - duk_pop(thr); - } - } else { - /* Use existing env (e.g. for non-strict eval); cannot have - * an own 'arguments' object (but can refer to an existing one). - */ - - DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func)); - - duk__handle_oldenv_for_call(thr, func, act); - - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - } - } else { - /* Lightfuncs are always native functions and have "newenv". */ - DUK_ASSERT(act->lex_env == NULL); - DUK_ASSERT(act->var_env == NULL); - } -} - -/* - * Misc shared helpers. - */ - -/* Check thread state, update current thread. */ -DUK_LOCAL void duk__call_thread_state_update(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - - if (DUK_LIKELY(thr == thr->heap->curr_thread)) { - if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_RUNNING)) { - /* Should actually never happen, but check anyway. */ - goto thread_state_error; - } - } else { - DUK_ASSERT(thr->heap->curr_thread == NULL || - thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING); - if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_INACTIVE)) { - goto thread_state_error; - } - DUK_HEAP_SWITCH_THREAD(thr->heap, thr); - thr->state = DUK_HTHREAD_STATE_RUNNING; - - /* Multiple threads may be simultaneously in the RUNNING - * state, but not in the same "resume chain". - */ - } - DUK_ASSERT(thr->heap->curr_thread == thr); - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); - return; - - thread_state_error: - DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state (%ld)", (long) thr->state); - DUK_UNREACHABLE(); -} - -/* - * Main unprotected call handler, handles: - * - * - All combinations of native/Ecmascript caller and native/Ecmascript - * target. - * - * - Optimized Ecmascript-to-Ecmascript call where call handling only - * sets up a new duk_activation but reuses an existing bytecode executor - * (the caller) without native recursion. - * - * - Tailcalls, where an activation is reused without increasing call - * stack (duk_activation) depth. - * - * - Setup for an initial Duktape.Thread.resume(). - * - * The call handler doesn't provide any protection guarantees, protected calls - * must be implemented e.g. by wrapping the call in a duk_safe_call(). - * Call setup may fail at any stage, even when the new activation is in - * place; the only guarantee is that the state is consistent for unwinding. - */ - -DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr, - duk_idx_t idx_func, - duk_small_uint_t call_flags) { -#if defined(DUK_USE_ASSERTIONS) - duk_activation *entry_act; - duk_size_t entry_callstack_top; -#endif - duk_size_t entry_valstack_bottom_byteoff; - duk_size_t entry_valstack_end_byteoff; - duk_int_t entry_call_recursion_depth; - duk_hthread *entry_curr_thread; - duk_uint_fast8_t entry_thread_state; - duk_instr_t **entry_ptr_curr_pc; - duk_idx_t idx_args; - duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */ - duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */ - duk_size_t vs_min_bytes; /* minimum value stack size (bytes) for handling call */ - duk_hobject *func; /* 'func' on stack (borrowed reference) */ - duk_activation *act; - duk_ret_t rc; - duk_small_uint_t use_tailcall; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - /* Asserts for heap->curr_thread omitted: it may be NULL, 'thr', or - * any other thread (e.g. when heap thread is used to run finalizers). - */ - DUK_ASSERT_CTX_VALID(thr); - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - DUK_ASSERT(idx_func >= 0); - - DUK_STATS_INC(thr->heap, stats_call_all); - - /* If a tail call: - * - an Ecmascript activation must be on top of the callstack - * - there cannot be any catch stack entries that would catch - * a return - */ -#if defined(DUK_USE_ASSERTIONS) - if (call_flags & DUK_CALL_FLAG_TAILCALL) { - duk_activation *tmp_act; - duk_catcher *tmp_cat; - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); - - /* No entry in the catch stack which would actually catch a - * throw can refer to the callstack entry being reused. - * There *can* be catch stack entries referring to the current - * callstack entry as long as they don't catch (e.g. label sites). - */ - - tmp_act = thr->callstack_curr; - for (tmp_cat = tmp_act->cat; tmp_cat != NULL; tmp_cat = tmp_cat->parent) { - DUK_ASSERT(DUK_CAT_GET_TYPE(tmp_cat) == DUK_CAT_TYPE_LABEL); /* a non-catching entry */ - } - } -#endif /* DUK_USE_ASSERTIONS */ - - /* - * Store entry state. - */ - -#if defined(DUK_USE_ASSERTIONS) - entry_act = thr->callstack_curr; - entry_callstack_top = thr->callstack_top; -#endif - entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); - entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); - entry_call_recursion_depth = thr->heap->call_recursion_depth; - entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */ - entry_thread_state = thr->state; - entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */ - - /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL - * thr->ptr_curr_pc so that it's not accidentally used with an incorrect - * activation when side effects occur. - */ - duk_hthread_sync_and_null_currpc(thr); - DUK_ASSERT(thr->ptr_curr_pc == NULL); - - DUK_DD(DUK_DDPRINT("duk__handle_call_raw: thr=%p, idx_func=%ld, " - "call_flags=0x%08lx (constructor=%ld), " - "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, " - "entry_valstack_bottom_byteoff=%ld, entry_valstack_end_byteoff=%ld, " - "entry_call_recursion_depth=%ld, " - "entry_curr_thread=%p, entry_thread_state=%ld", - (void *) thr, - (long) idx_func, - (unsigned long) call_flags, - (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) != 0 ? 1 : 0), - (long) duk_get_top(thr), - (long) idx_func, - (long) (idx_func + 2), - (long) thr->heap->call_recursion_depth, - (long) thr->heap->call_recursion_limit, - (long) entry_valstack_bottom_byteoff, - (long) entry_valstack_end_byteoff, - (long) entry_call_recursion_depth, - (void *) entry_curr_thread, - (long) entry_thread_state)); - - /* - * Thread state check and book-keeping. - */ - - duk__call_thread_state_update(thr); - - /* - * Resolve final target function; handle bound functions and special - * functions like .call() and .apply(). Also figure out the effective - * 'this' binding, which replaces the current value at idx_func + 1. - */ - - if (DUK_LIKELY(duk__resolve_target_fastpath_check(thr, idx_func, &func, call_flags) != 0U)) { - DUK_DDD(DUK_DDDPRINT("fast path target resolve")); - } else { - DUK_DDD(DUK_DDDPRINT("slow path target resolve")); - func = duk__resolve_target_func_and_this_binding(thr, idx_func, &call_flags); - } - DUK_ASSERT(duk_get_top(thr) - idx_func >= 2); /* at least func and this present */ - - DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); - DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) || - DUK_HOBJECT_IS_NATFUNC(func))); - - /* [ ... func this arg1 ... argN ] */ - - /* - * Setup a preliminary activation and figure out nargs/nregs and - * value stack minimum size. - * - * Don't touch valstack_bottom or valstack_top yet so that Duktape API - * calls work normally. - * - * Because 'act' is not zeroed, all fields must be filled in. - */ - -#if defined(DUK_USE_TAILCALL) - use_tailcall = (call_flags & DUK_CALL_FLAG_TAILCALL); - if (use_tailcall) { - use_tailcall = duk__call_setup_act_attempt_tailcall(thr, - call_flags, - idx_func, - func, - entry_valstack_bottom_byteoff, - entry_valstack_end_byteoff, - &nargs, - &nregs, - &vs_min_bytes, - &act); - } -#else - DUK_ASSERT((call_flags & DUK_CALL_FLAG_TAILCALL) == 0); /* compiler ensures this */ - use_tailcall = 0; -#endif - - if (use_tailcall) { - idx_args = 0; - DUK_STATS_INC(thr->heap, stats_call_tailcall); - } else { - duk__call_setup_act_not_tailcall(thr, - call_flags, - idx_func, - func, - entry_valstack_bottom_byteoff, - entry_valstack_end_byteoff, - &nargs, - &nregs, - &vs_min_bytes, - &act); - idx_args = idx_func + 2; - } - /* After this point idx_func is no longer valid for tailcalls. */ - - DUK_ASSERT(act != NULL); - - /* [ ... func this arg1 ... argN ] */ - - /* - * Environment record creation and 'arguments' object creation. - * Named function expression name binding is handled by the - * compiler; the compiled function's parent env will contain - * the (immutable) binding already. - * - * This handling is now identical for C and Ecmascript functions. - * C functions always have the 'NEWENV' flag set, so their - * environment record initialization is delayed (which is good). - * - * Delayed creation (on demand) is handled in duk_js_var.c. - */ - - duk__call_env_setup(thr, func, act, idx_args); - - /* [ ... func this arg1 ... argN ] */ - - /* - * Setup value stack: clamp to 'nargs', fill up to 'nregs', - * ensure value stack size matches target requirements, and - * switch value stack bottom. Valstack top is kept. - * - * Value stack can only grow here. - */ - - duk_valstack_grow_check_throw(thr, vs_min_bytes); - act->reserve_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); - - if (use_tailcall) { - DUK_ASSERT(nregs >= 0); - DUK_ASSERT(nregs >= nargs); - duk_set_top_and_wipe(thr, nregs, nargs); - } else { - if (nregs >= 0) { - DUK_ASSERT(nregs >= nargs); - duk_set_top_and_wipe(thr, idx_func + 2 + nregs, idx_func + 2 + nargs); - } else { - ; - } - thr->valstack_bottom = thr->valstack_bottom + idx_func + 2; - } - DUK_ASSERT(thr->valstack_bottom >= thr->valstack); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - - /* - * Make the actual call. For Ecma-to-Ecma calls detect that - * setup is complete, then return with a status code that allows - * the caller to reuse the running executor. - */ - - if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { - /* - * Ecmascript call. - */ - - DUK_ASSERT(func != NULL); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func)); - act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func); - - if (call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA) { - DUK_DD(DUK_DDPRINT("avoid native call, use existing executor")); - DUK_STATS_INC(thr->heap, stats_call_ecmatoecma); - DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0); - DUK_REFZERO_CHECK_FAST(thr); - DUK_ASSERT(thr->ptr_curr_pc == NULL); - return 1; /* 1=reuse executor */ - } - DUK_ASSERT(use_tailcall == 0); - - /* duk_hthread_activation_unwind_norz() will decrease this on unwind */ - DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0); - act->flags |= DUK_ACT_FLAG_PREVENT_YIELD; - thr->callstack_preventcount++; - - /* XXX: we could just do this on entry regardless of reuse, as long - * as recursion depth is decreased for e2e case. - */ - duk__call_c_recursion_limit_check(thr); - thr->heap->call_recursion_depth++; - - /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */ - - /* - * Bytecode executor call. - * - * Execute bytecode, handling any recursive function calls and - * thread resumptions. Returns when execution would return from - * the entry level activation. When the executor returns, a - * single return value is left on the stack top. - * - * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW), - * other types are handled internally by the executor. - */ - - /* thr->ptr_curr_pc is set by bytecode executor early on entry */ - DUK_ASSERT(thr->ptr_curr_pc == NULL); - DUK_DDD(DUK_DDDPRINT("entering bytecode execution")); - duk_js_execute_bytecode(thr); - DUK_DDD(DUK_DDDPRINT("returned from bytecode execution")); - } else { - /* - * Native call. - */ - - DUK_ASSERT(func == NULL || ((duk_hnatfunc *) func)->func != NULL); - DUK_ASSERT(use_tailcall == 0); - - /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */ - - /* duk_hthread_activation_unwind_norz() will decrease this on unwind */ - DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0); - act->flags |= DUK_ACT_FLAG_PREVENT_YIELD; - thr->callstack_preventcount++; - - /* XXX: we could just do this on entry regardless of reuse, as long - * as recursion depth is decreased for e2e case. - */ - duk__call_c_recursion_limit_check(thr); - thr->heap->call_recursion_depth++; - - /* For native calls must be NULL so we don't sync back */ - DUK_ASSERT(thr->ptr_curr_pc == NULL); - - /* XXX: native funcptr could come out of call setup. */ - if (func) { - rc = ((duk_hnatfunc *) func)->func(thr); - } else { - duk_tval *tv_func; - duk_c_function funcptr; - - tv_func = &act->tv_func; - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func)); - funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func); - rc = funcptr(thr); - } - - /* Automatic error throwing, retval check. */ - - if (rc == 0) { - DUK_ASSERT(thr->valstack < thr->valstack_end); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); - thr->valstack_top++; - } else if (rc == 1) { - ; - } else if (rc < 0) { - duk_error_throw_from_negative_rc(thr, rc); - DUK_UNREACHABLE(); - } else { - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC); - } - } - DUK_ASSERT(thr->ptr_curr_pc == NULL); - DUK_ASSERT(use_tailcall == 0); - - /* - * Constructor call post processing. - */ - -#if defined(DUK_USE_ES6_PROXY) - if (call_flags & (DUK_CALL_FLAG_CONSTRUCT | DUK_CALL_FLAG_CONSTRUCT_PROXY)) { - duk_call_construct_postprocess(thr, call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY); - } -#else - if (call_flags & DUK_CALL_FLAG_CONSTRUCT) { - duk_call_construct_postprocess(thr, 0); - } -#endif - - /* - * Unwind, restore valstack bottom and other book-keeping. - */ - - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(thr->callstack_curr->parent == entry_act); - DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_activation_unwind_norz(thr); - DUK_ASSERT(thr->callstack_curr == entry_act); - DUK_ASSERT(thr->callstack_top == entry_callstack_top); - - thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff); - /* keep current valstack_top */ - DUK_ASSERT(thr->valstack_bottom >= thr->valstack); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1); - - /* Return value handling. */ - - /* [ ... func this (crud) retval ] */ - - { - duk_tval *tv_ret; - duk_tval *tv_funret; - - tv_ret = thr->valstack_bottom + idx_func; - tv_funret = thr->valstack_top - 1; -#if defined(DUK_USE_FASTINT) - /* Explicit check for fastint downgrade. */ - DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret); -#endif - DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */ - } - - duk_set_top_unsafe(thr, idx_func + 1); - - /* [ ... retval ] */ - - /* Restore caller's value stack reserve (cannot fail). */ - DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff >= (duk_uint8_t *) thr->valstack_top); - DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff <= (duk_uint8_t *) thr->valstack_alloc_end); - thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff); - - /* XXX: Trial value stack shrink would be OK here, but we'd need - * to prevent side effects of the potential realloc. - */ - - /* Restore entry thread executor curr_pc stack frame pointer. */ - thr->ptr_curr_pc = entry_ptr_curr_pc; - - DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ - thr->state = (duk_uint8_t) entry_thread_state; - - /* Disabled assert: triggered with some torture tests. */ -#if 0 - DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ - (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ - (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ -#endif - - thr->heap->call_recursion_depth = entry_call_recursion_depth; - - /* If the debugger is active we need to force an interrupt so that - * debugger breakpoints are rechecked. This is important for function - * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see - * GH-303. Only needed for success path, error path always causes a - * breakpoint recheck in the executor. It would be enough to set this - * only when returning to an Ecmascript activation, but setting the flag - * on every return should have no ill effect. - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (duk_debug_is_attached(thr->heap)) { - DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); - DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); - thr->interrupt_init -= thr->interrupt_counter; - thr->interrupt_counter = 0; - thr->heap->dbg_force_restart = 1; - } -#endif - -#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) - duk__interrupt_fixup(thr, entry_curr_thread); -#endif - - /* Restored by success path. */ - DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); - DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); - DUK_ASSERT_LJSTATE_UNSET(thr->heap); - - DUK_REFZERO_CHECK_FAST(thr); - - return 0; /* 0=call handled inline */ -} - -DUK_INTERNAL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, - duk_idx_t nargs, - duk_small_uint_t call_flags) { - duk_idx_t idx_func; - DUK_ASSERT(duk_get_top(thr) >= nargs + 2); - idx_func = duk_get_top(thr) - (nargs + 2); - DUK_ASSERT(idx_func >= 0); - return duk_handle_call_unprotected(thr, idx_func, call_flags); -} - -DUK_INTERNAL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, - duk_idx_t idx_func, - duk_small_uint_t call_flags) { - DUK_ASSERT(duk_is_valid_index(thr, idx_func)); - DUK_ASSERT(idx_func >= 0); - return duk__handle_call_raw(thr, idx_func, call_flags); -} - -/* - * duk_handle_safe_call(): make a "C protected call" within the - * current activation. - * - * The allowed thread states for making a call are the same as for - * duk_handle_call_protected(). - * - * Even though this call is protected, errors are thrown for insane arguments - * and may result in a fatal error unless there's another protected call which - * catches such errors. - * - * The error handling path should be error free, even for out-of-memory - * errors, to ensure safe sandboxing. (As of Duktape 2.2.0 this is not - * yet the case for environment closing which may run out of memory, see - * XXX notes below.) - */ - -DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr, - duk_safe_call_function func, - void *udata, -#if defined(DUK_USE_ASSERTIONS) - duk_size_t entry_valstack_bottom_byteoff, - duk_size_t entry_callstack_top, -#endif - duk_hthread *entry_curr_thread, - duk_uint_fast8_t entry_thread_state, - duk_idx_t idx_retbase, - duk_idx_t num_stack_rets) { - duk_ret_t rc; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT_CTX_VALID(thr); - - /* - * Thread state check and book-keeping. - */ - - duk__call_thread_state_update(thr); - - /* - * Recursion limit check. - */ - - duk__call_c_recursion_limit_check(thr); - thr->heap->call_recursion_depth++; - - /* - * Make the C call. - */ - - rc = func(thr, udata); - - DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc)); - - /* - * Valstack manipulation for results. - */ - - /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */ - DUK_ASSERT(thr->callstack_top == entry_callstack_top); - DUK_ASSERT(thr->valstack_bottom >= thr->valstack); - DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); - DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - - if (DUK_UNLIKELY(rc < 0)) { - duk_error_throw_from_negative_rc(thr, rc); - } - DUK_ASSERT(rc >= 0); - - duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); /* throws for insane rc */ - - DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ - thr->state = (duk_uint8_t) entry_thread_state; -} - -DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr, - duk_activation *entry_act, -#if defined(DUK_USE_ASSERTIONS) - duk_size_t entry_callstack_top, -#endif - duk_hthread *entry_curr_thread, - duk_uint_fast8_t entry_thread_state, - duk_idx_t idx_retbase, - duk_idx_t num_stack_rets, - duk_size_t entry_valstack_bottom_byteoff, - duk_jmpbuf *old_jmpbuf_ptr) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT_CTX_VALID(thr); - - /* - * Error during call. The error value is at heap->lj.value1. - * - * The very first thing we do is restore the previous setjmp catcher. - * This means that any error in error handling will propagate outwards - * instead of causing a setjmp() re-entry above. - */ - - DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()")); - - /* Other longjmp types are handled by executor before propagating - * the error here. - */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); - DUK_ASSERT_LJSTATE_SET(thr->heap); - - /* Either pointer may be NULL (at entry), so don't assert. */ - thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; - - /* XXX: callstack unwind may now throw an error when closing - * scopes; this is a sandboxing issue, described in: - * https://github.com/svaarala/duktape/issues/476 - */ - /* XXX: "unwind to" primitive? */ - - DUK_ASSERT(thr->callstack_top >= entry_callstack_top); - while (thr->callstack_curr != entry_act) { - DUK_ASSERT(thr->callstack_curr != NULL); - duk_hthread_activation_unwind_norz(thr); - } - DUK_ASSERT(thr->callstack_top == entry_callstack_top); - - /* Switch active thread before any side effects to avoid a - * dangling curr_thread pointer. - */ - DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ - thr->state = (duk_uint8_t) entry_thread_state; - - DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread); - DUK_ASSERT(thr->state == entry_thread_state); - - /* Restore valstack bottom. */ - thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff); - - /* [ ... | (crud) ] */ - - /* XXX: ensure space in valstack (now relies on internal reserve)? */ - duk_push_tval(thr, &thr->heap->lj.value1); - - /* [ ... | (crud) errobj ] */ - - DUK_ASSERT(duk_get_top(thr) >= 1); /* at least errobj must be on stack */ - - duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */ - - /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */ - - /* Reset longjmp state. */ - thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN; - thr->heap->lj.iserror = 0; - DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value1); - DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value2); - - /* Error handling complete, remove side effect protections. Caller - * will process pending finalizers. - */ -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(thr->heap->error_not_allowed == 1); - thr->heap->error_not_allowed = 0; -#endif - DUK_ASSERT(thr->heap->pf_prevent_count > 0); - thr->heap->pf_prevent_count--; - DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); - - /* thr->ptr_curr_pc is restored by - * duk__handle_safe_call_shared_unwind() which is also used for - * success path. - */ -} - -DUK_LOCAL void duk__handle_safe_call_shared_unwind(duk_hthread *thr, - duk_idx_t idx_retbase, - duk_idx_t num_stack_rets, -#if defined(DUK_USE_ASSERTIONS) - duk_size_t entry_callstack_top, -#endif - duk_int_t entry_call_recursion_depth, - duk_hthread *entry_curr_thread, - duk_instr_t **entry_ptr_curr_pc) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT_CTX_VALID(thr); - DUK_UNREF(idx_retbase); - DUK_UNREF(num_stack_rets); - DUK_UNREF(entry_curr_thread); - - DUK_ASSERT(thr->callstack_top == entry_callstack_top); - - /* Restore entry thread executor curr_pc stack frame pointer. - * XXX: would be enough to do in error path only, should nest - * cleanly in success path. - */ - thr->ptr_curr_pc = entry_ptr_curr_pc; - - thr->heap->call_recursion_depth = entry_call_recursion_depth; - - /* stack discipline consistency check */ - DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets); - - /* A debugger forced interrupt check is not needed here, as - * problematic safe calls are not caused by side effects. - */ - -#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) - duk__interrupt_fixup(thr, entry_curr_thread); -#endif -} - -DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr, - duk_safe_call_function func, - void *udata, - duk_idx_t num_stack_args, - duk_idx_t num_stack_rets) { - duk_activation *entry_act; - duk_size_t entry_valstack_bottom_byteoff; -#if defined(DUK_USE_ASSERTIONS) - duk_size_t entry_valstack_end_byteoff; - duk_size_t entry_callstack_top; - duk_size_t entry_callstack_preventcount; -#endif - duk_int_t entry_call_recursion_depth; - duk_hthread *entry_curr_thread; - duk_uint_fast8_t entry_thread_state; - duk_instr_t **entry_ptr_curr_pc; - duk_jmpbuf *old_jmpbuf_ptr = NULL; - duk_jmpbuf our_jmpbuf; - duk_idx_t idx_retbase; - duk_int_t retval; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(duk_get_top(thr) >= num_stack_args); /* Caller ensures. */ - - DUK_STATS_INC(thr->heap, stats_safecall_all); - - /* Value stack reserve handling: safe call assumes caller has reserved - * space for nrets (assuming optimal unwind processing). Value stack - * reserve is not stored/restored as for normal calls because a safe - * call conceptually happens in the same activation. - */ - - /* Careful with indices like '-x'; if 'x' is zero, it refers to bottom */ - entry_act = thr->callstack_curr; - entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); -#if defined(DUK_USE_ASSERTIONS) - entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); - entry_callstack_top = thr->callstack_top; - entry_callstack_preventcount = thr->callstack_preventcount; -#endif - entry_call_recursion_depth = thr->heap->call_recursion_depth; - entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */ - entry_thread_state = thr->state; - entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */ - idx_retbase = duk_get_top(thr) - num_stack_args; /* not a valid stack index if num_stack_args == 0 */ - DUK_ASSERT(idx_retbase >= 0); - - DUK_ASSERT((duk_idx_t) (thr->valstack_top - thr->valstack_bottom) >= num_stack_args); /* Caller ensures. */ - DUK_ASSERT((duk_idx_t) (thr->valstack_end - (thr->valstack_bottom + idx_retbase)) >= num_stack_rets); /* Caller ensures. */ - - /* Cannot portably debug print a function pointer, hence 'func' not printed! */ - DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, " - "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, " - "entry_act=%p, entry_valstack_bottom_byteoff=%ld, entry_call_recursion_depth=%ld, " - "entry_curr_thread=%p, entry_thread_state=%ld", - (void *) thr, - (long) num_stack_args, - (long) num_stack_rets, - (long) duk_get_top(thr), - (long) idx_retbase, - (long) thr->heap->call_recursion_depth, - (long) thr->heap->call_recursion_limit, - (void *) entry_act, - (long) entry_valstack_bottom_byteoff, - (long) entry_call_recursion_depth, - (void *) entry_curr_thread, - (long) entry_thread_state)); - - /* Setjmp catchpoint setup. */ - old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr; - thr->heap->lj.jmpbuf_ptr = &our_jmpbuf; - - /* Prevent yields for the duration of the safe call. This only - * matters if the executor makes safe calls to functions that - * yield, this doesn't currently happen. - */ - thr->callstack_preventcount++; - -#if defined(DUK_USE_CPP_EXCEPTIONS) - try { -#else - DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf); - if (DUK_SETJMP(our_jmpbuf.jb) == 0) { - /* Success path. */ -#endif - DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete")); - - duk__handle_safe_call_inner(thr, - func, - udata, -#if defined(DUK_USE_ASSERTIONS) - entry_valstack_bottom_byteoff, - entry_callstack_top, -#endif - entry_curr_thread, - entry_thread_state, - idx_retbase, - num_stack_rets); - - DUK_STATS_INC(thr->heap, stats_safecall_nothrow); - - /* Either pointer may be NULL (at entry), so don't assert */ - thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; - - /* If calls happen inside the safe call, these are restored by - * whatever calls are made. Reserve cannot decrease. - */ - DUK_ASSERT(thr->callstack_curr == entry_act); - DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); - - retval = DUK_EXEC_SUCCESS; -#if defined(DUK_USE_CPP_EXCEPTIONS) - } catch (duk_internal_exception &exc) { - DUK_UNREF(exc); -#else - } else { - /* Error path. */ -#endif - DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); - - DUK_STATS_INC(thr->heap, stats_safecall_throw); - - duk__handle_safe_call_error(thr, - entry_act, -#if defined(DUK_USE_ASSERTIONS) - entry_callstack_top, -#endif - entry_curr_thread, - entry_thread_state, - idx_retbase, - num_stack_rets, - entry_valstack_bottom_byteoff, - old_jmpbuf_ptr); - - retval = DUK_EXEC_ERROR; - } -#if defined(DUK_USE_CPP_EXCEPTIONS) - catch (std::exception &exc) { - const char *what = exc.what(); - DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); - DUK_STATS_INC(thr->heap, stats_safecall_throw); - if (!what) { - what = "unknown"; - } - DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)")); - try { - DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what); - } catch (duk_internal_exception exc) { - DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception")); - DUK_UNREF(exc); - duk__handle_safe_call_error(thr, - entry_act, -#if defined(DUK_USE_ASSERTIONS) - entry_callstack_top, -#endif - entry_curr_thread, - entry_thread_state, - idx_retbase, - num_stack_rets, - entry_valstack_bottom_byteoff, - old_jmpbuf_ptr); - retval = DUK_EXEC_ERROR; - } - } catch (...) { - DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)")); - DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); - DUK_STATS_INC(thr->heap, stats_safecall_throw); - try { - DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)"); - } catch (duk_internal_exception exc) { - DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception")); - DUK_UNREF(exc); - duk__handle_safe_call_error(thr, - entry_act, -#if defined(DUK_USE_ASSERTIONS) - entry_callstack_top, -#endif - entry_curr_thread, - entry_thread_state, - idx_retbase, - num_stack_rets, - entry_valstack_bottom_byteoff, - old_jmpbuf_ptr); - retval = DUK_EXEC_ERROR; - } - } -#endif - - DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */ - - DUK_ASSERT_LJSTATE_UNSET(thr->heap); - - DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); - duk__handle_safe_call_shared_unwind(thr, - idx_retbase, - num_stack_rets, -#if defined(DUK_USE_ASSERTIONS) - entry_callstack_top, -#endif - entry_call_recursion_depth, - entry_curr_thread, - entry_ptr_curr_pc); - - /* Restore preventcount. */ - thr->callstack_preventcount--; - DUK_ASSERT(thr->callstack_preventcount == entry_callstack_preventcount); - - /* Final asserts. */ - DUK_ASSERT(thr->callstack_curr == entry_act); - DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff); - DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); - DUK_ASSERT(thr->callstack_top == entry_callstack_top); - DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); - DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread); - DUK_ASSERT(thr->state == entry_thread_state); - DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); - DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets); - DUK_ASSERT_LJSTATE_UNSET(thr->heap); - - /* Pending side effects. */ - DUK_REFZERO_CHECK_FAST(thr); - - return retval; -} - -/* - * Property-based call (foo.noSuch()) error setup: replace target function - * on stack top with a specially tagged (hidden Symbol) error which gets - * thrown in call handling at the proper spot to follow Ecmascript semantics. - */ - -#if defined(DUK_USE_VERBOSE_ERRORS) -DUK_INTERNAL DUK_NOINLINE DUK_COLD void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key) { - const char *str1, *str2, *str3; - duk_idx_t entry_top; - - entry_top = duk_get_top(thr); - - /* Must stabilize pointers first. Argument convention is a bit awkward, - * it comes from the executor call site where some arguments may not be - * on the value stack (consts). - */ - duk_push_tval(thr, tv_base); - duk_push_tval(thr, tv_key); - duk_push_tval(thr, tv_targ); - - DUK_GC_TORTURE(thr->heap); - - /* We only push an error, replacing the call target (at idx_func) - * with the error to ensure side effects come out correctly: - * - Property read - * - Call argument evaluation - * - Callability check and error thrown. - * - * A hidden Symbol on the error object pushed here is used by - * call handling to figure out the error is to be thrown as is. - * It is CRITICAL that the hidden Symbol can never occur on a - * user visible object that may get thrown. - */ - -#if defined(DUK_USE_PARANOID_ERRORS) - str1 = duk_get_type_name(thr, -1); - str2 = duk_get_type_name(thr, -2); - str3 = duk_get_type_name(thr, -3); - duk_push_error_object(thr, DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, "%s not callable (property %s of %s)", str1, str2, str3); -#else - str1 = duk_push_string_readable(thr, -1); - str2 = duk_push_string_readable(thr, -3); - str3 = duk_push_string_readable(thr, -5); - duk_push_error_object(thr, DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, "%s not callable (property %s of %s)", str1, str2, str3); -#endif - - duk_push_true(thr); - duk_put_prop_stridx(thr, -2, DUK_STRIDX_INT_TARGET); /* Marker property, reuse _Target. */ - - /* [ propValue error ] */ - duk_replace(thr, entry_top - 1); - duk_set_top(thr, entry_top); - - DUK_ASSERT(!duk_is_callable(thr, -1)); /* Critical so that call handling will throw the error. */ -} -#endif /* DUK_USE_VERBOSE_ERRORS */ - -/* automatic undefs */ -#undef DUK__AUGMENT_CALL_RELAX_COUNT -#line 1 "duk_js_compiler.c" -/* - * Ecmascript compiler. - * - * Parses an input string and generates a function template result. - * Compilation may happen in multiple contexts (global code, eval - * code, function code). - * - * The parser uses a traditional top-down recursive parsing for the - * statement level, and an operator precedence based top-down approach - * for the expression level. The attempt is to minimize the C stack - * depth. Bytecode is generated directly without an intermediate - * representation (tree), at the cost of needing two (and sometimes - * three) passes over each function. - * - * The top-down recursive parser functions are named "duk__parse_XXX". - * - * Recursion limits are in key functions to prevent arbitrary C recursion: - * function body parsing, statement parsing, and expression parsing. - * - * See doc/compiler.rst for discussion on the design. - * - * A few typing notes: - * - * - duk_regconst_t: signed, highest bit set (< 0) means constant, - * some call sites use -1 for "none" (equivalent to constant 0x7fffffff) - * - PC values: duk_int_t, negative values used as markers - */ - -/* #include duk_internal.h -> already included */ - -/* If highest bit of a register number is set, it refers to a constant instead. - * When interpreted as a signed value, this means const values are always - * negative (when interpreted as two's complement). For example DUK__ISREG_TEMP() - * uses this approach to avoid an explicit DUK__ISREG() check (the condition is - * logically "'x' is a register AND 'x' >= temp_first"). - */ -#define DUK__CONST_MARKER DUK_REGCONST_CONST_MARKER -#define DUK__REMOVECONST(x) ((x) & ~DUK__CONST_MARKER) -#define DUK__ISREG(x) ((x) >= 0) -#define DUK__ISCONST(x) ((x) < 0) -#define DUK__ISREG_TEMP(comp_ctx,x) ((duk_int32_t) (x) >= (duk_int32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= temp_first && x >= 0 by comparing as signed. */ -#define DUK__ISREG_NOTTEMP(comp_ctx,x) ((duk_uint32_t) (x) < (duk_uint32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= 0 && x < temp_first by interpreting as unsigned. */ -#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next) -#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */ -#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x)) -#define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx)) -#define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count)) - -/* Init value set size for array and object literals. */ -#define DUK__MAX_ARRAY_INIT_VALUES 20 -#define DUK__MAX_OBJECT_INIT_PAIRS 10 - -/* XXX: hack, remove when const lookup is not O(n) */ -#define DUK__GETCONST_MAX_CONSTS_CHECK 256 - -/* These limits are based on bytecode limits. Max temps is limited - * by duk_hcompfunc nargs/nregs fields being 16 bits. - */ -#define DUK__MAX_CONSTS DUK_BC_BC_MAX -#define DUK__MAX_FUNCS DUK_BC_BC_MAX -#define DUK__MAX_TEMPS 0xffffL - -/* Initial bytecode size allocation. */ -#if defined(DUK_USE_PREFER_SIZE) -#define DUK__BC_INITIAL_INSTS 16 -#else -#define DUK__BC_INITIAL_INSTS 256 -#endif - -#define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \ - DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \ - duk__comp_recursion_increase((comp_ctx)); \ - } while (0) - -#define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \ - DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \ - duk__comp_recursion_decrease((comp_ctx)); \ - } while (0) - -/* Value stack slot limits: these are quite approximate right now, and - * because they overlap in control flow, some could be eliminated. - */ -#define DUK__COMPILE_ENTRY_SLOTS 8 -#define DUK__FUNCTION_INIT_REQUIRE_SLOTS 16 -#define DUK__FUNCTION_BODY_REQUIRE_SLOTS 16 -#define DUK__PARSE_STATEMENTS_SLOTS 16 -#define DUK__PARSE_EXPR_SLOTS 16 - -/* Temporary structure used to pass a stack allocated region through - * duk_safe_call(). - */ -typedef struct { - duk_small_uint_t flags; - duk_compiler_ctx comp_ctx_alloc; - duk_lexer_point lex_pt_alloc; -} duk__compiler_stkstate; - -/* - * Prototypes - */ - -/* lexing */ -DUK_LOCAL_DECL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect); -DUK_LOCAL_DECL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect); -DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx); - -/* function helpers */ -DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg); -DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx); - -/* code emission */ -DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc); -DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins); -DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op); -DUK_LOCAL_DECL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c); -DUK_LOCAL_DECL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b); -DUK_LOCAL_DECL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c); -#if 0 /* unused */ -DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a); -DUK_LOCAL_DECL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b); -#endif -DUK_LOCAL_DECL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc); -DUK_LOCAL_DECL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc); -DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc); -DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val); -DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val); -DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc); -DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc); -DUK_LOCAL_DECL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc); -DUK_LOCAL_DECL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc); -DUK_LOCAL_DECL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags); -DUK_LOCAL_DECL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst); -DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst); -DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx); - -/* ivalue/ispec helpers */ -DUK_LOCAL_DECL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst); -DUK_LOCAL_DECL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x); -DUK_LOCAL_DECL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x); -DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h); -DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst); -DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst); -DUK_LOCAL_DECL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num); -DUK_LOCAL_DECL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next); -DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL -duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx, - duk_ispec *x, - duk_regconst_t forced_reg, - duk_small_uint_t flags); -DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg); -DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg); -DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x); -DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x); -DUK_LOCAL_DECL -duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx, - duk_ivalue *x, - duk_regconst_t forced_reg, - duk_small_uint_t flags); -DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x); -#if 0 /* unused */ -DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x); -#endif -DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg); -DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x); -DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x); - -/* identifier handling */ -DUK_LOCAL_DECL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname); - -/* label handling */ -DUK_LOCAL_DECL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id); -DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags); -DUK_LOCAL_DECL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest); -DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len); - -/* top-down expression parser */ -DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res); -DUK_LOCAL_DECL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx); - -/* exprtop is the top level variant which resets nud/led counts */ -DUK_LOCAL_DECL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); - -/* convenience helpers */ -#if 0 /* unused */ -DUK_LOCAL_DECL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -#endif -#if 0 /* unused */ -DUK_LOCAL_DECL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -#endif -DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg); -DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -#if 0 /* unused */ -DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -#endif -DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -#if 0 /* unused */ -DUK_LOCAL_DECL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -#endif -DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg); -DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -#if 0 /* unused */ -DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); -#endif - -/* expression parsing helpers */ -DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res); - -/* statement parsing */ -DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname); -DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags); -DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); -DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); -DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); -DUK_LOCAL_DECL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); -DUK_LOCAL_DECL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); -DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem); -DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id); -DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof); - -DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token); -DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx); -DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags); -DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags); - -#define DUK__FUNC_FLAG_DECL (1 << 0) /* Parsing a function declaration. */ -#define DUK__FUNC_FLAG_GETSET (1 << 1) /* Parsing an object literal getter/setter. */ -#define DUK__FUNC_FLAG_METDEF (1 << 2) /* Parsing an object literal method definition shorthand. */ -#define DUK__FUNC_FLAG_PUSHNAME_PASS1 (1 << 3) /* Push function name when creating template (first pass only). */ -#define DUK__FUNC_FLAG_USE_PREVTOKEN (1 << 4) /* Use prev_token to start function parsing (workaround for object literal). */ - -/* - * Parser control values for tokens. The token table is ordered by the - * DUK_TOK_XXX defines. - * - * The binding powers are for lbp() use (i.e. for use in led() context). - * Binding powers are positive for typing convenience, and bits at the - * top should be reserved for flags. Binding power step must be higher - * than 1 so that binding power "lbp - 1" can be used for right associative - * operators. Currently a step of 2 is used (which frees one more bit for - * flags). - */ - -/* XXX: actually single step levels would work just fine, clean up */ - -/* binding power "levels" (see doc/compiler.rst) */ -#define DUK__BP_INVALID 0 /* always terminates led() */ -#define DUK__BP_EOF 2 -#define DUK__BP_CLOSING 4 /* token closes expression, e.g. ')', ']' */ -#define DUK__BP_FOR_EXPR DUK__BP_CLOSING /* bp to use when parsing a top level Expression */ -#define DUK__BP_COMMA 6 -#define DUK__BP_ASSIGNMENT 8 -#define DUK__BP_CONDITIONAL 10 -#define DUK__BP_LOR 12 -#define DUK__BP_LAND 14 -#define DUK__BP_BOR 16 -#define DUK__BP_BXOR 18 -#define DUK__BP_BAND 20 -#define DUK__BP_EQUALITY 22 -#define DUK__BP_RELATIONAL 24 -#define DUK__BP_SHIFT 26 -#define DUK__BP_ADDITIVE 28 -#define DUK__BP_MULTIPLICATIVE 30 -#define DUK__BP_EXPONENTIATION 32 -#define DUK__BP_POSTFIX 34 -#define DUK__BP_CALL 36 -#define DUK__BP_MEMBER 38 - -#define DUK__TOKEN_LBP_BP_MASK 0x1f -#define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */ -#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */ -#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* unused */ - -#define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2)) - -#define DUK__MK_LBP(bp) ((bp) >> 1) /* bp is assumed to be even */ -#define DUK__MK_LBP_FLAGS(bp,flags) (((bp) >> 1) | (flags)) - -DUK_LOCAL const duk_uint8_t duk__token_lbp[] = { - DUK__MK_LBP(DUK__BP_EOF), /* DUK_TOK_EOF */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_IDENTIFIER */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BREAK */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CASE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CATCH */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONTINUE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEBUGGER */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEFAULT */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DELETE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DO */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ELSE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FINALLY */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FOR */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FUNCTION */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IF */ - DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_IN */ - DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_INSTANCEOF */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_NEW */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_RETURN */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SWITCH */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_THIS */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_THROW */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPORT */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SUPER */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NULL */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_TRUE */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_FALSE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_GET */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SET */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPLEMENTS */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_INTERFACE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LET */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PACKAGE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PRIVATE */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PROTECTED */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PUBLIC */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_STATIC */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_YIELD */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LCURLY */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RCURLY */ - DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_LBRACKET */ - DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RBRACKET */ - DUK__MK_LBP(DUK__BP_CALL), /* DUK_TOK_LPAREN */ - DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RPAREN */ - DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_PERIOD */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SEMICOLON */ - DUK__MK_LBP(DUK__BP_COMMA), /* DUK_TOK_COMMA */ - DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LT */ - DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GT */ - DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LE */ - DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GE */ - DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_EQ */ - DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_NEQ */ - DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SEQ */ - DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SNEQ */ - DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_ADD */ - DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_SUB */ - DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MUL */ - DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_DIV */ - DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MOD */ - DUK__MK_LBP(DUK__BP_EXPONENTIATION), /* DUK_TOK_EXP */ - DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_INCREMENT */ - DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_DECREMENT */ - DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ALSHIFT */ - DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ARSHIFT */ - DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_RSHIFT */ - DUK__MK_LBP(DUK__BP_BAND), /* DUK_TOK_BAND */ - DUK__MK_LBP(DUK__BP_BOR), /* DUK_TOK_BOR */ - DUK__MK_LBP(DUK__BP_BXOR), /* DUK_TOK_BXOR */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LNOT */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BNOT */ - DUK__MK_LBP(DUK__BP_LAND), /* DUK_TOK_LAND */ - DUK__MK_LBP(DUK__BP_LOR), /* DUK_TOK_LOR */ - DUK__MK_LBP(DUK__BP_CONDITIONAL), /* DUK_TOK_QUESTION */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_COLON */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EQUALSIGN */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ADD_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_SUB_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MUL_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_DIV_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MOD_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EXP_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ALSHIFT_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ARSHIFT_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_RSHIFT_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */ - DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */ - DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */ -}; - -/* - * Misc helpers - */ - -DUK_LOCAL void duk__comp_recursion_increase(duk_compiler_ctx *comp_ctx) { - DUK_ASSERT(comp_ctx != NULL); - DUK_ASSERT(comp_ctx->recursion_depth >= 0); - if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) { - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT); - } - comp_ctx->recursion_depth++; -} - -DUK_LOCAL void duk__comp_recursion_decrease(duk_compiler_ctx *comp_ctx) { - DUK_ASSERT(comp_ctx != NULL); - DUK_ASSERT(comp_ctx->recursion_depth > 0); - comp_ctx->recursion_depth--; -} - -DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) { - DUK_UNREF(comp_ctx); - DUK_ASSERT(h != NULL); - return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h); -} - -DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) { - DUK_ASSERT(h != NULL); - return (comp_ctx->curr_func.is_strict && - DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h)); -} - -/* - * Parser duk__advance() token eating functions - */ - -/* XXX: valstack handling is awkward. Add a valstack helper which - * avoids dup():ing; valstack_copy(src, dst)? - */ - -DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) { - duk_hthread *thr = comp_ctx->thr; - duk_bool_t regexp; - - DUK_ASSERT_DISABLE(comp_ctx->curr_token.t >= 0); /* unsigned */ - DUK_ASSERT(comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */ - - /* - * Use current token to decide whether a RegExp can follow. - * - * We can use either 't' or 't_nores'; the latter would not - * recognize keywords. Some keywords can be followed by a - * RegExp (e.g. "return"), so using 't' is better. This is - * not trivial, see doc/compiler.rst. - */ - - regexp = 1; - if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) { - regexp = 0; - } - if (comp_ctx->curr_func.reject_regexp_in_adv) { - comp_ctx->curr_func.reject_regexp_in_adv = 0; - regexp = 0; - } - - if (expect >= 0 && comp_ctx->curr_token.t != (duk_small_uint_t) expect) { - DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld", - (long) expect, (long) comp_ctx->curr_token.t)); - DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); - } - - /* make current token the previous; need to fiddle with valstack "backing store" */ - DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token)); - duk_copy(thr, comp_ctx->tok11_idx, comp_ctx->tok21_idx); - duk_copy(thr, comp_ctx->tok12_idx, comp_ctx->tok22_idx); - - /* parse new token */ - duk_lexer_parse_js_input_element(&comp_ctx->lex, - &comp_ctx->curr_token, - comp_ctx->curr_func.is_strict, - regexp); - - DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T " - "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T", - (long) comp_ctx->curr_token.t, - (long) comp_ctx->curr_token.t_nores, - (long) comp_ctx->curr_token.start_line, - (long) comp_ctx->curr_token.lineterm, - (duk_tval *) duk_get_tval(thr, comp_ctx->tok11_idx), - (duk_tval *) duk_get_tval(thr, comp_ctx->tok12_idx), - (long) comp_ctx->prev_token.t, - (long) comp_ctx->prev_token.t_nores, - (long) comp_ctx->prev_token.start_line, - (long) comp_ctx->prev_token.lineterm, - (duk_tval *) duk_get_tval(thr, comp_ctx->tok21_idx), - (duk_tval *) duk_get_tval(thr, comp_ctx->tok22_idx))); -} - -/* advance, expecting current token to be a specific token; parse next token in regexp context */ -DUK_LOCAL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) { - duk__advance_helper(comp_ctx, expect); -} - -/* advance, whatever the current token is; parse next token in regexp context */ -DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) { - duk__advance_helper(comp_ctx, -1); -} - -/* - * Helpers for duk_compiler_func. - */ - -/* init function state: inits valstack allocations */ -DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) { - duk_compiler_func *func = &comp_ctx->curr_func; - duk_hthread *thr = comp_ctx->thr; - duk_idx_t entry_top; - - entry_top = duk_get_top(thr); - - DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */ -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - func->h_name = NULL; - func->h_consts = NULL; - func->h_funcs = NULL; - func->h_decls = NULL; - func->h_labelnames = NULL; - func->h_labelinfos = NULL; - func->h_argnames = NULL; - func->h_varmap = NULL; -#endif - - duk_require_stack(thr, DUK__FUNCTION_INIT_REQUIRE_SLOTS); - - DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr)); - /* code_idx = entry_top + 0 */ - - duk_push_array(thr); - func->consts_idx = entry_top + 1; - func->h_consts = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 1); - DUK_ASSERT(func->h_consts != NULL); - - duk_push_array(thr); - func->funcs_idx = entry_top + 2; - func->h_funcs = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 2); - DUK_ASSERT(func->h_funcs != NULL); - DUK_ASSERT(func->fnum_next == 0); - - duk_push_array(thr); - func->decls_idx = entry_top + 3; - func->h_decls = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 3); - DUK_ASSERT(func->h_decls != NULL); - - duk_push_array(thr); - func->labelnames_idx = entry_top + 4; - func->h_labelnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 4); - DUK_ASSERT(func->h_labelnames != NULL); - - duk_push_dynamic_buffer(thr, 0); - func->labelinfos_idx = entry_top + 5; - func->h_labelinfos = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 5); - DUK_ASSERT(func->h_labelinfos != NULL); - DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos)); - - duk_push_array(thr); - func->argnames_idx = entry_top + 6; - func->h_argnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 6); - DUK_ASSERT(func->h_argnames != NULL); - - duk_push_bare_object(thr); - func->varmap_idx = entry_top + 7; - func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 7); - DUK_ASSERT(func->h_varmap != NULL); -} - -/* reset function state (prepare for pass 2) */ -DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) { - duk_compiler_func *func = &comp_ctx->curr_func; - duk_hthread *thr = comp_ctx->thr; - - /* reset bytecode buffer but keep current size; pass 2 will - * require same amount or more. - */ - DUK_BW_RESET_SIZE(thr, &func->bw_code); - - duk_set_length(thr, func->consts_idx, 0); - /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */ - func->fnum_next = 0; - /* duk_set_length(thr, func->funcs_idx, 0); */ - duk_set_length(thr, func->labelnames_idx, 0); - duk_hbuffer_reset(thr, func->h_labelinfos); - /* keep func->h_argnames; it is fixed for all passes */ - - /* truncated in case pass 3 needed */ - duk_push_bare_object(thr); - duk_replace(thr, func->varmap_idx); - func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, func->varmap_idx); - DUK_ASSERT(func->h_varmap != NULL); -} - -/* cleanup varmap from any null entries, compact it, etc; returns number - * of final entries after cleanup. - */ -DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) { - duk_hthread *thr = comp_ctx->thr; - duk_hobject *h_varmap; - duk_hstring *h_key; - duk_tval *tv; - duk_uint32_t i, e_next; - duk_int_t ret; - - /* [ ... varmap ] */ - - h_varmap = DUK_GET_HOBJECT_NEGIDX(thr, -1); - DUK_ASSERT(h_varmap != NULL); - - ret = 0; - e_next = DUK_HOBJECT_GET_ENEXT(h_varmap); - for (i = 0; i < e_next; i++) { - h_key = DUK_HOBJECT_E_GET_KEY(thr->heap, h_varmap, i); - if (!h_key) { - continue; - } - - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i)); - - /* The entries can either be register numbers or 'null' values. - * Thus, no need to DECREF them and get side effects. DECREF'ing - * the keys (strings) can cause memory to be freed but no side - * effects as strings don't have finalizers. This is why we can - * rely on the object properties not changing from underneath us. - */ - - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h_varmap, i); - if (!DUK_TVAL_IS_NUMBER(tv)) { - DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); - DUK_HOBJECT_E_SET_KEY(thr->heap, h_varmap, i, NULL); - DUK_HSTRING_DECREF(thr, h_key); - /* when key is NULL, value is garbage so no need to set */ - } else { - ret++; - } - } - - duk_compact_m1(thr); - - return ret; -} - -/* Convert duk_compiler_func into a function template, leaving the result - * on top of stack. - */ -/* XXX: awkward and bloated asm -- use faster internal accesses */ -DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) { - duk_compiler_func *func = &comp_ctx->curr_func; - duk_hthread *thr = comp_ctx->thr; - duk_hcompfunc *h_res; - duk_hbuffer_fixed *h_data; - duk_size_t consts_count; - duk_size_t funcs_count; - duk_size_t code_count; - duk_size_t code_size; - duk_size_t data_size; - duk_size_t i; - duk_tval *p_const; - duk_hobject **p_func; - duk_instr_t *p_instr; - duk_compiler_instr *q_instr; - duk_tval *tv; - duk_bool_t keep_varmap; - duk_bool_t keep_formals; -#if !defined(DUK_USE_DEBUGGER_SUPPORT) - duk_size_t formals_length; -#endif - - DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template")); - - /* - * Push result object and init its flags - */ - - /* Valstack should suffice here, required on function valstack init */ - - h_res = duk_push_hcompfunc(thr); - DUK_ASSERT(h_res != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_res) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_res, NULL); /* Function templates are "bare objects". */ - - if (func->is_function) { - DUK_DDD(DUK_DDDPRINT("function -> set NEWENV")); - DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res); - - if (!func->is_arguments_shadowed) { - /* arguments object would be accessible; note that shadowing - * bindings are arguments or function declarations, neither - * of which are deletable, so this is safe. - */ - - if (func->id_access_arguments || func->may_direct_eval) { - DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or " - "indirectly -> set CREATEARGS")); - DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res); - } - } - } else if (func->is_eval && func->is_strict) { - DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV")); - DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res); - } else { - /* non-strict eval: env is caller's env or global env (direct vs. indirect call) - * global code: env is is global env - */ - DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV")); - DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res)); - } - -#if defined(DUK_USE_FUNC_NAME_PROPERTY) - if (func->is_function && func->is_namebinding && func->h_name != NULL) { - /* Object literal set/get functions have a name (property - * name) but must not have a lexical name binding, see - * test-bug-getset-func-name.js. - */ - DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING")); - DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res); - } -#endif - - if (func->is_strict) { - DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT")); - DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res); - } - - if (func->is_notail) { - DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL")); - DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res); - } - - if (func->is_constructable) { - DUK_DDD(DUK_DDDPRINT("function is constructable -> set CONSTRUCTABLE")); - DUK_HOBJECT_SET_CONSTRUCTABLE((duk_hobject *) h_res); - } - - /* - * Build function fixed size 'data' buffer, which contains bytecode, - * constants, and inner function references. - * - * During the building phase 'data' is reachable but incomplete. - * Only incref's occur during building (no refzero or GC happens), - * so the building process is atomic. - */ - - consts_count = duk_hobject_get_length(thr, func->h_consts); - funcs_count = duk_hobject_get_length(thr, func->h_funcs) / 3; - code_count = DUK_BW_GET_SIZE(thr, &func->bw_code) / sizeof(duk_compiler_instr); - code_size = code_count * sizeof(duk_instr_t); - - data_size = consts_count * sizeof(duk_tval) + - funcs_count * sizeof(duk_hobject *) + - code_size; - - DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> " - "data_size=%ld*%ld + %ld*%ld + %ld = %ld", - (long) consts_count, (long) funcs_count, (long) code_size, - (long) consts_count, (long) sizeof(duk_tval), - (long) funcs_count, (long) sizeof(duk_hobject *), - (long) code_size, (long) data_size)); - - duk_push_fixed_buffer_nozero(thr, data_size); - h_data = (duk_hbuffer_fixed *) duk_known_hbuffer(thr, -1); - - DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data); - DUK_HEAPHDR_INCREF(thr, h_data); - - p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data); - for (i = 0; i < consts_count; i++) { - DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* const limits */ - tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_consts, (duk_uarridx_t) i); - DUK_ASSERT(tv != NULL); - DUK_TVAL_SET_TVAL(p_const, tv); - p_const++; - DUK_TVAL_INCREF(thr, tv); /* may be a string constant */ - - DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval *) tv)); - } - - p_func = (duk_hobject **) p_const; - DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_res, p_func); - for (i = 0; i < funcs_count; i++) { - duk_hobject *h; - DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX); /* func limits */ - tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_funcs, (duk_uarridx_t) (i * 3)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(h)); - *p_func++ = h; - DUK_HOBJECT_INCREF(thr, h); - - DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO", - (void *) h, (duk_heaphdr *) h)); - } - - p_instr = (duk_instr_t *) p_func; - DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_res, p_instr); - - /* copy bytecode instructions one at a time */ - q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code); - for (i = 0; i < code_count; i++) { - p_instr[i] = q_instr[i].ins; - } - /* Note: 'q_instr' is still used below */ - - DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size); - - duk_pop(thr); /* 'data' (and everything in it) is reachable through h_res now */ - - /* - * Init non-property result fields - * - * 'nregs' controls how large a register frame is allocated. - * - * 'nargs' controls how many formal arguments are written to registers: - * r0, ... r(nargs-1). The remaining registers are initialized to - * undefined. - */ - - DUK_ASSERT(func->temp_max >= 0); - h_res->nregs = (duk_uint16_t) func->temp_max; - h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames); - DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - h_res->start_line = (duk_uint32_t) func->min_line; - h_res->end_line = (duk_uint32_t) func->max_line; -#endif - - /* - * Init object properties - * - * Properties should be added in decreasing order of access frequency. - * (Not very critical for function templates.) - */ - - DUK_DDD(DUK_DDDPRINT("init function properties")); - - /* [ ... res ] */ - - /* _Varmap: omitted if function is guaranteed not to do a slow path - * identifier access that might be caught by locally declared variables. - * The varmap can also be omitted if it turns out empty of actual - * register mappings after a cleanup. When debugging is enabled, we - * always need the varmap to be able to lookup variables at any point. - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - DUK_DD(DUK_DDPRINT("keeping _Varmap because debugger support is enabled")); - keep_varmap = 1; -#else - if (func->id_access_slow_own || /* directly uses slow accesses that may match own variables */ - func->id_access_arguments || /* accesses 'arguments' directly */ - func->may_direct_eval || /* may indirectly slow access through a direct eval */ - funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */ - DUK_DD(DUK_DDPRINT("keeping _Varmap because of direct eval, slow path access that may match local variables, or presence of inner functions")); - keep_varmap = 1; - } else { - DUK_DD(DUK_DDPRINT("dropping _Varmap")); - keep_varmap = 0; - } -#endif - - if (keep_varmap) { - duk_int_t num_used; - duk_dup(thr, func->varmap_idx); - num_used = duk__cleanup_varmap(comp_ctx); - DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)", - (duk_tval *) duk_get_tval(thr, -1), (long) num_used)); - - if (num_used > 0) { - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); - } else { - DUK_DD(DUK_DDPRINT("varmap is empty after cleanup -> no need to add")); - duk_pop(thr); - } - } - - /* _Formals: omitted if function is guaranteed not to need a (non-strict) - * arguments object, and _Formals.length matches nargs exactly. - * - * Non-arrow functions can't see an outer function's 'argument' binding - * (because they have their own), but arrow functions can. When arrow - * functions are added, this condition would need to be added: - * inner_arrow_funcs_count > 0 inner arrow functions may access 'arguments' - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - DUK_DD(DUK_DDPRINT("keeping _Formals because debugger support is enabled")); - keep_formals = 1; -#else - formals_length = duk_get_length(thr, func->argnames_idx); - if (formals_length != (duk_size_t) h_res->nargs) { - /* Nargs not enough for closure .length: keep _Formals regardless - * of its length. Shouldn't happen in practice at the moment. - */ - DUK_DD(DUK_DDPRINT("keeping _Formals because _Formals.length != nargs")); - keep_formals = 1; - } else if ((func->id_access_arguments || func->may_direct_eval) && - (formals_length > 0)) { - /* Direct eval (may access 'arguments') or accesses 'arguments' - * explicitly: keep _Formals unless it is zero length. - */ - DUK_DD(DUK_DDPRINT("keeping _Formals because of direct eval or explicit access to 'arguments', and _Formals.length != 0")); - keep_formals = 1; - } else { - DUK_DD(DUK_DDPRINT("omitting _Formals, nargs matches _Formals.length, so no properties added")); - keep_formals = 0; - } -#endif - - if (keep_formals) { - duk_dup(thr, func->argnames_idx); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); - } - - /* name */ -#if defined(DUK_USE_FUNC_NAME_PROPERTY) - if (func->h_name) { - duk_push_hstring(thr, func->h_name); - DUK_DD(DUK_DDPRINT("setting function template .name to %!T", duk_get_tval(thr, -1))); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); - } -#endif /* DUK_USE_FUNC_NAME_PROPERTY */ - - /* _Source */ -#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY) - if (0) { - /* XXX: Currently function source code is not stored, as it is not - * required by the standard. Source code should not be stored by - * default (user should enable it explicitly), and the source should - * probably be compressed with a trivial text compressor; average - * compression of 20-30% is quite easy to achieve even with a trivial - * compressor (RLE + backwards lookup). - * - * Debugging needs source code to be useful: sometimes input code is - * not found in files as it may be generated and then eval()'d, given - * by dynamic C code, etc. - * - * Other issues: - * - * - Need tokenizer indices for start and end to substring - * - Always normalize function declaration part? - * - If we keep _Formals, only need to store body - */ - - /* - * For global or eval code this is straightforward. For functions - * created with the Function constructor we only get the source for - * the body and must manufacture the "function ..." part. - * - * For instance, for constructed functions (v8): - * - * > a = new Function("foo", "bar", "print(foo)"); - * [Function] - * > a.toString() - * 'function anonymous(foo,bar) {\nprint(foo)\n}' - * - * Similarly for e.g. getters (v8): - * - * > x = { get a(foo,bar) { print(foo); } } - * { a: [Getter] } - * > Object.getOwnPropertyDescriptor(x, 'a').get.toString() - * 'function a(foo,bar) { print(foo); }' - */ - -#if 0 - duk_push_string(thr, "XXX"); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE); -#endif - } -#endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */ - - /* _Pc2line */ -#if defined(DUK_USE_PC2LINE) - if (1) { - /* - * Size-optimized pc->line mapping. - */ - - DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH); - duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */ - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE); - - /* XXX: if assertions enabled, walk through all valid PCs - * and check line mapping. - */ - } -#endif /* DUK_USE_PC2LINE */ - - /* fileName */ -#if defined(DUK_USE_FUNC_FILENAME_PROPERTY) - if (comp_ctx->h_filename) { - /* - * Source filename (or equivalent), for identifying thrown errors. - */ - - duk_push_hstring(thr, comp_ctx->h_filename); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE); - } -#endif - - DUK_DD(DUK_DDPRINT("converted function: %!ixT", - (duk_tval *) duk_get_tval(thr, -1))); - - /* - * Compact the function template. - */ - - duk_compact_m1(thr); - - /* - * Debug dumping - */ - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - { - duk_hcompfunc *h; - duk_instr_t *p, *p_start, *p_end; - - h = (duk_hcompfunc *) duk_get_hobject(thr, -1); - p_start = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, h); - p_end = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, h); - - p = p_start; - while (p < p_end) { - DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!C) a=%ld b=%ld c=%ld", - (long) (p - p_start), - (duk_instr_t) (*p), - (unsigned long) (*p), - (long) DUK_DEC_OP(*p), - (long) DUK_DEC_OP(*p), - (long) DUK_DEC_A(*p), - (long) DUK_DEC_B(*p), - (long) DUK_DEC_C(*p))); - p++; - } - } -#endif -} - -/* - * Code emission helpers - * - * Some emission helpers understand the range of target and source reg/const - * values and automatically emit shuffling code if necessary. This is the - * case when the slot in question (A, B, C) is used in the standard way and - * for opcodes the emission helpers explicitly understand (like DUK_OP_MPUTOBJ). - * - * The standard way is that: - * - slot A is a target register - * - slot B is a source register/constant - * - slot C is a source register/constant - * - * If a slot is used in a non-standard way the caller must indicate this - * somehow. If a slot is used as a target instead of a source (or vice - * versa), this can be indicated with a flag to trigger proper shuffling - * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not - * register/const related at all, the caller must ensure that the raw value - * fits into the corresponding slot so as to not trigger shuffling. The - * caller must set a "no shuffle" flag to ensure compilation fails if - * shuffling were to be triggered because of an internal error. - * - * For slots B and C the raw slot size is 9 bits but one bit is reserved for - * the reg/const indicator. To use the full 9-bit range for a raw value, - * shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag. - * Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots. - * - * There is call handling specific understanding in the A-B-C emitter to - * convert call setup and call instructions into indirect ones if necessary. - */ - -/* Code emission flags, passed in the 'opcode' field. Opcode + flags - * fit into 16 bits for now, so use duk_small_uint_t. - */ -#define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8) -#define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9) -#define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10) -#define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */ -#define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */ -#define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */ -#define DUK__EMIT_FLAG_BC_REGCONST (1 << 14) /* slots B and C are reg/const */ -#define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */ - -/* XXX: macro smaller than call? */ -DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) { - duk_compiler_func *func; - func = &comp_ctx->curr_func; - return (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &func->bw_code) / sizeof(duk_compiler_instr)); -} - -DUK_LOCAL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc) { - DUK_ASSERT(pc >= 0); - DUK_ASSERT((duk_size_t) pc < (duk_size_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr))); - return ((duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code)) + pc; -} - -/* emit instruction; could return PC but that's not needed in the majority - * of cases. - */ -DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) { -#if defined(DUK_USE_PC2LINE) - duk_int_t line; -#endif - duk_compiler_instr *instr; - - DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I", - (unsigned long) ins, - (long) comp_ctx->curr_token.start_line, - (long) comp_ctx->prev_token.start_line, - (long) duk__get_current_pc(comp_ctx), - (duk_instr_t) ins)); - - instr = (duk_compiler_instr *) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr)); - DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr)); - -#if defined(DUK_USE_PC2LINE) - /* The line number tracking is a bit inconsistent right now, which - * affects debugger accuracy. Mostly call sites emit opcodes when - * they have parsed a token (say a terminating semicolon) and called - * duk__advance(). In this case the line number of the previous - * token is the most accurate one (except in prologue where - * prev_token.start_line is 0). This is probably not 100% correct - * right now. - */ - /* approximation, close enough */ - line = comp_ctx->prev_token.start_line; - if (line == 0) { - line = comp_ctx->curr_token.start_line; - } -#endif - - instr->ins = ins; -#if defined(DUK_USE_PC2LINE) - instr->line = (duk_uint32_t) line; -#endif -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (line < comp_ctx->curr_func.min_line) { - comp_ctx->curr_func.min_line = line; - } - if (line > comp_ctx->curr_func.max_line) { - comp_ctx->curr_func.max_line = line; - } -#endif - - /* Limit checks for bytecode byte size and line number. */ - if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) { - goto fail_bc_limit; - } -#if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS) -#if defined(DUK_USE_BUFLEN16) - /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */ - if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) { - goto fail_bc_limit; - } -#else - if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) { - goto fail_bc_limit; - } -#endif -#endif - - return; - - fail_bc_limit: - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT); -} - -/* Update function min/max line from current token. Needed to improve - * function line range information for debugging, so that e.g. opening - * curly brace is covered by line range even when no opcodes are emitted - * for the line containing the brace. - */ -DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) { -#if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_int_t line; - - line = comp_ctx->curr_token.start_line; - if (line == 0) { - return; - } - if (line < comp_ctx->curr_func.min_line) { - comp_ctx->curr_func.min_line = line; - } - if (line > comp_ctx->curr_func.max_line) { - comp_ctx->curr_func.max_line = line; - } -#else - DUK_UNREF(comp_ctx); -#endif -} - -DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) { - duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0)); -} - -/* Important main primitive. */ -DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c) { - duk_instr_t ins = 0; - duk_int_t a_out = -1; - duk_int_t b_out = -1; - duk_int_t c_out = -1; - duk_int_t tmp; - duk_small_uint_t op = op_flags & 0xffU; - - DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld", - (unsigned long) op_flags, (long) a, (long) b, (long) c)); - - /* We could rely on max temp/const checks: if they don't exceed BC - * limit, nothing here can either (just asserts would be enough). - * Currently we check for the limits, which provides additional - * protection against creating invalid bytecode due to compiler - * bugs. - */ - - DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */ - DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX); - DUK_ASSERT(DUK__ISREG(a)); - DUK_ASSERT(b != -1); /* Not 'none'. */ - DUK_ASSERT(c != -1); /* Not 'none'. */ - - /* Input shuffling happens before the actual operation, while output - * shuffling happens afterwards. Output shuffling decisions are still - * made at the same time to reduce branch clutter; output shuffle decisions - * are recorded into X_out variables. - */ - - /* Slot A: currently no support for reg/const. */ - -#if defined(DUK_USE_SHUFFLE_TORTURE) - if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) { -#else - if (a <= DUK_BC_A_MAX) { -#endif - ; - } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) { - DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a)); - goto error_outofregs; - } else if (a <= DUK_BC_BC_MAX) { - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle1; - if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) { - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a)); - } else { - /* Output shuffle needed after main operation */ - a_out = a; - - /* The DUK_OP_CSVAR output shuffle assumes shuffle registers are - * consecutive. - */ - DUK_ASSERT((comp_ctx->curr_func.shuffle1 == 0 && comp_ctx->curr_func.shuffle2 == 0) || - (comp_ctx->curr_func.shuffle2 == comp_ctx->curr_func.shuffle1 + 1)); - if (op == DUK_OP_CSVAR) { - /* For CSVAR the limit is one smaller because output shuffle - * must be able to express 'a + 1' in BC. - */ - if (a + 1 > DUK_BC_BC_MAX) { - goto error_outofregs; - } - } - } - a = tmp; - } else { - DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld", (long) a)); - goto error_outofregs; - } - - /* Slot B: reg/const support, mapped to bit 0 of opcode. */ - - if ((b & DUK__CONST_MARKER) != 0) { - DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0); - DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0); - b = b & ~DUK__CONST_MARKER; -#if defined(DUK_USE_SHUFFLE_TORTURE) - if (0) { -#else - if (b <= 0xff) { -#endif - if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) { - /* Opcode follows B/C reg/const convention. */ - DUK_ASSERT((op & 0x01) == 0); - ins |= DUK_ENC_OP_A_B_C(0x01, 0, 0, 0); /* const flag for B */ - } else { - DUK_D(DUK_DPRINT("B is const, opcode is not B/C reg/const: %x", op_flags)); - } - } else if (b <= DUK_BC_BC_MAX) { - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle2; - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b)); - b = tmp; - } else { - DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld", (long) b)); - goto error_outofregs; - } - } else { -#if defined(DUK_USE_SHUFFLE_TORTURE) - if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) { -#else - if (b <= 0xff) { -#endif - ; - } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) { - if (b > DUK_BC_B_MAX) { - /* Note: 0xff != DUK_BC_B_MAX */ - DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld", (long) b)); - goto error_outofregs; - } - } else if (b <= DUK_BC_BC_MAX) { - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle2; - if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) { - /* Output shuffle needed after main operation */ - b_out = b; - } - if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET)) { - if (op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) { - /* Special handling for MPUTOBJ/MPUTARR shuffling. - * For each, slot B identifies the first register of a range - * of registers, so normal shuffling won't work. Instead, - * an indirect version of the opcode is used. - */ - DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0); - duk__emit_load_int32_noshuffle(comp_ctx, tmp, b); - DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1); - DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1); - op_flags++; /* indirect opcode follows direct */ - } else { - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b)); - } - } - b = tmp; - } else { - DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld", (long) b)); - goto error_outofregs; - } - } - - /* Slot C: reg/const support, mapped to bit 1 of opcode. */ - - if ((c & DUK__CONST_MARKER) != 0) { - DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0); - DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0); - c = c & ~DUK__CONST_MARKER; -#if defined(DUK_USE_SHUFFLE_TORTURE) - if (0) { -#else - if (c <= 0xff) { -#endif - if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) { - /* Opcode follows B/C reg/const convention. */ - DUK_ASSERT((op & 0x02) == 0); - ins |= DUK_ENC_OP_A_B_C(0x02, 0, 0, 0); /* const flag for C */ - } else { - DUK_D(DUK_DPRINT("C is const, opcode is not B/C reg/const: %x", op_flags)); - } - } else if (c <= DUK_BC_BC_MAX) { - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle3; - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c)); - c = tmp; - } else { - DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld", (long) c)); - goto error_outofregs; - } - } else { -#if defined(DUK_USE_SHUFFLE_TORTURE) - if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) { -#else - if (c <= 0xff) { -#endif - ; - } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) { - if (c > DUK_BC_C_MAX) { - /* Note: 0xff != DUK_BC_C_MAX */ - DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld", (long) c)); - goto error_outofregs; - } - } else if (c <= DUK_BC_BC_MAX) { - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle3; - if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) { - /* Output shuffle needed after main operation */ - c_out = c; - } else { - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c)); - } - c = tmp; - } else { - DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld", (long) c)); - goto error_outofregs; - } - } - - /* Main operation */ - - DUK_ASSERT(a >= DUK_BC_A_MIN); - DUK_ASSERT(a <= DUK_BC_A_MAX); - DUK_ASSERT(b >= DUK_BC_B_MIN); - DUK_ASSERT(b <= DUK_BC_B_MAX); - DUK_ASSERT(c >= DUK_BC_C_MIN); - DUK_ASSERT(c <= DUK_BC_C_MAX); - - ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c); - duk__emit(comp_ctx, ins); - - /* NEXTENUM needs a jump slot right after the main instruction. - * When the JUMP is taken, output spilling is not needed so this - * workaround is possible. The jump slot PC is exceptionally - * plumbed through comp_ctx to minimize call sites. - */ - if (op_flags & DUK__EMIT_FLAG_RESERVE_JUMPSLOT) { - comp_ctx->emit_jumpslot_pc = duk__get_current_pc(comp_ctx); - duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0); - } - - /* Output shuffling: only one output register is realistically possible. - * - * (Zero would normally be an OK marker value: if the target register - * was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE - * this is no longer true, so use -1 as a marker instead.) - */ - - if (a_out >= 0) { - DUK_ASSERT(b_out < 0); - DUK_ASSERT(c_out < 0); - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out)); - - if (op == DUK_OP_CSVAR) { - /* Special handling for CSVAR shuffling. The variable lookup - * results in a pair in successive - * registers so use two shuffle registers and two output - * loads. (In practice this is dead code because temp/const - * limit is reached first.) - */ - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a + 1, a_out + 1)); - } - } else if (b_out >= 0) { - DUK_ASSERT(a_out < 0); - DUK_ASSERT(c_out < 0); - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out)); - } else if (c_out >= 0) { - DUK_ASSERT(b_out < 0); - DUK_ASSERT(c_out < 0); - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out)); - } - - return; - - error_outofregs: - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); -} - -/* For many of the helpers below it'd be technically correct to add - * "no shuffle" flags for parameters passed in as zero. For example, - * duk__emit_a_b() should call duk__emit_a_b_c() with C set to 0, and - * DUK__EMIT_FLAG_NO_SHUFFLE_C added to op_flags. However, since the - * C value is 0, it'll never get shuffled so adding the flag is just - * unnecessary additional code. This is unfortunately not true for - * "shuffle torture" mode which needs special handling. - */ - -DUK_LOCAL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b) { -#if defined(DUK_USE_SHUFFLE_TORTURE) - op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_C; -#endif - duk__emit_a_b_c(comp_ctx, op_flags, a, b, 0); -} - -DUK_LOCAL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c) { -#if defined(DUK_USE_SHUFFLE_TORTURE) - op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A; -#endif - duk__emit_a_b_c(comp_ctx, op_flags, 0, b, c); -} - -#if 0 /* unused */ -DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) { -#if defined(DUK_USE_SHUFFLE_TORTURE) - op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C; -#endif - duk__emit_a_b_c(comp_ctx, op_flags, a, 0, 0); -} -#endif - -#if 0 /* unused */ -DUK_LOCAL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b) { -#if defined(DUK_USE_SHUFFLE_TORTURE) - op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C; -#endif - duk__emit_a_b_c(comp_ctx, op_flags, 0, b, 0); -} -#endif - -DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc) { - duk_instr_t ins; - duk_int_t tmp; - - /* allow caller to give a const number with the DUK__CONST_MARKER */ - DUK_ASSERT(bc != -1); /* Not 'none'. */ - bc = bc & (~DUK__CONST_MARKER); - - DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */ - DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX); - DUK_ASSERT(bc >= DUK_BC_BC_MIN); - DUK_ASSERT(bc <= DUK_BC_BC_MAX); - DUK_ASSERT((bc & DUK__CONST_MARKER) == 0); - - if (bc <= DUK_BC_BC_MAX) { - ; - } else { - /* No BC shuffling now. */ - goto error_outofregs; - } - -#if defined(DUK_USE_SHUFFLE_TORTURE) - if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) { -#else - if (a <= DUK_BC_A_MAX) { -#endif - ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc); - duk__emit(comp_ctx, ins); - } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) { - goto error_outofregs; - } else if ((op_flags & 0xf0U) == DUK_OP_CALL0) { - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle1; - duk__emit_load_int32_noshuffle(comp_ctx, tmp, a); - op_flags |= DUK_BC_CALL_FLAG_INDIRECT; - ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc); - duk__emit(comp_ctx, ins); - } else if (a <= DUK_BC_BC_MAX) { - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle1; - ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc); - if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) { - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a)); - duk__emit(comp_ctx, ins); - } else { - duk__emit(comp_ctx, ins); - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a)); - } - } else { - goto error_outofregs; - } - return; - - error_outofregs: - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); -} - -DUK_LOCAL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc) { -#if defined(DUK_USE_SHUFFLE_TORTURE) - op |= DUK__EMIT_FLAG_NO_SHUFFLE_A; -#endif - duk__emit_a_bc(comp_ctx, op, 0, bc); -} - -DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) { - duk_instr_t ins; - - DUK_ASSERT_DISABLE(op >= DUK_BC_OP_MIN); /* unsigned */ - DUK_ASSERT(op <= DUK_BC_OP_MAX); - DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */ - DUK_ASSERT(abc <= DUK_BC_ABC_MAX); - DUK_ASSERT((abc & DUK__CONST_MARKER) == 0); - DUK_ASSERT(abc != -1); /* Not 'none'. */ - - if (abc <= DUK_BC_ABC_MAX) { - ; - } else { - goto error_outofregs; - } - ins = DUK_ENC_OP_ABC(op, abc); - DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!C) abc=%ld (%!I)", - (unsigned long) ins, (long) comp_ctx->curr_token.start_line, - (long) duk__get_current_pc(comp_ctx), (long) op, (long) op, - (long) abc, (duk_instr_t) ins)); - duk__emit(comp_ctx, ins); - return; - - error_outofregs: - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); -} - -DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val, duk_small_uint_t op_flags) { - /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX - * would only shuffle once (instead of twice). The current code works - * though, and has a smaller compiler footprint. - */ - - if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) && - (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) { - DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg, (long) val)); - duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS)); - } else { - duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT; - duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1); - DUK_ASSERT(lo >= 0); - DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld", - (long) reg, (long) val, (long) hi, (long) lo)); - duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS)); - duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo); - } -} - -DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) { - duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/); -} - -#if defined(DUK_USE_SHUFFLE_TORTURE) -/* Used by duk__emit*() calls so that we don't shuffle the loadints that - * are needed to handle indirect opcodes. - */ -DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) { - duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/); -} -#else -DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) { - /* When torture not enabled, can just use the same helper because - * 'reg' won't get spilled. - */ - DUK_ASSERT(reg <= DUK_BC_A_MAX); - duk__emit_load_int32(comp_ctx, reg, val); -} -#endif - -DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) { - duk_int_t curr_pc; - duk_int_t offset; - - curr_pc = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr)); - offset = (duk_int_t) target_pc - (duk_int_t) curr_pc - 1; - DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN); - DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX); - duk__emit_abc(comp_ctx, DUK_OP_JUMP, (duk_regconst_t) (offset + DUK_BC_JUMP_BIAS)); -} - -DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) { - duk_int_t ret; - - ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */ - duk__emit_op_only(comp_ctx, DUK_OP_JUMP); - return ret; -} - -/* Insert an empty jump in the middle of code emitted earlier. This is - * currently needed for compiling for-in. - */ -DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) { -#if defined(DUK_USE_PC2LINE) - duk_int_t line; -#endif - duk_compiler_instr *instr; - duk_size_t offset; - - DUK_ASSERT(jump_pc >= 0); - offset = (duk_size_t) jump_pc * sizeof(duk_compiler_instr); - instr = (duk_compiler_instr *) (void *) - DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr, - &comp_ctx->curr_func.bw_code, - offset, - sizeof(duk_compiler_instr)); - -#if defined(DUK_USE_PC2LINE) - line = comp_ctx->curr_token.start_line; /* approximation, close enough */ -#endif - instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0); -#if defined(DUK_USE_PC2LINE) - instr->line = (duk_uint32_t) line; -#endif - - DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr)); - if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) { - goto fail_bc_limit; - } - return; - - fail_bc_limit: - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT); -} - -/* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional - * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this). - */ -DUK_LOCAL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc) { - duk_compiler_instr *instr; - duk_int_t offset; - - /* allow negative PCs, behave as a no-op */ - if (jump_pc < 0) { - DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld", - (long) jump_pc, (long) target_pc)); - return; - } - DUK_ASSERT(jump_pc >= 0); - - /* XXX: range assert */ - instr = duk__get_instr_ptr(comp_ctx, jump_pc); - DUK_ASSERT(instr != NULL); - - /* XXX: range assert */ - offset = target_pc - jump_pc - 1; - - instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS); - DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld", - (long) jump_pc, (long) target_pc, (long) offset)); -} - -DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) { - duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx)); -} - -DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags) { - duk_compiler_instr *instr; - - DUK_ASSERT(DUK__ISREG(reg_catch)); - - instr = duk__get_instr_ptr(comp_ctx, ldconst_pc); - DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST); - DUK_ASSERT(instr != NULL); - if (const_varname & DUK__CONST_MARKER) { - /* Have a catch variable. */ - const_varname = const_varname & (~DUK__CONST_MARKER); - if (reg_catch > DUK_BC_BC_MAX || const_varname > DUK_BC_BC_MAX) { - /* Catch attempts to use out-of-range reg/const. Without this - * check Duktape 0.12.0 could generate invalid code which caused - * an assert failure on execution. This error is triggered e.g. - * for functions with a lot of constants and a try-catch statement. - * Shuffling or opcode semantics change is needed to fix the issue. - * See: test-bug-trycatch-many-constants.js. - */ - DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)", - (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname)); - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); - } - instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname); - } else { - /* No catch variable, e.g. a try-finally; replace LDCONST with - * NOP to avoid a bogus LDCONST. - */ - instr->ins = DUK_ENC_OP(DUK_OP_NOP); - } - - instr = duk__get_instr_ptr(comp_ctx, trycatch_pc); - DUK_ASSERT(instr != NULL); - DUK_ASSERT_DISABLE(flags >= DUK_BC_A_MIN); - DUK_ASSERT(flags <= DUK_BC_A_MAX); - instr->ins = DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH, flags, reg_catch); -} - -DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) { - duk_small_uint_t op; - - op = DUK__ISREG(regconst) ? DUK_OP_IFFALSE_R : DUK_OP_IFFALSE_C; - duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */ -} - -DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) { - duk_small_uint_t op; - - op = DUK__ISREG(regconst) ? DUK_OP_IFTRUE_R : DUK_OP_IFTRUE_C; - duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */ -} - -DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) { - duk__emit_op_only(comp_ctx, DUK_OP_INVALID); -} - -/* - * Peephole optimizer for finished bytecode. - * - * Does not remove opcodes; currently only straightens out unconditional - * jump chains which are generated by several control structures. - */ - -DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) { - duk_compiler_instr *bc; - duk_small_uint_t iter; - duk_int_t i, n; - duk_int_t count_opt; - - bc = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code); -#if defined(DUK_USE_BUFLEN16) - /* No need to assert, buffer size maximum is 0xffff. */ -#else - DUK_ASSERT((duk_size_t) DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr) <= (duk_size_t) DUK_INT_MAX); /* bytecode limits */ -#endif - n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr)); - - for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) { - count_opt = 0; - - for (i = 0; i < n; i++) { - duk_instr_t ins; - duk_int_t target_pc1; - duk_int_t target_pc2; - - ins = bc[i].ins; - if (DUK_DEC_OP(ins) != DUK_OP_JUMP) { - continue; - } - - target_pc1 = i + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS; - DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1)); - DUK_ASSERT(target_pc1 >= 0); - DUK_ASSERT(target_pc1 < n); - - /* Note: if target_pc1 == i, we'll optimize a jump to itself. - * This does not need to be checked for explicitly; the case - * is rare and max iter breaks us out. - */ - - ins = bc[target_pc1].ins; - if (DUK_DEC_OP(ins) != DUK_OP_JUMP) { - continue; - } - - target_pc2 = target_pc1 + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS; - - DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld", - (long) i, (long) target_pc1, (long) target_pc2)); - - bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS); - - count_opt++; - } - - DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt, (long) (iter + 1))); - - if (count_opt == 0) { - break; - } - } -} - -/* - * Intermediate value helpers - */ - -/* Flags for intermediate value coercions. A flag for using a forced reg - * is not needed, the forced_reg argument suffices and generates better - * code (it is checked as it is used). - */ -/* XXX: DUK__IVAL_FLAG_REQUIRE_SHORT is passed but not currently implemented - * by ispec/ivalue operations. - */ -#define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */ -#define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */ -#define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */ - -/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(thr,x) */ - -#if 0 /* enable manually for dumping */ -#define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0) -#define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0) - -DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) { - DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T", - (long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx, - duk_get_tval(comp_ctx->thr, x->valstack_idx))); -} -DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld " - "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} " - "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}", - (long) x->t, (long) x->op, - (long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx, - duk_get_tval(comp_ctx->thr, x->x1.valstack_idx), - (long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx, - duk_get_tval(comp_ctx->thr, x->x2.valstack_idx))); -} -#else -#define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0) -#define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0) -#endif - -DUK_LOCAL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst) { - x->t = DUK_IVAL_PLAIN; - x->x1.t = DUK_ISPEC_REGCONST; - x->x1.regconst = regconst; -} - -DUK_LOCAL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - x->t = DUK_IVAL_PLAIN; - x->x1.t = DUK_ISPEC_VALUE; - duk_replace(comp_ctx->thr, x->x1.valstack_idx); -} - -DUK_LOCAL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - x->t = DUK_IVAL_VAR; - x->x1.t = DUK_ISPEC_VALUE; - duk_replace(comp_ctx->thr, x->x1.valstack_idx); -} - -DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h) { - DUK_ASSERT(h != NULL); - duk_push_hstring(comp_ctx->thr, h); - duk__ivalue_var_fromstack(comp_ctx, x); -} - -DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) { - dst->t = src->t; - dst->regconst = src->regconst; - duk_copy(comp_ctx->thr, src->valstack_idx, dst->valstack_idx); -} - -DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) { - dst->t = src->t; - dst->op = src->op; - dst->x1.t = src->x1.t; - dst->x1.regconst = src->x1.regconst; - dst->x2.t = src->x2.t; - dst->x2.regconst = src->x2.regconst; - duk_copy(comp_ctx->thr, src->x1.valstack_idx, dst->x1.valstack_idx); - duk_copy(comp_ctx->thr, src->x2.valstack_idx, dst->x2.valstack_idx); -} - -DUK_LOCAL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) { - duk_regconst_t res; - - res = comp_ctx->curr_func.temp_next; - comp_ctx->curr_func.temp_next += num; - - if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */ - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT); - } - - /* maintain highest 'used' temporary, needed to figure out nregs of function */ - if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) { - comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next; - } - - return res; -} - -DUK_LOCAL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx) { - return duk__alloctemps(comp_ctx, 1); -} - -DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next) { - comp_ctx->curr_func.temp_next = temp_next; - if (temp_next > comp_ctx->curr_func.temp_max) { - comp_ctx->curr_func.temp_max = temp_next; - } -} - -/* get const for value at valstack top */ -DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) { - duk_hthread *thr = comp_ctx->thr; - duk_compiler_func *f = &comp_ctx->curr_func; - duk_tval *tv1; - duk_int_t i, n, n_check; - - n = (duk_int_t) duk_get_length(thr, f->consts_idx); - - tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); - DUK_ASSERT(tv1 != NULL); - -#if defined(DUK_USE_FASTINT) - /* Explicit check for fastint downgrade. */ - DUK_TVAL_CHKFAST_INPLACE_SLOW(tv1); -#endif - - /* Sanity workaround for handling functions with a large number of - * constants at least somewhat reasonably. Otherwise checking whether - * we already have the constant would grow very slow (as it is O(N^2)). - */ - n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n); - for (i = 0; i < n_check; i++) { - duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, f->h_consts, i); - - /* Strict equality is NOT enough, because we cannot use the same - * constant for e.g. +0 and -0. - */ - if (duk_js_samevalue(tv1, tv2)) { - DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld", - (duk_tval *) tv1, (long) i)); - duk_pop(thr); - return (duk_regconst_t) i | (duk_regconst_t) DUK__CONST_MARKER; - } - } - - if (n > DUK__MAX_CONSTS) { - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT); - } - - DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld", - (duk_tval *) tv1, (long) n)); - (void) duk_put_prop_index(thr, f->consts_idx, (duk_uarridx_t) n); /* invalidates tv1, tv2 */ - return (duk_regconst_t) n | (duk_regconst_t) DUK__CONST_MARKER; -} - -DUK_LOCAL duk_bool_t duk__const_needs_refcount(duk_compiler_ctx *comp_ctx, duk_regconst_t rc) { -#if defined(DUK_USE_REFERENCE_COUNTING) - duk_compiler_func *f = &comp_ctx->curr_func; - duk_bool_t ret; - - DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */ - (void) duk_get_prop_index(comp_ctx->thr, f->consts_idx, (duk_uarridx_t) rc); - ret = !duk_is_number(comp_ctx->thr, -1); /* now only number/string, so conservative check */ - duk_pop(comp_ctx->thr); - return ret; -#else - DUK_UNREF(comp_ctx); - DUK_UNREF(rc); - DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */ - return 0; -#endif -} - -/* Get the value represented by an duk_ispec to a register or constant. - * The caller can control the result by indicating whether or not: - * - * (1) a constant is allowed (sometimes the caller needs the result to - * be in a register) - * - * (2) a temporary register is required (usually when caller requires - * the register to be safely mutable; normally either a bound - * register or a temporary register are both OK) - * - * (3) a forced register target needs to be used - * - * Bytecode may be emitted to generate the necessary value. The return - * value is either a register or a constant. - */ - -DUK_LOCAL -duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx, - duk_ispec *x, - duk_regconst_t forced_reg, - duk_small_uint_t flags) { - duk_hthread *thr = comp_ctx->thr; - - DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, " - "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld", - (long) x->t, - (long) x->regconst, - (duk_tval *) duk_get_tval(thr, x->valstack_idx), - (long) forced_reg, - (unsigned long) flags, - (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0), - (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0), - (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0))); - - switch (x->t) { - case DUK_ISPEC_VALUE: { - duk_tval *tv; - - tv = DUK_GET_TVAL_POSIDX(thr, x->valstack_idx); - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: { - /* Note: although there is no 'undefined' literal, undefined - * values can occur during compilation as a result of e.g. - * the 'void' operator. - */ - duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); - duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, dest); - return dest; - } - case DUK_TAG_NULL: { - duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); - duk__emit_bc(comp_ctx, DUK_OP_LDNULL, dest); - return dest; - } - case DUK_TAG_BOOLEAN: { - duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); - duk__emit_bc(comp_ctx, - (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_OP_LDTRUE : DUK_OP_LDFALSE), - dest); - return dest; - } - case DUK_TAG_POINTER: { - DUK_UNREACHABLE(); - break; - } - case DUK_TAG_STRING: { - duk_hstring *h; - duk_regconst_t dest; - duk_regconst_t constidx; - - h = DUK_TVAL_GET_STRING(tv); - DUK_UNREF(h); - DUK_ASSERT(h != NULL); - -#if 0 /* XXX: to be implemented? */ - /* Use special opcodes to load short strings */ - if (DUK_HSTRING_GET_BYTELEN(h) <= 2) { - /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */ - } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) { - /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */ - } -#endif - duk_dup(thr, x->valstack_idx); - constidx = duk__getconst(comp_ctx); - - if (flags & DUK__IVAL_FLAG_ALLOW_CONST) { - return constidx; - } - - dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); - duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx); - return dest; - } - case DUK_TAG_OBJECT: { - DUK_UNREACHABLE(); - break; - } - case DUK_TAG_BUFFER: { - DUK_UNREACHABLE(); - break; - } - case DUK_TAG_LIGHTFUNC: { - DUK_UNREACHABLE(); - break; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: { - /* number */ - duk_regconst_t dest; - duk_regconst_t constidx; - duk_double_t dval; - duk_int32_t ival; - - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - dval = DUK_TVAL_GET_NUMBER(tv); - - if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) { - /* A number can be loaded either through a constant, using - * LDINT, or using LDINT+LDINTX. LDINT is always a size win, - * LDINT+LDINTX is not if the constant is used multiple times. - * Currently always prefer LDINT+LDINTX over a double constant. - */ - - if (duk_is_whole_get_int32_nonegzero(dval, &ival)) { - dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); - duk__emit_load_int32(comp_ctx, dest, ival); - return dest; - } - } - - duk_dup(thr, x->valstack_idx); - constidx = duk__getconst(comp_ctx); - - if (flags & DUK__IVAL_FLAG_ALLOW_CONST) { - return constidx; - } else { - dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); - duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx); - return dest; - } - } - } /* end switch */ - } - case DUK_ISPEC_REGCONST: { - if (forced_reg >= 0) { - if (DUK__ISCONST(x->regconst)) { - duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst); - } else if (x->regconst != forced_reg) { - duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst); - } else { - ; /* already in correct reg */ - } - return forced_reg; - } - - DUK_ASSERT(forced_reg < 0); - if (DUK__ISCONST(x->regconst)) { - if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) { - duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx); - duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, x->regconst); - return dest; - } - return x->regconst; - } - - DUK_ASSERT(forced_reg < 0 && !DUK__ISCONST(x->regconst)); - if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISREG_TEMP(comp_ctx, x->regconst)) { - duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx); - duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, x->regconst); - return dest; - } - return x->regconst; - } - default: { - break; - } - } - - DUK_ERROR_INTERNAL(thr); - return 0; -} - -DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg) { - DUK_ASSERT(forced_reg >= 0); - (void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/); -} - -/* Coerce an duk_ivalue to a 'plain' value by generating the necessary - * arithmetic operations, property access, or variable access bytecode. - * The duk_ivalue argument ('x') is converted into a plain value as a - * side effect. - */ -DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg) { - duk_hthread *thr = comp_ctx->thr; - - DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, " - "forced_reg=%ld", - (long) x->t, (long) x->op, - (long) x->x1.t, (long) x->x1.regconst, - (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx), - (long) x->x2.t, (long) x->x2.regconst, - (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx), - (long) forced_reg)); - - switch (x->t) { - case DUK_IVAL_PLAIN: { - return; - } - /* XXX: support unary arithmetic ivalues (useful?) */ - case DUK_IVAL_ARITH: { - duk_regconst_t arg1; - duk_regconst_t arg2; - duk_regconst_t dest; - duk_tval *tv1; - duk_tval *tv2; - - DUK_DDD(DUK_DDDPRINT("arith to plain conversion")); - - /* inline arithmetic check for constant values */ - /* XXX: use the exactly same arithmetic function here as in executor */ - if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) { - tv1 = DUK_GET_TVAL_POSIDX(thr, x->x1.valstack_idx); - tv2 = DUK_GET_TVAL_POSIDX(thr, x->x2.valstack_idx); - DUK_ASSERT(tv1 != NULL); - DUK_ASSERT(tv2 != NULL); - - DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T", - (duk_tval *) tv1, - (duk_tval *) tv2)); - - if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) { - duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1); - duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2); - duk_double_t d3; - duk_bool_t accept_fold = 1; - - DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld", - (double) d1, (double) d2, (long) x->op)); - switch (x->op) { - case DUK_OP_ADD: { - d3 = d1 + d2; - break; - } - case DUK_OP_SUB: { - d3 = d1 - d2; - break; - } - case DUK_OP_MUL: { - d3 = d1 * d2; - break; - } - case DUK_OP_DIV: { - d3 = d1 / d2; - break; - } - case DUK_OP_EXP: { - d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2); - break; - } - default: { - d3 = 0.0; /* Won't be used, but silence MSVC /W4 warning. */ - accept_fold = 0; - break; - } - } - - if (accept_fold) { - duk_double_union du; - du.d = d3; - DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); - d3 = du.d; - - x->t = DUK_IVAL_PLAIN; - DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE); - DUK_TVAL_SET_NUMBER(tv1, d3); /* old value is number: no refcount */ - return; - } - } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) { - /* Inline string concatenation. No need to check for - * symbols, as all inputs are valid Ecmascript strings. - */ - duk_dup(thr, x->x1.valstack_idx); - duk_dup(thr, x->x2.valstack_idx); - duk_concat(thr, 2); - duk_replace(thr, x->x1.valstack_idx); - x->t = DUK_IVAL_PLAIN; - DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE); - return; - } - } - - arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/); - arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/); - - /* If forced reg, use it as destination. Otherwise try to - * use either coerced ispec if it is a temporary. - */ - if (forced_reg >= 0) { - dest = forced_reg; - } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) { - dest = arg1; - } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) { - dest = arg2; - } else { - dest = DUK__ALLOCTEMP(comp_ctx); - } - - DUK_ASSERT(DUK__ISREG(dest)); - duk__emit_a_b_c(comp_ctx, x->op | DUK__EMIT_FLAG_BC_REGCONST, dest, arg1, arg2); - - duk__ivalue_regconst(x, dest); - return; - } - case DUK_IVAL_PROP: { - /* XXX: very similar to DUK_IVAL_ARITH - merge? */ - duk_regconst_t arg1; - duk_regconst_t arg2; - duk_regconst_t dest; - - /* Need a short reg/const, does not have to be a mutable temp. */ - arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/); - arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/); - - /* Pick a destination register. If either base value or key - * happens to be a temp value, reuse it as the destination. - * - * XXX: The temp must be a "mutable" one, i.e. such that no - * other expression is using it anymore. Here this should be - * the case because the value of a property access expression - * is neither the base nor the key, but the lookup result. - */ - - if (forced_reg >= 0) { - dest = forced_reg; - } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) { - dest = arg1; - } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) { - dest = arg2; - } else { - dest = DUK__ALLOCTEMP(comp_ctx); - } - - duk__emit_a_b_c(comp_ctx, - DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST, - dest, - arg1, - arg2); - - duk__ivalue_regconst(x, dest); - return; - } - case DUK_IVAL_VAR: { - /* x1 must be a string */ - duk_regconst_t dest; - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE); - - duk_dup(thr, x->x1.valstack_idx); - if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { - duk__ivalue_regconst(x, reg_varbind); - } else { - dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); - duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, dest, rc_varname); - duk__ivalue_regconst(x, dest); - } - return; - } - case DUK_IVAL_NONE: - default: { - DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x->t)); - break; - } - } - - DUK_ERROR_INTERNAL(thr); - return; -} - -/* evaluate to plain value, no forced register (temp/bound reg both ok) */ -DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/); -} - -/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */ -DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - duk_regconst_t temp; - - /* If duk__ivalue_toplain_raw() allocates a temp, forget it and - * restore next temp state. - */ - temp = DUK__GETTEMP(comp_ctx); - duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/); - DUK__SETTEMP(comp_ctx, temp); -} - -/* Coerce an duk_ivalue to a register or constant; result register may - * be a temp or a bound register. - * - * The duk_ivalue argument ('x') is converted into a regconst as a - * side effect. - */ -DUK_LOCAL -duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx, - duk_ivalue *x, - duk_regconst_t forced_reg, - duk_small_uint_t flags) { - duk_hthread *thr = comp_ctx->thr; - duk_regconst_t reg; - DUK_UNREF(thr); - - DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, " - "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld", - (long) x->t, (long) x->op, - (long) x->x1.t, (long) x->x1.regconst, - (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx), - (long) x->x2.t, (long) x->x2.regconst, - (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx), - (long) forced_reg, - (unsigned long) flags, - (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0), - (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0), - (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0))); - - /* first coerce to a plain value */ - duk__ivalue_toplain_raw(comp_ctx, x, forced_reg); - DUK_ASSERT(x->t == DUK_IVAL_PLAIN); - - /* then to a register */ - reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags); - duk__ivalue_regconst(x, reg); - - return reg; -} - -DUK_LOCAL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/); -} - -#if 0 /* unused */ -DUK_LOCAL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/); -} -#endif - -DUK_LOCAL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg) { - DUK_ASSERT(forced_reg >= 0); - (void) duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/); -} - -DUK_LOCAL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); -} - -DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { - return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/); -} - -/* The issues below can be solved with better flags */ - -/* XXX: many operations actually want toforcedtemp() -- brand new temp? */ -/* XXX: need a toplain_ignore() which will only coerce a value to a temp - * register if it might have a side effect. Side-effect free values do not - * need to be coerced. - */ - -/* - * Identifier handling - */ - -DUK_LOCAL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) { - duk_hthread *thr = comp_ctx->thr; - duk_hstring *h_varname; - duk_regconst_t ret; - - DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'", - (duk_tval *) duk_get_tval(thr, -1))); - - /* - * Special name handling - */ - - h_varname = duk_known_hstring(thr, -1); - - if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) { - DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'")); - comp_ctx->curr_func.id_access_arguments = 1; - } - - /* - * Inside one or more 'with' statements fall back to slow path always. - * (See e.g. test-stmt-with.js.) - */ - - if (comp_ctx->curr_func.with_depth > 0) { - DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path")); - goto slow_path_own; - } - - /* - * Any catch bindings ("catch (e)") also affect identifier binding. - * - * Currently, the varmap is modified for the duration of the catch - * clause to ensure any identifier accesses with the catch variable - * name will use slow path. - */ - - duk_get_prop(thr, comp_ctx->curr_func.varmap_idx); - if (duk_is_number(thr, -1)) { - ret = duk_to_int(thr, -1); - duk_pop(thr); - } else { - duk_pop(thr); - if (comp_ctx->curr_func.catch_depth > 0 || comp_ctx->curr_func.with_depth > 0) { - DUK_DDD(DUK_DDDPRINT("slow path access from inside a try-catch or with needs _Varmap")); - goto slow_path_own; - } else { - /* In this case we're doing a variable lookup that doesn't - * match our own variables, so _Varmap won't be needed at - * run time. - */ - DUK_DDD(DUK_DDDPRINT("slow path access outside of try-catch and with, no need for _Varmap")); - goto slow_path_notown; - } - } - - DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret)); - return ret; - - slow_path_notown: - DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, not own variable")); - - comp_ctx->curr_func.id_access_slow = 1; - return (duk_regconst_t) -1; - - slow_path_own: - DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, may be own variable")); - - comp_ctx->curr_func.id_access_slow = 1; - comp_ctx->curr_func.id_access_slow_own = 1; - return (duk_regconst_t) -1; -} - -/* Lookup an identifier name in the current varmap, indicating whether the - * identifier is register-bound and if not, allocating a constant for the - * identifier name. Returns 1 if register-bound, 0 otherwise. Caller can - * also check (out_reg_varbind >= 0) to check whether or not identifier is - * register bound. The caller must NOT use out_rc_varname at all unless - * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname - * is unsigned and doesn't have a "unused" / none value. - */ -DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) { - duk_hthread *thr = comp_ctx->thr; - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - /* [ ... varname ] */ - - duk_dup_top(thr); - reg_varbind = duk__lookup_active_register_binding(comp_ctx); - - if (reg_varbind >= 0) { - *out_reg_varbind = reg_varbind; - *out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */ - duk_pop(thr); - return 1; - } else { - rc_varname = duk__getconst(comp_ctx); - *out_reg_varbind = -1; - *out_rc_varname = rc_varname; - return 0; - } -} - -/* - * Label handling - * - * Labels are initially added with flags prohibiting both break and continue. - * When the statement type is finally uncovered (after potentially multiple - * labels), all the labels are updated to allow/prohibit break and continue. - */ - -DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) { - duk_hthread *thr = comp_ctx->thr; - duk_size_t n; - duk_size_t new_size; - duk_uint8_t *p; - duk_labelinfo *li_start, *li; - - /* Duplicate (shadowing) labels are not allowed, except for the empty - * labels (which are used as default labels for switch and iteration - * statements). - * - * We could also allow shadowing of non-empty pending labels without any - * other issues than breaking the required label shadowing requirements - * of the E5 specification, see Section 12.12. - */ - - p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos); - li_start = (duk_labelinfo *) (void *) p; - li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos)); - n = (duk_size_t) (li - li_start); - - while (li > li_start) { - li--; - - if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) { - DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL); - } - } - - duk_push_hstring(thr, h_label); - DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */ - (void) duk_put_prop_index(thr, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n); - - new_size = (n + 1) * sizeof(duk_labelinfo); - duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size); - /* XXX: slack handling, slow now */ - - /* relookup after possible realloc */ - p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos); - li_start = (duk_labelinfo *) (void *) p; - DUK_UNREF(li_start); /* silence scan-build warning */ - li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos)); - li--; - - /* Labels can be used for iteration statements but also for other statements, - * in particular a label can be used for a block statement. All cases of a - * named label accept a 'break' so that flag is set here. Iteration statements - * also allow 'continue', so that flag is updated when we figure out the - * statement type. - */ - - li->flags = DUK_LABEL_FLAG_ALLOW_BREAK; - li->label_id = label_id; - li->h_label = h_label; - li->catch_depth = comp_ctx->curr_func.catch_depth; /* catch depth from current func */ - li->pc_label = pc_label; - - DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld", - (unsigned long) li->flags, (long) li->label_id, (duk_heaphdr *) li->h_label, - (long) li->catch_depth, (long) li->pc_label)); -} - -/* Update all labels with matching label_id. */ -DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags) { - duk_uint8_t *p; - duk_labelinfo *li_start, *li; - - p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx->thr->heap, comp_ctx->curr_func.h_labelinfos); - li_start = (duk_labelinfo *) (void *) p; - li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos)); - - /* Match labels starting from latest; once label_id no longer matches, we can - * safely exit without checking the rest of the labels (only the topmost labels - * are ever updated). - */ - while (li > li_start) { - li--; - - if (li->label_id != label_id) { - break; - } - - DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld", - (void *) li, (long) label_id, (long) flags)); - - li->flags = flags; - } -} - -/* Lookup active label information. Break/continue distinction is necessary to handle switch - * statement related labels correctly: a switch will only catch a 'break', not a 'continue'. - * - * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled - * iteration and switch statements) can. A break will match the closest unlabelled or labelled - * statement. A continue will match the closest unlabelled or labelled iteration statement. It is - * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot - * be duplicated, the continue cannot match any valid label outside the switch. - * - * A side effect of these rules is that a LABEL statement related to a switch should never actually - * catch a continue abrupt completion at run-time. Hence an INVALID opcode can be placed in the - * continue slot of the switch's LABEL statement. - */ - -/* XXX: awkward, especially the bunch of separate output values -> output struct? */ -DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest) { - duk_hthread *thr = comp_ctx->thr; - duk_uint8_t *p; - duk_labelinfo *li_start, *li_end, *li; - duk_bool_t match = 0; - - DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld", - (duk_heaphdr *) h_label, (long) is_break)); - - DUK_UNREF(thr); - - p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos); - li_start = (duk_labelinfo *) (void *) p; - li_end = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos)); - li = li_end; - - /* Match labels starting from latest label because there can be duplicate empty - * labels in the label set. - */ - while (li > li_start) { - li--; - - if (li->h_label != h_label) { - DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O", - (long) (li - li_start), - (duk_heaphdr *) li->h_label, - (duk_heaphdr *) h_label)); - continue; - } - - DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)", - (long) (li - li_start), (duk_heaphdr *) h_label)); - - /* currently all labels accept a break, so no explicit check for it now */ - DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK); - - if (is_break) { - /* break matches always */ - match = 1; - break; - } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) { - /* iteration statements allow continue */ - match = 1; - break; - } else { - /* continue matched this label -- we can only continue if this is the empty - * label, for which duplication is allowed, and thus there is hope of - * finding a match deeper in the label stack. - */ - if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) { - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL); - } else { - DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not " - "allow a continue -> continue lookup deeper in label stack")); - } - } - } - /* XXX: match flag is awkward, rework */ - if (!match) { - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL); - } - - DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld", - (duk_heaphdr *) h_label, (long) li->label_id, - (long) li->catch_depth, (long) li->pc_label)); - - *out_label_id = li->label_id; - *out_label_catch_depth = li->catch_depth; - *out_label_pc = li->pc_label; - *out_is_closest = (li == li_end - 1); -} - -DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len) { - duk_hthread *thr = comp_ctx->thr; - - duk_set_length(thr, comp_ctx->curr_func.labelnames_idx, len); - duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * len); -} - -/* - * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers. - * - * - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal) - * - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator) - * - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token - */ - -/* object literal key tracking flags */ -#define DUK__OBJ_LIT_KEY_PLAIN (1 << 0) /* key encountered as a plain property */ -#define DUK__OBJ_LIT_KEY_GET (1 << 1) /* key encountered as a getter */ -#define DUK__OBJ_LIT_KEY_SET (1 << 2) /* key encountered as a setter */ - -DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_hthread *thr = comp_ctx->thr; - duk_regconst_t reg_obj; /* result reg */ - duk_regconst_t reg_temp; /* temp reg */ - duk_regconst_t temp_start; /* temp reg value for start of loop */ - duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */ - duk_small_uint_t num_values; /* number of values in current MPUTARR set */ - duk_uarridx_t curr_idx; /* current (next) array index */ - duk_uarridx_t start_idx; /* start array index of current MPUTARR set */ - duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */ - duk_bool_t require_comma; /* next loop requires a comma */ -#if !defined(DUK_USE_PREFER_SIZE) - duk_int_t pc_newarr; - duk_compiler_instr *instr; -#endif - - /* DUK_TOK_LBRACKET already eaten, current token is right after that */ - DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET); - - max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */ - - reg_obj = DUK__ALLOCTEMP(comp_ctx); -#if !defined(DUK_USE_PREFER_SIZE) - pc_newarr = duk__get_current_pc(comp_ctx); -#endif - duk__emit_bc(comp_ctx, DUK_OP_NEWARR, reg_obj); /* XXX: patch initial size hint afterwards? */ - temp_start = DUK__GETTEMP(comp_ctx); - - /* - * Emit initializers in sets of maximum max_init_values. - * Corner cases such as single value initializers do not have - * special handling now. - * - * Elided elements must not be emitted as 'undefined' values, - * because such values would be enumerable (which is incorrect). - * Also note that trailing elisions must be reflected in the - * length of the final array but cause no elements to be actually - * inserted. - */ - - curr_idx = 0; - init_idx = 0; /* tracks maximum initialized index + 1 */ - start_idx = 0; - require_comma = 0; - - for (;;) { - num_values = 0; - DUK__SETTEMP(comp_ctx, temp_start); - - if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) { - break; - } - - for (;;) { - if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) { - /* the outer loop will recheck and exit */ - break; - } - - /* comma check */ - if (require_comma) { - if (comp_ctx->curr_token.t == DUK_TOK_COMMA) { - /* comma after a value, expected */ - duk__advance(comp_ctx); - require_comma = 0; - continue; - } else { - goto syntax_error; - } - } else { - if (comp_ctx->curr_token.t == DUK_TOK_COMMA) { - /* elision - flush */ - curr_idx++; - duk__advance(comp_ctx); - /* if num_values > 0, MPUTARR emitted by outer loop after break */ - break; - } - } - /* else an array initializer element */ - - /* initial index */ - if (num_values == 0) { - start_idx = curr_idx; - reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk__emit_load_int32(comp_ctx, reg_temp, (duk_int32_t) start_idx); - } - - reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */ - DUK__SETTEMP(comp_ctx, reg_temp); - duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); - DUK__SETTEMP(comp_ctx, reg_temp + 1); - - num_values++; - curr_idx++; - require_comma = 1; - - if (num_values >= max_init_values) { - /* MPUTARR emitted by outer loop */ - break; - } - } - - if (num_values > 0) { - /* - A is a source register (it's not a write target, but used - * to identify the target object) but can be shuffled. - * - B cannot be shuffled normally because it identifies a range - * of registers, the emitter has special handling for this - * (the "no shuffle" flag must not be set). - * - C is a non-register number and cannot be shuffled, but - * never needs to be. - */ - duk__emit_a_b_c(comp_ctx, - DUK_OP_MPUTARR | - DUK__EMIT_FLAG_NO_SHUFFLE_C | - DUK__EMIT_FLAG_A_IS_SOURCE, - reg_obj, - temp_start, - (duk_regconst_t) (num_values + 1)); - init_idx = start_idx + num_values; - - /* num_values and temp_start reset at top of outer loop */ - } - } - - /* Update initil size for NEWARR, doesn't need to be exact and is - * capped at A field limit. - */ -#if !defined(DUK_USE_PREFER_SIZE) - instr = duk__get_instr_ptr(comp_ctx, pc_newarr); - instr->ins |= DUK_ENC_OP_A(0, curr_idx > DUK_BC_A_MAX ? DUK_BC_A_MAX : curr_idx); -#endif - - DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET); - duk__advance(comp_ctx); - - DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld", - (long) curr_idx, (long) init_idx)); - - /* trailing elisions? */ - if (curr_idx > init_idx) { - /* yes, must set array length explicitly */ - DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length")); - reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx); - duk__emit_a_bc(comp_ctx, - DUK_OP_SETALEN | DUK__EMIT_FLAG_A_IS_SOURCE, - reg_obj, - reg_temp); - } - - DUK__SETTEMP(comp_ctx, temp_start); - - duk__ivalue_regconst(res, reg_obj); - return; - - syntax_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL); -} - -typedef struct { - duk_regconst_t reg_obj; - duk_regconst_t temp_start; - duk_small_uint_t num_pairs; - duk_small_uint_t num_total_pairs; -} duk__objlit_state; - -DUK_LOCAL void duk__objlit_flush_keys(duk_compiler_ctx *comp_ctx, duk__objlit_state *st) { - if (st->num_pairs > 0) { - /* - A is a source register (it's not a write target, but used - * to identify the target object) but can be shuffled. - * - B cannot be shuffled normally because it identifies a range - * of registers, the emitter has special handling for this - * (the "no shuffle" flag must not be set). - * - C is a non-register number and cannot be shuffled, but - * never needs to be. - */ - DUK_ASSERT(st->num_pairs > 0); - duk__emit_a_b_c(comp_ctx, - DUK_OP_MPUTOBJ | - DUK__EMIT_FLAG_NO_SHUFFLE_C | - DUK__EMIT_FLAG_A_IS_SOURCE, - st->reg_obj, - st->temp_start, - (duk_regconst_t) (st->num_pairs * 2)); - st->num_total_pairs += st->num_pairs; - st->num_pairs = 0; - } - DUK__SETTEMP(comp_ctx, st->temp_start); -} - -DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_token *tok, duk_regconst_t reg_temp) { - if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t_nores == DUK_TOK_STRING) { - /* same handling for identifiers and strings */ - DUK_ASSERT(tok->str1 != NULL); - duk_push_hstring(comp_ctx->thr, tok->str1); - } else if (tok->t == DUK_TOK_NUMBER) { - /* numbers can be loaded as numbers and coerced on the fly */ - duk_push_number(comp_ctx->thr, tok->num); - } else { - return 1; /* error */ - } - - duk__ivalue_plain_fromstack(comp_ctx, res); - DUK__SETTEMP(comp_ctx, reg_temp + 1); - duk__ivalue_toforcedreg(comp_ctx, res, reg_temp); - DUK__SETTEMP(comp_ctx, reg_temp + 1); - return 0; -} - -DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_hthread *thr = comp_ctx->thr; - duk__objlit_state st; - duk_regconst_t reg_temp; /* temp reg */ - duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */ - duk_bool_t first; /* first value: comma must not precede the value */ - duk_bool_t is_set, is_get; /* temps */ -#if !defined(DUK_USE_PREFER_SIZE) - duk_int_t pc_newobj; - duk_compiler_instr *instr; -#endif - - DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY); - - max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */ - - st.reg_obj = DUK__ALLOCTEMP(comp_ctx); /* target object */ - st.temp_start = DUK__GETTEMP(comp_ctx); /* start of MPUTOBJ argument list */ - st.num_pairs = 0; /* number of key/value pairs emitted for current MPUTOBJ set */ - st.num_total_pairs = 0; /* number of key/value pairs emitted overall */ - -#if !defined(DUK_USE_PREFER_SIZE) - pc_newobj = duk__get_current_pc(comp_ctx); -#endif - duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, st.reg_obj); - - /* - * Emit initializers in sets of maximum max_init_pairs keys. - * Setter/getter is handled separately and terminates the - * current set of initializer values. Corner cases such as - * single value initializers do not have special handling now. - */ - - first = 1; - for (;;) { - /* - * ES5 and ES2015+ provide a lot of different PropertyDefinition - * formats, see http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer. - * - * PropertyName can be IdentifierName (includes reserved words), a string - * literal, or a number literal. Note that IdentifierName allows 'get' and - * 'set' too, so we need to look ahead to the next token to distinguish: - * - * { get : 1 } - * - * and - * - * { get foo() { return 1 } } - * { get get() { return 1 } } // 'get' as getter propertyname - * - * Finally, a trailing comma is allowed. - * - * Key name is coerced to string at compile time (and ends up as a - * a string constant) even for numeric keys (e.g. "{1:'foo'}"). - * These could be emitted using e.g. LDINT, but that seems hardly - * worth the effort and would increase code size. - */ - - DUK_DDD(DUK_DDDPRINT("object literal loop, curr_token->t = %ld", - (long) comp_ctx->curr_token.t)); - - if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) { - break; - } - - if (first) { - first = 0; - } else { - if (comp_ctx->curr_token.t != DUK_TOK_COMMA) { - goto syntax_error; - } - duk__advance(comp_ctx); - if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) { - /* trailing comma followed by rcurly */ - break; - } - } - - /* Advance to get one step of lookup. */ - duk__advance(comp_ctx); - - /* Flush current MPUTOBJ if enough many pairs gathered. */ - if (st.num_pairs >= max_init_pairs) { - duk__objlit_flush_keys(comp_ctx, &st); - DUK_ASSERT(st.num_pairs == 0); - } - - /* Reset temp register state and reserve reg_temp and - * reg_temp + 1 for handling the current property. - */ - DUK__SETTEMP(comp_ctx, st.temp_start + 2 * (duk_regconst_t) st.num_pairs); - reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2); - - /* NOTE: "get" and "set" are not officially ReservedWords and the lexer - * currently treats them always like ordinary identifiers (DUK_TOK_GET - * and DUK_TOK_SET are unused). They need to be detected based on the - * identifier string content. - */ - - is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER && - comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr)); - is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER && - comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr)); - if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) { - /* getter/setter */ - duk_int_t fnum; - - duk__objlit_flush_keys(comp_ctx, &st); - DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start); /* 2 regs are guaranteed to be allocated w.r.t. temp_max */ - reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2); - - if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->curr_token, reg_temp) != 0) { - goto syntax_error; - } - - /* curr_token = get/set name */ - fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_GETSET); - - duk__emit_a_bc(comp_ctx, - DUK_OP_CLOSURE, - st.temp_start + 1, - (duk_regconst_t) fnum); - - /* Slot C is used in a non-standard fashion (range of regs), - * emitter code has special handling for it (must not set the - * "no shuffle" flag). - */ - duk__emit_a_bc(comp_ctx, - (is_get ? DUK_OP_INITGET : DUK_OP_INITSET) | DUK__EMIT_FLAG_A_IS_SOURCE, - st.reg_obj, - st.temp_start); /* temp_start+0 = key, temp_start+1 = closure */ - - DUK_ASSERT(st.num_pairs == 0); /* temp state is reset on next loop */ -#if defined(DUK_USE_ES6) - } else if (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER && - (comp_ctx->curr_token.t == DUK_TOK_COMMA || comp_ctx->curr_token.t == DUK_TOK_RCURLY)) { - duk_bool_t load_rc; - - load_rc = duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp); - DUK_UNREF(load_rc); - DUK_ASSERT(load_rc == 0); /* always succeeds because token is identifier */ - - duk__ivalue_var_hstring(comp_ctx, res, comp_ctx->prev_token.str1); - DUK_ASSERT(DUK__GETTEMP(comp_ctx) == reg_temp + 1); - duk__ivalue_toforcedreg(comp_ctx, res, reg_temp + 1); - - st.num_pairs++; - } else if ((comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER || - comp_ctx->prev_token.t == DUK_TOK_STRING || - comp_ctx->prev_token.t == DUK_TOK_NUMBER) && - comp_ctx->curr_token.t == DUK_TOK_LPAREN) { - duk_int_t fnum; - - /* Parsing-wise there's a small hickup here: the token parsing - * state is one step too advanced for the function parse helper - * compared to other cases. The current solution is an extra - * flag to indicate whether function parsing should use the - * current or the previous token to starting parsing from. - */ - - if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) { - goto syntax_error; - } - - fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_USE_PREVTOKEN | DUK__FUNC_FLAG_METDEF); - - duk__emit_a_bc(comp_ctx, - DUK_OP_CLOSURE, - reg_temp + 1, - (duk_regconst_t) fnum); - - st.num_pairs++; -#endif /* DUK_USE_ES6 */ - } else { -#if defined(DUK_USE_ES6) - if (comp_ctx->prev_token.t == DUK_TOK_LBRACKET) { - /* ES2015 computed property name. Executor ToPropertyKey() - * coerces the key at runtime. - */ - DUK__SETTEMP(comp_ctx, reg_temp); - duk__expr_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR, reg_temp); - duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET); - - /* XXX: If next token is '(' we're dealing with - * the method shorthand with a computed name, - * e.g. { [Symbol.for('foo')](a,b) {} }. This - * form is not yet supported and causes a - * SyntaxError on the DUK_TOK_COLON check below. - */ - } - else -#endif /* DUK_USE_ES6 */ - { - if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) { - goto syntax_error; - } - } - - duk__advance_expect(comp_ctx, DUK_TOK_COLON); - - DUK__SETTEMP(comp_ctx, reg_temp + 1); - duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp + 1 /*forced_reg*/); - - st.num_pairs++; - } - } /* property loop */ - - /* Flush remaining properties. */ - duk__objlit_flush_keys(comp_ctx, &st); - DUK_ASSERT(st.num_pairs == 0); - DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start); - - /* Update initial size for NEWOBJ. The init size doesn't need to be - * exact as the purpose is just to avoid object resizes in common - * cases. The size is capped to field A limit, and will be too high - * if the object literal contains duplicate keys (this is harmless but - * increases memory traffic if the object is compacted later on). - */ -#if !defined(DUK_USE_PREFER_SIZE) - instr = duk__get_instr_ptr(comp_ctx, pc_newobj); - instr->ins |= DUK_ENC_OP_A(0, st.num_total_pairs > DUK_BC_A_MAX ? DUK_BC_A_MAX : st.num_total_pairs); -#endif - - DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY); - duk__advance(comp_ctx); - - duk__ivalue_regconst(res, st.reg_obj); - return; - - syntax_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL); -} - -/* Parse argument list. Arguments are written to temps starting from - * "next temp". Returns number of arguments parsed. Expects left paren - * to be already eaten, and eats the right paren before returning. - */ -DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_int_t nargs = 0; - duk_regconst_t reg_temp; - - /* Note: expect that caller has already eaten the left paren */ - - DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld", - (long) comp_ctx->prev_token.t, (long) comp_ctx->curr_token.t)); - - for (;;) { - if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) { - break; - } - if (nargs > 0) { - duk__advance_expect(comp_ctx, DUK_TOK_COMMA); - } - - /* We want the argument expression value to go to "next temp" - * without additional moves. That should almost always be the - * case, but we double check after expression parsing. - * - * This is not the cleanest possible approach. - */ - - reg_temp = DUK__ALLOCTEMP(comp_ctx); /* bump up "allocated" reg count, just in case */ - DUK__SETTEMP(comp_ctx, reg_temp); - - /* binding power must be high enough to NOT allow comma expressions directly */ - duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp); /* always allow 'in', coerce to 'tr' just in case */ - - DUK__SETTEMP(comp_ctx, reg_temp + 1); - nargs++; - - DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs, (long) reg_temp)); - } - - /* eat the right paren */ - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - - DUK_DDD(DUK_DDDPRINT("end parsing arguments")); - - return nargs; -} - -DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) { - /* empty expressions can be detected conveniently with nud/led counts */ - return (comp_ctx->curr_func.nud_count == 0) && - (comp_ctx->curr_func.led_count == 0); -} - -DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_hthread *thr = comp_ctx->thr; - duk_token *tk; - duk_regconst_t temp_at_entry; - duk_small_uint_t tok; - duk_uint32_t args; /* temp variable to pass constants and flags to shared code */ - - /* - * ctx->prev_token token to process with duk__expr_nud() - * ctx->curr_token updated by caller - * - * Note: the token in the switch below has already been eaten. - */ - - temp_at_entry = DUK__GETTEMP(comp_ctx); - - comp_ctx->curr_func.nud_count++; - - tk = &comp_ctx->prev_token; - tok = tk->t; - res->t = DUK_IVAL_NONE; - - DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld", - (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level)); - - switch (tok) { - - /* PRIMARY EXPRESSIONS */ - - case DUK_TOK_THIS: { - duk_regconst_t reg_temp; - reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk__emit_bc(comp_ctx, - DUK_OP_LDTHIS, - reg_temp); - duk__ivalue_regconst(res, reg_temp); - return; - } - case DUK_TOK_IDENTIFIER: { - duk__ivalue_var_hstring(comp_ctx, res, tk->str1); - return; - } - case DUK_TOK_NULL: { - duk_push_null(thr); - goto plain_value; - } - case DUK_TOK_TRUE: { - duk_push_true(thr); - goto plain_value; - } - case DUK_TOK_FALSE: { - duk_push_false(thr); - goto plain_value; - } - case DUK_TOK_NUMBER: { - duk_push_number(thr, tk->num); - goto plain_value; - } - case DUK_TOK_STRING: { - DUK_ASSERT(tk->str1 != NULL); - duk_push_hstring(thr, tk->str1); - goto plain_value; - } - case DUK_TOK_REGEXP: { -#if defined(DUK_USE_REGEXP_SUPPORT) - duk_regconst_t reg_temp; - duk_regconst_t rc_re_bytecode; /* const */ - duk_regconst_t rc_re_source; /* const */ - - DUK_ASSERT(tk->str1 != NULL); - DUK_ASSERT(tk->str2 != NULL); - - DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O", - (duk_heaphdr *) tk->str1, - (duk_heaphdr *) tk->str2)); - - reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk_push_hstring(thr, tk->str1); - duk_push_hstring(thr, tk->str2); - - /* [ ... pattern flags ] */ - - duk_regexp_compile(thr); - - /* [ ... escaped_source bytecode ] */ - - rc_re_bytecode = duk__getconst(comp_ctx); - rc_re_source = duk__getconst(comp_ctx); - - duk__emit_a_b_c(comp_ctx, - DUK_OP_REGEXP | DUK__EMIT_FLAG_BC_REGCONST, - reg_temp /*a*/, - rc_re_bytecode /*b*/, - rc_re_source /*c*/); - - duk__ivalue_regconst(res, reg_temp); - return; -#else /* DUK_USE_REGEXP_SUPPORT */ - goto syntax_error; -#endif /* DUK_USE_REGEXP_SUPPORT */ - } - case DUK_TOK_LBRACKET: { - DUK_DDD(DUK_DDDPRINT("parsing array literal")); - duk__nud_array_literal(comp_ctx, res); - return; - } - case DUK_TOK_LCURLY: { - DUK_DDD(DUK_DDDPRINT("parsing object literal")); - duk__nud_object_literal(comp_ctx, res); - return; - } - case DUK_TOK_LPAREN: { - duk_bool_t prev_allow_in; - - comp_ctx->curr_func.paren_level++; - prev_allow_in = comp_ctx->curr_func.allow_in; - comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */ - - duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */ - - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - comp_ctx->curr_func.allow_in = prev_allow_in; - comp_ctx->curr_func.paren_level--; - return; - } - - /* MEMBER/NEW/CALL EXPRESSIONS */ - - case DUK_TOK_NEW: { - /* - * Parsing an expression starting with 'new' is tricky because - * there are multiple possible productions deriving from - * LeftHandSideExpression which begin with 'new'. - * - * We currently resort to one-token lookahead to distinguish the - * cases. Hopefully this is correct. The binding power must be - * such that parsing ends at an LPAREN (CallExpression) but not at - * a PERIOD or LBRACKET (MemberExpression). - * - * See doc/compiler.rst for discussion on the parsing approach, - * and testcases/test-dev-new.js for a bunch of documented tests. - */ - - duk_regconst_t reg_target; - duk_int_t nargs; - - DUK_DDD(DUK_DDDPRINT("begin parsing new expression")); - - reg_target = DUK__ALLOCTEMPS(comp_ctx, 2); - -#if defined(DUK_USE_ES6) - if (comp_ctx->curr_token.t == DUK_TOK_PERIOD) { - /* new.target */ - DUK_DDD(DUK_DDDPRINT("new.target")); - duk__advance(comp_ctx); - if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER || - !duk_hstring_equals_ascii_cstring(comp_ctx->curr_token.str1, "target")) { - goto syntax_error_newtarget; - } - if (comp_ctx->curr_func.is_global) { - goto syntax_error_newtarget; - } - duk__advance(comp_ctx); - duk__emit_bc(comp_ctx, - DUK_OP_NEWTARGET, - reg_target); - duk__ivalue_regconst(res, reg_target); - return; - } -#endif /* DUK_USE_ES6 */ - - duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/); - duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, reg_target + 1); /* default instance */ - DUK__SETTEMP(comp_ctx, reg_target + 2); - - /* XXX: 'new obj.noSuch()' doesn't use GETPROPC now which - * makes the error message worse than for obj.noSuch(). - */ - - if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) { - /* 'new' MemberExpression Arguments */ - DUK_DDD(DUK_DDDPRINT("new expression has argument list")); - duk__advance(comp_ctx); - nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp", reg_target + 1 */ - /* right paren eaten */ - } else { - /* 'new' MemberExpression */ - DUK_DDD(DUK_DDDPRINT("new expression has no argument list")); - nargs = 0; - } - - duk__emit_a_bc(comp_ctx, - DUK_OP_CALL0 | DUK_BC_CALL_FLAG_CONSTRUCT, - nargs /*num_args*/, - reg_target /*target*/); - - DUK_DDD(DUK_DDDPRINT("end parsing new expression")); - - duk__ivalue_regconst(res, reg_target); - return; - } - - /* FUNCTION EXPRESSIONS */ - - case DUK_TOK_FUNCTION: { - /* Function expression. Note that any statement beginning with 'function' - * is handled by the statement parser as a function declaration, or a - * non-standard function expression/statement (or a SyntaxError). We only - * handle actual function expressions (occurring inside an expression) here. - * - * O(depth^2) parse count for inner functions is handled by recording a - * lexer offset on the first compilation pass, so that the function can - * be efficiently skipped on the second pass. This is encapsulated into - * duk__parse_func_like_fnum(). - */ - - duk_regconst_t reg_temp; - duk_int_t fnum; - - reg_temp = DUK__ALLOCTEMP(comp_ctx); - - /* curr_token follows 'function' */ - fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*flags*/); - DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum)); - - duk__emit_a_bc(comp_ctx, - DUK_OP_CLOSURE, - reg_temp /*a*/, - (duk_regconst_t) fnum /*bc*/); - - duk__ivalue_regconst(res, reg_temp); - return; - } - - /* UNARY EXPRESSIONS */ - - case DUK_TOK_DELETE: { - /* Delete semantics are a bit tricky. The description in E5 specification - * is kind of confusing, because it distinguishes between resolvability of - * a reference (which is only known at runtime) seemingly at compile time - * (= SyntaxError throwing). - */ - duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ - if (res->t == DUK_IVAL_VAR) { - /* not allowed in strict mode, regardless of whether resolves; - * in non-strict mode DELVAR handles both non-resolving and - * resolving cases (the specification description is a bit confusing). - */ - - duk_regconst_t reg_temp; - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - if (comp_ctx->curr_func.is_strict) { - DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER); - } - - DUK__SETTEMP(comp_ctx, temp_at_entry); - reg_temp = DUK__ALLOCTEMP(comp_ctx); - - duk_dup(thr, res->x1.valstack_idx); - if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { - /* register bound variables are non-configurable -> always false */ - duk__emit_bc(comp_ctx, - DUK_OP_LDFALSE, - reg_temp); - } else { - duk_dup(thr, res->x1.valstack_idx); - rc_varname = duk__getconst(comp_ctx); - duk__emit_a_bc(comp_ctx, - DUK_OP_DELVAR, - reg_temp, - rc_varname); - } - duk__ivalue_regconst(res, reg_temp); - } else if (res->t == DUK_IVAL_PROP) { - duk_regconst_t reg_temp; - duk_regconst_t reg_obj; - duk_regconst_t rc_key; - - DUK__SETTEMP(comp_ctx, temp_at_entry); - reg_temp = DUK__ALLOCTEMP(comp_ctx); - reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ - rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); - duk__emit_a_b_c(comp_ctx, - DUK_OP_DELPROP | DUK__EMIT_FLAG_BC_REGCONST, - reg_temp, - reg_obj, - rc_key); - - duk__ivalue_regconst(res, reg_temp); - } else { - /* non-Reference deletion is always 'true', even in strict mode */ - duk_push_true(thr); - goto plain_value; - } - return; - } - case DUK_TOK_VOID: { - duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ - duk_push_undefined(thr); - goto plain_value; - } - case DUK_TOK_TYPEOF: { - /* 'typeof' must handle unresolvable references without throwing - * a ReferenceError (E5 Section 11.4.3). Register mapped values - * will never be unresolvable so special handling is only required - * when an identifier is a "slow path" one. - */ - duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ - - if (res->t == DUK_IVAL_VAR) { - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - duk_regconst_t reg_temp; - - duk_dup(thr, res->x1.valstack_idx); - if (!duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { - DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved " - "at compile time, need to use special run-time handling")); - reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk__emit_a_bc(comp_ctx, - DUK_OP_TYPEOFID, - reg_temp, - rc_varname); - duk__ivalue_regconst(res, reg_temp); - return; - } - } - - args = DUK_OP_TYPEOF; - goto unary; - } - case DUK_TOK_INCREMENT: { - args = (DUK_OP_PREINCP << 8) + DUK_OP_PREINCR; - goto preincdec; - } - case DUK_TOK_DECREMENT: { - args = (DUK_OP_PREDECP << 8) + DUK_OP_PREDECR; - goto preincdec; - } - case DUK_TOK_ADD: { - /* unary plus */ - duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ - if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE && - duk_is_number(thr, res->x1.valstack_idx)) { - /* unary plus of a number is identity */ - return; - } - args = DUK_OP_UNP; - goto unary; - } - case DUK_TOK_SUB: { - /* unary minus */ - duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ - if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE && - duk_is_number(thr, res->x1.valstack_idx)) { - /* this optimization is important to handle negative literals - * (which are not directly provided by the lexical grammar) - */ - duk_tval *tv_num; - duk_double_union du; - - tv_num = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx); - DUK_ASSERT(tv_num != NULL); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num)); - du.d = DUK_TVAL_GET_NUMBER(tv_num); - du.d = -du.d; - DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); - DUK_TVAL_SET_NUMBER(tv_num, du.d); - return; - } - args = DUK_OP_UNM; - goto unary; - } - case DUK_TOK_BNOT: { - duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ - args = DUK_OP_BNOT; - goto unary; - } - case DUK_TOK_LNOT: { - duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ - if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) { - /* Very minimal inlining to handle common idioms '!0' and '!1', - * and also boolean arguments like '!false' and '!true'. - */ - duk_tval *tv_val; - - tv_val = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx); - DUK_ASSERT(tv_val != NULL); - if (DUK_TVAL_IS_NUMBER(tv_val)) { - duk_double_t d; - d = DUK_TVAL_GET_NUMBER(tv_val); - if (d == 0.0) { - /* Matches both +0 and -0 on purpose. */ - DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true")); - DUK_TVAL_SET_BOOLEAN_TRUE(tv_val); - return; - } else if (d == 1.0) { - DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false")); - DUK_TVAL_SET_BOOLEAN_FALSE(tv_val); - return; - } - } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) { - duk_small_uint_t v; - v = DUK_TVAL_GET_BOOLEAN(tv_val); - DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v)); - DUK_ASSERT(v == 0 || v == 1); - DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01); - return; - } - } - args = DUK_OP_LNOT; - goto unary; - } - - } /* end switch */ - - DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); - return; - - unary: - { - /* Unary opcodes use just the 'BC' register source because it - * matches current shuffle limits, and maps cleanly to 16 high - * bits of the opcode. - */ - - duk_regconst_t reg_src, reg_res; - - reg_src = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*flags*/); - if (DUK__ISREG_TEMP(comp_ctx, reg_src)) { - reg_res = reg_src; - } else { - reg_res = DUK__ALLOCTEMP(comp_ctx); - } - duk__emit_a_bc(comp_ctx, - args, - reg_res, - reg_src); - duk__ivalue_regconst(res, reg_res); - return; - } - - preincdec: - { - /* preincrement and predecrement */ - duk_regconst_t reg_res; - duk_small_uint_t args_op1 = args & 0xff; /* DUK_OP_PREINCR/DUK_OP_PREDECR */ - duk_small_uint_t args_op2 = args >> 8; /* DUK_OP_PREINCP_RR/DUK_OP_PREDECP_RR */ - - /* Specific assumptions for opcode numbering. */ - DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV); - DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV); - - reg_res = DUK__ALLOCTEMP(comp_ctx); - - duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ - if (res->t == DUK_IVAL_VAR) { - duk_hstring *h_varname; - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - h_varname = duk_known_hstring(thr, res->x1.valstack_idx); - - if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) { - goto syntax_error; - } - - duk_dup(thr, res->x1.valstack_idx); - if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { - duk__emit_a_bc(comp_ctx, - args_op1, /* e.g. DUK_OP_PREINCR */ - reg_res, - reg_varbind); - } else { - duk__emit_a_bc(comp_ctx, - args_op1 + 4, /* e.g. DUK_OP_PREINCV */ - reg_res, - rc_varname); - } - - DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld", - (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname)); - } else if (res->t == DUK_IVAL_PROP) { - duk_regconst_t reg_obj; /* allocate to reg only (not const) */ - duk_regconst_t rc_key; - reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ - rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); - duk__emit_a_b_c(comp_ctx, - args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_PREINCP */ - reg_res, - reg_obj, - rc_key); - } else { - /* Technically return value is not needed because INVLHS will - * unconditially throw a ReferenceError. Coercion is necessary - * for proper semantics (consider ToNumber() called for an object). - * Use DUK_OP_UNP with a dummy register to get ToNumber(). - */ - - duk__ivalue_toforcedreg(comp_ctx, res, reg_res); - duk__emit_bc(comp_ctx, - DUK_OP_UNP, - reg_res); /* for side effects, result ignored */ - duk__emit_op_only(comp_ctx, - DUK_OP_INVLHS); - } - DUK__SETTEMP(comp_ctx, reg_res + 1); - duk__ivalue_regconst(res, reg_res); - return; - } - - plain_value: - { - /* Stack top contains plain value */ - duk__ivalue_plain_fromstack(comp_ctx, res); - return; - } - -#if defined(DUK_USE_ES6) - syntax_error_newtarget: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_NEWTARGET); -#endif - - syntax_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION); -} - -/* XXX: add flag to indicate whether caller cares about return value; this - * affects e.g. handling of assignment expressions. This change needs API - * changes elsewhere too. - */ -DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) { - duk_hthread *thr = comp_ctx->thr; - duk_token *tk; - duk_small_uint_t tok; - duk_uint32_t args; /* temp variable to pass constants and flags to shared code */ - - /* - * ctx->prev_token token to process with duk__expr_led() - * ctx->curr_token updated by caller - */ - - comp_ctx->curr_func.led_count++; - - /* The token in the switch has already been eaten here */ - tk = &comp_ctx->prev_token; - tok = tk->t; - - DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld", - (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level)); - - /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */ - - switch (tok) { - - /* PRIMARY EXPRESSIONS */ - - case DUK_TOK_PERIOD: { - /* Property access expressions are critical for correct LHS ordering, - * see comments in duk__expr()! - * - * A conservative approach would be to use duk__ivalue_totempconst() - * for 'left'. However, allowing a reg-bound variable seems safe here - * and is nice because "foo.bar" is a common expression. If the ivalue - * is used in an expression a GETPROP will occur before any changes to - * the base value can occur. If the ivalue is used as an assignment - * LHS, the assignment code will ensure the base value is safe from - * RHS mutation. - */ - - /* XXX: This now coerces an identifier into a GETVAR to a temp, which - * causes an extra LDREG in call setup. It's sufficient to coerce to a - * unary ivalue? - */ - duk__ivalue_toplain(comp_ctx, left); - - /* NB: must accept reserved words as property name */ - if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) { - DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER); - } - - res->t = DUK_IVAL_PROP; - duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */ - DUK_ASSERT(comp_ctx->curr_token.str1 != NULL); - duk_push_hstring(thr, comp_ctx->curr_token.str1); - duk_replace(thr, res->x2.valstack_idx); - res->x2.t = DUK_ISPEC_VALUE; - - /* special RegExp literal handling after IdentifierName */ - comp_ctx->curr_func.reject_regexp_in_adv = 1; - - duk__advance(comp_ctx); - return; - } - case DUK_TOK_LBRACKET: { - /* Property access expressions are critical for correct LHS ordering, - * see comments in duk__expr()! - */ - - /* XXX: optimize temp reg use */ - /* XXX: similar coercion issue as in DUK_TOK_PERIOD */ - /* XXX: coerce to regs? it might be better for enumeration use, where the - * same PROP ivalue is used multiple times. Or perhaps coerce PROP further - * there? - */ - /* XXX: for simple cases like x['y'] an unnecessary LDREG is - * emitted for the base value; could avoid it if we knew that - * the key expression is safe (e.g. just a single literal). - */ - - /* The 'left' value must not be a register bound variable - * because it may be mutated during the rest of the expression - * and E5.1 Section 11.2.1 specifies the order of evaluation - * so that the base value is evaluated first. - * See: test-bug-nested-prop-mutate.js. - */ - duk__ivalue_totempconst(comp_ctx, left); - duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */ - duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET); - - res->t = DUK_IVAL_PROP; - duk__copy_ispec(comp_ctx, &res->x1, &res->x2); /* res.x1 -> res.x2 */ - duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */ - return; - } - case DUK_TOK_LPAREN: { - /* function call */ - duk_regconst_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2); - duk_int_t nargs; - duk_small_uint_t call_op = DUK_OP_CALL0; - - /* XXX: attempt to get the call result to "next temp" whenever - * possible to avoid unnecessary register shuffles. - */ - - /* - * Setup call: target and 'this' binding. Three cases: - * - * 1. Identifier base (e.g. "foo()") - * 2. Property base (e.g. "foo.bar()") - * 3. Register base (e.g. "foo()()"; i.e. when a return value is a function) - */ - - if (left->t == DUK_IVAL_VAR) { - duk_hstring *h_varname; - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - DUK_DDD(DUK_DDDPRINT("function call with identifier base")); - - h_varname = duk_known_hstring(thr, left->x1.valstack_idx); - if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) { - /* Potential direct eval call detected, flag the CALL - * so that a run-time "direct eval" check is made and - * special behavior may be triggered. Note that this - * does not prevent 'eval' from being register bound. - */ - DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' " - "-> using EVALCALL, marking function " - "as may_direct_eval")); - call_op |= DUK_BC_CALL_FLAG_CALLED_AS_EVAL; - comp_ctx->curr_func.may_direct_eval = 1; - } - - duk_dup(thr, left->x1.valstack_idx); - if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { - duk__emit_a_bc(comp_ctx, - DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE, - reg_varbind, - reg_cs + 0); - } else { - /* XXX: expand target register or constant field to - * reduce shuffling. - */ - DUK_ASSERT(DUK__ISCONST(rc_varname)); - duk__emit_a_b(comp_ctx, - DUK_OP_CSVAR | DUK__EMIT_FLAG_BC_REGCONST, - reg_cs + 0, - rc_varname); - } - } else if (left->t == DUK_IVAL_PROP) { - /* Call through a property lookup, E5 Section 11.2.3, step 6.a.i, - * E5 Section 10.4.3. There used to be a separate CSPROP opcode - * but a typical call setup took 3 opcodes (e.g. LDREG, LDCONST, - * CSPROP) and the same can be achieved with ordinary loads. - */ -#if defined(DUK_USE_VERBOSE_ERRORS) - duk_regconst_t reg_key; -#endif - - DUK_DDD(DUK_DDDPRINT("function call with property base")); - - /* XXX: For Math.sin() this generates: LDCONST + LDREG + - * GETPROPC + call. The LDREG is unnecessary because LDCONST - * could be loaded directly into reg_cs + 1. This doesn't - * happen now because a variable cannot be in left->x1 of a - * DUK_IVAL_PROP. We could notice that left->x1 is a temp - * and reuse, but it would still be in the wrong position - * (reg_cs + 0 rather than reg_cs + 1). - */ - duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 1); /* base */ -#if defined(DUK_USE_VERBOSE_ERRORS) - reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); - duk__emit_a_b_c(comp_ctx, - DUK_OP_GETPROPC | DUK__EMIT_FLAG_BC_REGCONST, - reg_cs + 0, - reg_cs + 1, - reg_key); -#else - duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0); /* base[key] */ -#endif - } else { - DUK_DDD(DUK_DDDPRINT("function call with register base")); - - duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0); -#if 0 - duk__emit_a_bc(comp_ctx, - DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE, - reg_cs + 0, - reg_cs + 0); /* in-place setup */ -#endif - /* Because of in-place setup, REGCS is equivalent to - * just this LDUNDEF. - */ - duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, reg_cs + 1); - } - - DUK__SETTEMP(comp_ctx, reg_cs + 2); - nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */ - - /* Tailcalls are handled by back-patching the already emitted opcode - * later in return statement parser. - */ - - duk__emit_a_bc(comp_ctx, - call_op, - (duk_regconst_t) nargs /*numargs*/, - reg_cs /*basereg*/); - DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */ - - duk__ivalue_regconst(res, reg_cs); - return; - } - - /* POSTFIX EXPRESSION */ - - case DUK_TOK_INCREMENT: { - args = (DUK_OP_POSTINCP_RR << 16) + (DUK_OP_POSTINCR << 8) + 0; - goto postincdec; - } - case DUK_TOK_DECREMENT: { - args = (DUK_OP_POSTDECP_RR << 16) + (DUK_OP_POSTDECR << 8) + 0; - goto postincdec; - } - - /* EXPONENTIATION EXPRESSION */ - -#if defined(DUK_USE_ES7_EXP_OPERATOR) - case DUK_TOK_EXP: { - args = (DUK_OP_EXP << 8) + DUK__BP_EXPONENTIATION - 1; /* UnaryExpression */ - goto binary; - } -#endif - - /* MULTIPLICATIVE EXPRESSION */ - - case DUK_TOK_MUL: { - args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */ - goto binary; - } - case DUK_TOK_DIV: { - args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */ - goto binary; - } - case DUK_TOK_MOD: { - args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */ - goto binary; - } - - /* ADDITIVE EXPRESSION */ - - case DUK_TOK_ADD: { - args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */ - goto binary; - } - case DUK_TOK_SUB: { - args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */ - goto binary; - } - - /* SHIFT EXPRESSION */ - - case DUK_TOK_ALSHIFT: { - /* << */ - args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT; - goto binary; - } - case DUK_TOK_ARSHIFT: { - /* >> */ - args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT; - goto binary; - } - case DUK_TOK_RSHIFT: { - /* >>> */ - args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT; - goto binary; - } - - /* RELATIONAL EXPRESSION */ - - case DUK_TOK_LT: { - /* < */ - args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL; - goto binary; - } - case DUK_TOK_GT: { - args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL; - goto binary; - } - case DUK_TOK_LE: { - args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL; - goto binary; - } - case DUK_TOK_GE: { - args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL; - goto binary; - } - case DUK_TOK_INSTANCEOF: { - args = (DUK_OP_INSTOF << 8) + DUK__BP_RELATIONAL; - goto binary; - } - case DUK_TOK_IN: { - args = (DUK_OP_IN << 8) + DUK__BP_RELATIONAL; - goto binary; - } - - /* EQUALITY EXPRESSION */ - - case DUK_TOK_EQ: { - args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY; - goto binary; - } - case DUK_TOK_NEQ: { - args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY; - goto binary; - } - case DUK_TOK_SEQ: { - args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY; - goto binary; - } - case DUK_TOK_SNEQ: { - args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY; - goto binary; - } - - /* BITWISE EXPRESSIONS */ - - case DUK_TOK_BAND: { - args = (DUK_OP_BAND << 8) + DUK__BP_BAND; - goto binary; - } - case DUK_TOK_BXOR: { - args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR; - goto binary; - } - case DUK_TOK_BOR: { - args = (DUK_OP_BOR << 8) + DUK__BP_BOR; - goto binary; - } - - /* LOGICAL EXPRESSIONS */ - - case DUK_TOK_LAND: { - /* syntactically left-associative but parsed as right-associative */ - args = (1 << 8) + DUK__BP_LAND - 1; - goto binary_logical; - } - case DUK_TOK_LOR: { - /* syntactically left-associative but parsed as right-associative */ - args = (0 << 8) + DUK__BP_LOR - 1; - goto binary_logical; - } - - /* CONDITIONAL EXPRESSION */ - - case DUK_TOK_QUESTION: { - /* XXX: common reg allocation need is to reuse a sub-expression's temp reg, - * but only if it really is a temp. Nothing fancy here now. - */ - duk_regconst_t reg_temp; - duk_int_t pc_jump1; - duk_int_t pc_jump2; - - reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk__ivalue_toforcedreg(comp_ctx, left, reg_temp); - duk__emit_if_true_skip(comp_ctx, reg_temp); - pc_jump1 = duk__emit_jump_empty(comp_ctx); /* jump to false */ - duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */ - duk__advance_expect(comp_ctx, DUK_TOK_COLON); - pc_jump2 = duk__emit_jump_empty(comp_ctx); /* jump to end */ - duk__patch_jump_here(comp_ctx, pc_jump1); - duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */ - duk__patch_jump_here(comp_ctx, pc_jump2); - - DUK__SETTEMP(comp_ctx, reg_temp + 1); - duk__ivalue_regconst(res, reg_temp); - return; - } - - /* ASSIGNMENT EXPRESSION */ - - case DUK_TOK_EQUALSIGN: { - /* - * Assignments are right associative, allows e.g. - * a = 5; - * a += b = 9; // same as a += (b = 9) - * -> expression value 14, a = 14, b = 9 - * - * Right associativiness is reflected in the BP for recursion, - * "-1" ensures assignment operations are allowed. - * - * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)? - */ - args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1; /* DUK_OP_NONE marks a 'plain' assignment */ - goto assign; - } - case DUK_TOK_ADD_EQ: { - /* right associative */ - args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_SUB_EQ: { - /* right associative */ - args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_MUL_EQ: { - /* right associative */ - args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_DIV_EQ: { - /* right associative */ - args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_MOD_EQ: { - /* right associative */ - args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } -#if defined(DUK_USE_ES7_EXP_OPERATOR) - case DUK_TOK_EXP_EQ: { - /* right associative */ - args = (DUK_OP_EXP << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } -#endif - case DUK_TOK_ALSHIFT_EQ: { - /* right associative */ - args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_ARSHIFT_EQ: { - /* right associative */ - args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_RSHIFT_EQ: { - /* right associative */ - args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_BAND_EQ: { - /* right associative */ - args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_BOR_EQ: { - /* right associative */ - args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - case DUK_TOK_BXOR_EQ: { - /* right associative */ - args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1; - goto assign; - } - - /* COMMA */ - - case DUK_TOK_COMMA: { - /* right associative */ - - duk__ivalue_toplain_ignore(comp_ctx, left); /* need side effects, not value */ - duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/); - - /* return 'res' (of right part) as our result */ - return; - } - - default: { - break; - } - } - - DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok)); - DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); - return; - -#if 0 - /* XXX: shared handling for 'duk__expr_lhs'? */ - if (comp_ctx->curr_func.paren_level == 0 && XXX) { - comp_ctx->curr_func.duk__expr_lhs = 0; - } -#endif - - binary: - /* - * Shared handling of binary operations - * - * args = (opcode << 8) + rbp - */ - { - duk__ivalue_toplain(comp_ctx, left); - duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/); - - /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */ - DUK_ASSERT(left->t == DUK_IVAL_PLAIN); - DUK_ASSERT(res->t == DUK_IVAL_PLAIN); - - res->t = DUK_IVAL_ARITH; - res->op = (args >> 8) & 0xff; - - res->x2.t = res->x1.t; - res->x2.regconst = res->x1.regconst; - duk_copy(thr, res->x1.valstack_idx, res->x2.valstack_idx); - - res->x1.t = left->x1.t; - res->x1.regconst = left->x1.regconst; - duk_copy(thr, left->x1.valstack_idx, res->x1.valstack_idx); - - DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx", - (long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst)); - return; - } - - binary_logical: - /* - * Shared handling for logical AND and logical OR. - * - * args = (truthval << 8) + rbp - * - * Truthval determines when to skip right-hand-side. - * For logical AND truthval=1, for logical OR truthval=0. - * - * See doc/compiler.rst for discussion on compiling logical - * AND and OR expressions. The approach here is very simplistic, - * generating extra jumps and multiple evaluations of truth values, - * but generates code on-the-fly with only local back-patching. - * - * Both logical AND and OR are syntactically left-associated. - * However, logical ANDs are compiled as right associative - * expressions, i.e. "A && B && C" as "A && (B && C)", to allow - * skip jumps to skip over the entire tail. Similarly for logical OR. - */ - - { - duk_regconst_t reg_temp; - duk_int_t pc_jump; - duk_small_uint_t args_truthval = args >> 8; - duk_small_uint_t args_rbp = args & 0xff; - - /* XXX: unoptimal use of temps, resetting */ - - reg_temp = DUK__ALLOCTEMP(comp_ctx); - - duk__ivalue_toforcedreg(comp_ctx, left, reg_temp); - DUK_ASSERT(DUK__ISREG(reg_temp)); - duk__emit_bc(comp_ctx, - (args_truthval ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R), - reg_temp); /* skip jump conditionally */ - pc_jump = duk__emit_jump_empty(comp_ctx); - duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/); - duk__patch_jump_here(comp_ctx, pc_jump); - - duk__ivalue_regconst(res, reg_temp); - return; - } - - assign: - /* - * Shared assignment expression handling - * - * args = (opcode << 8) + rbp - * - * If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic. - * Syntactically valid left-hand-side forms which are not accepted as - * left-hand-side values (e.g. as in "f() = 1") must NOT cause a - * SyntaxError, but rather a run-time ReferenceError. - * - * When evaluating X = Y, the LHS (X) is conceptually evaluated - * to a temporary first. The RHS is then evaluated. Finally, the - * is applied to the initial value of RHS (not the value after - * RHS evaluation), and written to X. Doing so concretely generates - * inefficient code so we'd like to avoid the temporary when possible. - * See: https://github.com/svaarala/duktape/pull/992. - * - * The expression value (final LHS value, written to RHS) is - * conceptually copied into a fresh temporary so that it won't - * change even if the LHS/RHS values change in outer expressions. - * For example, it'd be generally incorrect for the expression value - * to be the RHS register binding, unless there's a guarantee that it - * won't change during further expression evaluation. Using the - * temporary concretely produces inefficient bytecode, so we try to - * avoid the extra temporary for some known-to-be-safe cases. - * Currently the only safe case we detect is a "top level assignment", - * for example "x = y + z;", where the assignment expression value is - * ignored. - * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js. - */ - - { - duk_small_uint_t args_op = args >> 8; - duk_small_uint_t args_rbp = args & 0xff; - duk_bool_t toplevel_assign; - - /* XXX: here we need to know if 'left' is left-hand-side compatible. - * That information is no longer available from current expr parsing - * state; it would need to be carried into the 'left' ivalue or by - * some other means. - */ - - /* A top-level assignment is e.g. "x = y;". For these it's safe - * to use the RHS as-is as the expression value, even if the RHS - * is a reg-bound identifier. The RHS ('res') is right associative - * so it has consumed all other assignment level operations; the - * only relevant lower binding power construct is comma operator - * which will ignore the expression value provided here. Usually - * the top level assignment expression value is ignored, but it - * is relevant for e.g. eval code. - */ - toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */ - comp_ctx->curr_func.led_count == 1); /* one operator (= assign) */ - DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld", - (long) comp_ctx->curr_func.nud_count, - (long) comp_ctx->curr_func.led_count, - (long) toplevel_assign)); - - if (left->t == DUK_IVAL_VAR) { - duk_hstring *h_varname; - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */ - - h_varname = duk_known_hstring(thr, left->x1.valstack_idx); - if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) { - /* E5 Section 11.13.1 (and others for other assignments), step 4. */ - goto syntax_error_lvalue; - } - duk_dup(thr, left->x1.valstack_idx); - (void) duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname); - - if (args_op == DUK_OP_NONE) { - duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/); - if (toplevel_assign) { - /* Any 'res' will do. */ - DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is")); - } else { - /* 'res' must be a plain ivalue, and not register-bound variable. */ - DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier")); - if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST && - DUK__ISREG_NOTTEMP(comp_ctx, res->x1.regconst))) { - duk__ivalue_totempconst(comp_ctx, res); - } - } - } else { - /* For X = Y we need to evaluate the pre-op - * value of X before evaluating the RHS: the RHS - * can change X, but when we do we must use - * the pre-op value. - */ - duk_regconst_t reg_temp; - - reg_temp = DUK__ALLOCTEMP(comp_ctx); - - if (reg_varbind >= 0) { - duk_regconst_t reg_res; - duk_regconst_t reg_src; - duk_int_t pc_temp_load; - duk_int_t pc_before_rhs; - duk_int_t pc_after_rhs; - - if (toplevel_assign) { - /* 'reg_varbind' is the operation result and can also - * become the expression value for top level assignments - * such as: "var x; x += y;". - */ - DUK_DD(DUK_DDPRINT("= expression is top level, write directly to reg_varbind")); - reg_res = reg_varbind; - } else { - /* Not safe to use 'reg_varbind' as assignment expression - * value, so go through a temp. - */ - DUK_DD(DUK_DDPRINT("= expression is not top level, write to reg_temp")); - reg_res = reg_temp; /* reg_res should be smallest possible */ - reg_temp = DUK__ALLOCTEMP(comp_ctx); - } - - /* Try to optimize X = Y for reg-bound - * variables. Detect side-effect free RHS - * narrowly by seeing whether it emits code. - * If not, rewind the code emitter and overwrite - * the unnecessary temp reg load. - */ - - pc_temp_load = duk__get_current_pc(comp_ctx); - duk__emit_a_bc(comp_ctx, - DUK_OP_LDREG, - reg_temp, - reg_varbind); - - pc_before_rhs = duk__get_current_pc(comp_ctx); - duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); - DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); - pc_after_rhs = duk__get_current_pc(comp_ctx); - - DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld", - (long) pc_temp_load, (long) pc_before_rhs, - (long) pc_after_rhs)); - - if (pc_after_rhs == pc_before_rhs) { - /* Note: if the reg_temp load generated shuffling - * instructions, we may need to rewind more than - * one instruction, so use explicit PC computation. - */ - DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based =")); - DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (duk_size_t) (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr)); - reg_src = reg_varbind; - } else { - DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS")); - reg_src = reg_temp; - } - - duk__emit_a_b_c(comp_ctx, - args_op | DUK__EMIT_FLAG_BC_REGCONST, - reg_res, - reg_src, - res->x1.regconst); - - res->x1.regconst = reg_res; - - /* Ensure compact use of temps. */ - if (DUK__ISREG_TEMP(comp_ctx, reg_res)) { - DUK__SETTEMP(comp_ctx, reg_res + 1); - } - } else { - /* When LHS is not register bound, always go through a - * temporary. No optimization for top level assignment. - */ - - duk__emit_a_bc(comp_ctx, - DUK_OP_GETVAR, - reg_temp, - rc_varname); - - duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); - DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); - - duk__emit_a_b_c(comp_ctx, - args_op | DUK__EMIT_FLAG_BC_REGCONST, - reg_temp, - reg_temp, - res->x1.regconst); - res->x1.regconst = reg_temp; - } - - DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); - } - - /* At this point 'res' holds the potential expression value. - * It can be basically any ivalue here, including a reg-bound - * identifier (if code above deems it safe) or a unary/binary - * operation. Operations must be resolved to a side effect free - * plain value, and the side effects must happen exactly once. - */ - - if (reg_varbind >= 0) { - if (res->t != DUK_IVAL_PLAIN) { - /* Resolve 'res' directly into the LHS binding, and use - * that as the expression value if safe. If not safe, - * resolve to a temp/const and copy to LHS. - */ - if (toplevel_assign) { - duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind); - } else { - duk__ivalue_totempconst(comp_ctx, res); - duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */ - duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind); - } - } else { - /* Use 'res' as the expression value (it's side effect - * free and may be a plain value, a register, or a - * constant) and write it to the LHS binding too. - */ - duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */ - duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind); - } - } else { - /* Only a reg fits into 'A' so coerce 'res' into a register - * for PUTVAR. - * - * XXX: here the current A/B/C split is suboptimal: we could - * just use 9 bits for reg_res (and support constants) and 17 - * instead of 18 bits for the varname const index. - */ - - duk__ivalue_toreg(comp_ctx, res); - duk__emit_a_bc(comp_ctx, - DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, - res->x1.regconst, - rc_varname); - } - - /* 'res' contains expression value */ - } else if (left->t == DUK_IVAL_PROP) { - /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */ - duk_regconst_t reg_obj; - duk_regconst_t rc_key; - duk_regconst_t rc_res; - duk_regconst_t reg_temp; - - /* Property access expressions ('a[b]') are critical to correct - * LHS evaluation ordering, see test-dev-assign-eval-order*.js. - * We must make sure that the LHS target slot (base object and - * key) don't change during RHS evaluation. The only concrete - * problem is a register reference to a variable-bound register - * (i.e., non-temp). Require temp regs for both key and base. - * - * Don't allow a constant for the object (even for a number - * etc), as it goes into the 'A' field of the opcode. - */ - - reg_obj = duk__ispec_toregconst_raw(comp_ctx, - &left->x1, - -1 /*forced_reg*/, - DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/); - - rc_key = duk__ispec_toregconst_raw(comp_ctx, - &left->x2, - -1 /*forced_reg*/, - DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); - - /* Evaluate RHS only when LHS is safe. */ - - if (args_op == DUK_OP_NONE) { - duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); - DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); - rc_res = res->x1.regconst; - } else { - reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk__emit_a_b_c(comp_ctx, - DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST, - reg_temp, - reg_obj, - rc_key); - - duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); - DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); - - duk__emit_a_b_c(comp_ctx, - args_op | DUK__EMIT_FLAG_BC_REGCONST, - reg_temp, - reg_temp, - res->x1.regconst); - rc_res = reg_temp; - } - - duk__emit_a_b_c(comp_ctx, - DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST, - reg_obj, - rc_key, - rc_res); - - duk__ivalue_regconst(res, rc_res); - } else { - /* No support for lvalues returned from new or function call expressions. - * However, these must NOT cause compile-time SyntaxErrors, but run-time - * ReferenceErrors. Both left and right sides of the assignment must be - * evaluated before throwing a ReferenceError. For instance: - * - * f() = g(); - * - * must result in f() being evaluated, then g() being evaluated, and - * finally, a ReferenceError being thrown. See E5 Section 11.13.1. - */ - - duk_regconst_t rc_res; - - /* First evaluate LHS fully to ensure all side effects are out. */ - duk__ivalue_toplain_ignore(comp_ctx, left); - - /* Then evaluate RHS fully (its value becomes the expression value too). - * Technically we'd need the side effect safety check here too, but because - * we always throw using INVLHS the result doesn't matter. - */ - rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); - - duk__emit_op_only(comp_ctx, DUK_OP_INVLHS); - - duk__ivalue_regconst(res, rc_res); - } - - return; - } - - postincdec: - { - /* - * Post-increment/decrement will return the original value as its - * result value. However, even that value will be coerced using - * ToNumber() which is quite awkward. Specific bytecode opcodes - * are used to handle these semantics. - * - * Note that post increment/decrement has a "no LineTerminator here" - * restriction. This is handled by duk__expr_lbp(), which forcibly terminates - * the previous expression if a LineTerminator occurs before '++'/'--'. - */ - - duk_regconst_t reg_res; - duk_small_uint_t args_op1 = (args >> 8) & 0xff; /* DUK_OP_POSTINCR/DUK_OP_POSTDECR */ - duk_small_uint_t args_op2 = args >> 16; /* DUK_OP_POSTINCP_RR/DUK_OP_POSTDECP_RR */ - - /* Specific assumptions for opcode numbering. */ - DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV); - DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV); - - reg_res = DUK__ALLOCTEMP(comp_ctx); - - if (left->t == DUK_IVAL_VAR) { - duk_hstring *h_varname; - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - h_varname = duk_known_hstring(thr, left->x1.valstack_idx); - - if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) { - goto syntax_error; - } - - duk_dup(thr, left->x1.valstack_idx); - if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { - duk__emit_a_bc(comp_ctx, - args_op1, /* e.g. DUK_OP_POSTINCR */ - reg_res, - reg_varbind); - } else { - duk__emit_a_bc(comp_ctx, - args_op1 + 4, /* e.g. DUK_OP_POSTINCV */ - reg_res, - rc_varname); - } - - DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld", - (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname)); - } else if (left->t == DUK_IVAL_PROP) { - duk_regconst_t reg_obj; /* allocate to reg only (not const) */ - duk_regconst_t rc_key; - - reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ - rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); - duk__emit_a_b_c(comp_ctx, - args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_POSTINCP */ - reg_res, - reg_obj, - rc_key); - } else { - /* Technically return value is not needed because INVLHS will - * unconditially throw a ReferenceError. Coercion is necessary - * for proper semantics (consider ToNumber() called for an object). - * Use DUK_OP_UNP with a dummy register to get ToNumber(). - */ - duk__ivalue_toforcedreg(comp_ctx, left, reg_res); - duk__emit_bc(comp_ctx, - DUK_OP_UNP, - reg_res); /* for side effects, result ignored */ - duk__emit_op_only(comp_ctx, - DUK_OP_INVLHS); - } - - DUK__SETTEMP(comp_ctx, reg_res + 1); - duk__ivalue_regconst(res, reg_res); - return; - } - - syntax_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION); - return; - - syntax_error_lvalue: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE); - return; -} - -DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) { - duk_small_uint_t tok = comp_ctx->curr_token.t; - - DUK_ASSERT_DISABLE(tok >= DUK_TOK_MINVAL); /* unsigned */ - DUK_ASSERT(tok <= DUK_TOK_MAXVAL); - DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1); - - /* XXX: integrate support for this into led() instead? - * Similar issue as post-increment/post-decrement. - */ - - /* prevent duk__expr_led() by using a binding power less than anything valid */ - if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) { - return 0; - } - - if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) && - (comp_ctx->curr_token.lineterm)) { - /* '++' or '--' in a post-increment/decrement position, - * and a LineTerminator occurs between the operator and - * the preceding expression. Force the previous expr - * to terminate, in effect treating e.g. "a,b\n++" as - * "a,b;++" (= SyntaxError). - */ - return 0; - } - - return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]); /* format is bit packed */ -} - -/* - * Expression parsing. - * - * Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the - * first token of the expression. Upon exit, 'curr_tok' will be the first - * token not part of the expression (e.g. semicolon terminating an expression - * statement). - */ - -#define DUK__EXPR_RBP_MASK 0xff -#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */ -#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */ -#define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */ - -/* main expression parser function */ -DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk_hthread *thr = comp_ctx->thr; - duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */ - duk_ivalue *tmp = &tmp_alloc; - duk_small_uint_t rbp; - - DUK__RECURSION_INCREASE(comp_ctx, thr); - - duk_require_stack(thr, DUK__PARSE_EXPR_SLOTS); - - /* filter out flags from exprtop rbp_flags here to save space */ - rbp = rbp_flags & DUK__EXPR_RBP_MASK; - - DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld", - (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in, - (long) comp_ctx->curr_func.paren_level)); - - DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc)); - tmp->x1.valstack_idx = duk_get_top(thr); - tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1; - duk_push_undefined(thr); - duk_push_undefined(thr); - - /* XXX: where to release temp regs in intermediate expressions? - * e.g. 1+2+3 -> don't inflate temp register count when parsing this. - * that particular expression temp regs can be forced here. - */ - - /* XXX: increase ctx->expr_tokens here for every consumed token - * (this would be a nice statistic)? - */ - - if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) { - /* XXX: possibly incorrect handling of empty expression */ - DUK_DDD(DUK_DDDPRINT("empty expression")); - if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) { - DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED); - } - duk_push_undefined(thr); - duk__ivalue_plain_fromstack(comp_ctx, res); - goto cleanup; - } - - duk__advance(comp_ctx); - duk__expr_nud(comp_ctx, res); /* reuse 'res' as 'left' */ - while (rbp < duk__expr_lbp(comp_ctx)) { - duk__advance(comp_ctx); - duk__expr_led(comp_ctx, res, tmp); - duk__copy_ivalue(comp_ctx, tmp, res); /* tmp -> res */ - } - - cleanup: - /* final result is already in 'res' */ - - duk_pop_2(thr); - - DUK__RECURSION_DECREASE(comp_ctx, thr); -} - -DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk_hthread *thr = comp_ctx->thr; - - /* Note: these variables must reside in 'curr_func' instead of the global - * context: when parsing function expressions, expression parsing is nested. - */ - comp_ctx->curr_func.nud_count = 0; - comp_ctx->curr_func.led_count = 0; - comp_ctx->curr_func.paren_level = 0; - comp_ctx->curr_func.expr_lhs = 1; - comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1); - - duk__expr(comp_ctx, res, rbp_flags); - - if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) { - DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED); - } -} - -/* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop() - * and result conversions. - * - * Each helper needs at least 2-3 calls to make it worth while to wrap. - */ - -#if 0 /* unused */ -DUK_LOCAL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__expr(comp_ctx, res, rbp_flags); - return duk__ivalue_toreg(comp_ctx, res); -} -#endif - -#if 0 /* unused */ -DUK_LOCAL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__expr(comp_ctx, res, rbp_flags); - return duk__ivalue_totemp(comp_ctx, res); -} -#endif - -DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) { - DUK_ASSERT(forced_reg >= 0); - duk__expr(comp_ctx, res, rbp_flags); - duk__ivalue_toforcedreg(comp_ctx, res, forced_reg); -} - -DUK_LOCAL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__expr(comp_ctx, res, rbp_flags); - return duk__ivalue_toregconst(comp_ctx, res); -} - -#if 0 /* unused */ -DUK_LOCAL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__expr(comp_ctx, res, rbp_flags); - return duk__ivalue_totempconst(comp_ctx, res); -} -#endif - -DUK_LOCAL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__expr(comp_ctx, res, rbp_flags); - duk__ivalue_toplain(comp_ctx, res); -} - -DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__expr(comp_ctx, res, rbp_flags); - duk__ivalue_toplain_ignore(comp_ctx, res); -} - -DUK_LOCAL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__exprtop(comp_ctx, res, rbp_flags); - return duk__ivalue_toreg(comp_ctx, res); -} - -#if 0 /* unused */ -DUK_LOCAL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__exprtop(comp_ctx, res, rbp_flags); - return duk__ivalue_totemp(comp_ctx, res); -} -#endif - -DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) { - DUK_ASSERT(forced_reg >= 0); - duk__exprtop(comp_ctx, res, rbp_flags); - duk__ivalue_toforcedreg(comp_ctx, res, forced_reg); -} - -DUK_LOCAL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { - duk__exprtop(comp_ctx, res, rbp_flags); - return duk__ivalue_toregconst(comp_ctx, res); -} - -#if 0 /* unused */ -DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) { - duk__exprtop(comp_ctx, res, rbp_flags); - duk__ivalue_toplain_ignore(comp_ctx, res); -} -#endif - -/* - * Parse an individual source element (top level statement) or a statement. - * - * Handles labeled statements automatically (peeling away labels before - * parsing an expression that follows the label(s)). - * - * Upon entry, 'curr_tok' contains the first token of the statement (parsed - * in "allow regexp literal" mode). Upon exit, 'curr_tok' contains the first - * token following the statement (if the statement has a terminator, this is - * the token after the terminator). - */ - -#define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */ -#define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */ -#define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */ -#define DUK__STILL_PROLOGUE (1 << 3) /* statement does not terminate directive prologue */ -#define DUK__IS_TERMINAL (1 << 4) /* statement is guaranteed to be terminal (control doesn't flow to next statement) */ - -/* Parse a single variable declaration (e.g. "i" or "i=10"). A leading 'var' - * has already been eaten. These is no return value in 'res', it is used only - * as a temporary. - * - * When called from 'for-in' statement parser, the initializer expression must - * not allow the 'in' token. The caller supply additional expression parsing - * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'. - * - * Finally, out_rc_varname and out_reg_varbind are updated to reflect where - * the identifier is bound: - * - * If register bound: out_reg_varbind >= 0, out_rc_varname == 0 (ignore) - * If not register bound: out_reg_varbind < 0, out_rc_varname >= 0 - * - * These allow the caller to use the variable for further assignment, e.g. - * as is done in 'for-in' parsing. - */ - -DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) { - duk_hthread *thr = comp_ctx->thr; - duk_hstring *h_varname; - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - /* assume 'var' has been eaten */ - - /* Note: Identifier rejects reserved words */ - if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) { - goto syntax_error; - } - h_varname = comp_ctx->curr_token.str1; - - DUK_ASSERT(h_varname != NULL); - - /* strict mode restrictions (E5 Section 12.2.1) */ - if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) { - goto syntax_error; - } - - /* register declarations in first pass */ - if (comp_ctx->curr_func.in_scanning) { - duk_uarridx_t n; - DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1", - (duk_heaphdr *) h_varname)); - n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx); - duk_push_hstring(thr, h_varname); - duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n); - duk_push_int(thr, DUK_DECL_TYPE_VAR + (0 << 8)); - duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1); - } - - duk_push_hstring(thr, h_varname); /* push before advancing to keep reachable */ - - /* register binding lookup is based on varmap (even in first pass) */ - duk_dup_top(thr); - (void) duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname); - - duk__advance(comp_ctx); /* eat identifier */ - - if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) { - duk__advance(comp_ctx); - - DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld", - (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname)); - - duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/); /* AssignmentExpression */ - - if (reg_varbind >= 0) { - duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind); - } else { - duk_regconst_t reg_val; - reg_val = duk__ivalue_toreg(comp_ctx, res); - duk__emit_a_bc(comp_ctx, - DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, - reg_val, - rc_varname); - } - } else { - if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) { - /* Used for minimal 'const': initializer required. */ - goto syntax_error; - } - } - - duk_pop(thr); /* pop varname */ - - *out_rc_varname = rc_varname; - *out_reg_varbind = reg_varbind; - - return; - - syntax_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION); -} - -DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) { - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - duk__advance(comp_ctx); /* eat 'var' */ - - for (;;) { - /* rc_varname and reg_varbind are ignored here */ - duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, ®_varbind, &rc_varname); - - if (comp_ctx->curr_token.t != DUK_TOK_COMMA) { - break; - } - duk__advance(comp_ctx); - } -} - -DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { - duk_hthread *thr = comp_ctx->thr; - duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */ - duk_regconst_t temp_reset; /* knock back "next temp" to this whenever possible */ - duk_regconst_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */ - - DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement")); - - /* Two temporaries are preallocated here for variants 3 and 4 which need - * registers which are never clobbered by expressions in the loop - * (concretely: for the enumerator object and the next enumerated value). - * Variants 1 and 2 "release" these temps. - */ - - reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2); - - temp_reset = DUK__GETTEMP(comp_ctx); - - /* - * For/for-in main variants are: - * - * 1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement - * 2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement - * 3. for (LeftHandSideExpression in Expression) Statement - * 4. for (var VariableDeclarationNoIn in Expression) Statement - * - * Parsing these without arbitrary lookahead or backtracking is relatively - * tricky but we manage to do so for now. - * - * See doc/compiler.rst for a detailed discussion of control flow - * issues, evaluation order issues, etc. - */ - - duk__advance(comp_ctx); /* eat 'for' */ - duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); - - DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx))); - - /* a label site has been emitted by duk__parse_stmt() automatically - * (it will also emit the ENDLABEL). - */ - - if (comp_ctx->curr_token.t == DUK_TOK_VAR) { - /* - * Variant 2 or 4 - */ - - duk_regconst_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */ - duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */ - - duk__advance(comp_ctx); /* eat 'var' */ - duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, ®_varbind, &rc_varname); - DUK__SETTEMP(comp_ctx, temp_reset); - - if (comp_ctx->curr_token.t == DUK_TOK_IN) { - /* - * Variant 4 - */ - - DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement")); - pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here */ - if (reg_varbind >= 0) { - duk__emit_a_bc(comp_ctx, - DUK_OP_LDREG, - reg_varbind, - reg_temps + 0); - } else { - duk__emit_a_bc(comp_ctx, - DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, - reg_temps + 0, - rc_varname); - } - goto parse_3_or_4; - } else { - /* - * Variant 2 - */ - - DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement")); - for (;;) { - /* more initializers */ - if (comp_ctx->curr_token.t != DUK_TOK_COMMA) { - break; - } - DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer")); - - duk__advance(comp_ctx); /* eat comma */ - duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, ®_varbind, &rc_varname); - } - goto parse_1_or_2; - } - } else { - /* - * Variant 1 or 3 - */ - - pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here (variant 3) */ - - /* Note that duk__exprtop() here can clobber any reg above current temp_next, - * so any loop variables (e.g. enumerator) must be "preallocated". - */ - - /* don't coerce yet to a plain value (variant 3 needs special handling) */ - duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression */ - if (comp_ctx->curr_token.t == DUK_TOK_IN) { - /* - * Variant 3 - */ - - /* XXX: need to determine LHS type, and check that it is LHS compatible */ - DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement")); - if (duk__expr_is_empty(comp_ctx)) { - goto syntax_error; /* LeftHandSideExpression does not allow empty expression */ - } - - if (res->t == DUK_IVAL_VAR) { - duk_regconst_t reg_varbind; - duk_regconst_t rc_varname; - - duk_dup(thr, res->x1.valstack_idx); - if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { - duk__emit_a_bc(comp_ctx, - DUK_OP_LDREG, - reg_varbind, - reg_temps + 0); - } else { - duk__emit_a_bc(comp_ctx, - DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, - reg_temps + 0, - rc_varname); - } - } else if (res->t == DUK_IVAL_PROP) { - /* Don't allow a constant for the object (even for a number etc), as - * it goes into the 'A' field of the opcode. - */ - duk_regconst_t reg_obj; - duk_regconst_t rc_key; - reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ - rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); - duk__emit_a_b_c(comp_ctx, - DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST, - reg_obj, - rc_key, - reg_temps + 0); - } else { - duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */ - duk__emit_op_only(comp_ctx, - DUK_OP_INVLHS); - } - goto parse_3_or_4; - } else { - /* - * Variant 1 - */ - - DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement")); - duk__ivalue_toplain_ignore(comp_ctx, res); - goto parse_1_or_2; - } - } - - parse_1_or_2: - /* - * Parse variant 1 or 2. The first part expression (which differs - * in the variants) has already been parsed and its code emitted. - * - * reg_temps + 0: unused - * reg_temps + 1: unused - */ - { - duk_regconst_t rc_cond; - duk_int_t pc_l1, pc_l2, pc_l3, pc_l4; - duk_int_t pc_jumpto_l3, pc_jumpto_l4; - duk_bool_t expr_c_empty; - - DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2")); - - /* "release" preallocated temps since we won't need them */ - temp_reset = reg_temps + 0; - DUK__SETTEMP(comp_ctx, temp_reset); - - duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON); - - pc_l1 = duk__get_current_pc(comp_ctx); - duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */ - if (duk__expr_is_empty(comp_ctx)) { - /* no need to coerce */ - pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */ - pc_jumpto_l4 = -1; /* omitted */ - } else { - rc_cond = duk__ivalue_toregconst(comp_ctx, res); - duk__emit_if_false_skip(comp_ctx, rc_cond); - pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */ - pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); /* to exit */ - } - DUK__SETTEMP(comp_ctx, temp_reset); - - duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON); - - pc_l2 = duk__get_current_pc(comp_ctx); - duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */ - if (duk__expr_is_empty(comp_ctx)) { - /* no need to coerce */ - expr_c_empty = 1; - /* JUMP L1 omitted */ - } else { - duk__ivalue_toplain_ignore(comp_ctx, res); - expr_c_empty = 0; - duk__emit_jump(comp_ctx, pc_l1); - } - DUK__SETTEMP(comp_ctx, temp_reset); - - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - - pc_l3 = duk__get_current_pc(comp_ctx); - duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - if (expr_c_empty) { - duk__emit_jump(comp_ctx, pc_l1); - } else { - duk__emit_jump(comp_ctx, pc_l2); - } - /* temp reset is not necessary after duk__parse_stmt(), which already does it */ - - pc_l4 = duk__get_current_pc(comp_ctx); - - DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, " - "break: %ld->%ld, continue: %ld->%ld", - (long) pc_jumpto_l3, (long) pc_l3, (long) pc_jumpto_l4, (long) pc_l4, - (long) (pc_label_site + 1), (long) pc_l4, (long) (pc_label_site + 2), (long) pc_l2)); - - duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3); - duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4); - duk__patch_jump(comp_ctx, - pc_label_site + 1, - pc_l4); /* break jump */ - duk__patch_jump(comp_ctx, - pc_label_site + 2, - expr_c_empty ? pc_l1 : pc_l2); /* continue jump */ - } - goto finished; - - parse_3_or_4: - /* - * Parse variant 3 or 4. - * - * For variant 3 (e.g. "for (A in C) D;") the code for A (except the - * final property/variable write) has already been emitted. The first - * instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted - * there to satisfy control flow needs. - * - * For variant 4, if the variable declaration had an initializer - * (e.g. "for (var A = B in C) D;") the code for the assignment - * (B) has already been emitted. - * - * Variables set before entering here: - * - * pc_v34_lhs: insert a "JUMP L2" here (see doc/compiler.rst example). - * reg_temps + 0: iteration target value (written to LHS) - * reg_temps + 1: enumerator object - */ - { - duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5; - duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5; - duk_regconst_t reg_target; - - DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs)); - - DUK__SETTEMP(comp_ctx, temp_reset); - - /* First we need to insert a jump in the middle of previously - * emitted code to get the control flow right. No jumps can - * cross the position where the jump is inserted. See doc/compiler.rst - * for discussion on the intricacies of control flow and side effects - * for variants 3 and 4. - */ - - duk__insert_jump_entry(comp_ctx, pc_v34_lhs); - pc_jumpto_l2 = pc_v34_lhs; /* inserted jump */ - pc_l1 = pc_v34_lhs + 1; /* +1, right after inserted jump */ - - /* The code for writing reg_temps + 0 to the left hand side has already - * been emitted. - */ - - pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* -> loop body */ - - duk__advance(comp_ctx); /* eat 'in' */ - - /* Parse enumeration target and initialize enumerator. For 'null' and 'undefined', - * INITENUM will creates a 'null' enumerator which works like an empty enumerator - * (E5 Section 12.6.4, step 3). Note that INITENUM requires the value to be in a - * register (constant not allowed). - */ - - pc_l2 = duk__get_current_pc(comp_ctx); - reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */ - duk__emit_b_c(comp_ctx, - DUK_OP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET, - reg_temps + 1, - reg_target); - pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); - DUK__SETTEMP(comp_ctx, temp_reset); - - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - - pc_l3 = duk__get_current_pc(comp_ctx); - duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - /* temp reset is not necessary after duk__parse_stmt(), which already does it */ - - /* NEXTENUM needs a jump slot right after the main opcode. - * We need the code emitter to reserve the slot: if there's - * target shuffling, the target shuffle opcodes must happen - * after the jump slot (for NEXTENUM the shuffle opcodes are - * not needed if the enum is finished). - */ - pc_l4 = duk__get_current_pc(comp_ctx); - duk__emit_b_c(comp_ctx, - DUK_OP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT, - reg_temps + 0, - reg_temps + 1); - pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */ - duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */ - - pc_l5 = duk__get_current_pc(comp_ctx); - - /* XXX: since the enumerator may be a memory expensive object, - * perhaps clear it explicitly here? If so, break jump must - * go through this clearing operation. - */ - - DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, " - "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, " - "break: %ld->%ld, continue: %ld->%ld", - (long) pc_jumpto_l2, (long) pc_l2, (long) pc_jumpto_l3, (long) pc_l3, - (long) pc_jumpto_l4, (long) pc_l4, (long) pc_jumpto_l5, (long) pc_l5, - (long) (pc_label_site + 1), (long) pc_l5, (long) (pc_label_site + 2), (long) pc_l4)); - - duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2); - duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3); - duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4); - duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5); - duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5); /* break jump */ - duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4); /* continue jump */ - } - goto finished; - - finished: - DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement")); - return; - - syntax_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR); -} - -DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { - duk_hthread *thr = comp_ctx->thr; - duk_regconst_t temp_at_loop; - duk_regconst_t rc_switch; /* reg/const for switch value */ - duk_regconst_t rc_case; /* reg/const for case value */ - duk_regconst_t reg_temp; /* general temp register */ - duk_int_t pc_prevcase = -1; - duk_int_t pc_prevstmt = -1; - duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */ - - /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */ - - /* - * Switch is pretty complicated because of several conflicting concerns: - * - * - Want to generate code without an intermediate representation, - * i.e., in one go - * - * - Case selectors are expressions, not values, and may thus e.g. throw - * exceptions (which causes evaluation order concerns) - * - * - Evaluation semantics of case selectors and default clause need to be - * carefully implemented to provide correct behavior even with case value - * side effects - * - * - Fall through case and default clauses; avoiding dead JUMPs if case - * ends with an unconditional jump (a break or a continue) - * - * - The same case value may occur multiple times, but evaluation rules - * only process the first match before switching to a "propagation" mode - * where case values are no longer evaluated - * - * See E5 Section 12.11. Also see doc/compiler.rst for compilation - * discussion. - */ - - duk__advance(comp_ctx); - duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); - rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); - - DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch)); - - temp_at_loop = DUK__GETTEMP(comp_ctx); - - for (;;) { - duk_int_t num_stmts; - duk_small_uint_t tok; - - /* sufficient for keeping temp reg numbers in check */ - DUK__SETTEMP(comp_ctx, temp_at_loop); - - if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) { - break; - } - - /* - * Parse a case or default clause. - */ - - if (comp_ctx->curr_token.t == DUK_TOK_CASE) { - /* - * Case clause. - * - * Note: cannot use reg_case as a temp register (for SEQ target) - * because it may be a constant. - */ - - duk__patch_jump_here(comp_ctx, pc_prevcase); /* chain jumps for case - * evaluation and checking - */ - - duk__advance(comp_ctx); - rc_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - duk__advance_expect(comp_ctx, DUK_TOK_COLON); - - reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk__emit_a_b_c(comp_ctx, - DUK_OP_SEQ | DUK__EMIT_FLAG_BC_REGCONST, - reg_temp, - rc_switch, - rc_case); - duk__emit_if_true_skip(comp_ctx, reg_temp); - - /* jump to next case clause */ - pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */ - - /* statements go here (if any) on next loop */ - } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) { - /* - * Default clause. - */ - - if (pc_default >= 0) { - goto syntax_error; - } - duk__advance(comp_ctx); - duk__advance_expect(comp_ctx, DUK_TOK_COLON); - - /* Fix for https://github.com/svaarala/duktape/issues/155: - * If 'default' is first clause (detected by pc_prevcase < 0) - * we need to ensure we stay in the matching chain. - */ - if (pc_prevcase < 0) { - DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump")); - pc_prevcase = duk__emit_jump_empty(comp_ctx); - } - - /* default clause matches next statement list (if any) */ - pc_default = -2; - } else { - /* Code is not accepted before the first case/default clause */ - goto syntax_error; - } - - /* - * Parse code after the clause. Possible terminators are - * 'case', 'default', and '}'. - * - * Note that there may be no code at all, not even an empty statement, - * between case clauses. This must be handled just like an empty statement - * (omitting seemingly pointless JUMPs), to avoid situations like - * test-bug-case-fallthrough.js. - */ - - num_stmts = 0; - if (pc_default == -2) { - pc_default = duk__get_current_pc(comp_ctx); - } - - /* Note: this is correct even for default clause statements: - * they participate in 'fall-through' behavior even if the - * default clause is in the middle. - */ - duk__patch_jump_here(comp_ctx, pc_prevstmt); /* chain jumps for 'fall-through' - * after a case matches. - */ - - for (;;) { - tok = comp_ctx->curr_token.t; - if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT || - tok == DUK_TOK_RCURLY) { - break; - } - num_stmts++; - duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - } - - /* fall-through jump to next code of next case (backpatched) */ - pc_prevstmt = duk__emit_jump_empty(comp_ctx); - - /* XXX: would be nice to omit this jump when the jump is not - * reachable, at least in the obvious cases (such as the case - * ending with a 'break'. - * - * Perhaps duk__parse_stmt() could provide some info on whether - * the statement is a "dead end"? - * - * If implemented, just set pc_prevstmt to -1 when not needed. - */ - } - - DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY); - duk__advance(comp_ctx); - - /* default case control flow patchup; note that if pc_prevcase < 0 - * (i.e. no case clauses), control enters default case automatically. - */ - if (pc_default >= 0) { - /* default case exists: go there if no case matches */ - duk__patch_jump(comp_ctx, pc_prevcase, pc_default); - } else { - /* default case does not exist, or no statements present - * after default case: finish case evaluation - */ - duk__patch_jump_here(comp_ctx, pc_prevcase); - } - - /* fall-through control flow patchup; note that pc_prevstmt may be - * < 0 (i.e. no case clauses), in which case this is a no-op. - */ - duk__patch_jump_here(comp_ctx, pc_prevstmt); - - /* continue jump not patched, an INVALID opcode remains there */ - duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */ - - /* Note: 'fast' breaks will jump to pc_label_site + 1, which will - * then jump here. The double jump will be eliminated by a - * peephole pass, resulting in an optimal jump here. The label - * site jumps will remain in bytecode and will waste code size. - */ - - return; - - syntax_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH); -} - -DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_regconst_t temp_reset; - duk_regconst_t rc_cond; - duk_int_t pc_jump_false; - - DUK_DDD(DUK_DDDPRINT("begin parsing if statement")); - - temp_reset = DUK__GETTEMP(comp_ctx); - - duk__advance(comp_ctx); /* eat 'if' */ - duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); - - rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - duk__emit_if_true_skip(comp_ctx, rc_cond); - pc_jump_false = duk__emit_jump_empty(comp_ctx); /* jump to end or else part */ - DUK__SETTEMP(comp_ctx, temp_reset); - - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - - duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - - /* The 'else' ambiguity is resolved by 'else' binding to the innermost - * construct, so greedy matching is correct here. - */ - - if (comp_ctx->curr_token.t == DUK_TOK_ELSE) { - duk_int_t pc_jump_end; - - DUK_DDD(DUK_DDDPRINT("if has else part")); - - duk__advance(comp_ctx); - - pc_jump_end = duk__emit_jump_empty(comp_ctx); /* jump from true part to end */ - duk__patch_jump_here(comp_ctx, pc_jump_false); - - duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - - duk__patch_jump_here(comp_ctx, pc_jump_end); - } else { - DUK_DDD(DUK_DDDPRINT("if does not have else part")); - - duk__patch_jump_here(comp_ctx, pc_jump_false); - } - - DUK_DDD(DUK_DDDPRINT("end parsing if statement")); -} - -DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { - duk_regconst_t rc_cond; - duk_int_t pc_start; - - DUK_DDD(DUK_DDDPRINT("begin parsing do statement")); - - duk__advance(comp_ctx); /* eat 'do' */ - - pc_start = duk__get_current_pc(comp_ctx); - duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */ - - duk__advance_expect(comp_ctx, DUK_TOK_WHILE); - duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); - - rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - duk__emit_if_false_skip(comp_ctx, rc_cond); - duk__emit_jump(comp_ctx, pc_start); - /* no need to reset temps, as we're finished emitting code */ - - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - - duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */ - - DUK_DDD(DUK_DDDPRINT("end parsing do statement")); -} - -DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { - duk_regconst_t temp_reset; - duk_regconst_t rc_cond; - duk_int_t pc_start; - duk_int_t pc_jump_false; - - DUK_DDD(DUK_DDDPRINT("begin parsing while statement")); - - temp_reset = DUK__GETTEMP(comp_ctx); - - duk__advance(comp_ctx); /* eat 'while' */ - - duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); - - pc_start = duk__get_current_pc(comp_ctx); - duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */ - - rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - duk__emit_if_true_skip(comp_ctx, rc_cond); - pc_jump_false = duk__emit_jump_empty(comp_ctx); - DUK__SETTEMP(comp_ctx, temp_reset); - - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - - duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - duk__emit_jump(comp_ctx, pc_start); - - duk__patch_jump_here(comp_ctx, pc_jump_false); - duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */ - - DUK_DDD(DUK_DDDPRINT("end parsing while statement")); -} - -DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_hthread *thr = comp_ctx->thr; - duk_bool_t is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK); - duk_int_t label_id; - duk_int_t label_catch_depth; - duk_int_t label_pc; /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */ - duk_bool_t label_is_closest; - - DUK_UNREF(res); - - duk__advance(comp_ctx); /* eat 'break' or 'continue' */ - - if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */ - comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */ - comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */ - /* break/continue without label */ - - duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest); - } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) { - /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */ - DUK_ASSERT(comp_ctx->curr_token.str1 != NULL); - duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest); - duk__advance(comp_ctx); - } else { - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL); - } - - /* Use a fast break/continue when possible. A fast break/continue is - * just a jump to the LABEL break/continue jump slot, which then jumps - * to an appropriate place (for break, going through ENDLABEL correctly). - * The peephole optimizer will optimize the jump to a direct one. - */ - - if (label_catch_depth == comp_ctx->curr_func.catch_depth && - label_is_closest) { - DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, " - "label_catch_depth=%ld, catch_depth=%ld " - "-> use fast variant (direct jump)", - (long) is_break, (long) label_id, (long) label_is_closest, - (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth)); - - duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2)); - } else { - DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, " - "label_catch_depth=%ld, catch_depth=%ld " - "-> use slow variant (longjmp)", - (long) is_break, (long) label_id, (long) label_is_closest, - (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth)); - - duk__emit_bc(comp_ctx, - is_break ? DUK_OP_BREAK : DUK_OP_CONTINUE, - (duk_regconst_t) label_id); - } -} - -DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_hthread *thr = comp_ctx->thr; - duk_regconst_t rc_val; - - duk__advance(comp_ctx); /* eat 'return' */ - - /* A 'return' statement is only allowed inside an actual function body, - * not as part of eval or global code. - */ - if (!comp_ctx->curr_func.is_function) { - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN); - } - - if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */ - comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */ - comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */ - DUK_DDD(DUK_DDDPRINT("empty return value -> undefined")); - duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF); - } else { - duk_int_t pc_before_expr; - duk_int_t pc_after_expr; - - DUK_DDD(DUK_DDDPRINT("return with a value")); - - DUK_UNREF(pc_before_expr); - DUK_UNREF(pc_after_expr); - - pc_before_expr = duk__get_current_pc(comp_ctx); - rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - pc_after_expr = duk__get_current_pc(comp_ctx); - - /* Tail call check: if last opcode emitted was CALL, and - * the context allows it, add a tailcall flag to the CALL. - * This doesn't guarantee that a tail call will be allowed at - * runtime, so the RETURN must still be emitted. (Duktape - * 0.10.0 avoided this and simulated a RETURN if a tail call - * couldn't be used at runtime; but this didn't work - * correctly with a thread yield/resume, see - * test-bug-tailcall-thread-yield-resume.js for discussion.) - * - * In addition to the last opcode being CALL, we also need to - * be sure that 'rc_val' is the result register of the CALL. - * For instance, for the expression 'return 0, (function () - * { return 1; }), 2' the last opcode emitted is CALL (no - * bytecode is emitted for '2') but 'rc_val' indicates - * constant '2'. Similarly if '2' is replaced by a register - * bound variable, no opcodes are emitted but tail call would - * be incorrect. - * - * This is tricky and easy to get wrong. It would be best to - * track enough expression metadata to check that 'rc_val' came - * from that last CALL instruction. We don't have that metadata - * now, so we check that 'rc_val' is a temporary register result - * (not a constant or a register bound variable). There should - * be no way currently for 'rc_val' to be a temporary for an - * expression following the CALL instruction without emitting - * some opcodes following the CALL. This proxy check is used - * below. - * - * See: test-bug-comma-expr-gh131.js. - * - * The non-standard 'caller' property disables tail calls - * because they pose some special cases which haven't been - * fixed yet. - */ - -#if defined(DUK_USE_TAILCALL) - if (comp_ctx->curr_func.catch_depth == 0 && /* no catchers */ - pc_after_expr > pc_before_expr) { /* at least one opcode emitted */ - duk_compiler_instr *instr; - duk_instr_t ins; - duk_small_uint_t op; - - instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1); - DUK_ASSERT(instr != NULL); - - ins = instr->ins; - op = (duk_small_uint_t) DUK_DEC_OP(ins); - if ((op & ~0x0fU) == DUK_OP_CALL0 && - DUK__ISREG_TEMP(comp_ctx, rc_val) /* see above */) { - DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: " - "catch depth is 0, duk__exprtop() emitted >= 1 instructions, " - "and last instruction is a CALL " - "-> change to TAILCALL")); - ins |= DUK_ENC_OP(DUK_BC_CALL_FLAG_TAILCALL); - instr->ins = ins; - } - } -#endif /* DUK_USE_TAILCALL */ - - if (DUK__ISREG(rc_val)) { - duk__emit_bc(comp_ctx, DUK_OP_RETREG, rc_val); - } else { - rc_val = DUK__REMOVECONST(rc_val); - if (duk__const_needs_refcount(comp_ctx, rc_val)) { - duk__emit_bc(comp_ctx, DUK_OP_RETCONST, rc_val); - } else { - duk__emit_bc(comp_ctx, DUK_OP_RETCONSTN, rc_val); - } - } - } -} - -DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_regconst_t reg_val; - - duk__advance(comp_ctx); /* eat 'throw' */ - - /* Unlike break/continue, throw statement does not allow an empty value. */ - - if (comp_ctx->curr_token.lineterm) { - DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW); - } - - reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - duk__emit_bc(comp_ctx, - DUK_OP_THROW, - reg_val); -} - -DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_hthread *thr = comp_ctx->thr; - duk_regconst_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */ - duk_regconst_t rc_varname = 0; - duk_small_uint_t trycatch_flags = 0; - duk_int_t pc_ldconst = -1; - duk_int_t pc_trycatch = -1; - duk_int_t pc_catch = -1; - duk_int_t pc_finally = -1; - - DUK_UNREF(res); - - /* - * See the following documentation for discussion: - * - * doc/execution.rst: control flow details - * - * Try, catch, and finally "parts" are Blocks, not Statements, so - * they must always be delimited by curly braces. This is unlike e.g. - * the if statement, which accepts any Statement. This eliminates any - * questions of matching parts of nested try statements. The Block - * parsing is implemented inline here (instead of calling out). - * - * Finally part has a 'let scoped' variable, which requires a few kinks - * here. - */ - - comp_ctx->curr_func.catch_depth++; - - duk__advance(comp_ctx); /* eat 'try' */ - - reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2); - - /* The target for this LDCONST may need output shuffling, but we assume - * that 'pc_ldconst' will be the LDCONST that we can patch later. This - * should be the case because there's no input shuffling. (If there's - * no catch clause, this LDCONST will be replaced with a NOP.) - */ - pc_ldconst = duk__get_current_pc(comp_ctx); - duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/); - - pc_trycatch = duk__get_current_pc(comp_ctx); - duk__emit_invalid(comp_ctx); /* TRYCATCH, cannot emit now (not enough info) */ - duk__emit_invalid(comp_ctx); /* jump for 'catch' case */ - duk__emit_invalid(comp_ctx); /* jump for 'finally' case or end (if no finally) */ - - /* try part */ - duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); - duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/); - /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ - duk__emit_op_only(comp_ctx, - DUK_OP_ENDTRY); - - if (comp_ctx->curr_token.t == DUK_TOK_CATCH) { - /* - * The catch variable must be updated to reflect the new allocated - * register for the duration of the catch clause. We need to store - * and restore the original value for the varmap entry (if any). - */ - - /* - * Note: currently register bindings must be fixed for the entire - * function. So, even though the catch variable is in a register - * we know, we must use an explicit environment record and slow path - * accesses to read/write the catch binding to make closures created - * within the catch clause work correctly. This restriction should - * be fixable (at least in common cases) later. - * - * See: test-bug-catch-binding-2.js. - * - * XXX: improve to get fast path access to most catch clauses. - */ - - duk_hstring *h_var; - duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */ - - DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(thr))); - - trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH; - - pc_catch = duk__get_current_pc(comp_ctx); - - duk__advance(comp_ctx); - duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); - - if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) { - /* Identifier, i.e. don't allow reserved words */ - goto syntax_error; - } - h_var = comp_ctx->curr_token.str1; - DUK_ASSERT(h_var != NULL); - - duk_push_hstring(thr, h_var); /* keep in on valstack, use borrowed ref below */ - - if (comp_ctx->curr_func.is_strict && - ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) || - (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) { - DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError")); - goto syntax_error; - } - - duk_dup_top(thr); - rc_varname = duk__getconst(comp_ctx); - DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)", - (unsigned long) rc_varname, (long) rc_varname)); - - duk__advance(comp_ctx); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - - duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); - - DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT", - (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx))); - - duk_dup_top(thr); - duk_get_prop(thr, comp_ctx->curr_func.varmap_idx); - if (duk_is_undefined(thr, -1)) { - varmap_value = -2; - } else if (duk_is_null(thr, -1)) { - varmap_value = -1; - } else { - DUK_ASSERT(duk_is_number(thr, -1)); - varmap_value = duk_get_int(thr, -1); - DUK_ASSERT(varmap_value >= 0); - } - duk_pop(thr); - -#if 0 - /* It'd be nice to do something like this - but it doesn't - * work for closures created inside the catch clause. - */ - duk_dup_top(thr); - duk_push_int(thr, (duk_int_t) (reg_catch + 0)); - duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); -#endif - duk_dup_top(thr); - duk_push_null(thr); - duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); - - duk__emit_a_bc(comp_ctx, - DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, - reg_catch + 0 /*value*/, - rc_varname /*varname*/); - - DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT", - (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx))); - - duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/); - /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ - - if (varmap_value == -2) { - /* not present */ - duk_del_prop(thr, comp_ctx->curr_func.varmap_idx); - } else { - if (varmap_value == -1) { - duk_push_null(thr); - } else { - DUK_ASSERT(varmap_value >= 0); - duk_push_int(thr, varmap_value); - } - duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); - } - /* varname is popped by above code */ - - DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT", - (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx))); - - duk__emit_op_only(comp_ctx, - DUK_OP_ENDCATCH); - - /* - * XXX: for now, indicate that an expensive catch binding - * declarative environment is always needed. If we don't - * need it, we don't need the const_varname either. - */ - - trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING; - - DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(thr))); - } - - if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) { - trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY; - - pc_finally = duk__get_current_pc(comp_ctx); - - duk__advance(comp_ctx); - - duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); - duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/); - /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ - duk__emit_abc(comp_ctx, - DUK_OP_ENDFIN, - reg_catch); /* rethrow */ - } - - if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) && - !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) { - /* must have catch and/or finally */ - goto syntax_error; - } - - /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch() - * will replace the LDCONST with a NOP. For any actual constant (including - * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname. - */ - - duk__patch_trycatch(comp_ctx, - pc_ldconst, - pc_trycatch, - reg_catch, - rc_varname, - trycatch_flags); - - if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) { - DUK_ASSERT(pc_catch >= 0); - duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch); - } - - if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) { - DUK_ASSERT(pc_finally >= 0); - duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally); - } else { - /* without finally, the second jump slot is used to jump to end of stmt */ - duk__patch_jump_here(comp_ctx, pc_trycatch + 2); - } - - comp_ctx->curr_func.catch_depth--; - return; - - syntax_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY); -} - -DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { - duk_int_t pc_trycatch; - duk_int_t pc_finished; - duk_regconst_t reg_catch; - duk_small_uint_t trycatch_flags; - - if (comp_ctx->curr_func.is_strict) { - DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE); - } - - comp_ctx->curr_func.catch_depth++; - - duk__advance(comp_ctx); /* eat 'with' */ - - reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2); - - duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); - duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); - - pc_trycatch = duk__get_current_pc(comp_ctx); - trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING; - duk__emit_a_bc(comp_ctx, - DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A, - (duk_regconst_t) trycatch_flags /*a*/, - reg_catch /*bc*/); - duk__emit_invalid(comp_ctx); /* catch jump */ - duk__emit_invalid(comp_ctx); /* finished jump */ - - duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - duk__emit_op_only(comp_ctx, - DUK_OP_ENDTRY); - - pc_finished = duk__get_current_pc(comp_ctx); - - duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished); - - comp_ctx->curr_func.catch_depth--; -} - -DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id) { - /* if a site already exists, nop: max one label site per statement */ - if (label_id >= 0) { - return label_id; - } - - label_id = comp_ctx->curr_func.label_next++; - DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id)); - - duk__emit_bc(comp_ctx, - DUK_OP_LABEL, - (duk_regconst_t) label_id); - duk__emit_invalid(comp_ctx); - duk__emit_invalid(comp_ctx); - - return label_id; -} - -/* Parse a single statement. - * - * Creates a label site (with an empty label) automatically for iteration - * statements. Also "peels off" any label statements for explicit labels. - */ -DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) { - duk_hthread *thr = comp_ctx->thr; - duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */ - duk_regconst_t temp_at_entry; - duk_size_t labels_len_at_entry; - duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */ - duk_int_t stmt_id; - duk_small_uint_t stmt_flags = 0; - duk_int_t label_id = -1; - duk_small_uint_t tok; - duk_bool_t test_func_decl; - - DUK__RECURSION_INCREASE(comp_ctx, thr); - - temp_at_entry = DUK__GETTEMP(comp_ctx); - pc_at_entry = duk__get_current_pc(comp_ctx); - labels_len_at_entry = duk_get_length(thr, comp_ctx->curr_func.labelnames_idx); - stmt_id = comp_ctx->curr_func.stmt_next++; - dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue; - - DUK_UNREF(stmt_id); - - DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, " - "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld", - (long) stmt_id, (long) temp_at_entry, (long) labels_len_at_entry, - (long) comp_ctx->curr_func.is_strict, (long) comp_ctx->curr_func.in_directive_prologue, - (long) comp_ctx->curr_func.catch_depth)); - - /* The directive prologue flag is cleared by default so that it is - * unset for any recursive statement parsing. It is only "revived" - * if a directive is detected. (We could also make directives only - * allowed if 'allow_source_elem' was true.) - */ - comp_ctx->curr_func.in_directive_prologue = 0; - - retry_parse: - - DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld", - (long) stmt_id, (long) label_id, (long) allow_source_elem, - (long) comp_ctx->curr_func.catch_depth)); - - /* - * Detect iteration statements; if encountered, establish an - * empty label. - */ - - tok = comp_ctx->curr_token.t; - if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE || - tok == DUK_TOK_SWITCH) { - DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label")); - - label_id = duk__stmt_label_site(comp_ctx, label_id); - duk__add_label(comp_ctx, - DUK_HTHREAD_STRING_EMPTY_STRING(thr), - pc_at_entry /*pc_label*/, - label_id); - } - - /* - * Main switch for statement / source element type. - */ - - switch (comp_ctx->curr_token.t) { - case DUK_TOK_FUNCTION: { - /* - * Function declaration, function expression, or (non-standard) - * function statement. - * - * The E5 specification only allows function declarations at - * the top level (in "source elements"). An ExpressionStatement - * is explicitly not allowed to begin with a "function" keyword - * (E5 Section 12.4). Hence any non-error semantics for such - * non-top-level statements are non-standard. Duktape semantics - * for function statements are modelled after V8, see - * test-dev-func-decl-outside-top.js. - */ - test_func_decl = allow_source_elem; -#if defined(DUK_USE_NONSTD_FUNC_STMT) - /* Lenient: allow function declarations outside top level in - * non-strict mode but reject them in strict mode. - */ - test_func_decl = test_func_decl || !comp_ctx->curr_func.is_strict; -#endif /* DUK_USE_NONSTD_FUNC_STMT */ - /* Strict: never allow function declarations outside top level. */ - if (test_func_decl) { - /* FunctionDeclaration: not strictly a statement but handled as such. - * - * O(depth^2) parse count for inner functions is handled by recording a - * lexer offset on the first compilation pass, so that the function can - * be efficiently skipped on the second pass. This is encapsulated into - * duk__parse_func_like_fnum(). - */ - - duk_int_t fnum; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t top_before; -#endif - - DUK_DDD(DUK_DDDPRINT("function declaration statement")); - -#if defined(DUK_USE_ASSERTIONS) - top_before = duk_get_top(thr); -#endif - - duk__advance(comp_ctx); /* eat 'function' */ - fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_DECL | DUK__FUNC_FLAG_PUSHNAME_PASS1); - - /* The value stack convention here is a bit odd: the function - * name is only pushed on pass 1 (in_scanning), and is needed - * to process function declarations. - */ - if (comp_ctx->curr_func.in_scanning) { - duk_uarridx_t n; - -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(duk_get_top(thr) == top_before + 1); -#endif - DUK_DDD(DUK_DDDPRINT("register function declaration %!T in pass 1, fnum %ld", - duk_get_tval(thr, -1), (long) fnum)); - n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx); - /* funcname is at index -1 */ - duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n); - duk_push_int(thr, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8))); - duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1); - } else { -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(duk_get_top(thr) == top_before); -#endif - } - - /* no statement value (unlike function expression) */ - stmt_flags = 0; - break; - } else { - DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED); - } - break; - } - case DUK_TOK_LCURLY: { - DUK_DDD(DUK_DDDPRINT("block statement")); - duk__advance(comp_ctx); - duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/); - /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ - if (label_id >= 0) { - duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */ - } - stmt_flags = 0; - break; - } - case DUK_TOK_CONST: { - DUK_DDD(DUK_DDDPRINT("constant declaration statement")); - duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/); - stmt_flags = DUK__HAS_TERM; - break; - } - case DUK_TOK_VAR: { - DUK_DDD(DUK_DDDPRINT("variable declaration statement")); - duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/); - stmt_flags = DUK__HAS_TERM; - break; - } - case DUK_TOK_SEMICOLON: { - /* empty statement with an explicit semicolon */ - DUK_DDD(DUK_DDDPRINT("empty statement")); - stmt_flags = DUK__HAS_TERM; - break; - } - case DUK_TOK_IF: { - DUK_DDD(DUK_DDDPRINT("if statement")); - duk__parse_if_stmt(comp_ctx, res); - if (label_id >= 0) { - duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */ - } - stmt_flags = 0; - break; - } - case DUK_TOK_DO: { - /* - * Do-while statement is mostly trivial, but there is special - * handling for automatic semicolon handling (triggered by the - * DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at: - * - * https://bugs.ecmascript.org/show_bug.cgi?id=8 - * - * See doc/compiler.rst for details. - */ - DUK_DDD(DUK_DDDPRINT("do statement")); - DUK_ASSERT(label_id >= 0); - duk__update_label_flags(comp_ctx, - label_id, - DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE); - duk__parse_do_stmt(comp_ctx, res, pc_at_entry); - stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS; /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */ - break; - } - case DUK_TOK_WHILE: { - DUK_DDD(DUK_DDDPRINT("while statement")); - DUK_ASSERT(label_id >= 0); - duk__update_label_flags(comp_ctx, - label_id, - DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE); - duk__parse_while_stmt(comp_ctx, res, pc_at_entry); - stmt_flags = 0; - break; - } - case DUK_TOK_FOR: { - /* - * For/for-in statement is complicated to parse because - * determining the statement type (three-part for vs. a - * for-in) requires potential backtracking. - * - * See the helper for the messy stuff. - */ - DUK_DDD(DUK_DDDPRINT("for/for-in statement")); - DUK_ASSERT(label_id >= 0); - duk__update_label_flags(comp_ctx, - label_id, - DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE); - duk__parse_for_stmt(comp_ctx, res, pc_at_entry); - stmt_flags = 0; - break; - } - case DUK_TOK_CONTINUE: - case DUK_TOK_BREAK: { - DUK_DDD(DUK_DDDPRINT("break/continue statement")); - duk__parse_break_or_continue_stmt(comp_ctx, res); - stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL; - break; - } - case DUK_TOK_RETURN: { - DUK_DDD(DUK_DDDPRINT("return statement")); - duk__parse_return_stmt(comp_ctx, res); - stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL; - break; - } - case DUK_TOK_WITH: { - DUK_DDD(DUK_DDDPRINT("with statement")); - comp_ctx->curr_func.with_depth++; - duk__parse_with_stmt(comp_ctx, res); - if (label_id >= 0) { - duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */ - } - comp_ctx->curr_func.with_depth--; - stmt_flags = 0; - break; - } - case DUK_TOK_SWITCH: { - /* - * The switch statement is pretty messy to compile. - * See the helper for details. - */ - DUK_DDD(DUK_DDDPRINT("switch statement")); - DUK_ASSERT(label_id >= 0); - duk__update_label_flags(comp_ctx, - label_id, - DUK_LABEL_FLAG_ALLOW_BREAK); /* don't allow continue */ - duk__parse_switch_stmt(comp_ctx, res, pc_at_entry); - stmt_flags = 0; - break; - } - case DUK_TOK_THROW: { - DUK_DDD(DUK_DDDPRINT("throw statement")); - duk__parse_throw_stmt(comp_ctx, res); - stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL; - break; - } - case DUK_TOK_TRY: { - DUK_DDD(DUK_DDDPRINT("try statement")); - duk__parse_try_stmt(comp_ctx, res); - stmt_flags = 0; - break; - } - case DUK_TOK_DEBUGGER: { - duk__advance(comp_ctx); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode")); - duk__emit_op_only(comp_ctx, DUK_OP_DEBUGGER); -#else - DUK_DDD(DUK_DDDPRINT("debugger statement: ignored")); -#endif - stmt_flags = DUK__HAS_TERM; - break; - } - default: { - /* - * Else, must be one of: - * - ExpressionStatement, possibly a directive (String) - * - LabelledStatement (Identifier followed by ':') - * - * Expressions beginning with 'function' keyword are covered by a case - * above (such expressions are not allowed in standard E5 anyway). - * Also expressions starting with '{' are interpreted as block - * statements. See E5 Section 12.4. - * - * Directive detection is tricky; see E5 Section 14.1 on directive - * prologue. A directive is an expression statement with a single - * string literal and an explicit or automatic semicolon. Escape - * characters are significant and no parens etc are allowed: - * - * 'use strict'; // valid 'use strict' directive - * 'use\u0020strict'; // valid directive, not a 'use strict' directive - * ('use strict'); // not a valid directive - * - * The expression is determined to consist of a single string literal - * based on duk__expr_nud() and duk__expr_led() call counts. The string literal - * of a 'use strict' directive is determined to lack any escapes based - * num_escapes count from the lexer. Note that other directives may be - * allowed to contain escapes, so a directive with escapes does not - * terminate a directive prologue. - * - * We rely on the fact that the expression parser will not emit any - * code for a single token expression. However, it will generate an - * intermediate value which we will then successfully ignore. - * - * A similar approach is used for labels. - */ - - duk_bool_t single_token; - - DUK_DDD(DUK_DDDPRINT("expression statement")); - duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - - single_token = (comp_ctx->curr_func.nud_count == 1 && /* one token */ - comp_ctx->curr_func.led_count == 0); /* no operators */ - - if (single_token && - comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER && - comp_ctx->curr_token.t == DUK_TOK_COLON) { - /* - * Detected label - */ - - duk_hstring *h_lab; - - /* expected ival */ - DUK_ASSERT(res->t == DUK_IVAL_VAR); - DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE); - DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx))); - h_lab = comp_ctx->prev_token.str1; - DUK_ASSERT(h_lab != NULL); - - DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'", - (duk_heaphdr *) h_lab)); - - duk__advance(comp_ctx); /* eat colon */ - - label_id = duk__stmt_label_site(comp_ctx, label_id); - - duk__add_label(comp_ctx, - h_lab, - pc_at_entry /*pc_label*/, - label_id); - - /* a statement following a label cannot be a source element - * (a function declaration). - */ - allow_source_elem = 0; - - DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing")); - goto retry_parse; - } - - stmt_flags = 0; - - if (dir_prol_at_entry && /* still in prologue */ - single_token && /* single string token */ - comp_ctx->prev_token.t == DUK_TOK_STRING) { - /* - * Detected a directive - */ - duk_hstring *h_dir; - - /* expected ival */ - DUK_ASSERT(res->t == DUK_IVAL_PLAIN); - DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE); - DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx))); - h_dir = comp_ctx->prev_token.str1; - DUK_ASSERT(h_dir != NULL); - - DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir)); - - stmt_flags |= DUK__STILL_PROLOGUE; - - /* Note: escaped characters differentiate directives */ - - if (comp_ctx->prev_token.num_escapes > 0) { - DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive " - "but we ignore such directives")); - } else { - /* - * The length comparisons are present to handle - * strings like "use strict\u0000foo" as required. - */ - - if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 && - DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict", 10) == 0) { -#if defined(DUK_USE_STRICT_DECL) - DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld", - (long) comp_ctx->curr_func.is_strict, (long) 1)); - comp_ctx->curr_func.is_strict = 1; -#else - DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring")); -#endif - } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 && - DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail", 14) == 0) { - DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld", - (long) comp_ctx->curr_func.is_notail, (long) 1)); - comp_ctx->curr_func.is_notail = 1; - } else { - DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating " - "directive prologue", (duk_hobject *) h_dir)); - } - } - } else { - DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; " - "prologue terminated if still active")); - } - - stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM; - } - } /* end switch (tok) */ - - /* - * Statement value handling. - * - * Global code and eval code has an implicit return value - * which comes from the last statement with a value - * (technically a non-"empty" continuation, which is - * different from an empty statement). - * - * Since we don't know whether a later statement will - * override the value of the current statement, we need - * to coerce the statement value to a register allocated - * for implicit return values. In other cases we need - * to coerce the statement value to a plain value to get - * any side effects out (consider e.g. "foo.bar;"). - */ - - /* XXX: what about statements which leave a half-cooked value in 'res' - * but have no stmt value? Any such statements? - */ - - if (stmt_flags & DUK__HAS_VAL) { - duk_regconst_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value; - if (reg_stmt_value >= 0) { - duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value); - } else { - duk__ivalue_toplain_ignore(comp_ctx, res); - } - } else { - ; - } - - /* - * Statement terminator check, including automatic semicolon - * handling. After this step, 'curr_tok' should be the first - * token after a possible statement terminator. - */ - - if (stmt_flags & DUK__HAS_TERM) { - if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) { - DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement")); - duk__advance(comp_ctx); - } else { - if (comp_ctx->curr_token.allow_auto_semi) { - DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement")); - } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) { - /* XXX: make this lenience dependent on flags or strictness? */ - DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility " - "even though no lineterm present before next token)")); - } else { - DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT); - } - } - } else { - DUK_DDD(DUK_DDDPRINT("statement has no terminator")); - } - - /* - * Directive prologue tracking. - */ - - if (stmt_flags & DUK__STILL_PROLOGUE) { - DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue")); - comp_ctx->curr_func.in_directive_prologue = 1; - } - - /* - * Cleanups (all statement parsing flows through here). - * - * Pop label site and reset labels. Reset 'next temp' to value at - * entry to reuse temps. - */ - - if (label_id >= 0) { - duk__emit_bc(comp_ctx, - DUK_OP_ENDLABEL, - (duk_regconst_t) label_id); - } - - DUK__SETTEMP(comp_ctx, temp_at_entry); - - duk__reset_labels_to_length(comp_ctx, labels_len_at_entry); - - /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */ - - DUK__RECURSION_DECREASE(comp_ctx, thr); -} - -/* - * Parse a statement list. - * - * Handles automatic semicolon insertion and implicit return value. - * - * Upon entry, 'curr_tok' should contain the first token of the first - * statement (parsed in the "allow regexp literal" mode). Upon exit, - * 'curr_tok' contains the token following the statement list terminator - * (EOF or closing brace). - */ - -DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof) { - duk_hthread *thr = comp_ctx->thr; - duk_ivalue res_alloc; - duk_ivalue *res = &res_alloc; - - /* Setup state. Initial ivalue is 'undefined'. */ - - duk_require_stack(thr, DUK__PARSE_STATEMENTS_SLOTS); - - /* XXX: 'res' setup can be moved to function body level; in fact, two 'res' - * intermediate values suffice for parsing of each function. Nesting is needed - * for nested functions (which may occur inside expressions). - */ - - DUK_MEMZERO(&res_alloc, sizeof(res_alloc)); - res->t = DUK_IVAL_PLAIN; - res->x1.t = DUK_ISPEC_VALUE; - res->x1.valstack_idx = duk_get_top(thr); - res->x2.valstack_idx = res->x1.valstack_idx + 1; - duk_push_undefined(thr); - duk_push_undefined(thr); - - /* Parse statements until a closing token (EOF or '}') is found. */ - - for (;;) { - /* Check whether statement list ends. */ - - if (expect_eof) { - if (comp_ctx->curr_token.t == DUK_TOK_EOF) { - break; - } - } else { - if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) { - break; - } - } - - /* Check statement type based on the first token type. - * - * Note: expression parsing helpers expect 'curr_tok' to - * contain the first token of the expression upon entry. - */ - - DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx->curr_token.t)); - - duk__parse_stmt(comp_ctx, res, allow_source_elem); - } - - duk__advance(comp_ctx); - - /* Tear down state. */ - - duk_pop_2(thr); -} - -/* - * Declaration binding instantiation conceptually happens when calling a - * function; for us it essentially means that function prologue. The - * conceptual process is described in E5 Section 10.5. - * - * We need to keep track of all encountered identifiers to (1) create an - * identifier-to-register map ("varmap"); and (2) detect duplicate - * declarations. Identifiers which are not bound to registers still need - * to be tracked for detecting duplicates. Currently such identifiers - * are put into the varmap with a 'null' value, which is later cleaned up. - * - * To support functions with a large number of variable and function - * declarations, registers are not allocated beyond a certain limit; - * after that limit, variables and functions need slow path access. - * Arguments are currently always register bound, which imposes a hard - * (and relatively small) argument count limit. - * - * Some bindings in E5 are not configurable (= deletable) and almost all - * are mutable (writable). Exceptions are: - * - * - The 'arguments' binding, established only if no shadowing argument - * or function declaration exists. We handle 'arguments' creation - * and binding through an explicit slow path environment record. - * - * - The "name" binding for a named function expression. This is also - * handled through an explicit slow path environment record. - */ - -/* XXX: add support for variables to not be register bound always, to - * handle cases with a very large number of variables? - */ - -DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg) { - duk_hthread *thr = comp_ctx->thr; - duk_hstring *h_name; - duk_bool_t configurable_bindings; - duk_uarridx_t num_args; - duk_uarridx_t num_decls; - duk_regconst_t rc_name; - duk_small_uint_t declvar_flags; - duk_uarridx_t i; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top; -#endif - -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(thr); -#endif - - /* - * Preliminaries - */ - - configurable_bindings = comp_ctx->curr_func.is_eval; - DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings)); - - /* varmap is already in comp_ctx->curr_func.varmap_idx */ - - /* - * Function formal arguments, always bound to registers - * (there's no support for shuffling them now). - */ - - num_args = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx); - DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args)); - /* XXX: check num_args */ - - for (i = 0; i < num_args; i++) { - duk_get_prop_index(thr, comp_ctx->curr_func.argnames_idx, i); - h_name = duk_known_hstring(thr, -1); - - if (comp_ctx->curr_func.is_strict) { - if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) { - DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError")); - goto error_argname; - } - duk_dup_top(thr); - if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) { - DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError")); - goto error_argname; - } - - /* Ensure argument name is not a reserved word in current - * (final) strictness. Formal argument parsing may not - * catch reserved names if strictness changes during - * parsing. - * - * We only need to do this in strict mode because non-strict - * keyword are always detected in formal argument parsing. - */ - - if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) { - goto error_argname; - } - } - - /* overwrite any previous binding of the same name; the effect is - * that last argument of a certain name wins. - */ - - /* only functions can have arguments */ - DUK_ASSERT(comp_ctx->curr_func.is_function); - duk_push_uarridx(thr, i); /* -> [ ... name index ] */ - duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */ - - /* no code needs to be emitted, the regs already have values */ - } - - /* use temp_next for tracking register allocations */ - DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_regconst_t) num_args); - - /* - * After arguments, allocate special registers (like shuffling temps) - */ - - if (out_stmt_value_reg) { - *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx); - } - if (comp_ctx->curr_func.needs_shuffle) { - duk_regconst_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3); - comp_ctx->curr_func.shuffle1 = shuffle_base; - comp_ctx->curr_func.shuffle2 = shuffle_base + 1; - comp_ctx->curr_func.shuffle3 = shuffle_base + 2; - DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld", - (long) comp_ctx->curr_func.shuffle1, - (long) comp_ctx->curr_func.shuffle2, - (long) comp_ctx->curr_func.shuffle3)); - } - if (comp_ctx->curr_func.temp_next > 0x100) { - DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld", (long) comp_ctx->curr_func.temp_next)); - goto error_outofregs; - } - - /* - * Function declarations - */ - - num_decls = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx); - DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T", - (long) num_decls, - (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.decls_idx))); - for (i = 0; i < num_decls; i += 2) { - duk_int_t decl_type; - duk_int_t fnum; - - duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */ - decl_type = duk_to_int(thr, -1); - fnum = decl_type >> 8; /* XXX: macros */ - decl_type = decl_type & 0xff; - duk_pop(thr); - - if (decl_type != DUK_DECL_TYPE_FUNC) { - continue; - } - - duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */ - - /* XXX: spilling */ - if (comp_ctx->curr_func.is_function) { - duk_regconst_t reg_bind; - duk_dup_top(thr); - if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) { - /* shadowed; update value */ - duk_dup_top(thr); - duk_get_prop(thr, comp_ctx->curr_func.varmap_idx); - reg_bind = duk_to_int(thr, -1); /* [ ... name reg_bind ] */ - duk__emit_a_bc(comp_ctx, - DUK_OP_CLOSURE, - reg_bind, - (duk_regconst_t) fnum); - } else { - /* function: always register bound */ - reg_bind = DUK__ALLOCTEMP(comp_ctx); - duk__emit_a_bc(comp_ctx, - DUK_OP_CLOSURE, - reg_bind, - (duk_regconst_t) fnum); - duk_push_int(thr, (duk_int_t) reg_bind); - } - } else { - /* Function declaration for global/eval code is emitted even - * for duplicates, because of E5 Section 10.5, step 5.e of - * E5.1 (special behavior for variable bound to global object). - * - * DECLVAR will not re-declare a variable as such, but will - * update the binding value. - */ - - duk_regconst_t reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk_dup_top(thr); - rc_name = duk__getconst(comp_ctx); - duk_push_null(thr); - - duk__emit_a_bc(comp_ctx, - DUK_OP_CLOSURE, - reg_temp, - (duk_regconst_t) fnum); - - declvar_flags = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_ENUMERABLE | - DUK_BC_DECLVAR_FLAG_FUNC_DECL; - - if (configurable_bindings) { - declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; - } - - duk__emit_a_b_c(comp_ctx, - DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST, - (duk_regconst_t) declvar_flags /*flags*/, - rc_name /*name*/, - reg_temp /*value*/); - - DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */ - } - - DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(thr, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(thr, -1))); -#endif - duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */ - } - - /* - * 'arguments' binding is special; if a shadowing argument or - * function declaration exists, an arguments object will - * definitely not be needed, regardless of whether the identifier - * 'arguments' is referenced inside the function body. - */ - - if (duk_has_prop_stridx(thr, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) { - DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration " - "-> arguments object creation can be skipped")); - comp_ctx->curr_func.is_arguments_shadowed = 1; - } - - /* - * Variable declarations. - * - * Unlike function declarations, variable declaration values don't get - * assigned on entry. If a binding of the same name already exists, just - * ignore it silently. - */ - - for (i = 0; i < num_decls; i += 2) { - duk_int_t decl_type; - - duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */ - decl_type = duk_to_int(thr, -1); - decl_type = decl_type & 0xff; - duk_pop(thr); - - if (decl_type != DUK_DECL_TYPE_VAR) { - continue; - } - - duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */ - - if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) { - /* shadowed, ignore */ - } else { - duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */ - h_name = duk_known_hstring(thr, -1); - - if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) && - !comp_ctx->curr_func.is_arguments_shadowed) { - /* E5 Section steps 7-8 */ - DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, " - "but appears as a variable declaration -> treat as " - "a no-op for variable declaration purposes")); - duk_pop(thr); - continue; - } - - /* XXX: spilling */ - if (comp_ctx->curr_func.is_function) { - duk_regconst_t reg_bind = DUK__ALLOCTEMP(comp_ctx); - /* no need to init reg, it will be undefined on entry */ - duk_push_int(thr, (duk_int_t) reg_bind); - } else { - duk_dup_top(thr); - rc_name = duk__getconst(comp_ctx); - duk_push_null(thr); - - declvar_flags = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_ENUMERABLE; - if (configurable_bindings) { - declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; - } - - duk__emit_a_b_c(comp_ctx, - DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST, - (duk_regconst_t) declvar_flags /*flags*/, - rc_name /*name*/, - 0 /*value*/); - } - - duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */ - } - } - - /* - * Wrap up - */ - - DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld", - (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx), - (long) comp_ctx->curr_func.is_arguments_shadowed)); - - DUK_ASSERT_TOP(thr, entry_top); - return; - - error_outofregs: - DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT); - DUK_UNREACHABLE(); - return; - - error_argname: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME); - DUK_UNREACHABLE(); - return; -} - -/* - * Parse a function-body-like expression (FunctionBody or Program - * in E5 grammar) using a two-pass parse. The productions appear - * in the following contexts: - * - * - function expression - * - function statement - * - function declaration - * - getter in object literal - * - setter in object literal - * - global code - * - eval code - * - Function constructor body - * - * This function only parses the statement list of the body; the argument - * list and possible function name must be initialized by the caller. - * For instance, for Function constructor, the argument names are originally - * on the value stack. The parsing of statements ends either at an EOF or - * a closing brace; this is controlled by an input flag. - * - * Note that there are many differences affecting parsing and even code - * generation: - * - * - Global and eval code have an implicit return value generated - * by the last statement; function code does not - * - * - Global code, eval code, and Function constructor body end in - * an EOF, other bodies in a closing brace ('}') - * - * Upon entry, 'curr_tok' is ignored and the function will pull in the - * first token on its own. Upon exit, 'curr_tok' is the terminating - * token (EOF or closing brace). - */ - -DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token) { - duk_compiler_func *func; - duk_hthread *thr; - duk_regconst_t reg_stmt_value = -1; - duk_lexer_point lex_pt; - duk_regconst_t temp_first; - duk_small_int_t compile_round = 1; - - DUK_ASSERT(comp_ctx != NULL); - - thr = comp_ctx->thr; - DUK_ASSERT(thr != NULL); - - func = &comp_ctx->curr_func; - DUK_ASSERT(func != NULL); - - DUK__RECURSION_INCREASE(comp_ctx, thr); - - duk_require_stack(thr, DUK__FUNCTION_BODY_REQUIRE_SLOTS); - - /* - * Store lexer position for a later rewind - */ - - DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt); - - /* - * Program code (global and eval code) has an implicit return value - * from the last statement value (e.g. eval("1; 2+3;") returns 3). - * This is not the case with functions. If implicit statement return - * value is requested, all statements are coerced to a register - * allocated here, and used in the implicit return statement below. - */ - - /* XXX: this is pointless here because pass 1 is throw-away */ - if (implicit_return_value) { - reg_stmt_value = DUK__ALLOCTEMP(comp_ctx); - - /* If an implicit return value is needed by caller, it must be - * initialized to 'undefined' because we don't know whether any - * non-empty (where "empty" is a continuation type, and different - * from an empty statement) statements will be executed. - * - * However, since 1st pass is a throwaway one, no need to emit - * it here. - */ -#if 0 - duk__emit_bc(comp_ctx, - DUK_OP_LDUNDEF, - 0); -#endif - } - - /* - * First pass. - * - * Gather variable/function declarations needed for second pass. - * Code generated is dummy and discarded. - */ - - func->in_directive_prologue = 1; - func->in_scanning = 1; - func->may_direct_eval = 0; - func->id_access_arguments = 0; - func->id_access_slow = 0; - func->id_access_slow_own = 0; - func->reg_stmt_value = reg_stmt_value; -#if defined(DUK_USE_DEBUGGER_SUPPORT) - func->min_line = DUK_INT_MAX; - func->max_line = 0; -#endif - - /* duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp literal" mode with current strictness */ - if (expect_token >= 0) { - /* Eating a left curly; regexp mode is allowed by left curly - * based on duk__token_lbp[] automatically. - */ - DUK_ASSERT(expect_token == DUK_TOK_LCURLY); - duk__update_lineinfo_currtoken(comp_ctx); - duk__advance_expect(comp_ctx, expect_token); - } else { - /* Need to set curr_token.t because lexing regexp mode depends on current - * token type. Zero value causes "allow regexp" mode. - */ - comp_ctx->curr_token.t = 0; - duk__advance(comp_ctx); - } - - DUK_DDD(DUK_DDDPRINT("begin 1st pass")); - duk__parse_stmts(comp_ctx, - 1, /* allow source elements */ - expect_eof); /* expect EOF instead of } */ - DUK_DDD(DUK_DDDPRINT("end 1st pass")); - - /* - * Second (and possibly third) pass. - * - * Generate actual code. In most cases the need for shuffle - * registers is detected during pass 1, but in some corner cases - * we'll only detect it during pass 2 and a third pass is then - * needed (see GH-115). - */ - - for (;;) { - duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle; - compile_round++; - - /* - * Rewind lexer. - * - * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp - * literal" mode with current strictness. - * - * curr_token line number info should be initialized for pass 2 before - * generating prologue, to ensure prologue bytecode gets nice line numbers. - */ - - DUK_DDD(DUK_DDDPRINT("rewind lexer")); - DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt); - comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */ - comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */ - duk__advance(comp_ctx); - - /* - * Reset function state and perform register allocation, which creates - * 'varmap' for second pass. Function prologue for variable declarations, - * binding value initializations etc is emitted as a by-product. - * - * Strict mode restrictions for duplicate and invalid argument - * names are checked here now that we know whether the function - * is actually strict. See: test-dev-strict-mode-boundary.js. - * - * Inner functions are compiled during pass 1 and are not reset. - */ - - duk__reset_func_for_pass2(comp_ctx); - func->in_directive_prologue = 1; - func->in_scanning = 0; - - /* must be able to emit code, alloc consts, etc. */ - - duk__init_varmap_and_prologue_for_pass2(comp_ctx, - (implicit_return_value ? ®_stmt_value : NULL)); - func->reg_stmt_value = reg_stmt_value; - - temp_first = DUK__GETTEMP(comp_ctx); - - func->temp_first = temp_first; - func->temp_next = temp_first; - func->stmt_next = 0; - func->label_next = 0; - - /* XXX: init or assert catch depth etc -- all values */ - func->id_access_arguments = 0; - func->id_access_slow = 0; - func->id_access_slow_own = 0; - - /* - * Check function name validity now that we know strictness. - * This only applies to function declarations and expressions, - * not setter/getter name. - * - * See: test-dev-strict-mode-boundary.js - */ - - if (func->is_function && !func->is_setget && func->h_name != NULL) { - if (func->is_strict) { - if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) { - DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode")); - goto error_funcname; - } - if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) { - DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode")); - goto error_funcname; - } - } else { - if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) && - !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) { - DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode")); - goto error_funcname; - } - } - } - - /* - * Second pass parsing. - */ - - if (implicit_return_value) { - /* Default implicit return value. */ - duk__emit_bc(comp_ctx, - DUK_OP_LDUNDEF, - 0); - } - - DUK_DDD(DUK_DDDPRINT("begin 2nd pass")); - duk__parse_stmts(comp_ctx, - 1, /* allow source elements */ - expect_eof); /* expect EOF instead of } */ - DUK_DDD(DUK_DDDPRINT("end 2nd pass")); - - duk__update_lineinfo_currtoken(comp_ctx); - - if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) { - /* Shuffle decision not changed. */ - break; - } - if (compile_round >= 3) { - /* Should never happen but avoid infinite loop just in case. */ - DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen")); - DUK_ERROR_INTERNAL(thr); - } - DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round)); - } - - /* - * Emit a final RETURN. - * - * It would be nice to avoid emitting an unnecessary "return" opcode - * if the current PC is not reachable. However, this cannot be reliably - * detected; even if the previous instruction is an unconditional jump, - * there may be a previous jump which jumps to current PC (which is the - * case for iteration and conditional statements, for instance). - */ - - /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts(); - * we could avoid the last RETURN if we could ensure there is no way to get here - * (directly or via a jump) - */ - - DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0); - if (reg_stmt_value >= 0) { - DUK_ASSERT(DUK__ISREG(reg_stmt_value)); - duk__emit_bc(comp_ctx, DUK_OP_RETREG, reg_stmt_value /*reg*/); - } else { - duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF); - } - - /* - * Peephole optimize JUMP chains. - */ - - duk__peephole_optimize_bytecode(comp_ctx); - - /* - * comp_ctx->curr_func is now ready to be converted into an actual - * function template. - */ - - DUK__RECURSION_DECREASE(comp_ctx, thr); - return; - - error_funcname: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME); -} - -/* - * Parse a function-like expression: - * - * - function expression - * - function declaration - * - function statement (non-standard) - * - setter/getter - * - * Adds the function to comp_ctx->curr_func function table and returns the - * function number. - * - * On entry, curr_token points to: - * - * - the token after 'function' for function expression/declaration/statement - * - the token after 'set' or 'get' for setter/getter - */ - -/* Parse formals. */ -DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) { - duk_hthread *thr = comp_ctx->thr; - duk_bool_t first = 1; - duk_uarridx_t n; - - for (;;) { - if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) { - break; - } - - if (first) { - /* no comma */ - first = 0; - } else { - duk__advance_expect(comp_ctx, DUK_TOK_COMMA); - } - - /* Note: when parsing a formal list in non-strict context, e.g. - * "implements" is parsed as an identifier. When the function is - * later detected to be strict, the argument list must be rechecked - * against a larger set of reserved words (that of strict mode). - * This is handled by duk__parse_func_body(). Here we recognize - * whatever tokens are considered reserved in current strictness - * (which is not always enough). - */ - - if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) { - DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER); - } - DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER); - DUK_ASSERT(comp_ctx->curr_token.str1 != NULL); - DUK_DDD(DUK_DDDPRINT("formal argument: %!O", - (duk_heaphdr *) comp_ctx->curr_token.str1)); - - /* XXX: append primitive */ - duk_push_hstring(thr, comp_ctx->curr_token.str1); - n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx); - duk_put_prop_index(thr, comp_ctx->curr_func.argnames_idx, n); - - duk__advance(comp_ctx); /* eat identifier */ - } -} - -/* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is - * correctly set up. Assumes that curr_token is just after 'function' (or - * 'set'/'get' etc). - */ -DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) { - duk_hthread *thr = comp_ctx->thr; - duk_token *tok; - duk_bool_t no_advance; - - DUK_ASSERT(comp_ctx->curr_func.num_formals == 0); - DUK_ASSERT(comp_ctx->curr_func.is_function == 1); - DUK_ASSERT(comp_ctx->curr_func.is_eval == 0); - DUK_ASSERT(comp_ctx->curr_func.is_global == 0); - DUK_ASSERT(comp_ctx->curr_func.is_setget == ((flags & DUK__FUNC_FLAG_GETSET) != 0)); - - duk__update_lineinfo_currtoken(comp_ctx); - - /* - * Function name (if any) - * - * We don't check for prohibited names here, because we don't - * yet know whether the function will be strict. Function body - * parsing handles this retroactively. - * - * For function expressions and declarations function name must - * be an Identifer (excludes reserved words). For setter/getter - * it is a PropertyName which allows reserved words and also - * strings and numbers (e.g. "{ get 1() { ... } }"). - * - * Function parsing may start either from prev_token or curr_token - * (object literal method definition uses prev_token for example). - * This is dealt with for the initial token. - */ - - no_advance = (flags & DUK__FUNC_FLAG_USE_PREVTOKEN); - if (no_advance) { - tok = &comp_ctx->prev_token; - } else { - tok = &comp_ctx->curr_token; - } - - if (flags & DUK__FUNC_FLAG_GETSET) { - /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */ - if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t == DUK_TOK_STRING) { - duk_push_hstring(thr, tok->str1); /* keep in valstack */ - } else if (tok->t == DUK_TOK_NUMBER) { - duk_push_number(thr, tok->num); - duk_to_string(thr, -1); - } else { - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME); - } - comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */ - } else { - /* Function name is an Identifier (not IdentifierName), but we get - * the raw name (not recognizing keywords) here and perform the name - * checks only after pass 1. - */ - if (tok->t_nores == DUK_TOK_IDENTIFIER) { - duk_push_hstring(thr, tok->str1); /* keep in valstack */ - comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */ - } else { - /* valstack will be unbalanced, which is OK */ - DUK_ASSERT((flags & DUK__FUNC_FLAG_GETSET) == 0); - DUK_ASSERT(comp_ctx->curr_func.h_name == NULL); - no_advance = 1; - if (flags & DUK__FUNC_FLAG_DECL) { - DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED); - } - } - } - - DUK_DD(DUK_DDPRINT("function name: %!O", - (duk_heaphdr *) comp_ctx->curr_func.h_name)); - - if (!no_advance) { - duk__advance(comp_ctx); - } - - /* - * Formal argument list - * - * We don't check for prohibited names or for duplicate argument - * names here, becase we don't yet know whether the function will - * be strict. Function body parsing handles this retroactively. - */ - - duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); - - duk__parse_func_formals(comp_ctx); - - DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN); - duk__advance(comp_ctx); - - /* - * Parse function body - */ - - duk__parse_func_body(comp_ctx, - 0, /* expect_eof */ - 0, /* implicit_return_value */ - DUK_TOK_LCURLY); /* expect_token */ - - /* - * Convert duk_compiler_func to a function template and add it - * to the parent function table. - */ - - duk__convert_to_func_template(comp_ctx); /* -> [ ... func ] */ -} - -/* Parse an inner function, adding the function template to the current function's - * function table. Return a function number to be used by the outer function. - * - * Avoiding O(depth^2) inner function parsing is handled here. On the first pass, - * compile and register the function normally into the 'funcs' array, also recording - * a lexer point (offset/line) to the closing brace of the function. On the second - * pass, skip the function and return the same 'fnum' as on the first pass by using - * a running counter. - * - * An unfortunate side effect of this is that when parsing the inner function, almost - * nothing is known of the outer function, i.e. the inner function's scope. We don't - * need that information at the moment, but it would allow some optimizations if it - * were used. - */ -DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) { - duk_hthread *thr = comp_ctx->thr; - duk_compiler_func old_func; - duk_idx_t entry_top; - duk_int_t fnum; - - /* - * On second pass, skip the function. - */ - - if (!comp_ctx->curr_func.in_scanning) { - duk_lexer_point lex_pt; - - fnum = comp_ctx->curr_func.fnum_next++; - duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1)); - lex_pt.offset = (duk_size_t) duk_to_uint(thr, -1); - duk_pop(thr); - duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2)); - lex_pt.line = duk_to_int(thr, -1); - duk_pop(thr); - - DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld", - (long) lex_pt.offset, (long) lex_pt.line)); - - DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt); - comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */ - comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */ - duk__advance(comp_ctx); - duk__advance_expect(comp_ctx, DUK_TOK_RCURLY); - - return fnum; - } - - /* - * On first pass, perform actual parsing. Remember valstack top on entry - * to restore it later, and switch to using a new function in comp_ctx. - */ - - entry_top = duk_get_top(thr); - DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld", - (long) entry_top, (long) comp_ctx->curr_token.start_offset)); - - DUK_MEMCPY(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func)); - - DUK_MEMZERO(&comp_ctx->curr_func, sizeof(duk_compiler_func)); - duk__init_func_valstack_slots(comp_ctx); - DUK_ASSERT(comp_ctx->curr_func.num_formals == 0); - - /* inherit initial strictness from parent */ - comp_ctx->curr_func.is_strict = old_func.is_strict; - - /* XXX: It might be better to just store the flags into the curr_func - * struct and use them as is without this flag interpretation step - * here. - */ - DUK_ASSERT(comp_ctx->curr_func.is_notail == 0); - comp_ctx->curr_func.is_function = 1; - DUK_ASSERT(comp_ctx->curr_func.is_eval == 0); - DUK_ASSERT(comp_ctx->curr_func.is_global == 0); - comp_ctx->curr_func.is_setget = ((flags & DUK__FUNC_FLAG_GETSET) != 0); - comp_ctx->curr_func.is_namebinding = !(flags & (DUK__FUNC_FLAG_GETSET | - DUK__FUNC_FLAG_METDEF | - DUK__FUNC_FLAG_DECL)); /* no name binding for: declarations, objlit getset, objlit method def */ - comp_ctx->curr_func.is_constructable = !(flags & (DUK__FUNC_FLAG_GETSET | - DUK__FUNC_FLAG_METDEF)); /* not constructable: objlit getset, objlit method def */ - - /* - * Parse inner function - */ - - duk__parse_func_like_raw(comp_ctx, flags); /* pushes function template */ - - /* prev_token.start_offset points to the closing brace here; when skipping - * we're going to reparse the closing brace to ensure semicolon insertion - * etc work as expected. - */ - DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld", - (long) comp_ctx->prev_token.start_offset, (long) comp_ctx->curr_token.start_offset)); - DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY); - - /* XXX: append primitive */ - DUK_ASSERT(duk_get_length(thr, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3)); - fnum = old_func.fnum_next++; - - if (fnum > DUK__MAX_FUNCS) { - DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT); - } - - /* array writes autoincrement length */ - (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3)); - duk_push_size_t(thr, comp_ctx->prev_token.start_offset); - (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1)); - duk_push_int(thr, comp_ctx->prev_token.start_line); - (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2)); - - /* - * Cleanup: restore original function, restore valstack state. - * - * Function declaration handling needs the function name to be pushed - * on the value stack. - */ - - if (flags & DUK__FUNC_FLAG_PUSHNAME_PASS1) { - DUK_ASSERT(comp_ctx->curr_func.h_name != NULL); - duk_push_hstring(thr, comp_ctx->curr_func.h_name); - duk_replace(thr, entry_top); - duk_set_top(thr, entry_top + 1); - } else { - duk_set_top(thr, entry_top); - } - DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func)); - - return fnum; -} - -/* - * Compile input string into an executable function template without - * arguments. - * - * The string is parsed as the "Program" production of Ecmascript E5. - * Compilation context can be either global code or eval code (see E5 - * Sections 14 and 15.1.2.1). - * - * Input stack: [ ... filename ] - * Output stack: [ ... func_template ] - */ - -/* XXX: source code property */ - -DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_hthread *thr, void *udata) { - duk_hstring *h_filename; - duk__compiler_stkstate *comp_stk; - duk_compiler_ctx *comp_ctx; - duk_lexer_point *lex_pt; - duk_compiler_func *func; - duk_idx_t entry_top; - duk_bool_t is_strict; - duk_bool_t is_eval; - duk_bool_t is_funcexpr; - duk_small_uint_t flags; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(udata != NULL); - - /* - * Arguments check - */ - - entry_top = duk_get_top(thr); - DUK_ASSERT(entry_top >= 1); - - comp_stk = (duk__compiler_stkstate *) udata; - comp_ctx = &comp_stk->comp_ctx_alloc; - lex_pt = &comp_stk->lex_pt_alloc; - DUK_ASSERT(comp_ctx != NULL); - DUK_ASSERT(lex_pt != NULL); - - flags = comp_stk->flags; - is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0); - is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0); - is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0); - - h_filename = duk_get_hstring(thr, -1); /* may be undefined */ - - /* - * Init compiler and lexer contexts - */ - - func = &comp_ctx->curr_func; -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - comp_ctx->thr = NULL; - comp_ctx->h_filename = NULL; - comp_ctx->prev_token.str1 = NULL; - comp_ctx->prev_token.str2 = NULL; - comp_ctx->curr_token.str1 = NULL; - comp_ctx->curr_token.str2 = NULL; -#endif - - duk_require_stack(thr, DUK__COMPILE_ENTRY_SLOTS); - - duk_push_dynamic_buffer(thr, 0); /* entry_top + 0 */ - duk_push_undefined(thr); /* entry_top + 1 */ - duk_push_undefined(thr); /* entry_top + 2 */ - duk_push_undefined(thr); /* entry_top + 3 */ - duk_push_undefined(thr); /* entry_top + 4 */ - - comp_ctx->thr = thr; - comp_ctx->h_filename = h_filename; - comp_ctx->tok11_idx = entry_top + 1; - comp_ctx->tok12_idx = entry_top + 2; - comp_ctx->tok21_idx = entry_top + 3; - comp_ctx->tok22_idx = entry_top + 4; - comp_ctx->recursion_limit = DUK_USE_COMPILER_RECLIMIT; - - /* comp_ctx->lex has been pre-initialized by caller: it has been - * zeroed and input/input_length has been set. - */ - comp_ctx->lex.thr = thr; - /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */ - comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx; - comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx; - comp_ctx->lex.buf_idx = entry_top + 0; - comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 0); - DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf)); - comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT; - - lex_pt->offset = 0; - lex_pt->line = 1; - DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt); /* fills window */ - comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */ - - /* - * Initialize function state for a zero-argument function - */ - - duk__init_func_valstack_slots(comp_ctx); - DUK_ASSERT(func->num_formals == 0); - - if (is_funcexpr) { - /* Name will be filled from function expression, not by caller. - * This case is used by Function constructor and duk_compile() - * API with the DUK_COMPILE_FUNCTION option. - */ - DUK_ASSERT(func->h_name == NULL); - } else { - duk_push_hstring_stridx(thr, (is_eval ? DUK_STRIDX_EVAL : - DUK_STRIDX_GLOBAL)); - func->h_name = duk_get_hstring(thr, -1); - } - - /* - * Parse a function body or a function-like expression, depending - * on flags. - */ - - DUK_ASSERT(func->is_setget == 0); - func->is_strict = (duk_uint8_t) is_strict; - DUK_ASSERT(func->is_notail == 0); - - if (is_funcexpr) { - func->is_function = 1; - DUK_ASSERT(func->is_eval == 0); - DUK_ASSERT(func->is_global == 0); - func->is_namebinding = 1; - func->is_constructable = 1; - - duk__advance(comp_ctx); /* init 'curr_token' */ - duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION); - (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/); - } else { - DUK_ASSERT(func->is_function == 0); - DUK_ASSERT(is_eval == 0 || is_eval == 1); - func->is_eval = (duk_uint8_t) is_eval; - func->is_global = (duk_uint8_t) !is_eval; - DUK_ASSERT(func->is_namebinding == 0); - DUK_ASSERT(func->is_constructable == 0); - - duk__parse_func_body(comp_ctx, - 1, /* expect_eof */ - 1, /* implicit_return_value */ - -1); /* expect_token */ - } - - /* - * Convert duk_compiler_func to a function template - */ - - duk__convert_to_func_template(comp_ctx); - - /* - * Wrapping duk_safe_call() will mangle the stack, just return stack top - */ - - /* [ ... filename (temps) func ] */ - - return 1; -} - -DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) { - duk__compiler_stkstate comp_stk; - duk_compiler_ctx *prev_ctx; - duk_ret_t safe_rc; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(src_buffer != NULL); - - /* preinitialize lexer state partially */ - DUK_MEMZERO(&comp_stk, sizeof(comp_stk)); - comp_stk.flags = flags; - DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex); - comp_stk.comp_ctx_alloc.lex.input = src_buffer; - comp_stk.comp_ctx_alloc.lex.input_length = src_length; - comp_stk.comp_ctx_alloc.lex.flags = flags; /* Forward flags directly for now. */ - - /* [ ... filename ] */ - - prev_ctx = thr->compile_ctx; - thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */ - safe_rc = duk_safe_call(thr, duk__js_compile_raw, (void *) &comp_stk /*udata*/, 1 /*nargs*/, 1 /*nrets*/); - thr->compile_ctx = prev_ctx; /* must restore reliably before returning */ - - if (safe_rc != DUK_EXEC_SUCCESS) { - DUK_D(DUK_DPRINT("compilation failed: %!T", duk_get_tval(thr, -1))); - (void) duk_throw(thr); - } - - /* [ ... template ] */ -} - -/* automatic undefs */ -#undef DUK__ALLOCTEMP -#undef DUK__ALLOCTEMPS -#undef DUK__ALLOW_AUTO_SEMI_ALWAYS -#undef DUK__BC_INITIAL_INSTS -#undef DUK__BP_ADDITIVE -#undef DUK__BP_ASSIGNMENT -#undef DUK__BP_BAND -#undef DUK__BP_BOR -#undef DUK__BP_BXOR -#undef DUK__BP_CALL -#undef DUK__BP_CLOSING -#undef DUK__BP_COMMA -#undef DUK__BP_CONDITIONAL -#undef DUK__BP_EOF -#undef DUK__BP_EQUALITY -#undef DUK__BP_EXPONENTIATION -#undef DUK__BP_FOR_EXPR -#undef DUK__BP_INVALID -#undef DUK__BP_LAND -#undef DUK__BP_LOR -#undef DUK__BP_MEMBER -#undef DUK__BP_MULTIPLICATIVE -#undef DUK__BP_POSTFIX -#undef DUK__BP_RELATIONAL -#undef DUK__BP_SHIFT -#undef DUK__COMPILE_ENTRY_SLOTS -#undef DUK__CONST_MARKER -#undef DUK__DUMP_ISPEC -#undef DUK__DUMP_IVALUE -#undef DUK__EMIT_FLAG_A_IS_SOURCE -#undef DUK__EMIT_FLAG_BC_REGCONST -#undef DUK__EMIT_FLAG_B_IS_TARGET -#undef DUK__EMIT_FLAG_C_IS_TARGET -#undef DUK__EMIT_FLAG_NO_SHUFFLE_A -#undef DUK__EMIT_FLAG_NO_SHUFFLE_B -#undef DUK__EMIT_FLAG_NO_SHUFFLE_C -#undef DUK__EMIT_FLAG_RESERVE_JUMPSLOT -#undef DUK__EXPR_FLAG_ALLOW_EMPTY -#undef DUK__EXPR_FLAG_REJECT_IN -#undef DUK__EXPR_FLAG_REQUIRE_INIT -#undef DUK__EXPR_RBP_MASK -#undef DUK__FUNCTION_BODY_REQUIRE_SLOTS -#undef DUK__FUNCTION_INIT_REQUIRE_SLOTS -#undef DUK__FUNC_FLAG_DECL -#undef DUK__FUNC_FLAG_GETSET -#undef DUK__FUNC_FLAG_METDEF -#undef DUK__FUNC_FLAG_PUSHNAME_PASS1 -#undef DUK__FUNC_FLAG_USE_PREVTOKEN -#undef DUK__GETCONST_MAX_CONSTS_CHECK -#undef DUK__GETTEMP -#undef DUK__HAS_TERM -#undef DUK__HAS_VAL -#undef DUK__ISCONST -#undef DUK__ISREG -#undef DUK__ISREG_NOTTEMP -#undef DUK__ISREG_TEMP -#undef DUK__IS_TERMINAL -#undef DUK__IVAL_FLAG_ALLOW_CONST -#undef DUK__IVAL_FLAG_REQUIRE_SHORT -#undef DUK__IVAL_FLAG_REQUIRE_TEMP -#undef DUK__MAX_ARRAY_INIT_VALUES -#undef DUK__MAX_CONSTS -#undef DUK__MAX_FUNCS -#undef DUK__MAX_OBJECT_INIT_PAIRS -#undef DUK__MAX_TEMPS -#undef DUK__MK_LBP -#undef DUK__MK_LBP_FLAGS -#undef DUK__OBJ_LIT_KEY_GET -#undef DUK__OBJ_LIT_KEY_PLAIN -#undef DUK__OBJ_LIT_KEY_SET -#undef DUK__PARSE_EXPR_SLOTS -#undef DUK__PARSE_STATEMENTS_SLOTS -#undef DUK__RECURSION_DECREASE -#undef DUK__RECURSION_INCREASE -#undef DUK__REMOVECONST -#undef DUK__SETTEMP -#undef DUK__SETTEMP_CHECKMAX -#undef DUK__STILL_PROLOGUE -#undef DUK__TOKEN_LBP_BP_MASK -#undef DUK__TOKEN_LBP_FLAG_NO_REGEXP -#undef DUK__TOKEN_LBP_FLAG_TERMINATES -#undef DUK__TOKEN_LBP_FLAG_UNUSED -#undef DUK__TOKEN_LBP_GET_BP -#line 1 "duk_js_executor.c" -/* - * Ecmascript bytecode executor. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Local declarations. - */ - -DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act); - -/* - * Misc helpers. - */ - -/* Forced inline declaration, only applied for performance oriented build. */ -#if defined(DUK_USE_EXEC_PREFER_SIZE) -#define DUK__INLINE_PERF -#define DUK__NOINLINE_PERF -#else -#define DUK__INLINE_PERF DUK_ALWAYS_INLINE -#define DUK__NOINLINE_PERF DUK_NOINLINE -#endif - -/* Replace value stack top to value at 'tv_ptr'. Optimize for - * performance by only applying the net refcount change. - */ -#define DUK__REPLACE_TO_TVPTR(thr,tv_ptr) do { \ - duk_hthread *duk__thr; \ - duk_tval *duk__tvsrc; \ - duk_tval *duk__tvdst; \ - duk_tval duk__tvtmp; \ - duk__thr = (thr); \ - duk__tvsrc = DUK_GET_TVAL_NEGIDX(duk__thr, -1); \ - duk__tvdst = (tv_ptr); \ - DUK_TVAL_SET_TVAL(&duk__tvtmp, duk__tvdst); \ - DUK_TVAL_SET_TVAL(duk__tvdst, duk__tvsrc); \ - DUK_TVAL_SET_UNDEFINED(duk__tvsrc); /* value stack init policy */ \ - duk__thr->valstack_top = duk__tvsrc; \ - DUK_TVAL_DECREF(duk__thr, &duk__tvtmp); \ - } while (0) - -/* XXX: candidate of being an internal shared API call */ -#if 0 /* unused */ -DUK_LOCAL void duk__push_tvals_incref_only(duk_hthread *thr, duk_tval *tv_src, duk_small_uint_fast_t count) { - duk_tval *tv_dst; - duk_size_t copy_size; - duk_size_t i; - - tv_dst = thr->valstack_top; - copy_size = sizeof(duk_tval) * count; - DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, copy_size); - for (i = 0; i < count; i++) { - DUK_TVAL_INCREF(thr, tv_dst); - tv_dst++; - } - thr->valstack_top = tv_dst; -} -#endif - -/* - * Arithmetic, binary, and logical helpers. - * - * Note: there is no opcode for logical AND or logical OR; this is on - * purpose, because the evalution order semantics for them make such - * opcodes pretty pointless: short circuiting means they are most - * comfortably implemented as jumps. However, a logical NOT opcode - * is useful. - * - * Note: careful with duk_tval pointers here: they are potentially - * invalidated by any DECREF and almost any API call. It's still - * preferable to work without making a copy but that's not always - * possible. - */ - -DUK_LOCAL DUK__INLINE_PERF duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) { - return (duk_double_t) duk_js_arith_mod((double) d1, (double) d2); -} - -#if defined(DUK_USE_ES7_EXP_OPERATOR) -DUK_LOCAL DUK__INLINE_PERF duk_double_t duk__compute_exp(duk_double_t d1, duk_double_t d2) { - return (duk_double_t) duk_js_arith_pow((double) d1, (double) d2); -} -#endif - -DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z) { - /* - * Addition operator is different from other arithmetic - * operations in that it also provides string concatenation. - * Hence it is implemented separately. - * - * There is a fast path for number addition. Other cases go - * through potentially multiple coercions as described in the - * E5 specification. It may be possible to reduce the number - * of coercions, but this must be done carefully to preserve - * the exact semantics. - * - * E5 Section 11.6.1. - * - * Custom types also have special behavior implemented here. - */ - - duk_double_union du; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv_x != NULL); /* may be reg or const */ - DUK_ASSERT(tv_y != NULL); /* may be reg or const */ - DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */ - DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr)); - - /* - * Fast paths - */ - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) { - duk_int64_t v1, v2, v3; - duk_int32_t v3_hi; - duk_tval *tv_z; - - /* Input values are signed 48-bit so we can detect overflow - * reliably from high bits or just a comparison. - */ - - v1 = DUK_TVAL_GET_FASTINT(tv_x); - v2 = DUK_TVAL_GET_FASTINT(tv_y); - v3 = v1 + v2; - v3_hi = (duk_int32_t) (v3 >> 32); - if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) { - tv_z = thr->valstack_bottom + idx_z; - DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */ - return; - } else { - /* overflow, fall through */ - ; - } - } -#endif /* DUK_USE_FASTINT */ - - if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) { -#if !defined(DUK_USE_EXEC_PREFER_SIZE) - duk_tval *tv_z; -#endif - - du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y); -#if defined(DUK_USE_EXEC_PREFER_SIZE) - duk_push_number(thr, du.d); /* will NaN normalize result */ - duk_replace(thr, (duk_idx_t) idx_z); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - tv_z = thr->valstack_bottom + idx_z; - DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */ -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - return; - } - - /* - * Slow path: potentially requires function calls for coercion - */ - - duk_push_tval(thr, tv_x); - duk_push_tval(thr, tv_y); - duk_to_primitive(thr, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */ - duk_to_primitive(thr, -1, DUK_HINT_NONE); - - /* Since Duktape 2.x plain buffers are treated like ArrayBuffer. */ - if (duk_is_string(thr, -2) || duk_is_string(thr, -1)) { - /* Symbols shouldn't technically be handled here, but should - * go into the default ToNumber() coercion path instead and - * fail there with a TypeError. However, there's a ToString() - * in duk_concat_2() which also fails with TypeError so no - * explicit check is needed. - */ - duk_concat_2(thr); /* [... s1 s2] -> [... s1+s2] */ - } else { - duk_double_t d1, d2; - - d1 = duk_to_number_m2(thr); - d2 = duk_to_number_m1(thr); - DUK_ASSERT(duk_is_number(thr, -2)); - DUK_ASSERT(duk_is_number(thr, -1)); - DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1); - DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2); - - du.d = d1 + d2; - duk_pop_2_unsafe(thr); - duk_push_number(thr, du.d); /* will NaN normalize result */ - } - duk_replace(thr, (duk_idx_t) idx_z); /* side effects */ -} - -DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_uint_fast_t idx_z, duk_small_uint_fast_t opcode) { - /* - * Arithmetic operations other than '+' have number-only semantics - * and are implemented here. The separate switch-case here means a - * "double dispatch" of the arithmetic opcode, but saves code space. - * - * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3. - */ - - duk_double_t d1, d2; - duk_double_union du; - duk_small_uint_fast_t opcode_shifted; -#if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE) - duk_tval *tv_z; -#endif - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv_x != NULL); /* may be reg or const */ - DUK_ASSERT(tv_y != NULL); /* may be reg or const */ - DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */ - DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr)); - - opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */ - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) { - duk_int64_t v1, v2, v3; - duk_int32_t v3_hi; - - v1 = DUK_TVAL_GET_FASTINT(tv_x); - v2 = DUK_TVAL_GET_FASTINT(tv_y); - - switch (opcode_shifted) { - case DUK_OP_SUB >> 2: { - v3 = v1 - v2; - break; - } - case DUK_OP_MUL >> 2: { - /* Must ensure result is 64-bit (no overflow); a - * simple and sufficient fast path is to allow only - * 32-bit inputs. Avoid zero inputs to avoid - * negative zero issues (-1 * 0 = -0, for instance). - */ - if (v1 >= DUK_I64_CONSTANT(-0x80000000) && v1 <= DUK_I64_CONSTANT(0x7fffffff) && v1 != 0 && - v2 >= DUK_I64_CONSTANT(-0x80000000) && v2 <= DUK_I64_CONSTANT(0x7fffffff) && v2 != 0) { - v3 = v1 * v2; - } else { - goto skip_fastint; - } - break; - } - case DUK_OP_DIV >> 2: { - /* Don't allow a zero divisor. Fast path check by - * "verifying" with multiplication. Also avoid zero - * dividend to avoid negative zero issues (0 / -1 = -0 - * for instance). - */ - if (v1 == 0 || v2 == 0) { - goto skip_fastint; - } - v3 = v1 / v2; - if (v3 * v2 != v1) { - goto skip_fastint; - } - break; - } - case DUK_OP_MOD >> 2: { - /* Don't allow a zero divisor. Restrict both v1 and - * v2 to positive values to avoid compiler specific - * behavior. - */ - if (v1 < 1 || v2 < 1) { - goto skip_fastint; - } - v3 = v1 % v2; - DUK_ASSERT(v3 >= 0); - DUK_ASSERT(v3 < v2); - DUK_ASSERT(v1 - (v1 / v2) * v2 == v3); - break; - } - default: { - /* Possible with DUK_OP_EXP. */ - goto skip_fastint; - } - } - - v3_hi = (duk_int32_t) (v3 >> 32); - if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) { - tv_z = thr->valstack_bottom + idx_z; - DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */ - return; - } - /* fall through if overflow etc */ - } - skip_fastint: -#endif /* DUK_USE_FASTINT */ - - if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) { - /* fast path */ - d1 = DUK_TVAL_GET_NUMBER(tv_x); - d2 = DUK_TVAL_GET_NUMBER(tv_y); - } else { - duk_push_tval(thr, tv_x); - duk_push_tval(thr, tv_y); - d1 = duk_to_number_m2(thr); /* side effects */ - d2 = duk_to_number_m1(thr); - DUK_ASSERT(duk_is_number(thr, -2)); - DUK_ASSERT(duk_is_number(thr, -1)); - DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1); - DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2); - duk_pop_2_unsafe(thr); - } - - switch (opcode_shifted) { - case DUK_OP_SUB >> 2: { - du.d = d1 - d2; - break; - } - case DUK_OP_MUL >> 2: { - du.d = d1 * d2; - break; - } - case DUK_OP_DIV >> 2: { - du.d = d1 / d2; - break; - } - case DUK_OP_MOD >> 2: { - du.d = duk__compute_mod(d1, d2); - break; - } -#if defined(DUK_USE_ES7_EXP_OPERATOR) - case DUK_OP_EXP >> 2: { - du.d = duk__compute_exp(d1, d2); - break; - } -#endif - default: { - DUK_UNREACHABLE(); - du.d = DUK_DOUBLE_NAN; /* should not happen */ - break; - } - } - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - duk_push_number(thr, du.d); /* will NaN normalize result */ - duk_replace(thr, (duk_idx_t) idx_z); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - /* important to use normalized NaN with 8-byte tagged types */ - DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - tv_z = thr->valstack_bottom + idx_z; - DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */ -#endif /* DUK_USE_EXEC_PREFER_SIZE */ -} - -DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z, duk_small_uint_fast_t opcode) { - /* - * Binary bitwise operations use different coercions (ToInt32, ToUint32) - * depending on the operation. We coerce the arguments first using - * ToInt32(), and then cast to an 32-bit value if necessary. Note that - * such casts must be correct even if there is no native 32-bit type - * (e.g., duk_int32_t and duk_uint32_t are 64-bit). - * - * E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3 - */ - - duk_int32_t i1, i2, i3; - duk_uint32_t u1, u2, u3; -#if defined(DUK_USE_FASTINT) - duk_int64_t fi3; -#else - duk_double_t d3; -#endif - duk_small_uint_fast_t opcode_shifted; -#if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE) - duk_tval *tv_z; -#endif - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv_x != NULL); /* may be reg or const */ - DUK_ASSERT(tv_y != NULL); /* may be reg or const */ - DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */ - DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr)); - - opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */ - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) { - i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x); - i2 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_y); - } - else -#endif /* DUK_USE_FASTINT */ - { - duk_push_tval(thr, tv_x); - duk_push_tval(thr, tv_y); - i1 = duk_to_int32(thr, -2); - i2 = duk_to_int32(thr, -1); - duk_pop_2_unsafe(thr); - } - - switch (opcode_shifted) { - case DUK_OP_BAND >> 2: { - i3 = i1 & i2; - break; - } - case DUK_OP_BOR >> 2: { - i3 = i1 | i2; - break; - } - case DUK_OP_BXOR >> 2: { - i3 = i1 ^ i2; - break; - } - case DUK_OP_BASL >> 2: { - /* Signed shift, named "arithmetic" (asl) because the result - * is signed, e.g. 4294967295 << 1 -> -2. Note that result - * must be masked. - */ - - u2 = ((duk_uint32_t) i2) & 0xffffffffUL; - i3 = (duk_int32_t) (((duk_uint32_t) i1) << (u2 & 0x1fUL)); /* E5 Section 11.7.1, steps 7 and 8 */ - i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */ - break; - } - case DUK_OP_BASR >> 2: { - /* signed shift */ - - u2 = ((duk_uint32_t) i2) & 0xffffffffUL; - i3 = i1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */ - break; - } - case DUK_OP_BLSR >> 2: { - /* unsigned shift */ - - u1 = ((duk_uint32_t) i1) & 0xffffffffUL; - u2 = ((duk_uint32_t) i2) & 0xffffffffUL; - - /* special result value handling */ - u3 = u1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */ -#if defined(DUK_USE_FASTINT) - fi3 = (duk_int64_t) u3; - goto fastint_result_set; -#else - d3 = (duk_double_t) u3; - goto result_set; -#endif - } - default: { - DUK_UNREACHABLE(); - i3 = 0; /* should not happen */ - break; - } - } - -#if defined(DUK_USE_FASTINT) - /* Result is always fastint compatible. */ - /* XXX: Set 32-bit result (but must then handle signed and - * unsigned results separately). - */ - fi3 = (duk_int64_t) i3; - - fastint_result_set: - tv_z = thr->valstack_bottom + idx_z; - DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3); /* side effects */ -#else /* DUK_USE_FASTINT */ - d3 = (duk_double_t) i3; - - result_set: - DUK_ASSERT(!DUK_ISNAN(d3)); /* 'd3' is never NaN, so no need to normalize */ - DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */ - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - duk_push_number(thr, d3); /* would NaN normalize result, but unnecessary */ - duk_replace(thr, (duk_idx_t) idx_z); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - tv_z = thr->valstack_bottom + idx_z; - DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */ -#endif /* DUK_USE_EXEC_PREFER_SIZE */ -#endif /* DUK_USE_FASTINT */ -} - -/* In-place unary operation. */ -DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst, duk_small_uint_fast_t opcode) { - /* - * Arithmetic operations other than '+' have number-only semantics - * and are implemented here. The separate switch-case here means a - * "double dispatch" of the arithmetic opcode, but saves code space. - * - * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3. - */ - - duk_tval *tv; - duk_double_t d1; - duk_double_union du; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(opcode == DUK_OP_UNM || opcode == DUK_OP_UNP); - DUK_ASSERT_DISABLE(idx_src >= 0); - DUK_ASSERT_DISABLE(idx_dst >= 0); - - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src); - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv)) { - duk_int64_t v1, v2; - - v1 = DUK_TVAL_GET_FASTINT(tv); - if (opcode == DUK_OP_UNM) { - /* The smallest fastint is no longer 48-bit when - * negated. Positive zero becames negative zero - * (cannot be represented) when negated. - */ - if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) { - v2 = -v1; - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); - DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2); - return; - } - } else { - /* ToNumber() for a fastint is a no-op. */ - DUK_ASSERT(opcode == DUK_OP_UNP); - v2 = v1; - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); - DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2); - return; - } - /* fall through if overflow etc */ - } -#endif /* DUK_USE_FASTINT */ - - if (DUK_TVAL_IS_NUMBER(tv)) { - d1 = DUK_TVAL_GET_NUMBER(tv); - } else { - d1 = duk_to_number_tval(thr, tv); /* side effects */ - } - - if (opcode == DUK_OP_UNP) { - /* ToNumber() for a double is a no-op, but unary plus is - * used to force a fastint check so do that here. - */ - du.d = d1; - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); -#if defined(DUK_USE_FASTINT) - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); - DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d); /* always 'fast', i.e. inlined */ - return; -#endif - } else { - DUK_ASSERT(opcode == DUK_OP_UNM); - du.d = -d1; - DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - } - - /* XXX: size optimize: push+replace? */ - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); - DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, du.d); -} - -DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) { - /* - * E5 Section 11.4.8 - */ - - duk_tval *tv; - duk_int32_t i1, i2; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT_DISABLE(idx_src >= 0); - DUK_ASSERT_DISABLE(idx_dst >= 0); - DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr)); - DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr)); - - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src); - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv)) { - i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv); - } - else -#endif /* DUK_USE_FASTINT */ - { - duk_push_tval(thr, tv); - i1 = duk_to_int32(thr, -1); /* side effects */ - duk_pop_unsafe(thr); - } - - /* Result is always fastint compatible. */ - i2 = ~i1; - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); - DUK_TVAL_SET_I32_UPDREF(thr, tv, i2); /* side effects */ -} - -DUK_LOCAL DUK__INLINE_PERF void duk__vm_logical_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) { - /* - * E5 Section 11.4.9 - */ - - duk_tval *tv; - duk_bool_t res; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT_DISABLE(idx_src >= 0); - DUK_ASSERT_DISABLE(idx_dst >= 0); - DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr)); - DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr)); - - /* ToBoolean() does not require any operations with side effects so - * we can do it efficiently. For footprint it would be better to use - * duk_js_toboolean() and then push+replace to the result slot. - */ - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src); - res = duk_js_toboolean(tv); /* does not modify 'tv' */ - DUK_ASSERT(res == 0 || res == 1); - res ^= 1; - tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); - /* XXX: size optimize: push+replace? */ - DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, res); /* side effects */ -} - -/* XXX: size optimized variant */ -DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_reg_helper(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_small_uint_t op) { - duk_double_t x, y, z; - - /* Two lowest bits of opcode are used to distinguish - * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1). - */ - DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00); - DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01); - DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02); - DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03); - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_src)) { - duk_int64_t x_fi, y_fi, z_fi; - x_fi = DUK_TVAL_GET_FASTINT(tv_src); - if (op & 0x01) { - if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MIN)) { - goto skip_fastint; - } - y_fi = x_fi - 1; - } else { - if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MAX)) { - goto skip_fastint; - } - y_fi = x_fi + 1; - } - - DUK_TVAL_SET_FASTINT(tv_src, y_fi); /* no need for refcount update */ - - z_fi = (op & 0x02) ? x_fi : y_fi; - DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_dst, z_fi); /* side effects */ - return; - } - skip_fastint: -#endif - if (DUK_TVAL_IS_NUMBER(tv_src)) { - /* Fast path for the case where the register - * is a number (e.g. loop counter). - */ - - x = DUK_TVAL_GET_NUMBER(tv_src); - if (op & 0x01) { - y = x - 1.0; - } else { - y = x + 1.0; - } - - DUK_TVAL_SET_NUMBER(tv_src, y); /* no need for refcount update */ - } else { - /* Preserve duk_tval pointer(s) across a potential valstack - * resize by converting them into offsets temporarily. - */ - duk_idx_t bc; - duk_size_t off_dst; - - off_dst = (duk_size_t) ((duk_uint8_t *) tv_dst - (duk_uint8_t *) thr->valstack_bottom); - bc = (duk_idx_t) (tv_src - thr->valstack_bottom); /* XXX: pass index explicitly? */ - tv_src = NULL; /* no longer referenced */ - - x = duk_to_number(thr, bc); - if (op & 0x01) { - y = x - 1.0; - } else { - y = x + 1.0; - } - - duk_push_number(thr, y); - duk_replace(thr, bc); - - tv_dst = (duk_tval *) (void *) (((duk_uint8_t *) thr->valstack_bottom) + off_dst); - } - - z = (op & 0x02) ? x : y; - DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z); /* side effects */ -} - -DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr, duk_small_uint_t idx_dst, duk_tval *tv_id, duk_small_uint_t op, duk_small_uint_t is_strict) { - duk_activation *act; - duk_double_t x, y; - duk_hstring *name; - - /* XXX: The pre/post inc/dec for an identifier lookup is - * missing the important fast path where the identifier - * has a storage location e.g. in a scope object so that - * it can be updated in-place. In particular, the case - * where the identifier has a storage location AND the - * previous value is a number should be optimized because - * it's side effect free. - */ - - /* Two lowest bits of opcode are used to distinguish - * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1). - */ - DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00); - DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01); - DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02); - DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03); - - DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id)); - name = DUK_TVAL_GET_STRING(tv_id); - DUK_ASSERT(name != NULL); - act = thr->callstack_curr; - (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */ - - /* XXX: Fastint fast path would be useful here. Also fastints - * now lose their fastint status in current handling which is - * not intuitive. - */ - - x = duk_to_number_m2(thr); - if (op & 0x01) { - y = x - 1.0; - } else { - y = x + 1.0; - } - - /* [... x this] */ - - if (op & 0x02) { - duk_push_number(thr, y); /* -> [ ... x this y ] */ - DUK_ASSERT(act == thr->callstack_curr); - duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict); - duk_pop_2_unsafe(thr); /* -> [ ... x ] */ - } else { - duk_pop_2_unsafe(thr); /* -> [ ... ] */ - duk_push_number(thr, y); /* -> [ ... y ] */ - DUK_ASSERT(act == thr->callstack_curr); - duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict); - } - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - duk_replace(thr, (duk_idx_t) idx_dst); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - DUK__REPLACE_TO_TVPTR(thr, DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst)); -#endif /* DUK_USE_EXEC_PREFER_SIZE */ -} - -/* - * Longjmp and other control flow transfer for the bytecode executor. - * - * The longjmp handler can handle all longjmp types: error, yield, and - * resume (pseudotypes are never actually thrown). - * - * Error policy for longjmp: should not ordinarily throw errors; if errors - * occur (e.g. due to out-of-memory) they bubble outwards rather than being - * handled recursively. - */ - -#define DUK__LONGJMP_RESTART 0 /* state updated, restart bytecode execution */ -#define DUK__LONGJMP_RETHROW 1 /* exit bytecode executor by rethrowing an error to caller */ - -#define DUK__RETHAND_RESTART 0 /* state updated, restart bytecode execution */ -#define DUK__RETHAND_FINISHED 1 /* exit bytecode execution with return value */ - -/* XXX: optimize reconfig valstack operations so that resize, clamp, and setting - * top are combined into one pass. - */ - -/* Reconfigure value stack for return to an Ecmascript function at - * callstack top (caller unwinds). - */ -DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) { - duk_activation *act; - duk_hcompfunc *h_func; - duk_idx_t clamp_top; - - DUK_ASSERT(thr != NULL); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act))); - - /* Clamp so that values at 'clamp_top' and above are wiped and won't - * retain reachable garbage. Then extend to 'nregs' because we're - * returning to an Ecmascript function. - */ - - h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); - - thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff); - DUK_ASSERT(act->retval_byteoff >= act->bottom_byteoff); - clamp_top = (duk_idx_t) ((act->retval_byteoff - act->bottom_byteoff + sizeof(duk_tval)) / sizeof(duk_tval)); /* +1 = one retval */ - duk_set_top_and_wipe(thr, h_func->nregs, clamp_top); - - DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff); - thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff); - - /* XXX: a best effort shrink check would be OK here */ -} - -/* Reconfigure value stack for an Ecmascript catcher. Use topmost catcher - * in 'act'. - */ -DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_activation *act) { - duk_catcher *cat; - duk_hcompfunc *h_func; - duk_size_t idx_bottom; - duk_idx_t clamp_top; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(act != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act))); - cat = act->cat; - DUK_ASSERT(cat != NULL); - - h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); - - thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff); - idx_bottom = (duk_size_t) (thr->valstack_bottom - thr->valstack); - DUK_ASSERT(cat->idx_base >= idx_bottom); - clamp_top = (duk_idx_t) (cat->idx_base - idx_bottom + 2); /* +2 = catcher value, catcher lj_type */ - duk_set_top_and_wipe(thr, h_func->nregs, clamp_top); - - DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff); - thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff); - - /* XXX: a best effort shrink check would be OK here */ -} - -/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type. - * No side effects. - */ -DUK_LOCAL void duk__set_catcher_regs_norz(duk_hthread *thr, duk_catcher *cat, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) { - duk_tval *tv1; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv_val_unstable != NULL); - - tv1 = thr->valstack + cat->idx_base; - DUK_ASSERT(tv1 < thr->valstack_top); - DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr, tv1, tv_val_unstable); - - tv1++; - DUK_ASSERT(tv1 == thr->valstack + cat->idx_base + 1); - DUK_ASSERT(tv1 < thr->valstack_top); - DUK_TVAL_SET_U32_UPDREF_NORZ(thr, tv1, (duk_uint32_t) lj_type); -} - -DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) { - duk_activation *act; - duk_catcher *cat; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv_val_unstable != NULL); - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - DUK_ASSERT(act->cat != NULL); - DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF); - - duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type); - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - duk__reconfig_valstack_ecma_catcher(thr, act); - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - cat = act->cat; - DUK_ASSERT(cat != NULL); - - act->curr_pc = cat->pc_base + 0; /* +0 = catch */ - - /* - * If entering a 'catch' block which requires an automatic - * catch variable binding, create the lexical environment. - * - * The binding is mutable (= writable) but not deletable. - * Step 4 for the catch production in E5 Section 12.14; - * no value is given for CreateMutableBinding 'D' argument, - * which implies the binding is not deletable. - */ - - if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)) { - duk_hdecenv *new_env; - - DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding")); - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - - if (act->lex_env == NULL) { - DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); - - duk_js_init_activation_environment_records_delayed(thr, act); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - } - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); - - /* XXX: If an out-of-memory happens here, longjmp state asserts - * will be triggered at present and a try-catch fails to catch. - * That's not sandboxing fatal (C API protected calls are what - * matters), and script catch code can immediately throw anyway - * for almost any operation. - */ - new_env = duk_hdecenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); - DUK_ASSERT(new_env != NULL); - duk_push_hobject(thr, (duk_hobject *) new_env); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); - DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env)); - - /* Note: currently the catch binding is handled without a register - * binding because we don't support dynamic register bindings (they - * must be fixed for an entire function). So, there is no need to - * record regbases etc. - */ - - /* XXX: duk_xdef_prop() may cause an out-of-memory, see above. */ - DUK_ASSERT(cat->h_varname != NULL); - duk_push_hstring(thr, cat->h_varname); - duk_push_tval(thr, thr->valstack + cat->idx_base); - duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */ - - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env); - act->lex_env = (duk_hobject *) new_env; - DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); /* reachable through activation */ - /* Net refcount change to act->lex_env is 0: incref for new_env's - * prototype, decref for act->lex_env overwrite. - */ - - DUK_CAT_SET_LEXENV_ACTIVE(cat); - - duk_pop_unsafe(thr); - - DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env)); - } - - DUK_CAT_CLEAR_CATCH_ENABLED(cat); -} - -DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) { - duk_activation *act; - duk_catcher *cat; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv_val_unstable != NULL); - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - DUK_ASSERT(act->cat != NULL); - DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF); - - duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type); - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - duk__reconfig_valstack_ecma_catcher(thr, act); - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - cat = act->cat; - DUK_ASSERT(cat != NULL); - - act->curr_pc = cat->pc_base + 1; /* +1 = finally */ - - DUK_CAT_CLEAR_FINALLY_ENABLED(cat); -} - -DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_small_uint_t lj_type) { - duk_activation *act; - duk_catcher *cat; - - DUK_ASSERT(thr != NULL); - - DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act))); - - /* +0 = break, +1 = continue */ - cat = act->cat; - DUK_ASSERT(cat != NULL); - DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL); - - act->curr_pc = cat->pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0); - - /* valstack should not need changes */ -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) == - (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs); -#endif -} - -/* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and - * when a RETURN opcode terminates a thread and yields to the resumer. - * Caller unwinds so that top of callstack is the activation we return to. - */ -#if defined(DUK_USE_COROUTINE_SUPPORT) -DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_tval *tv_val_unstable) { - duk_activation *act_resumer; - duk_tval *tv1; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(resumer != NULL); - DUK_ASSERT(tv_val_unstable != NULL); - act_resumer = resumer->callstack_curr; - DUK_ASSERT(act_resumer != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(act_resumer) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act_resumer))); /* resume caller must be an ecmascript func */ - - tv1 = (duk_tval *) (void *) ((duk_uint8_t *) resumer->valstack + act_resumer->retval_byteoff); /* return value from Duktape.Thread.resume() */ - DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ /* XXX: avoid side effects */ - - duk__reconfig_valstack_ecma_return(resumer); - - /* caller must change active thread, and set thr->resumer to NULL */ -} -#endif /* DUK_USE_COROUTINE_SUPPORT */ - -DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation *entry_act) { - duk_small_uint_t retval = DUK__LONGJMP_RESTART; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(entry_act != NULL); - - /* 'thr' is the current thread, as no-one resumes except us and we - * switch 'thr' in that case. - */ - DUK_ASSERT(thr == thr->heap->curr_thread); - - /* - * (Re)try handling the longjmp. - * - * A longjmp handler may convert the longjmp to a different type and - * "virtually" rethrow by goto'ing to 'check_longjmp'. Before the goto, - * the following must be updated: - * - the heap 'lj' state - * - 'thr' must reflect the "throwing" thread - */ - - check_longjmp: - - DUK_DD(DUK_DDPRINT("handling longjmp: type=%ld, value1=%!T, value2=%!T, iserror=%ld", - (long) thr->heap->lj.type, - (duk_tval *) &thr->heap->lj.value1, - (duk_tval *) &thr->heap->lj.value2, - (long) thr->heap->lj.iserror)); - - switch (thr->heap->lj.type) { - -#if defined(DUK_USE_COROUTINE_SUPPORT) - case DUK_LJ_TYPE_RESUME: { - /* - * Note: lj.value1 is 'value', lj.value2 is 'resumee'. - * This differs from YIELD. - */ - - duk_tval *tv; - duk_tval *tv2; - duk_hthread *resumee; - - /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */ - - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */ - DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(thr->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume); - - tv = &thr->heap->lj.value2; /* resumee */ - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv))); - resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv); - - DUK_ASSERT(resumee != NULL); - DUK_ASSERT(resumee->resumer == NULL); - DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE || - resumee->state == DUK_HTHREAD_STATE_YIELDED); /* checked by Duktape.Thread.resume() */ - DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || - resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */ - DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield)); - DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE || - resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */ - - if (thr->heap->lj.iserror) { - /* - * Throw the error in the resumed thread's context; the - * error value is pushed onto the resumee valstack. - * - * Note: the callstack of the target may empty in this case - * too (i.e. the target thread has never been resumed). The - * value stack will contain the initial function in that case, - * which we simply ignore. - */ - - DUK_ASSERT(resumee->resumer == NULL); - resumee->resumer = thr; - DUK_HTHREAD_INCREF(thr, thr); - resumee->state = DUK_HTHREAD_STATE_RUNNING; - thr->state = DUK_HTHREAD_STATE_RESUMED; - DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); - thr = resumee; - - thr->heap->lj.type = DUK_LJ_TYPE_THROW; - - /* thr->heap->lj.value1 is already the value to throw */ - /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */ - - DUK_ASSERT(thr->heap->lj.iserror); /* already set */ - - DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate")); - goto check_longjmp; - } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) { - /* Unwind previous Duktape.Thread.yield() call. The - * activation remaining must always be an Ecmascript - * call now (yield() accepts calls from Ecmascript - * only). - */ - duk_activation *act_resumee; - - DUK_ASSERT(resumee->callstack_top >= 2); - act_resumee = resumee->callstack_curr; /* Duktape.Thread.yield() */ - DUK_ASSERT(act_resumee != NULL); - act_resumee = act_resumee->parent; /* Ecmascript call site for yield() */ - DUK_ASSERT(act_resumee != NULL); - - tv = (duk_tval *) (void *) ((duk_uint8_t *) resumee->valstack + act_resumee->retval_byteoff); /* return value from Duktape.Thread.yield() */ - DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top); - tv2 = &thr->heap->lj.value1; - DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ /* XXX: avoid side effects */ - - duk_hthread_activation_unwind_norz(resumee); /* unwind to 'yield' caller */ - /* no need to unwind catch stack */ - - duk__reconfig_valstack_ecma_return(resumee); - - DUK_ASSERT(resumee->resumer == NULL); - resumee->resumer = thr; - DUK_HTHREAD_INCREF(thr, thr); - resumee->state = DUK_HTHREAD_STATE_RUNNING; - thr->state = DUK_HTHREAD_STATE_RESUMED; - DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); -#if 0 - thr = resumee; /* not needed, as we exit right away */ -#endif - DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee")); - retval = DUK__LONGJMP_RESTART; - goto wipe_and_return; - } else { - /* Initial resume call. */ - duk_small_uint_t call_flags; - duk_int_t setup_rc; - - /* resumee: [... initial_func] (currently actually: [initial_func]) */ - - duk_push_undefined(resumee); - tv = &thr->heap->lj.value1; - duk_push_tval(resumee, tv); - - /* resumee: [... initial_func undefined(= this) resume_value ] */ - - call_flags = DUK_CALL_FLAG_ALLOW_ECMATOECMA; /* not tailcall, ecma-to-ecma (assumed to succeed) */ - - setup_rc = duk_handle_call_unprotected_nargs(resumee, 1 /*nargs*/, call_flags); - if (setup_rc == 0) { - /* This shouldn't happen; Duktape.Thread.resume() - * should make sure of that. If it does happen - * this internal error will propagate out of the - * executor which can be quite misleading. - */ - DUK_ERROR_INTERNAL(thr); - } - - DUK_ASSERT(resumee->resumer == NULL); - resumee->resumer = thr; - DUK_HTHREAD_INCREF(thr, thr); - resumee->state = DUK_HTHREAD_STATE_RUNNING; - thr->state = DUK_HTHREAD_STATE_RESUMED; - DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); -#if 0 - thr = resumee; /* not needed, as we exit right away */ -#endif - DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee")); - retval = DUK__LONGJMP_RESTART; - goto wipe_and_return; - } - DUK_UNREACHABLE(); - break; /* never here */ - } - - case DUK_LJ_TYPE_YIELD: { - /* - * Currently only allowed only if yielding thread has only - * Ecmascript activations (except for the Duktape.Thread.yield() - * call at the callstack top) and none of them constructor - * calls. - * - * This excludes the 'entry' thread which will always have - * a preventcount > 0. - */ - - duk_hthread *resumer; - - /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */ - -#if 0 /* entry_thread not available for assert */ - DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */ -#endif - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */ - DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */ - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(thr->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* an Ecmascript function */ - - resumer = thr->resumer; - - DUK_ASSERT(resumer != NULL); - DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */ - DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(resumer->callstack_curr != NULL); - DUK_ASSERT(resumer->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume); - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent))); /* an Ecmascript function */ - - if (thr->heap->lj.iserror) { - thr->state = DUK_HTHREAD_STATE_YIELDED; - thr->resumer = NULL; - DUK_HTHREAD_DECREF_NORZ(thr, resumer); - resumer->state = DUK_HTHREAD_STATE_RUNNING; - DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); - thr = resumer; - - thr->heap->lj.type = DUK_LJ_TYPE_THROW; - /* lj.value1 is already set */ - DUK_ASSERT(thr->heap->lj.iserror); /* already set */ - - DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate")); - goto check_longjmp; - } else { - duk_hthread_activation_unwind_norz(resumer); - duk__handle_yield(thr, resumer, &thr->heap->lj.value1); - - thr->state = DUK_HTHREAD_STATE_YIELDED; - thr->resumer = NULL; - DUK_HTHREAD_DECREF_NORZ(thr, resumer); - resumer->state = DUK_HTHREAD_STATE_RUNNING; - DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); -#if 0 - thr = resumer; /* not needed, as we exit right away */ -#endif - - DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer")); - retval = DUK__LONGJMP_RESTART; - goto wipe_and_return; - } - DUK_UNREACHABLE(); - break; /* never here */ - } -#endif /* DUK_USE_COROUTINE_SUPPORT */ - - case DUK_LJ_TYPE_THROW: { - /* - * Three possible outcomes: - * * A try or finally catcher is found => resume there. - * (or) - * * The error propagates to the bytecode executor entry - * level (and we're in the entry thread) => rethrow - * with a new longjmp(), after restoring the previous - * catchpoint. - * * The error is not caught in the current thread, so - * the thread finishes with an error. This works like - * a yielded error, except that the thread is finished - * and can no longer be resumed. (There is always a - * resumer in this case.) - * - * Note: until we hit the entry level, there can only be - * Ecmascript activations. - */ - - duk_activation *act; - duk_catcher *cat; - duk_hthread *resumer; - - for (;;) { - act = thr->callstack_curr; - if (act == NULL) { - break; - } - - for (;;) { - cat = act->cat; - if (cat == NULL) { - break; - } - - if (DUK_CAT_HAS_CATCH_ENABLED(cat)) { - DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF); - - duk__handle_catch(thr, - &thr->heap->lj.value1, - DUK_LJ_TYPE_THROW); - - DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution")); - retval = DUK__LONGJMP_RESTART; - goto wipe_and_return; - } - - if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) { - DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF); - DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); - - duk__handle_finally(thr, - &thr->heap->lj.value1, - DUK_LJ_TYPE_THROW); - - DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution")); - retval = DUK__LONGJMP_RESTART; - goto wipe_and_return; - } - - duk_hthread_catcher_unwind_norz(thr, act); - } - - if (act == entry_act) { - /* Not caught by anything before entry level; rethrow and let the - * final catcher finish unwinding (esp. value stack). - */ - DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor")); - retval = DUK__LONGJMP_RETHROW; - goto just_return; - } - - duk_hthread_activation_unwind_norz(thr); - } - - DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp")); - - /* Not caught by current thread, thread terminates (yield error to resumer); - * note that this may cause a cascade if the resumer terminates with an uncaught - * exception etc (this is OK, but needs careful testing). - */ - - DUK_ASSERT(thr->resumer != NULL); - DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(thr->resumer->callstack_curr != NULL); - DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an Ecmascript function */ - - resumer = thr->resumer; - - /* reset longjmp */ - - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); /* already set */ - /* lj.value1 already set */ - - duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */ - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); - - thr->resumer = NULL; - DUK_HTHREAD_DECREF_NORZ(thr, resumer); - resumer->state = DUK_HTHREAD_STATE_RUNNING; - DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); - thr = resumer; - goto check_longjmp; - } - - case DUK_LJ_TYPE_BREAK: /* pseudotypes, not used in actual longjmps */ - case DUK_LJ_TYPE_CONTINUE: - case DUK_LJ_TYPE_RETURN: - case DUK_LJ_TYPE_NORMAL: - default: { - /* should never happen, but be robust */ - DUK_D(DUK_DPRINT("caught unknown longjmp type %ld, treat as internal error", (long) thr->heap->lj.type)); - goto convert_to_internal_error; - } - - } /* end switch */ - - DUK_UNREACHABLE(); - - wipe_and_return: - /* this is not strictly necessary, but helps debugging */ - thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN; - thr->heap->lj.iserror = 0; - - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ - - DUK_GC_TORTURE(thr->heap); - - just_return: - return retval; - - convert_to_internal_error: - /* This could also be thrown internally (set the error, goto check_longjmp), - * but it's better for internal errors to bubble outwards so that we won't - * infinite loop in this catchpoint. - */ - DUK_ERROR_INTERNAL(thr); - DUK_UNREACHABLE(); - return retval; -} - -/* Handle a BREAK/CONTINUE opcode. Avoid using longjmp() for BREAK/CONTINUE - * handling because it has a measurable performance impact in ordinary - * environments and an extreme impact in Emscripten (GH-342). - */ -DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_break_or_continue(duk_hthread *thr, - duk_uint_t label_id, - duk_small_uint_t lj_type) { - duk_activation *act; - duk_catcher *cat; - - DUK_ASSERT(thr != NULL); - - /* Find a matching label catcher or 'finally' catcher in - * the same function, unwinding catchers as we go. - * - * A label catcher must always exist and will match unless - * a 'finally' captures the break/continue first. It is the - * compiler's responsibility to ensure that labels are used - * correctly. - */ - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - - for (;;) { - cat = act->cat; - if (cat == NULL) { - break; - } - - DUK_DDD(DUK_DDDPRINT("considering catcher %p: type=%ld label=%ld", - (void *) cat, - (long) DUK_CAT_GET_TYPE(cat), - (long) DUK_CAT_GET_LABEL(cat))); - - /* XXX: bit mask test; FINALLY <-> TCF, single bit mask would suffice? */ - - if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF && - DUK_CAT_HAS_FINALLY_ENABLED(cat)) { - duk_tval tv_tmp; - - DUK_TVAL_SET_U32(&tv_tmp, (duk_uint32_t) label_id); - duk__handle_finally(thr, &tv_tmp, lj_type); - - DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution")); - return; - } - if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL && - (duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) { - duk__handle_label(thr, lj_type); - - DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution")); - return; - } - - duk_hthread_catcher_unwind_norz(thr, act); - } - - /* Should never happen, but be robust. */ - DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error")); - DUK_ERROR_INTERNAL(thr); - return; -} - -/* Handle a RETURN opcode. Avoid using longjmp() for return handling because - * it has a measurable performance impact in ordinary environments and an extreme - * impact in Emscripten (GH-342). Return value is on value stack top. - */ -DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation *entry_act) { - duk_tval *tv1; - duk_tval *tv2; -#if defined(DUK_USE_COROUTINE_SUPPORT) - duk_hthread *resumer; -#endif - duk_activation *act; - duk_catcher *cat; - - /* We can directly access value stack here. */ - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(entry_act != NULL); - DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); - tv1 = thr->valstack_top - 1; - DUK_TVAL_CHKFAST_INPLACE_FAST(tv1); /* fastint downgrade check for return values */ - - /* - * Four possible outcomes: - * - * 1. A 'finally' in the same function catches the 'return'. - * It may continue to propagate when 'finally' is finished, - * or it may be neutralized by 'finally' (both handled by - * ENDFIN). - * - * 2. The return happens at the entry level of the bytecode - * executor, so return from the executor (in C stack). - * - * 3. There is a calling (Ecmascript) activation in the call - * stack => return to it, in the same executor instance. - * - * 4. There is no calling activation, and the thread is - * terminated. There is always a resumer in this case, - * which gets the return value similarly to a 'yield' - * (except that the current thread can no longer be - * resumed). - */ - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->callstack_top >= 1); - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - - for (;;) { - cat = act->cat; - if (cat == NULL) { - break; - } - - if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF && - DUK_CAT_HAS_FINALLY_ENABLED(cat)) { - DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); - duk__handle_finally(thr, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN); - - DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution")); - return DUK__RETHAND_RESTART; - } - - duk_hthread_catcher_unwind_norz(thr, act); - } - - if (act == entry_act) { - /* Return to the bytecode executor caller who will unwind stacks - * and handle constructor post-processing. - * Return value is already on the stack top: [ ... retval ]. - */ - - DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor")); - return DUK__RETHAND_FINISHED; - } - - if (thr->callstack_top >= 2) { - /* There is a caller; it MUST be an Ecmascript caller (otherwise it would - * match entry_act check). - */ - DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, retval_byteoff=%ld, lj_value1=%!T", - (long) (thr->callstack_curr->parent->retval_byteoff), - (duk_tval *) &thr->heap->lj.value1)); - - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(thr->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* must be ecmascript */ - -#if defined(DUK_USE_ES6_PROXY) - if (thr->callstack_curr->flags & (DUK_ACT_FLAG_CONSTRUCT | DUK_ACT_FLAG_CONSTRUCT_PROXY)) { - duk_call_construct_postprocess(thr, thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY); /* side effects */ - } -#else - if (thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT) { - duk_call_construct_postprocess(thr, 0); /* side effects */ - } -#endif - - tv1 = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + thr->callstack_curr->parent->retval_byteoff); - DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); - tv2 = thr->valstack_top - 1; - DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ - - /* Catch stack unwind happens inline in callstack unwind. */ - duk_hthread_activation_unwind_norz(thr); - - duk__reconfig_valstack_ecma_return(thr); - - DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller")); - return DUK__RETHAND_RESTART; - } - -#if defined(DUK_USE_COROUTINE_SUPPORT) - DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)")); - - DUK_ASSERT(thr->resumer != NULL); - DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(thr->resumer->callstack_curr != NULL); - DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an Ecmascript function */ - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); - DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); - - resumer = thr->resumer; - - /* Share yield longjmp handler. */ - DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); - duk_hthread_activation_unwind_norz(resumer); - duk__handle_yield(thr, resumer, thr->valstack_top - 1); - - duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */ - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); - - thr->resumer = NULL; - DUK_HTHREAD_DECREF(thr, resumer); - resumer->state = DUK_HTHREAD_STATE_RUNNING; - DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); -#if 0 - thr = resumer; /* not needed */ -#endif - - DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer")); - return DUK__RETHAND_RESTART; -#else - /* Without coroutine support this case should never happen. */ - DUK_ERROR_INTERNAL(thr); - return DUK__RETHAND_FINISHED; /* not executed */ -#endif -} - -/* - * Executor interrupt handling - * - * The handler is called whenever the interrupt countdown reaches zero - * (or below). The handler must perform whatever checks are activated, - * e.g. check for cumulative step count to impose an execution step - * limit or check for breakpoints or other debugger interaction. - * - * When the actions are done, the handler must reinit the interrupt - * init and counter values. The 'init' value must indicate how many - * bytecode instructions are executed before the next interrupt. The - * counter must interface with the bytecode executor loop. Concretely, - * the new init value is normally one higher than the new counter value. - * For instance, to execute exactly one bytecode instruction the init - * value is set to 1 and the counter to 0. If an error is thrown by the - * interrupt handler, the counters are set to the same value (e.g. both - * to 0 to cause an interrupt when the next bytecode instruction is about - * to be executed after error handling). - * - * Maintaining the init/counter value properly is important for accurate - * behavior. For instance, executor step limit needs a cumulative step - * count which is simply computed as a sum of 'init' values. This must - * work accurately even when single stepping. - */ - -#if defined(DUK_USE_INTERRUPT_COUNTER) - -#define DUK__INT_NOACTION 0 /* no specific action, resume normal execution */ -#define DUK__INT_RESTART 1 /* must "goto restart_execution", e.g. breakpoints changed */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) { - duk_activation *act; - duk_breakpoint *bp; - duk_breakpoint **bp_active; - duk_uint_fast32_t line = 0; - duk_bool_t process_messages; - duk_bool_t processed_messages = 0; - - DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */ - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - - /* It might seem that replacing 'thr->heap' with just 'heap' below - * might be a good idea, but it increases code size slightly - * (probably due to unnecessary spilling) at least on x64. - */ - - /* - * Single opcode step check - */ - - if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE) { - DUK_D(DUK_DPRINT("PAUSE TRIGGERED by one opcode step")); - duk_debug_set_paused(thr->heap); - } - - /* - * Breakpoint and step state checks - */ - - if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE || - (thr->heap->dbg_pause_act == thr->callstack_curr)) { - line = duk_debug_curr_line(thr); - - if (act->prev_line != line) { - /* Stepped? Step out is handled by callstack unwind. */ - if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) && - (thr->heap->dbg_pause_act == thr->callstack_curr) && - (line != thr->heap->dbg_pause_startline)) { - DUK_D(DUK_DPRINT("PAUSE TRIGGERED by line change, at line %ld", - (long) line)); - duk_debug_set_paused(thr->heap); - } - - /* Check for breakpoints only on line transition. - * Breakpoint is triggered when we enter the target - * line from a different line, and the previous line - * was within the same function. - * - * This condition is tricky: the condition used to be - * that transition to -or across- the breakpoint line - * triggered the breakpoint. This seems intuitively - * better because it handles breakpoints on lines with - * no emitted opcodes; but this leads to the issue - * described in: https://github.com/svaarala/duktape/issues/263. - */ - bp_active = thr->heap->dbg_breakpoints_active; - for (;;) { - bp = *bp_active++; - if (bp == NULL) { - break; - } - - DUK_ASSERT(bp->filename != NULL); - if (act->prev_line != bp->line && line == bp->line) { - DUK_D(DUK_DPRINT("PAUSE TRIGGERED by breakpoint at %!O:%ld", - (duk_heaphdr *) bp->filename, (long) bp->line)); - duk_debug_set_paused(thr->heap); - } - } - } else { - ; - } - - act->prev_line = (duk_uint32_t) line; - } - - /* - * Rate limit check for sending status update or peeking into - * the debug transport. Both can be expensive operations that - * we don't want to do on every opcode. - * - * Making sure the interval remains reasonable on a wide variety - * of targets and bytecode is difficult without a timestamp, so - * we use a Date-provided timestamp for the rate limit check. - * But since it's also expensive to get a timestamp, a bytecode - * counter is used to rate limit getting timestamps. - */ - - process_messages = 0; - if (thr->heap->dbg_state_dirty || DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->dbg_detaching) { - /* Enter message processing loop for sending Status notifys and - * to finish a pending detach. - */ - process_messages = 1; - } - - /* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */ - DUK_ASSERT(thr->interrupt_init >= 0); - thr->heap->dbg_exec_counter += (duk_uint_t) thr->interrupt_init; - if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) { - /* Overflow of the execution counter is fine and doesn't break - * anything here. - */ - - duk_double_t now, diff_last; - - thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter; - now = duk_time_get_monotonic_time(thr); - - diff_last = now - thr->heap->dbg_last_time; - if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) { - /* Monotonic time should not experience time jumps, - * but the provider may be missing and we're actually - * using Ecmascript time. So, tolerate negative values - * so that a time jump works reasonably. - * - * Same interval is now used for status sending and - * peeking. - */ - - thr->heap->dbg_last_time = now; - thr->heap->dbg_state_dirty = 1; - process_messages = 1; - } - } - - /* - * Process messages and send status if necessary. - * - * If we're paused, we'll block for new messages. If we're not - * paused, we'll process anything we can peek but won't block - * for more. Detach (and re-attach) handling is all localized - * to duk_debug_process_messages() too. - * - * Debugger writes outside the message loop may cause debugger - * detach1 phase to run, after which dbg_read_cb == NULL and - * dbg_detaching != 0. The message loop will finish the detach - * by running detach2 phase, so enter the message loop also when - * detaching. - */ - - if (process_messages) { - DUK_ASSERT(thr->heap->dbg_processing == 0); - processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/); - DUK_ASSERT(thr->heap->dbg_processing == 0); - } - - /* Continue checked execution if there are breakpoints or we're stepping. - * Also use checked execution if paused flag is active - it shouldn't be - * because the debug message loop shouldn't terminate if it was. Step out - * is handled by callstack unwind and doesn't need checked execution. - * Note that debugger may have detached due to error or explicit request - * above, so we must recheck attach status. - */ - - if (duk_debug_is_attached(thr->heap)) { - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE || - (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) || - ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) && - thr->heap->dbg_pause_act == thr->callstack_curr) || - DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) { - *out_immediate = 1; - } - - /* If we processed any debug messages breakpoints may have - * changed; restart execution to re-check active breakpoints. - */ - if (processed_messages) { - DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints")); - *out_interrupt_retval = DUK__INT_RESTART; - } else { - if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) { - /* Set 'pause after one opcode' active only when we're - * actually just about to execute code. - */ - thr->heap->dbg_pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE; - } - } - } else { - DUK_D(DUK_DPRINT("debugger became detached, resume normal execution")); - } -} -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -DUK_LOCAL DUK__NOINLINE_PERF DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { - duk_int_t ctr; - duk_activation *act; - duk_hcompfunc *fun; - duk_bool_t immediate = 0; - duk_small_uint_t retval; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(thr->callstack_top > 0); - -#if defined(DUK_USE_DEBUG) - thr->heap->inst_count_interrupt += thr->interrupt_init; - DUK_DD(DUK_DDPRINT("execution interrupt, counter=%ld, init=%ld, " - "instruction counts: executor=%ld, interrupt=%ld", - (long) thr->interrupt_counter, (long) thr->interrupt_init, - (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt)); -#endif - - retval = DUK__INT_NOACTION; - ctr = DUK_HTHREAD_INTCTR_DEFAULT; - - /* - * Avoid nested calls. Concretely this happens during debugging, e.g. - * when we eval() an expression. - * - * Also don't interrupt if we're currently doing debug processing - * (which can be initiated outside the bytecode executor) as this - * may cause the debugger to be called recursively. Check required - * for correct operation of throw intercept and other "exotic" halting - * scenarios. - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap) || thr->heap->dbg_processing) { -#else - if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap)) { -#endif - DUK_DD(DUK_DDPRINT("nested executor interrupt, ignoring")); - - /* Set a high interrupt counter; the original executor - * interrupt invocation will rewrite before exiting. - */ - thr->interrupt_init = ctr; - thr->interrupt_counter = ctr - 1; - return DUK__INT_NOACTION; - } - DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap); - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - - fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun)); - - DUK_UNREF(fun); - -#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) - /* - * Execution timeout check - */ - - if (DUK_USE_EXEC_TIMEOUT_CHECK(thr->heap->heap_udata)) { - /* Keep throwing an error whenever we get here. The unusual values - * are set this way because no instruction is ever executed, we just - * throw an error until all try/catch/finally and other catchpoints - * have been exhausted. Duktape/C code gets control at each protected - * call but whenever it enters back into Duktape the RangeError gets - * raised. User exec timeout check must consistently indicate a timeout - * until we've fully bubbled out of Duktape. - */ - DUK_D(DUK_DPRINT("execution timeout, throwing a RangeError")); - thr->interrupt_init = 0; - thr->interrupt_counter = 0; - DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap); - DUK_ERROR_RANGE(thr, "execution timeout"); - } -#endif /* DUK_USE_EXEC_TIMEOUT_CHECK */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (!thr->heap->dbg_processing && - (thr->heap->dbg_read_cb != NULL || thr->heap->dbg_detaching)) { - /* Avoid recursive re-entry; enter when we're attached or - * detaching (to finish off the pending detach). - */ - duk__interrupt_handle_debugger(thr, &immediate, &retval); - DUK_ASSERT(act == thr->callstack_curr); - } -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - - /* - * Update the interrupt counter - */ - - if (immediate) { - /* Cause an interrupt after executing one instruction. */ - ctr = 1; - } - - /* The counter value is one less than the init value: init value should - * indicate how many instructions are executed before interrupt. To - * execute 1 instruction (after interrupt handler return), counter must - * be 0. - */ - DUK_ASSERT(ctr >= 1); - thr->interrupt_init = ctr; - thr->interrupt_counter = ctr - 1; - DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap); - - return retval; -} -#endif /* DUK_USE_INTERRUPT_COUNTER */ - -/* - * Debugger handling for executor restart - * - * Check for breakpoints, stepping, etc, and figure out if we should execute - * in checked or normal mode. Note that we can't do this when an activation - * is created, because breakpoint status (and stepping status) may change - * later, so we must recheck every time we're executing an activation. - * This primitive should be side effect free to avoid changes during check. - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompfunc *fun) { - duk_heap *heap; - duk_tval *tv_tmp; - duk_hstring *filename; - duk_small_uint_t bp_idx; - duk_breakpoint **bp_active; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(act != NULL); - DUK_ASSERT(fun != NULL); - - heap = thr->heap; - bp_active = heap->dbg_breakpoints_active; - act->flags &= ~DUK_ACT_FLAG_BREAKPOINT_ACTIVE; - - tv_tmp = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) fun, DUK_HTHREAD_STRING_FILE_NAME(thr)); - if (tv_tmp && DUK_TVAL_IS_STRING(tv_tmp)) { - filename = DUK_TVAL_GET_STRING(tv_tmp); - - /* Figure out all active breakpoints. A breakpoint is - * considered active if the current function's fileName - * matches the breakpoint's fileName, AND there is no - * inner function that has matching line numbers - * (otherwise a breakpoint would be triggered both - * inside and outside of the inner function which would - * be confusing). Example: - * - * function foo() { - * print('foo'); - * function bar() { <-. breakpoints in these - * print('bar'); | lines should not affect - * } <-' foo() execution - * bar(); - * } - * - * We need a few things that are only available when - * debugger support is enabled: (1) a line range for - * each function, and (2) access to the function - * template to access the inner functions (and their - * line ranges). - * - * It's important to have a narrow match for active - * breakpoints so that we don't enter checked execution - * when that's not necessary. For instance, if we're - * running inside a certain function and there's - * breakpoint outside in (after the call site), we - * don't want to slow down execution of the function. - */ - - for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) { - duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx; - duk_hobject **funcs, **funcs_end; - duk_hcompfunc *inner_fun; - duk_bool_t bp_match; - - if (bp->filename == filename && - bp->line >= fun->start_line && bp->line <= fun->end_line) { - bp_match = 1; - DUK_DD(DUK_DDPRINT("breakpoint filename and line match: " - "%s:%ld vs. %s (line %ld vs. %ld-%ld)", - DUK_HSTRING_GET_DATA(bp->filename), - (long) bp->line, - DUK_HSTRING_GET_DATA(filename), - (long) bp->line, - (long) fun->start_line, - (long) fun->end_line)); - - funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun); - funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, fun); - while (funcs != funcs_end) { - inner_fun = (duk_hcompfunc *) *funcs; - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) inner_fun)); - if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) { - DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint")); - bp_match = 0; - break; - } - funcs++; - } - - if (bp_match) { - /* No need to check for size of bp_active list, - * it's always larger than maximum number of - * breakpoints. - */ - act->flags |= DUK_ACT_FLAG_BREAKPOINT_ACTIVE; - *bp_active = heap->dbg_breakpoints + bp_idx; - bp_active++; - } - } - } - } - - *bp_active = NULL; /* terminate */ - - DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active))); - - /* Force pause if we were doing "step into" in another activation. */ - if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) && - thr->heap->dbg_pause_act != thr->callstack_curr) { - DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry")); - duk_debug_set_paused(thr->heap); - } - - /* Force interrupt right away if we're paused or in "checked mode". - * Step out is handled by callstack unwind. - */ - if ((act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE) || - DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || - ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) && - thr->heap->dbg_pause_act == thr->callstack_curr)) { - /* We'll need to interrupt early so recompute the init - * counter to reflect the number of bytecode instructions - * executed so that step counts for e.g. debugger rate - * limiting are accurate. - */ - DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); - thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter; - thr->interrupt_counter = 0; - } -} -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -/* - * Opcode handlers for opcodes with a lot of code and which are relatively - * rare; NOINLINE to reduce amount of code in main bytecode dispatcher. - */ - -DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_initset_initget(duk_hthread *thr, duk_uint_fast32_t ins) { - duk_bool_t is_set = (DUK_DEC_OP(ins) == DUK_OP_INITSET); - duk_uint_fast_t idx; - duk_uint_t defprop_flags; - - /* A -> object register (acts as a source) - * BC -> BC+0 contains key, BC+1 closure (value) - */ - - /* INITSET/INITGET are only used to initialize object literal keys. - * There may be a previous propery in ES2015 because duplicate property - * names are allowed. - */ - - /* This could be made more optimal by accessing internals directly. */ - - idx = (duk_uint_fast_t) DUK_DEC_BC(ins); - duk_dup(thr, (duk_idx_t) (idx + 0)); /* key */ - duk_dup(thr, (duk_idx_t) (idx + 1)); /* getter/setter */ - if (is_set) { - defprop_flags = DUK_DEFPROP_HAVE_SETTER | - DUK_DEFPROP_FORCE | - DUK_DEFPROP_SET_ENUMERABLE | - DUK_DEFPROP_SET_CONFIGURABLE; - } else { - defprop_flags = DUK_DEFPROP_HAVE_GETTER | - DUK_DEFPROP_FORCE | - DUK_DEFPROP_SET_ENUMERABLE | - DUK_DEFPROP_SET_CONFIGURABLE; - } - duk_def_prop(thr, (duk_idx_t) DUK_DEC_A(ins), defprop_flags); -} - -DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_trycatch(duk_hthread *thr, duk_uint_fast32_t ins, duk_instr_t *curr_pc) { - duk_activation *act; - duk_catcher *cat; - duk_tval *tv1; - duk_small_uint_fast_t a; - duk_small_uint_fast_t bc; - - /* A -> flags - * BC -> reg_catch; base register for two registers used both during - * trycatch setup and when catch is triggered - * - * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set: - * reg_catch + 0: catch binding variable name (string). - * Automatic declarative environment is established for - * the duration of the 'catch' clause. - * - * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set: - * reg_catch + 0: with 'target value', which is coerced to - * an object and then used as a bindind object for an - * environment record. The binding is initialized here, for - * the 'try' clause. - * - * Note that a TRYCATCH generated for a 'with' statement has no - * catch or finally parts. - */ - - /* XXX: TRYCATCH handling should be reworked to avoid creating - * an explicit scope unless it is actually needed (e.g. function - * instances or eval is executed inside the catch block). This - * rework is not trivial because the compiler doesn't have an - * intermediate representation. When the rework is done, the - * opcode format can also be made more straightforward. - */ - - /* XXX: side effect handling is quite awkward here */ - - DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, " - "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)", - (long) DUK_DEC_BC(ins), - (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0), - (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0), - (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0), - (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0), - (unsigned long) DUK_DEC_A(ins))); - - a = DUK_DEC_A(ins); - bc = DUK_DEC_BC(ins); - - /* Registers 'bc' and 'bc + 1' are written in longjmp handling - * and if their previous values (which are temporaries) become - * unreachable -and- have a finalizer, there'll be a function - * call during error handling which is not supported now (GH-287). - * Ensure that both 'bc' and 'bc + 1' have primitive values to - * guarantee no finalizer calls in error handling. Scrubbing also - * ensures finalizers for the previous values run here rather than - * later. Error handling related values are also written to 'bc' - * and 'bc + 1' but those values never become unreachable during - * error handling, so there's no side effect problem even if the - * error value has a finalizer. - */ - duk_dup(thr, (duk_idx_t) bc); /* Stabilize value. */ - duk_to_undefined(thr, (duk_idx_t) bc); - duk_to_undefined(thr, (duk_idx_t) (bc + 1)); - - /* Allocate catcher and populate it. Doesn't have to - * be fully atomic, but the catcher must be in a - * consistent state if side effects (such as finalizer - * calls) occur. - */ - - cat = duk_hthread_catcher_alloc(thr); - DUK_ASSERT(cat != NULL); - - cat->flags = DUK_CAT_TYPE_TCF; - cat->h_varname = NULL; - cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ - cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - cat->parent = act->cat; - act->cat = cat; - - if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) { - cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED; - } - if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) { - cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; - } - if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) { - DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher")); - cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; - tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); - - /* borrowed reference; although 'tv1' comes from a register, - * its value was loaded using LDCONST so the constant will - * also exist and be reachable. - */ - cat->h_varname = DUK_TVAL_GET_STRING(tv1); - } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - duk_hobjenv *env; - duk_hobject *target; - - /* Delayed env initialization for activation (if needed). */ - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - if (act->lex_env == NULL) { - DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); - DUK_ASSERT(act->var_env == NULL); - - duk_js_init_activation_environment_records_delayed(thr, act); - DUK_ASSERT(act == thr->callstack_curr); - DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ - } - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - - /* Coerce 'with' target. */ - target = duk_to_hobject(thr, -1); - DUK_ASSERT(target != NULL); - - /* Create an object environment; it is not pushed - * so avoid side effects very carefully until it is - * referenced. - */ - env = duk_hobjenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); - DUK_ASSERT(env != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); - env->target = target; /* always provideThis=true */ - DUK_HOBJECT_INCREF(thr, target); - env->has_this = 1; - DUK_ASSERT_HOBJENV_VALID(env); - DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env)); - - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); - DUK_ASSERT(act->lex_env != NULL); - DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env); - act->lex_env = (duk_hobject *) env; /* Now reachable. */ - DUK_HOBJECT_INCREF(thr, (duk_hobject *) env); - /* Net refcount change to act->lex_env is 0: incref for env's - * prototype, decref for act->lex_env overwrite. - */ - - /* Set catcher lex_env active (affects unwind) - * only when the whole setup is complete. - */ - cat = act->cat; /* XXX: better to relookup? not mandatory because 'cat' is stable */ - cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; - } else { - ; - } - - DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, pc_base=%ld, " - "idx_base=%ld, h_varname=%!O", - (unsigned long) cat->flags, - (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname)); - - duk_pop_unsafe(thr); -} - -DUK_LOCAL DUK__NOINLINE_PERF duk_instr_t *duk__handle_op_endtry(duk_hthread *thr, duk_uint_fast32_t ins) { - duk_activation *act; - duk_catcher *cat; - duk_tval *tv1; - duk_instr_t *pc_base; - - DUK_UNREF(ins); - - DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - cat = act->cat; - DUK_ASSERT(cat != NULL); - DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF); - - DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)")); - DUK_CAT_CLEAR_CATCH_ENABLED(cat); - - pc_base = cat->pc_base; - - if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) { - DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'")); - - tv1 = thr->valstack + cat->idx_base; - DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */ - tv1 = NULL; - - tv1 = thr->valstack + cat->idx_base + 1; - DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); - DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */ - tv1 = NULL; - - DUK_CAT_CLEAR_FINALLY_ENABLED(cat); - } else { - DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)")); - - duk_hthread_catcher_unwind_norz(thr, act); /* lexenv may be set for 'with' binding */ - /* no need to unwind callstack */ - } - - return pc_base + 1; /* new curr_pc value */ -} - -DUK_LOCAL DUK__NOINLINE_PERF duk_instr_t *duk__handle_op_endcatch(duk_hthread *thr, duk_uint_fast32_t ins) { - duk_activation *act; - duk_catcher *cat; - duk_tval *tv1; - duk_instr_t *pc_base; - - DUK_UNREF(ins); - - DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - cat = act->cat; - DUK_ASSERT(cat != NULL); - DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */ - - if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) { - duk_hobject *prev_env; - - /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */ - DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)); - DUK_ASSERT(act->lex_env != NULL); - - DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment")); - - prev_env = act->lex_env; - DUK_ASSERT(prev_env != NULL); - act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env); - DUK_CAT_CLEAR_LEXENV_ACTIVE(cat); - DUK_HOBJECT_INCREF(thr, act->lex_env); - DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */ - - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - } - - pc_base = cat->pc_base; - - if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) { - DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'")); - - tv1 = thr->valstack + cat->idx_base; - DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */ - tv1 = NULL; - - tv1 = thr->valstack + cat->idx_base + 1; - DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); - DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */ - tv1 = NULL; - - DUK_CAT_CLEAR_FINALLY_ENABLED(cat); - } else { - DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)")); - - duk_hthread_catcher_unwind_norz(thr, act); - /* no need to unwind callstack */ - } - - return pc_base + 1; /* new curr_pc value */ -} - -DUK_LOCAL DUK__NOINLINE_PERF duk_small_uint_t duk__handle_op_endfin(duk_hthread *thr, duk_uint_fast32_t ins, duk_activation *entry_act) { - duk_activation *act; - duk_tval *tv1; - duk_uint_t reg_catch; - duk_small_uint_t cont_type; - duk_small_uint_t ret_result; - - DUK_ASSERT(thr->ptr_curr_pc == NULL); - DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - reg_catch = DUK_DEC_ABC(ins); - - /* CATCH flag may be enabled or disabled here; it may be enabled if - * the statement has a catch block but the try block does not throw - * an error. - */ - - DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T", - (duk_tval *) (thr->valstack_bottom + reg_catch + 0), - (duk_tval *) (thr->valstack_bottom + reg_catch + 1))); - - tv1 = thr->valstack_bottom + reg_catch + 1; /* type */ - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); - cont_type = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1); -#else - cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1); -#endif - - tv1--; /* value */ - - switch (cont_type) { - case DUK_LJ_TYPE_NORMAL: { - DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> " - "dismantle catcher, resume execution after ENDFIN")); - - duk_hthread_catcher_unwind_norz(thr, act); - /* no need to unwind callstack */ - return 0; /* restart execution */ - } - case DUK_LJ_TYPE_RETURN: { - DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle " - "catcher, handle return, lj.value1=%!T", tv1)); - - /* Not necessary to unwind catch stack: return handling will - * do it. The finally flag of 'cat' is no longer set. The - * catch flag may be set, but it's not checked by return handling. - */ - - duk_push_tval(thr, tv1); - ret_result = duk__handle_return(thr, entry_act); - if (ret_result == DUK__RETHAND_RESTART) { - return 0; /* restart execution */ - } - DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED); - - DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type")); - return 1; /* exit executor */ - } - case DUK_LJ_TYPE_BREAK: - case DUK_LJ_TYPE_CONTINUE: { - duk_uint_t label_id; - duk_small_uint_t lj_type; - - /* Not necessary to unwind catch stack: break/continue - * handling will do it. The finally flag of 'cat' is - * no longer set. The catch flag may be set, but it's - * not checked by break/continue handling. - */ - - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); - label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1); -#else - label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1); -#endif - lj_type = cont_type; - duk__handle_break_or_continue(thr, label_id, lj_type); - return 0; /* restart execution */ - } - default: { - DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> " - "dismantle catcher, re-throw error", - (long) cont_type)); - - duk_err_setup_ljstate1(thr, (duk_small_uint_t) cont_type, tv1); - /* No debugger Throw notify check on purpose (rethrow). */ - - DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ - duk_err_longjmp(thr); - DUK_UNREACHABLE(); - } - } - - DUK_UNREACHABLE(); - return 0; -} - -DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_initenum(duk_hthread *thr, duk_uint_fast32_t ins) { - duk_small_uint_t b; - duk_small_uint_t c; - - /* - * Enumeration semantics come from for-in statement, E5 Section 12.6.4. - * If called with 'null' or 'undefined', this opcode returns 'null' as - * the enumerator, which is special cased in NEXTENUM. This simplifies - * the compiler part - */ - - /* B -> register for writing enumerator object - * C -> value to be enumerated (register) - */ - b = DUK_DEC_B(ins); - c = DUK_DEC_C(ins); - - if (duk_is_null_or_undefined(thr, (duk_idx_t) c)) { - duk_push_null(thr); - duk_replace(thr, (duk_idx_t) b); - } else { - duk_dup(thr, (duk_idx_t) c); - duk_to_object(thr, -1); - duk_hobject_enumerator_create(thr, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */ - duk_replace(thr, (duk_idx_t) b); - } -} - -DUK_LOCAL DUK__NOINLINE_PERF duk_small_uint_t duk__handle_op_nextenum(duk_hthread *thr, duk_uint_fast32_t ins) { - duk_small_uint_t b; - duk_small_uint_t c; - duk_small_uint_t pc_skip = 0; - - /* - * NEXTENUM checks whether the enumerator still has unenumerated - * keys. If so, the next key is loaded to the target register - * and the next instruction is skipped. Otherwise the next instruction - * will be executed, jumping out of the enumeration loop. - */ - - /* B -> target register for next key - * C -> enum register - */ - b = DUK_DEC_B(ins); - c = DUK_DEC_C(ins); - - DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T", - (duk_tval *) duk_get_tval(thr, (duk_idx_t) b), - (duk_tval *) duk_get_tval(thr, (duk_idx_t) c))); - - if (duk_is_object(thr, (duk_idx_t) c)) { - /* XXX: assert 'c' is an enumerator */ - duk_dup(thr, (duk_idx_t) c); - if (duk_hobject_enumerator_next(thr, 0 /*get_value*/)) { - /* [ ... enum ] -> [ ... next_key ] */ - DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ", - (duk_tval *) duk_get_tval(thr, -1))); - pc_skip = 1; - } else { - /* [ ... enum ] -> [ ... ] */ - DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot")); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ - thr->valstack_top++; - } - duk_replace(thr, (duk_idx_t) b); - } else { - /* 'null' enumerator case -> behave as with an empty enumerator */ - DUK_ASSERT(duk_is_null(thr, (duk_idx_t) c)); - DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot")); - } - - return pc_skip; -} - -/* - * Call handling helpers. - */ - -DUK_LOCAL duk_bool_t duk__executor_handle_call(duk_hthread *thr, duk_idx_t idx, duk_idx_t nargs, duk_small_uint_t call_flags) { - duk_bool_t rc; - - duk_set_top_unsafe(thr, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */ - - /* Attempt an Ecma-to-Ecma call setup. If the call - * target is (directly or indirectly) Reflect.construct(), - * the call may change into a constructor call on the fly. - */ - rc = (duk_bool_t) duk_handle_call_unprotected(thr, idx, call_flags); - if (rc != 0) { - /* Ecma-to-ecma call possible, may or may not - * be a tail call. Avoid C recursion by - * reusing current executor instance. - */ - DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution")); - /* curr_pc synced by duk_handle_call_unprotected() */ - DUK_ASSERT(thr->ptr_curr_pc == NULL); - return rc; - } else { - /* Call was handled inline. */ - } - DUK_ASSERT(thr->ptr_curr_pc != NULL); - return rc; -} - -/* - * Ecmascript bytecode executor. - * - * Resume execution for the current thread from its current activation. - * Returns when execution would return from the entry level activation, - * leaving a single return value on top of the stack. Function calls - * and thread resumptions are handled internally. If an error occurs, - * a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level - * setjmp() jmpbuf. - * - * Ecmascript function calls and coroutine resumptions are handled - * internally (by the outer executor function) without recursive C calls. - * Other function calls are handled using duk_handle_call(), increasing - * C recursion depth. - * - * Abrupt completions (= long control tranfers) are handled either - * directly by reconfiguring relevant stacks and restarting execution, - * or via a longjmp. Longjmp-free handling is preferable for performance - * (especially Emscripten performance), and is used for: break, continue, - * and return. - * - * For more detailed notes, see doc/execution.rst. - * - * Also see doc/code-issues.rst for discussion of setjmp(), longjmp(), - * and volatile. - */ - -/* Presence of 'fun' is config based, there's a marginal performance - * difference and the best option is architecture dependent. - */ -#if defined(DUK_USE_EXEC_FUN_LOCAL) -#define DUK__FUN() fun -#else -#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr)) -#endif - -/* Strict flag. */ -#define DUK__STRICT() ((duk_small_uint_t) DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN())) - -/* Reg/const access macros: these are very footprint and performance sensitive - * so modify with care. Arguments are sometimes evaluated multiple times which - * is not ideal. - */ -#define DUK__REG(x) (*(thr->valstack_bottom + (x))) -#define DUK__REGP(x) (thr->valstack_bottom + (x)) -#define DUK__CONST(x) (*(consts + (x))) -#define DUK__CONSTP(x) (consts + (x)) - -/* Reg/const access macros which take the 32-bit instruction and avoid an - * explicit field decoding step by using shifts and masks. These must be - * kept in sync with duk_js_bytecode.h. The shift/mask values are chosen - * so that 'ins' can be shifted and masked and used as a -byte- offset - * instead of a duk_tval offset which needs further shifting (which is an - * issue on some, but not all, CPUs). - */ -#define DUK__RCBIT_B DUK_BC_REGCONST_B -#define DUK__RCBIT_C DUK_BC_REGCONST_C -#if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE) -#if defined(DUK_USE_PACKED_TVAL) -#define DUK__TVAL_SHIFT 3 /* sizeof(duk_tval) == 8 */ -#else -#define DUK__TVAL_SHIFT 4 /* sizeof(duk_tval) == 16; not always the case so also asserted for */ -#endif -#define DUK__SHIFT_A (DUK_BC_SHIFT_A - DUK__TVAL_SHIFT) -#define DUK__SHIFT_B (DUK_BC_SHIFT_B - DUK__TVAL_SHIFT) -#define DUK__SHIFT_C (DUK_BC_SHIFT_C - DUK__TVAL_SHIFT) -#define DUK__SHIFT_BC (DUK_BC_SHIFT_BC - DUK__TVAL_SHIFT) -#define DUK__MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK__TVAL_SHIFT) -#define DUK__MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK__TVAL_SHIFT) -#define DUK__MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK__TVAL_SHIFT) -#define DUK__MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK__TVAL_SHIFT) -#define DUK__BYTEOFF_A(ins) (((ins) >> DUK__SHIFT_A) & DUK__MASK_A) -#define DUK__BYTEOFF_B(ins) (((ins) >> DUK__SHIFT_B) & DUK__MASK_B) -#define DUK__BYTEOFF_C(ins) (((ins) >> DUK__SHIFT_C) & DUK__MASK_C) -#define DUK__BYTEOFF_BC(ins) (((ins) >> DUK__SHIFT_BC) & DUK__MASK_BC) - -#define DUK__REGP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_A((ins)))) -#define DUK__REGP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_B((ins)))) -#define DUK__REGP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_C((ins)))) -#define DUK__REGP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_BC((ins)))) -#define DUK__CONSTP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_A((ins)))) -#define DUK__CONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_B((ins)))) -#define DUK__CONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_C((ins)))) -#define DUK__CONSTP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_BC((ins)))) -#define DUK__REGCONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_B((ins)))) -#define DUK__REGCONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_C((ins)))) -#else /* DUK_USE_EXEC_REGCONST_OPTIMIZE */ -/* Safe alternatives, no assumption about duk_tval size. */ -#define DUK__REGP_A(ins) DUK__REGP(DUK_DEC_A((ins))) -#define DUK__REGP_B(ins) DUK__REGP(DUK_DEC_B((ins))) -#define DUK__REGP_C(ins) DUK__REGP(DUK_DEC_C((ins))) -#define DUK__REGP_BC(ins) DUK__REGP(DUK_DEC_BC((ins))) -#define DUK__CONSTP_A(ins) DUK__CONSTP(DUK_DEC_A((ins))) -#define DUK__CONSTP_B(ins) DUK__CONSTP(DUK_DEC_B((ins))) -#define DUK__CONSTP_C(ins) DUK__CONSTP(DUK_DEC_C((ins))) -#define DUK__CONSTP_BC(ins) DUK__CONSTP(DUK_DEC_BC((ins))) -#define DUK__REGCONSTP_B(ins) ((((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK_DEC_B((ins))) -#define DUK__REGCONSTP_C(ins) ((((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK_DEC_C((ins))) -#endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */ - -#if defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS) -#define DUK__INTERNAL_ERROR(msg) do { \ - DUK_ERROR_ERROR(thr, (msg)); \ - } while (0) -#else -#define DUK__INTERNAL_ERROR(msg) do { \ - goto internal_error; \ - } while (0) -#endif - -#define DUK__SYNC_CURR_PC() do { \ - duk_activation *duk__act; \ - duk__act = thr->callstack_curr; \ - duk__act->curr_pc = curr_pc; \ - } while (0) -#define DUK__SYNC_AND_NULL_CURR_PC() do { \ - duk_activation *duk__act; \ - duk__act = thr->callstack_curr; \ - duk__act->curr_pc = curr_pc; \ - thr->ptr_curr_pc = NULL; \ - } while (0) - -#if defined(DUK_USE_EXEC_PREFER_SIZE) -#define DUK__LOOKUP_INDIRECT(idx) do { \ - (idx) = (duk_uint_fast_t) duk_get_uint(thr, (duk_idx_t) (idx)); \ - } while (0) -#elif defined(DUK_USE_FASTINT) -#define DUK__LOOKUP_INDIRECT(idx) do { \ - duk_tval *tv_ind; \ - tv_ind = DUK__REGP((idx)); \ - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \ - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_ind)); /* compiler guarantees */ \ - (idx) = (duk_uint_fast_t) DUK_TVAL_GET_FASTINT_U32(tv_ind); \ - } while (0) -#else -#define DUK__LOOKUP_INDIRECT(idx) do { \ - duk_tval *tv_ind; \ - tv_ind = DUK__REGP(idx); \ - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \ - idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind); \ - } while (0) -#endif - -DUK_LOCAL void duk__handle_executor_error(duk_heap *heap, - duk_activation *entry_act, - duk_int_t entry_call_recursion_depth, - duk_jmpbuf *entry_jmpbuf_ptr) { - duk_small_uint_t lj_ret; - - /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc - * before longjmp. - */ - DUK_ASSERT(heap->curr_thread != NULL); - DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL); - - /* XXX: signalling the need to shrink check (only if unwound) */ - - /* Must be restored here to handle e.g. yields properly. */ - heap->call_recursion_depth = entry_call_recursion_depth; - - /* Switch to caller's setjmp() catcher so that if an error occurs - * during error handling, it is always propagated outwards instead - * of causing an infinite loop in our own handler. - */ - heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr; - - lj_ret = duk__handle_longjmp(heap->curr_thread, entry_act); - - /* Error handling complete, remove side effect protections. - */ -#if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(heap->error_not_allowed == 1); - heap->error_not_allowed = 0; -#endif - DUK_ASSERT(heap->pf_prevent_count > 0); - heap->pf_prevent_count--; - DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld", (long) heap->pf_prevent_count)); - - if (lj_ret == DUK__LONGJMP_RESTART) { - /* Restart bytecode execution, possibly with a changed thread. */ - DUK_REFZERO_CHECK_SLOW(heap->curr_thread); - } else { - /* If an error is propagated, don't run refzero checks here. - * The next catcher will deal with that. Pf_prevent_count - * will be re-bumped by the longjmp. - */ - - DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); /* Rethrow error to calling state. */ - DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); /* Longjmp handling has restored jmpbuf_ptr. */ - - /* Thread may have changed, e.g. YIELD converted to THROW. */ - duk_err_longjmp(heap->curr_thread); - DUK_UNREACHABLE(); - } -} - -/* Outer executor with setjmp/longjmp handling. */ -DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) { - /* Entry level info. */ - duk_hthread *entry_thread; - duk_activation *entry_act; - duk_int_t entry_call_recursion_depth; - duk_jmpbuf *entry_jmpbuf_ptr; - duk_jmpbuf our_jmpbuf; - duk_heap *heap; - - DUK_ASSERT(exec_thr != NULL); - DUK_ASSERT(exec_thr->heap != NULL); - DUK_ASSERT(exec_thr->heap->curr_thread != NULL); - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr); - DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */ - DUK_ASSERT(exec_thr->callstack_curr != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr))); - - DUK_GC_TORTURE(exec_thr->heap); - - entry_thread = exec_thr; - heap = entry_thread->heap; - entry_act = entry_thread->callstack_curr; - DUK_ASSERT(entry_act != NULL); - entry_call_recursion_depth = entry_thread->heap->call_recursion_depth; - entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr; - - /* - * Note: we currently assume that the setjmp() catchpoint is - * not re-entrant (longjmp() cannot be called more than once - * for a single setjmp()). - * - * See doc/code-issues.rst for notes on variable assignment - * before and after setjmp(). - */ - - for (;;) { - heap->lj.jmpbuf_ptr = &our_jmpbuf; - DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL); - -#if defined(DUK_USE_CPP_EXCEPTIONS) - try { -#else - DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf); - if (DUK_SETJMP(our_jmpbuf.jb) == 0) { -#endif - /* Execute bytecode until returned or longjmp(). */ - duk__js_execute_bytecode_inner(entry_thread, entry_act); - - /* Successful return: restore jmpbuf and return to caller. */ - heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr; - - return; -#if defined(DUK_USE_CPP_EXCEPTIONS) - } catch (duk_internal_exception &exc) { -#else - } else { -#endif -#if defined(DUK_USE_CPP_EXCEPTIONS) - DUK_UNREF(exc); -#endif - DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor")); - DUK_STATS_INC(exec_thr->heap, stats_exec_throw); - - duk__handle_executor_error(heap, - entry_act, - entry_call_recursion_depth, - entry_jmpbuf_ptr); - } -#if defined(DUK_USE_CPP_EXCEPTIONS) - catch (std::exception &exc) { - const char *what = exc.what(); - if (!what) { - what = "unknown"; - } - DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)")); - DUK_STATS_INC(exec_thr->heap, stats_exec_throw); - try { - DUK_ASSERT(heap->curr_thread != NULL); - DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what); - } catch (duk_internal_exception exc) { - DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception")); - DUK_UNREF(exc); - duk__handle_executor_error(heap, - entry_act, - entry_call_recursion_depth, - entry_jmpbuf_ptr); - } - } catch (...) { - DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)")); - DUK_STATS_INC(exec_thr->heap, stats_exec_throw); - try { - DUK_ASSERT(heap->curr_thread != NULL); - DUK_ERROR_TYPE(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)"); - } catch (duk_internal_exception exc) { - DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception")); - DUK_UNREF(exc); - duk__handle_executor_error(heap, - entry_act, - entry_call_recursion_depth, - entry_jmpbuf_ptr); - } - } -#endif - } - - DUK_UNREACHABLE(); -} - -/* Inner executor, performance critical. */ -DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act) { - /* Current PC, accessed by other functions through thr->ptr_to_curr_pc. - * Critical for performance. It would be safest to make this volatile, - * but that eliminates performance benefits; aliasing guarantees - * should be enough though. - */ - duk_instr_t *curr_pc; /* bytecode has a stable pointer */ - - /* Hot variables for interpretation. Critical for performance, - * but must add sparingly to minimize register shuffling. - */ - duk_hthread *thr; /* stable */ - duk_tval *consts; /* stable */ - duk_uint_fast32_t ins; - /* 'funcs' is quite rarely used, so no local for it */ -#if defined(DUK_USE_EXEC_FUN_LOCAL) - duk_hcompfunc *fun; -#else - /* 'fun' is quite rarely used, so no local for it */ -#endif - -#if defined(DUK_USE_INTERRUPT_COUNTER) - duk_int_t int_ctr; -#endif - -#if defined(DUK_USE_ASSERTIONS) - duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */ -#endif - - /* Optimized reg/const access macros assume sizeof(duk_tval) to be - * either 8 or 16. Heap allocation checks this even without asserts - * enabled now because it can't be autodetected in duk_config.h. - */ -#if 1 -#if defined(DUK_USE_PACKED_TVAL) - DUK_ASSERT(sizeof(duk_tval) == 8); -#else - DUK_ASSERT(sizeof(duk_tval) == 16); -#endif -#endif - - DUK_GC_TORTURE(entry_thread->heap); - - /* - * Restart execution by reloading thread state. - * - * Note that 'thr' and any thread configuration may have changed, - * so all local variables are suspect and we need to reinitialize. - * - * The number of local variables should be kept to a minimum: if - * the variables are spilled, they will need to be loaded from - * memory anyway. - * - * Any 'goto restart_execution;' code path in opcode dispatch must - * ensure 'curr_pc' is synced back to act->curr_pc before the goto - * takes place. - * - * The interpreter must be very careful with memory pointers, as - * many pointers are not guaranteed to be 'stable' and may be - * reallocated and relocated on-the-fly quite easily (e.g. by a - * memory allocation or a property access). - * - * The following are assumed to have stable pointers: - * - the current thread - * - the current function - * - the bytecode, constant table, inner function table of the - * current function (as they are a part of the function allocation) - * - * The following are assumed to have semi-stable pointers: - * - the current activation entry: stable as long as callstack - * is not changed (reallocated by growing or shrinking), or - * by any garbage collection invocation (through finalizers) - * - Note in particular that ANY DECREF can invalidate the - * activation pointer, so for the most part a fresh lookup - * is required - * - * The following are not assumed to have stable pointers at all: - * - the value stack (registers) of the current thread - * - * See execution.rst for discussion. - */ - - restart_execution: - - /* Lookup current thread; use the stable 'entry_thread' for this to - * avoid clobber warnings. Any valid, reachable 'thr' value would be - * fine for this, so using 'entry_thread' is just to silence warnings. - */ - thr = entry_thread->heap->curr_thread; - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(thr->callstack_curr != NULL); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); - - DUK_GC_TORTURE(thr->heap); - - thr->ptr_curr_pc = &curr_pc; - - /* Relookup and initialize dispatch loop variables. Debugger check. */ - { - duk_activation *act; -#if !defined(DUK_USE_EXEC_FUN_LOCAL) - duk_hcompfunc *fun; -#endif - - /* Assume interrupt init/counter are properly initialized here. */ - /* Assume that thr->valstack_bottom has been set-up before getting here. */ - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); - DUK_ASSERT(fun != NULL); - DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs); - consts = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, fun); - DUK_ASSERT(consts != NULL); - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_UNLIKELY(duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing)) { - duk__executor_recheck_debugger(thr, act, fun); - DUK_ASSERT(act == thr->callstack_curr); - DUK_ASSERT(act != NULL); - } -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - -#if defined(DUK_USE_ASSERTIONS) - valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack); -#endif - - /* Set up curr_pc for opcode dispatch. */ - curr_pc = act->curr_pc; - } - - DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p," - "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, " - "preventcount=%ld", - (void *) thr, - (long) (thr->callstack_top - 1), - (void *) DUK__FUN(), - (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, DUK__FUN()), - (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, DUK__FUN()), - (long) (thr->callstack_top - 1), - (long) (thr->valstack_bottom - thr->valstack), - (long) (thr->valstack_top - thr->valstack), - (long) thr->callstack_preventcount)); - - /* Dispatch loop. */ - - for (;;) { - duk_uint8_t op; - - DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs); - DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base); - - /* Executor interrupt counter check, used to implement breakpoints, - * debugging interface, execution timeouts, etc. The counter is heap - * specific but is maintained in the current thread to make the check - * as fast as possible. The counter is copied back to the heap struct - * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro. - */ -#if defined(DUK_USE_INTERRUPT_COUNTER) - int_ctr = thr->interrupt_counter; - if (DUK_LIKELY(int_ctr > 0)) { - thr->interrupt_counter = int_ctr - 1; - } else { - /* Trigger at zero or below */ - duk_small_uint_t exec_int_ret; - - DUK_STATS_INC(thr->heap, stats_exec_interrupt); - - /* Write curr_pc back for the debugger. */ - { - duk_activation *act; - DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - act->curr_pc = (duk_instr_t *) curr_pc; - } - - /* Forced restart caused by a function return; must recheck - * debugger breakpoints before checking line transitions, - * see GH-303. Restart and then handle interrupt_counter - * zero again. - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (thr->heap->dbg_force_restart) { - DUK_DD(DUK_DDPRINT("dbg_force_restart flag forced restart execution")); /* GH-303 */ - thr->heap->dbg_force_restart = 0; - goto restart_execution; - } -#endif - - exec_int_ret = duk__executor_interrupt(thr); - if (exec_int_ret == DUK__INT_RESTART) { - /* curr_pc synced back above */ - goto restart_execution; - } - } -#endif /* DUK_USE_INTERRUPT_COUNTER */ -#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) - /* For cross-checking during development: ensure dispatch count - * matches cumulative interrupt counter init value sums. - */ - thr->heap->inst_count_exec++; -#endif - -#if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG) - { - duk_activation *act; - act = thr->callstack_curr; - DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())); - DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN())); - DUK_UNREF(act); /* if debugging disabled */ - - DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I", - (long) (curr_pc - DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())), - (unsigned long) *curr_pc, - (long) DUK_DEC_OP(*curr_pc), - (long) (thr->valstack_top - thr->valstack), - (long) (thr->valstack_end - thr->valstack), - (long) (DUK__FUN() ? DUK__FUN()->nregs : -1), - (duk_instr_t) *curr_pc)); - } -#endif - -#if defined(DUK_USE_ASSERTIONS) - /* Quite heavy assert: check valstack policy. Improper - * shuffle instructions can write beyond valstack_top/end - * so this check catches them in the act. - */ - { - duk_tval *tv; - tv = thr->valstack_top; - while (tv != thr->valstack_end) { - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); - tv++; - } - } -#endif - - ins = *curr_pc++; - DUK_STATS_INC(thr->heap, stats_exec_opcodes); - - /* Typing: use duk_small_(u)int_fast_t when decoding small - * opcode fields (op, A, B, C, BC) which fit into 16 bits - * and duk_(u)int_fast_t when decoding larger fields (e.g. - * ABC). Use unsigned variant by default, signed when the - * value is used in signed arithmetic. Using variable names - * such as 'a', 'b', 'c', 'bc', etc makes it easier to spot - * typing mismatches. - */ - - /* Switch based on opcode. Cast to 8-bit unsigned value and - * use a fully populated case clauses so that the compiler - * will (at least usually) omit a bounds check. - */ - op = (duk_uint8_t) DUK_DEC_OP(ins); - switch (op) { - - /* Some useful macros. These access inner executor variables - * directly so they only apply within the executor. - */ -#if defined(DUK_USE_EXEC_PREFER_SIZE) -#define DUK__REPLACE_TOP_A_BREAK() { goto replace_top_a; } -#define DUK__REPLACE_TOP_BC_BREAK() { goto replace_top_bc; } -#define DUK__REPLACE_BOOL_A_BREAK(bval) { \ - duk_bool_t duk__bval; \ - duk__bval = (bval); \ - DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \ - duk_push_boolean(thr, duk__bval); \ - DUK__REPLACE_TOP_A_BREAK(); \ - } -#else -#define DUK__REPLACE_TOP_A_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins)); break; } -#define DUK__REPLACE_TOP_BC_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins)); break; } -#define DUK__REPLACE_BOOL_A_BREAK(bval) { \ - duk_bool_t duk__bval; \ - duk_tval *duk__tvdst; \ - duk__bval = (bval); \ - DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \ - duk__tvdst = DUK__REGP_A(ins); \ - DUK_TVAL_SET_BOOLEAN_UPDREF(thr, duk__tvdst, duk__bval); \ - break; \ - } -#endif - - /* XXX: 12 + 12 bit variant might make sense too, for both reg and - * const loads. - */ - - /* For LDREG, STREG, LDCONST footprint optimized variants would just - * duk_dup() + duk_replace(), but because they're used quite a lot - * they're currently intentionally not size optimized. - */ - case DUK_OP_LDREG: { - duk_tval *tv1, *tv2; - - tv1 = DUK__REGP_A(ins); - tv2 = DUK__REGP_BC(ins); - DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */ - break; - } - - case DUK_OP_STREG: { - duk_tval *tv1, *tv2; - - tv1 = DUK__REGP_A(ins); - tv2 = DUK__REGP_BC(ins); - DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1); /* side effects */ - break; - } - - case DUK_OP_LDCONST: { - duk_tval *tv1, *tv2; - - tv1 = DUK__REGP_A(ins); - tv2 = DUK__CONSTP_BC(ins); - DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */ - break; - } - - /* LDINT and LDINTX are intended to load an arbitrary signed - * 32-bit value. Only an LDINT+LDINTX sequence is supported. - * This also guarantees all values remain fastints. - */ -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_LDINT: { - duk_int32_t val; - - val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS; - duk_push_int(thr, val); - DUK__REPLACE_TOP_A_BREAK(); - } - case DUK_OP_LDINTX: { - duk_int32_t val; - - val = (duk_int32_t) duk_get_int(thr, DUK_DEC_A(ins)); - val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */ - duk_push_int(thr, val); - DUK__REPLACE_TOP_A_BREAK(); - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_LDINT: { - duk_tval *tv1; - duk_int32_t val; - - val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS; - tv1 = DUK__REGP_A(ins); - DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */ - break; - } - case DUK_OP_LDINTX: { - duk_tval *tv1; - duk_int32_t val; - - tv1 = DUK__REGP_A(ins); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); - val = DUK_TVAL_GET_FASTINT_I32(tv1); -#else - /* XXX: fast double-to-int conversion, we know number is integer in [-0x80000000,0xffffffff]. */ - val = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv1); -#endif - val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */ - DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */ - break; - } -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_LDTHIS: { - duk_push_this(thr); - DUK__REPLACE_TOP_BC_BREAK(); - } - case DUK_OP_LDUNDEF: { - duk_to_undefined(thr, (duk_idx_t) DUK_DEC_BC(ins)); - break; - } - case DUK_OP_LDNULL: { - duk_to_null(thr, (duk_idx_t) DUK_DEC_BC(ins)); - break; - } - case DUK_OP_LDTRUE: { - duk_push_true(thr); - DUK__REPLACE_TOP_BC_BREAK(); - } - case DUK_OP_LDFALSE: { - duk_push_false(thr); - DUK__REPLACE_TOP_BC_BREAK(); - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_LDTHIS: { - /* Note: 'this' may be bound to any value, not just an object */ - duk_tval *tv1, *tv2; - - tv1 = DUK__REGP_BC(ins); - tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */ - DUK_ASSERT(tv2 >= thr->valstack); - DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */ - break; - } - case DUK_OP_LDUNDEF: { - duk_tval *tv1; - - tv1 = DUK__REGP_BC(ins); - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */ - break; - } - case DUK_OP_LDNULL: { - duk_tval *tv1; - - tv1 = DUK__REGP_BC(ins); - DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */ - break; - } - case DUK_OP_LDTRUE: { - duk_tval *tv1; - - tv1 = DUK__REGP_BC(ins); - DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 1); /* side effects */ - break; - } - case DUK_OP_LDFALSE: { - duk_tval *tv1; - - tv1 = DUK__REGP_BC(ins); - DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 0); /* side effects */ - break; - } -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - case DUK_OP_BNOT: { - duk__vm_bitwise_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins)); - break; - } - - case DUK_OP_LNOT: { - duk__vm_logical_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins)); - break; - } - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_UNM: - case DUK_OP_UNP: { - duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), op); - break; - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_UNM: { - duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNM); - break; - } - case DUK_OP_UNP: { - duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNP); - break; - } -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_TYPEOF: { - duk_small_uint_t stridx; - - stridx = duk_js_typeof_stridx(DUK__REGP_BC(ins)); - DUK_ASSERT_STRIDX_VALID(stridx); - duk_push_hstring_stridx(thr, stridx); - DUK__REPLACE_TOP_A_BREAK(); - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_TYPEOF: { - duk_tval *tv; - duk_small_uint_t stridx; - duk_hstring *h_str; - - tv = DUK__REGP_BC(ins); - stridx = duk_js_typeof_stridx(tv); - DUK_ASSERT_STRIDX_VALID(stridx); - h_str = DUK_HTHREAD_GET_STRING(thr, stridx); - tv = DUK__REGP_A(ins); - DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str); - break; - } -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - case DUK_OP_TYPEOFID: { - duk_small_uint_t stridx; -#if !defined(DUK_USE_EXEC_PREFER_SIZE) - duk_hstring *h_str; -#endif - duk_activation *act; - duk_hstring *name; - duk_tval *tv; - - /* A -> target register - * BC -> constant index of identifier name - */ - - tv = DUK__CONSTP_BC(ins); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv)); - name = DUK_TVAL_GET_STRING(tv); - tv = NULL; /* lookup has side effects */ - act = thr->callstack_curr; - if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) { - /* -> [... val this] */ - tv = DUK_GET_TVAL_NEGIDX(thr, -2); - stridx = duk_js_typeof_stridx(tv); - tv = NULL; /* no longer needed */ - duk_pop_2_unsafe(thr); - } else { - /* unresolvable, no stack changes */ - stridx = DUK_STRIDX_LC_UNDEFINED; - } - DUK_ASSERT_STRIDX_VALID(stridx); -#if defined(DUK_USE_EXEC_PREFER_SIZE) - duk_push_hstring_stridx(thr, stridx); - DUK__REPLACE_TOP_A_BREAK(); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - h_str = DUK_HTHREAD_GET_STRING(thr, stridx); - tv = DUK__REGP_A(ins); - DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str); - break; -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - } - - /* Equality: E5 Sections 11.9.1, 11.9.3 */ - -#define DUK__EQ_BODY(barg,carg) { \ - duk_bool_t tmp; \ - tmp = duk_js_equals(thr, (barg), (carg)); \ - DUK_ASSERT(tmp == 0 || tmp == 1); \ - DUK__REPLACE_BOOL_A_BREAK(tmp); \ - } -#define DUK__NEQ_BODY(barg,carg) { \ - duk_bool_t tmp; \ - tmp = duk_js_equals(thr, (barg), (carg)); \ - DUK_ASSERT(tmp == 0 || tmp == 1); \ - tmp ^= 1; \ - DUK__REPLACE_BOOL_A_BREAK(tmp); \ - } -#define DUK__SEQ_BODY(barg,carg) { \ - duk_bool_t tmp; \ - tmp = duk_js_strict_equals((barg), (carg)); \ - DUK_ASSERT(tmp == 0 || tmp == 1); \ - DUK__REPLACE_BOOL_A_BREAK(tmp); \ - } -#define DUK__SNEQ_BODY(barg,carg) { \ - duk_bool_t tmp; \ - tmp = duk_js_strict_equals((barg), (carg)); \ - DUK_ASSERT(tmp == 0 || tmp == 1); \ - tmp ^= 1; \ - DUK__REPLACE_BOOL_A_BREAK(tmp); \ - } -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_EQ_RR: - case DUK_OP_EQ_CR: - case DUK_OP_EQ_RC: - case DUK_OP_EQ_CC: - DUK__EQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); - case DUK_OP_NEQ_RR: - case DUK_OP_NEQ_CR: - case DUK_OP_NEQ_RC: - case DUK_OP_NEQ_CC: - DUK__NEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); - case DUK_OP_SEQ_RR: - case DUK_OP_SEQ_CR: - case DUK_OP_SEQ_RC: - case DUK_OP_SEQ_CC: - DUK__SEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); - case DUK_OP_SNEQ_RR: - case DUK_OP_SNEQ_CR: - case DUK_OP_SNEQ_RC: - case DUK_OP_SNEQ_CC: - DUK__SNEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_EQ_RR: - DUK__EQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_EQ_CR: - DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_EQ_RC: - DUK__EQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_EQ_CC: - DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_NEQ_RR: - DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_NEQ_CR: - DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_NEQ_RC: - DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_NEQ_CC: - DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_SEQ_RR: - DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_SEQ_CR: - DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_SEQ_RC: - DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_SEQ_CC: - DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_SNEQ_RR: - DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_SNEQ_CR: - DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_SNEQ_RC: - DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_SNEQ_CC: - DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - -#define DUK__COMPARE_BODY(arg1,arg2,flags) { \ - duk_bool_t tmp; \ - tmp = duk_js_compare_helper(thr, (arg1), (arg2), (flags)); \ - DUK_ASSERT(tmp == 0 || tmp == 1); \ - DUK__REPLACE_BOOL_A_BREAK(tmp); \ - } -#define DUK__GT_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), 0) -#define DUK__GE_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE) -#define DUK__LT_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) -#define DUK__LE_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), DUK_COMPARE_FLAG_NEGATE) -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_GT_RR: - case DUK_OP_GT_CR: - case DUK_OP_GT_RC: - case DUK_OP_GT_CC: - DUK__GT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); - case DUK_OP_GE_RR: - case DUK_OP_GE_CR: - case DUK_OP_GE_RC: - case DUK_OP_GE_CC: - DUK__GE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); - case DUK_OP_LT_RR: - case DUK_OP_LT_CR: - case DUK_OP_LT_RC: - case DUK_OP_LT_CC: - DUK__LT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); - case DUK_OP_LE_RR: - case DUK_OP_LE_CR: - case DUK_OP_LE_RC: - case DUK_OP_LE_CC: - DUK__LE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_GT_RR: - DUK__GT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_GT_CR: - DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_GT_RC: - DUK__GT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_GT_CC: - DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_GE_RR: - DUK__GE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_GE_CR: - DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_GE_RC: - DUK__GE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_GE_CC: - DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_LT_RR: - DUK__LT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_LT_CR: - DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_LT_RC: - DUK__LT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_LT_CC: - DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_LE_RR: - DUK__LE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_LE_CR: - DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_LE_RC: - DUK__LE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_LE_CC: - DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - /* No size optimized variant at present for IF. */ - case DUK_OP_IFTRUE_R: { - if (duk_js_toboolean(DUK__REGP_BC(ins)) != 0) { - curr_pc++; - } - break; - } - case DUK_OP_IFTRUE_C: { - if (duk_js_toboolean(DUK__CONSTP_BC(ins)) != 0) { - curr_pc++; - } - break; - } - case DUK_OP_IFFALSE_R: { - if (duk_js_toboolean(DUK__REGP_BC(ins)) == 0) { - curr_pc++; - } - break; - } - case DUK_OP_IFFALSE_C: { - if (duk_js_toboolean(DUK__CONSTP_BC(ins)) == 0) { - curr_pc++; - } - break; - } - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_ADD_RR: - case DUK_OP_ADD_CR: - case DUK_OP_ADD_RC: - case DUK_OP_ADD_CC: { - /* XXX: could leave value on stack top and goto replace_top_a; */ - duk__vm_arith_add(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins)); - break; - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_ADD_RR: { - duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins)); - break; - } - case DUK_OP_ADD_CR: { - duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins)); - break; - } - case DUK_OP_ADD_RC: { - duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins)); - break; - } - case DUK_OP_ADD_CC: { - duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins)); - break; - } -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_SUB_RR: - case DUK_OP_SUB_CR: - case DUK_OP_SUB_RC: - case DUK_OP_SUB_CC: - case DUK_OP_MUL_RR: - case DUK_OP_MUL_CR: - case DUK_OP_MUL_RC: - case DUK_OP_MUL_CC: - case DUK_OP_DIV_RR: - case DUK_OP_DIV_CR: - case DUK_OP_DIV_RC: - case DUK_OP_DIV_CC: - case DUK_OP_MOD_RR: - case DUK_OP_MOD_CR: - case DUK_OP_MOD_RC: - case DUK_OP_MOD_CC: -#if defined(DUK_USE_ES7_EXP_OPERATOR) - case DUK_OP_EXP_RR: - case DUK_OP_EXP_CR: - case DUK_OP_EXP_RC: - case DUK_OP_EXP_CC: -#endif /* DUK_USE_ES7_EXP_OPERATOR */ - { - /* XXX: could leave value on stack top and goto replace_top_a; */ - duk__vm_arith_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op); - break; - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_SUB_RR: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB); - break; - } - case DUK_OP_SUB_CR: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB); - break; - } - case DUK_OP_SUB_RC: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB); - break; - } - case DUK_OP_SUB_CC: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB); - break; - } - case DUK_OP_MUL_RR: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL); - break; - } - case DUK_OP_MUL_CR: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL); - break; - } - case DUK_OP_MUL_RC: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL); - break; - } - case DUK_OP_MUL_CC: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL); - break; - } - case DUK_OP_DIV_RR: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV); - break; - } - case DUK_OP_DIV_CR: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV); - break; - } - case DUK_OP_DIV_RC: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV); - break; - } - case DUK_OP_DIV_CC: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV); - break; - } - case DUK_OP_MOD_RR: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD); - break; - } - case DUK_OP_MOD_CR: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD); - break; - } - case DUK_OP_MOD_RC: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD); - break; - } - case DUK_OP_MOD_CC: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD); - break; - } -#if defined(DUK_USE_ES7_EXP_OPERATOR) - case DUK_OP_EXP_RR: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP); - break; - } - case DUK_OP_EXP_CR: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP); - break; - } - case DUK_OP_EXP_RC: { - duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP); - break; - } - case DUK_OP_EXP_CC: { - duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP); - break; - } -#endif /* DUK_USE_ES7_EXP_OPERATOR */ -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_BAND_RR: - case DUK_OP_BAND_CR: - case DUK_OP_BAND_RC: - case DUK_OP_BAND_CC: - case DUK_OP_BOR_RR: - case DUK_OP_BOR_CR: - case DUK_OP_BOR_RC: - case DUK_OP_BOR_CC: - case DUK_OP_BXOR_RR: - case DUK_OP_BXOR_CR: - case DUK_OP_BXOR_RC: - case DUK_OP_BXOR_CC: - case DUK_OP_BASL_RR: - case DUK_OP_BASL_CR: - case DUK_OP_BASL_RC: - case DUK_OP_BASL_CC: - case DUK_OP_BLSR_RR: - case DUK_OP_BLSR_CR: - case DUK_OP_BLSR_RC: - case DUK_OP_BLSR_CC: - case DUK_OP_BASR_RR: - case DUK_OP_BASR_CR: - case DUK_OP_BASR_RC: - case DUK_OP_BASR_CC: { - /* XXX: could leave value on stack top and goto replace_top_a; */ - duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op); - break; - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_BAND_RR: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND); - break; - } - case DUK_OP_BAND_CR: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND); - break; - } - case DUK_OP_BAND_RC: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND); - break; - } - case DUK_OP_BAND_CC: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND); - break; - } - case DUK_OP_BOR_RR: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR); - break; - } - case DUK_OP_BOR_CR: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR); - break; - } - case DUK_OP_BOR_RC: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR); - break; - } - case DUK_OP_BOR_CC: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR); - break; - } - case DUK_OP_BXOR_RR: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR); - break; - } - case DUK_OP_BXOR_CR: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR); - break; - } - case DUK_OP_BXOR_RC: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR); - break; - } - case DUK_OP_BXOR_CC: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR); - break; - } - case DUK_OP_BASL_RR: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL); - break; - } - case DUK_OP_BASL_CR: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL); - break; - } - case DUK_OP_BASL_RC: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL); - break; - } - case DUK_OP_BASL_CC: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL); - break; - } - case DUK_OP_BLSR_RR: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR); - break; - } - case DUK_OP_BLSR_CR: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR); - break; - } - case DUK_OP_BLSR_RC: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR); - break; - } - case DUK_OP_BLSR_CC: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR); - break; - } - case DUK_OP_BASR_RR: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR); - break; - } - case DUK_OP_BASR_CR: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR); - break; - } - case DUK_OP_BASR_RC: { - duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR); - break; - } - case DUK_OP_BASR_CC: { - duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR); - break; - } -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - /* For INSTOF and IN, B is always a register. */ -#define DUK__INSTOF_BODY(barg,carg) { \ - duk_bool_t tmp; \ - tmp = duk_js_instanceof(thr, (barg), (carg)); \ - DUK_ASSERT(tmp == 0 || tmp == 1); \ - DUK__REPLACE_BOOL_A_BREAK(tmp); \ - } -#define DUK__IN_BODY(barg,carg) { \ - duk_bool_t tmp; \ - tmp = duk_js_in(thr, (barg), (carg)); \ - DUK_ASSERT(tmp == 0 || tmp == 1); \ - DUK__REPLACE_BOOL_A_BREAK(tmp); \ - } -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_INSTOF_RR: - case DUK_OP_INSTOF_CR: - case DUK_OP_INSTOF_RC: - case DUK_OP_INSTOF_CC: - DUK__INSTOF_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); - case DUK_OP_IN_RR: - case DUK_OP_IN_CR: - case DUK_OP_IN_RC: - case DUK_OP_IN_CC: - DUK__IN_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_INSTOF_RR: - DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_INSTOF_CR: - DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_INSTOF_RC: - DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_INSTOF_CC: - DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_IN_RR: - DUK__IN_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_IN_CR: - DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_IN_RC: - DUK__IN_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_IN_CC: - DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - /* Pre/post inc/dec for register variables, important for loops. */ -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_PREINCR: - case DUK_OP_PREDECR: - case DUK_OP_POSTINCR: - case DUK_OP_POSTDECR: { - duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), op); - break; - } - case DUK_OP_PREINCV: - case DUK_OP_PREDECV: - case DUK_OP_POSTINCV: - case DUK_OP_POSTDECV: { - duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), op, DUK__STRICT()); - break; - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_PREINCR: { - duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREINCR); - break; - } - case DUK_OP_PREDECR: { - duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREDECR); - break; - } - case DUK_OP_POSTINCR: { - duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTINCR); - break; - } - case DUK_OP_POSTDECR: { - duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTDECR); - break; - } - case DUK_OP_PREINCV: { - duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREINCV, DUK__STRICT()); - break; - } - case DUK_OP_PREDECV: { - duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREDECV, DUK__STRICT()); - break; - } - case DUK_OP_POSTINCV: { - duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTINCV, DUK__STRICT()); - break; - } - case DUK_OP_POSTDECV: { - duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTDECV, DUK__STRICT()); - break; - } -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - /* XXX: Move to separate helper, optimize for perf/size separately. */ - /* Preinc/predec for object properties. */ - case DUK_OP_PREINCP_RR: - case DUK_OP_PREINCP_CR: - case DUK_OP_PREINCP_RC: - case DUK_OP_PREINCP_CC: - case DUK_OP_PREDECP_RR: - case DUK_OP_PREDECP_CR: - case DUK_OP_PREDECP_RC: - case DUK_OP_PREDECP_CC: - case DUK_OP_POSTINCP_RR: - case DUK_OP_POSTINCP_CR: - case DUK_OP_POSTINCP_RC: - case DUK_OP_POSTINCP_CC: - case DUK_OP_POSTDECP_RR: - case DUK_OP_POSTDECP_CR: - case DUK_OP_POSTDECP_RC: - case DUK_OP_POSTDECP_CC: { - duk_tval *tv_obj; - duk_tval *tv_key; - duk_tval *tv_val; - duk_bool_t rc; - duk_double_t x, y, z; -#if !defined(DUK_USE_EXEC_PREFER_SIZE) - duk_tval *tv_dst; -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - /* A -> target reg - * B -> object reg/const (may be const e.g. in "'foo'[1]") - * C -> key reg/const - */ - - /* Opcode bits 0-1 are used to distinguish reg/const variants. - * Opcode bits 2-3 are used to distinguish inc/dec variants: - * Bit 2 = inc(0)/dec(1), bit 3 = pre(0)/post(1). - */ - DUK_ASSERT((DUK_OP_PREINCP_RR & 0x0c) == 0x00); - DUK_ASSERT((DUK_OP_PREDECP_RR & 0x0c) == 0x04); - DUK_ASSERT((DUK_OP_POSTINCP_RR & 0x0c) == 0x08); - DUK_ASSERT((DUK_OP_POSTDECP_RR & 0x0c) == 0x0c); - - tv_obj = DUK__REGCONSTP_B(ins); - tv_key = DUK__REGCONSTP_C(ins); - rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */ - DUK_UNREF(rc); /* ignore */ - tv_obj = NULL; /* invalidated */ - tv_key = NULL; /* invalidated */ - - /* XXX: Fastint fast path would be useful here. Also fastints - * now lose their fastint status in current handling which is - * not intuitive. - */ - - x = duk_to_number_m1(thr); - duk_pop_unsafe(thr); - if (ins & DUK_BC_INCDECP_FLAG_DEC) { - y = x - 1.0; - } else { - y = x + 1.0; - } - - duk_push_number(thr, y); - tv_val = DUK_GET_TVAL_NEGIDX(thr, -1); - DUK_ASSERT(tv_val != NULL); - tv_obj = DUK__REGCONSTP_B(ins); - tv_key = DUK__REGCONSTP_C(ins); - rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT()); - DUK_UNREF(rc); /* ignore */ - tv_obj = NULL; /* invalidated */ - tv_key = NULL; /* invalidated */ - duk_pop_unsafe(thr); - - z = (ins & DUK_BC_INCDECP_FLAG_POST) ? x : y; -#if defined(DUK_USE_EXEC_PREFER_SIZE) - duk_push_number(thr, z); - DUK__REPLACE_TOP_A_BREAK(); -#else - tv_dst = DUK__REGP_A(ins); - DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z); - break; -#endif - } - - /* XXX: GETPROP where object is 'this', GETPROPT? - * Occurs relatively often in object oriented code. - */ - -#define DUK__GETPROP_BODY(barg,carg) { \ - /* A -> target reg \ - * B -> object reg/const (may be const e.g. in "'foo'[1]") \ - * C -> key reg/const \ - */ \ - (void) duk_hobject_getprop(thr, (barg), (carg)); \ - DUK__REPLACE_TOP_A_BREAK(); \ - } -#define DUK__GETPROPC_BODY(barg,carg) { \ - /* Same as GETPROP but callability check for property-based calls. */ \ - duk_tval *tv__targ; \ - (void) duk_hobject_getprop(thr, (barg), (carg)); \ - DUK_GC_TORTURE(thr->heap); \ - tv__targ = DUK_GET_TVAL_NEGIDX(thr, -1); \ - if (DUK_UNLIKELY(!duk_is_callable_tval(thr, tv__targ))) { \ - /* Here we intentionally re-evaluate the macro \ - * arguments to deal with potentially changed \ - * valstack base pointer! \ - */ \ - duk_call_setup_propcall_error(thr, tv__targ, (barg), (carg)); \ - } \ - DUK__REPLACE_TOP_A_BREAK(); \ - } -#define DUK__PUTPROP_BODY(aarg,barg,carg) { \ - /* A -> object reg \ - * B -> key reg/const \ - * C -> value reg/const \ - * \ - * Note: intentional difference to register arrangement \ - * of e.g. GETPROP; 'A' must contain a register-only value. \ - */ \ - (void) duk_hobject_putprop(thr, (aarg), (barg), (carg), DUK__STRICT()); \ - break; \ - } -#define DUK__DELPROP_BODY(barg,carg) { \ - /* A -> result reg \ - * B -> object reg \ - * C -> key reg/const \ - */ \ - duk_bool_t rc; \ - rc = duk_hobject_delprop(thr, (barg), (carg), DUK__STRICT()); \ - DUK_ASSERT(rc == 0 || rc == 1); \ - DUK__REPLACE_BOOL_A_BREAK(rc); \ - } -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_GETPROP_RR: - case DUK_OP_GETPROP_CR: - case DUK_OP_GETPROP_RC: - case DUK_OP_GETPROP_CC: - DUK__GETPROP_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); -#if defined(DUK_USE_VERBOSE_ERRORS) - case DUK_OP_GETPROPC_RR: - case DUK_OP_GETPROPC_CR: - case DUK_OP_GETPROPC_RC: - case DUK_OP_GETPROPC_CC: - DUK__GETPROPC_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); -#endif - case DUK_OP_PUTPROP_RR: - case DUK_OP_PUTPROP_CR: - case DUK_OP_PUTPROP_RC: - case DUK_OP_PUTPROP_CC: - DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); - case DUK_OP_DELPROP_RR: - case DUK_OP_DELPROP_RC: /* B is always reg */ - DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGCONSTP_C(ins)); -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_GETPROP_RR: - DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_GETPROP_CR: - DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_GETPROP_RC: - DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_GETPROP_CC: - DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); -#if defined(DUK_USE_VERBOSE_ERRORS) - case DUK_OP_GETPROPC_RR: - DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_GETPROPC_CR: - DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_GETPROPC_RC: - DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_GETPROPC_CC: - DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); -#endif - case DUK_OP_PUTPROP_RR: - DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_PUTPROP_CR: - DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_PUTPROP_RC: - DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_PUTPROP_CC: - DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); - case DUK_OP_DELPROP_RR: /* B is always reg */ - DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); - case DUK_OP_DELPROP_RC: - DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - /* No fast path for DECLVAR now, it's quite a rare instruction. */ - case DUK_OP_DECLVAR_RR: - case DUK_OP_DECLVAR_CR: - case DUK_OP_DECLVAR_RC: - case DUK_OP_DECLVAR_CC: { - duk_activation *act; - duk_small_uint_fast_t a = DUK_DEC_A(ins); - duk_tval *tv1; - duk_hstring *name; - duk_small_uint_t prop_flags; - duk_bool_t is_func_decl; - - tv1 = DUK__REGCONSTP_B(ins); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); - name = DUK_TVAL_GET_STRING(tv1); - DUK_ASSERT(name != NULL); - - is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0); - - /* XXX: declvar takes an duk_tval pointer, which is awkward and - * should be reworked. - */ - - /* Compiler is responsible for selecting property flags (configurability, - * writability, etc). - */ - prop_flags = a & DUK_PROPDESC_FLAGS_MASK; - - if (is_func_decl) { - duk_push_tval(thr, DUK__REGCONSTP_C(ins)); - } else { - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ - thr->valstack_top++; - } - tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); - - act = thr->callstack_curr; - if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) { - if (is_func_decl) { - /* Already declared, update value. */ - tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); - duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); - } else { - /* Already declared but no initializer value - * (e.g. 'var xyz;'), no-op. - */ - } - } - - duk_pop_unsafe(thr); - break; - } - -#if defined(DUK_USE_REGEXP_SUPPORT) - /* The compiler should never emit DUK_OP_REGEXP if there is no - * regexp support. - */ - case DUK_OP_REGEXP_RR: - case DUK_OP_REGEXP_CR: - case DUK_OP_REGEXP_RC: - case DUK_OP_REGEXP_CC: { - /* A -> target register - * B -> bytecode (also contains flags) - * C -> escaped source - */ - - duk_push_tval(thr, DUK__REGCONSTP_C(ins)); - duk_push_tval(thr, DUK__REGCONSTP_B(ins)); /* -> [ ... escaped_source bytecode ] */ - duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */ - DUK__REPLACE_TOP_A_BREAK(); - } -#endif /* DUK_USE_REGEXP_SUPPORT */ - - /* XXX: 'c' is unused, use whole BC, etc. */ - case DUK_OP_CSVAR_RR: - case DUK_OP_CSVAR_CR: - case DUK_OP_CSVAR_RC: - case DUK_OP_CSVAR_CC: { - /* The speciality of calling through a variable binding is that the - * 'this' value may be provided by the variable lookup: E5 Section 6.b.i. - * - * The only (standard) case where the 'this' binding is non-null is when - * (1) the variable is found in an object environment record, and - * (2) that object environment record is a 'with' block. - */ - - duk_activation *act; - duk_uint_fast_t idx; - duk_tval *tv1; - duk_hstring *name; - - /* A -> target registers (A, A + 1) for call setup - * B -> identifier name, usually constant but can be a register due to shuffling - */ - - tv1 = DUK__REGCONSTP_B(ins); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); - name = DUK_TVAL_GET_STRING(tv1); - DUK_ASSERT(name != NULL); - act = thr->callstack_curr; - (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ - - idx = (duk_uint_fast_t) DUK_DEC_A(ins); - - /* Could add direct value stack handling. */ - duk_replace(thr, (duk_idx_t) (idx + 1)); /* 'this' binding */ - duk_replace(thr, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */ - break; - } - - case DUK_OP_CLOSURE: { - duk_activation *act; - duk_hcompfunc *fun_act; - duk_small_uint_fast_t bc = DUK_DEC_BC(ins); - duk_hobject *fun_temp; - - /* A -> target reg - * BC -> inner function index - */ - - DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)", - (long) DUK_DEC_A(ins), (long) DUK_DEC_BC(ins), (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN()))); - - DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */ - DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())); - - act = thr->callstack_curr; - fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); - fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc]; - DUK_ASSERT(fun_temp != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(fun_temp)); - - DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O", - (void *) fun_temp, (duk_heaphdr *) fun_temp)); - - if (act->lex_env == NULL) { - DUK_ASSERT(act->var_env == NULL); - duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack_curr; - } - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - - /* functions always have a NEWENV flag, i.e. they get a - * new variable declaration environment, so only lex_env - * matters here. - */ - duk_js_push_closure(thr, - (duk_hcompfunc *) fun_temp, - act->var_env, - act->lex_env, - 1 /*add_auto_proto*/); - DUK__REPLACE_TOP_A_BREAK(); - } - - case DUK_OP_GETVAR: { - duk_activation *act; - duk_tval *tv1; - duk_hstring *name; - - tv1 = DUK__CONSTP_BC(ins); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); - name = DUK_TVAL_GET_STRING(tv1); - DUK_ASSERT(name != NULL); - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ - duk_pop_unsafe(thr); /* 'this' binding is not needed here */ - DUK__REPLACE_TOP_A_BREAK(); - } - - case DUK_OP_PUTVAR: { - duk_activation *act; - duk_tval *tv1; - duk_hstring *name; - - tv1 = DUK__CONSTP_BC(ins); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); - name = DUK_TVAL_GET_STRING(tv1); - DUK_ASSERT(name != NULL); - - /* XXX: putvar takes a duk_tval pointer, which is awkward and - * should be reworked. - */ - - tv1 = DUK__REGP_A(ins); /* val */ - act = thr->callstack_curr; - duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); - break; - } - - case DUK_OP_DELVAR: { - duk_activation *act; - duk_tval *tv1; - duk_hstring *name; - duk_bool_t rc; - - tv1 = DUK__CONSTP_BC(ins); - DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); - name = DUK_TVAL_GET_STRING(tv1); - DUK_ASSERT(name != NULL); - act = thr->callstack_curr; - rc = duk_js_delvar_activation(thr, act, name); - DUK__REPLACE_BOOL_A_BREAK(rc); - } - - case DUK_OP_JUMP: { - /* Note: without explicit cast to signed, MSVC will - * apparently generate a large positive jump when the - * bias-corrected value would normally be negative. - */ - curr_pc += (duk_int_fast_t) DUK_DEC_ABC(ins) - (duk_int_fast_t) DUK_BC_JUMP_BIAS; - break; - } - -#define DUK__RETURN_SHARED() do { \ - duk_small_uint_t ret_result; \ - /* duk__handle_return() is guaranteed never to throw, except \ - * for potential out-of-memory situations which will then \ - * propagate out of the executor longjmp handler. \ - */ \ - DUK_ASSERT(thr->ptr_curr_pc == NULL); \ - ret_result = duk__handle_return(thr, entry_act); \ - if (ret_result == DUK__RETHAND_RESTART) { \ - goto restart_execution; \ - } \ - DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED); \ - return; \ - } while (0) -#if defined(DUK_USE_EXEC_PREFER_SIZE) - case DUK_OP_RETREG: - case DUK_OP_RETCONST: - case DUK_OP_RETCONSTN: - case DUK_OP_RETUNDEF: { - /* BC -> return value reg/const */ - - DUK__SYNC_AND_NULL_CURR_PC(); - - if (op == DUK_OP_RETREG) { - duk_push_tval(thr, DUK__REGP_BC(ins)); - } else if (op == DUK_OP_RETUNDEF) { - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ - thr->valstack_top++; - } else { - DUK_ASSERT(op == DUK_OP_RETCONST || op == DUK_OP_RETCONSTN); - duk_push_tval(thr, DUK__CONSTP_BC(ins)); - } - - DUK__RETURN_SHARED(); - } -#else /* DUK_USE_EXEC_PREFER_SIZE */ - case DUK_OP_RETREG: { - duk_tval *tv; - - DUK__SYNC_AND_NULL_CURR_PC(); - tv = DUK__REGP_BC(ins); - DUK_TVAL_SET_TVAL(thr->valstack_top, tv); - DUK_TVAL_INCREF(thr, tv); - thr->valstack_top++; - DUK__RETURN_SHARED(); - } - /* This will be unused without refcounting. */ - case DUK_OP_RETCONST: { - duk_tval *tv; - - DUK__SYNC_AND_NULL_CURR_PC(); - tv = DUK__CONSTP_BC(ins); - DUK_TVAL_SET_TVAL(thr->valstack_top, tv); - DUK_TVAL_INCREF(thr, tv); - thr->valstack_top++; - DUK__RETURN_SHARED(); - } - case DUK_OP_RETCONSTN: { - duk_tval *tv; - - DUK__SYNC_AND_NULL_CURR_PC(); - tv = DUK__CONSTP_BC(ins); - DUK_TVAL_SET_TVAL(thr->valstack_top, tv); -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Without refcounting only RETCONSTN is used. */ - DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */ -#endif - thr->valstack_top++; - DUK__RETURN_SHARED(); - } - case DUK_OP_RETUNDEF: { - DUK__SYNC_AND_NULL_CURR_PC(); - thr->valstack_top++; /* value at valstack top is already undefined by valstack policy */ - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); - DUK__RETURN_SHARED(); - } -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - - case DUK_OP_LABEL: { - duk_activation *act; - duk_catcher *cat; - duk_small_uint_fast_t bc = DUK_DEC_BC(ins); - - /* Allocate catcher and populate it (must be atomic). */ - - cat = duk_hthread_catcher_alloc(thr); - DUK_ASSERT(cat != NULL); - - cat->flags = (duk_uint32_t) (DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT)); - cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ - cat->idx_base = 0; /* unused for label */ - cat->h_varname = NULL; - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - cat->parent = act->cat; - act->cat = cat; - - DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, pc_base=%ld, " - "idx_base=%ld, h_varname=%!O, label_id=%ld", - (long) cat->flags, (long) cat->pc_base, - (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat))); - - curr_pc += 2; /* skip jump slots */ - break; - } - - case DUK_OP_ENDLABEL: { - duk_activation *act; -#if (defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)) || defined(DUK_USE_ASSERTIONS) - duk_small_uint_fast_t bc = DUK_DEC_BC(ins); -#endif -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc)); -#endif - - act = thr->callstack_curr; - DUK_ASSERT(act->cat != NULL); - DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_LABEL); - DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(act->cat) == bc); - duk_hthread_catcher_unwind_nolexenv_norz(thr, act); - - /* no need to unwind callstack */ - break; - } - - case DUK_OP_BREAK: { - duk_small_uint_fast_t bc = DUK_DEC_BC(ins); - - DUK__SYNC_AND_NULL_CURR_PC(); - duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK); - goto restart_execution; - } - - case DUK_OP_CONTINUE: { - duk_small_uint_fast_t bc = DUK_DEC_BC(ins); - - DUK__SYNC_AND_NULL_CURR_PC(); - duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE); - goto restart_execution; - } - - /* XXX: move to helper, too large to be inline here */ - case DUK_OP_TRYCATCH: { - duk__handle_op_trycatch(thr, ins, curr_pc); - curr_pc += 2; /* skip jump slots */ - break; - } - - case DUK_OP_ENDTRY: { - curr_pc = duk__handle_op_endtry(thr, ins); - break; - } - - case DUK_OP_ENDCATCH: { - duk__handle_op_endcatch(thr, ins); - break; - } - - case DUK_OP_ENDFIN: { - /* Sync and NULL early. */ - DUK__SYNC_AND_NULL_CURR_PC(); - - if (duk__handle_op_endfin(thr, ins, entry_act) != 0) { - return; - } - - /* Must restart because we NULLed out curr_pc. */ - goto restart_execution; - } - - case DUK_OP_THROW: { - duk_small_uint_fast_t bc = DUK_DEC_BC(ins); - - /* Note: errors are augmented when they are created, not - * when they are thrown. So, don't augment here, it would - * break re-throwing for instance. - */ - - /* Sync so that augmentation sees up-to-date activations, NULL - * thr->ptr_curr_pc so that it's not used if side effects occur - * in augmentation or longjmp handling. - */ - DUK__SYNC_AND_NULL_CURR_PC(); - - duk_dup(thr, (duk_idx_t) bc); - DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)", - (duk_tval *) duk_get_tval(thr, -1))); -#if defined(DUK_USE_AUGMENT_ERROR_THROW) - duk_err_augment_error_throw(thr); - DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)", - (duk_tval *) duk_get_tval(thr, -1))); -#endif - - duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1)); -#if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_err_check_debugger_integration(thr); -#endif - - DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ - duk_err_longjmp(thr); - DUK_UNREACHABLE(); - break; - } - - case DUK_OP_CSREG: { - /* - * Assuming a register binds to a variable declared within this - * function (a declarative binding), the 'this' for the call - * setup is always 'undefined'. E5 Section 10.2.1.1.6. - */ - - duk_small_uint_fast_t a = DUK_DEC_A(ins); - duk_small_uint_fast_t bc = DUK_DEC_BC(ins); - - /* A -> register containing target function (not type checked here) - * BC -> target registers (BC, BC + 1) for call setup - */ - -#if defined(DUK_USE_PREFER_SIZE) - duk_dup(thr, (duk_idx_t) a); - duk_replace(thr, (duk_idx_t) bc); - duk_to_undefined(thr, (duk_idx_t) (bc + 1)); -#else - duk_tval *tv1; - duk_tval *tv2; - duk_tval *tv3; - duk_tval tv_tmp1; - duk_tval tv_tmp2; - - tv1 = DUK__REGP(bc); - tv2 = tv1 + 1; - DUK_TVAL_SET_TVAL(&tv_tmp1, tv1); - DUK_TVAL_SET_TVAL(&tv_tmp2, tv2); - tv3 = DUK__REGP(a); - DUK_TVAL_SET_TVAL(tv1, tv3); - DUK_TVAL_INCREF(thr, tv1); /* no side effects */ - DUK_TVAL_SET_UNDEFINED(tv2); /* no need for incref */ - DUK_TVAL_DECREF(thr, &tv_tmp1); - DUK_TVAL_DECREF(thr, &tv_tmp2); -#endif - break; - } - - - /* XXX: in some cases it's faster NOT to reuse the value - * stack but rather copy the arguments on top of the stack - * (mainly when the calling value stack is large and the value - * stack resize would be large). - */ - - case DUK_OP_CALL0: - case DUK_OP_CALL1: - case DUK_OP_CALL2: - case DUK_OP_CALL3: - case DUK_OP_CALL4: - case DUK_OP_CALL5: - case DUK_OP_CALL6: - case DUK_OP_CALL7: { - /* Opcode packs 4 flag bits: 1 for indirect, 3 map - * 1:1 to three lowest call handling flags. - * - * A -> nargs or register with nargs (indirect) - * BC -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN) - */ - - duk_idx_t nargs; - duk_idx_t idx; - duk_small_uint_t call_flags; -#if !defined(DUK_USE_EXEC_FUN_LOCAL) - duk_hcompfunc *fun; -#endif - - DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0); - DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) == 0); - - nargs = (duk_idx_t) DUK_DEC_A(ins); - call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA; - idx = (duk_idx_t) DUK_DEC_BC(ins); - - if (duk__executor_handle_call(thr, idx, nargs, call_flags)) { - /* curr_pc synced by duk_handle_call_unprotected() */ - DUK_ASSERT(thr->ptr_curr_pc == NULL); - goto restart_execution; - } - DUK_ASSERT(thr->ptr_curr_pc != NULL); - - /* duk_js_call.c is required to restore the stack reserve - * so we only need to reset the top. - */ -#if !defined(DUK_USE_EXEC_FUN_LOCAL) - fun = DUK__FUN(); -#endif - duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs); - - /* No need to reinit setjmp() catchpoint, as call handling - * will store and restore our state. - * - * When debugger is enabled, we need to recheck the activation - * status after returning. This is now handled by call handling - * and heap->dbg_force_restart. - */ - break; - } - - case DUK_OP_CALL8: - case DUK_OP_CALL9: - case DUK_OP_CALL10: - case DUK_OP_CALL11: - case DUK_OP_CALL12: - case DUK_OP_CALL13: - case DUK_OP_CALL14: - case DUK_OP_CALL15: { - /* Indirect variant. */ - duk_uint_fast_t nargs; - duk_idx_t idx; - duk_small_uint_t call_flags; -#if !defined(DUK_USE_EXEC_FUN_LOCAL) - duk_hcompfunc *fun; -#endif - - DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0); - DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) != 0); - - nargs = (duk_uint_fast_t) DUK_DEC_A(ins); - DUK__LOOKUP_INDIRECT(nargs); - call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA; - idx = (duk_idx_t) DUK_DEC_BC(ins); - - if (duk__executor_handle_call(thr, idx, (duk_idx_t) nargs, call_flags)) { - DUK_ASSERT(thr->ptr_curr_pc == NULL); - goto restart_execution; - } - DUK_ASSERT(thr->ptr_curr_pc != NULL); - -#if !defined(DUK_USE_EXEC_FUN_LOCAL) - fun = DUK__FUN(); -#endif - duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs); - break; - } - - case DUK_OP_NEWOBJ: { - duk_push_object(thr); -#if defined(DUK_USE_ASSERTIONS) - { - duk_hobject *h; - h = duk_require_hobject(thr, -1); - DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0); - DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0); - DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0); - } -#endif -#if !defined(DUK_USE_PREFER_SIZE) - /* XXX: could do a direct props realloc, but need hash size */ - duk_hobject_resize_entrypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins)); -#endif - DUK__REPLACE_TOP_BC_BREAK(); - } - - case DUK_OP_NEWARR: { - duk_push_array(thr); -#if defined(DUK_USE_ASSERTIONS) - { - duk_hobject *h; - h = duk_require_hobject(thr, -1); - DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0); - DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0); - DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0); - DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(h)); - } -#endif -#if !defined(DUK_USE_PREFER_SIZE) - duk_hobject_realloc_props(thr, - duk_known_hobject(thr, -1), - 0 /*new_e_size*/, - DUK_DEC_A(ins) /*new_a_size*/, - 0 /*new_h_size*/, - 0 /*abandon_array*/); -#if 0 - duk_hobject_resize_arraypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins)); -#endif -#endif - DUK__REPLACE_TOP_BC_BREAK(); - } - - case DUK_OP_MPUTOBJ: - case DUK_OP_MPUTOBJI: { - duk_idx_t obj_idx; - duk_uint_fast_t idx, idx_end; - duk_small_uint_fast_t count; - - /* A -> register of target object - * B -> first register of key/value pair list - * or register containing first register number if indirect - * C -> number of key/value pairs * 2 - * (= number of value stack indices used starting from 'B') - */ - - obj_idx = DUK_DEC_A(ins); - DUK_ASSERT(duk_is_object(thr, obj_idx)); - - idx = (duk_uint_fast_t) DUK_DEC_B(ins); - if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) { - DUK__LOOKUP_INDIRECT(idx); - } - - count = (duk_small_uint_fast_t) DUK_DEC_C(ins); - DUK_ASSERT(count > 0); /* compiler guarantees */ - idx_end = idx + count; - -#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK) - if (DUK_UNLIKELY(idx_end > (duk_uint_fast_t) duk_get_top(thr))) { - /* XXX: use duk_is_valid_index() instead? */ - /* XXX: improve check; check against nregs, not against top */ - DUK__INTERNAL_ERROR("MPUTOBJ out of bounds"); - } -#endif - - /* Use 'force' flag to duk_def_prop() to ensure that any - * inherited properties don't prevent the operation. - * With ES2015 duplicate properties are allowed, so that we - * must overwrite any previous data or accessor property. - * - * With ES2015 computed property names the literal keys - * may be arbitrary values and need to be ToPropertyKey() - * coerced at runtime. - */ - do { - /* XXX: faster initialization (direct access or better primitives) */ - duk_dup(thr, (duk_idx_t) idx); - duk_dup(thr, (duk_idx_t) (idx + 1)); - duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_VALUE | - DUK_DEFPROP_FORCE | - DUK_DEFPROP_SET_WRITABLE | - DUK_DEFPROP_SET_ENUMERABLE | - DUK_DEFPROP_SET_CONFIGURABLE); - idx += 2; - } while (idx < idx_end); - break; - } - - case DUK_OP_INITSET: - case DUK_OP_INITGET: { - duk__handle_op_initset_initget(thr, ins); - break; - } - - case DUK_OP_MPUTARR: - case DUK_OP_MPUTARRI: { - duk_idx_t obj_idx; - duk_uint_fast_t idx, idx_end; - duk_small_uint_fast_t count; - duk_tval *tv1; - duk_uint32_t arr_idx; - - /* A -> register of target object - * B -> first register of value data (start_index, value1, value2, ..., valueN) - * or register containing first register number if indirect - * C -> number of key/value pairs (N) - */ - - obj_idx = DUK_DEC_A(ins); - DUK_ASSERT(duk_is_object(thr, obj_idx)); - - idx = (duk_uint_fast_t) DUK_DEC_B(ins); - if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) { - DUK__LOOKUP_INDIRECT(idx); - } - - count = (duk_small_uint_fast_t) DUK_DEC_C(ins); - DUK_ASSERT(count > 0 + 1); /* compiler guarantees */ - idx_end = idx + count; - -#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK) - if (idx_end > (duk_uint_fast_t) duk_get_top(thr)) { - /* XXX: use duk_is_valid_index() instead? */ - /* XXX: improve check; check against nregs, not against top */ - DUK__INTERNAL_ERROR("MPUTARR out of bounds"); - } -#endif - - tv1 = DUK__REGP(idx); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); - arr_idx = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1); -#else - arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1); -#endif - idx++; - - do { - /* duk_xdef_prop() will define an own property without any array - * special behaviors. We'll need to set the array length explicitly - * in the end. For arrays with elisions, the compiler will emit an - * explicit SETALEN which will update the length. - */ - - /* XXX: because we're dealing with 'own' properties of a fresh array, - * the array initializer should just ensure that the array has a large - * enough array part and write the values directly into array part, - * and finally set 'length' manually in the end (as already happens now). - */ - - duk_dup(thr, (duk_idx_t) idx); - duk_xdef_prop_index_wec(thr, obj_idx, arr_idx); - - idx++; - arr_idx++; - } while (idx < idx_end); - - /* XXX: E5.1 Section 11.1.4 coerces the final length through - * ToUint32() which is odd but happens now as a side effect of - * 'arr_idx' type. - */ - duk_set_length(thr, obj_idx, (duk_size_t) (duk_uarridx_t) arr_idx); - break; - } - - case DUK_OP_SETALEN: { - duk_tval *tv1; - duk_hobject *h; - duk_uint32_t len; - - tv1 = DUK__REGP_A(ins); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1)); - h = DUK_TVAL_GET_OBJECT(tv1); - DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(h)); - - tv1 = DUK__REGP_BC(ins); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); - len = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1); -#else - len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1); -#endif - ((duk_harray *) h)->length = len; - break; - } - - case DUK_OP_INITENUM: { - duk__handle_op_initenum(thr, ins); - break; - } - - case DUK_OP_NEXTENUM: { - curr_pc += duk__handle_op_nextenum(thr, ins); - break; - } - - case DUK_OP_INVLHS: { - DUK_ERROR_REFERENCE(thr, DUK_STR_INVALID_LVALUE); - DUK_UNREACHABLE(); - break; - } - - case DUK_OP_DEBUGGER: { - /* Opcode only emitted by compiler when debugger - * support is enabled. Ignore it silently without - * debugger support, in case it has been loaded - * from precompiled bytecode. - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (duk_debug_is_attached(thr->heap)) { - DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution")); - DUK__SYNC_AND_NULL_CURR_PC(); - duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); - DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution")); - goto restart_execution; - } else { - DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached")); - } -#else - DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support")); -#endif - break; - } - - case DUK_OP_NOP: { - /* Nop, ignored, but ABC fields may carry a value e.g. - * for indirect opcode handling. - */ - break; - } - - case DUK_OP_INVALID: { - DUK_ERROR_FMT1(thr, DUK_ERR_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_ABC(ins)); - break; - } - -#if defined(DUK_USE_ES6) - case DUK_OP_NEWTARGET: { - /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runtime-semantics-evaluation - * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget - * - * No newTarget support now, so as a first approximation - * use the resolved (non-bound) target function. - */ - /* XXX: C API: push_new_target()? */ - duk_activation *act; - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - - /* Check CONSTRUCT flag from current function, or if running - * direct eval, from a non-direct-eval parent (with possibly - * more than one nested direct eval). An alternative to this - * would be to store [[NewTarget]] as a hidden symbol of the - * lexical scope, and then just look up that variable. - */ - for (;;) { - if (act == NULL) { - duk_push_undefined(thr); - break; - } - if (act->flags & DUK_ACT_FLAG_CONSTRUCT) { - duk_push_tval(thr, &act->tv_func); - break; - } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { - act = act->parent; - } else { - duk_push_undefined(thr); - break; - } - } - - DUK__REPLACE_TOP_BC_BREAK(); - } -#endif /* DUK_USE_ES6 */ - -#if !defined(DUK_USE_EXEC_PREFER_SIZE) -#if !defined(DUK_USE_ES7_EXP_OPERATOR) - case DUK_OP_EXP_RR: - case DUK_OP_EXP_CR: - case DUK_OP_EXP_RC: - case DUK_OP_EXP_CC: -#endif -#if !defined(DUK_USE_ES6) - case DUK_OP_NEWTARGET: -#endif -#if !defined(DUK_USE_VERBOSE_ERRORS) - case DUK_OP_GETPROPC_RR: - case DUK_OP_GETPROPC_CR: - case DUK_OP_GETPROPC_RC: - case DUK_OP_GETPROPC_CC: -#endif - case DUK_OP_UNUSED207: - case DUK_OP_UNUSED212: - case DUK_OP_UNUSED213: - case DUK_OP_UNUSED214: - case DUK_OP_UNUSED215: - case DUK_OP_UNUSED216: - case DUK_OP_UNUSED217: - case DUK_OP_UNUSED218: - case DUK_OP_UNUSED219: - case DUK_OP_UNUSED220: - case DUK_OP_UNUSED221: - case DUK_OP_UNUSED222: - case DUK_OP_UNUSED223: - case DUK_OP_UNUSED224: - case DUK_OP_UNUSED225: - case DUK_OP_UNUSED226: - case DUK_OP_UNUSED227: - case DUK_OP_UNUSED228: - case DUK_OP_UNUSED229: - case DUK_OP_UNUSED230: - case DUK_OP_UNUSED231: - case DUK_OP_UNUSED232: - case DUK_OP_UNUSED233: - case DUK_OP_UNUSED234: - case DUK_OP_UNUSED235: - case DUK_OP_UNUSED236: - case DUK_OP_UNUSED237: - case DUK_OP_UNUSED238: - case DUK_OP_UNUSED239: - case DUK_OP_UNUSED240: - case DUK_OP_UNUSED241: - case DUK_OP_UNUSED242: - case DUK_OP_UNUSED243: - case DUK_OP_UNUSED244: - case DUK_OP_UNUSED245: - case DUK_OP_UNUSED246: - case DUK_OP_UNUSED247: - case DUK_OP_UNUSED248: - case DUK_OP_UNUSED249: - case DUK_OP_UNUSED250: - case DUK_OP_UNUSED251: - case DUK_OP_UNUSED252: - case DUK_OP_UNUSED253: - case DUK_OP_UNUSED254: - case DUK_OP_UNUSED255: - /* Force all case clauses to map to an actual handler - * so that the compiler can emit a jump without a bounds - * check: the switch argument is a duk_uint8_t so that - * the compiler may be able to figure it out. This is - * a small detail and obviously compiler dependent. - */ - /* default: clause omitted on purpose */ -#else /* DUK_USE_EXEC_PREFER_SIZE */ - default: -#endif /* DUK_USE_EXEC_PREFER_SIZE */ - { - /* Default case catches invalid/unsupported opcodes. */ - DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); - DUK__INTERNAL_ERROR("invalid opcode"); - break; - } - - } /* end switch */ - - continue; - - /* Some shared exit paths for opcode handling below. These - * are mostly useful to reduce code footprint when multiple - * opcodes have a similar epilogue (like replacing stack top - * with index 'a'). - */ - -#if defined(DUK_USE_EXEC_PREFER_SIZE) - replace_top_a: - DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins)); - continue; - replace_top_bc: - DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins)); - continue; -#endif - } - DUK_UNREACHABLE(); - -#if !defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS) - internal_error: - DUK_ERROR_INTERNAL(thr); -#endif -} - -/* automatic undefs */ -#undef DUK__BYTEOFF_A -#undef DUK__BYTEOFF_B -#undef DUK__BYTEOFF_BC -#undef DUK__BYTEOFF_C -#undef DUK__COMPARE_BODY -#undef DUK__CONST -#undef DUK__CONSTP -#undef DUK__CONSTP_A -#undef DUK__CONSTP_B -#undef DUK__CONSTP_BC -#undef DUK__CONSTP_C -#undef DUK__DELPROP_BODY -#undef DUK__EQ_BODY -#undef DUK__FUN -#undef DUK__GETPROPC_BODY -#undef DUK__GETPROP_BODY -#undef DUK__GE_BODY -#undef DUK__GT_BODY -#undef DUK__INLINE_PERF -#undef DUK__INSTOF_BODY -#undef DUK__INTERNAL_ERROR -#undef DUK__INT_NOACTION -#undef DUK__INT_RESTART -#undef DUK__IN_BODY -#undef DUK__LE_BODY -#undef DUK__LONGJMP_RESTART -#undef DUK__LONGJMP_RETHROW -#undef DUK__LOOKUP_INDIRECT -#undef DUK__LT_BODY -#undef DUK__MASK_A -#undef DUK__MASK_B -#undef DUK__MASK_BC -#undef DUK__MASK_C -#undef DUK__NEQ_BODY -#undef DUK__NOINLINE_PERF -#undef DUK__PUTPROP_BODY -#undef DUK__RCBIT_B -#undef DUK__RCBIT_C -#undef DUK__REG -#undef DUK__REGCONSTP_B -#undef DUK__REGCONSTP_C -#undef DUK__REGP -#undef DUK__REGP_A -#undef DUK__REGP_B -#undef DUK__REGP_BC -#undef DUK__REGP_C -#undef DUK__REPLACE_BOOL_A_BREAK -#undef DUK__REPLACE_TOP_A_BREAK -#undef DUK__REPLACE_TOP_BC_BREAK -#undef DUK__REPLACE_TO_TVPTR -#undef DUK__RETHAND_FINISHED -#undef DUK__RETHAND_RESTART -#undef DUK__RETURN_SHARED -#undef DUK__SEQ_BODY -#undef DUK__SHIFT_A -#undef DUK__SHIFT_B -#undef DUK__SHIFT_BC -#undef DUK__SHIFT_C -#undef DUK__SNEQ_BODY -#undef DUK__STRICT -#undef DUK__SYNC_AND_NULL_CURR_PC -#undef DUK__SYNC_CURR_PC -#undef DUK__TVAL_SHIFT -#line 1 "duk_js_ops.c" -/* - * Ecmascript specification algorithm and conversion helpers. - * - * These helpers encapsulate the primitive Ecmascript operation semantics, - * and are used by the bytecode executor and the API (among other places). - * Some primitives are only implemented as part of the API and have no - * "internal" helper. This is the case when an internal helper would not - * really be useful; e.g. the operation is rare, uses value stack heavily, - * etc. - * - * The operation arguments depend on what is required to implement - * the operation: - * - * - If an operation is simple and stateless, and has no side - * effects, it won't take an duk_hthread argument and its - * arguments may be duk_tval pointers (which are safe as long - * as no side effects take place). - * - * - If complex coercions are required (e.g. a "ToNumber" coercion) - * or errors may be thrown, the operation takes an duk_hthread - * argument. This also implies that the operation may have - * arbitrary side effects, invalidating any duk_tval pointers. - * - * - For operations with potential side effects, arguments can be - * taken in several ways: - * - * a) as duk_tval pointers, which makes sense if the "common case" - * can be resolved without side effects (e.g. coercion); the - * arguments are pushed to the valstack for coercion if - * necessary - * - * b) as duk_tval values - * - * c) implicitly on value stack top - * - * d) as indices to the value stack - * - * Future work: - * - * - Argument styles may not be the most sensible in every case now. - * - * - In-place coercions might be useful for several operations, if - * in-place coercion is OK for the bytecode executor and the API. - */ - -/* #include duk_internal.h -> already included */ - -/* - * ToPrimitive() (E5 Section 9.1) - * - * ==> implemented in the API. - */ - -/* - * ToBoolean() (E5 Section 9.2) - */ - -DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) { - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: - case DUK_TAG_NULL: - return 0; - case DUK_TAG_BOOLEAN: - DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 || DUK_TVAL_GET_BOOLEAN(tv) == 1); - return DUK_TVAL_GET_BOOLEAN(tv); - case DUK_TAG_STRING: { - /* Symbols ToBoolean() coerce to true, regardless of their - * description. This happens with no explicit check because - * of the symbol representation byte prefix. - */ - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); - return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0); - } - case DUK_TAG_OBJECT: { - return 1; - } - case DUK_TAG_BUFFER: { - /* Mimic Uint8Array semantics: objects coerce true, regardless - * of buffer length (zero or not) or context. - */ - return 1; - } - case DUK_TAG_POINTER: { - void *p = DUK_TVAL_GET_POINTER(tv); - return (p != NULL ? 1 : 0); - } - case DUK_TAG_LIGHTFUNC: { - return 1; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: - if (DUK_TVAL_GET_FASTINT(tv) != 0) { - return 1; - } else { - return 0; - } -#endif - default: { - /* number */ - duk_double_t d; -#if defined(DUK_USE_PREFER_SIZE) - int c; -#endif - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); - d = DUK_TVAL_GET_DOUBLE(tv); -#if defined(DUK_USE_PREFER_SIZE) - c = DUK_FPCLASSIFY((double) d); - if (c == DUK_FP_ZERO || c == DUK_FP_NAN) { - return 0; - } else { - return 1; - } -#else - DUK_ASSERT(duk_double_is_nan_or_zero(d) == 0 || duk_double_is_nan_or_zero(d) == 1); - return duk_double_is_nan_or_zero(d) ^ 1; -#endif - } - } - DUK_UNREACHABLE(); -} - -/* - * ToNumber() (E5 Section 9.3) - * - * Value to convert must be on stack top, and is popped before exit. - * - * See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf - * http://www.cs.indiana.edu/~burger/fp/index.html - * - * Notes on the conversion: - * - * - There are specific requirements on the accuracy of the conversion - * through a "Mathematical Value" (MV), so this conversion is not - * trivial. - * - * - Quick rejects (e.g. based on first char) are difficult because - * the grammar allows leading and trailing white space. - * - * - Quick reject based on string length is difficult even after - * accounting for white space; there may be arbitrarily many - * decimal digits. - * - * - Standard grammar allows decimal values ("123"), hex values - * ("0x123") and infinities - * - * - Unlike source code literals, ToNumber() coerces empty strings - * and strings with only whitespace to zero (not NaN). - */ - -/* E5 Section 9.3.1 */ -DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) { - duk_small_uint_t s2n_flags; - duk_double_t d; - - DUK_ASSERT(duk_is_string(thr, -1)); - - /* Quite lenient, e.g. allow empty as zero, but don't allow trailing - * garbage. - */ - s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | - DUK_S2N_FLAG_ALLOW_EXP | - DUK_S2N_FLAG_ALLOW_PLUS | - DUK_S2N_FLAG_ALLOW_MINUS | - DUK_S2N_FLAG_ALLOW_INF | - DUK_S2N_FLAG_ALLOW_FRAC | - DUK_S2N_FLAG_ALLOW_NAKED_FRAC | - DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | - DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO | - DUK_S2N_FLAG_ALLOW_LEADING_ZERO | - DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT | - DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT | - DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT; - - duk_numconv_parse(thr, 10 /*radix*/, s2n_flags); - -#if defined(DUK_USE_PREFER_SIZE) - d = duk_get_number(thr, -1); - duk_pop_unsafe(thr); -#else - thr->valstack_top--; - DUK_ASSERT(DUK_TVAL_IS_NUMBER(thr->valstack_top)); - DUK_ASSERT(DUK_TVAL_IS_DOUBLE(thr->valstack_top)); /* no fastint conversion in numconv now */ - DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(thr->valstack_top)); - d = DUK_TVAL_GET_DOUBLE(thr->valstack_top); /* assumes not a fastint */ - DUK_TVAL_SET_UNDEFINED(thr->valstack_top); -#endif - - return d; -} - -DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv != NULL); - - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_UNDEFINED: { - /* return a specific NaN (although not strictly necessary) */ - duk_double_union du; - DUK_DBLUNION_SET_NAN(&du); - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - return du.d; - } - case DUK_TAG_NULL: { - /* +0.0 */ - return 0.0; - } - case DUK_TAG_BOOLEAN: { - if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) { - return 1.0; - } - return 0.0; - } - case DUK_TAG_STRING: { - /* For Symbols ToNumber() is always a TypeError. */ - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL); - } - duk_push_hstring(thr, h); - return duk__tonumber_string_raw(thr); - } - case DUK_TAG_BUFFER: /* plain buffer treated like object */ - case DUK_TAG_OBJECT: { - duk_double_t d; - duk_push_tval(thr, tv); - duk_to_primitive(thr, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */ - - /* recursive call for a primitive value (guaranteed not to cause second - * recursion). - */ - DUK_ASSERT(duk_get_tval(thr, -1) != NULL); - d = duk_js_tonumber(thr, duk_get_tval(thr, -1)); - - duk_pop_unsafe(thr); - return d; - } - case DUK_TAG_POINTER: { - /* Coerce like boolean */ - void *p = DUK_TVAL_GET_POINTER(tv); - return (p != NULL ? 1.0 : 0.0); - } - case DUK_TAG_LIGHTFUNC: { - /* +(function(){}) -> NaN */ - return DUK_DOUBLE_NAN; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: - return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); -#endif - default: { - /* number */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); - return DUK_TVAL_GET_DOUBLE(tv); - } - } - - DUK_UNREACHABLE(); -} - -/* - * ToInteger() (E5 Section 9.4) - */ - -/* exposed, used by e.g. duk_bi_date.c */ -DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) { -#if defined(DUK_USE_PREFER_SIZE) - duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); - - if (DUK_UNLIKELY(c == DUK_FP_NAN)) { - return 0.0; - } else if (DUK_UNLIKELY(c == DUK_FP_INFINITE)) { - return x; - } else { - /* Finite, including neg/pos zero. Neg zero sign must be - * preserved. - */ - return duk_double_trunc_towards_zero(x); - } -#else /* DUK_USE_PREFER_SIZE */ - /* NaN and Infinity have the same exponent so it's a cheap - * initial check for the rare path. - */ - if (DUK_UNLIKELY(duk_double_is_nan_or_inf(x) != 0U)) { - if (duk_double_is_nan(x)) { - return 0.0; - } else { - return x; - } - } else { - return duk_double_trunc_towards_zero(x); - } -#endif /* DUK_USE_PREFER_SIZE */ -} - -DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) { - /* XXX: fastint */ - duk_double_t d = duk_js_tonumber(thr, tv); /* invalidates tv */ - return duk_js_tointeger_number(d); -} - -/* - * ToInt32(), ToUint32(), ToUint16() (E5 Sections 9.5, 9.6, 9.7) - */ - -/* combined algorithm matching E5 Sections 9.5 and 9.6 */ -DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) { -#if defined (DUK_USE_PREFER_SIZE) - duk_small_int_t c; -#endif - -#if defined (DUK_USE_PREFER_SIZE) - c = (duk_small_int_t) DUK_FPCLASSIFY(x); - if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) { - return 0.0; - } -#else - if (duk_double_is_nan_zero_inf(x)) { - return 0.0; - } -#endif - - /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */ - x = duk_double_trunc_towards_zero(x); - - /* NOTE: fmod(x) result sign is same as sign of x, which - * differs from what Javascript wants (see Section 9.6). - */ - - x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */ - - if (x < 0.0) { - x += DUK_DOUBLE_2TO32; - } - DUK_ASSERT(x >= 0 && x < DUK_DOUBLE_2TO32); /* -> x in [0, 2**32[ */ - - if (is_toint32) { - if (x >= DUK_DOUBLE_2TO31) { - /* x in [2**31, 2**32[ */ - - x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */ - } - } - - return x; -} - -DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) { - duk_double_t d; - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv)) { - return DUK_TVAL_GET_FASTINT_I32(tv); - } -#endif - - d = duk_js_tonumber(thr, tv); /* invalidates tv */ - d = duk__toint32_touint32_helper(d, 1); - DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL); - DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0); /* [-0x80000000,0x7fffffff] */ - DUK_ASSERT(d == ((duk_double_t) ((duk_int32_t) d))); /* whole, won't clip */ - return (duk_int32_t) d; -} - - -DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) { - duk_double_t d; - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv)) { - return DUK_TVAL_GET_FASTINT_U32(tv); - } -#endif - - d = duk_js_tonumber(thr, tv); /* invalidates tv */ - d = duk__toint32_touint32_helper(d, 0); - DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL); - DUK_ASSERT(d >= 0.0 && d <= 4294967295.0); /* [0x00000000, 0xffffffff] */ - DUK_ASSERT(d == ((duk_double_t) ((duk_uint32_t) d))); /* whole, won't clip */ - return (duk_uint32_t) d; - -} - -DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) { - /* should be a safe way to compute this */ - return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU); -} - -/* - * ToString() (E5 Section 9.8) - * ToObject() (E5 Section 9.9) - * CheckObjectCoercible() (E5 Section 9.10) - * IsCallable() (E5 Section 9.11) - * - * ==> implemented in the API. - */ - -/* - * Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4, - * 9.12). These have much in common so they can share some helpers. - * - * Future work notes: - * - * - Current implementation (and spec definition) has recursion; this should - * be fixed if possible. - * - * - String-to-number coercion should be possible without going through the - * value stack (and be more compact) if a shared helper is invoked. - */ - -/* Note that this is the same operation for strict and loose equality: - * - E5 Section 11.9.3, step 1.c (loose) - * - E5 Section 11.9.6, step 4 (strict) - */ - -DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) { -#if defined(DUK_USE_PARANOID_MATH) - /* Straightforward algorithm, makes fewer compiler assumptions. */ - duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x); - duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y); - if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) { - return 0; - } - if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) { - return 1; - } - if (x == y) { - return 1; - } - return 0; -#else /* DUK_USE_PARANOID_MATH */ - /* Better equivalent algorithm. If the compiler is compliant, C and - * Ecmascript semantics are identical for this particular comparison. - * In particular, NaNs must never compare equal and zeroes must compare - * equal regardless of sign. Could also use a macro, but this inlines - * already nicely (no difference on gcc, for instance). - */ - if (x == y) { - /* IEEE requires that NaNs compare false */ - DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN); - DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN); - return 1; - } else { - /* IEEE requires that zeros compare the same regardless - * of their signed, so if both x and y are zeroes, they - * are caught above. - */ - DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO)); - return 0; - } -#endif /* DUK_USE_PARANOID_MATH */ -} - -DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) { -#if defined(DUK_USE_PARANOID_MATH) - duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x); - duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y); - - if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) { - /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */ - return 1; - } - if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) { - /* Note: cannot assume that a non-zero return value of signbit() would - * always be the same -- hence cannot (portably) use something like: - * - * signbit(x) == signbit(y) - */ - duk_small_int_t sx = DUK_SIGNBIT(x) ? 1 : 0; - duk_small_int_t sy = DUK_SIGNBIT(y) ? 1 : 0; - return (sx == sy); - } - - /* normal comparison; known: - * - both x and y are not NaNs (but one of them can be) - * - both x and y are not zero (but one of them can be) - * - x and y may be denormal or infinite - */ - - return (x == y); -#else /* DUK_USE_PARANOID_MATH */ - duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x); - duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y); - - if (x == y) { - /* IEEE requires that NaNs compare false */ - DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN); - DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN); - - /* Using classification has smaller footprint than direct comparison. */ - if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) { - /* Note: cannot assume that a non-zero return value of signbit() would - * always be the same -- hence cannot (portably) use something like: - * - * signbit(x) == signbit(y) - */ - return duk_double_same_sign(x, y); - } - return 1; - } else { - /* IEEE requires that zeros compare the same regardless - * of their sign, so if both x and y are zeroes, they - * are caught above. - */ - DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO)); - - /* Difference to non-strict/strict comparison is that NaNs compare - * equal and signed zero signs matter. - */ - if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) { - /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */ - return 1; - } - return 0; - } -#endif /* DUK_USE_PARANOID_MATH */ -} - -DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) { - duk_uint_t type_mask_x; - duk_uint_t type_mask_y; - - /* If flags != 0 (strict or SameValue), thr can be NULL. For loose - * equals comparison it must be != NULL. - */ - DUK_ASSERT(flags != 0 || thr != NULL); - - /* - * Same type? - * - * Note: since number values have no explicit tag in the 8-byte - * representation, need the awkward if + switch. - */ - -#if defined(DUK_USE_FASTINT) - if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) { - if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) { - return 1; - } else { - return 0; - } - } - else -#endif - if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) { - duk_double_t d1, d2; - - /* Catches both doubles and cases where only one argument is - * a fastint so can't assume a double. - */ - d1 = DUK_TVAL_GET_NUMBER(tv_x); - d2 = DUK_TVAL_GET_NUMBER(tv_y); - if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) { - /* SameValue */ - return duk__js_samevalue_number(d1, d2); - } else { - /* equals and strict equals */ - return duk__js_equals_number(d1, d2); - } - } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) { - switch (DUK_TVAL_GET_TAG(tv_x)) { - case DUK_TAG_UNDEFINED: - case DUK_TAG_NULL: { - return 1; - } - case DUK_TAG_BOOLEAN: { - return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y); - } - case DUK_TAG_POINTER: { - return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y); - } - case DUK_TAG_STRING: - case DUK_TAG_OBJECT: { - /* Heap pointer comparison suffices for strings and objects. - * Symbols compare equal if they have the same internal - * representation; again heap pointer comparison suffices. - */ - return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y); - } - case DUK_TAG_BUFFER: { - /* In Duktape 2.x plain buffers mimic Uint8Array objects - * so always compare by heap pointer. In Duktape 1.x - * strict comparison would compare heap pointers and - * non-strict would compare contents. - */ - return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y); - } - case DUK_TAG_LIGHTFUNC: { - /* At least 'magic' has a significant impact on function - * identity. - */ - duk_small_uint_t lf_flags_x; - duk_small_uint_t lf_flags_y; - duk_c_function func_x; - duk_c_function func_y; - - DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x); - DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y); - return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: { - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x)); - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y)); - DUK_UNREACHABLE(); - return 0; - } - } - } - - if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) { - return 0; - } - - DUK_ASSERT(flags == 0); /* non-strict equality from here on */ - - /* - * Types are different; various cases for non-strict comparison - * - * Since comparison is symmetric, we use a "swap trick" to reduce - * code size. - */ - - type_mask_x = duk_get_type_mask_tval(tv_x); - type_mask_y = duk_get_type_mask_tval(tv_y); - - /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */ - if ((type_mask_x & (DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_NULL)) && - (type_mask_y & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED))) { - return 1; - } - - /* Number/string -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */ - if ((type_mask_x & DUK_TYPE_MASK_NUMBER) && (type_mask_y & DUK_TYPE_MASK_STRING)) { - if (!DUK_TVAL_STRING_IS_SYMBOL(tv_y)) { - duk_double_t d1, d2; - d1 = DUK_TVAL_GET_NUMBER(tv_x); - d2 = duk_to_number_tval(thr, tv_y); - return duk__js_equals_number(d1, d2); - } - } - if ((type_mask_x & DUK_TYPE_MASK_STRING) && (type_mask_y & DUK_TYPE_MASK_NUMBER)) { - if (!DUK_TVAL_STRING_IS_SYMBOL(tv_x)) { - duk_double_t d1, d2; - d1 = DUK_TVAL_GET_NUMBER(tv_y); - d2 = duk_to_number_tval(thr, tv_x); - return duk__js_equals_number(d1, d2); - } - } - - /* Boolean/any -> coerce boolean to number and try again. If boolean is - * compared to a pointer, the final comparison after coercion now always - * yields false (as pointer vs. number compares to false), but this is - * not special cased. - * - * ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. - */ - if (type_mask_x & DUK_TYPE_MASK_BOOLEAN) { - DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_x) == 0 || DUK_TVAL_GET_BOOLEAN(tv_x) == 1); - duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_x)); - duk_push_tval(thr, tv_y); - goto recursive_call; - } - if (type_mask_y & DUK_TYPE_MASK_BOOLEAN) { - DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1); - duk_push_tval(thr, tv_x); - duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_y)); - goto recursive_call; - } - - /* String-number-symbol/object -> coerce object to primitive (apparently without hint), then try again. */ - if ((type_mask_x & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER)) && - (type_mask_y & DUK_TYPE_MASK_OBJECT)) { - /* No symbol check needed because symbols and strings are accepted. */ - duk_push_tval(thr, tv_x); - duk_push_tval(thr, tv_y); - duk_to_primitive(thr, -1, DUK_HINT_NONE); /* apparently no hint? */ - goto recursive_call; - } - if ((type_mask_x & DUK_TYPE_MASK_OBJECT) && - (type_mask_y & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER))) { - /* No symbol check needed because symbols and strings are accepted. */ - duk_push_tval(thr, tv_x); - duk_push_tval(thr, tv_y); - duk_to_primitive(thr, -2, DUK_HINT_NONE); /* apparently no hint? */ - goto recursive_call; - } - - /* Nothing worked -> not equal. */ - return 0; - - recursive_call: - /* Shared code path to call the helper again with arguments on stack top. */ - { - duk_bool_t rc; - rc = duk_js_equals_helper(thr, - DUK_GET_TVAL_NEGIDX(thr, -2), - DUK_GET_TVAL_NEGIDX(thr, -1), - 0 /*flags:nonstrict*/); - duk_pop_2_unsafe(thr); - return rc; - } -} - -/* - * Comparisons (x >= y, x > y, x <= y, x < y) - * - * E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first - * flags to get the rest. - */ - -/* XXX: this should probably just operate on the stack top, because it - * needs to push stuff on the stack anyway... - */ - -DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2) { - duk_size_t prefix_len; - duk_small_int_t rc; - - prefix_len = (len1 <= len2 ? len1 : len2); - - /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length - * inputs so no zero length check is needed. - */ - rc = DUK_MEMCMP((const void *) buf1, - (const void *) buf2, - (size_t) prefix_len); - - if (rc < 0) { - return -1; - } else if (rc > 0) { - return 1; - } - - /* prefix matches, lengths matter now */ - if (len1 < len2) { - /* e.g. "x" < "xx" */ - return -1; - } else if (len1 > len2) { - return 1; - } - - return 0; -} - -DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) { - /* - * String comparison (E5 Section 11.8.5, step 4), which - * needs to compare codepoint by codepoint. - * - * However, UTF-8 allows us to use strcmp directly: the shared - * prefix will be encoded identically (UTF-8 has unique encoding) - * and the first differing character can be compared with a simple - * unsigned byte comparison (which strcmp does). - * - * This will not work properly for non-xutf-8 strings, but this - * is not an issue for compliance. - */ - - DUK_ASSERT(h1 != NULL); - DUK_ASSERT(h2 != NULL); - - return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1), - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2), - (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1), - (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2)); -} - -#if 0 /* unused */ -DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) { - /* Similar to String comparison. */ - - DUK_ASSERT(h1 != NULL); - DUK_ASSERT(h2 != NULL); - DUK_UNREF(heap); - - return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1), - (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2), - (duk_size_t) DUK_HBUFFER_GET_SIZE(h1), - (duk_size_t) DUK_HBUFFER_GET_SIZE(h2)); -} -#endif - -#if defined(DUK_USE_FASTINT) -DUK_LOCAL duk_bool_t duk__compare_fastint(duk_bool_t retval, duk_int64_t v1, duk_int64_t v2) { - DUK_ASSERT(retval == 0 || retval == 1); - if (v1 < v2) { - return retval ^ 1; - } else { - return retval; - } -} -#endif - -#if defined(DUK_USE_PARANOID_MATH) -DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) { - duk_small_int_t c1, s1, c2, s2; - - DUK_ASSERT(retval == 0 || retval == 1); - c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1); - s1 = (duk_small_int_t) DUK_SIGNBIT(d1); - c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2); - s2 = (duk_small_int_t) DUK_SIGNBIT(d2); - - if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) { - return 0; /* Always false, regardless of negation. */ - } - - if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) { - /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0, - * steps e, f, and g. - */ - return retval; /* false */ - } - - if (d1 == d2) { - return retval; /* false */ - } - - if (c1 == DUK_FP_INFINITE && s1 == 0) { - /* x == +Infinity */ - return retval; /* false */ - } - - if (c2 == DUK_FP_INFINITE && s2 == 0) { - /* y == +Infinity */ - return retval ^ 1; /* true */ - } - - if (c2 == DUK_FP_INFINITE && s2 != 0) { - /* y == -Infinity */ - return retval; /* false */ - } - - if (c1 == DUK_FP_INFINITE && s1 != 0) { - /* x == -Infinity */ - return retval ^ 1; /* true */ - } - - if (d1 < d2) { - return retval ^ 1; /* true */ - } - - return retval; /* false */ -} -#else /* DUK_USE_PARANOID_MATH */ -DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) { - /* This comparison tree relies doesn't match the exact steps in - * E5 Section 11.8.5 but should produce the same results. The - * steps rely on exact IEEE semantics for NaNs, etc. - */ - - DUK_ASSERT(retval == 0 || retval == 1); - if (d1 < d2) { - /* In no case should both (d1 < d2) and (d2 < d1) be true. - * It's possible that neither is true though, and that's - * handled below. - */ - DUK_ASSERT(!(d2 < d1)); - - /* - d1 < d2, both d1/d2 are normals (not Infinity, not NaN) - * - d2 is +Infinity, d1 != +Infinity and NaN - * - d1 is -Infinity, d2 != -Infinity and NaN - */ - return retval ^ 1; - } else { - if (d2 < d1) { - /* - !(d1 < d2), both d1/d2 are normals (not Infinity, not NaN) - * - d1 is +Infinity, d2 != +Infinity and NaN - * - d2 is -Infinity, d1 != -Infinity and NaN - */ - return retval; - } else { - /* - d1 and/or d2 is NaN - * - d1 and d2 are both +/- 0 - * - d1 == d2 (including infinities) - */ - if (duk_double_is_nan(d1) || duk_double_is_nan(d2)) { - /* Note: undefined from Section 11.8.5 always - * results in false return (see e.g. Section - * 11.8.3) - hence special treatment here. - */ - return 0; /* zero regardless of negation */ - } else { - return retval; - } - } - } -} -#endif /* DUK_USE_PARANOID_MATH */ - -DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) { - duk_double_t d1, d2; - duk_small_int_t rc; - duk_bool_t retval; - - DUK_ASSERT(DUK_COMPARE_FLAG_NEGATE == 1); /* Rely on this flag being lowest. */ - retval = flags & DUK_COMPARE_FLAG_NEGATE; - DUK_ASSERT(retval == 0 || retval == 1); - - /* Fast path for fastints */ -#if defined(DUK_USE_FASTINT) - if (DUK_LIKELY(DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y))) { - return duk__compare_fastint(retval, - DUK_TVAL_GET_FASTINT(tv_x), - DUK_TVAL_GET_FASTINT(tv_y)); - } -#endif /* DUK_USE_FASTINT */ - - /* Fast path for numbers (one of which may be a fastint) */ -#if !defined(DUK_USE_PREFER_SIZE) - if (DUK_LIKELY(DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y))) { - return duk__compare_number(retval, - DUK_TVAL_GET_NUMBER(tv_x), - DUK_TVAL_GET_NUMBER(tv_y)); - } -#endif - - /* Slow path */ - - duk_push_tval(thr, tv_x); - duk_push_tval(thr, tv_y); - - if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) { - duk_to_primitive(thr, -2, DUK_HINT_NUMBER); - duk_to_primitive(thr, -1, DUK_HINT_NUMBER); - } else { - duk_to_primitive(thr, -1, DUK_HINT_NUMBER); - duk_to_primitive(thr, -2, DUK_HINT_NUMBER); - } - - /* Note: reuse variables */ - tv_x = DUK_GET_TVAL_NEGIDX(thr, -2); - tv_y = DUK_GET_TVAL_NEGIDX(thr, -1); - - if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) { - duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x); - duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y); - DUK_ASSERT(h1 != NULL); - DUK_ASSERT(h2 != NULL); - - if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) { - rc = duk_js_string_compare(h1, h2); - duk_pop_2_unsafe(thr); - if (rc < 0) { - return retval ^ 1; - } else { - return retval; - } - } - - /* One or both are Symbols: fall through to handle in the - * generic path. Concretely, ToNumber() will fail. - */ - } - - /* Ordering should not matter (E5 Section 11.8.5, step 3.a). */ -#if 0 - if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) { - d1 = duk_to_number_m2(thr); - d2 = duk_to_number_m1(thr); - } else { - d2 = duk_to_number_m1(thr); - d1 = duk_to_number_m2(thr); - } -#endif - d1 = duk_to_number_m2(thr); - d2 = duk_to_number_m1(thr); - - /* We want to duk_pop_2_unsafe(thr); because the values are numbers - * no decref check is needed. - */ -#if defined(DUK_USE_PREFER_SIZE) - duk_pop_2_nodecref_unsafe(thr); -#else - DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -2))); - DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -1))); - DUK_ASSERT(duk_get_top(thr) >= 2); - thr->valstack_top -= 2; - tv_x = thr->valstack_top; - tv_y = tv_x + 1; - DUK_TVAL_SET_UNDEFINED(tv_x); /* Value stack policy */ - DUK_TVAL_SET_UNDEFINED(tv_y); -#endif - - return duk__compare_number(retval, d1, d2); -} - -/* - * instanceof - */ - -/* - * E5 Section 11.8.6 describes the main algorithm, which uses - * [[HasInstance]]. [[HasInstance]] is defined for only - * function objects: - * - * - Normal functions: - * E5 Section 15.3.5.3 - * - Functions established with Function.prototype.bind(): - * E5 Section 15.3.4.5.3 - * - * For other objects, a TypeError is thrown. - * - * Limited Proxy support: don't support 'getPrototypeOf' trap but - * continue lookup in Proxy target if the value is a Proxy. - */ - -DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { - duk_hobject *func; - duk_hobject *val; - duk_hobject *proto; - duk_tval *tv; - duk_bool_t skip_first; - duk_uint_t sanity; - - /* - * Get the values onto the stack first. It would be possible to cover - * some normal cases without resorting to the value stack. - * - * The right hand side could be a light function (as they generally - * behave like objects). Light functions never have a 'prototype' - * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError. - * Using duk_require_hobject() is thus correct (except for error msg). - */ - - duk_push_tval(thr, tv_x); - duk_push_tval(thr, tv_y); - func = duk_require_hobject(thr, -1); - DUK_ASSERT(func != NULL); - - /* - * For bound objects, [[HasInstance]] just calls the target function - * [[HasInstance]]. If that is again a bound object, repeat until - * we find a non-bound Function object. - * - * The bound function chain is now "collapsed" so there can be only - * one bound function in the chain. - */ - - if (!DUK_HOBJECT_IS_CALLABLE(func)) { - /* - * Note: of native Ecmascript objects, only Function instances - * have a [[HasInstance]] internal property. Custom objects might - * also have it, but not in current implementation. - * - * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF? - */ - goto error_invalid_rval; - } - - if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) { - duk_push_tval(thr, &((duk_hboundfunc *) func)->target); - duk_replace(thr, -2); - func = duk_require_hobject(thr, -1); /* lightfunc throws */ - - /* Rely on Function.prototype.bind() never creating bound - * functions whose target is not proper. - */ - DUK_ASSERT(func != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func)); - } - - /* - * 'func' is now a non-bound object which supports [[HasInstance]] - * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on - * to execute E5 Section 15.3.5.3. - */ - - DUK_ASSERT(func != NULL); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); - DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func)); - - /* [ ... lval rval(func) ] */ - - /* For lightfuncs, buffers, and pointers start the comparison directly - * from the virtual prototype object. - */ - skip_first = 0; - tv = DUK_GET_TVAL_NEGIDX(thr, -2); - switch (DUK_TVAL_GET_TAG(tv)) { - case DUK_TAG_LIGHTFUNC: - val = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]; - DUK_ASSERT(val != NULL); - break; - case DUK_TAG_BUFFER: - val = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; - DUK_ASSERT(val != NULL); - break; - case DUK_TAG_POINTER: - val = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE]; - DUK_ASSERT(val != NULL); - break; - case DUK_TAG_OBJECT: - skip_first = 1; /* Ignore object itself on first round. */ - val = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(val != NULL); - break; - default: - goto pop2_and_false; - } - DUK_ASSERT(val != NULL); /* Loop doesn't actually rely on this. */ - - /* Look up .prototype of rval. Leave it on the value stack in case it - * has been virtualized (e.g. getter, Proxy trap). - */ - duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */ -#if defined(DUK_USE_VERBOSE_ERRORS) - proto = duk_get_hobject(thr, -1); - if (proto == NULL) { - goto error_invalid_rval_noproto; - } -#else - proto = duk_require_hobject(thr, -1); -#endif - - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - do { - /* - * Note: prototype chain is followed BEFORE first comparison. This - * means that the instanceof lval is never itself compared to the - * rval.prototype property. This is apparently intentional, see E5 - * Section 15.3.5.3, step 4.a. - * - * Also note: - * - * js> (function() {}) instanceof Function - * true - * js> Function instanceof Function - * true - * - * For the latter, h_proto will be Function.prototype, which is the - * built-in Function prototype. Because Function.[[Prototype]] is - * also the built-in Function prototype, the result is true. - */ - - if (!val) { - goto pop3_and_false; - } - - DUK_ASSERT(val != NULL); -#if defined(DUK_USE_ES6_PROXY) - val = duk_hobject_resolve_proxy_target(val); -#endif - - if (skip_first) { - skip_first = 0; - } else if (val == proto) { - goto pop3_and_true; - } - - DUK_ASSERT(val != NULL); - val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val); - } while (--sanity > 0); - - if (DUK_UNLIKELY(sanity == 0)) { - DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); - } - DUK_UNREACHABLE(); - - pop2_and_false: - duk_pop_2_unsafe(thr); - return 0; - - pop3_and_false: - duk_pop_3_unsafe(thr); - return 0; - - pop3_and_true: - duk_pop_3_unsafe(thr); - return 1; - - error_invalid_rval: - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL); - return 0; - -#if defined(DUK_USE_VERBOSE_ERRORS) - error_invalid_rval_noproto: - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO); - return 0; -#endif -} - -/* - * in - */ - -/* - * E5 Sections 11.8.7, 8.12.6. - * - * Basically just a property existence check using [[HasProperty]]. - */ - -DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { - duk_bool_t retval; - - /* - * Get the values onto the stack first. It would be possible to cover - * some normal cases without resorting to the value stack (e.g. if - * lval is already a string). - */ - - /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj' - * must be string coerced before the internal HasProperty() algorithm is - * invoked. A fast path skipping coercion could be safely implemented for - * numbers (as number-to-string coercion has no side effects). For ES2015 - * proxy behavior, the trap 'key' argument must be in a string coerced - * form (which is a shame). - */ - - /* TypeError if rval is not an object or object like (e.g. lightfunc - * or plain buffer). - */ - duk_push_tval(thr, tv_x); - duk_push_tval(thr, tv_y); - duk_require_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); - - (void) duk_to_property_key_hstring(thr, -2); - - retval = duk_hobject_hasprop(thr, - DUK_GET_TVAL_NEGIDX(thr, -1), - DUK_GET_TVAL_NEGIDX(thr, -2)); - - duk_pop_2_unsafe(thr); - return retval; -} - -/* - * typeof - * - * E5 Section 11.4.3. - * - * Very straightforward. The only question is what to return for our - * non-standard tag / object types. - * - * There is an unfortunate string constant define naming problem with - * typeof return values for e.g. "Object" and "object"; careful with - * the built-in string defines. The LC_XXX defines are used for the - * lowercase variants now. - */ - -DUK_INTERNAL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x) { - duk_small_uint_t stridx = 0; - - switch (DUK_TVAL_GET_TAG(tv_x)) { - case DUK_TAG_UNDEFINED: { - stridx = DUK_STRIDX_LC_UNDEFINED; - break; - } - case DUK_TAG_NULL: { - /* Note: not a typo, "object" is returned for a null value. */ - stridx = DUK_STRIDX_LC_OBJECT; - break; - } - case DUK_TAG_BOOLEAN: { - stridx = DUK_STRIDX_LC_BOOLEAN; - break; - } - case DUK_TAG_POINTER: { - /* Implementation specific. */ - stridx = DUK_STRIDX_LC_POINTER; - break; - } - case DUK_TAG_STRING: { - duk_hstring *str; - - /* All internal keys are identified as Symbols. */ - str = DUK_TVAL_GET_STRING(tv_x); - DUK_ASSERT(str != NULL); - if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) { - stridx = DUK_STRIDX_LC_SYMBOL; - } else { - stridx = DUK_STRIDX_LC_STRING; - } - break; - } - case DUK_TAG_OBJECT: { - duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x); - DUK_ASSERT(obj != NULL); - if (DUK_HOBJECT_IS_CALLABLE(obj)) { - stridx = DUK_STRIDX_LC_FUNCTION; - } else { - stridx = DUK_STRIDX_LC_OBJECT; - } - break; - } - case DUK_TAG_BUFFER: { - /* Implementation specific. In Duktape 1.x this would be - * 'buffer', in Duktape 2.x changed to 'object' because plain - * buffers now mimic Uint8Array objects. - */ - stridx = DUK_STRIDX_LC_OBJECT; - break; - } - case DUK_TAG_LIGHTFUNC: { - stridx = DUK_STRIDX_LC_FUNCTION; - break; - } -#if defined(DUK_USE_FASTINT) - case DUK_TAG_FASTINT: -#endif - default: { - /* number */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x)); - stridx = DUK_STRIDX_LC_NUMBER; - break; - } - } - - DUK_ASSERT_STRIDX_VALID(stridx); - return stridx; -} - -/* - * Array index and length - * - * Array index: E5 Section 15.4 - * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write) - */ - -/* Compure array index from string context, or return a "not array index" - * indicator. - */ -DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) { - duk_uarridx_t res; - - /* Only strings with byte length 1-10 can be 32-bit array indices. - * Leading zeroes (except '0' alone), plus/minus signs are not allowed. - * We could do a lot of prechecks here, but since most strings won't - * start with any digits, it's simpler to just parse the number and - * fail quickly. - */ - - res = 0; - if (blen == 0) { - goto parse_fail; - } - do { - duk_uarridx_t dig; - dig = (duk_uarridx_t) (*str++) - DUK_ASC_0; - - if (dig <= 9U) { - /* Careful overflow handling. When multiplying by 10: - * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding - * 0...9 is safe. - * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding - * 0...5 is safe, 6...9 overflows. - * - 0x1999999a x 10 = 0x100000004: always overflow. - */ - if (DUK_UNLIKELY(res >= 0x19999999UL)) { - if (res >= 0x1999999aUL) { - /* Always overflow. */ - goto parse_fail; - } - DUK_ASSERT(res == 0x19999999UL); - if (dig >= 6U) { - goto parse_fail; - } - res = 0xfffffffaUL + dig; - DUK_ASSERT(res >= 0xfffffffaUL); - DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */ - } else { - res = res * 10U + dig; - if (DUK_UNLIKELY(res == 0)) { - /* If 'res' is 0, previous 'res' must - * have been 0 and we scanned in a zero. - * This is only allowed if blen == 1, - * i.e. the exact string '0'. - */ - if (blen == (duk_uint32_t) 1) { - return 0; - } - goto parse_fail; - } - } - } else { - /* Because 'dig' is unsigned, catches both values - * above '9' and below '0'. - */ - goto parse_fail; - } - } while (--blen > 0); - - return res; - - parse_fail: - return DUK_HSTRING_NO_ARRAY_INDEX; -} - -#if !defined(DUK_USE_HSTRING_ARRIDX) -/* Get array index for a string which is known to be an array index. This helper - * is needed when duk_hstring doesn't concretely store the array index, but strings - * are flagged as array indices at intern time. - */ -DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) { - const duk_uint8_t *p; - duk_uarridx_t res; - duk_uint8_t t; - - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h)); - - p = DUK_HSTRING_GET_DATA(h); - res = 0; - for (;;) { - t = *p++; - if (DUK_UNLIKELY(t == 0)) { - /* Scanning to NUL is always safe for interned strings. */ - break; - } - DUK_ASSERT(t >= (duk_uint8_t) DUK_ASC_0 && t <= (duk_uint8_t) DUK_ASC_9); - res = res * 10U + (duk_uarridx_t) t - (duk_uarridx_t) DUK_ASC_0; - } - return res; -} - -DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) { - DUK_ASSERT(h != NULL); - if (!DUK_HSTRING_HAS_ARRIDX(h)) { - return DUK_HSTRING_NO_ARRAY_INDEX; - } - return duk_js_to_arrayindex_hstring_fast_known(h); -} -#endif /* DUK_USE_HSTRING_ARRIDX */ -#line 1 "duk_js_var.c" -/* - * Identifier access and function closure handling. - * - * Provides the primitives for slow path identifier accesses: GETVAR, - * PUTVAR, DELVAR, etc. The fast path, direct register accesses, should - * be used for most identifier accesses. Consequently, these slow path - * primitives should be optimized for maximum compactness. - * - * Ecmascript environment records (declarative and object) are represented - * as internal objects with control keys. Environment records have a - * parent record ("outer environment reference") which is represented by - * the implicit prototype for technical reasons (in other words, it is a - * convenient field). The prototype chain is not followed in the ordinary - * sense for variable lookups. - * - * See identifier-handling.rst for more details on the identifier algorithms - * and the internal representation. See function-objects.rst for details on - * what function templates and instances are expected to look like. - * - * Care must be taken to avoid duk_tval pointer invalidation caused by - * e.g. value stack or object resizing. - * - * TODO: properties for function instances could be initialized much more - * efficiently by creating a property allocation for a certain size and - * filling in keys and values directly (and INCREFing both with "bulk incref" - * primitives. - * - * XXX: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit - * awkward (especially because they follow the prototype chain); rework - * if "raw" own property helpers are added. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Local result type for duk__get_identifier_reference() lookup. - */ - -typedef struct { - duk_hobject *env; - duk_hobject *holder; /* for object-bound identifiers */ - duk_tval *value; /* for register-bound and declarative env identifiers */ - duk_uint_t attrs; /* property attributes for identifier (relevant if value != NULL) */ - duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */ -} duk__id_lookup_result; - -/* - * Create a new function object based on a "template function" which contains - * compiled bytecode, constants, etc, but lacks a lexical environment. - * - * Ecmascript requires that each created closure is a separate object, with - * its own set of editable properties. However, structured property values - * (such as the formal arguments list and the variable map) are shared. - * Also the bytecode, constants, and inner functions are shared. - * - * See E5 Section 13.2 for detailed requirements on the function objects; - * there are no similar requirements for function "templates" which are an - * implementation dependent internal feature. Also see function-objects.rst - * for a discussion on the function instance properties provided by this - * implementation. - * - * Notes: - * - * * Order of internal properties should match frequency of use, since the - * properties will be linearly scanned on lookup (functions usually don't - * have enough properties to warrant a hash part). - * - * * The created closure is independent of its template; they do share the - * same 'data' buffer object, but the template object itself can be freed - * even if the closure object remains reachable. - */ - -DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompfunc *f) { - duk_tval *tv, *tv_end; - duk_hobject **funcs, **funcs_end; - - DUK_UNREF(thr); - - /* If function creation fails due to out-of-memory, the data buffer - * pointer may be NULL in some cases. That's actually possible for - * GC code, but shouldn't be possible here because the incomplete - * function will be unwound from the value stack and never instantiated. - */ - DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL); - - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f); - tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, f); - while (tv < tv_end) { - DUK_TVAL_INCREF(thr, tv); - tv++; - } - - funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, f); - funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f); - while (funcs < funcs_end) { - DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs); - funcs++; - } -} - -/* Push a new closure on the stack. - * - * Note: if fun_temp has NEWENV, i.e. a new lexical and variable declaration - * is created when the function is called, only outer_lex_env matters - * (outer_var_env is ignored and may or may not be same as outer_lex_env). - */ - -DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = { - /* order: most frequent to least frequent */ - DUK_STRIDX_INT_VARMAP, - DUK_STRIDX_INT_FORMALS, -#if defined(DUK_USE_PC2LINE) - DUK_STRIDX_INT_PC2LINE, -#endif -#if defined(DUK_USE_FUNC_FILENAME_PROPERTY) - DUK_STRIDX_FILE_NAME, -#endif -#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY) - DUK_STRIDX_INT_SOURCE -#endif -}; - -DUK_INTERNAL -void duk_js_push_closure(duk_hthread *thr, - duk_hcompfunc *fun_temp, - duk_hobject *outer_var_env, - duk_hobject *outer_lex_env, - duk_bool_t add_auto_proto) { - duk_hcompfunc *fun_clos; - duk_small_uint_t i; - duk_uint_t len_value; - - DUK_ASSERT(fun_temp != NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp) != NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp) != NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp) != NULL); - DUK_ASSERT(outer_var_env != NULL); - DUK_ASSERT(outer_lex_env != NULL); - DUK_UNREF(len_value); - - fun_clos = duk_push_hcompfunc(thr); - DUK_ASSERT(fun_clos != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) fun_clos) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); - - duk_push_hobject(thr, &fun_temp->obj); /* -> [ ... closure template ] */ - - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun_clos)); - DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) == NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) == NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) == NULL); - - DUK_HCOMPFUNC_SET_DATA(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp)); - DUK_HCOMPFUNC_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp)); - DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp)); - - /* Note: all references inside 'data' need to get their refcounts - * upped too. This is the case because refcounts are decreased - * through every function referencing 'data' independently. - */ - - DUK_HBUFFER_INCREF(thr, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos)); - duk__inc_data_inner_refcounts(thr, fun_temp); - - fun_clos->nregs = fun_temp->nregs; - fun_clos->nargs = fun_temp->nargs; -#if defined(DUK_USE_DEBUGGER_SUPPORT) - fun_clos->start_line = fun_temp->start_line; - fun_clos->end_line = fun_temp->end_line; -#endif - - DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) != NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) != NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) != NULL); - - /* XXX: Could also copy from template, but there's no way to have any - * other value here now (used code has no access to the template). - * Prototype is set by duk_push_hcompfunc(). - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); -#if 0 - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); -#endif - - /* Copy duk_hobject flags as is from the template using a mask. - * Leave out duk_heaphdr owned flags just in case (e.g. if there's - * some GC flag or similar). Some flags can then be adjusted - * separately if necessary. - */ - - /* DUK_HEAPHDR_SET_FLAGS() masks changes to non-duk_heaphdr flags only. */ - DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) fun_clos, DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp)); - DUK_DD(DUK_DDPRINT("fun_temp heaphdr flags: 0x%08lx, fun_clos heaphdr flags: 0x%08lx", - (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp), - (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_clos))); - - DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj)); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj)); - /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */ - /* DUK_HOBJECT_FLAG_NEWENV: handled below */ - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj)); - - if (!DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj)) { - /* If the template is not constructable don't add an automatic - * .prototype property. This is the case for e.g. ES2015 object - * literal getters/setters and method definitions. - */ - add_auto_proto = 0; - } - - /* - * Setup environment record properties based on the template and - * its flags. - * - * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment - * records represent identifiers "outside" the function; the - * "inner" environment records are created on demand. Otherwise, - * the environment records are those that will be directly used - * (e.g. for declarations). - * - * _Lexenv is always set; _Varenv defaults to _Lexenv if missing, - * so _Varenv is only set if _Lexenv != _Varenv. - * - * This is relatively complex, see doc/identifier-handling.rst. - */ - - if (DUK_HOBJECT_HAS_NEWENV(&fun_clos->obj)) { -#if defined(DUK_USE_FUNC_NAME_PROPERTY) - if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) { - duk_hobject *proto; - duk_hdecenv *new_env; - - /* - * Named function expression, name needs to be bound - * in an intermediate environment record. The "outer" - * lexical/variable environment will thus be: - * - * a) { funcname: , __prototype: outer_lex_env } - * b) { funcname: , __prototype: } (if outer_lex_env missing) - */ - - if (outer_lex_env) { - proto = outer_lex_env; - } else { - proto = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - } - - /* -> [ ... closure template env ] */ - new_env = duk_hdecenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); - DUK_ASSERT(new_env != NULL); - duk_push_hobject(thr, (duk_hobject *) new_env); - - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); - DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, proto); - DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto); - - DUK_ASSERT(new_env->thread == NULL); /* Closed. */ - DUK_ASSERT(new_env->varmap == NULL); - - /* It's important that duk_xdef_prop() is a 'raw define' so that any - * properties in an ancestor are never an issue (they should never be - * e.g. non-writable, but just in case). - * - * Because template objects are not visible to user code, the case - * where .name is missing shouldn't happen in practice. It it does, - * the name 'undefined' gets bound and maps to the closure (which is - * a bit odd, but safe). - */ - (void) duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME); - /* -> [ ... closure template env funcname ] */ - duk_dup_m4(thr); /* -> [ ... closure template env funcname closure ] */ - duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */ - /* env[funcname] = closure */ - - /* [ ... closure template env ] */ - - DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env); - DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env); - DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); - DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); - duk_pop_unsafe(thr); - - /* [ ... closure template ] */ - } - else -#endif /* DUK_USE_FUNC_NAME_PROPERTY */ - { - /* - * Other cases (function declaration, anonymous function expression, - * strict direct eval code). The "outer" environment will be whatever - * the caller gave us. - */ - - DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env); - DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_lex_env); - DUK_HOBJECT_INCREF(thr, outer_lex_env); - DUK_HOBJECT_INCREF(thr, outer_lex_env); - - /* [ ... closure template ] */ - } - } else { - /* - * Function gets no new environment when called. This is the - * case for global code, indirect eval code, and non-strict - * direct eval code. There is no direct correspondence to the - * E5 specification, as global/eval code is not exposed as a - * function. - */ - - DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)); - - DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env); - DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_var_env); - DUK_HOBJECT_INCREF(thr, outer_lex_env); /* NULLs not allowed; asserted on entry */ - DUK_HOBJECT_INCREF(thr, outer_var_env); - } - DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipO, lexenv -> %!ipO", - (duk_heaphdr *) fun_clos->var_env, - (duk_heaphdr *) fun_clos->lex_env)); - - /* Call handling assumes this for all callable closures. */ - DUK_ASSERT(DUK_HCOMPFUNC_GET_LEXENV(thr->heap, fun_clos) != NULL); - DUK_ASSERT(DUK_HCOMPFUNC_GET_VARENV(thr->heap, fun_clos) != NULL); - - /* - * Copy some internal properties directly - * - * The properties will be non-writable and non-enumerable, but - * configurable. - */ - - /* [ ... closure template ] */ - - DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - - for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) { - duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i]; - if (duk_get_prop_stridx_short(thr, -1, stridx)) { - /* [ ... closure template val ] */ - DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx)); - duk_xdef_prop_stridx_short(thr, -3, stridx, DUK_PROPDESC_FLAGS_C); - } else { - DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx)); - duk_pop_unsafe(thr); - } - } - - /* - * "length" maps to number of formals (E5 Section 13.2) for function - * declarations/expressions (non-bound functions). Note that 'nargs' - * is NOT necessarily equal to the number of arguments. Use length - * of _Formals; if missing, assume nargs matches .length. - */ - - /* [ ... closure template ] */ - - /* XXX: these lookups should be just own property lookups instead of - * looking up the inheritance chain. - */ - if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FORMALS)) { - /* [ ... closure template formals ] */ - len_value = (duk_uint_t) duk_get_length(thr, -1); /* could access duk_harray directly, not important */ - DUK_DD(DUK_DDPRINT("closure length from _Formals -> %ld", (long) len_value)); - } else { - len_value = fun_temp->nargs; - DUK_DD(DUK_DDPRINT("closure length defaulted from nargs -> %ld", (long) len_value)); - } - duk_pop_unsafe(thr); - - duk_push_uint(thr, len_value); /* [ ... closure template len_value ] */ - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); - - /* - * "prototype" is, by default, a fresh object with the "constructor" - * property. - * - * Note that this creates a circular reference for every function - * instance (closure) which prevents refcount-based collection of - * function instances. - * - * XXX: Try to avoid creating the default prototype object, because - * many functions are not used as constructors and the default - * prototype is unnecessary. Perhaps it could be created on-demand - * when it is first accessed? - */ - - /* [ ... closure template ] */ - - if (add_auto_proto) { - duk_push_object(thr); /* -> [ ... closure template newobj ] */ - duk_dup_m3(thr); /* -> [ ... closure template newobj closure ] */ - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */ - duk_compact(thr, -1); /* compact the prototype */ - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */ - } - - /* - * "arguments" and "caller" must be mapped to throwers for strict - * mode and bound functions (E5 Section 15.3.5). - * - * XXX: This is expensive to have for every strict function instance. - * Try to implement as virtual properties or on-demand created properties. - */ - - /* [ ... closure template ] */ - - if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) { - duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_CALLER); - duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_LC_ARGUMENTS); - } else { -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) - DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value")); - duk_push_null(thr); - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE); -#else - DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used")); -#endif - } - - /* - * "name" used to be non-standard but is now defined by ES2015. - * In ES2015/ES2016 the .name property is configurable. - */ - - /* [ ... closure template ] */ - -#if defined(DUK_USE_FUNC_NAME_PROPERTY) - /* XXX: Look for own property only; doesn't matter much because - * templates are bare objects. - */ - if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME)) { - /* [ ... closure template name ] */ - DUK_ASSERT(duk_is_string(thr, -1)); - DUK_DD(DUK_DDPRINT("setting function instance name to %!T", duk_get_tval(thr, -1))); - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); /* -> [ ... closure template ] */ - } else { - /* Anonymous functions don't have a .name in ES2015, so don't set - * it on the instance either. The instance will then inherit - * it from Function.prototype.name. - */ - DUK_DD(DUK_DDPRINT("not setting function instance .name")); - duk_pop_unsafe(thr); - } -#endif - - /* - * Compact the closure, in most cases no properties will be added later. - * Also, without this the closures end up having unused property slots - * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used). - * A better future solution would be to allocate the closure directly - * to correct size (and setup the properties directly without going - * through the API). - */ - - duk_compact(thr, -2); - - /* - * Some assertions (E5 Section 13.2). - */ - - DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION); - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); - DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj)); - DUK_ASSERT(duk_has_prop_stridx(thr, -2, DUK_STRIDX_LENGTH) != 0); - DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(thr, -2, DUK_STRIDX_PROTOTYPE) != 0); - /* May be missing .name */ - DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) || - duk_has_prop_stridx(thr, -2, DUK_STRIDX_CALLER) != 0); - DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) || - duk_has_prop_stridx(thr, -2, DUK_STRIDX_LC_ARGUMENTS) != 0); - - /* - * Finish - */ - - /* [ ... closure template ] */ - - DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT", - (duk_tval *) duk_get_tval(thr, -1), - (duk_tval *) duk_get_tval(thr, -2))); - - duk_pop_unsafe(thr); - - /* [ ... closure ] */ -} - -/* - * Delayed activation environment record initialization (for functions - * with NEWENV). - * - * The non-delayed initialization is handled by duk_handle_call(). - */ - -/* shared helper */ -DUK_INTERNAL -duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, - duk_hobject *func, - duk_size_t bottom_byteoff) { - duk_hdecenv *env; - duk_hobject *parent; - duk_hcompfunc *f; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(func != NULL); - - f = (duk_hcompfunc *) func; - parent = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f); - if (!parent) { - parent = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - } - - env = duk_hdecenv_alloc(thr, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); - DUK_ASSERT(env != NULL); - duk_push_hobject(thr, (duk_hobject *) env); - - DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); - DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent); - DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent); /* parent env is the prototype */ - - /* open scope information, for compiled functions only */ - - DUK_ASSERT(env->thread == NULL); - DUK_ASSERT(env->varmap == NULL); - DUK_ASSERT(env->regbase_byteoff == 0); - if (DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_hobject *varmap; - duk_tval *tv; - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); - if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - varmap = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(varmap != NULL); - env->varmap = varmap; - DUK_HOBJECT_INCREF(thr, varmap); - env->thread = thr; - DUK_HTHREAD_INCREF(thr, thr); - env->regbase_byteoff = bottom_byteoff; - } else { - /* If function has no _Varmap, leave the environment closed. */ - DUK_ASSERT(env->thread == NULL); - DUK_ASSERT(env->varmap == NULL); - DUK_ASSERT(env->regbase_byteoff == 0); - } - } - - return (duk_hobject *) env; -} - -DUK_INTERNAL -void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, - duk_activation *act) { - duk_hobject *func; - duk_hobject *env; - - DUK_ASSERT(thr != NULL); - func = DUK_ACT_GET_FUNC(act); - DUK_ASSERT(func != NULL); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */ - - /* - * Delayed initialization only occurs for 'NEWENV' functions. - */ - - DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func)); - DUK_ASSERT(act->lex_env == NULL); - DUK_ASSERT(act->var_env == NULL); - - env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff); - DUK_ASSERT(env != NULL); - /* 'act' is a stable pointer, so still OK. */ - - DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env)); -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - { - duk_hobject *p = env; - while (p) { - DUK_DDD(DUK_DDDPRINT(" -> %!ipO", (duk_heaphdr *) p)); - p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p); - } - } -#endif - - act->lex_env = env; - act->var_env = env; - DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */ - DUK_HOBJECT_INCREF(thr, env); - - duk_pop_unsafe(thr); -} - -/* - * Closing environment records. - * - * The environment record MUST be closed with the thread where its activation - * is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase - * and varmap must still be valid. On entry, 'env' must be reachable. - */ - -DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) { - duk_uint_fast32_t i; - duk_hobject *varmap; - duk_hstring *key; - duk_tval *tv; - duk_uint_t regnum; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(env != NULL); - - if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) { - DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO", (duk_heaphdr *) env)); - return; - } - - varmap = ((duk_hdecenv *) env)->varmap; - if (varmap == NULL) { - DUK_DDD(DUK_DDDPRINT("env already closed: %!iO", (duk_heaphdr *) env)); - - return; - } - DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL); - DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); - - DUK_DDD(DUK_DDDPRINT("closing env: %!iO", (duk_heaphdr *) env)); - DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); - - /* Env must be closed in the same thread as where it runs. */ - DUK_ASSERT(((duk_hdecenv *) env)->thread == thr); - - /* XXX: additional conditions when to close variables? we don't want to do it - * unless the environment may have "escaped" (referenced in a function closure). - * With delayed environments, the existence is probably good enough of a check. - */ - - /* Note: we rely on the _Varmap having a bunch of nice properties, like: - * - being compacted and unmodified during this process - * - not containing an array part - * - having correct value types - */ - - DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); - - /* Copy over current variable values from value stack to the - * environment record. The scope object is empty but may - * inherit from another scope which has conflicting names. - */ - - /* XXX: Do this using a once allocated entry area, no side effects. - * Hash part would need special treatment however (maybe copy, and - * then realloc with hash part if large enough). - */ - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { - duk_size_t regbase_byteoff; - - key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); - DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */ - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ - - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); - regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv); -#else - regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); -#endif - - regbase_byteoff = ((duk_hdecenv *) env)->regbase_byteoff; - DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum >= (duk_uint8_t *) thr->valstack); - DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum < (duk_uint8_t *) thr->valstack_top); - - /* If property already exists, overwrites silently. - * Property is writable, but not deletable (not configurable - * in terms of property attributes). - */ - duk_push_tval(thr, (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum)); - DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T", - (duk_heaphdr *) key, - (long) regnum, - (duk_tval *) duk_get_tval(thr, -1))); - duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE); - } - - /* NULL atomically to avoid inconsistent state + side effects. */ - DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread); - DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap); - ((duk_hdecenv *) env)->thread = NULL; - ((duk_hdecenv *) env)->varmap = NULL; - - DUK_DDD(DUK_DDDPRINT("env after closing: %!O", (duk_heaphdr *) env)); -} - -/* - * GETIDREF: a GetIdentifierReference-like helper. - * - * Provides a parent traversing lookup and a single level lookup - * (for HasBinding). - * - * Instead of returning the value, returns a bunch of values allowing - * the caller to read, write, or delete the binding. Value pointers - * are duk_tval pointers which can be mutated directly as long as - * refcounts are properly updated. Note that any operation which may - * reallocate valstacks or compact objects may invalidate the returned - * duk_tval (but not object) pointers, so caller must be very careful. - * - * If starting environment record 'env' is given, 'act' is ignored. - * However, if 'env' is NULL, the caller may identify, in 'act', an - * activation which hasn't had its declarative environment initialized - * yet. The activation registers are then looked up, and its parent - * traversed normally. - * - * The 'out' structure values are only valid if the function returns - * success (non-zero). - */ - -/* lookup name from an open declarative record's registers */ -DUK_LOCAL -duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr, - duk_hstring *name, - duk_hdecenv *env, - duk__id_lookup_result *out) { - duk_tval *tv; - duk_size_t reg_rel; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(name != NULL); - DUK_ASSERT(env != NULL); - DUK_ASSERT(out != NULL); - - DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env)); - DUK_ASSERT_HDECENV_VALID(env); - - if (env->thread == NULL) { - /* already closed */ - return 0; - } - DUK_ASSERT(env->varmap != NULL); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env->varmap, name); - if (DUK_UNLIKELY(tv == NULL)) { - return 0; - } - - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); - reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv); -#else - reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); -#endif - DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */ - - tv = (duk_tval *) (void *) ((duk_uint8_t *) env->thread->valstack + env->regbase_byteoff + sizeof(duk_tval) * reg_rel); - DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */ - - out->value = tv; - out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->env = (duk_hobject *) env; - out->holder = NULL; - out->has_this = 0; - return 1; -} - -/* lookup name from current activation record's functions' registers */ -DUK_LOCAL -duk_bool_t duk__getid_activation_regs(duk_hthread *thr, - duk_hstring *name, - duk_activation *act, - duk__id_lookup_result *out) { - duk_tval *tv; - duk_hobject *func; - duk_hobject *varmap; - duk_size_t reg_rel; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(name != NULL); - DUK_ASSERT(act != NULL); - DUK_ASSERT(out != NULL); - - func = DUK_ACT_GET_FUNC(act); - DUK_ASSERT(func != NULL); - DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func)); - - if (!DUK_HOBJECT_IS_COMPFUNC(func)) { - return 0; - } - - /* XXX: move varmap to duk_hcompfunc struct field. */ - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); - if (!tv) { - return 0; - } - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - varmap = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(varmap != NULL); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name); - if (!tv) { - return 0; - } - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); - DUK_ASSERT_DISABLE(reg_rel >= 0); - DUK_ASSERT(reg_rel < ((duk_hcompfunc *) func)->nregs); - - tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff); - tv += reg_rel; - - out->value = tv; - out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->env = NULL; - out->holder = NULL; - out->has_this = 0; - return 1; -} - -DUK_LOCAL -duk_bool_t duk__get_identifier_reference(duk_hthread *thr, - duk_hobject *env, - duk_hstring *name, - duk_activation *act, - duk_bool_t parents, - duk__id_lookup_result *out) { - duk_tval *tv; - duk_uint_t sanity; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(env != NULL || act != NULL); - DUK_ASSERT(name != NULL); - DUK_ASSERT(out != NULL); - - DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env)); - DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env)); - - /* - * Conceptually, we look for the identifier binding by starting from - * 'env' and following to chain of environment records (represented - * by the prototype chain). - * - * If 'env' is NULL, the current activation does not yet have an - * allocated declarative environment record; this should be treated - * exactly as if the environment record existed but had no bindings - * other than register bindings. - * - * Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared - * the environment will always be initialized immediately; hence - * a NULL 'env' should only happen with the flag set. This is the - * case for: (1) function calls, and (2) strict, direct eval calls. - */ - - if (env == NULL && act != NULL) { - duk_hobject *func; - duk_hcompfunc *f; - - DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> " - "delayed env case, look up activation regs first")); - - /* - * Try registers - */ - - if (duk__getid_activation_regs(thr, name, act, out)) { - DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " - "(found from register bindings when env=NULL)", - (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (long) out->has_this, - (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); - return 1; - } - - DUK_DDD(DUK_DDDPRINT("not found in current activation regs")); - - /* - * Not found in registers, proceed to the parent record. - * Here we need to determine what the parent would be, - * if 'env' was not NULL (i.e. same logic as when initializing - * the record). - * - * Note that environment initialization is only deferred when - * DUK_HOBJECT_HAS_NEWENV is set, and this only happens for: - * - Function code - * - Strict eval code - * - * We only need to check _Lexenv here; _Varenv exists only if it - * differs from _Lexenv (and thus _Lexenv will also be present). - */ - - if (!parents) { - DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal " - "(not found from register bindings when env=NULL)")); - goto fail_not_found; - } - - func = DUK_ACT_GET_FUNC(act); - DUK_ASSERT(func != NULL); - DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func)); - f = (duk_hcompfunc *) func; - - env = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f); - if (!env) { - env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - } - - DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO", - (duk_heaphdr *) env)); - } - - /* - * Prototype walking starting from 'env'. - * - * ('act' is not needed anywhere here.) - */ - - sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; - while (env != NULL) { - duk_small_uint_t cl; - duk_uint_t attrs; - - DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO", - (duk_heaphdr *) name, - (void *) env, - (duk_heaphdr *) env)); - - DUK_ASSERT(env != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_ENV(env)); - DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env)); - - cl = DUK_HOBJECT_GET_CLASS_NUMBER(env); - DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV); - if (cl == DUK_HOBJECT_CLASS_DECENV) { - /* - * Declarative environment record. - * - * Identifiers can never be stored in ancestors and are - * always plain values, so we can use an internal helper - * and access the value directly with an duk_tval ptr. - * - * A closed environment is only indicated by it missing - * the "book-keeping" properties required for accessing - * register-bound variables. - */ - - DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); - if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) { - DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " - "(declarative environment record, scope open, found in regs)", - (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (long) out->has_this, - (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); - return 1; - } - - tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs); - if (tv) { - out->value = tv; - out->attrs = attrs; - out->env = env; - out->holder = env; - out->has_this = 0; - - DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " - "(declarative environment record, found in properties)", - (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (long) out->has_this, - (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); - return 1; - } - } else { - /* - * Object environment record. - * - * Binding (target) object is an external, uncontrolled object. - * Identifier may be bound in an ancestor property, and may be - * an accessor. Target can also be a Proxy which we must support - * here. - */ - - /* XXX: we could save space by using _Target OR _This. If _Target, assume - * this binding is undefined. If _This, assumes this binding is _This, and - * target is also _This. One property would then be enough. - */ - - duk_hobject *target; - duk_bool_t found; - - DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV); - DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); - - target = ((duk_hobjenv *) env)->target; - DUK_ASSERT(target != NULL); - - /* Target may be a Proxy or property may be an accessor, so we must - * use an actual, Proxy-aware hasprop check here. - * - * out->holder is NOT set to the actual duk_hobject where the - * property is found, but rather the object binding target object. - */ - -#if defined(DUK_USE_ES6_PROXY) - if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(target))) { - duk_tval tv_name; - duk_tval tv_target_tmp; - - DUK_ASSERT(name != NULL); - DUK_TVAL_SET_STRING(&tv_name, name); - DUK_TVAL_SET_OBJECT(&tv_target_tmp, target); - - found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name); - } else -#endif /* DUK_USE_ES6_PROXY */ - { - /* XXX: duk_hobject_hasprop() would be correct for - * non-Proxy objects too, but it is about ~20-25% - * slower at present so separate code paths for - * Proxy and non-Proxy now. - */ - found = duk_hobject_hasprop_raw(thr, target, name); - } - - if (found) { - out->value = NULL; /* can't get value, may be accessor */ - out->attrs = 0; /* irrelevant when out->value == NULL */ - out->env = env; - out->holder = target; - out->has_this = ((duk_hobjenv *) env)->has_this; - - DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " - "(object environment record)", - (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (long) out->has_this, - (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); - return 1; - } - } - - if (!parents) { - DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal " - "(not found from first traversed env)")); - goto fail_not_found; - } - - if (DUK_UNLIKELY(sanity-- == 0)) { - DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); - } - env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); - } - - /* - * Not found (even in global object) - */ - - fail_not_found: - return 0; -} - -/* - * HASVAR: check identifier binding from a given environment record - * without traversing its parents. - * - * This primitive is not exposed to user code as such, but is used - * internally for e.g. declaration binding instantiation. - * - * See E5 Sections: - * 10.2.1.1.1 HasBinding(N) - * 10.2.1.2.1 HasBinding(N) - * - * Note: strictness has no bearing on this check. Hence we don't take - * a 'strict' parameter. - */ - -#if 0 /*unused*/ -DUK_INTERNAL -duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, - duk_hobject *env, - duk_hstring *name) { - duk__id_lookup_result ref; - duk_bool_t parents; - - DUK_DDD(DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O " - "(env -> %!dO)", - (void *) thr, (void *) env, (duk_heaphdr *) name, - (duk_heaphdr *) env)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(env != NULL); - DUK_ASSERT(name != NULL); - - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env); - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); - - DUK_ASSERT(DUK_HOBJECT_IS_ENV(env)); - DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env)); - - /* lookup results is ignored */ - parents = 0; - return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref); -} -#endif - -/* - * GETVAR - * - * See E5 Sections: - * 11.1.2 Identifier Reference - * 10.3.1 Identifier Resolution - * 11.13.1 Simple Assignment [example of where the Reference is GetValue'd] - * 8.7.1 GetValue (V) - * 8.12.1 [[GetOwnProperty]] (P) - * 8.12.2 [[GetProperty]] (P) - * 8.12.3 [[Get]] (P) - * - * If 'throw' is true, always leaves two values on top of stack: [val this]. - * - * If 'throw' is false, returns 0 if identifier cannot be resolved, and the - * stack will be unaffected in this case. If identifier is resolved, returns - * 1 and leaves [val this] on top of stack. - * - * Note: the 'strict' flag of a reference returned by GetIdentifierReference - * is ignored by GetValue. Hence we don't take a 'strict' parameter. - * - * The 'throw' flag is needed for implementing 'typeof' for an unreferenced - * identifier. An unreference identifier in other contexts generates a - * ReferenceError. - */ - -DUK_LOCAL -duk_bool_t duk__getvar_helper(duk_hthread *thr, - duk_hobject *env, - duk_activation *act, - duk_hstring *name, - duk_bool_t throw_flag) { - duk__id_lookup_result ref; - duk_tval tv_tmp_obj; - duk_tval tv_tmp_key; - duk_bool_t parents; - - DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O " - "(env -> %!dO)", - (void *) thr, (void *) env, (void *) act, - (duk_heaphdr *) name, (duk_heaphdr *) env)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(name != NULL); - /* env and act may be NULL */ - - DUK_STATS_INC(thr->heap, stats_getvar_all); - - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env); - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); - - parents = 1; /* follow parent chain */ - if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { - if (ref.value) { - duk_push_tval(thr, ref.value); - duk_push_undefined(thr); - } else { - DUK_ASSERT(ref.holder != NULL); - - /* ref.holder is safe across the getprop call (even - * with side effects) because 'env' is reachable and - * ref.holder is a direct heap pointer. - */ - - DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); - DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */ - - if (ref.has_this) { - duk_push_hobject(thr, ref.holder); - } else { - duk_push_undefined(thr); - } - - /* [value this] */ - } - - return 1; - } else { - if (throw_flag) { - DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR, - "identifier '%s' undefined", - (const char *) DUK_HSTRING_GET_DATA(name)); - } - - return 0; - } -} - -DUK_INTERNAL -duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, - duk_hobject *env, - duk_hstring *name, - duk_bool_t throw_flag) { - return duk__getvar_helper(thr, env, NULL, name, throw_flag); -} - -DUK_INTERNAL -duk_bool_t duk_js_getvar_activation(duk_hthread *thr, - duk_activation *act, - duk_hstring *name, - duk_bool_t throw_flag) { - DUK_ASSERT(act != NULL); - return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag); -} - -/* - * PUTVAR - * - * See E5 Sections: - * 11.1.2 Identifier Reference - * 10.3.1 Identifier Resolution - * 11.13.1 Simple Assignment [example of where the Reference is PutValue'd] - * 8.7.2 PutValue (V,W) [see especially step 3.b, undefined -> automatic global in non-strict mode] - * 8.12.4 [[CanPut]] (P) - * 8.12.5 [[Put]] (P) - * - * Note: may invalidate any valstack (or object) duk_tval pointers because - * putting a value may reallocate any object or any valstack. Caller beware. - */ - -DUK_LOCAL -void duk__putvar_helper(duk_hthread *thr, - duk_hobject *env, - duk_activation *act, - duk_hstring *name, - duk_tval *val, - duk_bool_t strict) { - duk__id_lookup_result ref; - duk_tval tv_tmp_obj; - duk_tval tv_tmp_key; - duk_bool_t parents; - - DUK_STATS_INC(thr->heap, stats_putvar_all); - - DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld " - "(env -> %!dO, val -> %!T)", - (void *) thr, (void *) env, (void *) act, - (duk_heaphdr *) name, (void *) val, (long) strict, - (duk_heaphdr *) env, (duk_tval *) val)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(name != NULL); - DUK_ASSERT(val != NULL); - /* env and act may be NULL */ - - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env); - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); - DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val); - - /* - * In strict mode E5 protects 'eval' and 'arguments' from being - * assigned to (or even declared anywhere). Attempt to do so - * should result in a compile time SyntaxError. See the internal - * design documentation for details. - * - * Thus, we should never come here, run-time, for strict code, - * and name 'eval' or 'arguments'. - */ - - DUK_ASSERT(!strict || - (name != DUK_HTHREAD_STRING_EVAL(thr) && - name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr))); - - /* - * Lookup variable and update in-place if found. - */ - - parents = 1; /* follow parent chain */ - - if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { - if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) { - /* Update duk_tval in-place if pointer provided and the - * property is writable. If the property is not writable - * (immutable binding), use duk_hobject_putprop() which - * will respect mutability. - */ - duk_tval *tv_val; - - tv_val = ref.value; - DUK_ASSERT(tv_val != NULL); - DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */ - - /* ref.value invalidated here */ - } else { - DUK_ASSERT(ref.holder != NULL); - - DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); - DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict); - - /* ref.value invalidated here */ - } - - return; - } - - /* - * Not found: write to global object (non-strict) or ReferenceError - * (strict); see E5 Section 8.7.2, step 3. - */ - - if (strict) { - DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error")); - DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR, - "identifier '%s' undefined", - (const char *) DUK_HSTRING_GET_DATA(name)); - } - - DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global")); - - DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]); - DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0); /* 0 = no throw */ - - /* NB: 'val' may be invalidated here because put_value may realloc valstack, - * caller beware. - */ -} - -DUK_INTERNAL -void duk_js_putvar_envrec(duk_hthread *thr, - duk_hobject *env, - duk_hstring *name, - duk_tval *val, - duk_bool_t strict) { - duk__putvar_helper(thr, env, NULL, name, val, strict); -} - -DUK_INTERNAL -void duk_js_putvar_activation(duk_hthread *thr, - duk_activation *act, - duk_hstring *name, - duk_tval *val, - duk_bool_t strict) { - DUK_ASSERT(act != NULL); - duk__putvar_helper(thr, act->lex_env, act, name, val, strict); -} - -/* - * DELVAR - * - * See E5 Sections: - * 11.4.1 The delete operator - * 10.2.1.1.5 DeleteBinding (N) [declarative environment record] - * 10.2.1.2.5 DeleteBinding (N) [object environment record] - * - * Variable bindings established inside eval() are deletable (configurable), - * other bindings are not, including variables declared in global level. - * Registers are always non-deletable, and the deletion of other bindings - * is controlled by the configurable flag. - * - * For strict mode code, the 'delete' operator should fail with a compile - * time SyntaxError if applied to identifiers. Hence, no strict mode - * run-time deletion of identifiers should ever happen. This function - * should never be called from strict mode code! - */ - -DUK_LOCAL -duk_bool_t duk__delvar_helper(duk_hthread *thr, - duk_hobject *env, - duk_activation *act, - duk_hstring *name) { - duk__id_lookup_result ref; - duk_bool_t parents; - - DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O " - "(env -> %!dO)", - (void *) thr, (void *) env, (void *) act, - (duk_heaphdr *) name, (duk_heaphdr *) env)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(name != NULL); - /* env and act may be NULL */ - - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); - - parents = 1; /* follow parent chain */ - - if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { - if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) { - /* Identifier found in registers (always non-deletable) - * or declarative environment record and non-configurable. - */ - return 0; - } - DUK_ASSERT(ref.holder != NULL); - - return duk_hobject_delprop_raw(thr, ref.holder, name, 0); - } - - /* - * Not found (even in global object). - * - * In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1, - * step 3.b. In strict mode this case is a compile time SyntaxError so - * we should not come here. - */ - - DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O " - "(treated as silent success)", - (duk_heaphdr *) name)); - return 1; -} - -#if 0 /*unused*/ -DUK_INTERNAL -duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, - duk_hobject *env, - duk_hstring *name) { - return duk__delvar_helper(thr, env, NULL, name); -} -#endif - -DUK_INTERNAL -duk_bool_t duk_js_delvar_activation(duk_hthread *thr, - duk_activation *act, - duk_hstring *name) { - DUK_ASSERT(act != NULL); - return duk__delvar_helper(thr, act->lex_env, act, name); -} - -/* - * DECLVAR - * - * See E5 Sections: - * 10.4.3 Entering Function Code - * 10.5 Declaration Binding Instantion - * 12.2 Variable Statement - * 11.1.2 Identifier Reference - * 10.3.1 Identifier Resolution - * - * Variable declaration behavior is mainly discussed in Section 10.5, - * and is not discussed in the execution semantics (Sections 11-13). - * - * Conceptually declarations happen when code (global, eval, function) - * is entered, before any user code is executed. In practice, register- - * bound identifiers are 'declared' automatically (by virtue of being - * allocated to registers with the initial value 'undefined'). Other - * identifiers are declared in the function prologue with this primitive. - * - * Since non-register bindings eventually back to an internal object's - * properties, the 'prop_flags' argument is used to specify binding - * type: - * - * - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false - * - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false - * - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it - * doesn't really matter for internal objects - * - * All bindings are non-deletable mutable bindings except: - * - * - Declarations in eval code (mutable, deletable) - * - 'arguments' binding in strict function code (immutable) - * - Function name binding of a function expression (immutable) - * - * Declarations may go to declarative environment records (always - * so for functions), but may also go to object environment records - * (e.g. global code). The global object environment has special - * behavior when re-declaring a function (but not a variable); see - * E5.1 specification, Section 10.5, step 5.e. - * - * Declarations always go to the 'top-most' environment record, i.e. - * we never check the record chain. It's not an error even if a - * property (even an immutable or non-deletable one) of the same name - * already exists. - * - * If a declared variable already exists, its value needs to be updated - * (if possible). Returns 1 if a PUTVAR needs to be done by the caller; - * otherwise returns 0. - */ - -DUK_LOCAL -duk_bool_t duk__declvar_helper(duk_hthread *thr, - duk_hobject *env, - duk_hstring *name, - duk_tval *val, - duk_small_uint_t prop_flags, - duk_bool_t is_func_decl) { - duk_hobject *holder; - duk_bool_t parents; - duk__id_lookup_result ref; - duk_tval *tv; - - DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld " - "(env -> %!iO)", - (void *) thr, (void *) env, (duk_heaphdr *) name, - (duk_tval *) val, (unsigned long) prop_flags, - (unsigned int) is_func_decl, (duk_heaphdr *) env)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(env != NULL); - DUK_ASSERT(name != NULL); - DUK_ASSERT(val != NULL); - - /* Note: in strict mode the compiler should reject explicit - * declaration of 'eval' or 'arguments'. However, internal - * bytecode may declare 'arguments' in the function prologue. - * We don't bother checking (or asserting) for these now. - */ - - /* Note: val is a stable duk_tval pointer. The caller makes - * a value copy into its stack frame, so 'tv_val' is not subject - * to side effects here. - */ - - /* - * Check whether already declared. - * - * We need to check whether the binding exists in the environment - * without walking its parents. However, we still need to check - * register-bound identifiers and the prototype chain of an object - * environment target object. - */ - - parents = 0; /* just check 'env' */ - if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) { - duk_int_t e_idx; - duk_int_t h_idx; - duk_small_uint_t flags; - - /* - * Variable already declared, ignore re-declaration. - * The only exception is the updated behavior of E5.1 for - * global function declarations, E5.1 Section 10.5, step 5.e. - * This behavior does not apply to global variable declarations. - */ - - if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) { - DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring")); - return 1; /* 1 -> needs a PUTVAR */ - } - - /* - * Special behavior in E5.1. - * - * Note that even though parents == 0, the conflicting property - * may be an inherited property (currently our global object's - * prototype is Object.prototype). Step 5.e first operates on - * the existing property (which is potentially in an ancestor) - * and then defines a new property in the global object (and - * never modifies the ancestor). - * - * Also note that this logic would become even more complicated - * if the conflicting property might be a virtual one. Object - * prototype has no virtual properties, though. - * - * XXX: this is now very awkward, rework. - */ - - DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, " - "updated E5.1 processing")); - - DUK_ASSERT(ref.holder != NULL); - holder = ref.holder; - - /* holder will be set to the target object, not the actual object - * where the property was found (see duk__get_identifier_reference()). - */ - DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL); - DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder)); /* global object doesn't have array part */ - - /* XXX: use a helper for prototype traversal; no loop check here */ - /* must be found: was found earlier, and cannot be inherited */ - for (;;) { - DUK_ASSERT(holder != NULL); - if (duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx)) { - DUK_ASSERT(e_idx >= 0); - break; - } - /* SCANBUILD: NULL pointer dereference, doesn't actually trigger, - * asserted above. - */ - holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder); - } - DUK_ASSERT(holder != NULL); - DUK_ASSERT(e_idx >= 0); - /* SCANBUILD: scan-build produces a NULL pointer dereference warning - * below; it never actually triggers because holder is actually never - * NULL. - */ - - /* ref.holder is global object, holder is the object with the - * conflicting property. - */ - - flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx); - if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) { - if (flags & DUK_PROPDESC_FLAG_ACCESSOR) { - DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable " - "accessor -> reject")); - goto fail_existing_attributes; - } - if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) && - (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) { - DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable " - "plain property which is not writable and " - "enumerable -> reject")); - goto fail_existing_attributes; - } - - DUK_DDD(DUK_DDDPRINT("existing property is not configurable but " - "is plain, enumerable, and writable -> " - "allow redeclaration")); - } - - if (holder == ref.holder) { - /* XXX: if duk_hobject_define_property_internal() was updated - * to handle a pre-existing accessor property, this would be - * a simple call (like for the ancestor case). - */ - DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself")); - - if (flags & DUK_PROPDESC_FLAG_ACCESSOR) { - duk_hobject *tmp; - - tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx); - DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL); - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - DUK_UNREF(tmp); - tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx); - DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL); - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - DUK_UNREF(tmp); - } else { - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx); - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); - } - - /* Here val would be potentially invalid if we didn't make - * a value copy at the caller. - */ - - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx); - DUK_TVAL_SET_TVAL(tv, val); - DUK_TVAL_INCREF(thr, tv); - DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags); - - DUK_DDD(DUK_DDDPRINT("updated global binding, final result: " - "value -> %!T, prop_flags=0x%08lx", - (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx), - (unsigned long) prop_flags)); - } else { - DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor")); - - DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]); - duk_push_tval(thr, val); - duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags); - } - - return 0; - } - - /* - * Not found (in registers or record objects). Declare - * to current variable environment. - */ - - /* - * Get holder object - */ - - if (DUK_HOBJECT_IS_DECENV(env)) { - DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); - holder = env; - } else { - DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); - holder = ((duk_hobjenv *) env)->target; - DUK_ASSERT(holder != NULL); - } - - /* - * Define new property - * - * Note: this may fail if the holder is not extensible. - */ - - /* XXX: this is awkward as we use an internal method which doesn't handle - * extensibility etc correctly. Basically we'd want to do a [[DefineOwnProperty]] - * or Object.defineProperty() here. - */ - - if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) { - goto fail_not_extensible; - } - - duk_push_hobject(thr, holder); - duk_push_hstring(thr, name); - duk_push_tval(thr, val); - duk_xdef_prop(thr, -3, prop_flags); /* [holder name val] -> [holder] */ - duk_pop_unsafe(thr); - - return 0; - - fail_existing_attributes: - fail_not_extensible: - DUK_ERROR_TYPE(thr, "declaration failed"); - return 0; -} - -DUK_INTERNAL -duk_bool_t duk_js_declvar_activation(duk_hthread *thr, - duk_activation *act, - duk_hstring *name, - duk_tval *val, - duk_small_uint_t prop_flags, - duk_bool_t is_func_decl) { - duk_hobject *env; - duk_tval tv_val_copy; - - DUK_ASSERT(act != NULL); - - /* - * Make a value copy of the input val. This ensures that - * side effects cannot invalidate the pointer. - */ - - DUK_TVAL_SET_TVAL(&tv_val_copy, val); - val = &tv_val_copy; - - /* - * Delayed env creation check - */ - - if (!act->var_env) { - DUK_ASSERT(act->lex_env == NULL); - duk_js_init_activation_environment_records_delayed(thr, act); - /* 'act' is a stable pointer, so still OK. */ - } - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - - env = act->var_env; - DUK_ASSERT(env != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_ENV(env)); - - return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl); -} -#line 1 "duk_lexer.c" -/* - * Lexer for source files, ToNumber() string conversions, RegExp expressions, - * and JSON. - * - * Provides a stream of Ecmascript tokens from an UTF-8/CESU-8 buffer. The - * caller can also rewind the token stream into a certain position which is - * needed by the compiler part for multi-pass scanning. Tokens are - * represented as duk_token structures, and contain line number information. - * Token types are identified with DUK_TOK_* defines. - * - * Characters are decoded into a fixed size lookup window consisting of - * decoded Unicode code points, with window positions past the end of the - * input filled with an invalid codepoint (-1). The tokenizer can thus - * perform multiple character lookups efficiently and with few sanity - * checks (such as access outside the end of the input), which keeps the - * tokenization code small at the cost of performance. - * - * Character data in tokens, such as identifier names and string literals, - * is encoded into CESU-8 format on-the-fly while parsing the token in - * question. The string data is made reachable to garbage collection by - * placing the token-related values in value stack entries allocated for - * this purpose by the caller. The characters exist in Unicode code point - * form only in the fixed size lookup window, which keeps character data - * expansion (of especially ASCII data) low. - * - * Token parsing supports the full range of Unicode characters as described - * in the E5 specification. Parsing has been optimized for ASCII characters - * because ordinary Ecmascript code consists almost entirely of ASCII - * characters. Matching of complex Unicode codepoint sets (such as in the - * IdentifierStart and IdentifierPart productions) is optimized for size, - * and is done using a linear scan of a bit-packed list of ranges. This is - * very slow, but should never be entered unless the source code actually - * contains Unicode characters. - * - * Ecmascript tokenization is partially context sensitive. First, - * additional future reserved words are recognized in strict mode (see E5 - * Section 7.6.1.2). Second, a forward slash character ('/') can be - * recognized either as starting a RegExp literal or as a division operator, - * depending on context. The caller must provide necessary context flags - * when requesting a new token. - * - * Future work: - * - * * Make line number tracking optional, as it consumes space. - * - * * Add a feature flag for disabling UTF-8 decoding of input, as most - * source code is ASCII. Because of Unicode escapes written in ASCII, - * this does not allow Unicode support to be removed from e.g. - * duk_unicode_is_identifier_start() nor does it allow removal of CESU-8 - * encoding of e.g. string literals. - * - * * Add a feature flag for disabling Unicode compliance of e.g. identifier - * names. This allows for a build more than a kilobyte smaller, because - * Unicode ranges needed by duk_unicode_is_identifier_start() and - * duk_unicode_is_identifier_part() can be dropped. String literals - * should still be allowed to contain escaped Unicode, so this still does - * not allow removal of CESU-8 encoding of e.g. string literals. - * - * * Character lookup tables for codepoints above BMP could be stripped. - * - * * Strictly speaking, E5 specification requires that source code consists - * of 16-bit code units, and if not, must be conceptually converted to - * that format first. The current lexer processes Unicode code points - * and allows characters outside the BMP. These should be converted to - * surrogate pairs while reading the source characters into the window, - * not after tokens have been formed (as is done now). However, the fix - * is not trivial because two characters are decoded from one codepoint. - * - * * Optimize for speed as well as size. Large if-else ladders are (at - * least potentially) slow. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Various defines and file specific helper macros - */ - -#define DUK__MAX_RE_DECESC_DIGITS 9 -#define DUK__MAX_RE_QUANT_DIGITS 9 /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */ - -/* whether to use macros or helper function depends on call count */ -#define DUK__ISDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_9) -#define DUK__ISHEXDIGIT(x) duk__is_hex_digit((x)) -#define DUK__ISOCTDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_7) -#define DUK__ISDIGIT03(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_3) -#define DUK__ISDIGIT47(x) ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7) - -/* lexer character window helpers */ -#define DUK__LOOKUP(lex_ctx,idx) ((lex_ctx)->window[(idx)].codepoint) -#define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_chars((lex_ctx), (count)) -#define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count)) -#define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx)) -#define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x)) -#define DUK__APPENDBUFFER_ASCII(lex_ctx,x) duk__appendbuffer_ascii((lex_ctx), (duk_codepoint_t) (x)) - -/* lookup shorthands (note: assume context variable is named 'lex_ctx') */ -#define DUK__L0() DUK__LOOKUP(lex_ctx, 0) -#define DUK__L1() DUK__LOOKUP(lex_ctx, 1) -#define DUK__L2() DUK__LOOKUP(lex_ctx, 2) -#define DUK__L3() DUK__LOOKUP(lex_ctx, 3) -#define DUK__L4() DUK__LOOKUP(lex_ctx, 4) -#define DUK__L5() DUK__LOOKUP(lex_ctx, 5) - -/* packed advance/token number macro used by multiple functions */ -#define DUK__ADVTOK(advbytes,tok) ((((advbytes) * sizeof(duk_lexer_codepoint)) << 8) + (tok)) - -/* - * Advance lookup window by N characters, filling in new characters as - * necessary. After returning caller is guaranteed a character window of - * at least DUK_LEXER_WINDOW_SIZE characters. - * - * The main function duk__advance_bytes() is called at least once per every - * token so it has a major lexer/compiler performance impact. There are two - * variants for the main duk__advance_bytes() algorithm: a sliding window - * approach which is slightly faster at the cost of larger code footprint, - * and a simple copying one. - * - * Decoding directly from the source string would be another lexing option. - * But the lookup window based approach has the advantage of hiding the - * source string and its encoding effectively which gives more flexibility - * going forward to e.g. support chunked streaming of source from flash. - * - * Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to - * U+10FFFF, causing an error if the input is unparseable. Leniency means: - * - * * Unicode code point validation is intentionally not performed, - * except to check that the codepoint does not exceed 0x10ffff. - * - * * In particular, surrogate pairs are allowed and not combined, which - * allows source files to represent all SourceCharacters with CESU-8. - * Broken surrogate pairs are allowed, as Ecmascript does not mandate - * their validation. - * - * * Allow non-shortest UTF-8 encodings. - * - * Leniency here causes few security concerns because all character data is - * decoded into Unicode codepoints before lexer processing, and is then - * re-encoded into CESU-8. The source can be parsed as strict UTF-8 with - * a compiler option. However, Ecmascript source characters include -all- - * 16-bit unsigned integer codepoints, so leniency seems to be appropriate. - * - * Note that codepoints above the BMP are not strictly SourceCharacters, - * but the lexer still accepts them as such. Before ending up in a string - * or an identifier name, codepoints above BMP are converted into surrogate - * pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as - * expected by Ecmascript. - * - * An alternative approach to dealing with invalid or partial sequences - * would be to skip them and replace them with e.g. the Unicode replacement - * character U+FFFD. This has limited utility because a replacement character - * will most likely cause a parse error, unless it occurs inside a string. - * Further, Ecmascript source is typically pure ASCII. - * - * See: - * - * http://en.wikipedia.org/wiki/UTF-8 - * http://en.wikipedia.org/wiki/CESU-8 - * http://tools.ietf.org/html/rfc3629 - * http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences - * - * Future work: - * - * * Reject other invalid Unicode sequences (see Wikipedia entry for examples) - * in strict UTF-8 mode. - * - * * Size optimize. An attempt to use a 16-byte lookup table for the first - * byte resulted in a code increase though. - * - * * Is checking against maximum 0x10ffff really useful? 4-byte encoding - * imposes a certain limit anyway. - * - * * Support chunked streaming of source code. Can be implemented either - * by streaming chunks of bytes or chunks of codepoints. - */ - -#if defined(DUK_USE_LEXER_SLIDING_WINDOW) -DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t start_offset_bytes) { - duk_lexer_codepoint *cp, *cp_end; - duk_ucodepoint_t x; - duk_small_uint_t contlen; - const duk_uint8_t *p, *p_end; -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - duk_ucodepoint_t mincp; -#endif - duk_int_t input_line; - - /* Use temporaries and update lex_ctx only when finished. */ - input_line = lex_ctx->input_line; - p = lex_ctx->input + lex_ctx->input_offset; - p_end = lex_ctx->input + lex_ctx->input_length; - - cp = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->buffer + start_offset_bytes); - cp_end = lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE; - - for (; cp != cp_end; cp++) { - cp->offset = (duk_size_t) (p - lex_ctx->input); - cp->line = input_line; - - /* XXX: potential issue with signed pointers, p_end < p. */ - if (DUK_UNLIKELY(p >= p_end)) { - /* If input_offset were assigned a negative value, it would - * result in a large positive value. Most likely it would be - * larger than input_length and be caught here. In any case - * no memory unsafe behavior would happen. - */ - cp->codepoint = -1; - continue; - } - - x = (duk_ucodepoint_t) (*p++); - - /* Fast path. */ - - if (DUK_LIKELY(x < 0x80UL)) { - DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */ - if (DUK_UNLIKELY(x <= 0x000dUL)) { - if ((x == 0x000aUL) || - ((x == 0x000dUL) && (p >= p_end || *p != 0x000aUL))) { - /* lookup for 0x000a above assumes shortest encoding now */ - - /* E5 Section 7.3, treat the following as newlines: - * LF - * CR [not followed by LF] - * LS - * PS - * - * For CR LF, CR is ignored if it is followed by LF, and the LF will bump - * the line number. - */ - input_line++; - } - } - - cp->codepoint = (duk_codepoint_t) x; - continue; - } - - /* Slow path. */ - - if (x < 0xc0UL) { - /* 10xx xxxx -> invalid */ - goto error_encoding; - } else if (x < 0xe0UL) { - /* 110x xxxx 10xx xxxx */ - contlen = 1; -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - mincp = 0x80UL; -#endif - x = x & 0x1fUL; - } else if (x < 0xf0UL) { - /* 1110 xxxx 10xx xxxx 10xx xxxx */ - contlen = 2; -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - mincp = 0x800UL; -#endif - x = x & 0x0fUL; - } else if (x < 0xf8UL) { - /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */ - contlen = 3; -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - mincp = 0x10000UL; -#endif - x = x & 0x07UL; - } else { - /* no point in supporting encodings of 5 or more bytes */ - goto error_encoding; - } - - DUK_ASSERT(p_end >= p); - if ((duk_size_t) contlen > (duk_size_t) (p_end - p)) { - goto error_clipped; - } - - while (contlen > 0) { - duk_small_uint_t y; - y = *p++; - if ((y & 0xc0U) != 0x80U) { - /* check that byte has the form 10xx xxxx */ - goto error_encoding; - } - x = x << 6; - x += y & 0x3fUL; - contlen--; - } - - /* check final character validity */ - - if (x > 0x10ffffUL) { - goto error_encoding; - } -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) { - goto error_encoding; - } -#endif - - DUK_ASSERT(x != 0x000aUL && x != 0x000dUL); - if ((x == 0x2028UL) || (x == 0x2029UL)) { - input_line++; - } - - cp->codepoint = (duk_codepoint_t) x; - } - - lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input); - lex_ctx->input_line = input_line; - return; - - error_clipped: /* clipped codepoint */ - error_encoding: /* invalid codepoint encoding or codepoint */ - lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input); - lex_ctx->input_line = input_line; - - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED); -} - -DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) { - duk_small_uint_t used_bytes, avail_bytes; - - DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */ - DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))); - DUK_ASSERT(lex_ctx->window >= lex_ctx->buffer); - DUK_ASSERT(lex_ctx->window < lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE); - DUK_ASSERT((duk_uint8_t *) lex_ctx->window + count_bytes <= (duk_uint8_t *) lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint)); - - /* Zero 'count' is also allowed to make call sites easier. - * Arithmetic in bytes generates better code in GCC. - */ - - lex_ctx->window = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->window + count_bytes); /* avoid multiply */ - used_bytes = (duk_small_uint_t) ((duk_uint8_t *) lex_ctx->window - (duk_uint8_t *) lex_ctx->buffer); - avail_bytes = DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint) - used_bytes; - if (avail_bytes < (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))) { - /* Not enough data to provide a full window, so "scroll" window to - * start of buffer and fill up the rest. - */ - DUK_MEMMOVE((void *) lex_ctx->buffer, - (const void *) lex_ctx->window, - (size_t) avail_bytes); - lex_ctx->window = lex_ctx->buffer; - duk__fill_lexer_buffer(lex_ctx, avail_bytes); - } -} - -DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) { - lex_ctx->window = lex_ctx->buffer; - duk__fill_lexer_buffer(lex_ctx, 0); -} -#else /* DUK_USE_LEXER_SLIDING_WINDOW */ -DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) { - duk_ucodepoint_t x; - duk_small_uint_t len; - duk_small_uint_t i; - const duk_uint8_t *p; -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - duk_ucodepoint_t mincp; -#endif - duk_size_t input_offset; - - input_offset = lex_ctx->input_offset; - if (DUK_UNLIKELY(input_offset >= lex_ctx->input_length)) { - /* If input_offset were assigned a negative value, it would - * result in a large positive value. Most likely it would be - * larger than input_length and be caught here. In any case - * no memory unsafe behavior would happen. - */ - return -1; - } - - p = lex_ctx->input + input_offset; - x = (duk_ucodepoint_t) (*p); - - if (DUK_LIKELY(x < 0x80UL)) { - /* 0xxx xxxx -> fast path */ - - /* input offset tracking */ - lex_ctx->input_offset++; - - DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */ - if (DUK_UNLIKELY(x <= 0x000dUL)) { - if ((x == 0x000aUL) || - ((x == 0x000dUL) && (lex_ctx->input_offset >= lex_ctx->input_length || - lex_ctx->input[lex_ctx->input_offset] != 0x000aUL))) { - /* lookup for 0x000a above assumes shortest encoding now */ - - /* E5 Section 7.3, treat the following as newlines: - * LF - * CR [not followed by LF] - * LS - * PS - * - * For CR LF, CR is ignored if it is followed by LF, and the LF will bump - * the line number. - */ - lex_ctx->input_line++; - } - } - - return (duk_codepoint_t) x; - } - - /* Slow path. */ - - if (x < 0xc0UL) { - /* 10xx xxxx -> invalid */ - goto error_encoding; - } else if (x < 0xe0UL) { - /* 110x xxxx 10xx xxxx */ - len = 2; -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - mincp = 0x80UL; -#endif - x = x & 0x1fUL; - } else if (x < 0xf0UL) { - /* 1110 xxxx 10xx xxxx 10xx xxxx */ - len = 3; -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - mincp = 0x800UL; -#endif - x = x & 0x0fUL; - } else if (x < 0xf8UL) { - /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */ - len = 4; -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - mincp = 0x10000UL; -#endif - x = x & 0x07UL; - } else { - /* no point in supporting encodings of 5 or more bytes */ - goto error_encoding; - } - - DUK_ASSERT(lex_ctx->input_length >= lex_ctx->input_offset); - if ((duk_size_t) len > (duk_size_t) (lex_ctx->input_length - lex_ctx->input_offset)) { - goto error_clipped; - } - - p++; - for (i = 1; i < len; i++) { - duk_small_uint_t y; - y = *p++; - if ((y & 0xc0U) != 0x80U) { - /* check that byte has the form 10xx xxxx */ - goto error_encoding; - } - x = x << 6; - x += y & 0x3fUL; - } - - /* check final character validity */ - - if (x > 0x10ffffUL) { - goto error_encoding; - } -#if defined(DUK_USE_STRICT_UTF8_SOURCE) - if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) { - goto error_encoding; - } -#endif - - /* input offset tracking */ - lex_ctx->input_offset += len; - - /* line tracking */ - DUK_ASSERT(x != 0x000aUL && x != 0x000dUL); - if ((x == 0x2028UL) || (x == 0x2029UL)) { - lex_ctx->input_line++; - } - - return (duk_codepoint_t) x; - - error_clipped: /* clipped codepoint */ - error_encoding: /* invalid codepoint encoding or codepoint */ - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED); - return 0; -} - -DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) { - duk_small_uint_t keep_bytes; - duk_lexer_codepoint *cp, *cp_end; - - DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */ - DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))); - - /* Zero 'count' is also allowed to make call sites easier. */ - - keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes; - DUK_MEMMOVE((void *) lex_ctx->window, - (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes), - (size_t) keep_bytes); - - cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes); - cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE; - for (; cp != cp_end; cp++) { - cp->offset = lex_ctx->input_offset; - cp->line = lex_ctx->input_line; - cp->codepoint = duk__read_char(lex_ctx); - } -} - -DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) { - /* Call with count == DUK_LEXER_WINDOW_SIZE to fill buffer initially. */ - duk__advance_bytes(lex_ctx, DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)); /* fill window */ -} -#endif /* DUK_USE_LEXER_SLIDING_WINDOW */ - -DUK_LOCAL void duk__advance_chars(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_chars) { - duk__advance_bytes(lex_ctx, count_chars * sizeof(duk_lexer_codepoint)); -} - -/* - * (Re)initialize the temporary byte buffer. May be called extra times - * with little impact. - */ - -DUK_LOCAL void duk__initbuffer(duk_lexer_ctx *lex_ctx) { - /* Reuse buffer as is unless buffer has grown large. */ - if (DUK_HBUFFER_DYNAMIC_GET_SIZE(lex_ctx->buf) < DUK_LEXER_TEMP_BUF_LIMIT) { - /* Keep current size */ - } else { - duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, DUK_LEXER_TEMP_BUF_LIMIT); - } - - DUK_BW_INIT_WITHBUF(lex_ctx->thr, &lex_ctx->bw, lex_ctx->buf); -} - -/* - * Append a Unicode codepoint to the temporary byte buffer. Performs - * CESU-8 surrogate pair encoding for codepoints above the BMP. - * Existing surrogate pairs are allowed and also encoded into CESU-8. - */ - -DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) { - /* - * Since character data is only generated by decoding the source or by - * the compiler itself, we rely on the input codepoints being correct - * and avoid a check here. - * - * Character data can also come here through decoding of Unicode - * escapes ("\udead\ubeef") so all 16-but unsigned values can be - * present, even when the source file itself is strict UTF-8. - */ - DUK_ASSERT(x >= 0 && x <= 0x10ffffL); - - DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x); -} - -DUK_LOCAL void duk__appendbuffer_ascii(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) { - /* ASCII characters can be emitted as a single byte without encoding - * which matters for some fast paths. - */ - DUK_ASSERT(x >= 0 && x <= 0x7f); - - DUK_BW_WRITE_ENSURE_U8(lex_ctx->thr, &lex_ctx->bw, (duk_uint8_t) x); -} - -/* - * Intern the temporary byte buffer into a valstack slot - * (in practice, slot1 or slot2). - */ - -DUK_LOCAL duk_hstring *duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) { - DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx); - - DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw); - duk_replace(lex_ctx->thr, valstack_idx); - return duk_known_hstring(lex_ctx->thr, valstack_idx); -} - -/* - * Init lexer context - */ - -DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) { - DUK_ASSERT(lex_ctx != NULL); - - DUK_MEMZERO(lex_ctx, sizeof(*lex_ctx)); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) -#if defined(DUK_USE_LEXER_SLIDING_WINDOW) - lex_ctx->window = NULL; -#endif - lex_ctx->thr = NULL; - lex_ctx->input = NULL; - lex_ctx->buf = NULL; -#endif -} - -/* - * Set lexer input position and reinitialize lookup window. - */ - -DUK_INTERNAL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) { - pt->offset = lex_ctx->window[0].offset; - pt->line = lex_ctx->window[0].line; -} - -DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) { - DUK_ASSERT_DISABLE(pt->offset >= 0); /* unsigned */ - DUK_ASSERT(pt->line >= 1); - lex_ctx->input_offset = pt->offset; - lex_ctx->input_line = pt->line; - duk__init_lexer_window(lex_ctx); -} - -/* - * Lexing helpers - */ - -/* Numeric value of a hex digit (also covers octal and decimal digits) or - * -1 if not a valid hex digit. - */ -DUK_LOCAL duk_codepoint_t duk__hexval_validate(duk_codepoint_t x) { - duk_small_int_t t; - - /* Here 'x' is a Unicode codepoint */ - if (DUK_LIKELY(x >= 0 && x <= 0xff)) { - t = duk_hex_dectab[x]; - if (DUK_LIKELY(t >= 0)) { - return t; - } - } - - return -1; -} - -/* Just a wrapper for call sites where 'x' is known to be valid so - * we assert for it before decoding. - */ -DUK_LOCAL duk_codepoint_t duk__hexval(duk_codepoint_t x) { - duk_codepoint_t ret; - - DUK_ASSERT((x >= DUK_ASC_0 && x <= DUK_ASC_9) || - (x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_F) || - (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_F)); - ret = duk__hexval_validate(x); - DUK_ASSERT(ret >= 0 && ret <= 15); - return ret; -} - -/* having this as a separate function provided a size benefit */ -DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) { - if (DUK_LIKELY(x >= 0 && x <= 0xff)) { - return (duk_hex_dectab[x] >= 0); - } - return 0; -} - -/* Parse a Unicode escape of the form \xHH, \uHHHH, or \u{H+}. Shared by - * source and RegExp parsing. - */ -DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bool_t allow_es6) { - duk_small_int_t digits; /* Initial value 2 or 4 for fixed length escapes, 0 for ES2015 \u{H+}. */ - duk_codepoint_t escval; - duk_codepoint_t x; - duk_small_uint_t adv; - - DUK_ASSERT(DUK__L0() == DUK_ASC_BACKSLASH); /* caller responsibilities */ - DUK_ASSERT(DUK__L1() == DUK_ASC_LC_X || DUK__L1() == DUK_ASC_LC_U); - DUK_UNREF(allow_es6); - - adv = 2; - digits = 2; - if (DUK__L1() == DUK_ASC_LC_U) { - digits = 4; -#if defined(DUK_USE_ES6_UNICODE_ESCAPE) - if (DUK__L2() == DUK_ASC_LCURLY && allow_es6) { - digits = 0; - adv = 3; - } -#endif - } - DUK__ADVANCECHARS(lex_ctx, adv); - - escval = 0; - for (;;) { - /* One of the escape forms: \xHH, \uHHHH, \u{H+}. - * The 'digits' variable tracks parsing state and is - * initialized to: - * - * \xHH 2 - * \uHH 4 - * \u{H+} 0 first time, updated to -1 to indicate - * at least one digit has been parsed - * - * Octal parsing is handled separately because it can be - * done with fixed lookahead and also has validation - * rules which depend on the escape length (which is - * variable). - * - * We don't need a specific check for x < 0 (end of - * input) or duk_unicode_is_line_terminator(x) - * because the 'dig' decode will fail and lead to a - * SyntaxError. - */ - duk_codepoint_t dig; - - x = DUK__L0(); - DUK__ADVANCECHARS(lex_ctx, 1); - - dig = duk__hexval_validate(x); - if (digits > 0) { - digits--; - if (dig < 0) { - goto fail_escape; - } - DUK_ASSERT(dig >= 0x00 && dig <= 0x0f); - escval = (escval << 4) + dig; - if (digits == 0) { - DUK_ASSERT(escval >= 0 && escval <= 0xffffL); - break; - } - } else { -#if defined(DUK_USE_ES6_UNICODE_ESCAPE) - DUK_ASSERT(digits == 0 /* first time */ || digits == -1 /* others */); - if (dig >= 0) { - DUK_ASSERT(dig >= 0x00 && dig <= 0x0f); - escval = (escval << 4) + dig; - if (escval > 0x10ffffL) { - goto fail_escape; - } - } else if (x == DUK_ASC_RCURLY) { - if (digits == 0) { - /* Empty escape, \u{}. */ - goto fail_escape; - } - DUK_ASSERT(escval >= 0 && escval <= 0x10ffffL); - break; - } else { - goto fail_escape; - } - digits = -1; /* Indicate we have at least one digit. */ -#else /* DUK_USE_ES6_UNICODE_ESCAPE */ - DUK_ASSERT(0); /* Never happens if \u{H+} support disabled. */ -#endif /* DUK_USE_ES6_UNICODE_ESCAPE */ - } - } - - return escval; - - fail_escape: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); -} - -/* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum - * allowed value is \0377 (U+00FF), longest match is used. Used for both string - * RegExp octal escape parsing. Window[0] must be the slash '\' and the first - * digit must already be validated to be in [0-9] by the caller. - */ -DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_uint_t *out_adv, duk_bool_t reject_annex_b) { - duk_codepoint_t cp; - duk_small_uint_t lookup_idx; - duk_small_uint_t adv; - duk_codepoint_t tmp; - - DUK_ASSERT(out_adv != NULL); - DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH); - DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9); - - cp = 0; - tmp = 0; - for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { - DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); - tmp = DUK__LOOKUP(lex_ctx, lookup_idx); - if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { - /* No more valid digits. */ - break; - } - tmp = (cp << 3) + (tmp - DUK_ASC_0); - if (tmp > 0xff) { - /* Three digit octal escapes above \377 (= 0xff) - * are not allowed. - */ - break; - } - cp = tmp; - } - DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); - - adv = lookup_idx; - if (lookup_idx == 1) { - DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); - DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9); - cp = tmp; - adv++; /* correction to above, eat offending character */ - } else if (lookup_idx == 2 && cp == 0) { - /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not. - * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError. - */ - DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); - } else { - /* This clause also handles non-shortest zero, e.g. \00. */ - if (reject_annex_b) { - DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode", (long) cp)); - cp = -1; - } else { - DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted", (long) cp)); - DUK_ASSERT(cp >= 0 && cp <= 0xff); - } - } - - *out_adv = adv; - - DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b)); - return cp; -} - -/* XXX: move strict mode to lex_ctx? */ -DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) { - duk_small_uint_t adv; - - for (adv = 1 /* initial quote */ ;;) { - duk_codepoint_t x; - - DUK__ADVANCECHARS(lex_ctx, adv); /* eat opening quote on first loop */ - x = DUK__L0(); - - adv = 1; - if (x == quote) { - DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */ - break; - } else if (x == '\\') { - /* DUK__L0 -> '\' char - * DUK__L1 ... DUK__L5 -> more lookup - */ - duk_small_int_t emitcp = -1; - - x = DUK__L1(); - - /* How much to advance before next loop. */ - adv = 2; /* note: long live range */ - - switch (x) { - case '\'': - emitcp = 0x0027; - break; - case '"': - emitcp = 0x0022; - break; - case '\\': - emitcp = 0x005c; - break; - case 'b': - emitcp = 0x0008; - break; - case 'f': - emitcp = 0x000c; - break; - case 'n': - emitcp = 0x000a; - break; - case 'r': - emitcp = 0x000d; - break; - case 't': - emitcp = 0x0009; - break; - case 'v': - emitcp = 0x000b; - break; - case 'x': - case 'u': { - duk_codepoint_t esc_cp; - esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/); - DUK__APPENDBUFFER(lex_ctx, esc_cp); - adv = 0; - break; - } - default: { - if (duk_unicode_is_line_terminator(x)) { - /* line continuation */ - if (x == 0x000d && DUK__L2() == 0x000a) { - /* CR LF again a special case */ - adv = 3; /* line terminator, CR, LF */ - } - } else if (DUK__ISDIGIT(x)) { - /* - * Octal escape or zero escape: - * \0 (lookahead not OctalDigit) - * \1 ... \7 (lookahead not OctalDigit) - * \ZeroToThree OctalDigit (lookahead not OctalDigit) - * \FourToSeven OctalDigit (no lookahead restrictions) - * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions) - * - * Zero escape is part of the standard syntax. Octal escapes are - * defined in E5 Section B.1.2, and are only allowed in non-strict mode. - * Any other productions starting with a decimal digit are invalid - * but are in practice treated like identity escapes. - * - * Parse octal (up to 3 digits) from the lookup window. - */ - - emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/); - if (emitcp < 0) { - goto fail_escape; - } - } else if (x < 0) { - goto fail_unterminated; - } else { - /* escaped NonEscapeCharacter */ - DUK__APPENDBUFFER(lex_ctx, x); - } - } /* end default clause */ - } /* end switch */ - - /* Shared handling for single codepoint escapes. */ - if (emitcp >= 0) { - DUK__APPENDBUFFER(lex_ctx, emitcp); - } - - /* Track number of escapes; count not really needed but directive - * prologues need to detect whether there were any escapes or line - * continuations or not. - */ - out_token->num_escapes++; - } else if (x >= 0x20 && x <= 0x7f) { - /* Fast path for ASCII case, avoids line terminator - * check and CESU-8 encoding. - */ - DUK_ASSERT(x >= 0); - DUK_ASSERT(!duk_unicode_is_line_terminator(x)); - DUK_ASSERT(x != quote); - DUK_ASSERT(x != DUK_ASC_BACKSLASH); - DUK__APPENDBUFFER_ASCII(lex_ctx, x); - } else if (x < 0 || duk_unicode_is_line_terminator(x)) { - goto fail_unterminated; - } else { - /* Character which is part of the string but wasn't handled - * by the fast path. - */ - DUK__APPENDBUFFER(lex_ctx, x); - } - } /* string parse loop */ - - return; - - fail_escape: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); - return; - - fail_unterminated: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_STRING); - return; -} - -/* Skip to end-of-line (or end-of-file), used for single line comments. */ -DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) { - for (;;) { - duk_codepoint_t x; - - x = DUK__L0(); - if (x < 0 || duk_unicode_is_line_terminator(x)) { - break; - } - DUK__ADVANCECHARS(lex_ctx, 1); - } -} - -/* - * Parse Ecmascript source InputElementDiv or InputElementRegExp - * (E5 Section 7), skipping whitespace, comments, and line terminators. - * - * Possible results are: - * (1) a token - * (2) a line terminator (skipped) - * (3) a comment (skipped) - * (4) EOF - * - * White space is automatically skipped from the current position (but - * not after the input element). If input has already ended, returns - * DUK_TOK_EOF indefinitely. If a parse error occurs, uses an DUK_ERROR() - * macro call (and hence a longjmp through current heap longjmp context). - * Comments and line terminator tokens are automatically skipped. - * - * The input element being matched is determined by regexp_mode; if set, - * parses a InputElementRegExp, otherwise a InputElementDiv. The - * difference between these are handling of productions starting with a - * forward slash. - * - * If strict_mode is set, recognizes additional future reserved words - * specific to strict mode, and refuses to parse octal literals. - * - * The matching strategy below is to (currently) use a six character - * lookup window to quickly determine which production is the -longest- - * matching one, and then parse that. The top-level if-else clauses - * match the first character, and the code blocks for each clause - * handle -all- alternatives for that first character. Ecmascript - * specification uses the "longest match wins" semantics, so the order - * of the if-clauses matters. - * - * Misc notes: - * - * * Ecmascript numeric literals do not accept a sign character. - * Consequently e.g. "-1.0" is parsed as two tokens: a negative - * sign and a positive numeric literal. The compiler performs - * the negation during compilation, so this has no adverse impact. - * - * * There is no token for "undefined": it is just a value available - * from the global object (or simply established by doing a reference - * to an undefined value). - * - * * Some contexts want Identifier tokens, which are IdentifierNames - * excluding reserved words, while some contexts want IdentifierNames - * directly. In the latter case e.g. "while" is interpreted as an - * identifier name, not a DUK_TOK_WHILE token. The solution here is - * to provide both token types: DUK_TOK_WHILE goes to 't' while - * DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains - * the identifier / keyword name. - * - * * Directive prologue needs to identify string literals such as - * "use strict" and 'use strict', which are sensitive to line - * continuations and escape sequences. For instance, "use\u0020strict" - * is a valid directive but is distinct from "use strict". The solution - * here is to decode escapes while tokenizing, but to keep track of the - * number of escapes. Directive detection can then check that the - * number of escapes is zero. - * - * * Multi-line comments with one or more internal LineTerminator are - * treated like a line terminator to comply with automatic semicolon - * insertion. - */ - -DUK_INTERNAL -void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx, - duk_token *out_token, - duk_bool_t strict_mode, - duk_bool_t regexp_mode) { - duk_codepoint_t x; /* temporary, must be signed and 32-bit to hold Unicode code points */ - duk_small_uint_t advtok = 0; /* (advance << 8) + token_type, updated at function end, - * init is unnecessary but suppresses "may be used uninitialized" warnings. - */ - duk_bool_t got_lineterm = 0; /* got lineterm preceding non-whitespace, non-lineterm token */ - - if (++lex_ctx->token_count >= lex_ctx->token_limit) { - goto fail_token_limit; - } - - out_token->t = DUK_TOK_EOF; - out_token->t_nores = DUK_TOK_INVALID; /* marker: copy t if not changed */ -#if 0 /* not necessary to init, disabled for faster parsing */ - out_token->num = DUK_DOUBLE_NAN; - out_token->str1 = NULL; - out_token->str2 = NULL; -#endif - out_token->num_escapes = 0; - /* out_token->lineterm set by caller */ - - /* This would be nice, but parsing is faster without resetting the - * value slots. The only side effect is that references to temporary - * string values may linger until lexing is finished; they're then - * freed normally. - */ -#if 0 - duk_to_undefined(lex_ctx->thr, lex_ctx->slot1_idx); - duk_to_undefined(lex_ctx->thr, lex_ctx->slot2_idx); -#endif - - /* 'advtok' indicates how much to advance and which token id to assign - * at the end. This shared functionality minimizes code size. All - * code paths are required to set 'advtok' to some value, so no default - * init value is used. Code paths calling DUK_ERROR() never return so - * they don't need to set advtok. - */ - - /* - * Matching order: - * - * Punctuator first chars, also covers comments, regexps - * LineTerminator - * Identifier or reserved word, also covers null/true/false literals - * NumericLiteral - * StringLiteral - * EOF - * - * The order does not matter as long as the longest match is - * always correctly identified. There are order dependencies - * in the clauses, so it's not trivial to convert to a switch. - */ - - restart_lineupdate: - out_token->start_line = lex_ctx->window[0].line; - - restart: - out_token->start_offset = lex_ctx->window[0].offset; - - x = DUK__L0(); - - switch (x) { - case DUK_ASC_SPACE: - case DUK_ASC_HT: /* fast paths for space and tab */ - DUK__ADVANCECHARS(lex_ctx, 1); - goto restart; - case DUK_ASC_LF: /* LF line terminator; CR LF and Unicode lineterms are handled in slow path */ - DUK__ADVANCECHARS(lex_ctx, 1); - got_lineterm = 1; - goto restart_lineupdate; -#if defined(DUK_USE_SHEBANG_COMMENTS) - case DUK_ASC_HASH: /* '#' */ - if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 && - (lex_ctx->flags & DUK_COMPILE_SHEBANG)) { - /* "Shebang" comment ('#! ...') on first line. */ - /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ - duk__lexer_skip_to_endofline(lex_ctx); - goto restart; /* line terminator will be handled on next round */ - } - goto fail_token; -#endif /* DUK_USE_SHEBANG_COMMENTS */ - case DUK_ASC_SLASH: /* '/' */ - if (DUK__L1() == DUK_ASC_SLASH) { - /* - * E5 Section 7.4, allow SourceCharacter (which is any 16-bit - * code point). - */ - - /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ - duk__lexer_skip_to_endofline(lex_ctx); - goto restart; /* line terminator will be handled on next round */ - } else if (DUK__L1() == DUK_ASC_STAR) { - /* - * E5 Section 7.4. If the multi-line comment contains a newline, - * it is treated like a single line terminator for automatic - * semicolon insertion. - */ - - duk_bool_t last_asterisk = 0; - DUK__ADVANCECHARS(lex_ctx, 2); - for (;;) { - x = DUK__L0(); - if (x < 0) { - goto fail_unterm_comment; - } - DUK__ADVANCECHARS(lex_ctx, 1); - if (last_asterisk && x == DUK_ASC_SLASH) { - break; - } - if (duk_unicode_is_line_terminator(x)) { - got_lineterm = 1; - } - last_asterisk = (x == DUK_ASC_STAR); - } - goto restart_lineupdate; - } else if (regexp_mode) { -#if defined(DUK_USE_REGEXP_SUPPORT) - /* - * "/" followed by something in regexp mode. See E5 Section 7.8.5. - * - * RegExp parsing is a bit complex. First, the regexp body is delimited - * by forward slashes, but the body may also contain forward slashes as - * part of an escape sequence or inside a character class (delimited by - * square brackets). A mini state machine is used to implement these. - * - * Further, an early (parse time) error must be thrown if the regexp - * would cause a run-time error when used in the expression new RegExp(...). - * Parsing here simply extracts the (candidate) regexp, and also accepts - * invalid regular expressions (which are delimited properly). The caller - * (compiler) must perform final validation and regexp compilation. - * - * RegExp first char may not be '/' (single line comment) or '*' (multi- - * line comment). These have already been checked above, so there is no - * need below for special handling of the first regexp character as in - * the E5 productions. - * - * About unicode escapes within regexp literals: - * - * E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes. - * However, Section 6 states that regexps accept the escapes, - * see paragraph starting with "In string literals...". - * The regexp grammar, which sees the decoded regexp literal - * (after lexical parsing) DOES have a \uHHHH unicode escape. - * So, for instance: - * - * /\u1234/ - * - * should first be parsed by the lexical grammar as: - * - * '\' 'u' RegularExpressionBackslashSequence - * '1' RegularExpressionNonTerminator - * '2' RegularExpressionNonTerminator - * '3' RegularExpressionNonTerminator - * '4' RegularExpressionNonTerminator - * - * and the escape itself is then parsed by the regexp engine. - * This is the current implementation. - * - * Minor spec inconsistency: - * - * E5 Section 7.8.5 RegularExpressionBackslashSequence is: - * - * \ RegularExpressionNonTerminator - * - * while Section A.1 RegularExpressionBackslashSequence is: - * - * \ NonTerminator - * - * The latter is not normative and a typo. - * - */ - - /* first, parse regexp body roughly */ - - duk_small_int_t state = 0; /* 0=base, 1=esc, 2=class, 3=class+esc */ - - DUK__INITBUFFER(lex_ctx); - for (;;) { - DUK__ADVANCECHARS(lex_ctx, 1); /* skip opening slash on first loop */ - x = DUK__L0(); - if (x < 0 || duk_unicode_is_line_terminator(x)) { - goto fail_unterm_regexp; - } - x = DUK__L0(); /* re-read to avoid spill / fetch */ - if (state == 0) { - if (x == DUK_ASC_SLASH) { - DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing slash */ - break; - } else if (x == DUK_ASC_BACKSLASH) { - state = 1; - } else if (x == DUK_ASC_LBRACKET) { - state = 2; - } - } else if (state == 1) { - state = 0; - } else if (state == 2) { - if (x == DUK_ASC_RBRACKET) { - state = 0; - } else if (x == DUK_ASC_BACKSLASH) { - state = 3; - } - } else { /* state == 3 */ - state = 2; - } - DUK__APPENDBUFFER(lex_ctx, x); - } - out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx); - - /* second, parse flags */ - - DUK__INITBUFFER(lex_ctx); - for (;;) { - x = DUK__L0(); - if (!duk_unicode_is_identifier_part(x)) { - break; - } - x = DUK__L0(); /* re-read to avoid spill / fetch */ - DUK__APPENDBUFFER(lex_ctx, x); - DUK__ADVANCECHARS(lex_ctx, 1); - } - out_token->str2 = duk__internbuffer(lex_ctx, lex_ctx->slot2_idx); - - DUK__INITBUFFER(lex_ctx); /* free some memory */ - - /* validation of the regexp is caller's responsibility */ - - advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP); -#else /* DUK_USE_REGEXP_SUPPORT */ - goto fail_regexp_support; -#endif /* DUK_USE_REGEXP_SUPPORT */ - } else if (DUK__L1() == DUK_ASC_EQUALS) { - /* "/=" and not in regexp mode */ - advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ); - } else { - /* "/" and not in regexp mode */ - advtok = DUK__ADVTOK(1, DUK_TOK_DIV); - } - break; - case DUK_ASC_LCURLY: /* '{' */ - advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY); - break; - case DUK_ASC_RCURLY: /* '}' */ - advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY); - break; - case DUK_ASC_LPAREN: /* '(' */ - advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN); - break; - case DUK_ASC_RPAREN: /* ')' */ - advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN); - break; - case DUK_ASC_LBRACKET: /* '[' */ - advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET); - break; - case DUK_ASC_RBRACKET: /* ']' */ - advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET); - break; - case DUK_ASC_PERIOD: /* '.' */ - if (DUK__ISDIGIT(DUK__L1())) { - /* Period followed by a digit can only start DecimalLiteral - * (handled in slow path). We could jump straight into the - * DecimalLiteral handling but should avoid goto to inside - * a block. - */ - goto slow_path; - } - advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD); - break; - case DUK_ASC_SEMICOLON: /* ';' */ - advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON); - break; - case DUK_ASC_COMMA: /* ',' */ - advtok = DUK__ADVTOK(1, DUK_TOK_COMMA); - break; - case DUK_ASC_LANGLE: /* '<' */ -#if defined(DUK_USE_HTML_COMMENTS) - if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) { - /* - * ES2015: B.1.3, handle "" SingleLineHTMLCloseComment - * Only allowed: - * - on new line - * - preceded only by whitespace - * - preceded by end of multiline comment and optional whitespace - * - * Since whitespace generates no tokens, and multiline comments - * are treated as a line ending, consulting `got_lineterm` is - * sufficient to test for these three options. - */ - - /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */ - duk__lexer_skip_to_endofline(lex_ctx); - goto restart; /* line terminator will be handled on next round */ - } else -#endif /* DUK_USE_HTML_COMMENTS */ - if (DUK__L1() == DUK_ASC_MINUS) { - advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT); - } else if (DUK__L1() == DUK_ASC_EQUALS) { - advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ); - } else { - advtok = DUK__ADVTOK(1, DUK_TOK_SUB); - } - break; - case DUK_ASC_STAR: /* '*' */ -#if defined(DUK_USE_ES7_EXP_OPERATOR) - if (DUK__L1() == DUK_ASC_STAR && DUK__L2() == DUK_ASC_EQUALS) { - advtok = DUK__ADVTOK(3, DUK_TOK_EXP_EQ); - } else if (DUK__L1() == DUK_ASC_STAR) { - advtok = DUK__ADVTOK(2, DUK_TOK_EXP); - } else -#endif - if (DUK__L1() == DUK_ASC_EQUALS) { - advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ); - } else { - advtok = DUK__ADVTOK(1, DUK_TOK_MUL); - } - break; - case DUK_ASC_PERCENT: /* '%' */ - if (DUK__L1() == DUK_ASC_EQUALS) { - advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ); - } else { - advtok = DUK__ADVTOK(1, DUK_TOK_MOD); - } - break; - case DUK_ASC_AMP: /* '&' */ - if (DUK__L1() == DUK_ASC_AMP) { - advtok = DUK__ADVTOK(2, DUK_TOK_LAND); - } else if (DUK__L1() == DUK_ASC_EQUALS) { - advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ); - } else { - advtok = DUK__ADVTOK(1, DUK_TOK_BAND); - } - break; - case DUK_ASC_PIPE: /* '|' */ - if (DUK__L1() == DUK_ASC_PIPE) { - advtok = DUK__ADVTOK(2, DUK_TOK_LOR); - } else if (DUK__L1() == DUK_ASC_EQUALS) { - advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ); - } else { - advtok = DUK__ADVTOK(1, DUK_TOK_BOR); - } - break; - case DUK_ASC_CARET: /* '^' */ - if (DUK__L1() == DUK_ASC_EQUALS) { - advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ); - } else { - advtok = DUK__ADVTOK(1, DUK_TOK_BXOR); - } - break; - case DUK_ASC_TILDE: /* '~' */ - advtok = DUK__ADVTOK(1, DUK_TOK_BNOT); - break; - case DUK_ASC_QUESTION: /* '?' */ - advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION); - break; - case DUK_ASC_COLON: /* ':' */ - advtok = DUK__ADVTOK(1, DUK_TOK_COLON); - break; - case DUK_ASC_DOUBLEQUOTE: /* '"' */ - case DUK_ASC_SINGLEQUOTE: { /* '\'' */ - DUK__INITBUFFER(lex_ctx); - duk__lexer_parse_string_literal(lex_ctx, out_token, x /*quote*/, strict_mode); - duk__internbuffer(lex_ctx, lex_ctx->slot1_idx); - out_token->str1 = duk_known_hstring(lex_ctx->thr, lex_ctx->slot1_idx); - - DUK__INITBUFFER(lex_ctx); /* free some memory */ - - advtok = DUK__ADVTOK(0, DUK_TOK_STRING); - break; - } - default: - goto slow_path; - } /* switch */ - - goto skip_slow_path; - - slow_path: - if (duk_unicode_is_line_terminator(x)) { - if (x == 0x000d && DUK__L1() == 0x000a) { - /* - * E5 Section 7.3: CR LF is detected as a single line terminator for - * line numbers. Here we also detect it as a single line terminator - * token. - */ - DUK__ADVANCECHARS(lex_ctx, 2); - } else { - DUK__ADVANCECHARS(lex_ctx, 1); - } - got_lineterm = 1; - goto restart_lineupdate; - } else if (duk_unicode_is_identifier_start(x) || x == DUK_ASC_BACKSLASH) { - /* - * Parse an identifier and then check whether it is: - * - reserved word (keyword or other reserved word) - * - "null" (NullLiteral) - * - "true" (BooleanLiteral) - * - "false" (BooleanLiteral) - * - anything else => identifier - * - * This does not follow the E5 productions cleanly, but is - * useful and compact. - * - * Note that identifiers may contain Unicode escapes, - * see E5 Sections 6 and 7.6. They must be decoded first, - * and the result checked against allowed characters. - * The above if-clause accepts an identifier start and an - * '\' character -- no other token can begin with a '\'. - * - * Note that "get" and "set" are not reserved words in E5 - * specification so they are recognized as plain identifiers - * (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not - * used now). The compiler needs to work around this. - * - * Strictly speaking, following Ecmascript longest match - * specification, an invalid escape for the first character - * should cause a syntax error. However, an invalid escape - * for IdentifierParts should just terminate the identifier - * early (longest match), and let the next tokenization - * fail. For instance Rhino croaks with 'foo\z' when - * parsing the identifier. This has little practical impact. - */ - - duk_small_uint_t i, i_end; - duk_bool_t first = 1; - duk_hstring *str; - - DUK__INITBUFFER(lex_ctx); - for (;;) { - /* re-lookup first char on first loop */ - if (DUK__L0() == DUK_ASC_BACKSLASH) { - duk_codepoint_t esc_cp; - if (DUK__L1() != DUK_ASC_LC_U) { - goto fail_escape; - } - esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/); - DUK__APPENDBUFFER(lex_ctx, esc_cp); - - /* IdentifierStart is stricter than IdentifierPart, so if the first - * character is escaped, must have a stricter check here. - */ - if (!(first ? duk_unicode_is_identifier_start(esc_cp) : duk_unicode_is_identifier_part(esc_cp))) { - goto fail_escape; - } - - /* Track number of escapes: necessary for proper keyword - * detection. - */ - out_token->num_escapes++; - } else { - /* Note: first character is checked against this. But because - * IdentifierPart includes all IdentifierStart characters, and - * the first character (if unescaped) has already been checked - * in the if condition, this is OK. - */ - if (!duk_unicode_is_identifier_part(DUK__L0())) { - break; - } - DUK__APPENDBUFFER(lex_ctx, DUK__L0()); - DUK__ADVANCECHARS(lex_ctx, 1); - } - first = 0; - } - - out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx); - str = out_token->str1; - out_token->t_nores = DUK_TOK_IDENTIFIER; - - DUK__INITBUFFER(lex_ctx); /* free some memory */ - - /* - * Interned identifier is compared against reserved words, which are - * currently interned into the heap context. See genbuiltins.py. - * - * Note that an escape in the identifier disables recognition of - * keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to - * identifier named "if"). This is not necessarily compliant, - * see test-dec-escaped-char-in-keyword.js. - * - * Note: "get" and "set" are awkward. They are not officially - * ReservedWords (and indeed e.g. "var set = 1;" is valid), and - * must come out as DUK_TOK_IDENTIFIER. The compiler needs to - * work around this a bit. - */ - - /* XXX: optimize by adding the token numbers directly into the - * always interned duk_hstring objects (there should be enough - * flag bits free for that)? - */ - - i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED); - - advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER); - if (out_token->num_escapes == 0) { - for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) { - DUK_ASSERT_DISABLE(i >= 0); /* unsigned */ - DUK_ASSERT(i < DUK_HEAP_NUM_STRINGS); - if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) { - advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i)); - break; - } - } - } - } else if (DUK__ISDIGIT(x) || (x == DUK_ASC_PERIOD)) { - /* Note: decimal number may start with a period, but must be followed by a digit */ - - /* - * Pre-parsing for decimal, hex, octal (both legacy and ES2015), - * and binary literals, followed by an actual parser step - * provided by numconv. - * - * Note: the leading sign character ('+' or '-') is -not- part of - * the production in E5 grammar, and that the a DecimalLiteral - * starting with a '0' must be followed by a non-digit. - * - * XXX: the two step parsing process is quite awkward, it would - * be more straightforward to allow numconv to parse the longest - * valid prefix (it already does that, it only needs to indicate - * where the input ended). However, the lexer decodes characters - * using a limited lookup window, so this is not a trivial change. - */ - - /* XXX: because of the final check below (that the literal is not - * followed by a digit), this could maybe be simplified, if we bail - * out early from a leading zero (and if there are no periods etc). - * Maybe too complex. - */ - - duk_double_t val; - duk_bool_t legacy_oct = 0; - duk_small_int_t state; /* 0=before period/exp, - * 1=after period, before exp - * 2=after exp, allow '+' or '-' - * 3=after exp and exp sign - */ - duk_small_uint_t s2n_flags; - duk_codepoint_t y, z; - duk_small_int_t s2n_radix = 10; - duk_small_uint_t pre_adv = 0; - - DUK__INITBUFFER(lex_ctx); - y = DUK__L1(); - - if (x == DUK_ASC_0) { - z = DUK_LOWERCASE_CHAR_ASCII(y); - - pre_adv = 2; /* default for 0xNNN, 0oNNN, 0bNNN. */ - if (z == DUK_ASC_LC_X) { - s2n_radix = 16; - } else if (z == DUK_ASC_LC_O) { - s2n_radix = 8; - } else if (z == DUK_ASC_LC_B) { - s2n_radix = 2; - } else { - pre_adv = 0; - if (DUK__ISDIGIT(y)) { - if (strict_mode) { - /* Reject octal like \07 but also octal-lookalike - * decimal like \08 in strict mode. - */ - goto fail_number_literal; - } else { - /* Legacy OctalIntegerLiteral or octal-lookalice - * decimal. Deciding between the two happens below - * in digit scanning. - */ - DUK__APPENDBUFFER(lex_ctx, x); - pre_adv = 1; - legacy_oct = 1; - s2n_radix = 8; /* tentative unless conflicting digits found */ - } - } - } - } - - DUK__ADVANCECHARS(lex_ctx, pre_adv); - - /* XXX: we could parse integers here directly, and fall back - * to numconv only when encountering a fractional expression - * or when an octal literal turned out to be decimal (0778 etc). - */ - state = 0; - for (;;) { - x = DUK__L0(); /* re-lookup curr char on first round */ - if (DUK__ISDIGIT(x)) { - /* Note: intentionally allow leading zeroes here, as the - * actual parser will check for them. - */ - if (state == 0 && legacy_oct && (x == DUK_ASC_8 || x == DUK_ASC_9)) { - /* Started out as an octal-lookalike - * but interpreted as decimal, e.g. - * '0779' -> 779. This also means - * that fractions are allowed, e.g. - * '0779.123' is allowed but '0777.123' - * is not! - */ - s2n_radix = 10; - } - if (state == 2) { - state = 3; - } - } else if (s2n_radix == 16 && DUK__ISHEXDIGIT(x)) { - /* Note: 'e' and 'E' are also accepted here. */ - ; - } else if (x == DUK_ASC_PERIOD) { - if (state >= 1 || s2n_radix != 10) { - break; - } else { - state = 1; - } - } else if (x == DUK_ASC_LC_E || x == DUK_ASC_UC_E) { - if (state >= 2 || s2n_radix != 10) { - break; - } else { - state = 2; - } - } else if (x == DUK_ASC_MINUS || x == DUK_ASC_PLUS) { - if (state != 2) { - break; - } else { - state = 3; - } - } else { - break; - } - DUK__APPENDBUFFER(lex_ctx, x); - DUK__ADVANCECHARS(lex_ctx, 1); - } - - /* XXX: better coercion */ - (void) duk__internbuffer(lex_ctx, lex_ctx->slot1_idx); - - if (s2n_radix != 10) { - /* For bases other than 10, integer only. */ - s2n_flags = DUK_S2N_FLAG_ALLOW_LEADING_ZERO; - } else { - s2n_flags = DUK_S2N_FLAG_ALLOW_EXP | - DUK_S2N_FLAG_ALLOW_FRAC | - DUK_S2N_FLAG_ALLOW_NAKED_FRAC | - DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | - DUK_S2N_FLAG_ALLOW_LEADING_ZERO; - } - - duk_dup(lex_ctx->thr, lex_ctx->slot1_idx); - duk_numconv_parse(lex_ctx->thr, s2n_radix, s2n_flags); - val = duk_to_number_m1(lex_ctx->thr); - if (DUK_ISNAN(val)) { - goto fail_number_literal; - } - duk_replace(lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */ - - DUK__INITBUFFER(lex_ctx); /* free some memory */ - - /* Section 7.8.3 (note): NumericLiteral must be followed by something other than - * IdentifierStart or DecimalDigit. - */ - - if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) { - goto fail_number_literal; - } - - out_token->num = val; - advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER); - } else if (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) { - DUK__ADVANCECHARS(lex_ctx, 1); - goto restart; - } else if (x < 0) { - advtok = DUK__ADVTOK(0, DUK_TOK_EOF); - } else { - goto fail_token; - } - skip_slow_path: - - /* - * Shared exit path - */ - - DUK__ADVANCEBYTES(lex_ctx, advtok >> 8); - out_token->t = advtok & 0xff; - if (out_token->t_nores == DUK_TOK_INVALID) { - out_token->t_nores = out_token->t; - } - out_token->lineterm = got_lineterm; - - /* Automatic semicolon insertion is allowed if a token is preceded - * by line terminator(s), or terminates a statement list (right curly - * or EOF). - */ - if (got_lineterm || out_token->t == DUK_TOK_RCURLY || out_token->t == DUK_TOK_EOF) { - out_token->allow_auto_semi = 1; - } else { - out_token->allow_auto_semi = 0; - } - - return; - - fail_token_limit: - DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT); - return; - - fail_token: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_TOKEN); - return; - - fail_number_literal: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_NUMBER_LITERAL); - return; - - fail_escape: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); - return; - - fail_unterm_regexp: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_REGEXP); - return; - - fail_unterm_comment: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_COMMENT); - return; - -#if !defined(DUK_USE_REGEXP_SUPPORT) - fail_regexp_support: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_REGEXP_SUPPORT_DISABLED); - return; -#endif -} - -#if defined(DUK_USE_REGEXP_SUPPORT) - -/* - * Parse a RegExp token. The grammar is described in E5 Section 15.10. - * Terminal constructions (such as quantifiers) are parsed directly here. - * - * 0xffffffffU is used as a marker for "infinity" in quantifiers. Further, - * DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that - * will be accepted for a quantifier. - */ - -DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) { - duk_small_uint_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */ - duk_codepoint_t x, y; - - if (++lex_ctx->token_count >= lex_ctx->token_limit) { - goto fail_token_limit; - } - - DUK_MEMZERO(out_token, sizeof(*out_token)); - - x = DUK__L0(); - y = DUK__L1(); - - DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld", (long) x, (long) y)); - - switch (x) { - case DUK_ASC_PIPE: { - advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION); - break; - } - case DUK_ASC_CARET: { - advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START); - break; - } - case DUK_ASC_DOLLAR: { - advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END); - break; - } - case DUK_ASC_QUESTION: { - out_token->qmin = 0; - out_token->qmax = 1; - if (y == DUK_ASC_QUESTION) { - advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER); - out_token->greedy = 0; - } else { - advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER); - out_token->greedy = 1; - } - break; - } - case DUK_ASC_STAR: { - out_token->qmin = 0; - out_token->qmax = DUK_RE_QUANTIFIER_INFINITE; - if (y == DUK_ASC_QUESTION) { - advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER); - out_token->greedy = 0; - } else { - advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER); - out_token->greedy = 1; - } - break; - } - case DUK_ASC_PLUS: { - out_token->qmin = 1; - out_token->qmax = DUK_RE_QUANTIFIER_INFINITE; - if (y == DUK_ASC_QUESTION) { - advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER); - out_token->greedy = 0; - } else { - advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER); - out_token->greedy = 1; - } - break; - } - case DUK_ASC_LCURLY: { - /* Production allows 'DecimalDigits', including leading zeroes */ - duk_uint32_t val1 = 0; - duk_uint32_t val2 = DUK_RE_QUANTIFIER_INFINITE; - duk_small_int_t digits = 0; -#if defined(DUK_USE_ES6_REGEXP_SYNTAX) - duk_lexer_point lex_pt; -#endif - -#if defined(DUK_USE_ES6_REGEXP_SYNTAX) - /* Store lexer position, restoring if quantifier is invalid. */ - DUK_LEXER_GETPOINT(lex_ctx, &lex_pt); -#endif - - for (;;) { - DUK__ADVANCECHARS(lex_ctx, 1); /* eat '{' on entry */ - x = DUK__L0(); - if (DUK__ISDIGIT(x)) { - digits++; - val1 = val1 * 10 + (duk_uint32_t) duk__hexval(x); - } else if (x == DUK_ASC_COMMA) { - if (digits > DUK__MAX_RE_QUANT_DIGITS) { - goto invalid_quantifier; - } - if (val2 != DUK_RE_QUANTIFIER_INFINITE) { - goto invalid_quantifier; - } - if (DUK__L1() == DUK_ASC_RCURLY) { - /* form: { DecimalDigits , }, val1 = min count */ - if (digits == 0) { - goto invalid_quantifier; - } - out_token->qmin = val1; - out_token->qmax = DUK_RE_QUANTIFIER_INFINITE; - DUK__ADVANCECHARS(lex_ctx, 2); - break; - } - val2 = val1; - val1 = 0; - digits = 0; /* not strictly necessary because of lookahead '}' above */ - } else if (x == DUK_ASC_RCURLY) { - if (digits > DUK__MAX_RE_QUANT_DIGITS) { - goto invalid_quantifier; - } - if (digits == 0) { - goto invalid_quantifier; - } - if (val2 != DUK_RE_QUANTIFIER_INFINITE) { - /* val2 = min count, val1 = max count */ - out_token->qmin = val2; - out_token->qmax = val1; - } else { - /* val1 = count */ - out_token->qmin = val1; - out_token->qmax = val1; - } - DUK__ADVANCECHARS(lex_ctx, 1); - break; - } else { - goto invalid_quantifier; - } - } - if (DUK__L0() == DUK_ASC_QUESTION) { - out_token->greedy = 0; - DUK__ADVANCECHARS(lex_ctx, 1); - } else { - out_token->greedy = 1; - } - advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER); - break; - invalid_quantifier: -#if defined(DUK_USE_ES6_REGEXP_SYNTAX) - /* Failed to match the quantifier, restore lexer and parse - * opening brace as a literal. - */ - DUK_LEXER_SETPOINT(lex_ctx, &lex_pt); - advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR); - out_token->num = DUK_ASC_LCURLY; -#else - goto fail_quantifier; -#endif - break; - } - case DUK_ASC_PERIOD: { - advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD); - break; - } - case DUK_ASC_BACKSLASH: { - /* The E5.1 specification does not seem to allow IdentifierPart characters - * to be used as identity escapes. Unfortunately this includes '$', which - * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'. - * Many other implementations (including V8 and Rhino, for instance) do - * accept '\$' as a valid identity escape, which is quite pragmatic, and - * ES2015 Annex B relaxes the rules to allow these (and other) real world forms. - */ - - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); /* default: char escape (two chars) */ - if (y == DUK_ASC_LC_B) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY); - } else if (y == DUK_ASC_UC_B) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY); - } else if (y == DUK_ASC_LC_F) { - out_token->num = 0x000c; - } else if (y == DUK_ASC_LC_N) { - out_token->num = 0x000a; - } else if (y == DUK_ASC_LC_T) { - out_token->num = 0x0009; - } else if (y == DUK_ASC_LC_R) { - out_token->num = 0x000d; - } else if (y == DUK_ASC_LC_V) { - out_token->num = 0x000b; - } else if (y == DUK_ASC_LC_C) { - x = DUK__L2(); - if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) || - (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) { - out_token->num = (duk_uint32_t) (x % 32); - advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR); - } else { - goto fail_escape; - } - } else if (y == DUK_ASC_LC_X || y == DUK_ASC_LC_U) { - /* The token value is the Unicode codepoint without - * it being decode into surrogate pair characters - * here. The \u{H+} is only allowed in Unicode mode - * which we don't support yet. - */ - out_token->num = (duk_uint32_t) duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/); - advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_CHAR); - } else if (y == DUK_ASC_LC_D) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT); - } else if (y == DUK_ASC_UC_D) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT); - } else if (y == DUK_ASC_LC_S) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE); - } else if (y == DUK_ASC_UC_S) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE); - } else if (y == DUK_ASC_LC_W) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR); - } else if (y == DUK_ASC_UC_W) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR); - } else if (DUK__ISDIGIT(y)) { - /* E5 Section 15.10.2.11 */ - if (y == DUK_ASC_0) { - if (DUK__ISDIGIT(DUK__L2())) { - goto fail_escape; - } - out_token->num = 0x0000; - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); - } else { - /* XXX: shared parsing? */ - duk_uint32_t val = 0; - duk_small_int_t i; - for (i = 0; ; i++) { - if (i >= DUK__MAX_RE_DECESC_DIGITS) { - goto fail_escape; - } - DUK__ADVANCECHARS(lex_ctx, 1); /* eat backslash on entry */ - x = DUK__L0(); - if (!DUK__ISDIGIT(x)) { - break; - } - val = val * 10 + (duk_uint32_t) duk__hexval(x); - } - /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */ - advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE); - out_token->num = val; - } -#if defined(DUK_USE_ES6_REGEXP_SYNTAX) - } else if (y >= 0) { - /* For ES2015 Annex B, accept any source character as identity - * escape except 'c' which is used for control characters. - * http://www.ecma-international.org/ecma-262/6.0/#sec-regular-expressions-patterns - * Careful not to match end-of-buffer (<0) here. - * This is not yet full ES2015 Annex B because cases above - * (like hex escape) won't backtrack. - */ - DUK_ASSERT(y != DUK_ASC_LC_C); /* covered above */ -#else /* DUK_USE_ES6_REGEXP_SYNTAX */ - } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) || - y == DUK_UNICODE_CP_ZWNJ || - y == DUK_UNICODE_CP_ZWJ) { - /* For ES5.1 identity escapes are not allowed for identifier - * parts. This conflicts with a lot of real world code as this - * doesn't e.g. allow escaping a dollar sign as /\$/, see - * test-regexp-identity-escape-dollar.js. - */ -#endif /* DUK_USE_ES6_REGEXP_SYNTAX */ - out_token->num = (duk_uint32_t) y; - } else { - goto fail_escape; - } - break; - } - case DUK_ASC_LPAREN: { - /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */ - - if (y == DUK_ASC_QUESTION) { - if (DUK__L2() == DUK_ASC_EQUALS) { - /* (?= */ - advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD); - } else if (DUK__L2() == DUK_ASC_EXCLAMATION) { - /* (?! */ - advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD); - } else if (DUK__L2() == DUK_ASC_COLON) { - /* (?: */ - advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP); - } else { - goto fail_group; - } - } else { - /* ( */ - advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP); - } - break; - } - case DUK_ASC_RPAREN: { - advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP); - break; - } - case DUK_ASC_LBRACKET: { - /* - * To avoid creating a heavy intermediate value for the list of ranges, - * only the start token ('[' or '[^') is parsed here. The regexp - * compiler parses the ranges itself. - */ - - /* XXX: with DUK_USE_ES6_REGEXP_SYNTAX we should allow left bracket - * literal too, but it's not easy to parse without backtracking. - */ - - advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS); - if (y == DUK_ASC_CARET) { - advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED); - } - break; - } -#if !defined(DUK_USE_ES6_REGEXP_SYNTAX) - case DUK_ASC_RCURLY: - case DUK_ASC_RBRACKET: { - /* Although these could be parsed as PatternCharacters unambiguously (here), - * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters. - */ - goto fail_invalid_char; - break; - } -#endif - case -1: { - /* EOF */ - advtok = DUK__ADVTOK(0, DUK_TOK_EOF); - break; - } - default: { - /* PatternCharacter, all excluded characters are matched by cases above */ - advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR); - out_token->num = (duk_uint32_t) x; - break; - } - } - - /* - * Shared exit path - */ - - DUK__ADVANCEBYTES(lex_ctx, advtok >> 8); - out_token->t = advtok & 0xff; - return; - - fail_token_limit: - DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT); - return; - - fail_escape: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); - return; - - fail_group: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP); - return; - -#if !defined(DUK_USE_ES6_REGEXP_SYNTAX) - fail_invalid_char: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER); - return; - - fail_quantifier: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_QUANTIFIER); - return; -#endif -} - -/* - * Special parser for character classes; calls callback for every - * range parsed and returns the number of ranges present. - */ - -/* XXX: this duplicates functionality in duk_regexp.c where a similar loop is - * required anyway. We could use that BUT we need to update the regexp compiler - * 'nranges' too. Work this out a bit more cleanly to save space. - */ - -/* XXX: the handling of character range detection is a bit convoluted. - * Try to simplify and make smaller. - */ - -/* XXX: logic for handling character ranges is now incorrect, it will accept - * e.g. [\d-z] whereas it should croak from it? SMJS accepts this too, though. - * - * Needs a read through and a lot of additional tests. - */ - -DUK_LOCAL -void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx, - duk_re_range_callback gen_range, - void *userdata, - const duk_uint16_t *ranges, - duk_small_int_t num) { - const duk_uint16_t *ranges_end; - - DUK_UNREF(lex_ctx); - - ranges_end = ranges + num; - while (ranges < ranges_end) { - /* mark range 'direct', bypass canonicalization (see Wiki) */ - gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1); - ranges += 2; - } -} - -DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) { - duk_codepoint_t start = -1; - duk_codepoint_t ch; - duk_codepoint_t x; - duk_bool_t dash = 0; - duk_small_uint_t adv = 0; - - DUK_DD(DUK_DDPRINT("parsing regexp ranges")); - - for (;;) { - DUK__ADVANCECHARS(lex_ctx, adv); - adv = 1; - - x = DUK__L0(); - - ch = -1; /* not strictly necessary, but avoids "uninitialized variable" warnings */ - DUK_UNREF(ch); - - if (x < 0) { - goto fail_unterm_charclass; - } else if (x == DUK_ASC_RBRACKET) { - if (start >= 0) { - gen_range(userdata, start, start, 0); - } - DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */ - break; - } else if (x == DUK_ASC_MINUS) { - if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) { - /* '-' as a range indicator */ - dash = 1; - continue; - } else { - /* '-' verbatim */ - ch = x; - } - } else if (x == DUK_ASC_BACKSLASH) { - /* - * The escapes are same as outside a character class, except that \b has a - * different meaning, and \B and backreferences are prohibited (see E5 - * Section 15.10.2.19). However, it's difficult to share code because we - * handle e.g. "\n" very differently: here we generate a single character - * range for it. - */ - - /* XXX: ES2015 surrogate pair handling. */ - - x = DUK__L1(); - - adv = 2; - - if (x == DUK_ASC_LC_B) { - /* Note: '\b' in char class is different than outside (assertion), - * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part() - * check below. - */ - ch = 0x0008; - } else if (x == DUK_ASC_LC_F) { - ch = 0x000c; - } else if (x == DUK_ASC_LC_N) { - ch = 0x000a; - } else if (x == DUK_ASC_LC_T) { - ch = 0x0009; - } else if (x == DUK_ASC_LC_R) { - ch = 0x000d; - } else if (x == DUK_ASC_LC_V) { - ch = 0x000b; - } else if (x == DUK_ASC_LC_C) { - x = DUK__L2(); - adv = 3; - if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) || - (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) { - ch = (x % 32); - } else { - goto fail_escape; - } - } else if (x == DUK_ASC_LC_X || x == DUK_ASC_LC_U) { - /* The \u{H+} form is only allowed in Unicode mode which - * we don't support yet. - */ - ch = duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/); - adv = 0; - } else if (x == DUK_ASC_LC_D) { - duk__emit_u16_direct_ranges(lex_ctx, - gen_range, - userdata, - duk_unicode_re_ranges_digit, - sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t)); - ch = -1; - } else if (x == DUK_ASC_UC_D) { - duk__emit_u16_direct_ranges(lex_ctx, - gen_range, - userdata, - duk_unicode_re_ranges_not_digit, - sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t)); - ch = -1; - } else if (x == DUK_ASC_LC_S) { - duk__emit_u16_direct_ranges(lex_ctx, - gen_range, - userdata, - duk_unicode_re_ranges_white, - sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t)); - ch = -1; - } else if (x == DUK_ASC_UC_S) { - duk__emit_u16_direct_ranges(lex_ctx, - gen_range, - userdata, - duk_unicode_re_ranges_not_white, - sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t)); - ch = -1; - } else if (x == DUK_ASC_LC_W) { - duk__emit_u16_direct_ranges(lex_ctx, - gen_range, - userdata, - duk_unicode_re_ranges_wordchar, - sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t)); - ch = -1; - } else if (x == DUK_ASC_UC_W) { - duk__emit_u16_direct_ranges(lex_ctx, - gen_range, - userdata, - duk_unicode_re_ranges_not_wordchar, - sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t)); - ch = -1; - } else if (DUK__ISDIGIT(x)) { - /* DecimalEscape, only \0 is allowed, no leading - * zeroes are allowed. - * - * ES2015 Annex B also allows (maximal match) legacy - * octal escapes up to \377 and \8 and \9 are - * accepted as literal '8' and '9', also in strict mode. - */ - -#if defined(DUK_USE_ES6_REGEXP_SYNTAX) - ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/); - DUK_ASSERT(ch >= 0); /* no rejections */ -#else - if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) { - ch = 0x0000; - } else { - goto fail_escape; - } -#endif -#if defined(DUK_USE_ES6_REGEXP_SYNTAX) - } else if (x >= 0) { - /* IdentityEscape: ES2015 Annex B allows almost all - * source characters here. Match anything except - * EOF here. - */ - ch = x; -#else /* DUK_USE_ES6_REGEXP_SYNTAX */ - } else if (!duk_unicode_is_identifier_part(x)) { - /* IdentityEscape: ES5.1 doesn't allow identity escape - * for identifier part characters, which conflicts with - * some real world code. For example, it doesn't allow - * /[\$]/ which is awkward. - */ - ch = x; -#endif /* DUK_USE_ES6_REGEXP_SYNTAX */ - } else { - goto fail_escape; - } - } else { - /* character represents itself */ - ch = x; - } - - /* ch is a literal character here or -1 if parsed entity was - * an escape such as "\s". - */ - - if (ch < 0) { - /* multi-character sets not allowed as part of ranges, see - * E5 Section 15.10.2.15, abstract operation CharacterRange. - */ - if (start >= 0) { - if (dash) { - goto fail_range; - } else { - gen_range(userdata, start, start, 0); - start = -1; - /* dash is already 0 */ - } - } - } else { - if (start >= 0) { - if (dash) { - if (start > ch) { - goto fail_range; - } - gen_range(userdata, start, ch, 0); - start = -1; - dash = 0; - } else { - gen_range(userdata, start, start, 0); - start = ch; - /* dash is already 0 */ - } - } else { - start = ch; - } - } - } - - return; - - fail_escape: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); - return; - - fail_range: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_RANGE); - return; - - fail_unterm_charclass: - DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_CHARCLASS); - return; -} - -#endif /* DUK_USE_REGEXP_SUPPORT */ - -/* automatic undefs */ -#undef DUK__ADVANCEBYTES -#undef DUK__ADVANCECHARS -#undef DUK__ADVTOK -#undef DUK__APPENDBUFFER -#undef DUK__APPENDBUFFER_ASCII -#undef DUK__INITBUFFER -#undef DUK__ISDIGIT -#undef DUK__ISDIGIT03 -#undef DUK__ISDIGIT47 -#undef DUK__ISHEXDIGIT -#undef DUK__ISOCTDIGIT -#undef DUK__L0 -#undef DUK__L1 -#undef DUK__L2 -#undef DUK__L3 -#undef DUK__L4 -#undef DUK__L5 -#undef DUK__LOOKUP -#undef DUK__MAX_RE_DECESC_DIGITS -#undef DUK__MAX_RE_QUANT_DIGITS -#line 1 "duk_numconv.c" -/* - * Number-to-string and string-to-number conversions. - * - * Slow path number-to-string and string-to-number conversion is based on - * a Dragon4 variant, with fast paths for small integers. Big integer - * arithmetic is needed for guaranteeing that the conversion is correct - * and uses a minimum number of digits. The big number arithmetic has a - * fixed maximum size and does not require dynamic allocations. - * - * See: doc/number-conversion.rst. - */ - -/* #include duk_internal.h -> already included */ - -#define DUK__IEEE_DOUBLE_EXP_BIAS 1023 -#define DUK__IEEE_DOUBLE_EXP_MIN (-1022) /* biased exp == 0 -> denormal, exp -1022 */ - -#define DUK__DIGITCHAR(x) duk_lc_digits[(x)] - -/* - * Tables generated with util/gennumdigits.py. - * - * duk__str2num_digits_for_radix indicates, for each radix, how many input - * digits should be considered significant for string-to-number conversion. - * The input is also padded to this many digits to give the Dragon4 - * conversion enough (apparent) precision to work with. - * - * duk__str2num_exp_limits indicates, for each radix, the radix-specific - * minimum/maximum exponent values (for a Dragon4 integer mantissa) - * below and above which the number is guaranteed to underflow to zero - * or overflow to Infinity. This allows parsing to keep bigint values - * bounded. - */ - -DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[] = { - 69, 44, 35, 30, 27, 25, 23, 22, 20, 20, /* 2 to 11 */ - 20, 19, 19, 18, 18, 17, 17, 17, 16, 16, /* 12 to 21 */ - 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, /* 22 to 31 */ - 14, 14, 14, 14, 14 /* 31 to 36 */ -}; - -typedef struct { - duk_int16_t upper; - duk_int16_t lower; -} duk__exp_limits; - -DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = { - { 957, -1147 }, { 605, -725 }, { 479, -575 }, { 414, -496 }, - { 372, -446 }, { 342, -411 }, { 321, -384 }, { 304, -364 }, - { 291, -346 }, { 279, -334 }, { 268, -323 }, { 260, -312 }, - { 252, -304 }, { 247, -296 }, { 240, -289 }, { 236, -283 }, - { 231, -278 }, { 227, -273 }, { 223, -267 }, { 220, -263 }, - { 216, -260 }, { 213, -256 }, { 210, -253 }, { 208, -249 }, - { 205, -246 }, { 203, -244 }, { 201, -241 }, { 198, -239 }, - { 196, -237 }, { 195, -234 }, { 193, -232 }, { 191, -230 }, - { 190, -228 }, { 188, -226 }, { 187, -225 }, -}; - -/* - * Limited functionality bigint implementation. - * - * Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits, - * with the caller responsible for ensuring this is never exceeded. No memory - * allocation (except stack) is needed for bigint computation. Operations - * have been tailored for number conversion needs. - * - * Argument order is "assignment order", i.e. target first, then arguments: - * x <- y * z --> duk__bi_mul(x, y, z); - */ - -/* This upper value has been experimentally determined; debug build will check - * bigint size with assertions. - */ -#define DUK__BI_MAX_PARTS 37 /* 37x32 = 1184 bits */ - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) -#define DUK__BI_PRINT(name,x) duk__bi_print((name),(x)) -#else -#define DUK__BI_PRINT(name,x) -#endif - -/* Current size is about 152 bytes. */ -typedef struct { - duk_small_int_t n; - duk_uint32_t v[DUK__BI_MAX_PARTS]; /* low to high */ -} duk__bigint; - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) -DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) { - /* Overestimate required size; debug code so not critical to be tight. */ - char buf[DUK__BI_MAX_PARTS * 9 + 64]; - char *p = buf; - duk_small_int_t i; - - /* No NUL term checks in this debug code. */ - p += DUK_SPRINTF(p, "%p n=%ld", (void *) x, (long) x->n); - if (x->n == 0) { - p += DUK_SPRINTF(p, " 0"); - } - for (i = x->n - 1; i >= 0; i--) { - p += DUK_SPRINTF(p, " %08lx", (unsigned long) x->v[i]); - } - - DUK_DDD(DUK_DDDPRINT("%s: %s", (const char *) name, (const char *) buf)); -} -#endif - -#if defined(DUK_USE_ASSERTIONS) -DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) { - return (duk_small_int_t) - ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ && - ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ ); -} -#endif - -DUK_LOCAL void duk__bi_normalize(duk__bigint *x) { - duk_small_int_t i; - - for (i = x->n - 1; i >= 0; i--) { - if (x->v[i] != 0) { - break; - } - } - - /* Note: if 'x' is zero, x->n becomes 0 here */ - x->n = i + 1; - DUK_ASSERT(duk__bi_is_valid(x)); -} - -/* x <- y */ -DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) { - duk_small_int_t n; - - n = y->n; - x->n = n; - if (n == 0) { - return; - } - DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * (size_t) n)); -} - -DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) { - if (v == 0U) { - x->n = 0; - } else { - x->n = 1; - x->v[0] = v; - } - DUK_ASSERT(duk__bi_is_valid(x)); -} - -/* Return value: <0 <=> x < y - * 0 <=> x == y - * >0 <=> x > y - */ -DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) { - duk_small_int_t i, nx, ny; - duk_uint32_t tx, ty; - - DUK_ASSERT(duk__bi_is_valid(x)); - DUK_ASSERT(duk__bi_is_valid(y)); - - nx = x->n; - ny = y->n; - if (nx > ny) { - goto ret_gt; - } - if (nx < ny) { - goto ret_lt; - } - for (i = nx - 1; i >= 0; i--) { - tx = x->v[i]; - ty = y->v[i]; - - if (tx > ty) { - goto ret_gt; - } - if (tx < ty) { - goto ret_lt; - } - } - - return 0; - - ret_gt: - return 1; - - ret_lt: - return -1; -} - -/* x <- y + z */ -#if defined(DUK_USE_64BIT_OPS) -DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) { - duk_uint64_t tmp; - duk_small_int_t i, ny, nz; - - DUK_ASSERT(duk__bi_is_valid(y)); - DUK_ASSERT(duk__bi_is_valid(z)); - - if (z->n > y->n) { - duk__bigint *t; - t = y; y = z; z = t; - } - DUK_ASSERT(y->n >= z->n); - - ny = y->n; nz = z->n; - tmp = 0U; - for (i = 0; i < ny; i++) { - DUK_ASSERT(i < DUK__BI_MAX_PARTS); - tmp += y->v[i]; - if (i < nz) { - tmp += z->v[i]; - } - x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL); - tmp = tmp >> 32; - } - if (tmp != 0U) { - DUK_ASSERT(i < DUK__BI_MAX_PARTS); - x->v[i++] = (duk_uint32_t) tmp; - } - x->n = i; - DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS); - - /* no need to normalize */ - DUK_ASSERT(duk__bi_is_valid(x)); -} -#else /* DUK_USE_64BIT_OPS */ -DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) { - duk_uint32_t carry, tmp1, tmp2; - duk_small_int_t i, ny, nz; - - DUK_ASSERT(duk__bi_is_valid(y)); - DUK_ASSERT(duk__bi_is_valid(z)); - - if (z->n > y->n) { - duk__bigint *t; - t = y; y = z; z = t; - } - DUK_ASSERT(y->n >= z->n); - - ny = y->n; nz = z->n; - carry = 0U; - for (i = 0; i < ny; i++) { - /* Carry is detected based on wrapping which relies on exact 32-bit - * types. - */ - DUK_ASSERT(i < DUK__BI_MAX_PARTS); - tmp1 = y->v[i]; - tmp2 = tmp1; - if (i < nz) { - tmp2 += z->v[i]; - } - - /* Careful with carry condition: - * - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678) - * - If carry added: 0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678) - */ - if (carry) { - tmp2++; - carry = (tmp2 <= tmp1 ? 1U : 0U); - } else { - carry = (tmp2 < tmp1 ? 1U : 0U); - } - - x->v[i] = tmp2; - } - if (carry) { - DUK_ASSERT(i < DUK__BI_MAX_PARTS); - DUK_ASSERT(carry == 1U); - x->v[i++] = carry; - } - x->n = i; - DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS); - - /* no need to normalize */ - DUK_ASSERT(duk__bi_is_valid(x)); -} -#endif /* DUK_USE_64BIT_OPS */ - -/* x <- y + z */ -DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) { - duk__bigint tmp; - - DUK_ASSERT(duk__bi_is_valid(y)); - - /* XXX: this could be optimized; there is only one call site now though */ - duk__bi_set_small(&tmp, z); - duk__bi_add(x, y, &tmp); - - DUK_ASSERT(duk__bi_is_valid(x)); -} - -#if 0 /* unused */ -/* x <- x + y, use t as temp */ -DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) { - duk__bi_add(t, x, y); - duk__bi_copy(x, t); -} -#endif - -/* x <- y - z, require x >= y => z >= 0, i.e. y >= z */ -#if defined(DUK_USE_64BIT_OPS) -DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) { - duk_small_int_t i, ny, nz; - duk_uint32_t ty, tz; - duk_int64_t tmp; - - DUK_ASSERT(duk__bi_is_valid(y)); - DUK_ASSERT(duk__bi_is_valid(z)); - DUK_ASSERT(duk__bi_compare(y, z) >= 0); - DUK_ASSERT(y->n >= z->n); - - ny = y->n; nz = z->n; - tmp = 0; - for (i = 0; i < ny; i++) { - ty = y->v[i]; - if (i < nz) { - tz = z->v[i]; - } else { - tz = 0; - } - tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp; - x->v[i] = (duk_uint32_t) ((duk_uint64_t) tmp & 0xffffffffUL); - tmp = tmp >> 32; /* 0 or -1 */ - } - DUK_ASSERT(tmp == 0); - - x->n = i; - duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */ - DUK_ASSERT(duk__bi_is_valid(x)); -} -#else -DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) { - duk_small_int_t i, ny, nz; - duk_uint32_t tmp1, tmp2, borrow; - - DUK_ASSERT(duk__bi_is_valid(y)); - DUK_ASSERT(duk__bi_is_valid(z)); - DUK_ASSERT(duk__bi_compare(y, z) >= 0); - DUK_ASSERT(y->n >= z->n); - - ny = y->n; nz = z->n; - borrow = 0U; - for (i = 0; i < ny; i++) { - /* Borrow is detected based on wrapping which relies on exact 32-bit - * types. - */ - tmp1 = y->v[i]; - tmp2 = tmp1; - if (i < nz) { - tmp2 -= z->v[i]; - } - - /* Careful with borrow condition: - * - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678) - * - If borrow subtracted: 0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678) - */ - if (borrow) { - tmp2--; - borrow = (tmp2 >= tmp1 ? 1U : 0U); - } else { - borrow = (tmp2 > tmp1 ? 1U : 0U); - } - - x->v[i] = tmp2; - } - DUK_ASSERT(borrow == 0U); - - x->n = i; - duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */ - DUK_ASSERT(duk__bi_is_valid(x)); -} -#endif - -#if 0 /* unused */ -/* x <- y - z */ -DUK_LOCAL void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) { - duk__bigint tmp; - - DUK_ASSERT(duk__bi_is_valid(y)); - - /* XXX: this could be optimized */ - duk__bi_set_small(&tmp, z); - duk__bi_sub(x, y, &tmp); - - DUK_ASSERT(duk__bi_is_valid(x)); -} -#endif - -/* x <- x - y, use t as temp */ -DUK_LOCAL void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) { - duk__bi_sub(t, x, y); - duk__bi_copy(x, t); -} - -/* x <- y * z */ -DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) { - duk_small_int_t i, j, nx, nz; - - DUK_ASSERT(duk__bi_is_valid(y)); - DUK_ASSERT(duk__bi_is_valid(z)); - - nx = y->n + z->n; /* max possible */ - DUK_ASSERT(nx <= DUK__BI_MAX_PARTS); - - if (nx == 0) { - /* Both inputs are zero; cases where only one is zero can go - * through main algorithm. - */ - x->n = 0; - return; - } - - DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * (size_t) nx)); - x->n = nx; - - nz = z->n; - for (i = 0; i < y->n; i++) { -#if defined(DUK_USE_64BIT_OPS) - duk_uint64_t tmp = 0U; - for (j = 0; j < nz; j++) { - tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j]; - x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL); - tmp = tmp >> 32; - } - if (tmp > 0) { - DUK_ASSERT(i + j < nx); - DUK_ASSERT(i + j < DUK__BI_MAX_PARTS); - DUK_ASSERT(x->v[i+j] == 0U); - x->v[i+j] = (duk_uint32_t) tmp; - } -#else - /* - * Multiply + add + carry for 32-bit components using only 16x16->32 - * multiplies and carry detection based on unsigned overflow. - * - * 1st mult, 32-bit: (A*2^16 + B) - * 2nd mult, 32-bit: (C*2^16 + D) - * 3rd add, 32-bit: E - * 4th add, 32-bit: F - * - * (AC*2^16 + B) * (C*2^16 + D) + E + F - * = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F - * = AC*2^32 + (AD + BC)*2^16 + (BD + E + F) - * = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F) - */ - duk_uint32_t a, b, c, d, e, f; - duk_uint32_t r, s, t; - - a = y->v[i]; b = a & 0xffffUL; a = a >> 16; - - f = 0; - for (j = 0; j < nz; j++) { - c = z->v[j]; d = c & 0xffffUL; c = c >> 16; - e = x->v[i+j]; - - /* build result as: (r << 32) + s: start with (BD + E + F) */ - r = 0; - s = b * d; - - /* add E */ - t = s + e; - if (t < s) { r++; } /* carry */ - s = t; - - /* add F */ - t = s + f; - if (t < s) { r++; } /* carry */ - s = t; - - /* add BC*2^16 */ - t = b * c; - r += (t >> 16); - t = s + ((t & 0xffffUL) << 16); - if (t < s) { r++; } /* carry */ - s = t; - - /* add AD*2^16 */ - t = a * d; - r += (t >> 16); - t = s + ((t & 0xffffUL) << 16); - if (t < s) { r++; } /* carry */ - s = t; - - /* add AC*2^32 */ - t = a * c; - r += t; - - DUK_DDD(DUK_DDDPRINT("ab=%08lx cd=%08lx ef=%08lx -> rs=%08lx %08lx", - (unsigned long) y->v[i], (unsigned long) z->v[j], - (unsigned long) x->v[i+j], (unsigned long) r, - (unsigned long) s)); - - x->v[i+j] = s; - f = r; - } - if (f > 0U) { - DUK_ASSERT(i + j < nx); - DUK_ASSERT(i + j < DUK__BI_MAX_PARTS); - DUK_ASSERT(x->v[i+j] == 0U); - x->v[i+j] = (duk_uint32_t) f; - } -#endif /* DUK_USE_64BIT_OPS */ - } - - duk__bi_normalize(x); - DUK_ASSERT(duk__bi_is_valid(x)); -} - -/* x <- y * z */ -DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) { - duk__bigint tmp; - - DUK_ASSERT(duk__bi_is_valid(y)); - - /* XXX: this could be optimized */ - duk__bi_set_small(&tmp, z); - duk__bi_mul(x, y, &tmp); - - DUK_ASSERT(duk__bi_is_valid(x)); -} - -/* x <- x * y, use t as temp */ -DUK_LOCAL void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) { - duk__bi_mul(t, x, y); - duk__bi_copy(x, t); -} - -/* x <- x * y, use t as temp */ -DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) { - duk__bi_mul_small(t, x, y); - duk__bi_copy(x, t); -} - -DUK_LOCAL int duk__bi_is_even(duk__bigint *x) { - DUK_ASSERT(duk__bi_is_valid(x)); - return (x->n == 0) || ((x->v[0] & 0x01) == 0); -} - -DUK_LOCAL int duk__bi_is_zero(duk__bigint *x) { - DUK_ASSERT(duk__bi_is_valid(x)); - return (x->n == 0); /* this is the case for normalized numbers */ -} - -/* Bigint is 2^52. Used to detect normalized IEEE double mantissa values - * which are at the lowest edge (next floating point value downwards has - * a different exponent). The lowest mantissa has the form: - * - * 1000........000 (52 zeroes; only "hidden bit" is set) - */ -DUK_LOCAL duk_small_int_t duk__bi_is_2to52(duk__bigint *x) { - DUK_ASSERT(duk__bi_is_valid(x)); - return (duk_small_int_t) - (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32))); -} - -/* x <- (1< 0); - r = y % 32; - DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * (size_t) n); - x->n = n; - x->v[n - 1] = (((duk_uint32_t) 1) << r); -} - -/* x <- b^y; use t1 and t2 as temps */ -DUK_LOCAL void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_int_t y, duk__bigint *t1, duk__bigint *t2) { - /* Fast path the binary case */ - - DUK_ASSERT(x != t1 && x != t2 && t1 != t2); /* distinct bignums, easy mistake to make */ - DUK_ASSERT(b >= 0); - DUK_ASSERT(y >= 0); - - if (b == 2) { - duk__bi_twoexp(x, y); - return; - } - - /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */ - - DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y)); - - duk__bi_set_small(x, 1); - duk__bi_set_small(t1, (duk_uint32_t) b); - for (;;) { - /* Loop structure ensures that we don't compute t1^2 unnecessarily - * on the final round, as that might create a bignum exceeding the - * current DUK__BI_MAX_PARTS limit. - */ - if (y & 0x01) { - duk__bi_mul_copy(x, t1, t2); - } - y = y >> 1; - if (y == 0) { - break; - } - duk__bi_mul_copy(t1, t1, t2); - } - - DUK__BI_PRINT("exp_small result", x); -} - -/* - * A Dragon4 number-to-string variant, based on: - * - * Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers - * Accurately" - * - * Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers - * Quickly and Accurately" - * - * The current algorithm is based on Figure 1 of the Burger-Dybvig paper, - * i.e. the base implementation without logarithm estimation speedups - * (these would increase code footprint considerably). Fixed-format output - * does not follow the suggestions in the paper; instead, we generate an - * extra digit and round-with-carry. - * - * The same algorithm is used for number parsing (with b=10 and B=2) - * by generating one extra digit and doing rounding manually. - * - * See doc/number-conversion.rst for limitations. - */ - -/* Maximum number of digits generated. */ -#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + slack */ - -/* Maximum number of characters in formatted value. */ -#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + slack */ - -/* Number and (minimum) size of bigints in the nc_ctx structure. */ -#define DUK__NUMCONV_CTX_NUM_BIGINTS 7 -#define DUK__NUMCONV_CTX_BIGINTS_SIZE (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS) - -typedef struct { - /* Currently about 7*152 = 1064 bytes. The space for these - * duk__bigints is used also as a temporary buffer for generating - * the final string. This is a bit awkard; a union would be - * more correct. - */ - duk__bigint f, r, s, mp, mm, t1, t2; - - duk_small_int_t is_s2n; /* if 1, doing a string-to-number; else doing a number-to-string */ - duk_small_int_t is_fixed; /* if 1, doing a fixed format output (not free format) */ - duk_small_int_t req_digits; /* requested number of output digits; 0 = free-format */ - duk_small_int_t abs_pos; /* digit position is absolute, not relative */ - duk_small_int_t e; /* exponent for 'f' */ - duk_small_int_t b; /* input radix */ - duk_small_int_t B; /* output radix */ - duk_small_int_t k; /* see algorithm */ - duk_small_int_t low_ok; /* see algorithm */ - duk_small_int_t high_ok; /* see algorithm */ - duk_small_int_t unequal_gaps; /* m+ != m- (very rarely) */ - - /* Buffer used for generated digits, values are in the range [0,B-1]. */ - duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS]; - duk_small_int_t count; /* digit count */ -} duk__numconv_stringify_ctx; - -/* Note: computes with 'idx' in assertions, so caller beware. - * 'idx' is preincremented, i.e. '1' on first call, because it - * is more convenient for the caller. - */ -#define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x) do { \ - DUK_ASSERT((preinc_idx) - 1 >= 0); \ - DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \ - ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \ - } while (0) - -DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) { - duk_uint8_t *p; - duk_size_t len; - duk_small_int_t dig; - duk_uint32_t t; - - DUK_ASSERT(radix >= 2 && radix <= 36); - - /* A 32-bit unsigned integer formats to at most 32 digits (the - * worst case happens with radix == 2). Output the digits backwards, - * and use a memmove() to get them in the right place. - */ - - p = buf + 32; - for (;;) { - t = x / (duk_uint32_t) radix; - dig = (duk_small_int_t) (x - t * (duk_uint32_t) radix); - x = t; - - DUK_ASSERT(dig >= 0 && dig < 36); - *(--p) = DUK__DIGITCHAR(dig); - - if (x == 0) { - break; - } - } - len = (duk_size_t) ((buf + 32) - p); - - DUK_MEMMOVE((void *) buf, (const void *) p, (size_t) len); - - return len; -} - -DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) { - duk_small_int_t lowest_mantissa; - -#if 1 - /* Assume IEEE round-to-even, so that shorter encoding can be used - * when round-to-even would produce correct result. By removing - * this check (and having low_ok == high_ok == 0) the results would - * still be accurate but in some cases longer than necessary. - */ - if (duk__bi_is_even(&nc_ctx->f)) { - DUK_DDD(DUK_DDDPRINT("f is even")); - nc_ctx->low_ok = 1; - nc_ctx->high_ok = 1; - } else { - DUK_DDD(DUK_DDDPRINT("f is odd")); - nc_ctx->low_ok = 0; - nc_ctx->high_ok = 0; - } -#else - /* Note: not honoring round-to-even should work but now generates incorrect - * results. For instance, 1e23 serializes to "a000...", i.e. the first digit - * equals the radix (10). Scaling stops one step too early in this case. - * Don't know why this is the case, but since this code path is unused, it - * doesn't matter. - */ - nc_ctx->low_ok = 0; - nc_ctx->high_ok = 0; -#endif - - /* For string-to-number, pretend we never have the lowest mantissa as there - * is no natural "precision" for inputs. Having lowest_mantissa == 0, we'll - * fall into the base cases for both e >= 0 and e < 0. - */ - if (nc_ctx->is_s2n) { - lowest_mantissa = 0; - } else { - lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f); - } - - nc_ctx->unequal_gaps = 0; - if (nc_ctx->e >= 0) { - /* exponent non-negative (and thus not minimum exponent) */ - - if (lowest_mantissa) { - /* (>= e 0) AND (= f (expt b (- p 1))) - * - * be <- (expt b e) == b^e - * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1) - * r <- (* f be1 2) == 2 * f * b^(e+1) [if b==2 -> f * b^(e+2)] - * s <- (* b 2) [if b==2 -> 4] - * m+ <- be1 == b^(e+1) - * m- <- be == b^e - * k <- 0 - * B <- B - * low_ok <- round - * high_ok <- round - */ - - DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); " - "lowest mantissa value for this exponent -> " - "unequal gaps")); - - duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */ - duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, (duk_uint32_t) nc_ctx->b); /* mp <- b^(e+1) */ - duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2); - duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */ - duk__bi_set_small(&nc_ctx->s, (duk_uint32_t) (nc_ctx->b * 2)); /* s <- 2 * b */ - nc_ctx->unequal_gaps = 1; - } else { - /* (>= e 0) AND (not (= f (expt b (- p 1)))) - * - * be <- (expt b e) == b^e - * r <- (* f be 2) == 2 * f * b^e [if b==2 -> f * b^(e+1)] - * s <- 2 - * m+ <- be == b^e - * m- <- be == b^e - * k <- 0 - * B <- B - * low_ok <- round - * high_ok <- round - */ - - DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); " - "not lowest mantissa for this exponent -> " - "equal gaps")); - - duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */ - duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm); /* mp <- b^e */ - duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2); - duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^e */ - duk__bi_set_small(&nc_ctx->s, 2); /* s <- 2 */ - } - } else { - /* When doing string-to-number, lowest_mantissa is always 0 so - * the exponent check, while incorrect, won't matter. - */ - if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ && - lowest_mantissa /* lowest mantissa for this exponent*/) { - /* r <- (* f b 2) [if b==2 -> (* f 4)] - * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2 [if b==2 -> b^(2-e)] - * m+ <- b == 2 - * m- <- 1 - * k <- 0 - * B <- B - * low_ok <- round - * high_ok <- round - */ - - DUK_DDD(DUK_DDDPRINT("negative exponent; not minimum exponent and " - "lowest mantissa for this exponent -> " - "unequal gaps")); - - duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, (duk_uint32_t) (nc_ctx->b * 2)); /* r <- (2 * b) * f */ - duk__bi_exp_small(&nc_ctx->t1, nc_ctx->b, 1 - nc_ctx->e, &nc_ctx->s, &nc_ctx->t2); /* NB: use 's' as temp on purpose */ - duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */ - duk__bi_set_small(&nc_ctx->mp, 2); - duk__bi_set_small(&nc_ctx->mm, 1); - nc_ctx->unequal_gaps = 1; - } else { - /* r <- (* f 2) - * s <- (* (expt b (- e)) 2) == b^(-e) * 2 [if b==2 -> b^(1-e)] - * m+ <- 1 - * m- <- 1 - * k <- 0 - * B <- B - * low_ok <- round - * high_ok <- round - */ - - DUK_DDD(DUK_DDDPRINT("negative exponent; minimum exponent or not " - "lowest mantissa for this exponent -> " - "equal gaps")); - - duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2); /* r <- 2 * f */ - duk__bi_exp_small(&nc_ctx->t1, nc_ctx->b, -nc_ctx->e, &nc_ctx->s, &nc_ctx->t2); /* NB: use 's' as temp on purpose */ - duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(-e) * 2 */ - duk__bi_set_small(&nc_ctx->mp, 1); - duk__bi_set_small(&nc_ctx->mm, 1); - } - } -} - -DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) { - duk_small_int_t k = 0; - - /* This is essentially the 'scale' algorithm, with recursion removed. - * Note that 'k' is either correct immediately, or will move in one - * direction in the loop. There's no need to do the low/high checks - * on every round (like the Scheme algorithm does). - * - * The scheme algorithm finds 'k' and updates 's' simultaneously, - * while the logical algorithm finds 'k' with 's' having its initial - * value, after which 's' is updated separately (see the Burger-Dybvig - * paper, Section 3.1, steps 2 and 3). - * - * The case where m+ == m- (almost always) is optimized for, because - * it reduces the bigint operations considerably and almost always - * applies. The scale loop only needs to work with m+, so this works. - */ - - /* XXX: this algorithm could be optimized quite a lot by using e.g. - * a logarithm based estimator for 'k' and performing B^n multiplication - * using a lookup table or using some bit-representation based exp - * algorithm. Currently we just loop, with significant performance - * impact for very large and very small numbers. - */ - - DUK_DDD(DUK_DDDPRINT("scale: B=%ld, low_ok=%ld, high_ok=%ld", - (long) nc_ctx->B, (long) nc_ctx->low_ok, (long) nc_ctx->high_ok)); - DUK__BI_PRINT("r(init)", &nc_ctx->r); - DUK__BI_PRINT("s(init)", &nc_ctx->s); - DUK__BI_PRINT("mp(init)", &nc_ctx->mp); - DUK__BI_PRINT("mm(init)", &nc_ctx->mm); - - for (;;) { - DUK_DDD(DUK_DDDPRINT("scale loop (inc k), k=%ld", (long) k)); - DUK__BI_PRINT("r", &nc_ctx->r); - DUK__BI_PRINT("s", &nc_ctx->s); - DUK__BI_PRINT("m+", &nc_ctx->mp); - DUK__BI_PRINT("m-", &nc_ctx->mm); - - duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */ - if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) { - DUK_DDD(DUK_DDDPRINT("k is too low")); - /* r <- r - * s <- (* s B) - * m+ <- m+ - * m- <- m- - * k <- (+ k 1) - */ - - duk__bi_mul_small_copy(&nc_ctx->s, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1); - k++; - } else { - break; - } - } - - /* k > 0 -> k was too low, and cannot be too high */ - if (k > 0) { - goto skip_dec_k; - } - - for (;;) { - DUK_DDD(DUK_DDDPRINT("scale loop (dec k), k=%ld", (long) k)); - DUK__BI_PRINT("r", &nc_ctx->r); - DUK__BI_PRINT("s", &nc_ctx->s); - DUK__BI_PRINT("m+", &nc_ctx->mp); - DUK__BI_PRINT("m-", &nc_ctx->mm); - - duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */ - duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, (duk_uint32_t) nc_ctx->B); /* t2 = (* (+ r m+) B) */ - if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) { - DUK_DDD(DUK_DDDPRINT("k is too high")); - /* r <- (* r B) - * s <- s - * m+ <- (* m+ B) - * m- <- (* m- B) - * k <- (- k 1) - */ - duk__bi_mul_small_copy(&nc_ctx->r, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1); - duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1); - if (nc_ctx->unequal_gaps) { - DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too")); - duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1); - } - k--; - } else { - break; - } - } - - skip_dec_k: - - if (!nc_ctx->unequal_gaps) { - DUK_DDD(DUK_DDDPRINT("equal gaps, copy m- from m+")); - duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp); /* mm <- mp */ - } - nc_ctx->k = k; - - DUK_DDD(DUK_DDDPRINT("final k: %ld", (long) k)); - DUK__BI_PRINT("r(final)", &nc_ctx->r); - DUK__BI_PRINT("s(final)", &nc_ctx->s); - DUK__BI_PRINT("mp(final)", &nc_ctx->mp); - DUK__BI_PRINT("mm(final)", &nc_ctx->mm); -} - -DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) { - duk_small_int_t tc1, tc2; /* terminating conditions */ - duk_small_int_t d; /* current digit */ - duk_small_int_t count = 0; /* digit count */ - - /* - * Digit generation loop. - * - * Different termination conditions: - * - * 1. Free format output. Terminate when shortest accurate - * representation found. - * - * 2. Fixed format output, with specific number of digits. - * Ignore termination conditions, terminate when digits - * generated. Caller requests an extra digit and rounds. - * - * 3. Fixed format output, with a specific absolute cut-off - * position (e.g. 10 digits after decimal point). Note - * that we always generate at least one digit, even if - * the digit is below the cut-off point already. - */ - - for (;;) { - DUK_DDD(DUK_DDDPRINT("generate loop, count=%ld, k=%ld, B=%ld, low_ok=%ld, high_ok=%ld", - (long) count, (long) nc_ctx->k, (long) nc_ctx->B, - (long) nc_ctx->low_ok, (long) nc_ctx->high_ok)); - DUK__BI_PRINT("r", &nc_ctx->r); - DUK__BI_PRINT("s", &nc_ctx->s); - DUK__BI_PRINT("m+", &nc_ctx->mp); - DUK__BI_PRINT("m-", &nc_ctx->mm); - - /* (quotient-remainder (* r B) s) using a dummy subtraction loop */ - duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, (duk_uint32_t) nc_ctx->B); /* t1 <- (* r B) */ - d = 0; - for (;;) { - if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { - break; - } - duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2); /* t1 <- t1 - s */ - d++; - } - duk__bi_copy(&nc_ctx->r, &nc_ctx->t1); /* r <- (remainder (* r B) s) */ - /* d <- (quotient (* r B) s) (in range 0...B-1) */ - DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d)); - DUK__BI_PRINT("r(rem)", &nc_ctx->r); - - duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */ - duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */ - DUK__BI_PRINT("mp(upd)", &nc_ctx->mp); - DUK__BI_PRINT("mm(upd)", &nc_ctx->mm); - - /* Terminating conditions. For fixed width output, we just ignore the - * terminating conditions (and pretend that tc1 == tc2 == false). The - * the current shortcut for fixed-format output is to generate a few - * extra digits and use rounding (with carry) to finish the output. - */ - - if (nc_ctx->is_fixed == 0) { - /* free-form */ - tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1)); - - duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 <- (+ r m+) */ - tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)); - - DUK_DDD(DUK_DDDPRINT("tc1=%ld, tc2=%ld", (long) tc1, (long) tc2)); - } else { - /* fixed-format */ - tc1 = 0; - tc2 = 0; - } - - /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call - * on purpose, which is taken into account by the macro. - */ - count++; - - if (tc1) { - if (tc2) { - /* tc1 = true, tc2 = true */ - duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2); - if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { /* (< (* r 2) s) */ - DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %ld (k=%ld)", - (long) d, (long) nc_ctx->k)); - DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d); - } else { - DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %ld (k=%ld)", - (long) (d + 1), (long) nc_ctx->k)); - DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1); - } - break; - } else { - /* tc1 = true, tc2 = false */ - DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=false: output d --> %ld (k=%ld)", - (long) d, (long) nc_ctx->k)); - DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d); - break; - } - } else { - if (tc2) { - /* tc1 = false, tc2 = true */ - DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %ld (k=%ld)", - (long) (d + 1), (long) nc_ctx->k)); - DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1); - break; - } else { - /* tc1 = false, tc2 = false */ - DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=false: output d --> %ld (k=%ld)", - (long) d, (long) nc_ctx->k)); - DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d); - - /* r <- r (updated above: r <- (remainder (* r B) s) - * s <- s - * m+ <- m+ (updated above: m+ <- (* m+ B) - * m- <- m- (updated above: m- <- (* m- B) - * B, low_ok, high_ok are fixed - */ - - /* fall through and continue for-loop */ - } - } - - /* fixed-format termination conditions */ - if (nc_ctx->is_fixed) { - if (nc_ctx->abs_pos) { - int pos = nc_ctx->k - count + 1; /* count is already incremented, take into account */ - DUK_DDD(DUK_DDDPRINT("fixed format, absolute: abs pos=%ld, k=%ld, count=%ld, req=%ld", - (long) pos, (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits)); - if (pos <= nc_ctx->req_digits) { - DUK_DDD(DUK_DDDPRINT("digit position reached req_digits, end generate loop")); - break; - } - } else { - DUK_DDD(DUK_DDDPRINT("fixed format, relative: k=%ld, count=%ld, req=%ld", - (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits)); - if (count >= nc_ctx->req_digits) { - DUK_DDD(DUK_DDDPRINT("digit count reached req_digits, end generate loop")); - break; - } - } - } - } /* for */ - - nc_ctx->count = count; - - DUK_DDD(DUK_DDDPRINT("generate finished")); - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - { - duk_uint8_t buf[2048]; - duk_small_int_t i, t; - DUK_MEMZERO(buf, sizeof(buf)); - for (i = 0; i < nc_ctx->count; i++) { - t = nc_ctx->digits[i]; - if (t < 0 || t > 36) { - buf[i] = (duk_uint8_t) '?'; - } else { - buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t); - } - } - DUK_DDD(DUK_DDDPRINT("-> generated digits; k=%ld, digits='%s'", - (long) nc_ctx->k, (const char *) buf)); - } -#endif -} - -/* Round up digits to a given position. If position is out-of-bounds, - * does nothing. If carry propagates over the first digit, a '1' is - * prepended to digits and 'k' will be updated. Return value indicates - * whether carry propagated over the first digit. - * - * Note that nc_ctx->count is NOT updated based on the rounding position - * (it is updated only if carry overflows over the first digit and an - * extra digit is prepended). - */ -DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) { - duk_small_int_t t; - duk_uint8_t *p; - duk_uint8_t roundup_limit; - duk_small_int_t ret = 0; - - /* - * round_idx points to the digit which is considered for rounding; the - * digit to its left is the final digit of the rounded value. If round_idx - * is zero, rounding will be performed; the result will either be an empty - * rounded value or if carry happens a '1' digit is generated. - */ - - if (round_idx >= nc_ctx->count) { - DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld >= %ld (count)) -> no rounding", - (long) round_idx, (long) nc_ctx->count)); - return 0; - } else if (round_idx < 0) { - DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld < 0) -> no rounding", - (long) round_idx)); - return 0; - } - - /* - * Round-up limit. - * - * For even values, divides evenly, e.g. 10 -> roundup_limit=5. - * - * For odd values, rounds up, e.g. 3 -> roundup_limit=2. - * If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up. - */ - roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2); - - p = &nc_ctx->digits[round_idx]; - if (*p >= roundup_limit) { - DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry required")); - /* carry */ - for (;;) { - *p = 0; - if (p == &nc_ctx->digits[0]) { - DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling")); - DUK_MEMMOVE((void *) (&nc_ctx->digits[1]), - (const void *) (&nc_ctx->digits[0]), - (size_t) (sizeof(char) * (size_t) nc_ctx->count)); - nc_ctx->digits[0] = 1; /* don't increase 'count' */ - nc_ctx->k++; /* position of highest digit changed */ - nc_ctx->count++; /* number of digits changed */ - ret = 1; - break; - } - - DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry: B=%ld, roundup_limit=%ld, p=%p, digits=%p", - (long) nc_ctx->B, (long) roundup_limit, (void *) p, (void *) nc_ctx->digits)); - p--; - t = *p; - DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t)); - if (++t < nc_ctx->B) { - DUK_DDD(DUK_DDDPRINT("rounding carry terminated")); - *p = (duk_uint8_t) t; - break; - } - - DUK_DDD(DUK_DDDPRINT("wraps, carry to next digit")); - } - } - - return ret; -} - -#define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */ - -DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx, - duk_hthread *thr, - duk_small_int_t radix, - duk_small_int_t digits, - duk_small_uint_t flags, - duk_small_int_t neg) { - duk_small_int_t k; - duk_small_int_t pos, pos_end; - duk_small_int_t expt; - duk_small_int_t dig; - duk_uint8_t *q; - duk_uint8_t *buf; - - /* - * The string conversion here incorporates all the necessary Ecmascript - * semantics without attempting to be generic. nc_ctx->digits contains - * nc_ctx->count digits (>= 1), with the topmost digit's 'position' - * indicated by nc_ctx->k as follows: - * - * digits="123" count=3 k=0 --> 0.123 - * digits="123" count=3 k=1 --> 1.23 - * digits="123" count=3 k=5 --> 12300 - * digits="123" count=3 k=-1 --> 0.0123 - * - * Note that the identifier names used for format selection are different - * in Burger-Dybvig paper and Ecmascript specification (quite confusingly - * so, because e.g. 'k' has a totally different meaning in each). See - * documentation for discussion. - * - * Ecmascript doesn't specify any specific behavior for format selection - * (e.g. when to use exponent notation) for non-base-10 numbers. - * - * The bigint space in the context is reused for string output, as there - * is more than enough space for that (>1kB at the moment), and we avoid - * allocating even more stack. - */ - - DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH); - DUK_ASSERT(nc_ctx->count >= 1); - - k = nc_ctx->k; - buf = (duk_uint8_t *) &nc_ctx->f; /* XXX: union would be more correct */ - q = buf; - - /* Exponent handling: if exponent format is used, record exponent value and - * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23"). - * - * toFixed() prevents exponent use; otherwise apply a set of criteria to - * match the other API calls (toString(), toPrecision, etc). - */ - - expt = DUK__NO_EXP; - if (!nc_ctx->abs_pos /* toFixed() */) { - if ((flags & DUK_N2S_FLAG_FORCE_EXP) || /* exponential notation forced */ - ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) && /* fixed precision and zero padding would be required */ - (k - digits >= 1)) || /* (e.g. k=3, digits=2 -> "12X") */ - ((k > 21 || k <= -6) && (radix == 10))) { /* toString() conditions */ - DUK_DDD(DUK_DDDPRINT("use exponential notation: k=%ld -> expt=%ld", - (long) k, (long) (k - 1))); - expt = k - 1; /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */ - k = 1; /* generate mantissa with a single leading whole number digit */ - } - } - - if (neg) { - *q++ = '-'; - } - - /* Start position (inclusive) and end position (exclusive) */ - pos = (k >= 1 ? k : 1); - if (nc_ctx->is_fixed) { - if (nc_ctx->abs_pos) { - /* toFixed() */ - pos_end = -digits; - } else { - pos_end = k - digits; - } - } else { - pos_end = k - nc_ctx->count; - } - if (pos_end > 0) { - pos_end = 0; - } - - DUK_DDD(DUK_DDDPRINT("expt=%ld, k=%ld, count=%ld, pos=%ld, pos_end=%ld, is_fixed=%ld, " - "digits=%ld, abs_pos=%ld", - (long) expt, (long) k, (long) nc_ctx->count, (long) pos, (long) pos_end, - (long) nc_ctx->is_fixed, (long) digits, (long) nc_ctx->abs_pos)); - - /* Digit generation */ - while (pos > pos_end) { - DUK_DDD(DUK_DDDPRINT("digit generation: pos=%ld, pos_end=%ld", - (long) pos, (long) pos_end)); - if (pos == 0) { - *q++ = (duk_uint8_t) '.'; - } - if (pos > k) { - *q++ = (duk_uint8_t) '0'; - } else if (pos <= k - nc_ctx->count) { - *q++ = (duk_uint8_t) '0'; - } else { - dig = nc_ctx->digits[k - pos]; - DUK_ASSERT(dig >= 0 && dig < nc_ctx->B); - *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig); - } - - pos--; - } - DUK_ASSERT(pos <= 1); - - /* Exponent */ - if (expt != DUK__NO_EXP) { - /* - * Exponent notation for non-base-10 numbers isn't specified in Ecmascript - * specification, as it never explicitly turns up: non-decimal numbers can - * only be formatted with Number.prototype.toString([radix]) and for that, - * behavior is not explicitly specified. - * - * Logical choices include formatting the exponent as decimal (e.g. binary - * 100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101). - * The Dragon4 algorithm (in the original paper) prints the exponent value - * in the target radix B. However, for radix values 15 and above, the - * exponent separator 'e' is no longer easily parseable. Consider, for - * instance, the number "1.faecee+1c". - */ - - duk_size_t len; - char expt_sign; - - *q++ = 'e'; - if (expt >= 0) { - expt_sign = '+'; - } else { - expt_sign = '-'; - expt = -expt; - } - *q++ = (duk_uint8_t) expt_sign; - len = duk__dragon4_format_uint32(q, (duk_uint32_t) expt, radix); - q += len; - } - - duk_push_lstring(thr, (const char *) buf, (size_t) (q - buf)); -} - -/* - * Conversion helpers - */ - -DUK_LOCAL void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) { - duk_double_union u; - duk_uint32_t tmp; - duk_small_int_t expt; - - /* - * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff - * A B C D E F G H - * - * s sign bit - * eee... exponent field - * fff... fraction - * - * ieee value = 1.ffff... * 2^(e - 1023) (normal) - * = 0.ffff... * 2^(-1022) (denormal) - * - * algorithm v = f * b^e - */ - - DUK_DBLUNION_SET_DOUBLE(&u, x); - - nc_ctx->f.n = 2; - - tmp = DUK_DBLUNION_GET_LOW32(&u); - nc_ctx->f.v[0] = tmp; - tmp = DUK_DBLUNION_GET_HIGH32(&u); - nc_ctx->f.v[1] = tmp & 0x000fffffUL; - expt = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL); - - if (expt == 0) { - /* denormal */ - expt = DUK__IEEE_DOUBLE_EXP_MIN - 52; - duk__bi_normalize(&nc_ctx->f); - } else { - /* normal: implicit leading 1-bit */ - nc_ctx->f.v[1] |= 0x00100000UL; - expt = expt - DUK__IEEE_DOUBLE_EXP_BIAS - 52; - DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); /* true, because v[1] has at least one bit set */ - } - - DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); - - nc_ctx->e = expt; -} - -DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) { - duk_double_union u; - duk_small_int_t expt; - duk_small_int_t i; - duk_small_int_t bitstart; - duk_small_int_t bitround; - duk_small_int_t bitidx; - duk_small_int_t skip_round; - duk_uint32_t t, v; - - DUK_ASSERT(nc_ctx->count == 53 + 1); - - /* Sometimes this assert is not true right now; it will be true after - * rounding. See: test-bug-numconv-mantissa-assert.js. - */ - DUK_ASSERT_DISABLE(nc_ctx->digits[0] == 1); /* zero handled by caller */ - - /* Should not be required because the code below always sets both high - * and low parts, but at least gcc-4.4.5 fails to deduce this correctly - * (perhaps because the low part is set (seemingly) conditionally in a - * loop), so this is here to avoid the bogus warning. - */ - DUK_MEMZERO((void *) &u, sizeof(u)); - - /* - * Figure out how generated digits match up with the mantissa, - * and then perform rounding. If mantissa overflows, need to - * recompute the exponent (it is bumped and may overflow to - * infinity). - * - * For normal numbers the leading '1' is hidden and ignored, - * and the last bit is used for rounding: - * - * rounding pt - * <--------52------->| - * 1 x x x x ... x x x x|y ==> x x x x ... x x x x - * - * For denormals, the leading '1' is included in the number, - * and the rounding point is different: - * - * rounding pt - * <--52 or less--->| - * 1 x x x x ... x x|x x y ==> 0 0 ... 1 x x ... x x - * - * The largest denormals will have a mantissa beginning with - * a '1' (the explicit leading bit); smaller denormals will - * have leading zero bits. - * - * If the exponent would become too high, the result becomes - * Infinity. If the exponent is so small that the entire - * mantissa becomes zero, the result becomes zero. - * - * Note: the Dragon4 'k' is off-by-one with respect to the IEEE - * exponent. For instance, k==0 indicates that the leading '1' - * digit is at the first binary fraction position (0.1xxx...); - * the corresponding IEEE exponent would be -1. - */ - - skip_round = 0; - - recheck_exp: - - expt = nc_ctx->k - 1; /* IEEE exp without bias */ - if (expt > 1023) { - /* Infinity */ - bitstart = -255; /* needed for inf: causes mantissa to become zero, - * and rounding to be skipped. - */ - expt = 2047; - } else if (expt >= -1022) { - /* normal */ - bitstart = 1; /* skip leading digit */ - expt += DUK__IEEE_DOUBLE_EXP_BIAS; - DUK_ASSERT(expt >= 1 && expt <= 2046); - } else { - /* denormal or zero */ - bitstart = 1023 + expt; /* expt==-1023 -> bitstart=0 (leading 1); - * expt==-1024 -> bitstart=-1 (one left of leading 1), etc - */ - expt = 0; - } - bitround = bitstart + 52; - - DUK_DDD(DUK_DDDPRINT("ieee expt=%ld, bitstart=%ld, bitround=%ld", - (long) expt, (long) bitstart, (long) bitround)); - - if (!skip_round) { - if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) { - /* Corner case: see test-numconv-parse-mant-carry.js. We could - * just bump the exponent and update bitstart, but it's more robust - * to recompute (but avoid rounding twice). - */ - DUK_DDD(DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent")); - skip_round = 1; - goto recheck_exp; - } - } - - /* - * Create mantissa - */ - - t = 0; - for (i = 0; i < 52; i++) { - bitidx = bitstart + 52 - 1 - i; - if (bitidx >= nc_ctx->count) { - v = 0; - } else if (bitidx < 0) { - v = 0; - } else { - v = nc_ctx->digits[bitidx]; - } - DUK_ASSERT(v == 0 || v == 1); - t += v << (i % 32); - if (i == 31) { - /* low 32 bits is complete */ - DUK_DBLUNION_SET_LOW32(&u, t); - t = 0; - } - } - /* t has high mantissa */ - - DUK_DDD(DUK_DDDPRINT("mantissa is complete: %08lx %08lx", - (unsigned long) t, - (unsigned long) DUK_DBLUNION_GET_LOW32(&u))); - - DUK_ASSERT(expt >= 0 && expt <= 0x7ffL); - t += ((duk_uint32_t) expt) << 20; -#if 0 /* caller handles sign change */ - if (negative) { - t |= 0x80000000U; - } -#endif - DUK_DBLUNION_SET_HIGH32(&u, t); - - DUK_DDD(DUK_DDDPRINT("number is complete: %08lx %08lx", - (unsigned long) DUK_DBLUNION_GET_HIGH32(&u), - (unsigned long) DUK_DBLUNION_GET_LOW32(&u))); - - *x = DUK_DBLUNION_GET_DOUBLE(&u); -} - -/* - * Exposed number-to-string API - * - * Input: [ number ] - * Output: [ string ] - */ - -DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) { - duk_double_t x; - duk_small_int_t c; - duk_small_int_t neg; - duk_uint32_t uval; - duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */ - duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc; - - x = (duk_double_t) duk_require_number(thr, -1); - duk_pop(thr); - - /* - * Handle special cases (NaN, infinity, zero). - */ - - c = (duk_small_int_t) DUK_FPCLASSIFY(x); - if (DUK_SIGNBIT((double) x)) { - x = -x; - neg = 1; - } else { - neg = 0; - } - - /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */ - DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0); - - if (c == DUK_FP_NAN) { - duk_push_hstring_stridx(thr, DUK_STRIDX_NAN); - return; - } else if (c == DUK_FP_INFINITE) { - if (neg) { - /* -Infinity */ - duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_INFINITY); - } else { - /* Infinity */ - duk_push_hstring_stridx(thr, DUK_STRIDX_INFINITY); - } - return; - } else if (c == DUK_FP_ZERO) { - /* We can't shortcut zero here if it goes through special formatting - * (such as forced exponential notation). - */ - ; - } - - /* - * Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1]) - * specially, as they're very likely for embedded programs. This - * is now done for all radix values. We must be careful not to use - * the fast path when special formatting (e.g. forced exponential) - * is in force. - * - * XXX: could save space by supporting radix 10 only and using - * sprintf "%lu" for the fast path and for exponent formatting. - */ - - uval = (unsigned int) x; - if (((double) uval) == x && /* integer number in range */ - flags == 0) { /* no special formatting */ - /* use bigint area as a temp */ - duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f); - duk_uint8_t *p = buf; - - DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1); /* max size: radix=2 + sign */ - if (neg && uval != 0) { - /* no negative sign for zero */ - *p++ = (duk_uint8_t) '-'; - } - p += duk__dragon4_format_uint32(p, uval, radix); - duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf)); - return; - } - - /* - * Dragon4 setup. - * - * Convert double from IEEE representation for conversion; - * normal finite values have an implicit leading 1-bit. The - * slow path algorithm doesn't handle zero, so zero is special - * cased here but still creates a valid nc_ctx, and goes - * through normal formatting in case special formatting has - * been requested (e.g. forced exponential format: 0 -> "0e+0"). - */ - - /* Would be nice to bulk clear the allocation, but the context - * is 1-2 kilobytes and nothing should rely on it being zeroed. - */ -#if 0 - DUK_MEMZERO((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */ -#endif - - nc_ctx->is_s2n = 0; - nc_ctx->b = 2; - nc_ctx->B = radix; - nc_ctx->abs_pos = 0; - if (flags & DUK_N2S_FLAG_FIXED_FORMAT) { - nc_ctx->is_fixed = 1; - if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) { - /* absolute req_digits; e.g. digits = 1 -> last digit is 0, - * but add an extra digit for rounding. - */ - nc_ctx->abs_pos = 1; - nc_ctx->req_digits = (-digits + 1) - 1; - } else { - nc_ctx->req_digits = digits + 1; - } - } else { - nc_ctx->is_fixed = 0; - nc_ctx->req_digits = 0; - } - - if (c == DUK_FP_ZERO) { - /* Zero special case: fake requested number of zero digits; ensure - * no sign bit is printed. Relative and absolute fixed format - * require separate handling. - */ - duk_small_int_t count; - if (nc_ctx->is_fixed) { - if (nc_ctx->abs_pos) { - count = digits + 2; /* lead zero + 'digits' fractions + 1 for rounding */ - } else { - count = digits + 1; /* + 1 for rounding */ - } - } else { - count = 1; - } - DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count)); - DUK_ASSERT(count >= 1); - DUK_MEMZERO((void *) nc_ctx->digits, (size_t) count); - nc_ctx->count = count; - nc_ctx->k = 1; /* 0.000... */ - neg = 0; - goto zero_skip; - } - - duk__dragon4_double_to_ctx(nc_ctx, x); /* -> sets 'f' and 'e' */ - DUK__BI_PRINT("f", &nc_ctx->f); - DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e)); - - /* - * Dragon4 slow path digit generation. - */ - - duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */ - - DUK_DDD(DUK_DDDPRINT("after prepare:")); - DUK__BI_PRINT("r", &nc_ctx->r); - DUK__BI_PRINT("s", &nc_ctx->s); - DUK__BI_PRINT("mp", &nc_ctx->mp); - DUK__BI_PRINT("mm", &nc_ctx->mm); - - duk__dragon4_scale(nc_ctx); - - DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k)); - DUK__BI_PRINT("r", &nc_ctx->r); - DUK__BI_PRINT("s", &nc_ctx->s); - DUK__BI_PRINT("mp", &nc_ctx->mp); - DUK__BI_PRINT("mm", &nc_ctx->mm); - - duk__dragon4_generate(nc_ctx); - - /* - * Convert and push final string. - */ - - zero_skip: - - if (flags & DUK_N2S_FLAG_FIXED_FORMAT) { - /* Perform fixed-format rounding. */ - duk_small_int_t roundpos; - if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) { - /* 'roundpos' is relative to nc_ctx->k and increases to the right - * (opposite of how 'k' changes). - */ - roundpos = -digits; /* absolute position for digit considered for rounding */ - roundpos = nc_ctx->k - roundpos; - } else { - roundpos = digits; - } - DUK_DDD(DUK_DDDPRINT("rounding: k=%ld, count=%ld, digits=%ld, roundpos=%ld", - (long) nc_ctx->k, (long) nc_ctx->count, (long) digits, (long) roundpos)); - (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos); - - /* Note: 'count' is currently not adjusted by rounding (i.e. the - * digits are not "chopped off". That shouldn't matter because - * the digit position (absolute or relative) is passed on to the - * convert-and-push function. - */ - } - - duk__dragon4_convert_and_push(nc_ctx, thr, radix, digits, flags, neg); -} - -/* - * Exposed string-to-number API - * - * Input: [ string ] - * Output: [ number ] - * - * If number parsing fails, a NaN is pushed as the result. If number parsing - * fails due to an internal error, an InternalError is thrown. - */ - -DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags) { - duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */ - duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc; - duk_double_t res; - duk_hstring *h_str; - duk_small_int_t expt; - duk_small_int_t expt_neg; - duk_small_int_t expt_adj; - duk_small_int_t neg; - duk_small_int_t dig; - duk_small_int_t dig_whole; - duk_small_int_t dig_lzero; - duk_small_int_t dig_frac; - duk_small_int_t dig_expt; - duk_small_int_t dig_prec; - const duk__exp_limits *explim; - const duk_uint8_t *p; - duk_small_int_t ch; - - DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx", - (duk_tval *) duk_get_tval(thr, -1), - (long) radix, (unsigned long) flags)); - - DUK_ASSERT(radix >= 2 && radix <= 36); - DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix)); - - /* - * Preliminaries: trim, sign, Infinity check - * - * We rely on the interned string having a NUL terminator, which will - * cause a parse failure wherever it is encountered. As a result, we - * don't need separate pointer checks. - * - * There is no special parsing for 'NaN' in the specification although - * 'Infinity' (with an optional sign) is allowed in some contexts. - * Some contexts allow plus/minus sign, while others only allow the - * minus sign (like JSON.parse()). - * - * Automatic hex number detection (leading '0x' or '0X') and octal - * number detection (leading '0' followed by at least one octal digit) - * is done here too. - * - * Symbols are not explicitly rejected here (that's up to the caller). - * If a symbol were passed here, it should ultimately safely fail - * parsing due to a syntax error. - */ - - if (flags & DUK_S2N_FLAG_TRIM_WHITE) { - /* Leading / trailing whitespace is sometimes accepted and - * sometimes not. After white space trimming, all valid input - * characters are pure ASCII. - */ - duk_trim(thr, -1); - } - h_str = duk_require_hstring(thr, -1); - DUK_ASSERT(h_str != NULL); - p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str); - - neg = 0; - ch = *p; - if (ch == (duk_small_int_t) '+') { - if ((flags & DUK_S2N_FLAG_ALLOW_PLUS) == 0) { - DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed")); - goto parse_fail; - } - p++; - } else if (ch == (duk_small_int_t) '-') { - if ((flags & DUK_S2N_FLAG_ALLOW_MINUS) == 0) { - DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed")); - goto parse_fail; - } - p++; - neg = 1; - } - - if ((flags & DUK_S2N_FLAG_ALLOW_INF) && DUK_STRNCMP((const char *) p, "Infinity", 8) == 0) { - /* Don't check for Infinity unless the context allows it. - * 'Infinity' is a valid integer literal in e.g. base-36: - * - * parseInt('Infinity', 36) - * 1461559270678 - */ - - if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0 && p[8] != DUK_ASC_NUL) { - DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed")); - goto parse_fail; - } else { - res = DUK_DOUBLE_INFINITY; - goto negcheck_and_ret; - } - } - ch = *p; - if (ch == (duk_small_int_t) '0') { - duk_small_int_t detect_radix = 0; - ch = DUK_LOWERCASE_CHAR_ASCII(p[1]); /* 'x' or 'X' -> 'x' */ - if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT) && ch == DUK_ASC_LC_X) { - DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent")); - detect_radix = 16; -#if 0 - } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT) && - (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) { - DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent")); - detect_radix = 8; - - /* NOTE: if this legacy octal case is added back, it has - * different flags and 'p' advance so this needs to be - * reworked. - */ - flags |= DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO; /* interpret e.g. '09' as '0', not NaN */ - p += 1; -#endif - } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) && ch == DUK_ASC_LC_O) { - DUK_DDD(DUK_DDDPRINT("detected 0o oct prefix, changing radix and preventing fractions and exponent")); - detect_radix = 8; - } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT) && ch == DUK_ASC_LC_B) { - DUK_DDD(DUK_DDDPRINT("detected 0b bin prefix, changing radix and preventing fractions and exponent")); - detect_radix = 2; - } - if (detect_radix > 0) { - radix = detect_radix; - /* Clear empty as zero flag: interpret e.g. '0x' and '0xg' as a NaN (= parse error) */ - flags &= ~(DUK_S2N_FLAG_ALLOW_EXP | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | - DUK_S2N_FLAG_ALLOW_FRAC | DUK_S2N_FLAG_ALLOW_NAKED_FRAC | - DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO); - flags |= DUK_S2N_FLAG_ALLOW_LEADING_ZERO; /* allow e.g. '0x0009' and '0b00010001' */ - p += 2; - } - } - - /* - * Scan number and setup for Dragon4. - * - * The fast path case is detected during setup: an integer which - * can be converted without rounding, no net exponent. The fast - * path could be implemented as a separate scan, but may not really - * be worth it: the multiplications for building 'f' are not - * expensive when 'f' is small. - * - * The significand ('f') must contain enough bits of (apparent) - * accuracy, so that Dragon4 will generate enough binary output digits. - * For decimal numbers, this means generating a 20-digit significand, - * which should yield enough practical accuracy to parse IEEE doubles. - * In fact, the Ecmascript specification explicitly allows an - * implementation to treat digits beyond 20 as zeroes (and even - * to round the 20th digit upwards). For non-decimal numbers, the - * appropriate number of digits has been precomputed for comparable - * accuracy. - * - * Digit counts: - * - * [ dig_lzero ] - * | - * .+-..---[ dig_prec ]----. - * | || | - * 0000123.456789012345678901234567890e+123456 - * | | | | | | - * `--+--' `------[ dig_frac ]-------' `-+--' - * | | - * [ dig_whole ] [ dig_expt ] - * - * dig_frac and dig_expt are -1 if not present - * dig_lzero is only computed for whole number part - * - * Parsing state - * - * Parsing whole part dig_frac < 0 AND dig_expt < 0 - * Parsing fraction part dig_frac >= 0 AND dig_expt < 0 - * Parsing exponent part dig_expt >= 0 (dig_frac may be < 0 or >= 0) - * - * Note: in case we hit an implementation limit (like exponent range), - * we should throw an error, NOT return NaN or Infinity. Even with - * very large exponent (or significand) values the final result may be - * finite, so NaN/Infinity would be incorrect. - */ - - duk__bi_set_small(&nc_ctx->f, 0); - dig_prec = 0; - dig_lzero = 0; - dig_whole = 0; - dig_frac = -1; - dig_expt = -1; - expt = 0; - expt_adj = 0; /* essentially tracks digit position of lowest 'f' digit */ - expt_neg = 0; - for (;;) { - ch = *p++; - - DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, " - "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld", - (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch, - (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac, - (long) dig_expt, (long) dig_lzero, (long) dig_prec)); - DUK__BI_PRINT("f", &nc_ctx->f); - - /* Most common cases first. */ - if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') { - dig = (duk_small_int_t) ch - '0' + 0; - } else if (ch == (duk_small_int_t) '.') { - /* A leading digit is not required in some cases, e.g. accept ".123". - * In other cases (JSON.parse()) a leading digit is required. This - * is checked for after the loop. - */ - if (dig_frac >= 0 || dig_expt >= 0) { - if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) { - DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)")); - break; - } else { - DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed")); - goto parse_fail; - } - } - - if ((flags & DUK_S2N_FLAG_ALLOW_FRAC) == 0) { - /* Some contexts don't allow fractions at all; this can't be a - * post-check because the state ('f' and expt) would be incorrect. - */ - if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) { - DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)")); - break; - } else { - DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed")); - } - } - - DUK_DDD(DUK_DDDPRINT("start fraction part")); - dig_frac = 0; - continue; - } else if (ch == (duk_small_int_t) 0) { - DUK_DDD(DUK_DDDPRINT("NUL termination")); - break; - } else if ((flags & DUK_S2N_FLAG_ALLOW_EXP) && - dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) { - /* Note: we don't parse back exponent notation for anything else - * than radix 10, so this is not an ambiguous check (e.g. hex - * exponent values may have 'e' either as a significand digit - * or as an exponent separator). - * - * If the exponent separator occurs twice, 'e' will be interpreted - * as a digit (= 14) and will be rejected as an invalid decimal - * digit. - */ - - DUK_DDD(DUK_DDDPRINT("start exponent part")); - - /* Exponent without a sign or with a +/- sign is accepted - * by all call sites (even JSON.parse()). - */ - ch = *p; - if (ch == (duk_small_int_t) '-') { - expt_neg = 1; - p++; - } else if (ch == (duk_small_int_t) '+') { - p++; - } - dig_expt = 0; - continue; - } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') { - dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a); - } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') { - dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a); - } else { - dig = 255; /* triggers garbage digit check below */ - } - DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255); - - if (dig >= radix) { - if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) { - DUK_DDD(DUK_DDDPRINT("garbage termination")); - break; - } else { - DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit")); - goto parse_fail; - } - } - - if (dig_expt < 0) { - /* whole or fraction digit */ - - if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) { - /* significant from precision perspective */ - - duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f); - if (f_zero && dig == 0) { - /* Leading zero is not counted towards precision digits; not - * in the integer part, nor in the fraction part. - */ - if (dig_frac < 0) { - dig_lzero++; - } - } else { - /* XXX: join these ops (multiply-accumulate), but only if - * code footprint decreases. - */ - duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, (duk_uint32_t) radix); - duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, (duk_uint32_t) dig); - dig_prec++; - } - } else { - /* Ignore digits beyond a radix-specific limit, but note them - * in expt_adj. - */ - expt_adj++; - } - - if (dig_frac >= 0) { - dig_frac++; - expt_adj--; - } else { - dig_whole++; - } - } else { - /* exponent digit */ - - expt = expt * radix + dig; - if (expt > DUK_S2N_MAX_EXPONENT) { - /* impose a reasonable exponent limit, so that exp - * doesn't need to get tracked using a bigint. - */ - DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large")); - goto parse_explimit_error; - } - dig_expt++; - } - } - - /* Leading zero. */ - - if (dig_lzero > 0 && dig_whole > 1) { - if ((flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO) == 0) { - DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part")); - goto parse_fail; - } - } - - /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */ - - if (dig_whole == 0) { - if (dig_frac == 0) { - /* "." is not accepted in any format */ - DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits")); - goto parse_fail; - } else if (dig_frac > 0) { - /* ".123" */ - if ((flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC) == 0) { - DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without " - "leading integer digit(s)")); - goto parse_fail; - } - } else { - /* empty ("") is allowed in some formats (e.g. Number(''), as zero */ - if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO) == 0) { - DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)")); - goto parse_fail; - } - } - } else { - if (dig_frac == 0) { - /* "123." is allowed in some formats */ - if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC) == 0) { - DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions")); - goto parse_fail; - } - } else if (dig_frac > 0) { - /* "123.456" */ - ; - } else { - /* "123" */ - ; - } - } - - /* Exponent without digits (e.g. "1e" or "1e+"). If trailing garbage is - * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0). - */ - - if (dig_expt == 0) { - if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0) { - DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent")); - goto parse_fail; - } - DUK_ASSERT(expt == 0); - } - - if (expt_neg) { - expt = -expt; - } - DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld", - (long) expt, (long) expt_adj, (long) (expt + expt_adj))); - expt += expt_adj; - - /* Fast path check. */ - - if (nc_ctx->f.n <= 1 && /* 32-bit value */ - expt == 0 /* no net exponent */) { - /* Fast path is triggered for no exponent and also for balanced exponent - * and fraction parts, e.g. for "1.23e2" == "123". Remember to respect - * zero sign. - */ - - /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */ - DUK_DDD(DUK_DDDPRINT("fast path number parse")); - if (nc_ctx->f.n == 1) { - res = (double) nc_ctx->f.v[0]; - } else { - res = 0.0; - } - goto negcheck_and_ret; - } - - /* Significand ('f') padding. */ - - while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) { - /* Pad significand with "virtual" zero digits so that Dragon4 will - * have enough (apparent) precision to work with. - */ - DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec)); - duk__bi_mul_small_copy(&nc_ctx->f, (duk_uint32_t) radix, &nc_ctx->t1); - DUK__BI_PRINT("f", &nc_ctx->f); - expt--; - dig_prec++; - } - - DUK_DDD(DUK_DDDPRINT("final exponent: %ld", (long) expt)); - - /* Detect zero special case. */ - - if (nc_ctx->f.n == 0) { - /* This may happen even after the fast path check, if exponent is - * not balanced (e.g. "0e1"). Remember to respect zero sign. - */ - DUK_DDD(DUK_DDDPRINT("significand is zero")); - res = 0.0; - goto negcheck_and_ret; - } - - - /* Quick reject of too large or too small exponents. This check - * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity) - * so zero check must be above. - */ - - explim = &duk__str2num_exp_limits[radix - 2]; - if (expt > explim->upper) { - DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite")); - res = (duk_double_t) DUK_DOUBLE_INFINITY; - goto negcheck_and_ret; - } else if (expt < explim->lower) { - DUK_DDD(DUK_DDDPRINT("exponent too small -> zero")); - res = (duk_double_t) 0.0; - goto negcheck_and_ret; - } - - nc_ctx->is_s2n = 1; - nc_ctx->e = expt; - nc_ctx->b = radix; - nc_ctx->B = 2; - nc_ctx->is_fixed = 1; - nc_ctx->abs_pos = 0; - nc_ctx->req_digits = 53 + 1; - - DUK__BI_PRINT("f", &nc_ctx->f); - DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e)); - - /* - * Dragon4 slow path (binary) digit generation. - * An extra digit is generated for rounding. - */ - - duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */ - - DUK_DDD(DUK_DDDPRINT("after prepare:")); - DUK__BI_PRINT("r", &nc_ctx->r); - DUK__BI_PRINT("s", &nc_ctx->s); - DUK__BI_PRINT("mp", &nc_ctx->mp); - DUK__BI_PRINT("mm", &nc_ctx->mm); - - duk__dragon4_scale(nc_ctx); - - DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k)); - DUK__BI_PRINT("r", &nc_ctx->r); - DUK__BI_PRINT("s", &nc_ctx->s); - DUK__BI_PRINT("mp", &nc_ctx->mp); - DUK__BI_PRINT("mm", &nc_ctx->mm); - - duk__dragon4_generate(nc_ctx); - - DUK_ASSERT(nc_ctx->count == 53 + 1); - - /* - * Convert binary digits into an IEEE double. Need to handle - * denormals and rounding correctly. - * - * Some call sites currently assume the result is always a - * non-fastint double. If this is changed, check all call - * sites. - */ - - duk__dragon4_ctx_to_double(nc_ctx, &res); - goto negcheck_and_ret; - - negcheck_and_ret: - if (neg) { - res = -res; - } - duk_pop(thr); - duk_push_number(thr, (double) res); - DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(thr, -1))); - return; - - parse_fail: - DUK_DDD(DUK_DDDPRINT("parse failed")); - duk_pop(thr); - duk_push_nan(thr); - return; - - parse_explimit_error: - DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value")); - DUK_ERROR_RANGE(thr, "exponent too large"); - return; -} - -/* automatic undefs */ -#undef DUK__BI_MAX_PARTS -#undef DUK__BI_PRINT -#undef DUK__DIGITCHAR -#undef DUK__DRAGON4_OUTPUT_PREINC -#undef DUK__IEEE_DOUBLE_EXP_BIAS -#undef DUK__IEEE_DOUBLE_EXP_MIN -#undef DUK__MAX_FORMATTED_LENGTH -#undef DUK__MAX_OUTPUT_DIGITS -#undef DUK__NO_EXP -#undef DUK__NUMCONV_CTX_BIGINTS_SIZE -#undef DUK__NUMCONV_CTX_NUM_BIGINTS -#line 1 "duk_regexp_compiler.c" -/* - * Regexp compilation. - * - * See doc/regexp.rst for a discussion of the compilation approach and - * current limitations. - * - * Regexp bytecode assumes jumps can be expressed with signed 32-bit - * integers. Consequently the bytecode size must not exceed 0x7fffffffL. - * The implementation casts duk_size_t (buffer size) to duk_(u)int32_t - * in many places. Although this could be changed, the bytecode format - * limit would still prevent regexps exceeding the signed 32-bit limit - * from working. - * - * XXX: The implementation does not prevent bytecode from exceeding the - * maximum supported size. This could be done by limiting the maximum - * input string size (assuming an upper bound can be computed for number - * of bytecode bytes emitted per input byte) or checking buffer maximum - * size when emitting bytecode (slower). - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_REGEXP_SUPPORT) - -/* - * Helper macros - */ - -#define DUK__RE_INITIAL_BUFSIZE 64 - -#define DUK__RE_BUFLEN(re_ctx) \ - DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw) - -/* - * Disjunction struct: result of parsing a disjunction - */ - -typedef struct { - /* Number of characters that the atom matches (e.g. 3 for 'abc'), - * -1 if atom is complex and number of matched characters either - * varies or is not known. - */ - duk_int32_t charlen; - -#if 0 - /* These are not needed to implement quantifier capture handling, - * but might be needed at some point. - */ - - /* re_ctx->captures at start and end of atom parsing. - * Since 'captures' indicates highest capture number emitted - * so far in a DUK_REOP_SAVE, the captures numbers saved by - * the atom are: ]start_captures,end_captures]. - */ - duk_uint32_t start_captures; - duk_uint32_t end_captures; -#endif -} duk__re_disjunction_info; - -/* - * Encoding helpers - * - * Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit - * even though the buffer operations will use duk_size_t. - */ - -/* XXX: the insert helpers should ensure that the bytecode result is not - * larger than expected (or at least assert for it). Many things in the - * bytecode, like skip offsets, won't work correctly if the bytecode is - * larger than say 2G. - */ - -DUK_LOCAL duk_uint32_t duk__encode_i32(duk_int32_t x) { - if (x < 0) { - return ((duk_uint32_t) (-x)) * 2 + 1; - } else { - return ((duk_uint32_t) x) * 2; - } -} - -/* XXX: return type should probably be duk_size_t, or explicit checks are needed for - * maximum size. - */ -DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) { - duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH]; - duk_small_int_t len; - - len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf); - DUK_ASSERT(len >= 0); - DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, (duk_size_t) len); - return (duk_uint32_t) len; -} - -DUK_LOCAL void duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) { - DUK_BW_WRITE_ENSURE_XUTF8(re_ctx->thr, &re_ctx->bw, x); -} - -DUK_LOCAL void duk__append_7bit(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) { -#if defined(DUK_USE_PREFER_SIZE) - duk__append_u32(re_ctx, x); -#else - DUK_ASSERT(x <= 0x7fU); - DUK_BW_WRITE_ENSURE_U8(re_ctx->thr, &re_ctx->bw, (duk_uint8_t) x); -#endif -} - -#if 0 -DUK_LOCAL void duk__append_2bytes(duk_re_compiler_ctx *re_ctx, duk_uint8_t x, duk_uint8_t y) { - DUK_BW_WRITE_ENSURE_U8_2(re_ctx->thr, &re_ctx->bw, x, y); -} -#endif - -DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) { - return duk__insert_u32(re_ctx, offset, duk__encode_i32(x)); -} - -DUK_LOCAL void duk__append_reop(duk_re_compiler_ctx *re_ctx, duk_uint32_t reop) { - DUK_ASSERT(reop <= 0x7fU); - (void) duk__append_7bit(re_ctx, reop); -} - -#if 0 /* unused */ -DUK_LOCAL void duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) { - duk__append_u32(re_ctx, duk__encode_i32(x)); -} -#endif - -/* special helper for emitting u16 lists (used for character ranges for built-in char classes) */ -DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) { - /* Call sites don't need the result length so it's not accumulated. */ - while (count-- > 0) { - duk__append_u32(re_ctx, (duk_uint32_t) (*values++)); - } -} - -DUK_LOCAL void duk__insert_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t data_offset, duk_uint32_t data_length) { - DUK_BW_INSERT_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, offset, data_offset, data_length); -} - -DUK_LOCAL void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) { - DUK_BW_WRITE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length); -} - -DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) { - DUK_BW_REMOVE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length); -} - -/* - * Insert a jump offset at 'offset' to complete an instruction - * (the jump offset is always the last component of an instruction). - * The 'skip' argument must be computed relative to 'offset', - * -without- taking into account the skip field being inserted. - * - * ... A B C ins X Y Z ... (ins may be a JUMP, SPLIT1/SPLIT2, etc) - * => ... A B C ins SKIP X Y Z - * - * Computing the final (adjusted) skip value, which is relative to the - * first byte of the next instruction, is a bit tricky because of the - * variable length UTF-8 encoding. See doc/regexp.rst for discussion. - */ -DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) { -#if 0 - /* Iterative solution. */ - if (skip < 0) { - duk_small_int_t len; - /* two encoding attempts suffices */ - len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip)); - len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len)); - DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len); /* no change */ - skip -= (duk_int32_t) len; - } -#endif - -#if defined(DUK_USE_PREFER_SIZE) - /* Closed form solution, this produces smallest code. - * See re_neg_jump_offset (closed2). - */ - if (skip < 0) { - skip--; - if (skip < -0x3fL) { - skip--; - } - if (skip < -0x3ffL) { - skip--; - } - if (skip < -0x7fffL) { - skip--; - } - if (skip < -0xfffffL) { - skip--; - } - if (skip < -0x1ffffffL) { - skip--; - } - if (skip < -0x3fffffffL) { - skip--; - } - } -#else /* DUK_USE_PREFER_SIZE */ - /* Closed form solution, this produces fastest code. - * See re_neg_jump_offset (closed1). - */ - if (skip < 0) { - if (skip >= -0x3eL) { - skip -= 1; - } else if (skip >= -0x3fdL) { - skip -= 2; - } else if (skip >= -0x7ffcL) { - skip -= 3; - } else if (skip >= -0xffffbL) { - skip -= 4; - } else if (skip >= -0x1fffffaL) { - skip -= 5; - } else if (skip >= -0x3ffffff9L) { - skip -= 6; - } else { - skip -= 7; - } - } -#endif /* DUK_USE_PREFER_SIZE */ - - return duk__insert_i32(re_ctx, offset, skip); -} - -DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) { - return (duk_uint32_t) duk__insert_jump_offset(re_ctx, (duk_uint32_t) DUK__RE_BUFLEN(re_ctx), skip); -} - -/* - * duk_re_range_callback for generating character class ranges. - * - * When ignoreCase is false, the range is simply emitted as is. We don't, - * for instance, eliminate duplicates or overlapping ranges in a character - * class. - * - * When ignoreCase is true but the 'direct' flag is set, the caller knows - * that the range canonicalizes to itself for case insensitive matching, - * so the range is emitted as is. This is mainly useful for built-in ranges - * like \W. - * - * Otherwise, when ignoreCase is true, the range needs to be normalized - * through canonicalization. Unfortunately a canonicalized version of a - * continuous range is not necessarily continuous (e.g. [x-{] is continuous - * but [X-{] is not). As a result, a single input range may expand to a lot - * of output ranges. The current algorithm creates the canonicalized ranges - * footprint efficiently at the cost of compile time execution time; see - * doc/regexp.rst for discussion, and some more details below. - * - * Note that the ctx->nranges is a context-wide temporary value. This is OK - * because there cannot be multiple character classes being parsed - * simultaneously. - * - * More detail on canonicalization: - * - * Conceptually, a range is canonicalized by scanning the entire range, - * normalizing each codepoint by converting it to uppercase, and generating - * a set of result ranges. - * - * Ideally a minimal set of output ranges would be emitted by merging all - * possible ranges even if they're emitted out of sequence. Because the - * input string is also case normalized during matching, some codepoints - * never occur at runtime; these "don't care" codepoints can be included or - * excluded from ranges when merging/optimizing ranges. - * - * The current algorithm does not do optimal range merging. Rather, output - * codepoints are generated in sequence, and when the output codepoints are - * continuous (CP, CP+1, CP+2, ...), they are merged locally into as large a - * range as possible. A small canonicalization bitmap is used to reduce - * actual codepoint canonicalizations which are quite slow at present. The - * bitmap provides a "codepoint block is continuous with respect to - * canonicalization" for N-codepoint blocks. This allows blocks to be - * skipped quickly. - * - * There are a number of shortcomings and future work here: - * - * - Individual codepoint normalizations are slow because they involve - * walking bit-packed rules without a lookup index. - * - * - The conceptual algorithm needs to canonicalize every codepoint in the - * input range to figure out the output range(s). Even with the small - * canonicalization bitmap the algorithm runs quite slowly for worst case - * inputs. There are many data structure alternatives to improve this. - * - * - While the current algorithm generates maximal output ranges when the - * output codepoints are emitted linearly, output ranges are not sorted or - * merged otherwise. In the worst case a lot of ranges are emitted when - * most of the ranges could be merged. In this process one could take - * advantage of "don't care" codepoints, which are never matched against at - * runtime due to canonicalization of input codepoints before comparison, - * to merge otherwise discontinuous output ranges. - * - * - The runtime data structure is just a linear list of ranges to match - * against. This can be quite slow if there are a lot of output ranges. - * There are various ways to make matching against the ranges faster, - * e.g. sorting the ranges and using a binary search; skip lists; tree - * based representations; full or approximate codepoint bitmaps, etc. - * - * - Only BMP is supported, codepoints above BMP are assumed to canonicalize - * to themselves. For now this is one place where we don't want to - * support chars outside the BMP, because the exhaustive search would be - * massively larger. It would be possible to support non-BMP with a - * different algorithm, or perhaps doing case normalization only at match - * time. - */ - -DUK_LOCAL void duk__regexp_emit_range(duk_re_compiler_ctx *re_ctx, duk_codepoint_t r1, duk_codepoint_t r2) { - DUK_ASSERT(r2 >= r1); - duk__append_u32(re_ctx, (duk_uint32_t) r1); - duk__append_u32(re_ctx, (duk_uint32_t) r2); - re_ctx->nranges++; -} - -#if defined(DUK_USE_REGEXP_CANON_BITMAP) -/* Find next canonicalization discontinuity (conservative estimate) starting - * from 'start', not exceeding 'end'. If continuity is fine up to 'end' - * inclusive, returns end. Minimum possible return value is start. - */ -DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) { - duk_uint_t start_blk; - duk_uint_t end_blk; - duk_uint_t blk; - duk_uint_t offset; - duk_uint8_t mask; - - /* Inclusive block range. */ - DUK_ASSERT(start >= 0); - DUK_ASSERT(end >= 0); - DUK_ASSERT(end >= start); - start_blk = (duk_uint_t) (start >> DUK_CANON_BITMAP_BLKSHIFT); - end_blk = (duk_uint_t) (end >> DUK_CANON_BITMAP_BLKSHIFT); - - for (blk = start_blk; blk <= end_blk; blk++) { - offset = blk >> 3; - mask = 1U << (blk & 0x07); - if (offset >= sizeof(duk_unicode_re_canon_bitmap)) { - /* Reached non-BMP range which is assumed continuous. */ - return end; - } - DUK_ASSERT(offset < sizeof(duk_unicode_re_canon_bitmap)); - if ((duk_unicode_re_canon_bitmap[offset] & mask) == 0) { - /* Block is discontinuous, continuity is guaranteed - * only up to end of previous block (+1 for exclusive - * return value => start of current block). Start - * block requires special handling. - */ - if (blk > start_blk) { - return (duk_codepoint_t) (blk << DUK_CANON_BITMAP_BLKSHIFT); - } else { - return start; - } - } - } - DUK_ASSERT(blk == end_blk + 1); /* Reached end block which is continuous. */ - return end; -} -#else /* DUK_USE_REGEXP_CANON_BITMAP */ -DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) { - DUK_ASSERT(start >= 0); - DUK_ASSERT(end >= 0); - DUK_ASSERT(end >= start); - if (start >= 0x10000) { - /* Even without the bitmap, treat non-BMP as continuous. */ - return end; - } - return start; -} -#endif /* DUK_USE_REGEXP_CANON_BITMAP */ - -DUK_LOCAL void duk__regexp_generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) { - duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata; - duk_codepoint_t r_start; - duk_codepoint_t r_end; - duk_codepoint_t i; - duk_codepoint_t t; - duk_codepoint_t r_disc; - - DUK_DD(DUK_DDPRINT("duk__regexp_generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld", - (void *) re_ctx, (long) r1, (long) r2, (long) direct)); - - DUK_ASSERT(r2 >= r1); /* SyntaxError for out of order range. */ - - if (direct || (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) == 0) { - DUK_DD(DUK_DDPRINT("direct or not case sensitive, emit range: [%ld,%ld]", (long) r1, (long) r2)); - duk__regexp_emit_range(re_ctx, r1, r2); - return; - } - - DUK_DD(DUK_DDPRINT("case sensitive, process range: [%ld,%ld]", (long) r1, (long) r2)); - - r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1); - r_end = r_start; - - for (i = r1 + 1; i <= r2;) { - /* Input codepoint space processed up to i-1, and - * current range in r_{start,end} is up-to-date - * (inclusive) and may either break or continue. - */ - r_disc = duk__re_canon_next_discontinuity(i, r2); - DUK_ASSERT(r_disc >= i); - DUK_ASSERT(r_disc <= r2); - - r_end += r_disc - i; /* May be zero. */ - t = duk_unicode_re_canonicalize_char(re_ctx->thr, r_disc); - if (t == r_end + 1) { - /* Not actually a discontinuity, continue range - * to r_disc and recheck. - */ - r_end = t; - } else { - duk__regexp_emit_range(re_ctx, r_start, r_end); - r_start = t; - r_end = t; - } - i = r_disc + 1; /* Guarantees progress. */ - } - duk__regexp_emit_range(re_ctx, r_start, r_end); - -#if 0 /* Exhaustive search, very slow. */ - r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1); - r_end = r_start; - for (i = r1 + 1; i <= r2; i++) { - t = duk_unicode_re_canonicalize_char(re_ctx->thr, i); - if (t == r_end + 1) { - r_end = t; - } else { - DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end)); - duk__append_u32(re_ctx, (duk_uint32_t) r_start); - duk__append_u32(re_ctx, (duk_uint32_t) r_end); - re_ctx->nranges++; - r_start = t; - r_end = t; - } - } - DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end)); - duk__append_u32(re_ctx, (duk_uint32_t) r_start); - duk__append_u32(re_ctx, (duk_uint32_t) r_end); - re_ctx->nranges++; -#endif -} - -/* - * Parse regexp Disjunction. Most of regexp compilation happens here. - * - * Handles Disjunction, Alternative, and Term productions directly without - * recursion. The only constructs requiring recursion are positive/negative - * lookaheads, capturing parentheses, and non-capturing parentheses. - * - * The function determines whether the entire disjunction is a 'simple atom' - * (see doc/regexp.rst discussion on 'simple quantifiers') and if so, - * returns the atom character length which is needed by the caller to keep - * track of its own atom character length. A disjunction with more than one - * alternative is never considered a simple atom (although in some cases - * that might be the case). - * - * Return value: simple atom character length or < 0 if not a simple atom. - * Appends the bytecode for the disjunction matcher to the end of the temp - * buffer. - * - * Regexp top level structure is: - * - * Disjunction = Term* - * | Term* | Disjunction - * - * Term = Assertion - * | Atom - * | Atom Quantifier - * - * An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/). - * - * Notes: - * - * * Tracking of the 'simple-ness' of the current atom vs. the entire - * disjunction are separate matters. For instance, the disjunction - * may be complex, but individual atoms may be simple. Furthermore, - * simple quantifiers are used whenever possible, even if the - * disjunction as a whole is complex. - * - * * The estimate of whether an atom is simple is conservative now, - * and it would be possible to expand it. For instance, captures - * cause the disjunction to be marked complex, even though captures - * -can- be handled by simple quantifiers with some minor modifications. - * - * * Disjunction 'tainting' as 'complex' is handled at the end of the - * main for loop collectively for atoms. Assertions, quantifiers, - * and '|' tokens need to taint the result manually if necessary. - * Assertions cannot add to result char length, only atoms (and - * quantifiers) can; currently quantifiers will taint the result - * as complex though. - */ - -DUK_LOCAL const duk_uint16_t * const duk__re_range_lookup1[3] = { - duk_unicode_re_ranges_digit, - duk_unicode_re_ranges_white, - duk_unicode_re_ranges_wordchar -}; -DUK_LOCAL const duk_uint8_t duk__re_range_lookup2[3] = { - sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)), - sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)), - sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t)) -}; - -DUK_LOCAL void duk__append_range_atom_matcher(duk_re_compiler_ctx *re_ctx, duk_small_uint_t re_op, const duk_uint16_t *ranges, duk_small_uint_t count) { -#if 0 - DUK_ASSERT(re_op <= 0x7fUL); - DUK_ASSERT(count <= 0x7fUL); - duk__append_2bytes(re_ctx, (duk_uint8_t) re_op, (duk_uint8_t) count); -#endif - duk__append_reop(re_ctx, re_op); - duk__append_7bit(re_ctx, count); - duk__append_u16_list(re_ctx, ranges, count * 2); -} - -DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) { - duk_int32_t atom_start_offset = -1; /* negative -> no atom matched on previous round */ - duk_int32_t atom_char_length = 0; /* negative -> complex atom */ - duk_uint32_t atom_start_captures = re_ctx->captures; /* value of re_ctx->captures at start of atom */ - duk_int32_t unpatched_disjunction_split = -1; - duk_int32_t unpatched_disjunction_jump = -1; - duk_uint32_t entry_offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); - duk_int32_t res_charlen = 0; /* -1 if disjunction is complex, char length if simple */ - duk__re_disjunction_info tmp_disj; - - DUK_ASSERT(out_atom_info != NULL); - - if (re_ctx->recursion_depth >= re_ctx->recursion_limit) { - DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT); - } - re_ctx->recursion_depth++; - -#if 0 - out_atom_info->start_captures = re_ctx->captures; -#endif - - for (;;) { - /* atom_char_length, atom_start_offset, atom_start_offset reflect the - * atom matched on the previous loop. If a quantifier is encountered - * on this loop, these are needed to handle the quantifier correctly. - * new_atom_char_length etc are for the atom parsed on this round; - * they're written to atom_char_length etc at the end of the round. - */ - duk_int32_t new_atom_char_length; /* char length of the atom parsed in this loop */ - duk_int32_t new_atom_start_offset; /* bytecode start offset of the atom parsed in this loop - * (allows quantifiers to copy the atom bytecode) - */ - duk_uint32_t new_atom_start_captures; /* re_ctx->captures at the start of the atom parsed in this loop */ - - duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token); - - DUK_DD(DUK_DDPRINT("re token: %ld (num=%ld, char=%c)", - (long) re_ctx->curr_token.t, - (long) re_ctx->curr_token.num, - (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ? - (int) re_ctx->curr_token.num : (int) '?')); - - /* set by atom case clauses */ - new_atom_start_offset = -1; - new_atom_char_length = -1; - new_atom_start_captures = re_ctx->captures; - - switch (re_ctx->curr_token.t) { - case DUK_RETOK_DISJUNCTION: { - /* - * The handling here is a bit tricky. If a previous '|' has been processed, - * we have a pending split1 and a pending jump (for a previous match). These - * need to be back-patched carefully. See docs for a detailed example. - */ - - /* patch pending jump and split */ - if (unpatched_disjunction_jump >= 0) { - duk_uint32_t offset; - - DUK_ASSERT(unpatched_disjunction_split >= 0); - offset = (duk_uint32_t) unpatched_disjunction_jump; - offset += duk__insert_jump_offset(re_ctx, - offset, - (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset)); - /* offset is now target of the pending split (right after jump) */ - duk__insert_jump_offset(re_ctx, - (duk_uint32_t) unpatched_disjunction_split, - (duk_int32_t) offset - unpatched_disjunction_split); - } - - /* add a new pending split to the beginning of the entire disjunction */ - (void) duk__insert_u32(re_ctx, - entry_offset, - DUK_REOP_SPLIT1); /* prefer direct execution */ - unpatched_disjunction_split = (duk_int32_t) (entry_offset + 1); /* +1 for opcode */ - - /* add a new pending match jump for latest finished alternative */ - duk__append_reop(re_ctx, DUK_REOP_JUMP); - unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); - - /* 'taint' result as complex */ - res_charlen = -1; - break; - } - case DUK_RETOK_QUANTIFIER: { - if (atom_start_offset < 0) { - DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM); - } - if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) { - DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES); - } - if (atom_char_length >= 0) { - /* - * Simple atom - * - * If atom_char_length is zero, we'll have unbounded execution time for e.g. - * /()*x/.exec('x'). We can't just skip the match because it might have some - * side effects (for instance, if we allowed captures in simple atoms, the - * capture needs to happen). The simple solution below is to force the - * quantifier to match at most once, since the additional matches have no effect. - * - * With a simple atom there can be no capture groups, so no captures need - * to be reset. - */ - duk_int32_t atom_code_length; - duk_uint32_t offset; - duk_uint32_t qmin, qmax; - - qmin = re_ctx->curr_token.qmin; - qmax = re_ctx->curr_token.qmax; - if (atom_char_length == 0) { - /* qmin and qmax will be 0 or 1 */ - if (qmin > 1) { - qmin = 1; - } - if (qmax > 1) { - qmax = 1; - } - } - - duk__append_reop(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */ - atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (duk_size_t) atom_start_offset); - - offset = (duk_uint32_t) atom_start_offset; - if (re_ctx->curr_token.greedy) { - offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY); - offset += duk__insert_u32(re_ctx, offset, qmin); - offset += duk__insert_u32(re_ctx, offset, qmax); - offset += duk__insert_u32(re_ctx, offset, (duk_uint32_t) atom_char_length); - offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length); - } else { - offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL); - offset += duk__insert_u32(re_ctx, offset, qmin); - offset += duk__insert_u32(re_ctx, offset, qmax); - offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length); - } - DUK_UNREF(offset); /* silence scan-build warning */ - } else { - /* - * Complex atom - * - * The original code is used as a template, and removed at the end - * (this differs from the handling of simple quantifiers). - * - * NOTE: there is no current solution for empty atoms in complex - * quantifiers. This would need some sort of a 'progress' instruction. - * - * XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies? - */ - duk_int32_t atom_code_length; - duk_uint32_t atom_copies; - duk_uint32_t tmp_qmin, tmp_qmax; - - /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */ - atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ? - re_ctx->curr_token.qmin : re_ctx->curr_token.qmax; - if (atom_copies > DUK_RE_MAX_ATOM_COPIES) { - DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES); - } - - /* wipe the capture range made by the atom (if any) */ - DUK_ASSERT(atom_start_captures <= re_ctx->captures); - if (atom_start_captures != re_ctx->captures) { - DUK_ASSERT(atom_start_captures < re_ctx->captures); - DUK_DDD(DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%ld,%ld]", - (long) atom_start_captures, (long) re_ctx->captures)); - - /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */ - duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (re_ctx->captures - atom_start_captures) * 2U); - duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (atom_start_captures + 1) * 2); - duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, DUK_REOP_WIPERANGE); - } else { - DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld", - (long) atom_start_captures)); - } - - atom_code_length = (duk_int32_t) DUK__RE_BUFLEN(re_ctx) - atom_start_offset; - - /* insert the required matches (qmin) by copying the atom */ - tmp_qmin = re_ctx->curr_token.qmin; - tmp_qmax = re_ctx->curr_token.qmax; - while (tmp_qmin > 0) { - duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length); - tmp_qmin--; - if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) { - tmp_qmax--; - } - } - DUK_ASSERT(tmp_qmin == 0); - - /* insert code for matching the remainder - infinite or finite */ - if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) { - /* reuse last emitted atom for remaining 'infinite' quantifier */ - - if (re_ctx->curr_token.qmin == 0) { - /* Special case: original qmin was zero so there is nothing - * to repeat. Emit an atom copy but jump over it here. - */ - duk__append_reop(re_ctx, DUK_REOP_JUMP); - duk__append_jump_offset(re_ctx, atom_code_length); - duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length); - } - if (re_ctx->curr_token.greedy) { - duk__append_reop(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */ - } else { - duk__append_reop(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */ - } - duk__append_jump_offset(re_ctx, -atom_code_length - 1); /* -1 for opcode */ - } else { - /* - * The remaining matches are emitted as sequence of SPLITs and atom - * copies; the SPLITs skip the remaining copies and match the sequel. - * This sequence needs to be emitted starting from the last copy - * because the SPLITs are variable length due to the variable length - * skip offset. This causes a lot of memory copying now. - * - * Example structure (greedy, match maximum # atoms): - * - * SPLIT1 LSEQ - * (atom) - * SPLIT1 LSEQ ; <- the byte length of this instruction is needed - * (atom) ; to encode the above SPLIT1 correctly - * ... - * LSEQ: - */ - duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); - while (tmp_qmax > 0) { - duk__insert_slice(re_ctx, offset, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length); - if (re_ctx->curr_token.greedy) { - duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */ - } else { - duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2); /* prefer jump */ - } - duk__insert_jump_offset(re_ctx, - offset + 1, /* +1 for opcode */ - (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1))); - tmp_qmax--; - } - } - - /* remove the original 'template' atom */ - duk__remove_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length); - } - - /* 'taint' result as complex */ - res_charlen = -1; - break; - } - case DUK_RETOK_ASSERT_START: { - duk__append_reop(re_ctx, DUK_REOP_ASSERT_START); - break; - } - case DUK_RETOK_ASSERT_END: { - duk__append_reop(re_ctx, DUK_REOP_ASSERT_END); - break; - } - case DUK_RETOK_ASSERT_WORD_BOUNDARY: { - duk__append_reop(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY); - break; - } - case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: { - duk__append_reop(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY); - break; - } - case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD: - case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: { - duk_uint32_t offset; - duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ? - DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG; - - offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); - duk__parse_disjunction(re_ctx, 0, &tmp_disj); - duk__append_reop(re_ctx, DUK_REOP_MATCH); - - (void) duk__insert_u32(re_ctx, offset, opcode); - (void) duk__insert_jump_offset(re_ctx, - offset + 1, /* +1 for opcode */ - (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1))); - - /* 'taint' result as complex -- this is conservative, - * as lookaheads do not backtrack. - */ - res_charlen = -1; - break; - } - case DUK_RETOK_ATOM_PERIOD: { - new_atom_char_length = 1; - new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); - duk__append_reop(re_ctx, DUK_REOP_PERIOD); - break; - } - case DUK_RETOK_ATOM_CHAR: { - /* Note: successive characters could be joined into string matches - * but this is not trivial (consider e.g. '/xyz+/); see docs for - * more discussion. - * - * No support for \u{H+} yet. While only BMP Unicode escapes are - * supported for RegExps at present, 'ch' may still be a non-BMP - * codepoint if it is decoded straight from source text UTF-8. - * There's no non-BMP support yet so this is handled simply by - * matching the non-BMP character (which is custom behavior). - */ - duk_uint32_t ch; - - new_atom_char_length = 1; - new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); - duk__append_reop(re_ctx, DUK_REOP_CHAR); - ch = re_ctx->curr_token.num; - if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) { - ch = (duk_uint32_t) duk_unicode_re_canonicalize_char(re_ctx->thr, (duk_codepoint_t) ch); - } - duk__append_u32(re_ctx, ch); - break; - } - case DUK_RETOK_ATOM_DIGIT: - case DUK_RETOK_ATOM_NOT_DIGIT: - case DUK_RETOK_ATOM_WHITE: - case DUK_RETOK_ATOM_NOT_WHITE: - case DUK_RETOK_ATOM_WORD_CHAR: - case DUK_RETOK_ATOM_NOT_WORD_CHAR: { - duk_small_uint_t re_op; - duk_small_uint_t idx; - - new_atom_char_length = 1; - new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); - - DUK_ASSERT((DUK_RETOK_ATOM_DIGIT & 0x01) != 0); - DUK_ASSERT((DUK_RETOK_ATOM_WHITE & 0x01) != 0); - DUK_ASSERT((DUK_RETOK_ATOM_WORD_CHAR & 0x01) != 0); - DUK_ASSERT((DUK_RETOK_ATOM_NOT_DIGIT & 0x01) == 0); - DUK_ASSERT((DUK_RETOK_ATOM_NOT_WHITE & 0x01) == 0); - DUK_ASSERT((DUK_RETOK_ATOM_NOT_WORD_CHAR & 0x01) == 0); - re_op = (re_ctx->curr_token.t & 0x01) ? DUK_REOP_RANGES : DUK_REOP_INVRANGES; - - DUK_ASSERT(DUK_RETOK_ATOM_WHITE == DUK_RETOK_ATOM_DIGIT + 2); - DUK_ASSERT(DUK_RETOK_ATOM_WORD_CHAR == DUK_RETOK_ATOM_DIGIT + 4); - idx = (duk_small_uint_t) ((re_ctx->curr_token.t - DUK_RETOK_ATOM_DIGIT) >> 1U); - DUK_ASSERT(idx <= 2U); /* Assume continuous token numbers; also checks negative underflow. */ - - duk__append_range_atom_matcher(re_ctx, re_op, duk__re_range_lookup1[idx], duk__re_range_lookup2[idx]); - break; - } - case DUK_RETOK_ATOM_BACKREFERENCE: { - duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num; - if (backref > re_ctx->highest_backref) { - re_ctx->highest_backref = backref; - } - new_atom_char_length = -1; /* mark as complex */ - new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); - duk__append_reop(re_ctx, DUK_REOP_BACKREFERENCE); - duk__append_u32(re_ctx, backref); - break; - } - case DUK_RETOK_ATOM_START_CAPTURE_GROUP: { - duk_uint32_t cap; - - new_atom_char_length = -1; /* mark as complex (capture handling) */ - new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); - cap = ++re_ctx->captures; - duk__append_reop(re_ctx, DUK_REOP_SAVE); - duk__append_u32(re_ctx, cap * 2); - duk__parse_disjunction(re_ctx, 0, &tmp_disj); /* retval (sub-atom char length) unused, tainted as complex above */ - duk__append_reop(re_ctx, DUK_REOP_SAVE); - duk__append_u32(re_ctx, cap * 2 + 1); - break; - } - case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: { - new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); - duk__parse_disjunction(re_ctx, 0, &tmp_disj); - new_atom_char_length = tmp_disj.charlen; - break; - } - case DUK_RETOK_ATOM_START_CHARCLASS: - case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: { - /* - * Range parsing is done with a special lexer function which calls - * us for every range parsed. This is different from how rest of - * the parsing works, but avoids a heavy, arbitrary size intermediate - * value type to hold the ranges. - * - * Another complication is the handling of character ranges when - * case insensitive matching is used (see docs for discussion). - * The range handler callback given to the lexer takes care of this - * as well. - * - * Note that duplicate ranges are not eliminated when parsing character - * classes, so that canonicalization of - * - * [0-9a-fA-Fx-{] - * - * creates the result (note the duplicate ranges): - * - * [0-9A-FA-FX-Z{-{] - * - * where [x-{] is split as a result of canonicalization. The duplicate - * ranges are not a semantics issue: they work correctly. - */ - - duk_uint32_t offset; - - DUK_DD(DUK_DDPRINT("character class")); - - /* insert ranges instruction, range count patched in later */ - new_atom_char_length = 1; - new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); - duk__append_reop(re_ctx, - (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ? - DUK_REOP_RANGES : DUK_REOP_INVRANGES); - offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); /* patch in range count later */ - - /* parse ranges until character class ends */ - re_ctx->nranges = 0; /* note: ctx-wide temporary */ - duk_lexer_parse_re_ranges(&re_ctx->lex, duk__regexp_generate_ranges, (void *) re_ctx); - - /* insert range count */ - duk__insert_u32(re_ctx, offset, re_ctx->nranges); - break; - } - case DUK_RETOK_ATOM_END_GROUP: { - if (expect_eof) { - DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN); - } - goto done; - } - case DUK_RETOK_EOF: { - if (!expect_eof) { - DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN); - } - goto done; - } - default: { - DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN); - } - } - - /* a complex (new) atom taints the result */ - if (new_atom_start_offset >= 0) { - if (new_atom_char_length < 0) { - res_charlen = -1; - } else if (res_charlen >= 0) { - /* only advance if not tainted */ - res_charlen += new_atom_char_length; - } - } - - /* record previous atom info in case next token is a quantifier */ - atom_start_offset = new_atom_start_offset; - atom_char_length = new_atom_char_length; - atom_start_captures = new_atom_start_captures; - } - - done: - - /* finish up pending jump and split for last alternative */ - if (unpatched_disjunction_jump >= 0) { - duk_uint32_t offset; - - DUK_ASSERT(unpatched_disjunction_split >= 0); - offset = (duk_uint32_t) unpatched_disjunction_jump; - offset += duk__insert_jump_offset(re_ctx, - offset, - (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset)); - /* offset is now target of the pending split (right after jump) */ - duk__insert_jump_offset(re_ctx, - (duk_uint32_t) unpatched_disjunction_split, - (duk_int32_t) offset - unpatched_disjunction_split); - } - -#if 0 - out_atom_info->end_captures = re_ctx->captures; -#endif - out_atom_info->charlen = res_charlen; - DUK_DDD(DUK_DDDPRINT("parse disjunction finished: charlen=%ld", - (long) out_atom_info->charlen)); - - re_ctx->recursion_depth--; -} - -/* - * Flags parsing (see E5 Section 15.10.4.1). - */ - -DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) { - const duk_uint8_t *p; - const duk_uint8_t *p_end; - duk_uint32_t flags = 0; - - p = DUK_HSTRING_GET_DATA(h); - p_end = p + DUK_HSTRING_GET_BYTELEN(h); - - /* Note: can be safely scanned as bytes (undecoded) */ - - while (p < p_end) { - duk_uint8_t c = *p++; - switch (c) { - case (duk_uint8_t) 'g': { - if (flags & DUK_RE_FLAG_GLOBAL) { - goto flags_error; - } - flags |= DUK_RE_FLAG_GLOBAL; - break; - } - case (duk_uint8_t) 'i': { - if (flags & DUK_RE_FLAG_IGNORE_CASE) { - goto flags_error; - } - flags |= DUK_RE_FLAG_IGNORE_CASE; - break; - } - case (duk_uint8_t) 'm': { - if (flags & DUK_RE_FLAG_MULTILINE) { - goto flags_error; - } - flags |= DUK_RE_FLAG_MULTILINE; - break; - } - default: { - goto flags_error; - } - } - } - - return flags; - - flags_error: - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS); - return 0; /* never here */ -} - -/* - * Create escaped RegExp source (E5 Section 15.10.3). - * - * The current approach is to special case the empty RegExp - * ('' -> '(?:)') and otherwise replace unescaped '/' characters - * with '\/' regardless of where they occur in the regexp. - * - * Note that normalization does not seem to be necessary for - * RegExp literals (e.g. '/foo/') because to be acceptable as - * a RegExp literal, the text between forward slashes must - * already match the escaping requirements (e.g. must not contain - * unescaped forward slashes or be empty). Escaping IS needed - * for expressions like 'new Regexp("...", "")' however. - * Currently, we re-escape in either case. - * - * Also note that we process the source here in UTF-8 encoded - * form. This is correct, because any non-ASCII characters are - * passed through without change. - */ - -DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) { - duk_hstring *h; - const duk_uint8_t *p; - duk_bufwriter_ctx bw_alloc; - duk_bufwriter_ctx *bw; - duk_uint8_t *q; - duk_size_t i, n; - duk_uint_fast8_t c_prev, c; - - h = duk_known_hstring(thr, idx_pattern); - p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); - n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); - - if (n == 0) { - duk_push_string(thr, "(?:)"); - return; - } - - bw = &bw_alloc; - DUK_BW_INIT_PUSHBUF(thr, bw, n); - q = DUK_BW_GET_PTR(thr, bw); - - c_prev = (duk_uint_fast8_t) 0; - - for (i = 0; i < n; i++) { - c = p[i]; - - q = DUK_BW_ENSURE_RAW(thr, bw, 2, q); - - if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') { - /* Unescaped '/' ANYWHERE in the regexp (in disjunction, - * inside a character class, ...) => same escape works. - */ - *q++ = DUK_ASC_BACKSLASH; - } - *q++ = (duk_uint8_t) c; - - c_prev = c; - } - - DUK_BW_SETPTR_AND_COMPACT(thr, bw, q); - (void) duk_buffer_to_string(thr, -1); /* Safe if input is safe. */ - - /* [ ... escaped_source ] */ -} - -/* - * Exposed regexp compilation primitive. - * - * Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the - * actual parsing. Handles generation of the compiled regexp header and the - * "boilerplate" capture of the matching substring (save 0 and 1). Also does some - * global level regexp checks after recursive compilation has finished. - * - * An escaped version of the regexp source, suitable for use as a RegExp instance - * 'source' property (see E5 Section 15.10.3), is also left on the stack. - * - * Input stack: [ pattern flags ] - * Output stack: [ bytecode escaped_source ] (both as strings) - */ - -DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) { - duk_re_compiler_ctx re_ctx; - duk_lexer_point lex_point; - duk_hstring *h_pattern; - duk_hstring *h_flags; - duk__re_disjunction_info ign_disj; - - DUK_ASSERT(thr != NULL); - - /* - * Args validation - */ - - /* TypeError if fails */ - h_pattern = duk_require_hstring_notsymbol(thr, -2); - h_flags = duk_require_hstring_notsymbol(thr, -1); - - /* - * Create normalized 'source' property (E5 Section 15.10.3). - */ - - /* [ ... pattern flags ] */ - - duk__create_escaped_source(thr, -2); - - /* [ ... pattern flags escaped_source ] */ - - /* - * Init compilation context - */ - - /* [ ... pattern flags escaped_source buffer ] */ - - DUK_MEMZERO(&re_ctx, sizeof(re_ctx)); - DUK_LEXER_INITCTX(&re_ctx.lex); /* duplicate zeroing, expect for (possible) NULL inits */ - re_ctx.thr = thr; - re_ctx.lex.thr = thr; - re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern); - re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern); - re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT; - re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT; - re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags); - - DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE); - - DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld", - (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit)); - - /* - * Init lexer - */ - - lex_point.offset = 0; /* expensive init, just want to fill window */ - lex_point.line = 1; - DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point); - - /* - * Compilation - */ - - DUK_DD(DUK_DDPRINT("starting regexp compilation")); - - duk__append_reop(&re_ctx, DUK_REOP_SAVE); - duk__append_7bit(&re_ctx, 0); - duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj); - duk__append_reop(&re_ctx, DUK_REOP_SAVE); - duk__append_7bit(&re_ctx, 1); - duk__append_reop(&re_ctx, DUK_REOP_MATCH); - - /* - * Check for invalid backreferences; note that it is NOT an error - * to back-reference a capture group which has not yet been introduced - * in the pattern (as in /\1(foo)/); in fact, the backreference will - * always match! It IS an error to back-reference a capture group - * which will never be introduced in the pattern. Thus, we can check - * for such references only after parsing is complete. - */ - - if (re_ctx.highest_backref > re_ctx.captures) { - DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS); - } - - /* - * Emit compiled regexp header: flags, ncaptures - * (insertion order inverted on purpose) - */ - - duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2); - duk__insert_u32(&re_ctx, 0, re_ctx.re_flags); - - /* [ ... pattern flags escaped_source buffer ] */ - - DUK_BW_COMPACT(thr, &re_ctx.bw); - (void) duk_buffer_to_string(thr, -1); /* Safe because flags is at most 7 bit. */ - - /* [ ... pattern flags escaped_source bytecode ] */ - - /* - * Finalize stack - */ - - duk_remove(thr, -4); /* -> [ ... flags escaped_source bytecode ] */ - duk_remove(thr, -3); /* -> [ ... escaped_source bytecode ] */ - - DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T", - (duk_tval *) duk_get_tval(thr, -1), (duk_tval *) duk_get_tval(thr, -2))); -} - -/* - * Create a RegExp instance (E5 Section 15.10.7). - * - * Note: the output stack left by duk_regexp_compile() is directly compatible - * with the input here. - * - * Input stack: [ escaped_source bytecode ] (both as strings) - * Output stack: [ RegExp ] - */ - -DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) { - duk_hobject *h; - - /* [ ... escaped_source bytecode ] */ - - duk_push_object(thr); - h = duk_known_hobject(thr, -1); - duk_insert(thr, -3); - - /* [ ... regexp_object escaped_source bytecode ] */ - - DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]); - - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE); - - /* [ ... regexp_object escaped_source ] */ - - /* In ES2015 .source, and the .global, .multiline, etc flags are - * inherited getters. Store the escaped source as an internal - * property for the getter. - */ - - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE); - - /* [ ... regexp_object ] */ - - duk_push_int(thr, 0); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W); - - /* [ ... regexp_object ] */ -} - -#else /* DUK_USE_REGEXP_SUPPORT */ - -/* regexp support disabled */ - -#endif /* DUK_USE_REGEXP_SUPPORT */ - -/* automatic undefs */ -#undef DUK__RE_BUFLEN -#undef DUK__RE_INITIAL_BUFSIZE -#line 1 "duk_regexp_executor.c" -/* - * Regexp executor. - * - * Safety: the Ecmascript executor should prevent user from reading and - * replacing regexp bytecode. Even so, the executor must validate all - * memory accesses etc. When an invalid access is detected (e.g. a 'save' - * opcode to invalid, unallocated index) it should fail with an internal - * error but not cause a segmentation fault. - * - * Notes: - * - * - Backtrack counts are limited to unsigned 32 bits but should - * technically be duk_size_t for strings longer than 4G chars. - * This also requires a regexp bytecode change. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_REGEXP_SUPPORT) - -/* - * Helpers for UTF-8 handling - * - * For bytecode readers the duk_uint32_t and duk_int32_t types are correct - * because they're used for more than just codepoints. - */ - -DUK_LOCAL duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) { - return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end); -} - -DUK_LOCAL duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) { - duk_uint32_t t; - - /* signed integer encoding needed to work with UTF-8 */ - t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end); - if (t & 1) { - return -((duk_int32_t) (t >> 1)); - } else { - return (duk_int32_t) (t >> 1); - } -} - -DUK_LOCAL const duk_uint8_t *duk__utf8_backtrack(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) { - const duk_uint8_t *p; - - /* Note: allow backtracking from p == ptr_end */ - p = *ptr; - if (p < ptr_start || p > ptr_end) { - goto fail; - } - - while (count > 0) { - for (;;) { - p--; - if (p < ptr_start) { - goto fail; - } - if ((*p & 0xc0) != 0x80) { - /* utf-8 continuation bytes have the form 10xx xxxx */ - break; - } - } - count--; - } - *ptr = p; - return p; - - fail: - DUK_ERROR_INTERNAL(thr); - return NULL; /* never here */ -} - -DUK_LOCAL const duk_uint8_t *duk__utf8_advance(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) { - const duk_uint8_t *p; - - p = *ptr; - if (p < ptr_start || p >= ptr_end) { - goto fail; - } - - while (count > 0) { - for (;;) { - p++; - - /* Note: if encoding ends by hitting end of input, we don't check that - * the encoding is valid, we just assume it is. - */ - if (p >= ptr_end || ((*p & 0xc0) != 0x80)) { - /* utf-8 continuation bytes have the form 10xx xxxx */ - break; - } - } - count--; - } - - *ptr = p; - return p; - - fail: - DUK_ERROR_INTERNAL(thr); - return NULL; /* never here */ -} - -/* - * Helpers for dealing with the input string - */ - -/* Get a (possibly canonicalized) input character from current sp. The input - * itself is never modified, and captures always record non-canonicalized - * characters even in case-insensitive matching. Return <0 if out of input. - */ -DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) { - duk_codepoint_t res; - - if (*sp >= re_ctx->input_end) { - return -1; - } - res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end); - if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) { - res = duk_unicode_re_canonicalize_char(re_ctx->thr, res); - } - return res; -} - -DUK_LOCAL const duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp, duk_uint_fast32_t count) { - return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count); -} - -/* Backtrack utf-8 input and return a (possibly canonicalized) input character. */ -DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *sp) { - /* note: caller 'sp' is intentionally not updated here */ - (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1); - return duk__inp_get_cp(re_ctx, &sp); -} - -/* - * Regexp recursive matching function. - * - * Returns 'sp' on successful match (points to character after last matched one), - * NULL otherwise. - * - * The C recursion depth limit check is only performed in this function, this - * suffices because the function is present in all true recursion required by - * regexp execution. - */ - -DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) { - if (re_ctx->recursion_depth >= re_ctx->recursion_limit) { - DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT); - } - re_ctx->recursion_depth++; - - for (;;) { - duk_small_int_t op; - - if (re_ctx->steps_count >= re_ctx->steps_limit) { - DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT); - } - re_ctx->steps_count++; - - /* Opcodes are at most 7 bits now so they encode to one byte. If this - * were not the case or 'pc' is invalid here (due to a bug etc) we'll - * still fail safely through the switch default case. - */ - DUK_ASSERT(pc[0] <= 0x7fU); -#if 0 - op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc); -#endif - op = *pc++; - - DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld", - (long) re_ctx->recursion_depth, - (long) re_ctx->steps_count, - (long) (pc - re_ctx->bytecode), - (long) (sp - re_ctx->input), - (long) op)); - - switch (op) { - case DUK_REOP_MATCH: { - goto match; - } - case DUK_REOP_CHAR: { - /* - * Byte-based matching would be possible for case-sensitive - * matching but not for case-insensitive matching. So, we - * match by decoding the input and bytecode character normally. - * - * Bytecode characters are assumed to be already canonicalized. - * Input characters are canonicalized automatically by - * duk__inp_get_cp() if necessary. - * - * There is no opcode for matching multiple characters. The - * regexp compiler has trouble joining strings efficiently - * during compilation. See doc/regexp.rst for more discussion. - */ - duk_codepoint_t c1, c2; - - c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc); - DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) || - c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1)); /* canonicalized by compiler */ - c2 = duk__inp_get_cp(re_ctx, &sp); - /* No need to check for c2 < 0 (end of input): because c1 >= 0, it - * will fail the match below automatically and cause goto fail. - */ -#if 0 - if (c2 < 0) { - goto fail; - } -#endif - DUK_ASSERT(c1 >= 0); - - DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld", (long) c1, (long) c2)); - if (c1 != c2) { - goto fail; - } - break; - } - case DUK_REOP_PERIOD: { - duk_codepoint_t c; - - c = duk__inp_get_cp(re_ctx, &sp); - if (c < 0 || duk_unicode_is_line_terminator(c)) { - /* E5 Sections 15.10.2.8, 7.3 */ - goto fail; - } - break; - } - case DUK_REOP_RANGES: - case DUK_REOP_INVRANGES: { - duk_uint32_t n; - duk_codepoint_t c; - duk_small_int_t match; - - n = duk__bc_get_u32(re_ctx, &pc); - c = duk__inp_get_cp(re_ctx, &sp); - if (c < 0) { - goto fail; - } - - match = 0; - while (n) { - duk_codepoint_t r1, r2; - r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc); - r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc); - DUK_DDD(DUK_DDDPRINT("matching ranges/invranges, n=%ld, r1=%ld, r2=%ld, c=%ld", - (long) n, (long) r1, (long) r2, (long) c)); - if (c >= r1 && c <= r2) { - /* Note: don't bail out early, we must read all the ranges from - * bytecode. Another option is to skip them efficiently after - * breaking out of here. Prefer smallest code. - */ - match = 1; - } - n--; - } - - if (op == DUK_REOP_RANGES) { - if (!match) { - goto fail; - } - } else { - DUK_ASSERT(op == DUK_REOP_INVRANGES); - if (match) { - goto fail; - } - } - break; - } - case DUK_REOP_ASSERT_START: { - duk_codepoint_t c; - - if (sp <= re_ctx->input) { - break; - } - if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) { - goto fail; - } - c = duk__inp_get_prev_cp(re_ctx, sp); - if (duk_unicode_is_line_terminator(c)) { - /* E5 Sections 15.10.2.8, 7.3 */ - break; - } - goto fail; - } - case DUK_REOP_ASSERT_END: { - duk_codepoint_t c; - const duk_uint8_t *tmp_sp; - - tmp_sp = sp; - c = duk__inp_get_cp(re_ctx, &tmp_sp); - if (c < 0) { - break; - } - if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) { - goto fail; - } - if (duk_unicode_is_line_terminator(c)) { - /* E5 Sections 15.10.2.8, 7.3 */ - break; - } - goto fail; - } - case DUK_REOP_ASSERT_WORD_BOUNDARY: - case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: { - /* - * E5 Section 15.10.2.6. The previous and current character - * should -not- be canonicalized as they are now. However, - * canonicalization does not affect the result of IsWordChar() - * (which depends on Unicode characters never canonicalizing - * into ASCII characters) so this does not matter. - */ - duk_small_int_t w1, w2; - - if (sp <= re_ctx->input) { - w1 = 0; /* not a wordchar */ - } else { - duk_codepoint_t c; - c = duk__inp_get_prev_cp(re_ctx, sp); - w1 = duk_unicode_re_is_wordchar(c); - } - if (sp >= re_ctx->input_end) { - w2 = 0; /* not a wordchar */ - } else { - const duk_uint8_t *tmp_sp = sp; /* dummy so sp won't get updated */ - duk_codepoint_t c; - c = duk__inp_get_cp(re_ctx, &tmp_sp); - w2 = duk_unicode_re_is_wordchar(c); - } - - if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) { - if (w1 == w2) { - goto fail; - } - } else { - DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY); - if (w1 != w2) { - goto fail; - } - } - break; - } - case DUK_REOP_JUMP: { - duk_int32_t skip; - - skip = duk__bc_get_i32(re_ctx, &pc); - pc += skip; - break; - } - case DUK_REOP_SPLIT1: { - /* split1: prefer direct execution (no jump) */ - const duk_uint8_t *sub_sp; - duk_int32_t skip; - - skip = duk__bc_get_i32(re_ctx, &pc); - sub_sp = duk__match_regexp(re_ctx, pc, sp); - if (sub_sp) { - sp = sub_sp; - goto match; - } - pc += skip; - break; - } - case DUK_REOP_SPLIT2: { - /* split2: prefer jump execution (not direct) */ - const duk_uint8_t *sub_sp; - duk_int32_t skip; - - skip = duk__bc_get_i32(re_ctx, &pc); - sub_sp = duk__match_regexp(re_ctx, pc + skip, sp); - if (sub_sp) { - sp = sub_sp; - goto match; - } - break; - } - case DUK_REOP_SQMINIMAL: { - duk_uint32_t q, qmin, qmax; - duk_int32_t skip; - const duk_uint8_t *sub_sp; - - qmin = duk__bc_get_u32(re_ctx, &pc); - qmax = duk__bc_get_u32(re_ctx, &pc); - skip = duk__bc_get_i32(re_ctx, &pc); - DUK_DDD(DUK_DDDPRINT("minimal quantifier, qmin=%lu, qmax=%lu, skip=%ld", - (unsigned long) qmin, (unsigned long) qmax, (long) skip)); - - q = 0; - while (q <= qmax) { - if (q >= qmin) { - sub_sp = duk__match_regexp(re_ctx, pc + skip, sp); - if (sub_sp) { - sp = sub_sp; - goto match; - } - } - sub_sp = duk__match_regexp(re_ctx, pc, sp); - if (!sub_sp) { - break; - } - sp = sub_sp; - q++; - } - goto fail; - } - case DUK_REOP_SQGREEDY: { - duk_uint32_t q, qmin, qmax, atomlen; - duk_int32_t skip; - const duk_uint8_t *sub_sp; - - qmin = duk__bc_get_u32(re_ctx, &pc); - qmax = duk__bc_get_u32(re_ctx, &pc); - atomlen = duk__bc_get_u32(re_ctx, &pc); - skip = duk__bc_get_i32(re_ctx, &pc); - DUK_DDD(DUK_DDDPRINT("greedy quantifier, qmin=%lu, qmax=%lu, atomlen=%lu, skip=%ld", - (unsigned long) qmin, (unsigned long) qmax, (unsigned long) atomlen, (long) skip)); - - q = 0; - while (q < qmax) { - sub_sp = duk__match_regexp(re_ctx, pc, sp); - if (!sub_sp) { - break; - } - sp = sub_sp; - q++; - } - while (q >= qmin) { - sub_sp = duk__match_regexp(re_ctx, pc + skip, sp); - if (sub_sp) { - sp = sub_sp; - goto match; - } - if (q == qmin) { - break; - } - - /* Note: if atom were to contain e.g. captures, we would need to - * re-match the atom to get correct captures. Simply quantifiers - * do not allow captures in their atom now, so this is not an issue. - */ - - DUK_DDD(DUK_DDDPRINT("greedy quantifier, backtrack %ld characters (atomlen)", - (long) atomlen)); - sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen); - q--; - } - goto fail; - } - case DUK_REOP_SAVE: { - duk_uint32_t idx; - const duk_uint8_t *old; - const duk_uint8_t *sub_sp; - - idx = duk__bc_get_u32(re_ctx, &pc); - if (idx >= re_ctx->nsaved) { - /* idx is unsigned, < 0 check is not necessary */ - DUK_D(DUK_DPRINT("internal error, regexp save index insane: idx=%ld", (long) idx)); - goto internal_error; - } - old = re_ctx->saved[idx]; - re_ctx->saved[idx] = sp; - sub_sp = duk__match_regexp(re_ctx, pc, sp); - if (sub_sp) { - sp = sub_sp; - goto match; - } - re_ctx->saved[idx] = old; - goto fail; - } - case DUK_REOP_WIPERANGE: { - /* Wipe capture range and save old values for backtracking. - * - * XXX: this typically happens with a relatively small idx_count. - * It might be useful to handle cases where the count is small - * (say <= 8) by saving the values in stack instead. This would - * reduce memory churn and improve performance, at the cost of a - * slightly higher code footprint. - */ - duk_uint32_t idx_start, idx_count; -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - duk_uint32_t idx_end, idx; -#endif - duk_uint8_t **range_save; - const duk_uint8_t *sub_sp; - - idx_start = duk__bc_get_u32(re_ctx, &pc); - idx_count = duk__bc_get_u32(re_ctx, &pc); - DUK_DDD(DUK_DDDPRINT("wipe saved range: start=%ld, count=%ld -> [%ld,%ld] (captures [%ld,%ld])", - (long) idx_start, (long) idx_count, - (long) idx_start, (long) (idx_start + idx_count - 1), - (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2))); - if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) { - /* idx is unsigned, < 0 check is not necessary */ - DUK_D(DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%ld, idx_count=%ld", - (long) idx_start, (long) idx_count)); - goto internal_error; - } - DUK_ASSERT(idx_count > 0); - - duk_require_stack(re_ctx->thr, 1); - range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr, - sizeof(duk_uint8_t *) * idx_count); - DUK_ASSERT(range_save != NULL); - DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - idx_end = idx_start + idx_count; - for (idx = idx_start; idx < idx_end; idx++) { - re_ctx->saved[idx] = NULL; - } -#else - DUK_MEMZERO((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count); -#endif - - sub_sp = duk__match_regexp(re_ctx, pc, sp); - if (sub_sp) { - /* match: keep wiped/resaved values */ - DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])", - (long) idx_start, (long) (idx_start + idx_count - 1), - (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2))); - duk_pop_unsafe(re_ctx->thr); - sp = sub_sp; - goto match; - } - - /* fail: restore saves */ - DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])", - (long) idx_start, (long) (idx_start + idx_count - 1), - (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2))); - DUK_MEMCPY((void *) (re_ctx->saved + idx_start), - (const void *) range_save, - sizeof(duk_uint8_t *) * idx_count); - duk_pop_unsafe(re_ctx->thr); - goto fail; - } - case DUK_REOP_LOOKPOS: - case DUK_REOP_LOOKNEG: { - /* - * Needs a save of multiple saved[] entries depending on what range - * may be overwritten. Because the regexp parser does no such analysis, - * we currently save the entire saved array here. Lookaheads are thus - * a bit expensive. Note that the saved array is not needed for just - * the lookahead sub-match, but for the matching of the entire sequel. - * - * The temporary save buffer is pushed on to the valstack to handle - * errors correctly. Each lookahead causes a C recursion and pushes - * more stuff on the value stack. If the C recursion limit is less - * than the value stack slack, there is no need to check the stack. - * We do so regardless, just in case. - */ - - duk_int32_t skip; - duk_uint8_t **full_save; - const duk_uint8_t *sub_sp; - - DUK_ASSERT(re_ctx->nsaved > 0); - - duk_require_stack(re_ctx->thr, 1); - full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr, - sizeof(duk_uint8_t *) * re_ctx->nsaved); - DUK_ASSERT(full_save != NULL); - DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved); - - skip = duk__bc_get_i32(re_ctx, &pc); - sub_sp = duk__match_regexp(re_ctx, pc, sp); - if (op == DUK_REOP_LOOKPOS) { - if (!sub_sp) { - goto lookahead_fail; - } - } else { - if (sub_sp) { - goto lookahead_fail; - } - } - sub_sp = duk__match_regexp(re_ctx, pc + skip, sp); - if (sub_sp) { - /* match: keep saves */ - duk_pop_unsafe(re_ctx->thr); - sp = sub_sp; - goto match; - } - - /* fall through */ - - lookahead_fail: - /* fail: restore saves */ - DUK_MEMCPY((void *) re_ctx->saved, - (const void *) full_save, - sizeof(duk_uint8_t *) * re_ctx->nsaved); - duk_pop_unsafe(re_ctx->thr); - goto fail; - } - case DUK_REOP_BACKREFERENCE: { - /* - * Byte matching for back-references would be OK in case- - * sensitive matching. In case-insensitive matching we need - * to canonicalize characters, so back-reference matching needs - * to be done with codepoints instead. So, we just decode - * everything normally here, too. - * - * Note: back-reference index which is 0 or higher than - * NCapturingParens (= number of capturing parens in the - * -entire- regexp) is a compile time error. However, a - * backreference referring to a valid capture which has - * not matched anything always succeeds! See E5 Section - * 15.10.2.9, step 5, sub-step 3. - */ - duk_uint32_t idx; - const duk_uint8_t *p; - - idx = duk__bc_get_u32(re_ctx, &pc); - idx = idx << 1; /* backref n -> saved indices [n*2, n*2+1] */ - if (idx < 2 || idx + 1 >= re_ctx->nsaved) { - /* regexp compiler should catch these */ - DUK_D(DUK_DPRINT("internal error, backreference index insane")); - goto internal_error; - } - if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) { - /* capture is 'undefined', always matches! */ - DUK_DDD(DUK_DDDPRINT("backreference: saved[%ld,%ld] not complete, always match", - (long) idx, (long) (idx + 1))); - break; - } - DUK_DDD(DUK_DDDPRINT("backreference: match saved[%ld,%ld]", (long) idx, (long) (idx + 1))); - - p = re_ctx->saved[idx]; - while (p < re_ctx->saved[idx+1]) { - duk_codepoint_t c1, c2; - - /* Note: not necessary to check p against re_ctx->input_end: - * the memory access is checked by duk__inp_get_cp(), while - * valid compiled regexps cannot write a saved[] entry - * which points to outside the string. - */ - c1 = duk__inp_get_cp(re_ctx, &p); - DUK_ASSERT(c1 >= 0); - c2 = duk__inp_get_cp(re_ctx, &sp); - /* No need for an explicit c2 < 0 check: because c1 >= 0, - * the comparison will always fail if c2 < 0. - */ -#if 0 - if (c2 < 0) { - goto fail; - } -#endif - if (c1 != c2) { - goto fail; - } - } - break; - } - default: { - DUK_D(DUK_DPRINT("internal error, regexp opcode error: %ld", (long) op)); - goto internal_error; - } - } - } - - match: - re_ctx->recursion_depth--; - return sp; - - fail: - re_ctx->recursion_depth--; - return NULL; - - internal_error: - DUK_ERROR_INTERNAL(re_ctx->thr); - return NULL; /* never here */ -} - -/* - * Exposed matcher function which provides the semantics of RegExp.prototype.exec(). - * - * RegExp.prototype.test() has the same semantics as exec() but does not return the - * result object (which contains the matching string and capture groups). Currently - * there is no separate test() helper, so a temporary result object is created and - * discarded if test() is needed. This is intentional, to save code space. - * - * Input stack: [ ... re_obj input ] - * Output stack: [ ... result ] - */ - -DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) { - duk_re_matcher_ctx re_ctx; - duk_hobject *h_regexp; - duk_hstring *h_bytecode; - duk_hstring *h_input; - duk_uint8_t *p_buf; - const duk_uint8_t *pc; - const duk_uint8_t *sp; - duk_small_int_t match = 0; - duk_small_int_t global; - duk_uint_fast32_t i; - double d; - duk_uint32_t char_offset; - - DUK_ASSERT(thr != NULL); - - DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T", - (duk_tval *) duk_get_tval(thr, -2), - (duk_tval *) duk_get_tval(thr, -1))); - - /* - * Regexp instance check, bytecode check, input coercion. - * - * See E5 Section 15.10.6. - */ - - /* TypeError if wrong; class check, see E5 Section 15.10.6 */ - h_regexp = duk_require_hobject_with_class(thr, -2, DUK_HOBJECT_CLASS_REGEXP); - DUK_ASSERT(h_regexp != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP); - DUK_UNREF(h_regexp); - - h_input = duk_to_hstring(thr, -1); - DUK_ASSERT(h_input != NULL); - - duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */ - h_bytecode = duk_require_hstring(thr, -1); /* no regexp instance should exist without a non-configurable bytecode property */ - DUK_ASSERT(h_bytecode != NULL); - - /* - * Basic context initialization. - * - * Some init values are read from the bytecode header - * whose format is (UTF-8 codepoints): - * - * uint flags - * uint nsaved (even, 2n+2 where n = num captures) - */ - - /* [ ... re_obj input bc ] */ - - DUK_MEMZERO(&re_ctx, sizeof(re_ctx)); - - re_ctx.thr = thr; - re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); - re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input); - re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode); - re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode); - re_ctx.saved = NULL; - re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT; - re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT; - - /* read header */ - pc = re_ctx.bytecode; - re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc); - re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc); - re_ctx.bytecode = pc; - - DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */ - global = (duk_small_int_t) (force_global | (duk_small_int_t) (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL)); - - DUK_ASSERT(re_ctx.nsaved >= 2); - DUK_ASSERT((re_ctx.nsaved % 2) == 0); - - p_buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, sizeof(duk_uint8_t *) * re_ctx.nsaved); /* rely on zeroing */ - DUK_UNREF(p_buf); - re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(thr, -1, NULL); - DUK_ASSERT(re_ctx.saved != NULL); - - /* [ ... re_obj input bc saved_buf ] */ - -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - for (i = 0; i < re_ctx.nsaved; i++) { - re_ctx.saved[i] = (duk_uint8_t *) NULL; - } -#elif defined(DUK_USE_ZERO_BUFFER_DATA) - /* buffer is automatically zeroed */ -#else - DUK_MEMZERO((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved); -#endif - - DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld", - (unsigned long) re_ctx.re_flags, (long) re_ctx.nsaved, (long) re_ctx.recursion_limit, - (long) re_ctx.steps_limit)); - - /* - * Get starting character offset for match, and initialize 'sp' based on it. - * - * Note: lastIndex is non-configurable so it must be present (we check the - * internal class of the object above, so we know it is). User code can set - * its value to an arbitrary (garbage) value though; E5 requires that lastIndex - * be coerced to a number before using. The code below works even if the - * property is missing: the value will then be coerced to zero. - * - * Note: lastIndex may be outside Uint32 range even after ToInteger() coercion. - * For instance, ToInteger(+Infinity) = +Infinity. We track the match offset - * as an integer, but pre-check it to be inside the 32-bit range before the loop. - * If not, the check in E5 Section 15.10.6.2, step 9.a applies. - */ - - /* XXX: lastIndex handling produces a lot of asm */ - - /* [ ... re_obj input bc saved_buf ] */ - - duk_get_prop_stridx_short(thr, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */ - (void) duk_to_int(thr, -1); /* ToInteger(lastIndex) */ - d = duk_get_number(thr, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */ - duk_pop_nodecref_unsafe(thr); - - if (global) { - if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) { - /* match fail */ - char_offset = 0; /* not really necessary */ - DUK_ASSERT(match == 0); - goto match_over; - } - char_offset = (duk_uint32_t) d; - } else { - /* lastIndex must be ignored for non-global regexps, but get the - * value for (theoretical) side effects. No side effects can - * really occur, because lastIndex is a normal property and is - * always non-configurable for RegExp instances. - */ - char_offset = (duk_uint32_t) 0; - } - - DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input)); - sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset); - - /* - * Match loop. - * - * Try matching at different offsets until match found or input exhausted. - */ - - /* [ ... re_obj input bc saved_buf ] */ - - DUK_ASSERT(match == 0); - - for (;;) { - /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */ - DUK_ASSERT_DISABLE(char_offset >= 0); - DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input)); - - /* Note: re_ctx.steps is intentionally not reset, it applies to the entire unanchored match */ - DUK_ASSERT(re_ctx.recursion_depth == 0); - - DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]", - (long) char_offset, (const void *) sp, - (const void *) re_ctx.input, (const void *) re_ctx.input_end)); - - /* - * Note: - * - * - duk__match_regexp() is required not to longjmp() in ordinary "non-match" - * conditions; a longjmp() will terminate the entire matching process. - * - * - Clearing saved[] is not necessary because backtracking does it - * - * - Backtracking also rewinds re_ctx.recursion back to zero, unless an - * internal/limit error occurs (which causes a longjmp()) - * - * - If we supported anchored matches, we would break out here - * unconditionally; however, Ecmascript regexps don't have anchored - * matches. It might make sense to implement a fast bail-out if - * the regexp begins with '^' and sp is not 0: currently we'll just - * run through the entire input string, trivially failing the match - * at every non-zero offset. - */ - - if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) { - DUK_DDD(DUK_DDDPRINT("match at offset %ld", (long) char_offset)); - match = 1; - break; - } - - /* advance by one character (code point) and one char_offset */ - char_offset++; - if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) { - /* - * Note: - * - * - Intentionally attempt (empty) match at char_offset == k_input->clen - * - * - Negative char_offsets have been eliminated and char_offset is duk_uint32_t - * -> no need or use for a negative check - */ - - DUK_DDD(DUK_DDDPRINT("no match after trying all sp offsets")); - break; - } - - /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */ - (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1); - } - - match_over: - - /* - * Matching complete, create result array or return a 'null'. Update lastIndex - * if necessary. See E5 Section 15.10.6.2. - * - * Because lastIndex is a character (not byte) offset, we need the character - * length of the match which we conveniently get as a side effect of interning - * the matching substring (0th index of result array). - * - * saved[0] start pointer (~ byte offset) of current match - * saved[1] end pointer (~ byte offset) of current match (exclusive) - * char_offset start character offset of current match (-> .index of result) - * char_end_offset end character offset (computed below) - */ - - /* [ ... re_obj input bc saved_buf ] */ - - if (match) { -#if defined(DUK_USE_ASSERTIONS) - duk_hobject *h_res; -#endif - duk_uint32_t char_end_offset = 0; - - DUK_DDD(DUK_DDDPRINT("regexp matches at char_offset %ld", (long) char_offset)); - - DUK_ASSERT(re_ctx.nsaved >= 2); /* must have start and end */ - DUK_ASSERT((re_ctx.nsaved % 2) == 0); /* and even number */ - - /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken - * advantage of now. The array is not compacted either, as regexp match - * objects are usually short lived. - */ - - duk_push_array(thr); - -#if defined(DUK_USE_ASSERTIONS) - h_res = duk_require_hobject(thr, -1); - DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res)); - DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res)); - DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY); -#endif - - /* [ ... re_obj input bc saved_buf res_obj ] */ - - duk_push_u32(thr, char_offset); - duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INDEX); - - duk_dup_m4(thr); - duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INPUT); - - for (i = 0; i < re_ctx.nsaved; i += 2) { - /* Captures which are undefined have NULL pointers and are returned - * as 'undefined'. The same is done when saved[] pointers are insane - * (this should, of course, never happen in practice). - */ - if (re_ctx.saved[i] && re_ctx.saved[i + 1] && re_ctx.saved[i + 1] >= re_ctx.saved[i]) { - duk_push_lstring(thr, - (const char *) re_ctx.saved[i], - (duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i])); - if (i == 0) { - /* Assumes that saved[0] and saved[1] are always - * set by regexp bytecode (if not, char_end_offset - * will be zero). Also assumes clen reflects the - * correct char length. - */ - char_end_offset = char_offset + (duk_uint32_t) duk_get_length(thr, -1); /* add charlen */ - } - } else { - duk_push_undefined(thr); - } - - /* [ ... re_obj input bc saved_buf res_obj val ] */ - duk_put_prop_index(thr, -2, (duk_uarridx_t) (i / 2)); - } - - /* [ ... re_obj input bc saved_buf res_obj ] */ - - /* NB: 'length' property is automatically updated by the array setup loop */ - - if (global) { - /* global regexp: lastIndex updated on match */ - duk_push_u32(thr, char_end_offset); - duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX); - } else { - /* non-global regexp: lastIndex never updated on match */ - ; - } - } else { - /* - * No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless - * of 'global' flag of the RegExp. In particular, if lastIndex is invalid - * initially, it is reset to zero. - */ - - DUK_DDD(DUK_DDDPRINT("regexp does not match")); - - duk_push_null(thr); - - /* [ ... re_obj input bc saved_buf res_obj ] */ - - duk_push_int(thr, 0); - duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX); - } - - /* [ ... re_obj input bc saved_buf res_obj ] */ - - duk_insert(thr, -5); - - /* [ ... res_obj re_obj input bc saved_buf ] */ - - duk_pop_n_unsafe(thr, 4); - - /* [ ... res_obj ] */ - - /* XXX: these last tricks are unnecessary if the function is made - * a genuine native function. - */ -} - -DUK_INTERNAL void duk_regexp_match(duk_hthread *thr) { - duk__regexp_match_helper(thr, 0 /*force_global*/); -} - -/* This variant is needed by String.prototype.split(); it needs to perform - * global-style matching on a cloned RegExp which is potentially non-global. - */ -DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) { - duk__regexp_match_helper(thr, 1 /*force_global*/); -} - -#else /* DUK_USE_REGEXP_SUPPORT */ - -/* regexp support disabled */ - -#endif /* DUK_USE_REGEXP_SUPPORT */ -#line 1 "duk_selftest.c" -/* - * Self tests to ensure execution environment is sane. Intended to catch - * compiler/platform problems which cannot be detected at compile time. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_SELF_TESTS) - -/* - * Unions and structs for self tests - */ - -typedef union { - double d; - duk_uint8_t x[8]; -} duk__test_double_union; - -/* Self test failed. Expects a local variable 'error_count' to exist. */ -#define DUK__FAILED(msg) do { \ - DUK_D(DUK_DPRINT("self test failed: " #msg " at " DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO))); \ - error_count++; \ - } while (0) - -#define DUK__DBLUNION_CMP_TRUE(a,b) do { \ - if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \ - DUK__FAILED("double union compares false (expected true)"); \ - } \ - } while (0) - -#define DUK__DBLUNION_CMP_FALSE(a,b) do { \ - if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \ - DUK__FAILED("double union compares true (expected false)"); \ - } \ - } while (0) - -typedef union { - duk_uint32_t i; - duk_uint8_t x[8]; -} duk__test_u32_union; - -#if defined(DUK_USE_INTEGER_LE) -#define DUK__U32_INIT(u, a, b, c, d) do { \ - (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \ - } while (0) -#elif defined(DUK_USE_INTEGER_ME) -#error integer mixed endian not supported now -#elif defined(DUK_USE_INTEGER_BE) -#define DUK__U32_INIT(u, a, b, c, d) do { \ - (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \ - } while (0) -#else -#error unknown integer endianness -#endif - -#if defined(DUK_USE_DOUBLE_LE) -#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \ - (u)->x[0] = (h); (u)->x[1] = (g); (u)->x[2] = (f); (u)->x[3] = (e); \ - (u)->x[4] = (d); (u)->x[5] = (c); (u)->x[6] = (b); (u)->x[7] = (a); \ - } while (0) -#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \ - ((u)->x[0] == (h) && (u)->x[1] == (g) && (u)->x[2] == (f) && (u)->x[3] == (e) && \ - (u)->x[4] == (d) && (u)->x[5] == (c) && (u)->x[6] == (b) && (u)->x[7] == (a)) -#elif defined(DUK_USE_DOUBLE_ME) -#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \ - (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \ - (u)->x[4] = (h); (u)->x[5] = (g); (u)->x[6] = (f); (u)->x[7] = (e); \ - } while (0) -#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \ - ((u)->x[0] == (d) && (u)->x[1] == (c) && (u)->x[2] == (b) && (u)->x[3] == (a) && \ - (u)->x[4] == (h) && (u)->x[5] == (g) && (u)->x[6] == (f) && (u)->x[7] == (e)) -#elif defined(DUK_USE_DOUBLE_BE) -#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \ - (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \ - (u)->x[4] = (e); (u)->x[5] = (f); (u)->x[6] = (g); (u)->x[7] = (h); \ - } while (0) -#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \ - ((u)->x[0] == (a) && (u)->x[1] == (b) && (u)->x[2] == (c) && (u)->x[3] == (d) && \ - (u)->x[4] == (e) && (u)->x[5] == (f) && (u)->x[6] == (g) && (u)->x[7] == (h)) -#else -#error unknown double endianness -#endif - -/* - * Various sanity checks for typing - */ - -DUK_LOCAL duk_uint_t duk__selftest_types(void) { - duk_uint_t error_count = 0; - - if (!(sizeof(duk_int8_t) == 1 && - sizeof(duk_uint8_t) == 1 && - sizeof(duk_int16_t) == 2 && - sizeof(duk_uint16_t) == 2 && - sizeof(duk_int32_t) == 4 && - sizeof(duk_uint32_t) == 4)) { - DUK__FAILED("duk_(u)int{8,16,32}_t size"); - } -#if defined(DUK_USE_64BIT_OPS) - if (!(sizeof(duk_int64_t) == 8 && - sizeof(duk_uint64_t) == 8)) { - DUK__FAILED("duk_(u)int64_t size"); - } -#endif - - if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) { - /* Some internal code now assumes that all duk_uint_t values - * can be expressed with a duk_size_t. - */ - DUK__FAILED("duk_size_t is smaller than duk_uint_t"); - } - if (!(sizeof(duk_int_t) >= 4)) { - DUK__FAILED("duk_int_t is not 32 bits"); - } - - return error_count; -} - -/* - * Packed tval sanity - */ - -DUK_LOCAL duk_uint_t duk__selftest_packed_tval(void) { - duk_uint_t error_count = 0; - -#if defined(DUK_USE_PACKED_TVAL) - if (sizeof(void *) > 4) { - DUK__FAILED("packed duk_tval in use but sizeof(void *) > 4"); - } -#endif - - return error_count; -} - -/* - * Two's complement arithmetic. - */ - -DUK_LOCAL duk_uint_t duk__selftest_twos_complement(void) { - duk_uint_t error_count = 0; - volatile int test; - test = -1; - - /* Note that byte order doesn't affect this test: all bytes in - * 'test' will be 0xFF for two's complement. - */ - if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) { - DUK__FAILED("two's complement arithmetic"); - } - - return error_count; -} - -/* - * Byte order. Important to self check, because on some exotic platforms - * there is no actual detection but rather assumption based on platform - * defines. - */ - -DUK_LOCAL duk_uint_t duk__selftest_byte_order(void) { - duk_uint_t error_count = 0; - duk__test_u32_union u1; - duk__test_double_union u2; - - /* - * >>> struct.pack('>d', 102030405060).encode('hex') - * '4237c17c6dc40000' - */ - - DUK__U32_INIT(&u1, 0xde, 0xad, 0xbe, 0xef); - DUK__DOUBLE_INIT(&u2, 0x42, 0x37, 0xc1, 0x7c, 0x6d, 0xc4, 0x00, 0x00); - - if (u1.i != (duk_uint32_t) 0xdeadbeefUL) { - DUK__FAILED("duk_uint32_t byte order"); - } - - if (u2.d != (double) 102030405060.0) { - DUK__FAILED("double byte order"); - } - - return error_count; -} - -/* - * DUK_BSWAP macros - */ - -DUK_LOCAL duk_uint_t duk__selftest_bswap_macros(void) { - duk_uint_t error_count = 0; - duk_uint32_t x32; - duk_uint16_t x16; - duk_double_union du; - duk_double_t du_diff; - - x16 = 0xbeefUL; - x16 = DUK_BSWAP16(x16); - if (x16 != (duk_uint16_t) 0xefbeUL) { - DUK__FAILED("DUK_BSWAP16"); - } - - x32 = 0xdeadbeefUL; - x32 = DUK_BSWAP32(x32); - if (x32 != (duk_uint32_t) 0xefbeaddeUL) { - DUK__FAILED("DUK_BSWAP32"); - } - - /* >>> struct.unpack('>d', '4000112233445566'.decode('hex')) - * (2.008366013071895,) - */ - - du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22; - du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66; - DUK_DBLUNION_DOUBLE_NTOH(&du); - du_diff = du.d - 2.008366013071895; -#if 0 - DUK_D(DUK_DPRINT("du_diff: %lg\n", (double) du_diff)); -#endif - if (du_diff > 1e-15) { - /* Allow very small lenience because some compilers won't parse - * exact IEEE double constants (happened in matrix testing with - * Linux gcc-4.8 -m32 at least). - */ -#if 0 - DUK_D(DUK_DPRINT("Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n", - (unsigned int) du.uc[0], (unsigned int) du.uc[1], - (unsigned int) du.uc[2], (unsigned int) du.uc[3], - (unsigned int) du.uc[4], (unsigned int) du.uc[5], - (unsigned int) du.uc[6], (unsigned int) du.uc[7])); -#endif - DUK__FAILED("DUK_DBLUNION_DOUBLE_NTOH"); - } - - return error_count; -} - -/* - * Basic double / byte union memory layout. - */ - -DUK_LOCAL duk_uint_t duk__selftest_double_union_size(void) { - duk_uint_t error_count = 0; - - if (sizeof(duk__test_double_union) != 8) { - DUK__FAILED("invalid union size"); - } - - return error_count; -} - -/* - * Union aliasing, see misc/clang_aliasing.c. - */ - -DUK_LOCAL duk_uint_t duk__selftest_double_aliasing(void) { - /* This testcase fails when Emscripten-generated code runs on Firefox. - * It's not an issue because the failure should only affect packed - * duk_tval representation, which is not used with Emscripten. - */ -#if defined(DUK_USE_PACKED_TVAL) - duk_uint_t error_count = 0; - duk__test_double_union a, b; - - /* Test signaling NaN and alias assignment in all endianness combinations. - */ - - /* little endian */ - a.x[0] = 0x11; a.x[1] = 0x22; a.x[2] = 0x33; a.x[3] = 0x44; - a.x[4] = 0x00; a.x[5] = 0x00; a.x[6] = 0xf1; a.x[7] = 0xff; - b = a; - DUK__DBLUNION_CMP_TRUE(&a, &b); - - /* big endian */ - a.x[0] = 0xff; a.x[1] = 0xf1; a.x[2] = 0x00; a.x[3] = 0x00; - a.x[4] = 0x44; a.x[5] = 0x33; a.x[6] = 0x22; a.x[7] = 0x11; - b = a; - DUK__DBLUNION_CMP_TRUE(&a, &b); - - /* mixed endian */ - a.x[0] = 0x00; a.x[1] = 0x00; a.x[2] = 0xf1; a.x[3] = 0xff; - a.x[4] = 0x11; a.x[5] = 0x22; a.x[6] = 0x33; a.x[7] = 0x44; - b = a; - DUK__DBLUNION_CMP_TRUE(&a, &b); - - return error_count; -#else - DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed")); - return 0; -#endif -} - -/* - * Zero sign, see misc/tcc_zerosign2.c. - */ - -DUK_LOCAL duk_uint_t duk__selftest_double_zero_sign(void) { - duk_uint_t error_count = 0; - duk__test_double_union a, b; - - a.d = 0.0; - b.d = -a.d; - DUK__DBLUNION_CMP_FALSE(&a, &b); - - return error_count; -} - -/* - * Rounding mode: Duktape assumes round-to-nearest, check that this is true. - * If we had C99 fenv.h we could check that fegetround() == FE_TONEAREST, - * but we don't want to rely on that header; and even if we did, it's good - * to ensure the rounding actually works. - */ - -DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) { - duk_uint_t error_count = 0; - duk__test_double_union a, b, c; - -#if 0 - /* Include and test manually; these trigger failures: */ - fesetround(FE_UPWARD); - fesetround(FE_DOWNWARD); - fesetround(FE_TOWARDZERO); - - /* This is the default and passes. */ - fesetround(FE_TONEAREST); -#endif - - /* Rounding tests check that none of the other modes (round to - * +Inf, round to -Inf, round to zero) can be active: - * http://www.gnu.org/software/libc/manual/html_node/Rounding.html - */ - - /* 1.0 + 2^(-53): result is midway between 1.0 and 1.0 + ulp. - * Round to nearest: 1.0 - * Round to +Inf: 1.0 + ulp - * Round to -Inf: 1.0 - * Round to zero: 1.0 - * => Correct result eliminates round to +Inf. - */ - DUK__DOUBLE_INIT(&a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - DUK_MEMSET((void *) &c, 0, sizeof(c)); - c.d = a.d + b.d; - if (!DUK__DOUBLE_COMPARE(&c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)) { - DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x", - (unsigned int) c.x[0], (unsigned int) c.x[1], - (unsigned int) c.x[2], (unsigned int) c.x[3], - (unsigned int) c.x[4], (unsigned int) c.x[5], - (unsigned int) c.x[6], (unsigned int) c.x[7])); - DUK__FAILED("invalid result from 1.0 + 0.5ulp"); - } - - /* (1.0 + ulp) + 2^(-53): result is midway between 1.0 + ulp and 1.0 + 2*ulp. - * Round to nearest: 1.0 + 2*ulp (round to even mantissa) - * Round to +Inf: 1.0 + 2*ulp - * Round to -Inf: 1.0 + ulp - * Round to zero: 1.0 + ulp - * => Correct result eliminates round to -Inf and round to zero. - */ - DUK__DOUBLE_INIT(&a, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01); - DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - DUK_MEMSET((void *) &c, 0, sizeof(c)); - c.d = a.d + b.d; - if (!DUK__DOUBLE_COMPARE(&c, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02)) { - DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x", - (unsigned int) c.x[0], (unsigned int) c.x[1], - (unsigned int) c.x[2], (unsigned int) c.x[3], - (unsigned int) c.x[4], (unsigned int) c.x[5], - (unsigned int) c.x[6], (unsigned int) c.x[7])); - DUK__FAILED("invalid result from (1.0 + ulp) + 0.5ulp"); - } - - /* Could do negative number testing too, but the tests above should - * differentiate between IEEE 754 rounding modes. - */ - return error_count; -} - -/* - * fmod(): often a portability issue in embedded or bare platform targets. - * Check for at least minimally correct behavior. Unlike some other math - * functions (like cos()) Duktape relies on fmod() internally too. - */ - -DUK_LOCAL duk_uint_t duk__selftest_fmod(void) { - duk_uint_t error_count = 0; - duk__test_double_union u1, u2; - volatile duk_double_t t1, t2, t3; - - /* fmod() with integer argument and exponent 2^32 is used by e.g. - * ToUint32() and some Duktape internals. - */ - u1.d = DUK_FMOD(10.0, 4294967296.0); - u2.d = 10.0; - DUK__DBLUNION_CMP_TRUE(&u1, &u2); - - u1.d = DUK_FMOD(4294967306.0, 4294967296.0); - u2.d = 10.0; - DUK__DBLUNION_CMP_TRUE(&u1, &u2); - - u1.d = DUK_FMOD(73014444042.0, 4294967296.0); - u2.d = 10.0; - DUK__DBLUNION_CMP_TRUE(&u1, &u2); - - /* 52-bit integer split into two parts: - * >>> 0x1fedcba9876543 - * 8987183256397123 - * >>> float(0x1fedcba9876543) / float(2**53) - * 0.9977777777777778 - */ - u1.d = DUK_FMOD(8987183256397123.0, 4294967296.0); - u2.d = (duk_double_t) 0xa9876543UL; - DUK__DBLUNION_CMP_TRUE(&u1, &u2); - t1 = 8987183256397123.0; - t2 = 4294967296.0; - t3 = t1 / t2; - u1.d = DUK_FLOOR(t3); - u2.d = (duk_double_t) 0x1fedcbUL; - DUK__DBLUNION_CMP_TRUE(&u1, &u2); - - /* C99 behavior is for fmod() result sign to mathc argument sign. */ - u1.d = DUK_FMOD(-10.0, 4294967296.0); - u2.d = -10.0; - DUK__DBLUNION_CMP_TRUE(&u1, &u2); - - u1.d = DUK_FMOD(-4294967306.0, 4294967296.0); - u2.d = -10.0; - DUK__DBLUNION_CMP_TRUE(&u1, &u2); - - u1.d = DUK_FMOD(-73014444042.0, 4294967296.0); - u2.d = -10.0; - DUK__DBLUNION_CMP_TRUE(&u1, &u2); - - return error_count; -} - -/* - * Struct size/alignment if platform requires it - * - * There are some compiler specific struct padding pragmas etc in use, this - * selftest ensures they're correctly detected and used. - */ - -DUK_LOCAL duk_uint_t duk__selftest_struct_align(void) { - duk_uint_t error_count = 0; - -#if (DUK_USE_ALIGN_BY == 4) - if ((sizeof(duk_hbuffer_fixed) % 4) != 0) { - DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 4"); - } -#elif (DUK_USE_ALIGN_BY == 8) - if ((sizeof(duk_hbuffer_fixed) % 8) != 0) { - DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 8"); - } -#elif (DUK_USE_ALIGN_BY == 1) - /* no check */ -#else -#error invalid DUK_USE_ALIGN_BY -#endif - return error_count; -} - -/* - * 64-bit arithmetic - * - * There are some platforms/compilers where 64-bit types are available - * but don't work correctly. Test for known cases. - */ - -DUK_LOCAL duk_uint_t duk__selftest_64bit_arithmetic(void) { - duk_uint_t error_count = 0; -#if defined(DUK_USE_64BIT_OPS) - volatile duk_int64_t i; - volatile duk_double_t d; - - /* Catch a double-to-int64 cast issue encountered in practice. */ - d = 2147483648.0; - i = (duk_int64_t) d; - if (i != DUK_I64_CONSTANT(0x80000000)) { - DUK__FAILED("casting 2147483648.0 to duk_int64_t failed"); - } -#else - /* nop */ -#endif - return error_count; -} - -/* - * Casting - */ - -DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_small_uint(void) { - /* - * https://github.com/svaarala/duktape/issues/127#issuecomment-77863473 - */ - - duk_uint_t error_count = 0; - - duk_double_t d1, d2; - duk_small_uint_t u; - - duk_double_t d1v, d2v; - duk_small_uint_t uv; - - /* Test without volatiles */ - - d1 = 1.0; - u = (duk_small_uint_t) d1; - d2 = (duk_double_t) u; - - if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) { - DUK__FAILED("double to duk_small_uint_t cast failed"); - } - - /* Same test with volatiles */ - - d1v = 1.0; - uv = (duk_small_uint_t) d1v; - d2v = (duk_double_t) uv; - - if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) { - DUK__FAILED("double to duk_small_uint_t cast failed"); - } - - return error_count; -} - -DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_uint32(void) { - /* - * This test fails on an exotic ARM target; double-to-uint - * cast is incorrectly clamped to -signed- int highest value. - * - * https://github.com/svaarala/duktape/issues/336 - */ - - duk_uint_t error_count = 0; - duk_double_t dv; - duk_uint32_t uv; - - dv = 3735928559.0; /* 0xdeadbeef in decimal */ - uv = (duk_uint32_t) dv; - - if (uv != 0xdeadbeefUL) { - DUK__FAILED("double to duk_uint32_t cast failed"); - } - - return error_count; -} - -/* - * Minimal test of user supplied allocation functions - * - * - Basic alloc + realloc + free cycle - * - * - Realloc to significantly larger size to (hopefully) trigger a - * relocation and check that relocation copying works - */ - -DUK_LOCAL duk_uint_t duk__selftest_alloc_funcs(duk_alloc_function alloc_func, - duk_realloc_function realloc_func, - duk_free_function free_func, - void *udata) { - duk_uint_t error_count = 0; - void *ptr; - void *new_ptr; - duk_small_int_t i, j; - unsigned char x; - - if (alloc_func == NULL || realloc_func == NULL || free_func == NULL) { - return 0; - } - - for (i = 1; i <= 256; i++) { - ptr = alloc_func(udata, (duk_size_t) i); - if (ptr == NULL) { - DUK_D(DUK_DPRINT("alloc failed, ignore")); - continue; /* alloc failed, ignore */ - } - for (j = 0; j < i; j++) { - ((unsigned char *) ptr)[j] = (unsigned char) (0x80 + j); - } - new_ptr = realloc_func(udata, ptr, 1024); - if (new_ptr == NULL) { - DUK_D(DUK_DPRINT("realloc failed, ignore")); - free_func(udata, ptr); - continue; /* realloc failed, ignore */ - } - ptr = new_ptr; - for (j = 0; j < i; j++) { - x = ((unsigned char *) ptr)[j]; - if (x != (unsigned char) (0x80 + j)) { - DUK_D(DUK_DPRINT("byte at index %ld doesn't match after realloc: %02lx", - (long) j, (unsigned long) x)); - DUK__FAILED("byte compare after realloc"); - break; - } - } - free_func(udata, ptr); - } - - return error_count; -} - -/* - * Self test main - */ - -DUK_INTERNAL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func, - duk_realloc_function realloc_func, - duk_free_function free_func, - void *udata) { - duk_uint_t error_count = 0; - - DUK_D(DUK_DPRINT("self test starting")); - - error_count += duk__selftest_types(); - error_count += duk__selftest_packed_tval(); - error_count += duk__selftest_twos_complement(); - error_count += duk__selftest_byte_order(); - error_count += duk__selftest_bswap_macros(); - error_count += duk__selftest_double_union_size(); - error_count += duk__selftest_double_aliasing(); - error_count += duk__selftest_double_zero_sign(); - error_count += duk__selftest_double_rounding(); - error_count += duk__selftest_fmod(); - error_count += duk__selftest_struct_align(); - error_count += duk__selftest_64bit_arithmetic(); - error_count += duk__selftest_cast_double_to_small_uint(); - error_count += duk__selftest_cast_double_to_uint32(); - error_count += duk__selftest_alloc_funcs(alloc_func, realloc_func, free_func, udata); - - DUK_D(DUK_DPRINT("self test complete, total error count: %ld", (long) error_count)); - - return error_count; -} - -#endif /* DUK_USE_SELF_TESTS */ - -/* automatic undefs */ -#undef DUK__DBLUNION_CMP_FALSE -#undef DUK__DBLUNION_CMP_TRUE -#undef DUK__DOUBLE_COMPARE -#undef DUK__DOUBLE_INIT -#undef DUK__FAILED -#undef DUK__U32_INIT -/* #include duk_internal.h -> already included */ -#line 2 "duk_tval.c" - -#if defined(DUK_USE_FASTINT) - -/* - * Manually optimized double-to-fastint downgrade check. - * - * This check has a large impact on performance, especially for fastint - * slow paths, so must be changed carefully. The code should probably be - * optimized for the case where the result does not fit into a fastint, - * to minimize the penalty for "slow path code" dealing with fractions etc. - * - * At least on one tested soft float ARM platform double-to-int64 coercion - * is very slow (and sometimes produces incorrect results, see self tests). - * This algorithm combines a fastint compatibility check and extracting the - * integer value from an IEEE double for setting the tagged fastint. For - * other platforms a more naive approach might be better. - * - * See doc/fastint.rst for details. - */ - -DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x) { - duk_double_union du; - duk_int64_t i; - duk_small_int_t expt; - duk_small_int_t shift; - - /* XXX: optimize for packed duk_tval directly? */ - - du.d = x; - i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du); - expt = (duk_small_int_t) ((i >> 52) & 0x07ff); - shift = expt - 1023; - - if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */ - duk_int64_t t; - - if (((DUK_I64_CONSTANT(0x000fffffffffffff) >> shift) & i) == 0) { - t = i | DUK_I64_CONSTANT(0x0010000000000000); /* implicit leading one */ - t = t & DUK_I64_CONSTANT(0x001fffffffffffff); - t = t >> (52 - shift); - if (i < 0) { - t = -t; - } - DUK_TVAL_SET_FASTINT(tv, t); - return; - } - } else if (shift == -1023) { /* exponent 0 */ - if (i >= 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) { - /* Note: reject negative zero. */ - DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0); - return; - } - } else if (shift == 47) { /* exponent 1070 */ - if (i < 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) { - DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN); - return; - } - } - - DUK_TVAL_SET_DOUBLE(tv, x); - return; -} - -DUK_INTERNAL DUK_NOINLINE void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x) { - duk_tval_set_number_chkfast_fast(tv, x); -} - -/* - * Manually optimized number-to-double conversion - */ - -#if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL) -DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) { - duk_double_union du; - duk_uint64_t t; - - t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv); - if ((t >> 48) != DUK_TAG_FASTINT) { - return tv->d; - } else if (t & DUK_U64_CONSTANT(0x0000800000000000)) { - t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */ - t = t & DUK_U64_CONSTANT(0x0000ffffffffffff); /* negative */ - t |= DUK_U64_CONSTANT(0xc330000000000000); - DUK_DBLUNION_SET_UINT64(&du, t); - return du.d + 4503599627370496.0; /* 1 << 52 */ - } else if (t != 0) { - t &= DUK_U64_CONSTANT(0x0000ffffffffffff); /* positive */ - t |= DUK_U64_CONSTANT(0x4330000000000000); - DUK_DBLUNION_SET_UINT64(&du, t); - return du.d - 4503599627370496.0; /* 1 << 52 */ - } else { - return 0.0; /* zero */ - } -} -#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */ - -#if 0 /* unused */ -#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL) -DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) { - duk_double_union du; - duk_uint64_t t; - - DUK_ASSERT(tv->t == DUK_TAG_NUMBER || tv->t == DUK_TAG_FASTINT); - - if (tv->t == DUK_TAG_FASTINT) { - if (tv->v.fi >= 0) { - t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi; - DUK_DBLUNION_SET_UINT64(&du, t); - return du.d - 4503599627370496.0; /* 1 << 52 */ - } else { - t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi); - DUK_DBLUNION_SET_UINT64(&du, t); - return du.d + 4503599627370496.0; /* 1 << 52 */ - } - } else { - return tv->v.d; - } -} -#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */ -#endif /* 0 */ - -#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL) -DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) { - duk_double_union du; - duk_uint64_t t; - - DUK_ASSERT(tv->t == DUK_TAG_FASTINT); - - if (tv->v.fi >= 0) { - t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi; - DUK_DBLUNION_SET_UINT64(&du, t); - return du.d - 4503599627370496.0; /* 1 << 52 */ - } else { - t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi); - DUK_DBLUNION_SET_UINT64(&du, t); - return du.d + 4503599627370496.0; /* 1 << 52 */ - } -} -#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */ - -#endif /* DUK_USE_FASTINT */ -#line 1 "duk_unicode_tables.c" -/* - * Unicode support tables automatically generated during build. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Unicode tables containing ranges of Unicode characters in a - * packed format. These tables are used to match non-ASCII - * characters of complex productions by resorting to a linear - * range-by-range comparison. This is very slow, but is expected - * to be very rare in practical Ecmascript source code, and thus - * compactness is most important. - * - * The tables are matched using uni_range_match() and the format - * is described in tools/extract_chars.py. - */ - -#if defined(DUK_USE_SOURCE_NONBMP) -/* IdentifierStart production with ASCII excluded */ -/* duk_unicode_ids_noa[] */ -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -const duk_uint8_t duk_unicode_ids_noa[1036] = { -249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34, -2,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191, -21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240, -101,10,4,15,9,240,159,57,240,82,127,56,242,100,15,4,8,159,1,240,5,115,19, -240,98,98,4,52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47, -2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,18, -47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,12, -38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,6, -41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98, -34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2, -85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35, -63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227, -240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5, -15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40, -240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27, -43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,32,47, -15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,68, -112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,52, -29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,12, -146,240,184,132,52,95,70,114,47,74,35,111,25,79,78,240,63,11,242,127,0,255, -224,244,255,240,0,138,143,60,255,240,4,12,143,28,255,227,127,243,95,30,63, -253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,243,26,34, -35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,143,31, -240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32, -240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,223,7, -95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245, -207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10, -207,73,69,53,53,50,241,91,47,10,47,3,33,46,61,241,79,107,243,127,37,255, -223,13,79,33,242,31,16,240,47,11,111,22,191,14,63,20,87,36,241,207,142,240, -79,20,95,20,95,24,159,36,248,239,254,2,154,240,107,127,138,83,2,241,194,20, -3,240,123,240,122,240,255,51,240,50,27,240,107,240,175,56,242,135,31,50,15, -1,50,34,240,191,30,240,212,240,223,21,114,240,207,13,242,107,240,107,240, -62,240,47,96,243,159,41,242,62,242,63,254,32,79,37,243,223,29,241,47,9,240, -207,20,241,191,19,64,223,32,240,3,240,112,32,241,95,2,47,9,244,102,32,35, -46,41,143,31,241,135,49,63,6,38,33,36,64,240,64,212,249,15,37,240,67,242, -127,32,240,97,32,250,175,31,241,179,241,111,32,240,96,242,223,27,244,127, -10,255,224,122,243,15,17,15,254,11,79,41,255,152,47,21,240,48,242,63,14, -255,226,100,255,226,140,245,143,95,240,63,180,255,233,176,255,227,33,255, -238,197,255,225,57,255,240,1,10,223,254,18,184,240,255,99,240,239,4,242,15, -2,63,17,240,86,240,63,254,38,79,53,192,243,76,243,32,241,31,255,0,6,223, -240,95,254,30,95,255,0,20,1,31,254,175,47,91,108,72,137,255,240,0,101,175, -69,47,55,33,48,49,51,43,32,38,47,49,35,55,38,47,12,35,36,32,70,47,254,4,99, -240,146,240,146,240,242,240,146,240,242,240,146,240,242,240,146,240,242, -240,146,127,254,242,143,181,242,223,52,255,227,176,50,240,178,18,3,2,146, -50,2,7,5,2,2,2,34,18,3,2,2,2,2,2,18,3,50,98,50,50,2,146,240,22,34,66,240, -31,255,0,0,56,255,240,9,92,159,27,255,239,39,207,206,63,255,0,5,116,255, -240,1,133,47,254,17,0, -}; -#else -/* IdentifierStart production with ASCII and non-BMP excluded */ -/* duk_unicode_ids_noabmp[] */ -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -const duk_uint8_t duk_unicode_ids_noabmp[625] = { -249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34, -2,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191, -21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240, -101,10,4,15,9,240,159,57,240,82,127,56,242,100,15,4,8,159,1,240,5,115,19, -240,98,98,4,52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47, -2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,18, -47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,12, -38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,6, -41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98, -34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2, -85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35, -63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227, -240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5, -15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40, -240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27, -43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,32,47, -15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,68, -112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,52, -29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,12, -146,240,184,132,52,95,70,114,47,74,35,111,25,79,78,240,63,11,242,127,0,255, -224,244,255,240,0,138,143,60,255,240,4,12,143,28,255,227,127,243,95,30,63, -253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,243,26,34, -35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,143,31, -240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32, -240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,223,7, -95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245, -207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10, -207,73,69,53,53,50,0, -}; -#endif - -#if defined(DUK_USE_SOURCE_NONBMP) -/* IdentifierStart production with Letter and ASCII excluded */ -/* duk_unicode_ids_m_let_noa[] */ -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -const duk_uint8_t duk_unicode_ids_m_let_noa[42] = { -255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89, -249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,240, -}; -#else -/* IdentifierStart production with Letter, ASCII, and non-BMP excluded */ -/* duk_unicode_ids_m_let_noabmp[] */ -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = { -255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89, -249,0, -}; -#endif - -#if defined(DUK_USE_SOURCE_NONBMP) -/* IdentifierPart production with IdentifierStart and ASCII excluded */ -/* duk_unicode_idp_m_ids_noa[] */ -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -const duk_uint8_t duk_unicode_idp_m_ids_noa[530] = { -255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112, -245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34, -36,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50, -160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240, -97,57,240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9, -240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,50, -242,198,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,41, -244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245, -111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241, -241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,242, -244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,57, -241,237,242,47,4,153,121,246,130,47,5,80,82,65,251,143,38,100,255,225,0,31, -35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31, -255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,242, -79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,29, -208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3, -225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,15,254,27,16,253,64, -248,116,255,224,25,159,254,68,178,33,99,241,162,80,249,113,255,228,13,47, -39,239,17,159,1,63,31,175,39,151,47,22,210,159,37,13,47,34,218,36,159,68, -183,15,146,182,151,63,42,2,99,19,42,11,19,100,79,178,240,42,159,72,240,77, -159,199,99,143,13,31,68,240,31,1,159,67,201,159,69,229,159,254,9,169,255, -226,57,114,127,2,159,42,240,98,223,255,0,60,157,159,120,79,45,111,11,159, -254,46,191,30,240,35,255,240,3,191,225,255,240,0,59,164,69,151,54,241,3, -248,98,255,228,125,242,47,254,15,79,39,95,34,144,240,0,240,132,46,255,228, -68,98,240,19,98,18,79,254,121,150,245,246,105,255,240,192,105,175,224,0, -}; -#else -/* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */ -/* duk_unicode_idp_m_ids_noabmp[] */ -/* - * Automatically generated by extract_chars.py, do not edit! - */ - -const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357] = { -255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112, -245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34, -36,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50, -160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240, -97,57,240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9, -240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,50, -242,198,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,41, -244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245, -111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241, -241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,242, -244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,57, -241,237,242,47,4,153,121,246,130,47,5,80,82,65,251,143,38,100,255,225,0,31, -35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31, -255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,242, -79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,29, -208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3, -225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,0, -}; -#endif - -/* - * Case conversion tables generated using tools/extract_caseconv.py. - */ - -/* duk_unicode_caseconv_uc[] */ -/* duk_unicode_caseconv_lc[] */ - -/* - * Automatically generated by extract_caseconv.py, do not edit! - */ - -const duk_uint8_t duk_unicode_caseconv_uc[1386] = { -144,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162, -128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30, -104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,9,252,9,248,6,28,131,4, -33,4,62,0,62,16,32,124,64,124,96,48,249,0,249,64,129,243,1,243,129,3,232,3, -233,1,135,216,7,218,4,15,184,15,221,2,31,114,31,200,8,62,236,63,180,8,125, -224,127,224,16,251,208,255,80,33,247,193,255,160,67,246,3,247,0,135,244,7, -246,1,15,240,15,244,2,33,112,33,96,32,73,160,73,108,104,176,192,176,1,121, -104,0,133,2,106,183,1,58,10,31,232,63,228,38,162,1,1,1,0,48,2,102,2,100,12, -4,232,4,228,64,10,88,10,81,112,23,160,23,144,96,48,96,48,64,128,104,64,104, -1,128,218,0,217,130,1,206,1,205,16,3,190,3,188,36,7,228,7,224,160,17,24,17, -16,144,36,112,36,96,160,110,32,110,0,128,246,64,246,6,2,48,130,48,17,4,139, -4,138,54,9,132,9,130,28,19,68,19,65,128,240,8,240,4,177,234,17,234,6,3,234, -35,235,33,11,26,11,25,193,150,64,150,64,50,44,236,44,235,5,76,131,76,128, -94,154,6,154,0,117,57,29,57,16,122,115,58,115,35,244,239,84,239,32,169,223, -233,223,130,211,200,211,200,2,167,151,167,150,21,79,107,79,104,8,112,26, -208,26,192,64,56,160,56,128,192,113,128,113,1,128,249,0,248,130,2,128,1, -166,4,7,240,7,238,8,177,204,177,200,16,96,49,0,48,224,128,110,64,110,1,1, -51,83,213,2,0,48,35,192,35,176,64,77,32,50,192,139,73,196,49,193,127,48,2, -212,14,112,3,252,5,224,4,196,1,36,5,252,1,76,6,0,9,12,6,72,6,68,6,84,7,216, -6,100,6,96,6,104,8,244,6,120,8,128,6,160,6,156,6,252,7,220,7,116,6,56,7, -204,7,196,9,64,177,188,9,68,177,180,9,72,177,192,9,76,6,4,9,80,6,24,9,100, -6,60,9,108,6,64,9,114,158,172,9,128,6,76,9,134,158,176,9,140,6,80,9,150, -158,52,9,160,6,92,9,172,177,136,9,178,158,180,9,196,177,184,9,200,6,116,9, -212,6,124,9,244,177,144,10,30,158,196,10,32,6,184,10,36,9,16,10,48,9,20,10, -72,6,220,10,118,158,200,10,122,158,192,13,20,14,100,13,220,13,216,14,176, -14,24,15,8,14,140,15,48,14,48,15,64,14,72,15,68,14,96,15,84,14,152,15,88, -14,128,15,92,15,60,15,192,14,104,15,196,14,132,15,200,15,228,15,204,13,252, -15,212,14,84,19,60,19,0,114,0,16,72,114,4,16,80,114,8,16,120,114,20,16,136, -114,24,16,168,114,28,17,136,114,34,153,40,117,230,157,244,117,244,177,140, -122,108,121,128,126,248,14,100,127,148,127,176,133,56,132,200,134,16,134, -12,177,132,177,128,177,148,8,232,177,152,8,248,179,204,179,202,158,50,158, -46,173,78,158,207,48,6,252,0,166,0,166,2,147,1,94,0,39,0,248,64,9,64,97, -128,114,24,28,200,24,64,24,8,29,134,7,74,6,16,6,2,11,15,2,154,130,169,15, -75,64,9,0,102,35,210,240,2,160,24,64,244,196,0,174,6,20,61,51,0,44,129,133, -15,77,64,8,32,87,195,234,16,29,40,24,152,250,150,7,74,6,38,6,0,62,169,129, -210,129,137,129,128,143,171,96,116,160,98,96,104,67,240,16,248,64,28,200, -252,12,62,18,7,50,63,5,15,133,1,204,143,193,195,225,96,115,35,240,144,248, -96,28,200,252,44,62,26,7,50,63,13,15,135,1,204,143,195,195,225,224,115,35, -241,16,248,64,28,200,252,76,62,18,7,50,63,21,15,133,1,204,143,197,195,225, -96,115,35,241,144,248,96,28,200,252,108,62,26,7,50,63,29,15,135,1,204,143, -199,195,225,224,115,35,242,16,249,64,28,200,252,140,62,82,7,50,63,37,15, -149,1,204,143,201,195,229,96,115,35,242,144,249,96,28,200,252,172,62,90,7, -50,63,45,15,151,1,204,143,203,195,229,224,115,35,243,16,249,64,28,200,252, -204,62,82,7,50,63,53,15,149,1,204,143,205,195,229,96,115,35,243,144,249,96, -28,200,252,236,62,90,7,50,63,61,15,151,1,204,143,207,195,229,224,115,35, -244,16,251,64,28,200,253,12,62,210,7,50,63,69,15,181,1,204,143,209,195,237, -96,115,35,244,144,251,96,28,200,253,44,62,218,7,50,63,77,15,183,1,204,143, -211,195,237,224,115,35,245,16,251,64,28,200,253,76,62,210,7,50,63,85,15, -181,1,204,143,213,195,237,96,115,35,245,144,251,96,28,200,253,108,62,218,7, -50,63,93,15,183,1,204,143,215,195,237,224,115,35,246,80,253,208,28,200,253, -156,7,34,7,50,63,105,1,195,1,204,143,219,64,114,32,104,67,246,248,28,136, -26,16,28,200,253,228,7,34,7,50,63,133,15,229,1,204,143,225,192,114,224,115, -35,248,144,28,72,28,200,254,52,7,46,6,132,63,143,129,203,129,161,1,204,143, -230,64,114,224,115,35,250,88,28,200,24,64,24,0,254,158,7,50,6,16,6,2,63, -173,1,204,129,161,15,235,224,115,32,97,0,104,67,252,88,29,40,24,64,24,0, -255,30,7,74,6,16,6,2,63,201,1,208,129,137,143,243,64,116,160,104,67,252, -248,29,40,24,64,26,16,255,148,63,244,7,50,63,231,1,212,129,204,143,250,64, -113,224,115,35,254,208,29,72,26,16,255,190,7,82,6,132,7,50,63,249,1,212, -129,204,253,128,64,8,192,8,223,96,48,2,48,2,79,216,20,0,140,0,153,246,7, -128,35,0,35,0,36,253,130,96,8,192,8,192,9,159,96,176,2,152,2,167,216,52,0, -166,0,169,246,39,2,162,2,163,125,138,64,168,128,166,191,98,176,42,32,41, -223,216,180,10,156,10,141,246,47,2,162,2,158,128, -}; -const duk_uint8_t duk_unicode_caseconv_lc[680] = { -152,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0, -235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32, -0,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,9,208,85,184,80,19, -240,19,248,12,62,16,62,0,32,124,96,124,64,48,249,64,249,0,129,243,129,243, -1,3,233,3,232,1,135,218,7,216,4,15,196,15,192,8,31,152,31,144,16,63,80,63, -64,32,126,224,126,192,16,253,208,251,128,33,252,129,247,32,131,251,3,250,0, -135,246,135,221,129,15,244,15,240,2,31,234,31,122,4,63,240,62,240,8,127, -232,125,240,17,11,1,11,129,2,75,98,77,3,69,128,5,134,11,203,31,128,143,193, -127,144,255,160,154,140,4,0,4,4,192,9,144,9,152,48,19,144,19,161,0,41,64, -41,101,192,94,64,94,129,128,193,0,193,130,1,160,1,161,6,3,102,3,104,8,7,44, -7,48,72,14,240,14,248,144,31,32,31,48,64,63,0,63,37,0,136,128,136,196,129, -35,1,35,133,3,112,3,113,4,7,176,7,178,48,17,128,17,132,136,36,80,36,89,176, -76,16,76,32,224,154,0,154,44,7,128,7,128,101,143,80,15,80,176,31,89,31,81, -8,88,206,88,208,12,178,0,178,5,145,103,89,103,96,42,100,10,100,18,244,208, -20,208,35,169,200,169,200,195,211,153,83,153,159,167,121,167,122,5,78,253, -78,254,22,158,66,158,68,21,60,181,60,184,170,123,74,123,80,67,0,211,1,64,2, -1,172,1,173,4,3,136,3,140,12,7,20,7,24,16,31,184,31,192,34,199,34,199,48, -65,128,195,128,196,2,1,184,1,185,5,79,84,4,204,8,0,192,101,128,154,65,1,29, -129,30,2,16,199,45,39,5,251,240,23,128,15,240,24,16,37,48,24,96,37,64,24, -224,29,208,24,240,37,144,25,0,37,176,25,16,25,32,25,48,38,0,25,64,38,48,25, -112,38,128,25,128,25,144,25,208,39,32,25,240,39,80,26,112,26,128,26,224,40, -128,27,112,41,32,31,16,31,48,31,96,25,80,31,112,27,240,34,0,25,224,35,162, -198,80,35,208,25,160,35,226,198,96,36,48,24,0,36,64,40,144,36,80,40,192,55, -96,55,112,55,240,63,48,56,96,58,192,56,192,60,192,60,240,61,112,63,64,59, -128,63,144,63,32,76,0,76,241,233,224,13,241,251,193,251,49,252,193,252,49, -254,193,254,81,255,193,255,50,18,96,60,146,18,160,6,178,18,176,14,82,19,34, -20,226,24,50,24,66,198,2,198,18,198,32,38,178,198,49,215,210,198,64,39,210, -198,208,37,18,198,224,39,18,198,240,37,2,199,0,37,34,207,34,207,58,119,209, -215,154,120,186,120,202,120,208,38,90,122,176,37,202,122,192,38,26,122,208, -38,202,123,0,41,234,123,16,40,122,123,32,41,218,123,58,181,48,32,38,16,3, -72,24,56, -}; - -#if defined(DUK_USE_REGEXP_CANON_WORKAROUND) -/* - * Automatically generated by extract_caseconv.py, do not edit! - */ - -const duk_uint16_t duk_unicode_re_canon_lookup[65536] = { -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,65,66,67,68,69,70,71,72,73,74,75,76,77, -78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70, -71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,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,924,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,192,193,194,195,196,197,198,199,200,201, -202,203,204,205,206,207,208,209,210,211,212,213,214,247,216,217,218,219, -220,221,222,376,256,256,258,258,260,260,262,262,264,264,266,266,268,268, -270,270,272,272,274,274,276,276,278,278,280,280,282,282,284,284,286,286, -288,288,290,290,292,292,294,294,296,296,298,298,300,300,302,302,304,305, -306,306,308,308,310,310,312,313,313,315,315,317,317,319,319,321,321,323, -323,325,325,327,327,329,330,330,332,332,334,334,336,336,338,338,340,340, -342,342,344,344,346,346,348,348,350,350,352,352,354,354,356,356,358,358, -360,360,362,362,364,364,366,366,368,368,370,370,372,372,374,374,376,377, -377,379,379,381,381,383,579,385,386,386,388,388,390,391,391,393,394,395, -395,397,398,399,400,401,401,403,404,502,406,407,408,408,573,411,412,413, -544,415,416,416,418,418,420,420,422,423,423,425,426,427,428,428,430,431, -431,433,434,435,435,437,437,439,440,440,442,443,444,444,446,503,448,449, -450,451,452,452,452,455,455,455,458,458,458,461,461,463,463,465,465,467, -467,469,469,471,471,473,473,475,475,398,478,478,480,480,482,482,484,484, -486,486,488,488,490,490,492,492,494,494,496,497,497,497,500,500,502,503, -504,504,506,506,508,508,510,510,512,512,514,514,516,516,518,518,520,520, -522,522,524,524,526,526,528,528,530,530,532,532,534,534,536,536,538,538, -540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556, -558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390, -11391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375, -11373,11376,385,390,597,393,394,600,399,602,400,42923L,605,606,607,403, -42924L,610,404,612,42893L,42922L,615,407,406,42926L,11362,42925L,621,622, -412,624,11374,413,627,628,415,630,631,632,633,634,635,636,11364,638,639, -422,641,642,425,644,645,646,42929L,430,580,433,434,581,653,654,655,656,657, -439,659,660,661,662,663,664,665,666,667,668,42930L,42928L,671,672,673,674, -675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692, -693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710, -711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728, -729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746, -747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764, -765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782, -783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800, -801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818, -819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836, -921,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854, -855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872, -873,874,875,876,877,878,879,880,880,882,882,884,885,886,886,888,889,890, -1021,1022,1023,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908, -909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926, -927,928,929,930,931,932,933,934,935,936,937,938,939,902,904,905,906,944, -913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931, -931,932,933,934,935,936,937,938,939,908,910,911,975,914,920,978,979,980, -934,928,975,984,984,986,986,988,988,990,990,992,992,994,994,996,996,998, -998,1000,1000,1002,1002,1004,1004,1006,1006,922,929,1017,895,1012,917,1014, -1015,1015,1017,1018,1018,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029, -1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044, -1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059, -1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1040,1041,1042, -1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057, -1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024, -1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039, -1120,1120,1122,1122,1124,1124,1126,1126,1128,1128,1130,1130,1132,1132,1134, -1134,1136,1136,1138,1138,1140,1140,1142,1142,1144,1144,1146,1146,1148,1148, -1150,1150,1152,1152,1154,1155,1156,1157,1158,1159,1160,1161,1162,1162,1164, -1164,1166,1166,1168,1168,1170,1170,1172,1172,1174,1174,1176,1176,1178,1178, -1180,1180,1182,1182,1184,1184,1186,1186,1188,1188,1190,1190,1192,1192,1194, -1194,1196,1196,1198,1198,1200,1200,1202,1202,1204,1204,1206,1206,1208,1208, -1210,1210,1212,1212,1214,1214,1216,1217,1217,1219,1219,1221,1221,1223,1223, -1225,1225,1227,1227,1229,1229,1216,1232,1232,1234,1234,1236,1236,1238,1238, -1240,1240,1242,1242,1244,1244,1246,1246,1248,1248,1250,1250,1252,1252,1254, -1254,1256,1256,1258,1258,1260,1260,1262,1262,1264,1264,1266,1266,1268,1268, -1270,1270,1272,1272,1274,1274,1276,1276,1278,1278,1280,1280,1282,1282,1284, -1284,1286,1286,1288,1288,1290,1290,1292,1292,1294,1294,1296,1296,1298,1298, -1300,1300,1302,1302,1304,1304,1306,1306,1308,1308,1310,1310,1312,1312,1314, -1314,1316,1316,1318,1318,1320,1320,1322,1322,1324,1324,1326,1326,1328,1329, -1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344, -1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359, -1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374, -1375,1376,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341, -1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356, -1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1415,1416,1417,1418,1419, -1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434, -1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449, -1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464, -1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479, -1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494, -1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509, -1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524, -1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539, -1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554, -1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569, -1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584, -1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599, -1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614, -1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629, -1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644, -1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659, -1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674, -1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689, -1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704, -1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719, -1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734, -1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749, -1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764, -1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779, -1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794, -1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809, -1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824, -1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839, -1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854, -1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869, -1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884, -1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899, -1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914, -1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929, -1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944, -1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959, -1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974, -1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989, -1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004, -2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019, -2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034, -2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049, -2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064, -2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079, -2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094, -2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109, -2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124, -2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139, -2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154, -2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169, -2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184, -2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199, -2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214, -2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229, -2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244, -2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259, -2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274, -2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289, -2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304, -2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319, -2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334, -2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349, -2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364, -2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379, -2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394, -2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409, -2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424, -2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439, -2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454, -2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469, -2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484, -2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499, -2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514, -2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529, -2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544, -2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559, -2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574, -2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589, -2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604, -2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619, -2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634, -2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649, -2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664, -2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679, -2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694, -2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709, -2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724, -2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739, -2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754, -2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769, -2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784, -2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799, -2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814, -2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829, -2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844, -2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859, -2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874, -2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889, -2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904, -2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919, -2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934, -2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949, -2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964, -2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979, -2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994, -2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009, -3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024, -3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039, -3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054, -3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069, -3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084, -3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099, -3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114, -3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129, -3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144, -3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159, -3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174, -3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189, -3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204, -3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219, -3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234, -3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249, -3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264, -3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279, -3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294, -3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309, -3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324, -3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339, -3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354, -3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369, -3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384, -3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399, -3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414, -3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429, -3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444, -3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459, -3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474, -3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489, -3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504, -3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519, -3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534, -3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549, -3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564, -3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579, -3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594, -3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609, -3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624, -3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639, -3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654, -3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669, -3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684, -3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699, -3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714, -3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729, -3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744, -3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759, -3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774, -3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789, -3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804, -3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819, -3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834, -3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849, -3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864, -3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879, -3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894, -3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909, -3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924, -3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939, -3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954, -3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969, -3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984, -3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999, -4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014, -4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029, -4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044, -4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059, -4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074, -4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089, -4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104, -4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119, -4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134, -4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149, -4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164, -4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179, -4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194, -4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209, -4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224, -4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239, -4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254, -4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269, -4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284, -4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299, -4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314, -4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329, -4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344, -4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359, -4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374, -4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389, -4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404, -4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419, -4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434, -4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449, -4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464, -4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479, -4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494, -4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509, -4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524, -4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539, -4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554, -4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569, -4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584, -4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599, -4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614, -4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629, -4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644, -4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659, -4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674, -4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689, -4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704, -4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719, -4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734, -4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749, -4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764, -4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779, -4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794, -4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809, -4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824, -4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839, -4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854, -4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869, -4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884, -4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899, -4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914, -4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929, -4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944, -4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959, -4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974, -4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989, -4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004, -5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019, -5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034, -5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049, -5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064, -5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079, -5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094, -5095,5096,5097,5098,5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109, -5110,5111,5104,5105,5106,5107,5108,5109,5118,5119,5120,5121,5122,5123,5124, -5125,5126,5127,5128,5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139, -5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154, -5155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169, -5170,5171,5172,5173,5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184, -5185,5186,5187,5188,5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199, -5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214, -5215,5216,5217,5218,5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229, -5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244, -5245,5246,5247,5248,5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259, -5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274, -5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289, -5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304, -5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319, -5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334, -5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349, -5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364, -5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, -5380,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394, -5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409, -5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, -5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439, -5440,5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454, -5455,5456,5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469, -5470,5471,5472,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484, -5485,5486,5487,5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499, -5500,5501,5502,5503,5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514, -5515,5516,5517,5518,5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529, -5530,5531,5532,5533,5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544, -5545,5546,5547,5548,5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559, -5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574, -5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589, -5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604, -5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619, -5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634, -5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649, -5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, -5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679, -5680,5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694, -5695,5696,5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709, -5710,5711,5712,5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724, -5725,5726,5727,5728,5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739, -5740,5741,5742,5743,5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754, -5755,5756,5757,5758,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769, -5770,5771,5772,5773,5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784, -5785,5786,5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799, -5800,5801,5802,5803,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814, -5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829, -5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844, -5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859, -5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874, -5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889, -5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, -5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919, -5920,5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934, -5935,5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949, -5950,5951,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964, -5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979, -5980,5981,5982,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994, -5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009, -6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024, -6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039, -6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054, -6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069, -6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084, -6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099, -6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114, -6115,6116,6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129, -6130,6131,6132,6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144, -6145,6146,6147,6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159, -6160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174, -6175,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189, -6190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204, -6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219, -6220,6221,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234, -6235,6236,6237,6238,6239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249, -6250,6251,6252,6253,6254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264, -6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275,6276,6277,6278,6279, -6280,6281,6282,6283,6284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294, -6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309, -6310,6311,6312,6313,6314,6315,6316,6317,6318,6319,6320,6321,6322,6323,6324, -6325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339, -6340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354, -6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369, -6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384, -6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399, -6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414, -6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429, -6430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6444, -6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459, -6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474, -6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489, -6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504, -6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519, -6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534, -6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549, -6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564, -6565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579, -6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594, -6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609, -6610,6611,6612,6613,6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624, -6625,6626,6627,6628,6629,6630,6631,6632,6633,6634,6635,6636,6637,6638,6639, -6640,6641,6642,6643,6644,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654, -6655,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669, -6670,6671,6672,6673,6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684, -6685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699, -6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714, -6715,6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729, -6730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744, -6745,6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759, -6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774, -6775,6776,6777,6778,6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6789, -6790,6791,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804, -6805,6806,6807,6808,6809,6810,6811,6812,6813,6814,6815,6816,6817,6818,6819, -6820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834, -6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849, -6850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864, -6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879, -6880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894, -6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909, -6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924, -6925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939, -6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954, -6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969, -6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984, -6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999, -7000,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014, -7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029, -7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042,7043,7044, -7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059, -7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074, -7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089, -7090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104, -7105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119, -7120,7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134, -7135,7136,7137,7138,7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149, -7150,7151,7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164, -7165,7166,7167,7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179, -7180,7181,7182,7183,7184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194, -7195,7196,7197,7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209, -7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224, -7225,7226,7227,7228,7229,7230,7231,7232,7233,7234,7235,7236,7237,7238,7239, -7240,7241,7242,7243,7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254, -7255,7256,7257,7258,7259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269, -7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284, -7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,1042,1044,1054,1057, -1058,1058,1066,1122,42570L,7305,7306,7307,7308,7309,7310,7311,7312,7313, -7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327,7328, -7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343, -7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,7358, -7359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372,7373, -7374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387,7388, -7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402,7403, -7404,7405,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415,7416,7417,7418, -7419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431,7432,7433, -7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447,7448, -7449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462,7463, -7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,7475,7476,7477,7478, -7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492,7493, -7494,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507,7508, -7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,7522,7523, -7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537,7538, -7539,7540,7541,7542,7543,7544,42877L,7546,7547,7548,11363,7550,7551,7552, -7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567, -7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582, -7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597, -7598,7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612, -7613,7614,7615,7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627, -7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642, -7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657, -7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,7671,7672, -7673,7674,7675,7676,7677,7678,7679,7680,7680,7682,7682,7684,7684,7686,7686, -7688,7688,7690,7690,7692,7692,7694,7694,7696,7696,7698,7698,7700,7700,7702, -7702,7704,7704,7706,7706,7708,7708,7710,7710,7712,7712,7714,7714,7716,7716, -7718,7718,7720,7720,7722,7722,7724,7724,7726,7726,7728,7728,7730,7730,7732, -7732,7734,7734,7736,7736,7738,7738,7740,7740,7742,7742,7744,7744,7746,7746, -7748,7748,7750,7750,7752,7752,7754,7754,7756,7756,7758,7758,7760,7760,7762, -7762,7764,7764,7766,7766,7768,7768,7770,7770,7772,7772,7774,7774,7776,7776, -7778,7778,7780,7780,7782,7782,7784,7784,7786,7786,7788,7788,7790,7790,7792, -7792,7794,7794,7796,7796,7798,7798,7800,7800,7802,7802,7804,7804,7806,7806, -7808,7808,7810,7810,7812,7812,7814,7814,7816,7816,7818,7818,7820,7820,7822, -7822,7824,7824,7826,7826,7828,7828,7830,7831,7832,7833,7834,7776,7836,7837, -7838,7839,7840,7840,7842,7842,7844,7844,7846,7846,7848,7848,7850,7850,7852, -7852,7854,7854,7856,7856,7858,7858,7860,7860,7862,7862,7864,7864,7866,7866, -7868,7868,7870,7870,7872,7872,7874,7874,7876,7876,7878,7878,7880,7880,7882, -7882,7884,7884,7886,7886,7888,7888,7890,7890,7892,7892,7894,7894,7896,7896, -7898,7898,7900,7900,7902,7902,7904,7904,7906,7906,7908,7908,7910,7910,7912, -7912,7914,7914,7916,7916,7918,7918,7920,7920,7922,7922,7924,7924,7926,7926, -7928,7928,7930,7930,7932,7932,7934,7934,7944,7945,7946,7947,7948,7949,7950, -7951,7944,7945,7946,7947,7948,7949,7950,7951,7960,7961,7962,7963,7964,7965, -7958,7959,7960,7961,7962,7963,7964,7965,7966,7967,7976,7977,7978,7979,7980, -7981,7982,7983,7976,7977,7978,7979,7980,7981,7982,7983,7992,7993,7994,7995, -7996,7997,7998,7999,7992,7993,7994,7995,7996,7997,7998,7999,8008,8009,8010, -8011,8012,8013,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015,8016,8025, -8018,8027,8020,8029,8022,8031,8024,8025,8026,8027,8028,8029,8030,8031,8040, -8041,8042,8043,8044,8045,8046,8047,8040,8041,8042,8043,8044,8045,8046,8047, -8122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171,8186,8187,8062, -8063,8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077, -8078,8079,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092, -8093,8094,8095,8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107, -8108,8109,8110,8111,8120,8121,8114,8115,8116,8117,8118,8119,8120,8121,8122, -8123,8124,8125,921,8127,8128,8129,8130,8131,8132,8133,8134,8135,8136,8137, -8138,8139,8140,8141,8142,8143,8152,8153,8146,8147,8148,8149,8150,8151,8152, -8153,8154,8155,8156,8157,8158,8159,8168,8169,8162,8163,8164,8172,8166,8167, -8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,8182, -8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197, -8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212, -8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,8227, -8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242, -8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257, -8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272, -8273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284,8285,8286,8287, -8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302, -8303,8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317, -8318,8319,8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332, -8333,8334,8335,8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346,8347, -8348,8349,8350,8351,8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362, -8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373,8374,8375,8376,8377, -8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389,8390,8391,8392, -8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8405,8406,8407, -8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421,8422, -8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437, -8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,8450,8451,8452, -8453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467, -8468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,8480,8481,8482, -8483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,8496,8497, -8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512, -8513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524,8525,8498,8527, -8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8540,8541,8542, -8543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557, -8558,8559,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556, -8557,8558,8559,8576,8577,8578,8579,8579,8581,8582,8583,8584,8585,8586,8587, -8588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599,8600,8601,8602, -8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613,8614,8615,8616,8617, -8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629,8630,8631,8632, -8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,8645,8646,8647, -8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,8660,8661,8662, -8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677, -8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,8690,8691,8692, -8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,8705,8706,8707, -8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8720,8721,8722, -8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734,8735,8736,8737, -8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749,8750,8751,8752, -8753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,8764,8765,8766,8767, -8768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,8780,8781,8782, -8783,8784,8785,8786,8787,8788,8789,8790,8791,8792,8793,8794,8795,8796,8797, -8798,8799,8800,8801,8802,8803,8804,8805,8806,8807,8808,8809,8810,8811,8812, -8813,8814,8815,8816,8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827, -8828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839,8840,8841,8842, -8843,8844,8845,8846,8847,8848,8849,8850,8851,8852,8853,8854,8855,8856,8857, -8858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869,8870,8871,8872, -8873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,8885,8886,8887, -8888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899,8900,8901,8902, -8903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914,8915,8916,8917, -8918,8919,8920,8921,8922,8923,8924,8925,8926,8927,8928,8929,8930,8931,8932, -8933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,8944,8945,8946,8947, -8948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959,8960,8961,8962, -8963,8964,8965,8966,8967,8968,8969,8970,8971,8972,8973,8974,8975,8976,8977, -8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992, -8993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007, -9008,9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,9022, -9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037, -9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052, -9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,9065,9066,9067, -9068,9069,9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082, -9083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097, -9098,9099,9100,9101,9102,9103,9104,9105,9106,9107,9108,9109,9110,9111,9112, -9113,9114,9115,9116,9117,9118,9119,9120,9121,9122,9123,9124,9125,9126,9127, -9128,9129,9130,9131,9132,9133,9134,9135,9136,9137,9138,9139,9140,9141,9142, -9143,9144,9145,9146,9147,9148,9149,9150,9151,9152,9153,9154,9155,9156,9157, -9158,9159,9160,9161,9162,9163,9164,9165,9166,9167,9168,9169,9170,9171,9172, -9173,9174,9175,9176,9177,9178,9179,9180,9181,9182,9183,9184,9185,9186,9187, -9188,9189,9190,9191,9192,9193,9194,9195,9196,9197,9198,9199,9200,9201,9202, -9203,9204,9205,9206,9207,9208,9209,9210,9211,9212,9213,9214,9215,9216,9217, -9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,9232, -9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9246,9247, -9248,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258,9259,9260,9261,9262, -9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9274,9275,9276,9277, -9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289,9290,9291,9292, -9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9304,9305,9306,9307, -9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322, -9323,9324,9325,9326,9327,9328,9329,9330,9331,9332,9333,9334,9335,9336,9337, -9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9352, -9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,9365,9366,9367, -9368,9369,9370,9371,9372,9373,9374,9375,9376,9377,9378,9379,9380,9381,9382, -9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,9396,9397, -9398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412, -9413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,9398,9399,9400,9401, -9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416, -9417,9418,9419,9420,9421,9422,9423,9450,9451,9452,9453,9454,9455,9456,9457, -9458,9459,9460,9461,9462,9463,9464,9465,9466,9467,9468,9469,9470,9471,9472, -9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487, -9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502, -9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517, -9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532, -9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547, -9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562, -9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577, -9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588,9589,9590,9591,9592, -9593,9594,9595,9596,9597,9598,9599,9600,9601,9602,9603,9604,9605,9606,9607, -9608,9609,9610,9611,9612,9613,9614,9615,9616,9617,9618,9619,9620,9621,9622, -9623,9624,9625,9626,9627,9628,9629,9630,9631,9632,9633,9634,9635,9636,9637, -9638,9639,9640,9641,9642,9643,9644,9645,9646,9647,9648,9649,9650,9651,9652, -9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9663,9664,9665,9666,9667, -9668,9669,9670,9671,9672,9673,9674,9675,9676,9677,9678,9679,9680,9681,9682, -9683,9684,9685,9686,9687,9688,9689,9690,9691,9692,9693,9694,9695,9696,9697, -9698,9699,9700,9701,9702,9703,9704,9705,9706,9707,9708,9709,9710,9711,9712, -9713,9714,9715,9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727, -9728,9729,9730,9731,9732,9733,9734,9735,9736,9737,9738,9739,9740,9741,9742, -9743,9744,9745,9746,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9757, -9758,9759,9760,9761,9762,9763,9764,9765,9766,9767,9768,9769,9770,9771,9772, -9773,9774,9775,9776,9777,9778,9779,9780,9781,9782,9783,9784,9785,9786,9787, -9788,9789,9790,9791,9792,9793,9794,9795,9796,9797,9798,9799,9800,9801,9802, -9803,9804,9805,9806,9807,9808,9809,9810,9811,9812,9813,9814,9815,9816,9817, -9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9828,9829,9830,9831,9832, -9833,9834,9835,9836,9837,9838,9839,9840,9841,9842,9843,9844,9845,9846,9847, -9848,9849,9850,9851,9852,9853,9854,9855,9856,9857,9858,9859,9860,9861,9862, -9863,9864,9865,9866,9867,9868,9869,9870,9871,9872,9873,9874,9875,9876,9877, -9878,9879,9880,9881,9882,9883,9884,9885,9886,9887,9888,9889,9890,9891,9892, -9893,9894,9895,9896,9897,9898,9899,9900,9901,9902,9903,9904,9905,9906,9907, -9908,9909,9910,9911,9912,9913,9914,9915,9916,9917,9918,9919,9920,9921,9922, -9923,9924,9925,9926,9927,9928,9929,9930,9931,9932,9933,9934,9935,9936,9937, -9938,9939,9940,9941,9942,9943,9944,9945,9946,9947,9948,9949,9950,9951,9952, -9953,9954,9955,9956,9957,9958,9959,9960,9961,9962,9963,9964,9965,9966,9967, -9968,9969,9970,9971,9972,9973,9974,9975,9976,9977,9978,9979,9980,9981,9982, -9983,9984,9985,9986,9987,9988,9989,9990,9991,9992,9993,9994,9995,9996,9997, -9998,9999,10000,10001,10002,10003,10004,10005,10006,10007,10008,10009, -10010,10011,10012,10013,10014,10015,10016,10017,10018,10019,10020,10021, -10022,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033, -10034,10035,10036,10037,10038,10039,10040,10041,10042,10043,10044,10045, -10046,10047,10048,10049,10050,10051,10052,10053,10054,10055,10056,10057, -10058,10059,10060,10061,10062,10063,10064,10065,10066,10067,10068,10069, -10070,10071,10072,10073,10074,10075,10076,10077,10078,10079,10080,10081, -10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092,10093, -10094,10095,10096,10097,10098,10099,10100,10101,10102,10103,10104,10105, -10106,10107,10108,10109,10110,10111,10112,10113,10114,10115,10116,10117, -10118,10119,10120,10121,10122,10123,10124,10125,10126,10127,10128,10129, -10130,10131,10132,10133,10134,10135,10136,10137,10138,10139,10140,10141, -10142,10143,10144,10145,10146,10147,10148,10149,10150,10151,10152,10153, -10154,10155,10156,10157,10158,10159,10160,10161,10162,10163,10164,10165, -10166,10167,10168,10169,10170,10171,10172,10173,10174,10175,10176,10177, -10178,10179,10180,10181,10182,10183,10184,10185,10186,10187,10188,10189, -10190,10191,10192,10193,10194,10195,10196,10197,10198,10199,10200,10201, -10202,10203,10204,10205,10206,10207,10208,10209,10210,10211,10212,10213, -10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225, -10226,10227,10228,10229,10230,10231,10232,10233,10234,10235,10236,10237, -10238,10239,10240,10241,10242,10243,10244,10245,10246,10247,10248,10249, -10250,10251,10252,10253,10254,10255,10256,10257,10258,10259,10260,10261, -10262,10263,10264,10265,10266,10267,10268,10269,10270,10271,10272,10273, -10274,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,10285, -10286,10287,10288,10289,10290,10291,10292,10293,10294,10295,10296,10297, -10298,10299,10300,10301,10302,10303,10304,10305,10306,10307,10308,10309, -10310,10311,10312,10313,10314,10315,10316,10317,10318,10319,10320,10321, -10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333, -10334,10335,10336,10337,10338,10339,10340,10341,10342,10343,10344,10345, -10346,10347,10348,10349,10350,10351,10352,10353,10354,10355,10356,10357, -10358,10359,10360,10361,10362,10363,10364,10365,10366,10367,10368,10369, -10370,10371,10372,10373,10374,10375,10376,10377,10378,10379,10380,10381, -10382,10383,10384,10385,10386,10387,10388,10389,10390,10391,10392,10393, -10394,10395,10396,10397,10398,10399,10400,10401,10402,10403,10404,10405, -10406,10407,10408,10409,10410,10411,10412,10413,10414,10415,10416,10417, -10418,10419,10420,10421,10422,10423,10424,10425,10426,10427,10428,10429, -10430,10431,10432,10433,10434,10435,10436,10437,10438,10439,10440,10441, -10442,10443,10444,10445,10446,10447,10448,10449,10450,10451,10452,10453, -10454,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10465, -10466,10467,10468,10469,10470,10471,10472,10473,10474,10475,10476,10477, -10478,10479,10480,10481,10482,10483,10484,10485,10486,10487,10488,10489, -10490,10491,10492,10493,10494,10495,10496,10497,10498,10499,10500,10501, -10502,10503,10504,10505,10506,10507,10508,10509,10510,10511,10512,10513, -10514,10515,10516,10517,10518,10519,10520,10521,10522,10523,10524,10525, -10526,10527,10528,10529,10530,10531,10532,10533,10534,10535,10536,10537, -10538,10539,10540,10541,10542,10543,10544,10545,10546,10547,10548,10549, -10550,10551,10552,10553,10554,10555,10556,10557,10558,10559,10560,10561, -10562,10563,10564,10565,10566,10567,10568,10569,10570,10571,10572,10573, -10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585, -10586,10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597, -10598,10599,10600,10601,10602,10603,10604,10605,10606,10607,10608,10609, -10610,10611,10612,10613,10614,10615,10616,10617,10618,10619,10620,10621, -10622,10623,10624,10625,10626,10627,10628,10629,10630,10631,10632,10633, -10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645, -10646,10647,10648,10649,10650,10651,10652,10653,10654,10655,10656,10657, -10658,10659,10660,10661,10662,10663,10664,10665,10666,10667,10668,10669, -10670,10671,10672,10673,10674,10675,10676,10677,10678,10679,10680,10681, -10682,10683,10684,10685,10686,10687,10688,10689,10690,10691,10692,10693, -10694,10695,10696,10697,10698,10699,10700,10701,10702,10703,10704,10705, -10706,10707,10708,10709,10710,10711,10712,10713,10714,10715,10716,10717, -10718,10719,10720,10721,10722,10723,10724,10725,10726,10727,10728,10729, -10730,10731,10732,10733,10734,10735,10736,10737,10738,10739,10740,10741, -10742,10743,10744,10745,10746,10747,10748,10749,10750,10751,10752,10753, -10754,10755,10756,10757,10758,10759,10760,10761,10762,10763,10764,10765, -10766,10767,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777, -10778,10779,10780,10781,10782,10783,10784,10785,10786,10787,10788,10789, -10790,10791,10792,10793,10794,10795,10796,10797,10798,10799,10800,10801, -10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812,10813, -10814,10815,10816,10817,10818,10819,10820,10821,10822,10823,10824,10825, -10826,10827,10828,10829,10830,10831,10832,10833,10834,10835,10836,10837, -10838,10839,10840,10841,10842,10843,10844,10845,10846,10847,10848,10849, -10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860,10861, -10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873, -10874,10875,10876,10877,10878,10879,10880,10881,10882,10883,10884,10885, -10886,10887,10888,10889,10890,10891,10892,10893,10894,10895,10896,10897, -10898,10899,10900,10901,10902,10903,10904,10905,10906,10907,10908,10909, -10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,10920,10921, -10922,10923,10924,10925,10926,10927,10928,10929,10930,10931,10932,10933, -10934,10935,10936,10937,10938,10939,10940,10941,10942,10943,10944,10945, -10946,10947,10948,10949,10950,10951,10952,10953,10954,10955,10956,10957, -10958,10959,10960,10961,10962,10963,10964,10965,10966,10967,10968,10969, -10970,10971,10972,10973,10974,10975,10976,10977,10978,10979,10980,10981, -10982,10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10993, -10994,10995,10996,10997,10998,10999,11000,11001,11002,11003,11004,11005, -11006,11007,11008,11009,11010,11011,11012,11013,11014,11015,11016,11017, -11018,11019,11020,11021,11022,11023,11024,11025,11026,11027,11028,11029, -11030,11031,11032,11033,11034,11035,11036,11037,11038,11039,11040,11041, -11042,11043,11044,11045,11046,11047,11048,11049,11050,11051,11052,11053, -11054,11055,11056,11057,11058,11059,11060,11061,11062,11063,11064,11065, -11066,11067,11068,11069,11070,11071,11072,11073,11074,11075,11076,11077, -11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088,11089, -11090,11091,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101, -11102,11103,11104,11105,11106,11107,11108,11109,11110,11111,11112,11113, -11114,11115,11116,11117,11118,11119,11120,11121,11122,11123,11124,11125, -11126,11127,11128,11129,11130,11131,11132,11133,11134,11135,11136,11137, -11138,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149, -11150,11151,11152,11153,11154,11155,11156,11157,11158,11159,11160,11161, -11162,11163,11164,11165,11166,11167,11168,11169,11170,11171,11172,11173, -11174,11175,11176,11177,11178,11179,11180,11181,11182,11183,11184,11185, -11186,11187,11188,11189,11190,11191,11192,11193,11194,11195,11196,11197, -11198,11199,11200,11201,11202,11203,11204,11205,11206,11207,11208,11209, -11210,11211,11212,11213,11214,11215,11216,11217,11218,11219,11220,11221, -11222,11223,11224,11225,11226,11227,11228,11229,11230,11231,11232,11233, -11234,11235,11236,11237,11238,11239,11240,11241,11242,11243,11244,11245, -11246,11247,11248,11249,11250,11251,11252,11253,11254,11255,11256,11257, -11258,11259,11260,11261,11262,11263,11264,11265,11266,11267,11268,11269, -11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281, -11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293, -11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305, -11306,11307,11308,11309,11310,11311,11264,11265,11266,11267,11268,11269, -11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281, -11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293, -11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305, -11306,11307,11308,11309,11310,11359,11360,11360,11362,11363,11364,570,574, -11367,11367,11369,11369,11371,11371,11373,11374,11375,11376,11377,11378, -11378,11380,11381,11381,11383,11384,11385,11386,11387,11388,11389,11390, -11391,11392,11392,11394,11394,11396,11396,11398,11398,11400,11400,11402, -11402,11404,11404,11406,11406,11408,11408,11410,11410,11412,11412,11414, -11414,11416,11416,11418,11418,11420,11420,11422,11422,11424,11424,11426, -11426,11428,11428,11430,11430,11432,11432,11434,11434,11436,11436,11438, -11438,11440,11440,11442,11442,11444,11444,11446,11446,11448,11448,11450, -11450,11452,11452,11454,11454,11456,11456,11458,11458,11460,11460,11462, -11462,11464,11464,11466,11466,11468,11468,11470,11470,11472,11472,11474, -11474,11476,11476,11478,11478,11480,11480,11482,11482,11484,11484,11486, -11486,11488,11488,11490,11490,11492,11493,11494,11495,11496,11497,11498, -11499,11499,11501,11501,11503,11504,11505,11506,11506,11508,11509,11510, -11511,11512,11513,11514,11515,11516,11517,11518,11519,4256,4257,4258,4259, -4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274, -4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289, -4290,4291,4292,4293,11558,4295,11560,11561,11562,11563,11564,4301,11566, -11567,11568,11569,11570,11571,11572,11573,11574,11575,11576,11577,11578, -11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,11590, -11591,11592,11593,11594,11595,11596,11597,11598,11599,11600,11601,11602, -11603,11604,11605,11606,11607,11608,11609,11610,11611,11612,11613,11614, -11615,11616,11617,11618,11619,11620,11621,11622,11623,11624,11625,11626, -11627,11628,11629,11630,11631,11632,11633,11634,11635,11636,11637,11638, -11639,11640,11641,11642,11643,11644,11645,11646,11647,11648,11649,11650, -11651,11652,11653,11654,11655,11656,11657,11658,11659,11660,11661,11662, -11663,11664,11665,11666,11667,11668,11669,11670,11671,11672,11673,11674, -11675,11676,11677,11678,11679,11680,11681,11682,11683,11684,11685,11686, -11687,11688,11689,11690,11691,11692,11693,11694,11695,11696,11697,11698, -11699,11700,11701,11702,11703,11704,11705,11706,11707,11708,11709,11710, -11711,11712,11713,11714,11715,11716,11717,11718,11719,11720,11721,11722, -11723,11724,11725,11726,11727,11728,11729,11730,11731,11732,11733,11734, -11735,11736,11737,11738,11739,11740,11741,11742,11743,11744,11745,11746, -11747,11748,11749,11750,11751,11752,11753,11754,11755,11756,11757,11758, -11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770, -11771,11772,11773,11774,11775,11776,11777,11778,11779,11780,11781,11782, -11783,11784,11785,11786,11787,11788,11789,11790,11791,11792,11793,11794, -11795,11796,11797,11798,11799,11800,11801,11802,11803,11804,11805,11806, -11807,11808,11809,11810,11811,11812,11813,11814,11815,11816,11817,11818, -11819,11820,11821,11822,11823,11824,11825,11826,11827,11828,11829,11830, -11831,11832,11833,11834,11835,11836,11837,11838,11839,11840,11841,11842, -11843,11844,11845,11846,11847,11848,11849,11850,11851,11852,11853,11854, -11855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866, -11867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878, -11879,11880,11881,11882,11883,11884,11885,11886,11887,11888,11889,11890, -11891,11892,11893,11894,11895,11896,11897,11898,11899,11900,11901,11902, -11903,11904,11905,11906,11907,11908,11909,11910,11911,11912,11913,11914, -11915,11916,11917,11918,11919,11920,11921,11922,11923,11924,11925,11926, -11927,11928,11929,11930,11931,11932,11933,11934,11935,11936,11937,11938, -11939,11940,11941,11942,11943,11944,11945,11946,11947,11948,11949,11950, -11951,11952,11953,11954,11955,11956,11957,11958,11959,11960,11961,11962, -11963,11964,11965,11966,11967,11968,11969,11970,11971,11972,11973,11974, -11975,11976,11977,11978,11979,11980,11981,11982,11983,11984,11985,11986, -11987,11988,11989,11990,11991,11992,11993,11994,11995,11996,11997,11998, -11999,12000,12001,12002,12003,12004,12005,12006,12007,12008,12009,12010, -12011,12012,12013,12014,12015,12016,12017,12018,12019,12020,12021,12022, -12023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034, -12035,12036,12037,12038,12039,12040,12041,12042,12043,12044,12045,12046, -12047,12048,12049,12050,12051,12052,12053,12054,12055,12056,12057,12058, -12059,12060,12061,12062,12063,12064,12065,12066,12067,12068,12069,12070, -12071,12072,12073,12074,12075,12076,12077,12078,12079,12080,12081,12082, -12083,12084,12085,12086,12087,12088,12089,12090,12091,12092,12093,12094, -12095,12096,12097,12098,12099,12100,12101,12102,12103,12104,12105,12106, -12107,12108,12109,12110,12111,12112,12113,12114,12115,12116,12117,12118, -12119,12120,12121,12122,12123,12124,12125,12126,12127,12128,12129,12130, -12131,12132,12133,12134,12135,12136,12137,12138,12139,12140,12141,12142, -12143,12144,12145,12146,12147,12148,12149,12150,12151,12152,12153,12154, -12155,12156,12157,12158,12159,12160,12161,12162,12163,12164,12165,12166, -12167,12168,12169,12170,12171,12172,12173,12174,12175,12176,12177,12178, -12179,12180,12181,12182,12183,12184,12185,12186,12187,12188,12189,12190, -12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202, -12203,12204,12205,12206,12207,12208,12209,12210,12211,12212,12213,12214, -12215,12216,12217,12218,12219,12220,12221,12222,12223,12224,12225,12226, -12227,12228,12229,12230,12231,12232,12233,12234,12235,12236,12237,12238, -12239,12240,12241,12242,12243,12244,12245,12246,12247,12248,12249,12250, -12251,12252,12253,12254,12255,12256,12257,12258,12259,12260,12261,12262, -12263,12264,12265,12266,12267,12268,12269,12270,12271,12272,12273,12274, -12275,12276,12277,12278,12279,12280,12281,12282,12283,12284,12285,12286, -12287,12288,12289,12290,12291,12292,12293,12294,12295,12296,12297,12298, -12299,12300,12301,12302,12303,12304,12305,12306,12307,12308,12309,12310, -12311,12312,12313,12314,12315,12316,12317,12318,12319,12320,12321,12322, -12323,12324,12325,12326,12327,12328,12329,12330,12331,12332,12333,12334, -12335,12336,12337,12338,12339,12340,12341,12342,12343,12344,12345,12346, -12347,12348,12349,12350,12351,12352,12353,12354,12355,12356,12357,12358, -12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370, -12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382, -12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394, -12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406, -12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418, -12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430, -12431,12432,12433,12434,12435,12436,12437,12438,12439,12440,12441,12442, -12443,12444,12445,12446,12447,12448,12449,12450,12451,12452,12453,12454, -12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466, -12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478, -12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490, -12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502, -12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514, -12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526, -12527,12528,12529,12530,12531,12532,12533,12534,12535,12536,12537,12538, -12539,12540,12541,12542,12543,12544,12545,12546,12547,12548,12549,12550, -12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562, -12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574, -12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,12586, -12587,12588,12589,12590,12591,12592,12593,12594,12595,12596,12597,12598, -12599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610, -12611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622, -12623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634, -12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646, -12647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658, -12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670, -12671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682, -12683,12684,12685,12686,12687,12688,12689,12690,12691,12692,12693,12694, -12695,12696,12697,12698,12699,12700,12701,12702,12703,12704,12705,12706, -12707,12708,12709,12710,12711,12712,12713,12714,12715,12716,12717,12718, -12719,12720,12721,12722,12723,12724,12725,12726,12727,12728,12729,12730, -12731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742, -12743,12744,12745,12746,12747,12748,12749,12750,12751,12752,12753,12754, -12755,12756,12757,12758,12759,12760,12761,12762,12763,12764,12765,12766, -12767,12768,12769,12770,12771,12772,12773,12774,12775,12776,12777,12778, -12779,12780,12781,12782,12783,12784,12785,12786,12787,12788,12789,12790, -12791,12792,12793,12794,12795,12796,12797,12798,12799,12800,12801,12802, -12803,12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814, -12815,12816,12817,12818,12819,12820,12821,12822,12823,12824,12825,12826, -12827,12828,12829,12830,12831,12832,12833,12834,12835,12836,12837,12838, -12839,12840,12841,12842,12843,12844,12845,12846,12847,12848,12849,12850, -12851,12852,12853,12854,12855,12856,12857,12858,12859,12860,12861,12862, -12863,12864,12865,12866,12867,12868,12869,12870,12871,12872,12873,12874, -12875,12876,12877,12878,12879,12880,12881,12882,12883,12884,12885,12886, -12887,12888,12889,12890,12891,12892,12893,12894,12895,12896,12897,12898, -12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910, -12911,12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922, -12923,12924,12925,12926,12927,12928,12929,12930,12931,12932,12933,12934, -12935,12936,12937,12938,12939,12940,12941,12942,12943,12944,12945,12946, -12947,12948,12949,12950,12951,12952,12953,12954,12955,12956,12957,12958, -12959,12960,12961,12962,12963,12964,12965,12966,12967,12968,12969,12970, -12971,12972,12973,12974,12975,12976,12977,12978,12979,12980,12981,12982, -12983,12984,12985,12986,12987,12988,12989,12990,12991,12992,12993,12994, -12995,12996,12997,12998,12999,13000,13001,13002,13003,13004,13005,13006, -13007,13008,13009,13010,13011,13012,13013,13014,13015,13016,13017,13018, -13019,13020,13021,13022,13023,13024,13025,13026,13027,13028,13029,13030, -13031,13032,13033,13034,13035,13036,13037,13038,13039,13040,13041,13042, -13043,13044,13045,13046,13047,13048,13049,13050,13051,13052,13053,13054, -13055,13056,13057,13058,13059,13060,13061,13062,13063,13064,13065,13066, -13067,13068,13069,13070,13071,13072,13073,13074,13075,13076,13077,13078, -13079,13080,13081,13082,13083,13084,13085,13086,13087,13088,13089,13090, -13091,13092,13093,13094,13095,13096,13097,13098,13099,13100,13101,13102, -13103,13104,13105,13106,13107,13108,13109,13110,13111,13112,13113,13114, -13115,13116,13117,13118,13119,13120,13121,13122,13123,13124,13125,13126, -13127,13128,13129,13130,13131,13132,13133,13134,13135,13136,13137,13138, -13139,13140,13141,13142,13143,13144,13145,13146,13147,13148,13149,13150, -13151,13152,13153,13154,13155,13156,13157,13158,13159,13160,13161,13162, -13163,13164,13165,13166,13167,13168,13169,13170,13171,13172,13173,13174, -13175,13176,13177,13178,13179,13180,13181,13182,13183,13184,13185,13186, -13187,13188,13189,13190,13191,13192,13193,13194,13195,13196,13197,13198, -13199,13200,13201,13202,13203,13204,13205,13206,13207,13208,13209,13210, -13211,13212,13213,13214,13215,13216,13217,13218,13219,13220,13221,13222, -13223,13224,13225,13226,13227,13228,13229,13230,13231,13232,13233,13234, -13235,13236,13237,13238,13239,13240,13241,13242,13243,13244,13245,13246, -13247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258, -13259,13260,13261,13262,13263,13264,13265,13266,13267,13268,13269,13270, -13271,13272,13273,13274,13275,13276,13277,13278,13279,13280,13281,13282, -13283,13284,13285,13286,13287,13288,13289,13290,13291,13292,13293,13294, -13295,13296,13297,13298,13299,13300,13301,13302,13303,13304,13305,13306, -13307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318, -13319,13320,13321,13322,13323,13324,13325,13326,13327,13328,13329,13330, -13331,13332,13333,13334,13335,13336,13337,13338,13339,13340,13341,13342, -13343,13344,13345,13346,13347,13348,13349,13350,13351,13352,13353,13354, -13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366, -13367,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378, -13379,13380,13381,13382,13383,13384,13385,13386,13387,13388,13389,13390, -13391,13392,13393,13394,13395,13396,13397,13398,13399,13400,13401,13402, -13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414, -13415,13416,13417,13418,13419,13420,13421,13422,13423,13424,13425,13426, -13427,13428,13429,13430,13431,13432,13433,13434,13435,13436,13437,13438, -13439,13440,13441,13442,13443,13444,13445,13446,13447,13448,13449,13450, -13451,13452,13453,13454,13455,13456,13457,13458,13459,13460,13461,13462, -13463,13464,13465,13466,13467,13468,13469,13470,13471,13472,13473,13474, -13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486, -13487,13488,13489,13490,13491,13492,13493,13494,13495,13496,13497,13498, -13499,13500,13501,13502,13503,13504,13505,13506,13507,13508,13509,13510, -13511,13512,13513,13514,13515,13516,13517,13518,13519,13520,13521,13522, -13523,13524,13525,13526,13527,13528,13529,13530,13531,13532,13533,13534, -13535,13536,13537,13538,13539,13540,13541,13542,13543,13544,13545,13546, -13547,13548,13549,13550,13551,13552,13553,13554,13555,13556,13557,13558, -13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570, -13571,13572,13573,13574,13575,13576,13577,13578,13579,13580,13581,13582, -13583,13584,13585,13586,13587,13588,13589,13590,13591,13592,13593,13594, -13595,13596,13597,13598,13599,13600,13601,13602,13603,13604,13605,13606, -13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618, -13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630, -13631,13632,13633,13634,13635,13636,13637,13638,13639,13640,13641,13642, -13643,13644,13645,13646,13647,13648,13649,13650,13651,13652,13653,13654, -13655,13656,13657,13658,13659,13660,13661,13662,13663,13664,13665,13666, -13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13678, -13679,13680,13681,13682,13683,13684,13685,13686,13687,13688,13689,13690, -13691,13692,13693,13694,13695,13696,13697,13698,13699,13700,13701,13702, -13703,13704,13705,13706,13707,13708,13709,13710,13711,13712,13713,13714, -13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726, -13727,13728,13729,13730,13731,13732,13733,13734,13735,13736,13737,13738, -13739,13740,13741,13742,13743,13744,13745,13746,13747,13748,13749,13750, -13751,13752,13753,13754,13755,13756,13757,13758,13759,13760,13761,13762, -13763,13764,13765,13766,13767,13768,13769,13770,13771,13772,13773,13774, -13775,13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786, -13787,13788,13789,13790,13791,13792,13793,13794,13795,13796,13797,13798, -13799,13800,13801,13802,13803,13804,13805,13806,13807,13808,13809,13810, -13811,13812,13813,13814,13815,13816,13817,13818,13819,13820,13821,13822, -13823,13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834, -13835,13836,13837,13838,13839,13840,13841,13842,13843,13844,13845,13846, -13847,13848,13849,13850,13851,13852,13853,13854,13855,13856,13857,13858, -13859,13860,13861,13862,13863,13864,13865,13866,13867,13868,13869,13870, -13871,13872,13873,13874,13875,13876,13877,13878,13879,13880,13881,13882, -13883,13884,13885,13886,13887,13888,13889,13890,13891,13892,13893,13894, -13895,13896,13897,13898,13899,13900,13901,13902,13903,13904,13905,13906, -13907,13908,13909,13910,13911,13912,13913,13914,13915,13916,13917,13918, -13919,13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930, -13931,13932,13933,13934,13935,13936,13937,13938,13939,13940,13941,13942, -13943,13944,13945,13946,13947,13948,13949,13950,13951,13952,13953,13954, -13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966, -13967,13968,13969,13970,13971,13972,13973,13974,13975,13976,13977,13978, -13979,13980,13981,13982,13983,13984,13985,13986,13987,13988,13989,13990, -13991,13992,13993,13994,13995,13996,13997,13998,13999,14000,14001,14002, -14003,14004,14005,14006,14007,14008,14009,14010,14011,14012,14013,14014, -14015,14016,14017,14018,14019,14020,14021,14022,14023,14024,14025,14026, -14027,14028,14029,14030,14031,14032,14033,14034,14035,14036,14037,14038, -14039,14040,14041,14042,14043,14044,14045,14046,14047,14048,14049,14050, -14051,14052,14053,14054,14055,14056,14057,14058,14059,14060,14061,14062, -14063,14064,14065,14066,14067,14068,14069,14070,14071,14072,14073,14074, -14075,14076,14077,14078,14079,14080,14081,14082,14083,14084,14085,14086, -14087,14088,14089,14090,14091,14092,14093,14094,14095,14096,14097,14098, -14099,14100,14101,14102,14103,14104,14105,14106,14107,14108,14109,14110, -14111,14112,14113,14114,14115,14116,14117,14118,14119,14120,14121,14122, -14123,14124,14125,14126,14127,14128,14129,14130,14131,14132,14133,14134, -14135,14136,14137,14138,14139,14140,14141,14142,14143,14144,14145,14146, -14147,14148,14149,14150,14151,14152,14153,14154,14155,14156,14157,14158, -14159,14160,14161,14162,14163,14164,14165,14166,14167,14168,14169,14170, -14171,14172,14173,14174,14175,14176,14177,14178,14179,14180,14181,14182, -14183,14184,14185,14186,14187,14188,14189,14190,14191,14192,14193,14194, -14195,14196,14197,14198,14199,14200,14201,14202,14203,14204,14205,14206, -14207,14208,14209,14210,14211,14212,14213,14214,14215,14216,14217,14218, -14219,14220,14221,14222,14223,14224,14225,14226,14227,14228,14229,14230, -14231,14232,14233,14234,14235,14236,14237,14238,14239,14240,14241,14242, -14243,14244,14245,14246,14247,14248,14249,14250,14251,14252,14253,14254, -14255,14256,14257,14258,14259,14260,14261,14262,14263,14264,14265,14266, -14267,14268,14269,14270,14271,14272,14273,14274,14275,14276,14277,14278, -14279,14280,14281,14282,14283,14284,14285,14286,14287,14288,14289,14290, -14291,14292,14293,14294,14295,14296,14297,14298,14299,14300,14301,14302, -14303,14304,14305,14306,14307,14308,14309,14310,14311,14312,14313,14314, -14315,14316,14317,14318,14319,14320,14321,14322,14323,14324,14325,14326, -14327,14328,14329,14330,14331,14332,14333,14334,14335,14336,14337,14338, -14339,14340,14341,14342,14343,14344,14345,14346,14347,14348,14349,14350, -14351,14352,14353,14354,14355,14356,14357,14358,14359,14360,14361,14362, -14363,14364,14365,14366,14367,14368,14369,14370,14371,14372,14373,14374, -14375,14376,14377,14378,14379,14380,14381,14382,14383,14384,14385,14386, -14387,14388,14389,14390,14391,14392,14393,14394,14395,14396,14397,14398, -14399,14400,14401,14402,14403,14404,14405,14406,14407,14408,14409,14410, -14411,14412,14413,14414,14415,14416,14417,14418,14419,14420,14421,14422, -14423,14424,14425,14426,14427,14428,14429,14430,14431,14432,14433,14434, -14435,14436,14437,14438,14439,14440,14441,14442,14443,14444,14445,14446, -14447,14448,14449,14450,14451,14452,14453,14454,14455,14456,14457,14458, -14459,14460,14461,14462,14463,14464,14465,14466,14467,14468,14469,14470, -14471,14472,14473,14474,14475,14476,14477,14478,14479,14480,14481,14482, -14483,14484,14485,14486,14487,14488,14489,14490,14491,14492,14493,14494, -14495,14496,14497,14498,14499,14500,14501,14502,14503,14504,14505,14506, -14507,14508,14509,14510,14511,14512,14513,14514,14515,14516,14517,14518, -14519,14520,14521,14522,14523,14524,14525,14526,14527,14528,14529,14530, -14531,14532,14533,14534,14535,14536,14537,14538,14539,14540,14541,14542, -14543,14544,14545,14546,14547,14548,14549,14550,14551,14552,14553,14554, -14555,14556,14557,14558,14559,14560,14561,14562,14563,14564,14565,14566, -14567,14568,14569,14570,14571,14572,14573,14574,14575,14576,14577,14578, -14579,14580,14581,14582,14583,14584,14585,14586,14587,14588,14589,14590, -14591,14592,14593,14594,14595,14596,14597,14598,14599,14600,14601,14602, -14603,14604,14605,14606,14607,14608,14609,14610,14611,14612,14613,14614, -14615,14616,14617,14618,14619,14620,14621,14622,14623,14624,14625,14626, -14627,14628,14629,14630,14631,14632,14633,14634,14635,14636,14637,14638, -14639,14640,14641,14642,14643,14644,14645,14646,14647,14648,14649,14650, -14651,14652,14653,14654,14655,14656,14657,14658,14659,14660,14661,14662, -14663,14664,14665,14666,14667,14668,14669,14670,14671,14672,14673,14674, -14675,14676,14677,14678,14679,14680,14681,14682,14683,14684,14685,14686, -14687,14688,14689,14690,14691,14692,14693,14694,14695,14696,14697,14698, -14699,14700,14701,14702,14703,14704,14705,14706,14707,14708,14709,14710, -14711,14712,14713,14714,14715,14716,14717,14718,14719,14720,14721,14722, -14723,14724,14725,14726,14727,14728,14729,14730,14731,14732,14733,14734, -14735,14736,14737,14738,14739,14740,14741,14742,14743,14744,14745,14746, -14747,14748,14749,14750,14751,14752,14753,14754,14755,14756,14757,14758, -14759,14760,14761,14762,14763,14764,14765,14766,14767,14768,14769,14770, -14771,14772,14773,14774,14775,14776,14777,14778,14779,14780,14781,14782, -14783,14784,14785,14786,14787,14788,14789,14790,14791,14792,14793,14794, -14795,14796,14797,14798,14799,14800,14801,14802,14803,14804,14805,14806, -14807,14808,14809,14810,14811,14812,14813,14814,14815,14816,14817,14818, -14819,14820,14821,14822,14823,14824,14825,14826,14827,14828,14829,14830, -14831,14832,14833,14834,14835,14836,14837,14838,14839,14840,14841,14842, -14843,14844,14845,14846,14847,14848,14849,14850,14851,14852,14853,14854, -14855,14856,14857,14858,14859,14860,14861,14862,14863,14864,14865,14866, -14867,14868,14869,14870,14871,14872,14873,14874,14875,14876,14877,14878, -14879,14880,14881,14882,14883,14884,14885,14886,14887,14888,14889,14890, -14891,14892,14893,14894,14895,14896,14897,14898,14899,14900,14901,14902, -14903,14904,14905,14906,14907,14908,14909,14910,14911,14912,14913,14914, -14915,14916,14917,14918,14919,14920,14921,14922,14923,14924,14925,14926, -14927,14928,14929,14930,14931,14932,14933,14934,14935,14936,14937,14938, -14939,14940,14941,14942,14943,14944,14945,14946,14947,14948,14949,14950, -14951,14952,14953,14954,14955,14956,14957,14958,14959,14960,14961,14962, -14963,14964,14965,14966,14967,14968,14969,14970,14971,14972,14973,14974, -14975,14976,14977,14978,14979,14980,14981,14982,14983,14984,14985,14986, -14987,14988,14989,14990,14991,14992,14993,14994,14995,14996,14997,14998, -14999,15000,15001,15002,15003,15004,15005,15006,15007,15008,15009,15010, -15011,15012,15013,15014,15015,15016,15017,15018,15019,15020,15021,15022, -15023,15024,15025,15026,15027,15028,15029,15030,15031,15032,15033,15034, -15035,15036,15037,15038,15039,15040,15041,15042,15043,15044,15045,15046, -15047,15048,15049,15050,15051,15052,15053,15054,15055,15056,15057,15058, -15059,15060,15061,15062,15063,15064,15065,15066,15067,15068,15069,15070, -15071,15072,15073,15074,15075,15076,15077,15078,15079,15080,15081,15082, -15083,15084,15085,15086,15087,15088,15089,15090,15091,15092,15093,15094, -15095,15096,15097,15098,15099,15100,15101,15102,15103,15104,15105,15106, -15107,15108,15109,15110,15111,15112,15113,15114,15115,15116,15117,15118, -15119,15120,15121,15122,15123,15124,15125,15126,15127,15128,15129,15130, -15131,15132,15133,15134,15135,15136,15137,15138,15139,15140,15141,15142, -15143,15144,15145,15146,15147,15148,15149,15150,15151,15152,15153,15154, -15155,15156,15157,15158,15159,15160,15161,15162,15163,15164,15165,15166, -15167,15168,15169,15170,15171,15172,15173,15174,15175,15176,15177,15178, -15179,15180,15181,15182,15183,15184,15185,15186,15187,15188,15189,15190, -15191,15192,15193,15194,15195,15196,15197,15198,15199,15200,15201,15202, -15203,15204,15205,15206,15207,15208,15209,15210,15211,15212,15213,15214, -15215,15216,15217,15218,15219,15220,15221,15222,15223,15224,15225,15226, -15227,15228,15229,15230,15231,15232,15233,15234,15235,15236,15237,15238, -15239,15240,15241,15242,15243,15244,15245,15246,15247,15248,15249,15250, -15251,15252,15253,15254,15255,15256,15257,15258,15259,15260,15261,15262, -15263,15264,15265,15266,15267,15268,15269,15270,15271,15272,15273,15274, -15275,15276,15277,15278,15279,15280,15281,15282,15283,15284,15285,15286, -15287,15288,15289,15290,15291,15292,15293,15294,15295,15296,15297,15298, -15299,15300,15301,15302,15303,15304,15305,15306,15307,15308,15309,15310, -15311,15312,15313,15314,15315,15316,15317,15318,15319,15320,15321,15322, -15323,15324,15325,15326,15327,15328,15329,15330,15331,15332,15333,15334, -15335,15336,15337,15338,15339,15340,15341,15342,15343,15344,15345,15346, -15347,15348,15349,15350,15351,15352,15353,15354,15355,15356,15357,15358, -15359,15360,15361,15362,15363,15364,15365,15366,15367,15368,15369,15370, -15371,15372,15373,15374,15375,15376,15377,15378,15379,15380,15381,15382, -15383,15384,15385,15386,15387,15388,15389,15390,15391,15392,15393,15394, -15395,15396,15397,15398,15399,15400,15401,15402,15403,15404,15405,15406, -15407,15408,15409,15410,15411,15412,15413,15414,15415,15416,15417,15418, -15419,15420,15421,15422,15423,15424,15425,15426,15427,15428,15429,15430, -15431,15432,15433,15434,15435,15436,15437,15438,15439,15440,15441,15442, -15443,15444,15445,15446,15447,15448,15449,15450,15451,15452,15453,15454, -15455,15456,15457,15458,15459,15460,15461,15462,15463,15464,15465,15466, -15467,15468,15469,15470,15471,15472,15473,15474,15475,15476,15477,15478, -15479,15480,15481,15482,15483,15484,15485,15486,15487,15488,15489,15490, -15491,15492,15493,15494,15495,15496,15497,15498,15499,15500,15501,15502, -15503,15504,15505,15506,15507,15508,15509,15510,15511,15512,15513,15514, -15515,15516,15517,15518,15519,15520,15521,15522,15523,15524,15525,15526, -15527,15528,15529,15530,15531,15532,15533,15534,15535,15536,15537,15538, -15539,15540,15541,15542,15543,15544,15545,15546,15547,15548,15549,15550, -15551,15552,15553,15554,15555,15556,15557,15558,15559,15560,15561,15562, -15563,15564,15565,15566,15567,15568,15569,15570,15571,15572,15573,15574, -15575,15576,15577,15578,15579,15580,15581,15582,15583,15584,15585,15586, -15587,15588,15589,15590,15591,15592,15593,15594,15595,15596,15597,15598, -15599,15600,15601,15602,15603,15604,15605,15606,15607,15608,15609,15610, -15611,15612,15613,15614,15615,15616,15617,15618,15619,15620,15621,15622, -15623,15624,15625,15626,15627,15628,15629,15630,15631,15632,15633,15634, -15635,15636,15637,15638,15639,15640,15641,15642,15643,15644,15645,15646, -15647,15648,15649,15650,15651,15652,15653,15654,15655,15656,15657,15658, -15659,15660,15661,15662,15663,15664,15665,15666,15667,15668,15669,15670, -15671,15672,15673,15674,15675,15676,15677,15678,15679,15680,15681,15682, -15683,15684,15685,15686,15687,15688,15689,15690,15691,15692,15693,15694, -15695,15696,15697,15698,15699,15700,15701,15702,15703,15704,15705,15706, -15707,15708,15709,15710,15711,15712,15713,15714,15715,15716,15717,15718, -15719,15720,15721,15722,15723,15724,15725,15726,15727,15728,15729,15730, -15731,15732,15733,15734,15735,15736,15737,15738,15739,15740,15741,15742, -15743,15744,15745,15746,15747,15748,15749,15750,15751,15752,15753,15754, -15755,15756,15757,15758,15759,15760,15761,15762,15763,15764,15765,15766, -15767,15768,15769,15770,15771,15772,15773,15774,15775,15776,15777,15778, -15779,15780,15781,15782,15783,15784,15785,15786,15787,15788,15789,15790, -15791,15792,15793,15794,15795,15796,15797,15798,15799,15800,15801,15802, -15803,15804,15805,15806,15807,15808,15809,15810,15811,15812,15813,15814, -15815,15816,15817,15818,15819,15820,15821,15822,15823,15824,15825,15826, -15827,15828,15829,15830,15831,15832,15833,15834,15835,15836,15837,15838, -15839,15840,15841,15842,15843,15844,15845,15846,15847,15848,15849,15850, -15851,15852,15853,15854,15855,15856,15857,15858,15859,15860,15861,15862, -15863,15864,15865,15866,15867,15868,15869,15870,15871,15872,15873,15874, -15875,15876,15877,15878,15879,15880,15881,15882,15883,15884,15885,15886, -15887,15888,15889,15890,15891,15892,15893,15894,15895,15896,15897,15898, -15899,15900,15901,15902,15903,15904,15905,15906,15907,15908,15909,15910, -15911,15912,15913,15914,15915,15916,15917,15918,15919,15920,15921,15922, -15923,15924,15925,15926,15927,15928,15929,15930,15931,15932,15933,15934, -15935,15936,15937,15938,15939,15940,15941,15942,15943,15944,15945,15946, -15947,15948,15949,15950,15951,15952,15953,15954,15955,15956,15957,15958, -15959,15960,15961,15962,15963,15964,15965,15966,15967,15968,15969,15970, -15971,15972,15973,15974,15975,15976,15977,15978,15979,15980,15981,15982, -15983,15984,15985,15986,15987,15988,15989,15990,15991,15992,15993,15994, -15995,15996,15997,15998,15999,16000,16001,16002,16003,16004,16005,16006, -16007,16008,16009,16010,16011,16012,16013,16014,16015,16016,16017,16018, -16019,16020,16021,16022,16023,16024,16025,16026,16027,16028,16029,16030, -16031,16032,16033,16034,16035,16036,16037,16038,16039,16040,16041,16042, -16043,16044,16045,16046,16047,16048,16049,16050,16051,16052,16053,16054, -16055,16056,16057,16058,16059,16060,16061,16062,16063,16064,16065,16066, -16067,16068,16069,16070,16071,16072,16073,16074,16075,16076,16077,16078, -16079,16080,16081,16082,16083,16084,16085,16086,16087,16088,16089,16090, -16091,16092,16093,16094,16095,16096,16097,16098,16099,16100,16101,16102, -16103,16104,16105,16106,16107,16108,16109,16110,16111,16112,16113,16114, -16115,16116,16117,16118,16119,16120,16121,16122,16123,16124,16125,16126, -16127,16128,16129,16130,16131,16132,16133,16134,16135,16136,16137,16138, -16139,16140,16141,16142,16143,16144,16145,16146,16147,16148,16149,16150, -16151,16152,16153,16154,16155,16156,16157,16158,16159,16160,16161,16162, -16163,16164,16165,16166,16167,16168,16169,16170,16171,16172,16173,16174, -16175,16176,16177,16178,16179,16180,16181,16182,16183,16184,16185,16186, -16187,16188,16189,16190,16191,16192,16193,16194,16195,16196,16197,16198, -16199,16200,16201,16202,16203,16204,16205,16206,16207,16208,16209,16210, -16211,16212,16213,16214,16215,16216,16217,16218,16219,16220,16221,16222, -16223,16224,16225,16226,16227,16228,16229,16230,16231,16232,16233,16234, -16235,16236,16237,16238,16239,16240,16241,16242,16243,16244,16245,16246, -16247,16248,16249,16250,16251,16252,16253,16254,16255,16256,16257,16258, -16259,16260,16261,16262,16263,16264,16265,16266,16267,16268,16269,16270, -16271,16272,16273,16274,16275,16276,16277,16278,16279,16280,16281,16282, -16283,16284,16285,16286,16287,16288,16289,16290,16291,16292,16293,16294, -16295,16296,16297,16298,16299,16300,16301,16302,16303,16304,16305,16306, -16307,16308,16309,16310,16311,16312,16313,16314,16315,16316,16317,16318, -16319,16320,16321,16322,16323,16324,16325,16326,16327,16328,16329,16330, -16331,16332,16333,16334,16335,16336,16337,16338,16339,16340,16341,16342, -16343,16344,16345,16346,16347,16348,16349,16350,16351,16352,16353,16354, -16355,16356,16357,16358,16359,16360,16361,16362,16363,16364,16365,16366, -16367,16368,16369,16370,16371,16372,16373,16374,16375,16376,16377,16378, -16379,16380,16381,16382,16383,16384,16385,16386,16387,16388,16389,16390, -16391,16392,16393,16394,16395,16396,16397,16398,16399,16400,16401,16402, -16403,16404,16405,16406,16407,16408,16409,16410,16411,16412,16413,16414, -16415,16416,16417,16418,16419,16420,16421,16422,16423,16424,16425,16426, -16427,16428,16429,16430,16431,16432,16433,16434,16435,16436,16437,16438, -16439,16440,16441,16442,16443,16444,16445,16446,16447,16448,16449,16450, -16451,16452,16453,16454,16455,16456,16457,16458,16459,16460,16461,16462, -16463,16464,16465,16466,16467,16468,16469,16470,16471,16472,16473,16474, -16475,16476,16477,16478,16479,16480,16481,16482,16483,16484,16485,16486, -16487,16488,16489,16490,16491,16492,16493,16494,16495,16496,16497,16498, -16499,16500,16501,16502,16503,16504,16505,16506,16507,16508,16509,16510, -16511,16512,16513,16514,16515,16516,16517,16518,16519,16520,16521,16522, -16523,16524,16525,16526,16527,16528,16529,16530,16531,16532,16533,16534, -16535,16536,16537,16538,16539,16540,16541,16542,16543,16544,16545,16546, -16547,16548,16549,16550,16551,16552,16553,16554,16555,16556,16557,16558, -16559,16560,16561,16562,16563,16564,16565,16566,16567,16568,16569,16570, -16571,16572,16573,16574,16575,16576,16577,16578,16579,16580,16581,16582, -16583,16584,16585,16586,16587,16588,16589,16590,16591,16592,16593,16594, -16595,16596,16597,16598,16599,16600,16601,16602,16603,16604,16605,16606, -16607,16608,16609,16610,16611,16612,16613,16614,16615,16616,16617,16618, -16619,16620,16621,16622,16623,16624,16625,16626,16627,16628,16629,16630, -16631,16632,16633,16634,16635,16636,16637,16638,16639,16640,16641,16642, -16643,16644,16645,16646,16647,16648,16649,16650,16651,16652,16653,16654, -16655,16656,16657,16658,16659,16660,16661,16662,16663,16664,16665,16666, -16667,16668,16669,16670,16671,16672,16673,16674,16675,16676,16677,16678, -16679,16680,16681,16682,16683,16684,16685,16686,16687,16688,16689,16690, -16691,16692,16693,16694,16695,16696,16697,16698,16699,16700,16701,16702, -16703,16704,16705,16706,16707,16708,16709,16710,16711,16712,16713,16714, -16715,16716,16717,16718,16719,16720,16721,16722,16723,16724,16725,16726, -16727,16728,16729,16730,16731,16732,16733,16734,16735,16736,16737,16738, -16739,16740,16741,16742,16743,16744,16745,16746,16747,16748,16749,16750, -16751,16752,16753,16754,16755,16756,16757,16758,16759,16760,16761,16762, -16763,16764,16765,16766,16767,16768,16769,16770,16771,16772,16773,16774, -16775,16776,16777,16778,16779,16780,16781,16782,16783,16784,16785,16786, -16787,16788,16789,16790,16791,16792,16793,16794,16795,16796,16797,16798, -16799,16800,16801,16802,16803,16804,16805,16806,16807,16808,16809,16810, -16811,16812,16813,16814,16815,16816,16817,16818,16819,16820,16821,16822, -16823,16824,16825,16826,16827,16828,16829,16830,16831,16832,16833,16834, -16835,16836,16837,16838,16839,16840,16841,16842,16843,16844,16845,16846, -16847,16848,16849,16850,16851,16852,16853,16854,16855,16856,16857,16858, -16859,16860,16861,16862,16863,16864,16865,16866,16867,16868,16869,16870, -16871,16872,16873,16874,16875,16876,16877,16878,16879,16880,16881,16882, -16883,16884,16885,16886,16887,16888,16889,16890,16891,16892,16893,16894, -16895,16896,16897,16898,16899,16900,16901,16902,16903,16904,16905,16906, -16907,16908,16909,16910,16911,16912,16913,16914,16915,16916,16917,16918, -16919,16920,16921,16922,16923,16924,16925,16926,16927,16928,16929,16930, -16931,16932,16933,16934,16935,16936,16937,16938,16939,16940,16941,16942, -16943,16944,16945,16946,16947,16948,16949,16950,16951,16952,16953,16954, -16955,16956,16957,16958,16959,16960,16961,16962,16963,16964,16965,16966, -16967,16968,16969,16970,16971,16972,16973,16974,16975,16976,16977,16978, -16979,16980,16981,16982,16983,16984,16985,16986,16987,16988,16989,16990, -16991,16992,16993,16994,16995,16996,16997,16998,16999,17000,17001,17002, -17003,17004,17005,17006,17007,17008,17009,17010,17011,17012,17013,17014, -17015,17016,17017,17018,17019,17020,17021,17022,17023,17024,17025,17026, -17027,17028,17029,17030,17031,17032,17033,17034,17035,17036,17037,17038, -17039,17040,17041,17042,17043,17044,17045,17046,17047,17048,17049,17050, -17051,17052,17053,17054,17055,17056,17057,17058,17059,17060,17061,17062, -17063,17064,17065,17066,17067,17068,17069,17070,17071,17072,17073,17074, -17075,17076,17077,17078,17079,17080,17081,17082,17083,17084,17085,17086, -17087,17088,17089,17090,17091,17092,17093,17094,17095,17096,17097,17098, -17099,17100,17101,17102,17103,17104,17105,17106,17107,17108,17109,17110, -17111,17112,17113,17114,17115,17116,17117,17118,17119,17120,17121,17122, -17123,17124,17125,17126,17127,17128,17129,17130,17131,17132,17133,17134, -17135,17136,17137,17138,17139,17140,17141,17142,17143,17144,17145,17146, -17147,17148,17149,17150,17151,17152,17153,17154,17155,17156,17157,17158, -17159,17160,17161,17162,17163,17164,17165,17166,17167,17168,17169,17170, -17171,17172,17173,17174,17175,17176,17177,17178,17179,17180,17181,17182, -17183,17184,17185,17186,17187,17188,17189,17190,17191,17192,17193,17194, -17195,17196,17197,17198,17199,17200,17201,17202,17203,17204,17205,17206, -17207,17208,17209,17210,17211,17212,17213,17214,17215,17216,17217,17218, -17219,17220,17221,17222,17223,17224,17225,17226,17227,17228,17229,17230, -17231,17232,17233,17234,17235,17236,17237,17238,17239,17240,17241,17242, -17243,17244,17245,17246,17247,17248,17249,17250,17251,17252,17253,17254, -17255,17256,17257,17258,17259,17260,17261,17262,17263,17264,17265,17266, -17267,17268,17269,17270,17271,17272,17273,17274,17275,17276,17277,17278, -17279,17280,17281,17282,17283,17284,17285,17286,17287,17288,17289,17290, -17291,17292,17293,17294,17295,17296,17297,17298,17299,17300,17301,17302, -17303,17304,17305,17306,17307,17308,17309,17310,17311,17312,17313,17314, -17315,17316,17317,17318,17319,17320,17321,17322,17323,17324,17325,17326, -17327,17328,17329,17330,17331,17332,17333,17334,17335,17336,17337,17338, -17339,17340,17341,17342,17343,17344,17345,17346,17347,17348,17349,17350, -17351,17352,17353,17354,17355,17356,17357,17358,17359,17360,17361,17362, -17363,17364,17365,17366,17367,17368,17369,17370,17371,17372,17373,17374, -17375,17376,17377,17378,17379,17380,17381,17382,17383,17384,17385,17386, -17387,17388,17389,17390,17391,17392,17393,17394,17395,17396,17397,17398, -17399,17400,17401,17402,17403,17404,17405,17406,17407,17408,17409,17410, -17411,17412,17413,17414,17415,17416,17417,17418,17419,17420,17421,17422, -17423,17424,17425,17426,17427,17428,17429,17430,17431,17432,17433,17434, -17435,17436,17437,17438,17439,17440,17441,17442,17443,17444,17445,17446, -17447,17448,17449,17450,17451,17452,17453,17454,17455,17456,17457,17458, -17459,17460,17461,17462,17463,17464,17465,17466,17467,17468,17469,17470, -17471,17472,17473,17474,17475,17476,17477,17478,17479,17480,17481,17482, -17483,17484,17485,17486,17487,17488,17489,17490,17491,17492,17493,17494, -17495,17496,17497,17498,17499,17500,17501,17502,17503,17504,17505,17506, -17507,17508,17509,17510,17511,17512,17513,17514,17515,17516,17517,17518, -17519,17520,17521,17522,17523,17524,17525,17526,17527,17528,17529,17530, -17531,17532,17533,17534,17535,17536,17537,17538,17539,17540,17541,17542, -17543,17544,17545,17546,17547,17548,17549,17550,17551,17552,17553,17554, -17555,17556,17557,17558,17559,17560,17561,17562,17563,17564,17565,17566, -17567,17568,17569,17570,17571,17572,17573,17574,17575,17576,17577,17578, -17579,17580,17581,17582,17583,17584,17585,17586,17587,17588,17589,17590, -17591,17592,17593,17594,17595,17596,17597,17598,17599,17600,17601,17602, -17603,17604,17605,17606,17607,17608,17609,17610,17611,17612,17613,17614, -17615,17616,17617,17618,17619,17620,17621,17622,17623,17624,17625,17626, -17627,17628,17629,17630,17631,17632,17633,17634,17635,17636,17637,17638, -17639,17640,17641,17642,17643,17644,17645,17646,17647,17648,17649,17650, -17651,17652,17653,17654,17655,17656,17657,17658,17659,17660,17661,17662, -17663,17664,17665,17666,17667,17668,17669,17670,17671,17672,17673,17674, -17675,17676,17677,17678,17679,17680,17681,17682,17683,17684,17685,17686, -17687,17688,17689,17690,17691,17692,17693,17694,17695,17696,17697,17698, -17699,17700,17701,17702,17703,17704,17705,17706,17707,17708,17709,17710, -17711,17712,17713,17714,17715,17716,17717,17718,17719,17720,17721,17722, -17723,17724,17725,17726,17727,17728,17729,17730,17731,17732,17733,17734, -17735,17736,17737,17738,17739,17740,17741,17742,17743,17744,17745,17746, -17747,17748,17749,17750,17751,17752,17753,17754,17755,17756,17757,17758, -17759,17760,17761,17762,17763,17764,17765,17766,17767,17768,17769,17770, -17771,17772,17773,17774,17775,17776,17777,17778,17779,17780,17781,17782, -17783,17784,17785,17786,17787,17788,17789,17790,17791,17792,17793,17794, -17795,17796,17797,17798,17799,17800,17801,17802,17803,17804,17805,17806, -17807,17808,17809,17810,17811,17812,17813,17814,17815,17816,17817,17818, -17819,17820,17821,17822,17823,17824,17825,17826,17827,17828,17829,17830, -17831,17832,17833,17834,17835,17836,17837,17838,17839,17840,17841,17842, -17843,17844,17845,17846,17847,17848,17849,17850,17851,17852,17853,17854, -17855,17856,17857,17858,17859,17860,17861,17862,17863,17864,17865,17866, -17867,17868,17869,17870,17871,17872,17873,17874,17875,17876,17877,17878, -17879,17880,17881,17882,17883,17884,17885,17886,17887,17888,17889,17890, -17891,17892,17893,17894,17895,17896,17897,17898,17899,17900,17901,17902, -17903,17904,17905,17906,17907,17908,17909,17910,17911,17912,17913,17914, -17915,17916,17917,17918,17919,17920,17921,17922,17923,17924,17925,17926, -17927,17928,17929,17930,17931,17932,17933,17934,17935,17936,17937,17938, -17939,17940,17941,17942,17943,17944,17945,17946,17947,17948,17949,17950, -17951,17952,17953,17954,17955,17956,17957,17958,17959,17960,17961,17962, -17963,17964,17965,17966,17967,17968,17969,17970,17971,17972,17973,17974, -17975,17976,17977,17978,17979,17980,17981,17982,17983,17984,17985,17986, -17987,17988,17989,17990,17991,17992,17993,17994,17995,17996,17997,17998, -17999,18000,18001,18002,18003,18004,18005,18006,18007,18008,18009,18010, -18011,18012,18013,18014,18015,18016,18017,18018,18019,18020,18021,18022, -18023,18024,18025,18026,18027,18028,18029,18030,18031,18032,18033,18034, -18035,18036,18037,18038,18039,18040,18041,18042,18043,18044,18045,18046, -18047,18048,18049,18050,18051,18052,18053,18054,18055,18056,18057,18058, -18059,18060,18061,18062,18063,18064,18065,18066,18067,18068,18069,18070, -18071,18072,18073,18074,18075,18076,18077,18078,18079,18080,18081,18082, -18083,18084,18085,18086,18087,18088,18089,18090,18091,18092,18093,18094, -18095,18096,18097,18098,18099,18100,18101,18102,18103,18104,18105,18106, -18107,18108,18109,18110,18111,18112,18113,18114,18115,18116,18117,18118, -18119,18120,18121,18122,18123,18124,18125,18126,18127,18128,18129,18130, -18131,18132,18133,18134,18135,18136,18137,18138,18139,18140,18141,18142, -18143,18144,18145,18146,18147,18148,18149,18150,18151,18152,18153,18154, -18155,18156,18157,18158,18159,18160,18161,18162,18163,18164,18165,18166, -18167,18168,18169,18170,18171,18172,18173,18174,18175,18176,18177,18178, -18179,18180,18181,18182,18183,18184,18185,18186,18187,18188,18189,18190, -18191,18192,18193,18194,18195,18196,18197,18198,18199,18200,18201,18202, -18203,18204,18205,18206,18207,18208,18209,18210,18211,18212,18213,18214, -18215,18216,18217,18218,18219,18220,18221,18222,18223,18224,18225,18226, -18227,18228,18229,18230,18231,18232,18233,18234,18235,18236,18237,18238, -18239,18240,18241,18242,18243,18244,18245,18246,18247,18248,18249,18250, -18251,18252,18253,18254,18255,18256,18257,18258,18259,18260,18261,18262, -18263,18264,18265,18266,18267,18268,18269,18270,18271,18272,18273,18274, -18275,18276,18277,18278,18279,18280,18281,18282,18283,18284,18285,18286, -18287,18288,18289,18290,18291,18292,18293,18294,18295,18296,18297,18298, -18299,18300,18301,18302,18303,18304,18305,18306,18307,18308,18309,18310, -18311,18312,18313,18314,18315,18316,18317,18318,18319,18320,18321,18322, -18323,18324,18325,18326,18327,18328,18329,18330,18331,18332,18333,18334, -18335,18336,18337,18338,18339,18340,18341,18342,18343,18344,18345,18346, -18347,18348,18349,18350,18351,18352,18353,18354,18355,18356,18357,18358, -18359,18360,18361,18362,18363,18364,18365,18366,18367,18368,18369,18370, -18371,18372,18373,18374,18375,18376,18377,18378,18379,18380,18381,18382, -18383,18384,18385,18386,18387,18388,18389,18390,18391,18392,18393,18394, -18395,18396,18397,18398,18399,18400,18401,18402,18403,18404,18405,18406, -18407,18408,18409,18410,18411,18412,18413,18414,18415,18416,18417,18418, -18419,18420,18421,18422,18423,18424,18425,18426,18427,18428,18429,18430, -18431,18432,18433,18434,18435,18436,18437,18438,18439,18440,18441,18442, -18443,18444,18445,18446,18447,18448,18449,18450,18451,18452,18453,18454, -18455,18456,18457,18458,18459,18460,18461,18462,18463,18464,18465,18466, -18467,18468,18469,18470,18471,18472,18473,18474,18475,18476,18477,18478, -18479,18480,18481,18482,18483,18484,18485,18486,18487,18488,18489,18490, -18491,18492,18493,18494,18495,18496,18497,18498,18499,18500,18501,18502, -18503,18504,18505,18506,18507,18508,18509,18510,18511,18512,18513,18514, -18515,18516,18517,18518,18519,18520,18521,18522,18523,18524,18525,18526, -18527,18528,18529,18530,18531,18532,18533,18534,18535,18536,18537,18538, -18539,18540,18541,18542,18543,18544,18545,18546,18547,18548,18549,18550, -18551,18552,18553,18554,18555,18556,18557,18558,18559,18560,18561,18562, -18563,18564,18565,18566,18567,18568,18569,18570,18571,18572,18573,18574, -18575,18576,18577,18578,18579,18580,18581,18582,18583,18584,18585,18586, -18587,18588,18589,18590,18591,18592,18593,18594,18595,18596,18597,18598, -18599,18600,18601,18602,18603,18604,18605,18606,18607,18608,18609,18610, -18611,18612,18613,18614,18615,18616,18617,18618,18619,18620,18621,18622, -18623,18624,18625,18626,18627,18628,18629,18630,18631,18632,18633,18634, -18635,18636,18637,18638,18639,18640,18641,18642,18643,18644,18645,18646, -18647,18648,18649,18650,18651,18652,18653,18654,18655,18656,18657,18658, -18659,18660,18661,18662,18663,18664,18665,18666,18667,18668,18669,18670, -18671,18672,18673,18674,18675,18676,18677,18678,18679,18680,18681,18682, -18683,18684,18685,18686,18687,18688,18689,18690,18691,18692,18693,18694, -18695,18696,18697,18698,18699,18700,18701,18702,18703,18704,18705,18706, -18707,18708,18709,18710,18711,18712,18713,18714,18715,18716,18717,18718, -18719,18720,18721,18722,18723,18724,18725,18726,18727,18728,18729,18730, -18731,18732,18733,18734,18735,18736,18737,18738,18739,18740,18741,18742, -18743,18744,18745,18746,18747,18748,18749,18750,18751,18752,18753,18754, -18755,18756,18757,18758,18759,18760,18761,18762,18763,18764,18765,18766, -18767,18768,18769,18770,18771,18772,18773,18774,18775,18776,18777,18778, -18779,18780,18781,18782,18783,18784,18785,18786,18787,18788,18789,18790, -18791,18792,18793,18794,18795,18796,18797,18798,18799,18800,18801,18802, -18803,18804,18805,18806,18807,18808,18809,18810,18811,18812,18813,18814, -18815,18816,18817,18818,18819,18820,18821,18822,18823,18824,18825,18826, -18827,18828,18829,18830,18831,18832,18833,18834,18835,18836,18837,18838, -18839,18840,18841,18842,18843,18844,18845,18846,18847,18848,18849,18850, -18851,18852,18853,18854,18855,18856,18857,18858,18859,18860,18861,18862, -18863,18864,18865,18866,18867,18868,18869,18870,18871,18872,18873,18874, -18875,18876,18877,18878,18879,18880,18881,18882,18883,18884,18885,18886, -18887,18888,18889,18890,18891,18892,18893,18894,18895,18896,18897,18898, -18899,18900,18901,18902,18903,18904,18905,18906,18907,18908,18909,18910, -18911,18912,18913,18914,18915,18916,18917,18918,18919,18920,18921,18922, -18923,18924,18925,18926,18927,18928,18929,18930,18931,18932,18933,18934, -18935,18936,18937,18938,18939,18940,18941,18942,18943,18944,18945,18946, -18947,18948,18949,18950,18951,18952,18953,18954,18955,18956,18957,18958, -18959,18960,18961,18962,18963,18964,18965,18966,18967,18968,18969,18970, -18971,18972,18973,18974,18975,18976,18977,18978,18979,18980,18981,18982, -18983,18984,18985,18986,18987,18988,18989,18990,18991,18992,18993,18994, -18995,18996,18997,18998,18999,19000,19001,19002,19003,19004,19005,19006, -19007,19008,19009,19010,19011,19012,19013,19014,19015,19016,19017,19018, -19019,19020,19021,19022,19023,19024,19025,19026,19027,19028,19029,19030, -19031,19032,19033,19034,19035,19036,19037,19038,19039,19040,19041,19042, -19043,19044,19045,19046,19047,19048,19049,19050,19051,19052,19053,19054, -19055,19056,19057,19058,19059,19060,19061,19062,19063,19064,19065,19066, -19067,19068,19069,19070,19071,19072,19073,19074,19075,19076,19077,19078, -19079,19080,19081,19082,19083,19084,19085,19086,19087,19088,19089,19090, -19091,19092,19093,19094,19095,19096,19097,19098,19099,19100,19101,19102, -19103,19104,19105,19106,19107,19108,19109,19110,19111,19112,19113,19114, -19115,19116,19117,19118,19119,19120,19121,19122,19123,19124,19125,19126, -19127,19128,19129,19130,19131,19132,19133,19134,19135,19136,19137,19138, -19139,19140,19141,19142,19143,19144,19145,19146,19147,19148,19149,19150, -19151,19152,19153,19154,19155,19156,19157,19158,19159,19160,19161,19162, -19163,19164,19165,19166,19167,19168,19169,19170,19171,19172,19173,19174, -19175,19176,19177,19178,19179,19180,19181,19182,19183,19184,19185,19186, -19187,19188,19189,19190,19191,19192,19193,19194,19195,19196,19197,19198, -19199,19200,19201,19202,19203,19204,19205,19206,19207,19208,19209,19210, -19211,19212,19213,19214,19215,19216,19217,19218,19219,19220,19221,19222, -19223,19224,19225,19226,19227,19228,19229,19230,19231,19232,19233,19234, -19235,19236,19237,19238,19239,19240,19241,19242,19243,19244,19245,19246, -19247,19248,19249,19250,19251,19252,19253,19254,19255,19256,19257,19258, -19259,19260,19261,19262,19263,19264,19265,19266,19267,19268,19269,19270, -19271,19272,19273,19274,19275,19276,19277,19278,19279,19280,19281,19282, -19283,19284,19285,19286,19287,19288,19289,19290,19291,19292,19293,19294, -19295,19296,19297,19298,19299,19300,19301,19302,19303,19304,19305,19306, -19307,19308,19309,19310,19311,19312,19313,19314,19315,19316,19317,19318, -19319,19320,19321,19322,19323,19324,19325,19326,19327,19328,19329,19330, -19331,19332,19333,19334,19335,19336,19337,19338,19339,19340,19341,19342, -19343,19344,19345,19346,19347,19348,19349,19350,19351,19352,19353,19354, -19355,19356,19357,19358,19359,19360,19361,19362,19363,19364,19365,19366, -19367,19368,19369,19370,19371,19372,19373,19374,19375,19376,19377,19378, -19379,19380,19381,19382,19383,19384,19385,19386,19387,19388,19389,19390, -19391,19392,19393,19394,19395,19396,19397,19398,19399,19400,19401,19402, -19403,19404,19405,19406,19407,19408,19409,19410,19411,19412,19413,19414, -19415,19416,19417,19418,19419,19420,19421,19422,19423,19424,19425,19426, -19427,19428,19429,19430,19431,19432,19433,19434,19435,19436,19437,19438, -19439,19440,19441,19442,19443,19444,19445,19446,19447,19448,19449,19450, -19451,19452,19453,19454,19455,19456,19457,19458,19459,19460,19461,19462, -19463,19464,19465,19466,19467,19468,19469,19470,19471,19472,19473,19474, -19475,19476,19477,19478,19479,19480,19481,19482,19483,19484,19485,19486, -19487,19488,19489,19490,19491,19492,19493,19494,19495,19496,19497,19498, -19499,19500,19501,19502,19503,19504,19505,19506,19507,19508,19509,19510, -19511,19512,19513,19514,19515,19516,19517,19518,19519,19520,19521,19522, -19523,19524,19525,19526,19527,19528,19529,19530,19531,19532,19533,19534, -19535,19536,19537,19538,19539,19540,19541,19542,19543,19544,19545,19546, -19547,19548,19549,19550,19551,19552,19553,19554,19555,19556,19557,19558, -19559,19560,19561,19562,19563,19564,19565,19566,19567,19568,19569,19570, -19571,19572,19573,19574,19575,19576,19577,19578,19579,19580,19581,19582, -19583,19584,19585,19586,19587,19588,19589,19590,19591,19592,19593,19594, -19595,19596,19597,19598,19599,19600,19601,19602,19603,19604,19605,19606, -19607,19608,19609,19610,19611,19612,19613,19614,19615,19616,19617,19618, -19619,19620,19621,19622,19623,19624,19625,19626,19627,19628,19629,19630, -19631,19632,19633,19634,19635,19636,19637,19638,19639,19640,19641,19642, -19643,19644,19645,19646,19647,19648,19649,19650,19651,19652,19653,19654, -19655,19656,19657,19658,19659,19660,19661,19662,19663,19664,19665,19666, -19667,19668,19669,19670,19671,19672,19673,19674,19675,19676,19677,19678, -19679,19680,19681,19682,19683,19684,19685,19686,19687,19688,19689,19690, -19691,19692,19693,19694,19695,19696,19697,19698,19699,19700,19701,19702, -19703,19704,19705,19706,19707,19708,19709,19710,19711,19712,19713,19714, -19715,19716,19717,19718,19719,19720,19721,19722,19723,19724,19725,19726, -19727,19728,19729,19730,19731,19732,19733,19734,19735,19736,19737,19738, -19739,19740,19741,19742,19743,19744,19745,19746,19747,19748,19749,19750, -19751,19752,19753,19754,19755,19756,19757,19758,19759,19760,19761,19762, -19763,19764,19765,19766,19767,19768,19769,19770,19771,19772,19773,19774, -19775,19776,19777,19778,19779,19780,19781,19782,19783,19784,19785,19786, -19787,19788,19789,19790,19791,19792,19793,19794,19795,19796,19797,19798, -19799,19800,19801,19802,19803,19804,19805,19806,19807,19808,19809,19810, -19811,19812,19813,19814,19815,19816,19817,19818,19819,19820,19821,19822, -19823,19824,19825,19826,19827,19828,19829,19830,19831,19832,19833,19834, -19835,19836,19837,19838,19839,19840,19841,19842,19843,19844,19845,19846, -19847,19848,19849,19850,19851,19852,19853,19854,19855,19856,19857,19858, -19859,19860,19861,19862,19863,19864,19865,19866,19867,19868,19869,19870, -19871,19872,19873,19874,19875,19876,19877,19878,19879,19880,19881,19882, -19883,19884,19885,19886,19887,19888,19889,19890,19891,19892,19893,19894, -19895,19896,19897,19898,19899,19900,19901,19902,19903,19904,19905,19906, -19907,19908,19909,19910,19911,19912,19913,19914,19915,19916,19917,19918, -19919,19920,19921,19922,19923,19924,19925,19926,19927,19928,19929,19930, -19931,19932,19933,19934,19935,19936,19937,19938,19939,19940,19941,19942, -19943,19944,19945,19946,19947,19948,19949,19950,19951,19952,19953,19954, -19955,19956,19957,19958,19959,19960,19961,19962,19963,19964,19965,19966, -19967,19968,19969,19970,19971,19972,19973,19974,19975,19976,19977,19978, -19979,19980,19981,19982,19983,19984,19985,19986,19987,19988,19989,19990, -19991,19992,19993,19994,19995,19996,19997,19998,19999,20000,20001,20002, -20003,20004,20005,20006,20007,20008,20009,20010,20011,20012,20013,20014, -20015,20016,20017,20018,20019,20020,20021,20022,20023,20024,20025,20026, -20027,20028,20029,20030,20031,20032,20033,20034,20035,20036,20037,20038, -20039,20040,20041,20042,20043,20044,20045,20046,20047,20048,20049,20050, -20051,20052,20053,20054,20055,20056,20057,20058,20059,20060,20061,20062, -20063,20064,20065,20066,20067,20068,20069,20070,20071,20072,20073,20074, -20075,20076,20077,20078,20079,20080,20081,20082,20083,20084,20085,20086, -20087,20088,20089,20090,20091,20092,20093,20094,20095,20096,20097,20098, -20099,20100,20101,20102,20103,20104,20105,20106,20107,20108,20109,20110, -20111,20112,20113,20114,20115,20116,20117,20118,20119,20120,20121,20122, -20123,20124,20125,20126,20127,20128,20129,20130,20131,20132,20133,20134, -20135,20136,20137,20138,20139,20140,20141,20142,20143,20144,20145,20146, -20147,20148,20149,20150,20151,20152,20153,20154,20155,20156,20157,20158, -20159,20160,20161,20162,20163,20164,20165,20166,20167,20168,20169,20170, -20171,20172,20173,20174,20175,20176,20177,20178,20179,20180,20181,20182, -20183,20184,20185,20186,20187,20188,20189,20190,20191,20192,20193,20194, -20195,20196,20197,20198,20199,20200,20201,20202,20203,20204,20205,20206, -20207,20208,20209,20210,20211,20212,20213,20214,20215,20216,20217,20218, -20219,20220,20221,20222,20223,20224,20225,20226,20227,20228,20229,20230, -20231,20232,20233,20234,20235,20236,20237,20238,20239,20240,20241,20242, -20243,20244,20245,20246,20247,20248,20249,20250,20251,20252,20253,20254, -20255,20256,20257,20258,20259,20260,20261,20262,20263,20264,20265,20266, -20267,20268,20269,20270,20271,20272,20273,20274,20275,20276,20277,20278, -20279,20280,20281,20282,20283,20284,20285,20286,20287,20288,20289,20290, -20291,20292,20293,20294,20295,20296,20297,20298,20299,20300,20301,20302, -20303,20304,20305,20306,20307,20308,20309,20310,20311,20312,20313,20314, -20315,20316,20317,20318,20319,20320,20321,20322,20323,20324,20325,20326, -20327,20328,20329,20330,20331,20332,20333,20334,20335,20336,20337,20338, -20339,20340,20341,20342,20343,20344,20345,20346,20347,20348,20349,20350, -20351,20352,20353,20354,20355,20356,20357,20358,20359,20360,20361,20362, -20363,20364,20365,20366,20367,20368,20369,20370,20371,20372,20373,20374, -20375,20376,20377,20378,20379,20380,20381,20382,20383,20384,20385,20386, -20387,20388,20389,20390,20391,20392,20393,20394,20395,20396,20397,20398, -20399,20400,20401,20402,20403,20404,20405,20406,20407,20408,20409,20410, -20411,20412,20413,20414,20415,20416,20417,20418,20419,20420,20421,20422, -20423,20424,20425,20426,20427,20428,20429,20430,20431,20432,20433,20434, -20435,20436,20437,20438,20439,20440,20441,20442,20443,20444,20445,20446, -20447,20448,20449,20450,20451,20452,20453,20454,20455,20456,20457,20458, -20459,20460,20461,20462,20463,20464,20465,20466,20467,20468,20469,20470, -20471,20472,20473,20474,20475,20476,20477,20478,20479,20480,20481,20482, -20483,20484,20485,20486,20487,20488,20489,20490,20491,20492,20493,20494, -20495,20496,20497,20498,20499,20500,20501,20502,20503,20504,20505,20506, -20507,20508,20509,20510,20511,20512,20513,20514,20515,20516,20517,20518, -20519,20520,20521,20522,20523,20524,20525,20526,20527,20528,20529,20530, -20531,20532,20533,20534,20535,20536,20537,20538,20539,20540,20541,20542, -20543,20544,20545,20546,20547,20548,20549,20550,20551,20552,20553,20554, -20555,20556,20557,20558,20559,20560,20561,20562,20563,20564,20565,20566, -20567,20568,20569,20570,20571,20572,20573,20574,20575,20576,20577,20578, -20579,20580,20581,20582,20583,20584,20585,20586,20587,20588,20589,20590, -20591,20592,20593,20594,20595,20596,20597,20598,20599,20600,20601,20602, -20603,20604,20605,20606,20607,20608,20609,20610,20611,20612,20613,20614, -20615,20616,20617,20618,20619,20620,20621,20622,20623,20624,20625,20626, -20627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638, -20639,20640,20641,20642,20643,20644,20645,20646,20647,20648,20649,20650, -20651,20652,20653,20654,20655,20656,20657,20658,20659,20660,20661,20662, -20663,20664,20665,20666,20667,20668,20669,20670,20671,20672,20673,20674, -20675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686, -20687,20688,20689,20690,20691,20692,20693,20694,20695,20696,20697,20698, -20699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20710, -20711,20712,20713,20714,20715,20716,20717,20718,20719,20720,20721,20722, -20723,20724,20725,20726,20727,20728,20729,20730,20731,20732,20733,20734, -20735,20736,20737,20738,20739,20740,20741,20742,20743,20744,20745,20746, -20747,20748,20749,20750,20751,20752,20753,20754,20755,20756,20757,20758, -20759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20769,20770, -20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782, -20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794, -20795,20796,20797,20798,20799,20800,20801,20802,20803,20804,20805,20806, -20807,20808,20809,20810,20811,20812,20813,20814,20815,20816,20817,20818, -20819,20820,20821,20822,20823,20824,20825,20826,20827,20828,20829,20830, -20831,20832,20833,20834,20835,20836,20837,20838,20839,20840,20841,20842, -20843,20844,20845,20846,20847,20848,20849,20850,20851,20852,20853,20854, -20855,20856,20857,20858,20859,20860,20861,20862,20863,20864,20865,20866, -20867,20868,20869,20870,20871,20872,20873,20874,20875,20876,20877,20878, -20879,20880,20881,20882,20883,20884,20885,20886,20887,20888,20889,20890, -20891,20892,20893,20894,20895,20896,20897,20898,20899,20900,20901,20902, -20903,20904,20905,20906,20907,20908,20909,20910,20911,20912,20913,20914, -20915,20916,20917,20918,20919,20920,20921,20922,20923,20924,20925,20926, -20927,20928,20929,20930,20931,20932,20933,20934,20935,20936,20937,20938, -20939,20940,20941,20942,20943,20944,20945,20946,20947,20948,20949,20950, -20951,20952,20953,20954,20955,20956,20957,20958,20959,20960,20961,20962, -20963,20964,20965,20966,20967,20968,20969,20970,20971,20972,20973,20974, -20975,20976,20977,20978,20979,20980,20981,20982,20983,20984,20985,20986, -20987,20988,20989,20990,20991,20992,20993,20994,20995,20996,20997,20998, -20999,21000,21001,21002,21003,21004,21005,21006,21007,21008,21009,21010, -21011,21012,21013,21014,21015,21016,21017,21018,21019,21020,21021,21022, -21023,21024,21025,21026,21027,21028,21029,21030,21031,21032,21033,21034, -21035,21036,21037,21038,21039,21040,21041,21042,21043,21044,21045,21046, -21047,21048,21049,21050,21051,21052,21053,21054,21055,21056,21057,21058, -21059,21060,21061,21062,21063,21064,21065,21066,21067,21068,21069,21070, -21071,21072,21073,21074,21075,21076,21077,21078,21079,21080,21081,21082, -21083,21084,21085,21086,21087,21088,21089,21090,21091,21092,21093,21094, -21095,21096,21097,21098,21099,21100,21101,21102,21103,21104,21105,21106, -21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21117,21118, -21119,21120,21121,21122,21123,21124,21125,21126,21127,21128,21129,21130, -21131,21132,21133,21134,21135,21136,21137,21138,21139,21140,21141,21142, -21143,21144,21145,21146,21147,21148,21149,21150,21151,21152,21153,21154, -21155,21156,21157,21158,21159,21160,21161,21162,21163,21164,21165,21166, -21167,21168,21169,21170,21171,21172,21173,21174,21175,21176,21177,21178, -21179,21180,21181,21182,21183,21184,21185,21186,21187,21188,21189,21190, -21191,21192,21193,21194,21195,21196,21197,21198,21199,21200,21201,21202, -21203,21204,21205,21206,21207,21208,21209,21210,21211,21212,21213,21214, -21215,21216,21217,21218,21219,21220,21221,21222,21223,21224,21225,21226, -21227,21228,21229,21230,21231,21232,21233,21234,21235,21236,21237,21238, -21239,21240,21241,21242,21243,21244,21245,21246,21247,21248,21249,21250, -21251,21252,21253,21254,21255,21256,21257,21258,21259,21260,21261,21262, -21263,21264,21265,21266,21267,21268,21269,21270,21271,21272,21273,21274, -21275,21276,21277,21278,21279,21280,21281,21282,21283,21284,21285,21286, -21287,21288,21289,21290,21291,21292,21293,21294,21295,21296,21297,21298, -21299,21300,21301,21302,21303,21304,21305,21306,21307,21308,21309,21310, -21311,21312,21313,21314,21315,21316,21317,21318,21319,21320,21321,21322, -21323,21324,21325,21326,21327,21328,21329,21330,21331,21332,21333,21334, -21335,21336,21337,21338,21339,21340,21341,21342,21343,21344,21345,21346, -21347,21348,21349,21350,21351,21352,21353,21354,21355,21356,21357,21358, -21359,21360,21361,21362,21363,21364,21365,21366,21367,21368,21369,21370, -21371,21372,21373,21374,21375,21376,21377,21378,21379,21380,21381,21382, -21383,21384,21385,21386,21387,21388,21389,21390,21391,21392,21393,21394, -21395,21396,21397,21398,21399,21400,21401,21402,21403,21404,21405,21406, -21407,21408,21409,21410,21411,21412,21413,21414,21415,21416,21417,21418, -21419,21420,21421,21422,21423,21424,21425,21426,21427,21428,21429,21430, -21431,21432,21433,21434,21435,21436,21437,21438,21439,21440,21441,21442, -21443,21444,21445,21446,21447,21448,21449,21450,21451,21452,21453,21454, -21455,21456,21457,21458,21459,21460,21461,21462,21463,21464,21465,21466, -21467,21468,21469,21470,21471,21472,21473,21474,21475,21476,21477,21478, -21479,21480,21481,21482,21483,21484,21485,21486,21487,21488,21489,21490, -21491,21492,21493,21494,21495,21496,21497,21498,21499,21500,21501,21502, -21503,21504,21505,21506,21507,21508,21509,21510,21511,21512,21513,21514, -21515,21516,21517,21518,21519,21520,21521,21522,21523,21524,21525,21526, -21527,21528,21529,21530,21531,21532,21533,21534,21535,21536,21537,21538, -21539,21540,21541,21542,21543,21544,21545,21546,21547,21548,21549,21550, -21551,21552,21553,21554,21555,21556,21557,21558,21559,21560,21561,21562, -21563,21564,21565,21566,21567,21568,21569,21570,21571,21572,21573,21574, -21575,21576,21577,21578,21579,21580,21581,21582,21583,21584,21585,21586, -21587,21588,21589,21590,21591,21592,21593,21594,21595,21596,21597,21598, -21599,21600,21601,21602,21603,21604,21605,21606,21607,21608,21609,21610, -21611,21612,21613,21614,21615,21616,21617,21618,21619,21620,21621,21622, -21623,21624,21625,21626,21627,21628,21629,21630,21631,21632,21633,21634, -21635,21636,21637,21638,21639,21640,21641,21642,21643,21644,21645,21646, -21647,21648,21649,21650,21651,21652,21653,21654,21655,21656,21657,21658, -21659,21660,21661,21662,21663,21664,21665,21666,21667,21668,21669,21670, -21671,21672,21673,21674,21675,21676,21677,21678,21679,21680,21681,21682, -21683,21684,21685,21686,21687,21688,21689,21690,21691,21692,21693,21694, -21695,21696,21697,21698,21699,21700,21701,21702,21703,21704,21705,21706, -21707,21708,21709,21710,21711,21712,21713,21714,21715,21716,21717,21718, -21719,21720,21721,21722,21723,21724,21725,21726,21727,21728,21729,21730, -21731,21732,21733,21734,21735,21736,21737,21738,21739,21740,21741,21742, -21743,21744,21745,21746,21747,21748,21749,21750,21751,21752,21753,21754, -21755,21756,21757,21758,21759,21760,21761,21762,21763,21764,21765,21766, -21767,21768,21769,21770,21771,21772,21773,21774,21775,21776,21777,21778, -21779,21780,21781,21782,21783,21784,21785,21786,21787,21788,21789,21790, -21791,21792,21793,21794,21795,21796,21797,21798,21799,21800,21801,21802, -21803,21804,21805,21806,21807,21808,21809,21810,21811,21812,21813,21814, -21815,21816,21817,21818,21819,21820,21821,21822,21823,21824,21825,21826, -21827,21828,21829,21830,21831,21832,21833,21834,21835,21836,21837,21838, -21839,21840,21841,21842,21843,21844,21845,21846,21847,21848,21849,21850, -21851,21852,21853,21854,21855,21856,21857,21858,21859,21860,21861,21862, -21863,21864,21865,21866,21867,21868,21869,21870,21871,21872,21873,21874, -21875,21876,21877,21878,21879,21880,21881,21882,21883,21884,21885,21886, -21887,21888,21889,21890,21891,21892,21893,21894,21895,21896,21897,21898, -21899,21900,21901,21902,21903,21904,21905,21906,21907,21908,21909,21910, -21911,21912,21913,21914,21915,21916,21917,21918,21919,21920,21921,21922, -21923,21924,21925,21926,21927,21928,21929,21930,21931,21932,21933,21934, -21935,21936,21937,21938,21939,21940,21941,21942,21943,21944,21945,21946, -21947,21948,21949,21950,21951,21952,21953,21954,21955,21956,21957,21958, -21959,21960,21961,21962,21963,21964,21965,21966,21967,21968,21969,21970, -21971,21972,21973,21974,21975,21976,21977,21978,21979,21980,21981,21982, -21983,21984,21985,21986,21987,21988,21989,21990,21991,21992,21993,21994, -21995,21996,21997,21998,21999,22000,22001,22002,22003,22004,22005,22006, -22007,22008,22009,22010,22011,22012,22013,22014,22015,22016,22017,22018, -22019,22020,22021,22022,22023,22024,22025,22026,22027,22028,22029,22030, -22031,22032,22033,22034,22035,22036,22037,22038,22039,22040,22041,22042, -22043,22044,22045,22046,22047,22048,22049,22050,22051,22052,22053,22054, -22055,22056,22057,22058,22059,22060,22061,22062,22063,22064,22065,22066, -22067,22068,22069,22070,22071,22072,22073,22074,22075,22076,22077,22078, -22079,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090, -22091,22092,22093,22094,22095,22096,22097,22098,22099,22100,22101,22102, -22103,22104,22105,22106,22107,22108,22109,22110,22111,22112,22113,22114, -22115,22116,22117,22118,22119,22120,22121,22122,22123,22124,22125,22126, -22127,22128,22129,22130,22131,22132,22133,22134,22135,22136,22137,22138, -22139,22140,22141,22142,22143,22144,22145,22146,22147,22148,22149,22150, -22151,22152,22153,22154,22155,22156,22157,22158,22159,22160,22161,22162, -22163,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174, -22175,22176,22177,22178,22179,22180,22181,22182,22183,22184,22185,22186, -22187,22188,22189,22190,22191,22192,22193,22194,22195,22196,22197,22198, -22199,22200,22201,22202,22203,22204,22205,22206,22207,22208,22209,22210, -22211,22212,22213,22214,22215,22216,22217,22218,22219,22220,22221,22222, -22223,22224,22225,22226,22227,22228,22229,22230,22231,22232,22233,22234, -22235,22236,22237,22238,22239,22240,22241,22242,22243,22244,22245,22246, -22247,22248,22249,22250,22251,22252,22253,22254,22255,22256,22257,22258, -22259,22260,22261,22262,22263,22264,22265,22266,22267,22268,22269,22270, -22271,22272,22273,22274,22275,22276,22277,22278,22279,22280,22281,22282, -22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294, -22295,22296,22297,22298,22299,22300,22301,22302,22303,22304,22305,22306, -22307,22308,22309,22310,22311,22312,22313,22314,22315,22316,22317,22318, -22319,22320,22321,22322,22323,22324,22325,22326,22327,22328,22329,22330, -22331,22332,22333,22334,22335,22336,22337,22338,22339,22340,22341,22342, -22343,22344,22345,22346,22347,22348,22349,22350,22351,22352,22353,22354, -22355,22356,22357,22358,22359,22360,22361,22362,22363,22364,22365,22366, -22367,22368,22369,22370,22371,22372,22373,22374,22375,22376,22377,22378, -22379,22380,22381,22382,22383,22384,22385,22386,22387,22388,22389,22390, -22391,22392,22393,22394,22395,22396,22397,22398,22399,22400,22401,22402, -22403,22404,22405,22406,22407,22408,22409,22410,22411,22412,22413,22414, -22415,22416,22417,22418,22419,22420,22421,22422,22423,22424,22425,22426, -22427,22428,22429,22430,22431,22432,22433,22434,22435,22436,22437,22438, -22439,22440,22441,22442,22443,22444,22445,22446,22447,22448,22449,22450, -22451,22452,22453,22454,22455,22456,22457,22458,22459,22460,22461,22462, -22463,22464,22465,22466,22467,22468,22469,22470,22471,22472,22473,22474, -22475,22476,22477,22478,22479,22480,22481,22482,22483,22484,22485,22486, -22487,22488,22489,22490,22491,22492,22493,22494,22495,22496,22497,22498, -22499,22500,22501,22502,22503,22504,22505,22506,22507,22508,22509,22510, -22511,22512,22513,22514,22515,22516,22517,22518,22519,22520,22521,22522, -22523,22524,22525,22526,22527,22528,22529,22530,22531,22532,22533,22534, -22535,22536,22537,22538,22539,22540,22541,22542,22543,22544,22545,22546, -22547,22548,22549,22550,22551,22552,22553,22554,22555,22556,22557,22558, -22559,22560,22561,22562,22563,22564,22565,22566,22567,22568,22569,22570, -22571,22572,22573,22574,22575,22576,22577,22578,22579,22580,22581,22582, -22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594, -22595,22596,22597,22598,22599,22600,22601,22602,22603,22604,22605,22606, -22607,22608,22609,22610,22611,22612,22613,22614,22615,22616,22617,22618, -22619,22620,22621,22622,22623,22624,22625,22626,22627,22628,22629,22630, -22631,22632,22633,22634,22635,22636,22637,22638,22639,22640,22641,22642, -22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22654, -22655,22656,22657,22658,22659,22660,22661,22662,22663,22664,22665,22666, -22667,22668,22669,22670,22671,22672,22673,22674,22675,22676,22677,22678, -22679,22680,22681,22682,22683,22684,22685,22686,22687,22688,22689,22690, -22691,22692,22693,22694,22695,22696,22697,22698,22699,22700,22701,22702, -22703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714, -22715,22716,22717,22718,22719,22720,22721,22722,22723,22724,22725,22726, -22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22737,22738, -22739,22740,22741,22742,22743,22744,22745,22746,22747,22748,22749,22750, -22751,22752,22753,22754,22755,22756,22757,22758,22759,22760,22761,22762, -22763,22764,22765,22766,22767,22768,22769,22770,22771,22772,22773,22774, -22775,22776,22777,22778,22779,22780,22781,22782,22783,22784,22785,22786, -22787,22788,22789,22790,22791,22792,22793,22794,22795,22796,22797,22798, -22799,22800,22801,22802,22803,22804,22805,22806,22807,22808,22809,22810, -22811,22812,22813,22814,22815,22816,22817,22818,22819,22820,22821,22822, -22823,22824,22825,22826,22827,22828,22829,22830,22831,22832,22833,22834, -22835,22836,22837,22838,22839,22840,22841,22842,22843,22844,22845,22846, -22847,22848,22849,22850,22851,22852,22853,22854,22855,22856,22857,22858, -22859,22860,22861,22862,22863,22864,22865,22866,22867,22868,22869,22870, -22871,22872,22873,22874,22875,22876,22877,22878,22879,22880,22881,22882, -22883,22884,22885,22886,22887,22888,22889,22890,22891,22892,22893,22894, -22895,22896,22897,22898,22899,22900,22901,22902,22903,22904,22905,22906, -22907,22908,22909,22910,22911,22912,22913,22914,22915,22916,22917,22918, -22919,22920,22921,22922,22923,22924,22925,22926,22927,22928,22929,22930, -22931,22932,22933,22934,22935,22936,22937,22938,22939,22940,22941,22942, -22943,22944,22945,22946,22947,22948,22949,22950,22951,22952,22953,22954, -22955,22956,22957,22958,22959,22960,22961,22962,22963,22964,22965,22966, -22967,22968,22969,22970,22971,22972,22973,22974,22975,22976,22977,22978, -22979,22980,22981,22982,22983,22984,22985,22986,22987,22988,22989,22990, -22991,22992,22993,22994,22995,22996,22997,22998,22999,23000,23001,23002, -23003,23004,23005,23006,23007,23008,23009,23010,23011,23012,23013,23014, -23015,23016,23017,23018,23019,23020,23021,23022,23023,23024,23025,23026, -23027,23028,23029,23030,23031,23032,23033,23034,23035,23036,23037,23038, -23039,23040,23041,23042,23043,23044,23045,23046,23047,23048,23049,23050, -23051,23052,23053,23054,23055,23056,23057,23058,23059,23060,23061,23062, -23063,23064,23065,23066,23067,23068,23069,23070,23071,23072,23073,23074, -23075,23076,23077,23078,23079,23080,23081,23082,23083,23084,23085,23086, -23087,23088,23089,23090,23091,23092,23093,23094,23095,23096,23097,23098, -23099,23100,23101,23102,23103,23104,23105,23106,23107,23108,23109,23110, -23111,23112,23113,23114,23115,23116,23117,23118,23119,23120,23121,23122, -23123,23124,23125,23126,23127,23128,23129,23130,23131,23132,23133,23134, -23135,23136,23137,23138,23139,23140,23141,23142,23143,23144,23145,23146, -23147,23148,23149,23150,23151,23152,23153,23154,23155,23156,23157,23158, -23159,23160,23161,23162,23163,23164,23165,23166,23167,23168,23169,23170, -23171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182, -23183,23184,23185,23186,23187,23188,23189,23190,23191,23192,23193,23194, -23195,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206, -23207,23208,23209,23210,23211,23212,23213,23214,23215,23216,23217,23218, -23219,23220,23221,23222,23223,23224,23225,23226,23227,23228,23229,23230, -23231,23232,23233,23234,23235,23236,23237,23238,23239,23240,23241,23242, -23243,23244,23245,23246,23247,23248,23249,23250,23251,23252,23253,23254, -23255,23256,23257,23258,23259,23260,23261,23262,23263,23264,23265,23266, -23267,23268,23269,23270,23271,23272,23273,23274,23275,23276,23277,23278, -23279,23280,23281,23282,23283,23284,23285,23286,23287,23288,23289,23290, -23291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302, -23303,23304,23305,23306,23307,23308,23309,23310,23311,23312,23313,23314, -23315,23316,23317,23318,23319,23320,23321,23322,23323,23324,23325,23326, -23327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338, -23339,23340,23341,23342,23343,23344,23345,23346,23347,23348,23349,23350, -23351,23352,23353,23354,23355,23356,23357,23358,23359,23360,23361,23362, -23363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374, -23375,23376,23377,23378,23379,23380,23381,23382,23383,23384,23385,23386, -23387,23388,23389,23390,23391,23392,23393,23394,23395,23396,23397,23398, -23399,23400,23401,23402,23403,23404,23405,23406,23407,23408,23409,23410, -23411,23412,23413,23414,23415,23416,23417,23418,23419,23420,23421,23422, -23423,23424,23425,23426,23427,23428,23429,23430,23431,23432,23433,23434, -23435,23436,23437,23438,23439,23440,23441,23442,23443,23444,23445,23446, -23447,23448,23449,23450,23451,23452,23453,23454,23455,23456,23457,23458, -23459,23460,23461,23462,23463,23464,23465,23466,23467,23468,23469,23470, -23471,23472,23473,23474,23475,23476,23477,23478,23479,23480,23481,23482, -23483,23484,23485,23486,23487,23488,23489,23490,23491,23492,23493,23494, -23495,23496,23497,23498,23499,23500,23501,23502,23503,23504,23505,23506, -23507,23508,23509,23510,23511,23512,23513,23514,23515,23516,23517,23518, -23519,23520,23521,23522,23523,23524,23525,23526,23527,23528,23529,23530, -23531,23532,23533,23534,23535,23536,23537,23538,23539,23540,23541,23542, -23543,23544,23545,23546,23547,23548,23549,23550,23551,23552,23553,23554, -23555,23556,23557,23558,23559,23560,23561,23562,23563,23564,23565,23566, -23567,23568,23569,23570,23571,23572,23573,23574,23575,23576,23577,23578, -23579,23580,23581,23582,23583,23584,23585,23586,23587,23588,23589,23590, -23591,23592,23593,23594,23595,23596,23597,23598,23599,23600,23601,23602, -23603,23604,23605,23606,23607,23608,23609,23610,23611,23612,23613,23614, -23615,23616,23617,23618,23619,23620,23621,23622,23623,23624,23625,23626, -23627,23628,23629,23630,23631,23632,23633,23634,23635,23636,23637,23638, -23639,23640,23641,23642,23643,23644,23645,23646,23647,23648,23649,23650, -23651,23652,23653,23654,23655,23656,23657,23658,23659,23660,23661,23662, -23663,23664,23665,23666,23667,23668,23669,23670,23671,23672,23673,23674, -23675,23676,23677,23678,23679,23680,23681,23682,23683,23684,23685,23686, -23687,23688,23689,23690,23691,23692,23693,23694,23695,23696,23697,23698, -23699,23700,23701,23702,23703,23704,23705,23706,23707,23708,23709,23710, -23711,23712,23713,23714,23715,23716,23717,23718,23719,23720,23721,23722, -23723,23724,23725,23726,23727,23728,23729,23730,23731,23732,23733,23734, -23735,23736,23737,23738,23739,23740,23741,23742,23743,23744,23745,23746, -23747,23748,23749,23750,23751,23752,23753,23754,23755,23756,23757,23758, -23759,23760,23761,23762,23763,23764,23765,23766,23767,23768,23769,23770, -23771,23772,23773,23774,23775,23776,23777,23778,23779,23780,23781,23782, -23783,23784,23785,23786,23787,23788,23789,23790,23791,23792,23793,23794, -23795,23796,23797,23798,23799,23800,23801,23802,23803,23804,23805,23806, -23807,23808,23809,23810,23811,23812,23813,23814,23815,23816,23817,23818, -23819,23820,23821,23822,23823,23824,23825,23826,23827,23828,23829,23830, -23831,23832,23833,23834,23835,23836,23837,23838,23839,23840,23841,23842, -23843,23844,23845,23846,23847,23848,23849,23850,23851,23852,23853,23854, -23855,23856,23857,23858,23859,23860,23861,23862,23863,23864,23865,23866, -23867,23868,23869,23870,23871,23872,23873,23874,23875,23876,23877,23878, -23879,23880,23881,23882,23883,23884,23885,23886,23887,23888,23889,23890, -23891,23892,23893,23894,23895,23896,23897,23898,23899,23900,23901,23902, -23903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23913,23914, -23915,23916,23917,23918,23919,23920,23921,23922,23923,23924,23925,23926, -23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23938, -23939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950, -23951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23961,23962, -23963,23964,23965,23966,23967,23968,23969,23970,23971,23972,23973,23974, -23975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986, -23987,23988,23989,23990,23991,23992,23993,23994,23995,23996,23997,23998, -23999,24000,24001,24002,24003,24004,24005,24006,24007,24008,24009,24010, -24011,24012,24013,24014,24015,24016,24017,24018,24019,24020,24021,24022, -24023,24024,24025,24026,24027,24028,24029,24030,24031,24032,24033,24034, -24035,24036,24037,24038,24039,24040,24041,24042,24043,24044,24045,24046, -24047,24048,24049,24050,24051,24052,24053,24054,24055,24056,24057,24058, -24059,24060,24061,24062,24063,24064,24065,24066,24067,24068,24069,24070, -24071,24072,24073,24074,24075,24076,24077,24078,24079,24080,24081,24082, -24083,24084,24085,24086,24087,24088,24089,24090,24091,24092,24093,24094, -24095,24096,24097,24098,24099,24100,24101,24102,24103,24104,24105,24106, -24107,24108,24109,24110,24111,24112,24113,24114,24115,24116,24117,24118, -24119,24120,24121,24122,24123,24124,24125,24126,24127,24128,24129,24130, -24131,24132,24133,24134,24135,24136,24137,24138,24139,24140,24141,24142, -24143,24144,24145,24146,24147,24148,24149,24150,24151,24152,24153,24154, -24155,24156,24157,24158,24159,24160,24161,24162,24163,24164,24165,24166, -24167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24178, -24179,24180,24181,24182,24183,24184,24185,24186,24187,24188,24189,24190, -24191,24192,24193,24194,24195,24196,24197,24198,24199,24200,24201,24202, -24203,24204,24205,24206,24207,24208,24209,24210,24211,24212,24213,24214, -24215,24216,24217,24218,24219,24220,24221,24222,24223,24224,24225,24226, -24227,24228,24229,24230,24231,24232,24233,24234,24235,24236,24237,24238, -24239,24240,24241,24242,24243,24244,24245,24246,24247,24248,24249,24250, -24251,24252,24253,24254,24255,24256,24257,24258,24259,24260,24261,24262, -24263,24264,24265,24266,24267,24268,24269,24270,24271,24272,24273,24274, -24275,24276,24277,24278,24279,24280,24281,24282,24283,24284,24285,24286, -24287,24288,24289,24290,24291,24292,24293,24294,24295,24296,24297,24298, -24299,24300,24301,24302,24303,24304,24305,24306,24307,24308,24309,24310, -24311,24312,24313,24314,24315,24316,24317,24318,24319,24320,24321,24322, -24323,24324,24325,24326,24327,24328,24329,24330,24331,24332,24333,24334, -24335,24336,24337,24338,24339,24340,24341,24342,24343,24344,24345,24346, -24347,24348,24349,24350,24351,24352,24353,24354,24355,24356,24357,24358, -24359,24360,24361,24362,24363,24364,24365,24366,24367,24368,24369,24370, -24371,24372,24373,24374,24375,24376,24377,24378,24379,24380,24381,24382, -24383,24384,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394, -24395,24396,24397,24398,24399,24400,24401,24402,24403,24404,24405,24406, -24407,24408,24409,24410,24411,24412,24413,24414,24415,24416,24417,24418, -24419,24420,24421,24422,24423,24424,24425,24426,24427,24428,24429,24430, -24431,24432,24433,24434,24435,24436,24437,24438,24439,24440,24441,24442, -24443,24444,24445,24446,24447,24448,24449,24450,24451,24452,24453,24454, -24455,24456,24457,24458,24459,24460,24461,24462,24463,24464,24465,24466, -24467,24468,24469,24470,24471,24472,24473,24474,24475,24476,24477,24478, -24479,24480,24481,24482,24483,24484,24485,24486,24487,24488,24489,24490, -24491,24492,24493,24494,24495,24496,24497,24498,24499,24500,24501,24502, -24503,24504,24505,24506,24507,24508,24509,24510,24511,24512,24513,24514, -24515,24516,24517,24518,24519,24520,24521,24522,24523,24524,24525,24526, -24527,24528,24529,24530,24531,24532,24533,24534,24535,24536,24537,24538, -24539,24540,24541,24542,24543,24544,24545,24546,24547,24548,24549,24550, -24551,24552,24553,24554,24555,24556,24557,24558,24559,24560,24561,24562, -24563,24564,24565,24566,24567,24568,24569,24570,24571,24572,24573,24574, -24575,24576,24577,24578,24579,24580,24581,24582,24583,24584,24585,24586, -24587,24588,24589,24590,24591,24592,24593,24594,24595,24596,24597,24598, -24599,24600,24601,24602,24603,24604,24605,24606,24607,24608,24609,24610, -24611,24612,24613,24614,24615,24616,24617,24618,24619,24620,24621,24622, -24623,24624,24625,24626,24627,24628,24629,24630,24631,24632,24633,24634, -24635,24636,24637,24638,24639,24640,24641,24642,24643,24644,24645,24646, -24647,24648,24649,24650,24651,24652,24653,24654,24655,24656,24657,24658, -24659,24660,24661,24662,24663,24664,24665,24666,24667,24668,24669,24670, -24671,24672,24673,24674,24675,24676,24677,24678,24679,24680,24681,24682, -24683,24684,24685,24686,24687,24688,24689,24690,24691,24692,24693,24694, -24695,24696,24697,24698,24699,24700,24701,24702,24703,24704,24705,24706, -24707,24708,24709,24710,24711,24712,24713,24714,24715,24716,24717,24718, -24719,24720,24721,24722,24723,24724,24725,24726,24727,24728,24729,24730, -24731,24732,24733,24734,24735,24736,24737,24738,24739,24740,24741,24742, -24743,24744,24745,24746,24747,24748,24749,24750,24751,24752,24753,24754, -24755,24756,24757,24758,24759,24760,24761,24762,24763,24764,24765,24766, -24767,24768,24769,24770,24771,24772,24773,24774,24775,24776,24777,24778, -24779,24780,24781,24782,24783,24784,24785,24786,24787,24788,24789,24790, -24791,24792,24793,24794,24795,24796,24797,24798,24799,24800,24801,24802, -24803,24804,24805,24806,24807,24808,24809,24810,24811,24812,24813,24814, -24815,24816,24817,24818,24819,24820,24821,24822,24823,24824,24825,24826, -24827,24828,24829,24830,24831,24832,24833,24834,24835,24836,24837,24838, -24839,24840,24841,24842,24843,24844,24845,24846,24847,24848,24849,24850, -24851,24852,24853,24854,24855,24856,24857,24858,24859,24860,24861,24862, -24863,24864,24865,24866,24867,24868,24869,24870,24871,24872,24873,24874, -24875,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886, -24887,24888,24889,24890,24891,24892,24893,24894,24895,24896,24897,24898, -24899,24900,24901,24902,24903,24904,24905,24906,24907,24908,24909,24910, -24911,24912,24913,24914,24915,24916,24917,24918,24919,24920,24921,24922, -24923,24924,24925,24926,24927,24928,24929,24930,24931,24932,24933,24934, -24935,24936,24937,24938,24939,24940,24941,24942,24943,24944,24945,24946, -24947,24948,24949,24950,24951,24952,24953,24954,24955,24956,24957,24958, -24959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970, -24971,24972,24973,24974,24975,24976,24977,24978,24979,24980,24981,24982, -24983,24984,24985,24986,24987,24988,24989,24990,24991,24992,24993,24994, -24995,24996,24997,24998,24999,25000,25001,25002,25003,25004,25005,25006, -25007,25008,25009,25010,25011,25012,25013,25014,25015,25016,25017,25018, -25019,25020,25021,25022,25023,25024,25025,25026,25027,25028,25029,25030, -25031,25032,25033,25034,25035,25036,25037,25038,25039,25040,25041,25042, -25043,25044,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054, -25055,25056,25057,25058,25059,25060,25061,25062,25063,25064,25065,25066, -25067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25077,25078, -25079,25080,25081,25082,25083,25084,25085,25086,25087,25088,25089,25090, -25091,25092,25093,25094,25095,25096,25097,25098,25099,25100,25101,25102, -25103,25104,25105,25106,25107,25108,25109,25110,25111,25112,25113,25114, -25115,25116,25117,25118,25119,25120,25121,25122,25123,25124,25125,25126, -25127,25128,25129,25130,25131,25132,25133,25134,25135,25136,25137,25138, -25139,25140,25141,25142,25143,25144,25145,25146,25147,25148,25149,25150, -25151,25152,25153,25154,25155,25156,25157,25158,25159,25160,25161,25162, -25163,25164,25165,25166,25167,25168,25169,25170,25171,25172,25173,25174, -25175,25176,25177,25178,25179,25180,25181,25182,25183,25184,25185,25186, -25187,25188,25189,25190,25191,25192,25193,25194,25195,25196,25197,25198, -25199,25200,25201,25202,25203,25204,25205,25206,25207,25208,25209,25210, -25211,25212,25213,25214,25215,25216,25217,25218,25219,25220,25221,25222, -25223,25224,25225,25226,25227,25228,25229,25230,25231,25232,25233,25234, -25235,25236,25237,25238,25239,25240,25241,25242,25243,25244,25245,25246, -25247,25248,25249,25250,25251,25252,25253,25254,25255,25256,25257,25258, -25259,25260,25261,25262,25263,25264,25265,25266,25267,25268,25269,25270, -25271,25272,25273,25274,25275,25276,25277,25278,25279,25280,25281,25282, -25283,25284,25285,25286,25287,25288,25289,25290,25291,25292,25293,25294, -25295,25296,25297,25298,25299,25300,25301,25302,25303,25304,25305,25306, -25307,25308,25309,25310,25311,25312,25313,25314,25315,25316,25317,25318, -25319,25320,25321,25322,25323,25324,25325,25326,25327,25328,25329,25330, -25331,25332,25333,25334,25335,25336,25337,25338,25339,25340,25341,25342, -25343,25344,25345,25346,25347,25348,25349,25350,25351,25352,25353,25354, -25355,25356,25357,25358,25359,25360,25361,25362,25363,25364,25365,25366, -25367,25368,25369,25370,25371,25372,25373,25374,25375,25376,25377,25378, -25379,25380,25381,25382,25383,25384,25385,25386,25387,25388,25389,25390, -25391,25392,25393,25394,25395,25396,25397,25398,25399,25400,25401,25402, -25403,25404,25405,25406,25407,25408,25409,25410,25411,25412,25413,25414, -25415,25416,25417,25418,25419,25420,25421,25422,25423,25424,25425,25426, -25427,25428,25429,25430,25431,25432,25433,25434,25435,25436,25437,25438, -25439,25440,25441,25442,25443,25444,25445,25446,25447,25448,25449,25450, -25451,25452,25453,25454,25455,25456,25457,25458,25459,25460,25461,25462, -25463,25464,25465,25466,25467,25468,25469,25470,25471,25472,25473,25474, -25475,25476,25477,25478,25479,25480,25481,25482,25483,25484,25485,25486, -25487,25488,25489,25490,25491,25492,25493,25494,25495,25496,25497,25498, -25499,25500,25501,25502,25503,25504,25505,25506,25507,25508,25509,25510, -25511,25512,25513,25514,25515,25516,25517,25518,25519,25520,25521,25522, -25523,25524,25525,25526,25527,25528,25529,25530,25531,25532,25533,25534, -25535,25536,25537,25538,25539,25540,25541,25542,25543,25544,25545,25546, -25547,25548,25549,25550,25551,25552,25553,25554,25555,25556,25557,25558, -25559,25560,25561,25562,25563,25564,25565,25566,25567,25568,25569,25570, -25571,25572,25573,25574,25575,25576,25577,25578,25579,25580,25581,25582, -25583,25584,25585,25586,25587,25588,25589,25590,25591,25592,25593,25594, -25595,25596,25597,25598,25599,25600,25601,25602,25603,25604,25605,25606, -25607,25608,25609,25610,25611,25612,25613,25614,25615,25616,25617,25618, -25619,25620,25621,25622,25623,25624,25625,25626,25627,25628,25629,25630, -25631,25632,25633,25634,25635,25636,25637,25638,25639,25640,25641,25642, -25643,25644,25645,25646,25647,25648,25649,25650,25651,25652,25653,25654, -25655,25656,25657,25658,25659,25660,25661,25662,25663,25664,25665,25666, -25667,25668,25669,25670,25671,25672,25673,25674,25675,25676,25677,25678, -25679,25680,25681,25682,25683,25684,25685,25686,25687,25688,25689,25690, -25691,25692,25693,25694,25695,25696,25697,25698,25699,25700,25701,25702, -25703,25704,25705,25706,25707,25708,25709,25710,25711,25712,25713,25714, -25715,25716,25717,25718,25719,25720,25721,25722,25723,25724,25725,25726, -25727,25728,25729,25730,25731,25732,25733,25734,25735,25736,25737,25738, -25739,25740,25741,25742,25743,25744,25745,25746,25747,25748,25749,25750, -25751,25752,25753,25754,25755,25756,25757,25758,25759,25760,25761,25762, -25763,25764,25765,25766,25767,25768,25769,25770,25771,25772,25773,25774, -25775,25776,25777,25778,25779,25780,25781,25782,25783,25784,25785,25786, -25787,25788,25789,25790,25791,25792,25793,25794,25795,25796,25797,25798, -25799,25800,25801,25802,25803,25804,25805,25806,25807,25808,25809,25810, -25811,25812,25813,25814,25815,25816,25817,25818,25819,25820,25821,25822, -25823,25824,25825,25826,25827,25828,25829,25830,25831,25832,25833,25834, -25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846, -25847,25848,25849,25850,25851,25852,25853,25854,25855,25856,25857,25858, -25859,25860,25861,25862,25863,25864,25865,25866,25867,25868,25869,25870, -25871,25872,25873,25874,25875,25876,25877,25878,25879,25880,25881,25882, -25883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25893,25894, -25895,25896,25897,25898,25899,25900,25901,25902,25903,25904,25905,25906, -25907,25908,25909,25910,25911,25912,25913,25914,25915,25916,25917,25918, -25919,25920,25921,25922,25923,25924,25925,25926,25927,25928,25929,25930, -25931,25932,25933,25934,25935,25936,25937,25938,25939,25940,25941,25942, -25943,25944,25945,25946,25947,25948,25949,25950,25951,25952,25953,25954, -25955,25956,25957,25958,25959,25960,25961,25962,25963,25964,25965,25966, -25967,25968,25969,25970,25971,25972,25973,25974,25975,25976,25977,25978, -25979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990, -25991,25992,25993,25994,25995,25996,25997,25998,25999,26000,26001,26002, -26003,26004,26005,26006,26007,26008,26009,26010,26011,26012,26013,26014, -26015,26016,26017,26018,26019,26020,26021,26022,26023,26024,26025,26026, -26027,26028,26029,26030,26031,26032,26033,26034,26035,26036,26037,26038, -26039,26040,26041,26042,26043,26044,26045,26046,26047,26048,26049,26050, -26051,26052,26053,26054,26055,26056,26057,26058,26059,26060,26061,26062, -26063,26064,26065,26066,26067,26068,26069,26070,26071,26072,26073,26074, -26075,26076,26077,26078,26079,26080,26081,26082,26083,26084,26085,26086, -26087,26088,26089,26090,26091,26092,26093,26094,26095,26096,26097,26098, -26099,26100,26101,26102,26103,26104,26105,26106,26107,26108,26109,26110, -26111,26112,26113,26114,26115,26116,26117,26118,26119,26120,26121,26122, -26123,26124,26125,26126,26127,26128,26129,26130,26131,26132,26133,26134, -26135,26136,26137,26138,26139,26140,26141,26142,26143,26144,26145,26146, -26147,26148,26149,26150,26151,26152,26153,26154,26155,26156,26157,26158, -26159,26160,26161,26162,26163,26164,26165,26166,26167,26168,26169,26170, -26171,26172,26173,26174,26175,26176,26177,26178,26179,26180,26181,26182, -26183,26184,26185,26186,26187,26188,26189,26190,26191,26192,26193,26194, -26195,26196,26197,26198,26199,26200,26201,26202,26203,26204,26205,26206, -26207,26208,26209,26210,26211,26212,26213,26214,26215,26216,26217,26218, -26219,26220,26221,26222,26223,26224,26225,26226,26227,26228,26229,26230, -26231,26232,26233,26234,26235,26236,26237,26238,26239,26240,26241,26242, -26243,26244,26245,26246,26247,26248,26249,26250,26251,26252,26253,26254, -26255,26256,26257,26258,26259,26260,26261,26262,26263,26264,26265,26266, -26267,26268,26269,26270,26271,26272,26273,26274,26275,26276,26277,26278, -26279,26280,26281,26282,26283,26284,26285,26286,26287,26288,26289,26290, -26291,26292,26293,26294,26295,26296,26297,26298,26299,26300,26301,26302, -26303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314, -26315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326, -26327,26328,26329,26330,26331,26332,26333,26334,26335,26336,26337,26338, -26339,26340,26341,26342,26343,26344,26345,26346,26347,26348,26349,26350, -26351,26352,26353,26354,26355,26356,26357,26358,26359,26360,26361,26362, -26363,26364,26365,26366,26367,26368,26369,26370,26371,26372,26373,26374, -26375,26376,26377,26378,26379,26380,26381,26382,26383,26384,26385,26386, -26387,26388,26389,26390,26391,26392,26393,26394,26395,26396,26397,26398, -26399,26400,26401,26402,26403,26404,26405,26406,26407,26408,26409,26410, -26411,26412,26413,26414,26415,26416,26417,26418,26419,26420,26421,26422, -26423,26424,26425,26426,26427,26428,26429,26430,26431,26432,26433,26434, -26435,26436,26437,26438,26439,26440,26441,26442,26443,26444,26445,26446, -26447,26448,26449,26450,26451,26452,26453,26454,26455,26456,26457,26458, -26459,26460,26461,26462,26463,26464,26465,26466,26467,26468,26469,26470, -26471,26472,26473,26474,26475,26476,26477,26478,26479,26480,26481,26482, -26483,26484,26485,26486,26487,26488,26489,26490,26491,26492,26493,26494, -26495,26496,26497,26498,26499,26500,26501,26502,26503,26504,26505,26506, -26507,26508,26509,26510,26511,26512,26513,26514,26515,26516,26517,26518, -26519,26520,26521,26522,26523,26524,26525,26526,26527,26528,26529,26530, -26531,26532,26533,26534,26535,26536,26537,26538,26539,26540,26541,26542, -26543,26544,26545,26546,26547,26548,26549,26550,26551,26552,26553,26554, -26555,26556,26557,26558,26559,26560,26561,26562,26563,26564,26565,26566, -26567,26568,26569,26570,26571,26572,26573,26574,26575,26576,26577,26578, -26579,26580,26581,26582,26583,26584,26585,26586,26587,26588,26589,26590, -26591,26592,26593,26594,26595,26596,26597,26598,26599,26600,26601,26602, -26603,26604,26605,26606,26607,26608,26609,26610,26611,26612,26613,26614, -26615,26616,26617,26618,26619,26620,26621,26622,26623,26624,26625,26626, -26627,26628,26629,26630,26631,26632,26633,26634,26635,26636,26637,26638, -26639,26640,26641,26642,26643,26644,26645,26646,26647,26648,26649,26650, -26651,26652,26653,26654,26655,26656,26657,26658,26659,26660,26661,26662, -26663,26664,26665,26666,26667,26668,26669,26670,26671,26672,26673,26674, -26675,26676,26677,26678,26679,26680,26681,26682,26683,26684,26685,26686, -26687,26688,26689,26690,26691,26692,26693,26694,26695,26696,26697,26698, -26699,26700,26701,26702,26703,26704,26705,26706,26707,26708,26709,26710, -26711,26712,26713,26714,26715,26716,26717,26718,26719,26720,26721,26722, -26723,26724,26725,26726,26727,26728,26729,26730,26731,26732,26733,26734, -26735,26736,26737,26738,26739,26740,26741,26742,26743,26744,26745,26746, -26747,26748,26749,26750,26751,26752,26753,26754,26755,26756,26757,26758, -26759,26760,26761,26762,26763,26764,26765,26766,26767,26768,26769,26770, -26771,26772,26773,26774,26775,26776,26777,26778,26779,26780,26781,26782, -26783,26784,26785,26786,26787,26788,26789,26790,26791,26792,26793,26794, -26795,26796,26797,26798,26799,26800,26801,26802,26803,26804,26805,26806, -26807,26808,26809,26810,26811,26812,26813,26814,26815,26816,26817,26818, -26819,26820,26821,26822,26823,26824,26825,26826,26827,26828,26829,26830, -26831,26832,26833,26834,26835,26836,26837,26838,26839,26840,26841,26842, -26843,26844,26845,26846,26847,26848,26849,26850,26851,26852,26853,26854, -26855,26856,26857,26858,26859,26860,26861,26862,26863,26864,26865,26866, -26867,26868,26869,26870,26871,26872,26873,26874,26875,26876,26877,26878, -26879,26880,26881,26882,26883,26884,26885,26886,26887,26888,26889,26890, -26891,26892,26893,26894,26895,26896,26897,26898,26899,26900,26901,26902, -26903,26904,26905,26906,26907,26908,26909,26910,26911,26912,26913,26914, -26915,26916,26917,26918,26919,26920,26921,26922,26923,26924,26925,26926, -26927,26928,26929,26930,26931,26932,26933,26934,26935,26936,26937,26938, -26939,26940,26941,26942,26943,26944,26945,26946,26947,26948,26949,26950, -26951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962, -26963,26964,26965,26966,26967,26968,26969,26970,26971,26972,26973,26974, -26975,26976,26977,26978,26979,26980,26981,26982,26983,26984,26985,26986, -26987,26988,26989,26990,26991,26992,26993,26994,26995,26996,26997,26998, -26999,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010, -27011,27012,27013,27014,27015,27016,27017,27018,27019,27020,27021,27022, -27023,27024,27025,27026,27027,27028,27029,27030,27031,27032,27033,27034, -27035,27036,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046, -27047,27048,27049,27050,27051,27052,27053,27054,27055,27056,27057,27058, -27059,27060,27061,27062,27063,27064,27065,27066,27067,27068,27069,27070, -27071,27072,27073,27074,27075,27076,27077,27078,27079,27080,27081,27082, -27083,27084,27085,27086,27087,27088,27089,27090,27091,27092,27093,27094, -27095,27096,27097,27098,27099,27100,27101,27102,27103,27104,27105,27106, -27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27117,27118, -27119,27120,27121,27122,27123,27124,27125,27126,27127,27128,27129,27130, -27131,27132,27133,27134,27135,27136,27137,27138,27139,27140,27141,27142, -27143,27144,27145,27146,27147,27148,27149,27150,27151,27152,27153,27154, -27155,27156,27157,27158,27159,27160,27161,27162,27163,27164,27165,27166, -27167,27168,27169,27170,27171,27172,27173,27174,27175,27176,27177,27178, -27179,27180,27181,27182,27183,27184,27185,27186,27187,27188,27189,27190, -27191,27192,27193,27194,27195,27196,27197,27198,27199,27200,27201,27202, -27203,27204,27205,27206,27207,27208,27209,27210,27211,27212,27213,27214, -27215,27216,27217,27218,27219,27220,27221,27222,27223,27224,27225,27226, -27227,27228,27229,27230,27231,27232,27233,27234,27235,27236,27237,27238, -27239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27249,27250, -27251,27252,27253,27254,27255,27256,27257,27258,27259,27260,27261,27262, -27263,27264,27265,27266,27267,27268,27269,27270,27271,27272,27273,27274, -27275,27276,27277,27278,27279,27280,27281,27282,27283,27284,27285,27286, -27287,27288,27289,27290,27291,27292,27293,27294,27295,27296,27297,27298, -27299,27300,27301,27302,27303,27304,27305,27306,27307,27308,27309,27310, -27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322, -27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334, -27335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346, -27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358, -27359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370, -27371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382, -27383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394, -27395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406, -27407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418, -27419,27420,27421,27422,27423,27424,27425,27426,27427,27428,27429,27430, -27431,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27442, -27443,27444,27445,27446,27447,27448,27449,27450,27451,27452,27453,27454, -27455,27456,27457,27458,27459,27460,27461,27462,27463,27464,27465,27466, -27467,27468,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478, -27479,27480,27481,27482,27483,27484,27485,27486,27487,27488,27489,27490, -27491,27492,27493,27494,27495,27496,27497,27498,27499,27500,27501,27502, -27503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27513,27514, -27515,27516,27517,27518,27519,27520,27521,27522,27523,27524,27525,27526, -27527,27528,27529,27530,27531,27532,27533,27534,27535,27536,27537,27538, -27539,27540,27541,27542,27543,27544,27545,27546,27547,27548,27549,27550, -27551,27552,27553,27554,27555,27556,27557,27558,27559,27560,27561,27562, -27563,27564,27565,27566,27567,27568,27569,27570,27571,27572,27573,27574, -27575,27576,27577,27578,27579,27580,27581,27582,27583,27584,27585,27586, -27587,27588,27589,27590,27591,27592,27593,27594,27595,27596,27597,27598, -27599,27600,27601,27602,27603,27604,27605,27606,27607,27608,27609,27610, -27611,27612,27613,27614,27615,27616,27617,27618,27619,27620,27621,27622, -27623,27624,27625,27626,27627,27628,27629,27630,27631,27632,27633,27634, -27635,27636,27637,27638,27639,27640,27641,27642,27643,27644,27645,27646, -27647,27648,27649,27650,27651,27652,27653,27654,27655,27656,27657,27658, -27659,27660,27661,27662,27663,27664,27665,27666,27667,27668,27669,27670, -27671,27672,27673,27674,27675,27676,27677,27678,27679,27680,27681,27682, -27683,27684,27685,27686,27687,27688,27689,27690,27691,27692,27693,27694, -27695,27696,27697,27698,27699,27700,27701,27702,27703,27704,27705,27706, -27707,27708,27709,27710,27711,27712,27713,27714,27715,27716,27717,27718, -27719,27720,27721,27722,27723,27724,27725,27726,27727,27728,27729,27730, -27731,27732,27733,27734,27735,27736,27737,27738,27739,27740,27741,27742, -27743,27744,27745,27746,27747,27748,27749,27750,27751,27752,27753,27754, -27755,27756,27757,27758,27759,27760,27761,27762,27763,27764,27765,27766, -27767,27768,27769,27770,27771,27772,27773,27774,27775,27776,27777,27778, -27779,27780,27781,27782,27783,27784,27785,27786,27787,27788,27789,27790, -27791,27792,27793,27794,27795,27796,27797,27798,27799,27800,27801,27802, -27803,27804,27805,27806,27807,27808,27809,27810,27811,27812,27813,27814, -27815,27816,27817,27818,27819,27820,27821,27822,27823,27824,27825,27826, -27827,27828,27829,27830,27831,27832,27833,27834,27835,27836,27837,27838, -27839,27840,27841,27842,27843,27844,27845,27846,27847,27848,27849,27850, -27851,27852,27853,27854,27855,27856,27857,27858,27859,27860,27861,27862, -27863,27864,27865,27866,27867,27868,27869,27870,27871,27872,27873,27874, -27875,27876,27877,27878,27879,27880,27881,27882,27883,27884,27885,27886, -27887,27888,27889,27890,27891,27892,27893,27894,27895,27896,27897,27898, -27899,27900,27901,27902,27903,27904,27905,27906,27907,27908,27909,27910, -27911,27912,27913,27914,27915,27916,27917,27918,27919,27920,27921,27922, -27923,27924,27925,27926,27927,27928,27929,27930,27931,27932,27933,27934, -27935,27936,27937,27938,27939,27940,27941,27942,27943,27944,27945,27946, -27947,27948,27949,27950,27951,27952,27953,27954,27955,27956,27957,27958, -27959,27960,27961,27962,27963,27964,27965,27966,27967,27968,27969,27970, -27971,27972,27973,27974,27975,27976,27977,27978,27979,27980,27981,27982, -27983,27984,27985,27986,27987,27988,27989,27990,27991,27992,27993,27994, -27995,27996,27997,27998,27999,28000,28001,28002,28003,28004,28005,28006, -28007,28008,28009,28010,28011,28012,28013,28014,28015,28016,28017,28018, -28019,28020,28021,28022,28023,28024,28025,28026,28027,28028,28029,28030, -28031,28032,28033,28034,28035,28036,28037,28038,28039,28040,28041,28042, -28043,28044,28045,28046,28047,28048,28049,28050,28051,28052,28053,28054, -28055,28056,28057,28058,28059,28060,28061,28062,28063,28064,28065,28066, -28067,28068,28069,28070,28071,28072,28073,28074,28075,28076,28077,28078, -28079,28080,28081,28082,28083,28084,28085,28086,28087,28088,28089,28090, -28091,28092,28093,28094,28095,28096,28097,28098,28099,28100,28101,28102, -28103,28104,28105,28106,28107,28108,28109,28110,28111,28112,28113,28114, -28115,28116,28117,28118,28119,28120,28121,28122,28123,28124,28125,28126, -28127,28128,28129,28130,28131,28132,28133,28134,28135,28136,28137,28138, -28139,28140,28141,28142,28143,28144,28145,28146,28147,28148,28149,28150, -28151,28152,28153,28154,28155,28156,28157,28158,28159,28160,28161,28162, -28163,28164,28165,28166,28167,28168,28169,28170,28171,28172,28173,28174, -28175,28176,28177,28178,28179,28180,28181,28182,28183,28184,28185,28186, -28187,28188,28189,28190,28191,28192,28193,28194,28195,28196,28197,28198, -28199,28200,28201,28202,28203,28204,28205,28206,28207,28208,28209,28210, -28211,28212,28213,28214,28215,28216,28217,28218,28219,28220,28221,28222, -28223,28224,28225,28226,28227,28228,28229,28230,28231,28232,28233,28234, -28235,28236,28237,28238,28239,28240,28241,28242,28243,28244,28245,28246, -28247,28248,28249,28250,28251,28252,28253,28254,28255,28256,28257,28258, -28259,28260,28261,28262,28263,28264,28265,28266,28267,28268,28269,28270, -28271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282, -28283,28284,28285,28286,28287,28288,28289,28290,28291,28292,28293,28294, -28295,28296,28297,28298,28299,28300,28301,28302,28303,28304,28305,28306, -28307,28308,28309,28310,28311,28312,28313,28314,28315,28316,28317,28318, -28319,28320,28321,28322,28323,28324,28325,28326,28327,28328,28329,28330, -28331,28332,28333,28334,28335,28336,28337,28338,28339,28340,28341,28342, -28343,28344,28345,28346,28347,28348,28349,28350,28351,28352,28353,28354, -28355,28356,28357,28358,28359,28360,28361,28362,28363,28364,28365,28366, -28367,28368,28369,28370,28371,28372,28373,28374,28375,28376,28377,28378, -28379,28380,28381,28382,28383,28384,28385,28386,28387,28388,28389,28390, -28391,28392,28393,28394,28395,28396,28397,28398,28399,28400,28401,28402, -28403,28404,28405,28406,28407,28408,28409,28410,28411,28412,28413,28414, -28415,28416,28417,28418,28419,28420,28421,28422,28423,28424,28425,28426, -28427,28428,28429,28430,28431,28432,28433,28434,28435,28436,28437,28438, -28439,28440,28441,28442,28443,28444,28445,28446,28447,28448,28449,28450, -28451,28452,28453,28454,28455,28456,28457,28458,28459,28460,28461,28462, -28463,28464,28465,28466,28467,28468,28469,28470,28471,28472,28473,28474, -28475,28476,28477,28478,28479,28480,28481,28482,28483,28484,28485,28486, -28487,28488,28489,28490,28491,28492,28493,28494,28495,28496,28497,28498, -28499,28500,28501,28502,28503,28504,28505,28506,28507,28508,28509,28510, -28511,28512,28513,28514,28515,28516,28517,28518,28519,28520,28521,28522, -28523,28524,28525,28526,28527,28528,28529,28530,28531,28532,28533,28534, -28535,28536,28537,28538,28539,28540,28541,28542,28543,28544,28545,28546, -28547,28548,28549,28550,28551,28552,28553,28554,28555,28556,28557,28558, -28559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570, -28571,28572,28573,28574,28575,28576,28577,28578,28579,28580,28581,28582, -28583,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594, -28595,28596,28597,28598,28599,28600,28601,28602,28603,28604,28605,28606, -28607,28608,28609,28610,28611,28612,28613,28614,28615,28616,28617,28618, -28619,28620,28621,28622,28623,28624,28625,28626,28627,28628,28629,28630, -28631,28632,28633,28634,28635,28636,28637,28638,28639,28640,28641,28642, -28643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28654, -28655,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666, -28667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678, -28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28689,28690, -28691,28692,28693,28694,28695,28696,28697,28698,28699,28700,28701,28702, -28703,28704,28705,28706,28707,28708,28709,28710,28711,28712,28713,28714, -28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28725,28726, -28727,28728,28729,28730,28731,28732,28733,28734,28735,28736,28737,28738, -28739,28740,28741,28742,28743,28744,28745,28746,28747,28748,28749,28750, -28751,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762, -28763,28764,28765,28766,28767,28768,28769,28770,28771,28772,28773,28774, -28775,28776,28777,28778,28779,28780,28781,28782,28783,28784,28785,28786, -28787,28788,28789,28790,28791,28792,28793,28794,28795,28796,28797,28798, -28799,28800,28801,28802,28803,28804,28805,28806,28807,28808,28809,28810, -28811,28812,28813,28814,28815,28816,28817,28818,28819,28820,28821,28822, -28823,28824,28825,28826,28827,28828,28829,28830,28831,28832,28833,28834, -28835,28836,28837,28838,28839,28840,28841,28842,28843,28844,28845,28846, -28847,28848,28849,28850,28851,28852,28853,28854,28855,28856,28857,28858, -28859,28860,28861,28862,28863,28864,28865,28866,28867,28868,28869,28870, -28871,28872,28873,28874,28875,28876,28877,28878,28879,28880,28881,28882, -28883,28884,28885,28886,28887,28888,28889,28890,28891,28892,28893,28894, -28895,28896,28897,28898,28899,28900,28901,28902,28903,28904,28905,28906, -28907,28908,28909,28910,28911,28912,28913,28914,28915,28916,28917,28918, -28919,28920,28921,28922,28923,28924,28925,28926,28927,28928,28929,28930, -28931,28932,28933,28934,28935,28936,28937,28938,28939,28940,28941,28942, -28943,28944,28945,28946,28947,28948,28949,28950,28951,28952,28953,28954, -28955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28966, -28967,28968,28969,28970,28971,28972,28973,28974,28975,28976,28977,28978, -28979,28980,28981,28982,28983,28984,28985,28986,28987,28988,28989,28990, -28991,28992,28993,28994,28995,28996,28997,28998,28999,29000,29001,29002, -29003,29004,29005,29006,29007,29008,29009,29010,29011,29012,29013,29014, -29015,29016,29017,29018,29019,29020,29021,29022,29023,29024,29025,29026, -29027,29028,29029,29030,29031,29032,29033,29034,29035,29036,29037,29038, -29039,29040,29041,29042,29043,29044,29045,29046,29047,29048,29049,29050, -29051,29052,29053,29054,29055,29056,29057,29058,29059,29060,29061,29062, -29063,29064,29065,29066,29067,29068,29069,29070,29071,29072,29073,29074, -29075,29076,29077,29078,29079,29080,29081,29082,29083,29084,29085,29086, -29087,29088,29089,29090,29091,29092,29093,29094,29095,29096,29097,29098, -29099,29100,29101,29102,29103,29104,29105,29106,29107,29108,29109,29110, -29111,29112,29113,29114,29115,29116,29117,29118,29119,29120,29121,29122, -29123,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29134, -29135,29136,29137,29138,29139,29140,29141,29142,29143,29144,29145,29146, -29147,29148,29149,29150,29151,29152,29153,29154,29155,29156,29157,29158, -29159,29160,29161,29162,29163,29164,29165,29166,29167,29168,29169,29170, -29171,29172,29173,29174,29175,29176,29177,29178,29179,29180,29181,29182, -29183,29184,29185,29186,29187,29188,29189,29190,29191,29192,29193,29194, -29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206, -29207,29208,29209,29210,29211,29212,29213,29214,29215,29216,29217,29218, -29219,29220,29221,29222,29223,29224,29225,29226,29227,29228,29229,29230, -29231,29232,29233,29234,29235,29236,29237,29238,29239,29240,29241,29242, -29243,29244,29245,29246,29247,29248,29249,29250,29251,29252,29253,29254, -29255,29256,29257,29258,29259,29260,29261,29262,29263,29264,29265,29266, -29267,29268,29269,29270,29271,29272,29273,29274,29275,29276,29277,29278, -29279,29280,29281,29282,29283,29284,29285,29286,29287,29288,29289,29290, -29291,29292,29293,29294,29295,29296,29297,29298,29299,29300,29301,29302, -29303,29304,29305,29306,29307,29308,29309,29310,29311,29312,29313,29314, -29315,29316,29317,29318,29319,29320,29321,29322,29323,29324,29325,29326, -29327,29328,29329,29330,29331,29332,29333,29334,29335,29336,29337,29338, -29339,29340,29341,29342,29343,29344,29345,29346,29347,29348,29349,29350, -29351,29352,29353,29354,29355,29356,29357,29358,29359,29360,29361,29362, -29363,29364,29365,29366,29367,29368,29369,29370,29371,29372,29373,29374, -29375,29376,29377,29378,29379,29380,29381,29382,29383,29384,29385,29386, -29387,29388,29389,29390,29391,29392,29393,29394,29395,29396,29397,29398, -29399,29400,29401,29402,29403,29404,29405,29406,29407,29408,29409,29410, -29411,29412,29413,29414,29415,29416,29417,29418,29419,29420,29421,29422, -29423,29424,29425,29426,29427,29428,29429,29430,29431,29432,29433,29434, -29435,29436,29437,29438,29439,29440,29441,29442,29443,29444,29445,29446, -29447,29448,29449,29450,29451,29452,29453,29454,29455,29456,29457,29458, -29459,29460,29461,29462,29463,29464,29465,29466,29467,29468,29469,29470, -29471,29472,29473,29474,29475,29476,29477,29478,29479,29480,29481,29482, -29483,29484,29485,29486,29487,29488,29489,29490,29491,29492,29493,29494, -29495,29496,29497,29498,29499,29500,29501,29502,29503,29504,29505,29506, -29507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29517,29518, -29519,29520,29521,29522,29523,29524,29525,29526,29527,29528,29529,29530, -29531,29532,29533,29534,29535,29536,29537,29538,29539,29540,29541,29542, -29543,29544,29545,29546,29547,29548,29549,29550,29551,29552,29553,29554, -29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29566, -29567,29568,29569,29570,29571,29572,29573,29574,29575,29576,29577,29578, -29579,29580,29581,29582,29583,29584,29585,29586,29587,29588,29589,29590, -29591,29592,29593,29594,29595,29596,29597,29598,29599,29600,29601,29602, -29603,29604,29605,29606,29607,29608,29609,29610,29611,29612,29613,29614, -29615,29616,29617,29618,29619,29620,29621,29622,29623,29624,29625,29626, -29627,29628,29629,29630,29631,29632,29633,29634,29635,29636,29637,29638, -29639,29640,29641,29642,29643,29644,29645,29646,29647,29648,29649,29650, -29651,29652,29653,29654,29655,29656,29657,29658,29659,29660,29661,29662, -29663,29664,29665,29666,29667,29668,29669,29670,29671,29672,29673,29674, -29675,29676,29677,29678,29679,29680,29681,29682,29683,29684,29685,29686, -29687,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698, -29699,29700,29701,29702,29703,29704,29705,29706,29707,29708,29709,29710, -29711,29712,29713,29714,29715,29716,29717,29718,29719,29720,29721,29722, -29723,29724,29725,29726,29727,29728,29729,29730,29731,29732,29733,29734, -29735,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29746, -29747,29748,29749,29750,29751,29752,29753,29754,29755,29756,29757,29758, -29759,29760,29761,29762,29763,29764,29765,29766,29767,29768,29769,29770, -29771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29781,29782, -29783,29784,29785,29786,29787,29788,29789,29790,29791,29792,29793,29794, -29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29805,29806, -29807,29808,29809,29810,29811,29812,29813,29814,29815,29816,29817,29818, -29819,29820,29821,29822,29823,29824,29825,29826,29827,29828,29829,29830, -29831,29832,29833,29834,29835,29836,29837,29838,29839,29840,29841,29842, -29843,29844,29845,29846,29847,29848,29849,29850,29851,29852,29853,29854, -29855,29856,29857,29858,29859,29860,29861,29862,29863,29864,29865,29866, -29867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878, -29879,29880,29881,29882,29883,29884,29885,29886,29887,29888,29889,29890, -29891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902, -29903,29904,29905,29906,29907,29908,29909,29910,29911,29912,29913,29914, -29915,29916,29917,29918,29919,29920,29921,29922,29923,29924,29925,29926, -29927,29928,29929,29930,29931,29932,29933,29934,29935,29936,29937,29938, -29939,29940,29941,29942,29943,29944,29945,29946,29947,29948,29949,29950, -29951,29952,29953,29954,29955,29956,29957,29958,29959,29960,29961,29962, -29963,29964,29965,29966,29967,29968,29969,29970,29971,29972,29973,29974, -29975,29976,29977,29978,29979,29980,29981,29982,29983,29984,29985,29986, -29987,29988,29989,29990,29991,29992,29993,29994,29995,29996,29997,29998, -29999,30000,30001,30002,30003,30004,30005,30006,30007,30008,30009,30010, -30011,30012,30013,30014,30015,30016,30017,30018,30019,30020,30021,30022, -30023,30024,30025,30026,30027,30028,30029,30030,30031,30032,30033,30034, -30035,30036,30037,30038,30039,30040,30041,30042,30043,30044,30045,30046, -30047,30048,30049,30050,30051,30052,30053,30054,30055,30056,30057,30058, -30059,30060,30061,30062,30063,30064,30065,30066,30067,30068,30069,30070, -30071,30072,30073,30074,30075,30076,30077,30078,30079,30080,30081,30082, -30083,30084,30085,30086,30087,30088,30089,30090,30091,30092,30093,30094, -30095,30096,30097,30098,30099,30100,30101,30102,30103,30104,30105,30106, -30107,30108,30109,30110,30111,30112,30113,30114,30115,30116,30117,30118, -30119,30120,30121,30122,30123,30124,30125,30126,30127,30128,30129,30130, -30131,30132,30133,30134,30135,30136,30137,30138,30139,30140,30141,30142, -30143,30144,30145,30146,30147,30148,30149,30150,30151,30152,30153,30154, -30155,30156,30157,30158,30159,30160,30161,30162,30163,30164,30165,30166, -30167,30168,30169,30170,30171,30172,30173,30174,30175,30176,30177,30178, -30179,30180,30181,30182,30183,30184,30185,30186,30187,30188,30189,30190, -30191,30192,30193,30194,30195,30196,30197,30198,30199,30200,30201,30202, -30203,30204,30205,30206,30207,30208,30209,30210,30211,30212,30213,30214, -30215,30216,30217,30218,30219,30220,30221,30222,30223,30224,30225,30226, -30227,30228,30229,30230,30231,30232,30233,30234,30235,30236,30237,30238, -30239,30240,30241,30242,30243,30244,30245,30246,30247,30248,30249,30250, -30251,30252,30253,30254,30255,30256,30257,30258,30259,30260,30261,30262, -30263,30264,30265,30266,30267,30268,30269,30270,30271,30272,30273,30274, -30275,30276,30277,30278,30279,30280,30281,30282,30283,30284,30285,30286, -30287,30288,30289,30290,30291,30292,30293,30294,30295,30296,30297,30298, -30299,30300,30301,30302,30303,30304,30305,30306,30307,30308,30309,30310, -30311,30312,30313,30314,30315,30316,30317,30318,30319,30320,30321,30322, -30323,30324,30325,30326,30327,30328,30329,30330,30331,30332,30333,30334, -30335,30336,30337,30338,30339,30340,30341,30342,30343,30344,30345,30346, -30347,30348,30349,30350,30351,30352,30353,30354,30355,30356,30357,30358, -30359,30360,30361,30362,30363,30364,30365,30366,30367,30368,30369,30370, -30371,30372,30373,30374,30375,30376,30377,30378,30379,30380,30381,30382, -30383,30384,30385,30386,30387,30388,30389,30390,30391,30392,30393,30394, -30395,30396,30397,30398,30399,30400,30401,30402,30403,30404,30405,30406, -30407,30408,30409,30410,30411,30412,30413,30414,30415,30416,30417,30418, -30419,30420,30421,30422,30423,30424,30425,30426,30427,30428,30429,30430, -30431,30432,30433,30434,30435,30436,30437,30438,30439,30440,30441,30442, -30443,30444,30445,30446,30447,30448,30449,30450,30451,30452,30453,30454, -30455,30456,30457,30458,30459,30460,30461,30462,30463,30464,30465,30466, -30467,30468,30469,30470,30471,30472,30473,30474,30475,30476,30477,30478, -30479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30489,30490, -30491,30492,30493,30494,30495,30496,30497,30498,30499,30500,30501,30502, -30503,30504,30505,30506,30507,30508,30509,30510,30511,30512,30513,30514, -30515,30516,30517,30518,30519,30520,30521,30522,30523,30524,30525,30526, -30527,30528,30529,30530,30531,30532,30533,30534,30535,30536,30537,30538, -30539,30540,30541,30542,30543,30544,30545,30546,30547,30548,30549,30550, -30551,30552,30553,30554,30555,30556,30557,30558,30559,30560,30561,30562, -30563,30564,30565,30566,30567,30568,30569,30570,30571,30572,30573,30574, -30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30585,30586, -30587,30588,30589,30590,30591,30592,30593,30594,30595,30596,30597,30598, -30599,30600,30601,30602,30603,30604,30605,30606,30607,30608,30609,30610, -30611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622, -30623,30624,30625,30626,30627,30628,30629,30630,30631,30632,30633,30634, -30635,30636,30637,30638,30639,30640,30641,30642,30643,30644,30645,30646, -30647,30648,30649,30650,30651,30652,30653,30654,30655,30656,30657,30658, -30659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30669,30670, -30671,30672,30673,30674,30675,30676,30677,30678,30679,30680,30681,30682, -30683,30684,30685,30686,30687,30688,30689,30690,30691,30692,30693,30694, -30695,30696,30697,30698,30699,30700,30701,30702,30703,30704,30705,30706, -30707,30708,30709,30710,30711,30712,30713,30714,30715,30716,30717,30718, -30719,30720,30721,30722,30723,30724,30725,30726,30727,30728,30729,30730, -30731,30732,30733,30734,30735,30736,30737,30738,30739,30740,30741,30742, -30743,30744,30745,30746,30747,30748,30749,30750,30751,30752,30753,30754, -30755,30756,30757,30758,30759,30760,30761,30762,30763,30764,30765,30766, -30767,30768,30769,30770,30771,30772,30773,30774,30775,30776,30777,30778, -30779,30780,30781,30782,30783,30784,30785,30786,30787,30788,30789,30790, -30791,30792,30793,30794,30795,30796,30797,30798,30799,30800,30801,30802, -30803,30804,30805,30806,30807,30808,30809,30810,30811,30812,30813,30814, -30815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30826, -30827,30828,30829,30830,30831,30832,30833,30834,30835,30836,30837,30838, -30839,30840,30841,30842,30843,30844,30845,30846,30847,30848,30849,30850, -30851,30852,30853,30854,30855,30856,30857,30858,30859,30860,30861,30862, -30863,30864,30865,30866,30867,30868,30869,30870,30871,30872,30873,30874, -30875,30876,30877,30878,30879,30880,30881,30882,30883,30884,30885,30886, -30887,30888,30889,30890,30891,30892,30893,30894,30895,30896,30897,30898, -30899,30900,30901,30902,30903,30904,30905,30906,30907,30908,30909,30910, -30911,30912,30913,30914,30915,30916,30917,30918,30919,30920,30921,30922, -30923,30924,30925,30926,30927,30928,30929,30930,30931,30932,30933,30934, -30935,30936,30937,30938,30939,30940,30941,30942,30943,30944,30945,30946, -30947,30948,30949,30950,30951,30952,30953,30954,30955,30956,30957,30958, -30959,30960,30961,30962,30963,30964,30965,30966,30967,30968,30969,30970, -30971,30972,30973,30974,30975,30976,30977,30978,30979,30980,30981,30982, -30983,30984,30985,30986,30987,30988,30989,30990,30991,30992,30993,30994, -30995,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31006, -31007,31008,31009,31010,31011,31012,31013,31014,31015,31016,31017,31018, -31019,31020,31021,31022,31023,31024,31025,31026,31027,31028,31029,31030, -31031,31032,31033,31034,31035,31036,31037,31038,31039,31040,31041,31042, -31043,31044,31045,31046,31047,31048,31049,31050,31051,31052,31053,31054, -31055,31056,31057,31058,31059,31060,31061,31062,31063,31064,31065,31066, -31067,31068,31069,31070,31071,31072,31073,31074,31075,31076,31077,31078, -31079,31080,31081,31082,31083,31084,31085,31086,31087,31088,31089,31090, -31091,31092,31093,31094,31095,31096,31097,31098,31099,31100,31101,31102, -31103,31104,31105,31106,31107,31108,31109,31110,31111,31112,31113,31114, -31115,31116,31117,31118,31119,31120,31121,31122,31123,31124,31125,31126, -31127,31128,31129,31130,31131,31132,31133,31134,31135,31136,31137,31138, -31139,31140,31141,31142,31143,31144,31145,31146,31147,31148,31149,31150, -31151,31152,31153,31154,31155,31156,31157,31158,31159,31160,31161,31162, -31163,31164,31165,31166,31167,31168,31169,31170,31171,31172,31173,31174, -31175,31176,31177,31178,31179,31180,31181,31182,31183,31184,31185,31186, -31187,31188,31189,31190,31191,31192,31193,31194,31195,31196,31197,31198, -31199,31200,31201,31202,31203,31204,31205,31206,31207,31208,31209,31210, -31211,31212,31213,31214,31215,31216,31217,31218,31219,31220,31221,31222, -31223,31224,31225,31226,31227,31228,31229,31230,31231,31232,31233,31234, -31235,31236,31237,31238,31239,31240,31241,31242,31243,31244,31245,31246, -31247,31248,31249,31250,31251,31252,31253,31254,31255,31256,31257,31258, -31259,31260,31261,31262,31263,31264,31265,31266,31267,31268,31269,31270, -31271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282, -31283,31284,31285,31286,31287,31288,31289,31290,31291,31292,31293,31294, -31295,31296,31297,31298,31299,31300,31301,31302,31303,31304,31305,31306, -31307,31308,31309,31310,31311,31312,31313,31314,31315,31316,31317,31318, -31319,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330, -31331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342, -31343,31344,31345,31346,31347,31348,31349,31350,31351,31352,31353,31354, -31355,31356,31357,31358,31359,31360,31361,31362,31363,31364,31365,31366, -31367,31368,31369,31370,31371,31372,31373,31374,31375,31376,31377,31378, -31379,31380,31381,31382,31383,31384,31385,31386,31387,31388,31389,31390, -31391,31392,31393,31394,31395,31396,31397,31398,31399,31400,31401,31402, -31403,31404,31405,31406,31407,31408,31409,31410,31411,31412,31413,31414, -31415,31416,31417,31418,31419,31420,31421,31422,31423,31424,31425,31426, -31427,31428,31429,31430,31431,31432,31433,31434,31435,31436,31437,31438, -31439,31440,31441,31442,31443,31444,31445,31446,31447,31448,31449,31450, -31451,31452,31453,31454,31455,31456,31457,31458,31459,31460,31461,31462, -31463,31464,31465,31466,31467,31468,31469,31470,31471,31472,31473,31474, -31475,31476,31477,31478,31479,31480,31481,31482,31483,31484,31485,31486, -31487,31488,31489,31490,31491,31492,31493,31494,31495,31496,31497,31498, -31499,31500,31501,31502,31503,31504,31505,31506,31507,31508,31509,31510, -31511,31512,31513,31514,31515,31516,31517,31518,31519,31520,31521,31522, -31523,31524,31525,31526,31527,31528,31529,31530,31531,31532,31533,31534, -31535,31536,31537,31538,31539,31540,31541,31542,31543,31544,31545,31546, -31547,31548,31549,31550,31551,31552,31553,31554,31555,31556,31557,31558, -31559,31560,31561,31562,31563,31564,31565,31566,31567,31568,31569,31570, -31571,31572,31573,31574,31575,31576,31577,31578,31579,31580,31581,31582, -31583,31584,31585,31586,31587,31588,31589,31590,31591,31592,31593,31594, -31595,31596,31597,31598,31599,31600,31601,31602,31603,31604,31605,31606, -31607,31608,31609,31610,31611,31612,31613,31614,31615,31616,31617,31618, -31619,31620,31621,31622,31623,31624,31625,31626,31627,31628,31629,31630, -31631,31632,31633,31634,31635,31636,31637,31638,31639,31640,31641,31642, -31643,31644,31645,31646,31647,31648,31649,31650,31651,31652,31653,31654, -31655,31656,31657,31658,31659,31660,31661,31662,31663,31664,31665,31666, -31667,31668,31669,31670,31671,31672,31673,31674,31675,31676,31677,31678, -31679,31680,31681,31682,31683,31684,31685,31686,31687,31688,31689,31690, -31691,31692,31693,31694,31695,31696,31697,31698,31699,31700,31701,31702, -31703,31704,31705,31706,31707,31708,31709,31710,31711,31712,31713,31714, -31715,31716,31717,31718,31719,31720,31721,31722,31723,31724,31725,31726, -31727,31728,31729,31730,31731,31732,31733,31734,31735,31736,31737,31738, -31739,31740,31741,31742,31743,31744,31745,31746,31747,31748,31749,31750, -31751,31752,31753,31754,31755,31756,31757,31758,31759,31760,31761,31762, -31763,31764,31765,31766,31767,31768,31769,31770,31771,31772,31773,31774, -31775,31776,31777,31778,31779,31780,31781,31782,31783,31784,31785,31786, -31787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798, -31799,31800,31801,31802,31803,31804,31805,31806,31807,31808,31809,31810, -31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31821,31822, -31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834, -31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846, -31847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858, -31859,31860,31861,31862,31863,31864,31865,31866,31867,31868,31869,31870, -31871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31881,31882, -31883,31884,31885,31886,31887,31888,31889,31890,31891,31892,31893,31894, -31895,31896,31897,31898,31899,31900,31901,31902,31903,31904,31905,31906, -31907,31908,31909,31910,31911,31912,31913,31914,31915,31916,31917,31918, -31919,31920,31921,31922,31923,31924,31925,31926,31927,31928,31929,31930, -31931,31932,31933,31934,31935,31936,31937,31938,31939,31940,31941,31942, -31943,31944,31945,31946,31947,31948,31949,31950,31951,31952,31953,31954, -31955,31956,31957,31958,31959,31960,31961,31962,31963,31964,31965,31966, -31967,31968,31969,31970,31971,31972,31973,31974,31975,31976,31977,31978, -31979,31980,31981,31982,31983,31984,31985,31986,31987,31988,31989,31990, -31991,31992,31993,31994,31995,31996,31997,31998,31999,32000,32001,32002, -32003,32004,32005,32006,32007,32008,32009,32010,32011,32012,32013,32014, -32015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026, -32027,32028,32029,32030,32031,32032,32033,32034,32035,32036,32037,32038, -32039,32040,32041,32042,32043,32044,32045,32046,32047,32048,32049,32050, -32051,32052,32053,32054,32055,32056,32057,32058,32059,32060,32061,32062, -32063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074, -32075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086, -32087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098, -32099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32110, -32111,32112,32113,32114,32115,32116,32117,32118,32119,32120,32121,32122, -32123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134, -32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146, -32147,32148,32149,32150,32151,32152,32153,32154,32155,32156,32157,32158, -32159,32160,32161,32162,32163,32164,32165,32166,32167,32168,32169,32170, -32171,32172,32173,32174,32175,32176,32177,32178,32179,32180,32181,32182, -32183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194, -32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206, -32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218, -32219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230, -32231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242, -32243,32244,32245,32246,32247,32248,32249,32250,32251,32252,32253,32254, -32255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266, -32267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278, -32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290, -32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302, -32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314, -32315,32316,32317,32318,32319,32320,32321,32322,32323,32324,32325,32326, -32327,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338, -32339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,32350, -32351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362, -32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374, -32375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32386, -32387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398, -32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410, -32411,32412,32413,32414,32415,32416,32417,32418,32419,32420,32421,32422, -32423,32424,32425,32426,32427,32428,32429,32430,32431,32432,32433,32434, -32435,32436,32437,32438,32439,32440,32441,32442,32443,32444,32445,32446, -32447,32448,32449,32450,32451,32452,32453,32454,32455,32456,32457,32458, -32459,32460,32461,32462,32463,32464,32465,32466,32467,32468,32469,32470, -32471,32472,32473,32474,32475,32476,32477,32478,32479,32480,32481,32482, -32483,32484,32485,32486,32487,32488,32489,32490,32491,32492,32493,32494, -32495,32496,32497,32498,32499,32500,32501,32502,32503,32504,32505,32506, -32507,32508,32509,32510,32511,32512,32513,32514,32515,32516,32517,32518, -32519,32520,32521,32522,32523,32524,32525,32526,32527,32528,32529,32530, -32531,32532,32533,32534,32535,32536,32537,32538,32539,32540,32541,32542, -32543,32544,32545,32546,32547,32548,32549,32550,32551,32552,32553,32554, -32555,32556,32557,32558,32559,32560,32561,32562,32563,32564,32565,32566, -32567,32568,32569,32570,32571,32572,32573,32574,32575,32576,32577,32578, -32579,32580,32581,32582,32583,32584,32585,32586,32587,32588,32589,32590, -32591,32592,32593,32594,32595,32596,32597,32598,32599,32600,32601,32602, -32603,32604,32605,32606,32607,32608,32609,32610,32611,32612,32613,32614, -32615,32616,32617,32618,32619,32620,32621,32622,32623,32624,32625,32626, -32627,32628,32629,32630,32631,32632,32633,32634,32635,32636,32637,32638, -32639,32640,32641,32642,32643,32644,32645,32646,32647,32648,32649,32650, -32651,32652,32653,32654,32655,32656,32657,32658,32659,32660,32661,32662, -32663,32664,32665,32666,32667,32668,32669,32670,32671,32672,32673,32674, -32675,32676,32677,32678,32679,32680,32681,32682,32683,32684,32685,32686, -32687,32688,32689,32690,32691,32692,32693,32694,32695,32696,32697,32698, -32699,32700,32701,32702,32703,32704,32705,32706,32707,32708,32709,32710, -32711,32712,32713,32714,32715,32716,32717,32718,32719,32720,32721,32722, -32723,32724,32725,32726,32727,32728,32729,32730,32731,32732,32733,32734, -32735,32736,32737,32738,32739,32740,32741,32742,32743,32744,32745,32746, -32747,32748,32749,32750,32751,32752,32753,32754,32755,32756,32757,32758, -32759,32760,32761,32762,32763,32764,32765,32766,32767,32768L,32769L,32770L, -32771L,32772L,32773L,32774L,32775L,32776L,32777L,32778L,32779L,32780L, -32781L,32782L,32783L,32784L,32785L,32786L,32787L,32788L,32789L,32790L, -32791L,32792L,32793L,32794L,32795L,32796L,32797L,32798L,32799L,32800L, -32801L,32802L,32803L,32804L,32805L,32806L,32807L,32808L,32809L,32810L, -32811L,32812L,32813L,32814L,32815L,32816L,32817L,32818L,32819L,32820L, -32821L,32822L,32823L,32824L,32825L,32826L,32827L,32828L,32829L,32830L, -32831L,32832L,32833L,32834L,32835L,32836L,32837L,32838L,32839L,32840L, -32841L,32842L,32843L,32844L,32845L,32846L,32847L,32848L,32849L,32850L, -32851L,32852L,32853L,32854L,32855L,32856L,32857L,32858L,32859L,32860L, -32861L,32862L,32863L,32864L,32865L,32866L,32867L,32868L,32869L,32870L, -32871L,32872L,32873L,32874L,32875L,32876L,32877L,32878L,32879L,32880L, -32881L,32882L,32883L,32884L,32885L,32886L,32887L,32888L,32889L,32890L, -32891L,32892L,32893L,32894L,32895L,32896L,32897L,32898L,32899L,32900L, -32901L,32902L,32903L,32904L,32905L,32906L,32907L,32908L,32909L,32910L, -32911L,32912L,32913L,32914L,32915L,32916L,32917L,32918L,32919L,32920L, -32921L,32922L,32923L,32924L,32925L,32926L,32927L,32928L,32929L,32930L, -32931L,32932L,32933L,32934L,32935L,32936L,32937L,32938L,32939L,32940L, -32941L,32942L,32943L,32944L,32945L,32946L,32947L,32948L,32949L,32950L, -32951L,32952L,32953L,32954L,32955L,32956L,32957L,32958L,32959L,32960L, -32961L,32962L,32963L,32964L,32965L,32966L,32967L,32968L,32969L,32970L, -32971L,32972L,32973L,32974L,32975L,32976L,32977L,32978L,32979L,32980L, -32981L,32982L,32983L,32984L,32985L,32986L,32987L,32988L,32989L,32990L, -32991L,32992L,32993L,32994L,32995L,32996L,32997L,32998L,32999L,33000L, -33001L,33002L,33003L,33004L,33005L,33006L,33007L,33008L,33009L,33010L, -33011L,33012L,33013L,33014L,33015L,33016L,33017L,33018L,33019L,33020L, -33021L,33022L,33023L,33024L,33025L,33026L,33027L,33028L,33029L,33030L, -33031L,33032L,33033L,33034L,33035L,33036L,33037L,33038L,33039L,33040L, -33041L,33042L,33043L,33044L,33045L,33046L,33047L,33048L,33049L,33050L, -33051L,33052L,33053L,33054L,33055L,33056L,33057L,33058L,33059L,33060L, -33061L,33062L,33063L,33064L,33065L,33066L,33067L,33068L,33069L,33070L, -33071L,33072L,33073L,33074L,33075L,33076L,33077L,33078L,33079L,33080L, -33081L,33082L,33083L,33084L,33085L,33086L,33087L,33088L,33089L,33090L, -33091L,33092L,33093L,33094L,33095L,33096L,33097L,33098L,33099L,33100L, -33101L,33102L,33103L,33104L,33105L,33106L,33107L,33108L,33109L,33110L, -33111L,33112L,33113L,33114L,33115L,33116L,33117L,33118L,33119L,33120L, -33121L,33122L,33123L,33124L,33125L,33126L,33127L,33128L,33129L,33130L, -33131L,33132L,33133L,33134L,33135L,33136L,33137L,33138L,33139L,33140L, -33141L,33142L,33143L,33144L,33145L,33146L,33147L,33148L,33149L,33150L, -33151L,33152L,33153L,33154L,33155L,33156L,33157L,33158L,33159L,33160L, -33161L,33162L,33163L,33164L,33165L,33166L,33167L,33168L,33169L,33170L, -33171L,33172L,33173L,33174L,33175L,33176L,33177L,33178L,33179L,33180L, -33181L,33182L,33183L,33184L,33185L,33186L,33187L,33188L,33189L,33190L, -33191L,33192L,33193L,33194L,33195L,33196L,33197L,33198L,33199L,33200L, -33201L,33202L,33203L,33204L,33205L,33206L,33207L,33208L,33209L,33210L, -33211L,33212L,33213L,33214L,33215L,33216L,33217L,33218L,33219L,33220L, -33221L,33222L,33223L,33224L,33225L,33226L,33227L,33228L,33229L,33230L, -33231L,33232L,33233L,33234L,33235L,33236L,33237L,33238L,33239L,33240L, -33241L,33242L,33243L,33244L,33245L,33246L,33247L,33248L,33249L,33250L, -33251L,33252L,33253L,33254L,33255L,33256L,33257L,33258L,33259L,33260L, -33261L,33262L,33263L,33264L,33265L,33266L,33267L,33268L,33269L,33270L, -33271L,33272L,33273L,33274L,33275L,33276L,33277L,33278L,33279L,33280L, -33281L,33282L,33283L,33284L,33285L,33286L,33287L,33288L,33289L,33290L, -33291L,33292L,33293L,33294L,33295L,33296L,33297L,33298L,33299L,33300L, -33301L,33302L,33303L,33304L,33305L,33306L,33307L,33308L,33309L,33310L, -33311L,33312L,33313L,33314L,33315L,33316L,33317L,33318L,33319L,33320L, -33321L,33322L,33323L,33324L,33325L,33326L,33327L,33328L,33329L,33330L, -33331L,33332L,33333L,33334L,33335L,33336L,33337L,33338L,33339L,33340L, -33341L,33342L,33343L,33344L,33345L,33346L,33347L,33348L,33349L,33350L, -33351L,33352L,33353L,33354L,33355L,33356L,33357L,33358L,33359L,33360L, -33361L,33362L,33363L,33364L,33365L,33366L,33367L,33368L,33369L,33370L, -33371L,33372L,33373L,33374L,33375L,33376L,33377L,33378L,33379L,33380L, -33381L,33382L,33383L,33384L,33385L,33386L,33387L,33388L,33389L,33390L, -33391L,33392L,33393L,33394L,33395L,33396L,33397L,33398L,33399L,33400L, -33401L,33402L,33403L,33404L,33405L,33406L,33407L,33408L,33409L,33410L, -33411L,33412L,33413L,33414L,33415L,33416L,33417L,33418L,33419L,33420L, -33421L,33422L,33423L,33424L,33425L,33426L,33427L,33428L,33429L,33430L, -33431L,33432L,33433L,33434L,33435L,33436L,33437L,33438L,33439L,33440L, -33441L,33442L,33443L,33444L,33445L,33446L,33447L,33448L,33449L,33450L, -33451L,33452L,33453L,33454L,33455L,33456L,33457L,33458L,33459L,33460L, -33461L,33462L,33463L,33464L,33465L,33466L,33467L,33468L,33469L,33470L, -33471L,33472L,33473L,33474L,33475L,33476L,33477L,33478L,33479L,33480L, -33481L,33482L,33483L,33484L,33485L,33486L,33487L,33488L,33489L,33490L, -33491L,33492L,33493L,33494L,33495L,33496L,33497L,33498L,33499L,33500L, -33501L,33502L,33503L,33504L,33505L,33506L,33507L,33508L,33509L,33510L, -33511L,33512L,33513L,33514L,33515L,33516L,33517L,33518L,33519L,33520L, -33521L,33522L,33523L,33524L,33525L,33526L,33527L,33528L,33529L,33530L, -33531L,33532L,33533L,33534L,33535L,33536L,33537L,33538L,33539L,33540L, -33541L,33542L,33543L,33544L,33545L,33546L,33547L,33548L,33549L,33550L, -33551L,33552L,33553L,33554L,33555L,33556L,33557L,33558L,33559L,33560L, -33561L,33562L,33563L,33564L,33565L,33566L,33567L,33568L,33569L,33570L, -33571L,33572L,33573L,33574L,33575L,33576L,33577L,33578L,33579L,33580L, -33581L,33582L,33583L,33584L,33585L,33586L,33587L,33588L,33589L,33590L, -33591L,33592L,33593L,33594L,33595L,33596L,33597L,33598L,33599L,33600L, -33601L,33602L,33603L,33604L,33605L,33606L,33607L,33608L,33609L,33610L, -33611L,33612L,33613L,33614L,33615L,33616L,33617L,33618L,33619L,33620L, -33621L,33622L,33623L,33624L,33625L,33626L,33627L,33628L,33629L,33630L, -33631L,33632L,33633L,33634L,33635L,33636L,33637L,33638L,33639L,33640L, -33641L,33642L,33643L,33644L,33645L,33646L,33647L,33648L,33649L,33650L, -33651L,33652L,33653L,33654L,33655L,33656L,33657L,33658L,33659L,33660L, -33661L,33662L,33663L,33664L,33665L,33666L,33667L,33668L,33669L,33670L, -33671L,33672L,33673L,33674L,33675L,33676L,33677L,33678L,33679L,33680L, -33681L,33682L,33683L,33684L,33685L,33686L,33687L,33688L,33689L,33690L, -33691L,33692L,33693L,33694L,33695L,33696L,33697L,33698L,33699L,33700L, -33701L,33702L,33703L,33704L,33705L,33706L,33707L,33708L,33709L,33710L, -33711L,33712L,33713L,33714L,33715L,33716L,33717L,33718L,33719L,33720L, -33721L,33722L,33723L,33724L,33725L,33726L,33727L,33728L,33729L,33730L, -33731L,33732L,33733L,33734L,33735L,33736L,33737L,33738L,33739L,33740L, -33741L,33742L,33743L,33744L,33745L,33746L,33747L,33748L,33749L,33750L, -33751L,33752L,33753L,33754L,33755L,33756L,33757L,33758L,33759L,33760L, -33761L,33762L,33763L,33764L,33765L,33766L,33767L,33768L,33769L,33770L, -33771L,33772L,33773L,33774L,33775L,33776L,33777L,33778L,33779L,33780L, -33781L,33782L,33783L,33784L,33785L,33786L,33787L,33788L,33789L,33790L, -33791L,33792L,33793L,33794L,33795L,33796L,33797L,33798L,33799L,33800L, -33801L,33802L,33803L,33804L,33805L,33806L,33807L,33808L,33809L,33810L, -33811L,33812L,33813L,33814L,33815L,33816L,33817L,33818L,33819L,33820L, -33821L,33822L,33823L,33824L,33825L,33826L,33827L,33828L,33829L,33830L, -33831L,33832L,33833L,33834L,33835L,33836L,33837L,33838L,33839L,33840L, -33841L,33842L,33843L,33844L,33845L,33846L,33847L,33848L,33849L,33850L, -33851L,33852L,33853L,33854L,33855L,33856L,33857L,33858L,33859L,33860L, -33861L,33862L,33863L,33864L,33865L,33866L,33867L,33868L,33869L,33870L, -33871L,33872L,33873L,33874L,33875L,33876L,33877L,33878L,33879L,33880L, -33881L,33882L,33883L,33884L,33885L,33886L,33887L,33888L,33889L,33890L, -33891L,33892L,33893L,33894L,33895L,33896L,33897L,33898L,33899L,33900L, -33901L,33902L,33903L,33904L,33905L,33906L,33907L,33908L,33909L,33910L, -33911L,33912L,33913L,33914L,33915L,33916L,33917L,33918L,33919L,33920L, -33921L,33922L,33923L,33924L,33925L,33926L,33927L,33928L,33929L,33930L, -33931L,33932L,33933L,33934L,33935L,33936L,33937L,33938L,33939L,33940L, -33941L,33942L,33943L,33944L,33945L,33946L,33947L,33948L,33949L,33950L, -33951L,33952L,33953L,33954L,33955L,33956L,33957L,33958L,33959L,33960L, -33961L,33962L,33963L,33964L,33965L,33966L,33967L,33968L,33969L,33970L, -33971L,33972L,33973L,33974L,33975L,33976L,33977L,33978L,33979L,33980L, -33981L,33982L,33983L,33984L,33985L,33986L,33987L,33988L,33989L,33990L, -33991L,33992L,33993L,33994L,33995L,33996L,33997L,33998L,33999L,34000L, -34001L,34002L,34003L,34004L,34005L,34006L,34007L,34008L,34009L,34010L, -34011L,34012L,34013L,34014L,34015L,34016L,34017L,34018L,34019L,34020L, -34021L,34022L,34023L,34024L,34025L,34026L,34027L,34028L,34029L,34030L, -34031L,34032L,34033L,34034L,34035L,34036L,34037L,34038L,34039L,34040L, -34041L,34042L,34043L,34044L,34045L,34046L,34047L,34048L,34049L,34050L, -34051L,34052L,34053L,34054L,34055L,34056L,34057L,34058L,34059L,34060L, -34061L,34062L,34063L,34064L,34065L,34066L,34067L,34068L,34069L,34070L, -34071L,34072L,34073L,34074L,34075L,34076L,34077L,34078L,34079L,34080L, -34081L,34082L,34083L,34084L,34085L,34086L,34087L,34088L,34089L,34090L, -34091L,34092L,34093L,34094L,34095L,34096L,34097L,34098L,34099L,34100L, -34101L,34102L,34103L,34104L,34105L,34106L,34107L,34108L,34109L,34110L, -34111L,34112L,34113L,34114L,34115L,34116L,34117L,34118L,34119L,34120L, -34121L,34122L,34123L,34124L,34125L,34126L,34127L,34128L,34129L,34130L, -34131L,34132L,34133L,34134L,34135L,34136L,34137L,34138L,34139L,34140L, -34141L,34142L,34143L,34144L,34145L,34146L,34147L,34148L,34149L,34150L, -34151L,34152L,34153L,34154L,34155L,34156L,34157L,34158L,34159L,34160L, -34161L,34162L,34163L,34164L,34165L,34166L,34167L,34168L,34169L,34170L, -34171L,34172L,34173L,34174L,34175L,34176L,34177L,34178L,34179L,34180L, -34181L,34182L,34183L,34184L,34185L,34186L,34187L,34188L,34189L,34190L, -34191L,34192L,34193L,34194L,34195L,34196L,34197L,34198L,34199L,34200L, -34201L,34202L,34203L,34204L,34205L,34206L,34207L,34208L,34209L,34210L, -34211L,34212L,34213L,34214L,34215L,34216L,34217L,34218L,34219L,34220L, -34221L,34222L,34223L,34224L,34225L,34226L,34227L,34228L,34229L,34230L, -34231L,34232L,34233L,34234L,34235L,34236L,34237L,34238L,34239L,34240L, -34241L,34242L,34243L,34244L,34245L,34246L,34247L,34248L,34249L,34250L, -34251L,34252L,34253L,34254L,34255L,34256L,34257L,34258L,34259L,34260L, -34261L,34262L,34263L,34264L,34265L,34266L,34267L,34268L,34269L,34270L, -34271L,34272L,34273L,34274L,34275L,34276L,34277L,34278L,34279L,34280L, -34281L,34282L,34283L,34284L,34285L,34286L,34287L,34288L,34289L,34290L, -34291L,34292L,34293L,34294L,34295L,34296L,34297L,34298L,34299L,34300L, -34301L,34302L,34303L,34304L,34305L,34306L,34307L,34308L,34309L,34310L, -34311L,34312L,34313L,34314L,34315L,34316L,34317L,34318L,34319L,34320L, -34321L,34322L,34323L,34324L,34325L,34326L,34327L,34328L,34329L,34330L, -34331L,34332L,34333L,34334L,34335L,34336L,34337L,34338L,34339L,34340L, -34341L,34342L,34343L,34344L,34345L,34346L,34347L,34348L,34349L,34350L, -34351L,34352L,34353L,34354L,34355L,34356L,34357L,34358L,34359L,34360L, -34361L,34362L,34363L,34364L,34365L,34366L,34367L,34368L,34369L,34370L, -34371L,34372L,34373L,34374L,34375L,34376L,34377L,34378L,34379L,34380L, -34381L,34382L,34383L,34384L,34385L,34386L,34387L,34388L,34389L,34390L, -34391L,34392L,34393L,34394L,34395L,34396L,34397L,34398L,34399L,34400L, -34401L,34402L,34403L,34404L,34405L,34406L,34407L,34408L,34409L,34410L, -34411L,34412L,34413L,34414L,34415L,34416L,34417L,34418L,34419L,34420L, -34421L,34422L,34423L,34424L,34425L,34426L,34427L,34428L,34429L,34430L, -34431L,34432L,34433L,34434L,34435L,34436L,34437L,34438L,34439L,34440L, -34441L,34442L,34443L,34444L,34445L,34446L,34447L,34448L,34449L,34450L, -34451L,34452L,34453L,34454L,34455L,34456L,34457L,34458L,34459L,34460L, -34461L,34462L,34463L,34464L,34465L,34466L,34467L,34468L,34469L,34470L, -34471L,34472L,34473L,34474L,34475L,34476L,34477L,34478L,34479L,34480L, -34481L,34482L,34483L,34484L,34485L,34486L,34487L,34488L,34489L,34490L, -34491L,34492L,34493L,34494L,34495L,34496L,34497L,34498L,34499L,34500L, -34501L,34502L,34503L,34504L,34505L,34506L,34507L,34508L,34509L,34510L, -34511L,34512L,34513L,34514L,34515L,34516L,34517L,34518L,34519L,34520L, -34521L,34522L,34523L,34524L,34525L,34526L,34527L,34528L,34529L,34530L, -34531L,34532L,34533L,34534L,34535L,34536L,34537L,34538L,34539L,34540L, -34541L,34542L,34543L,34544L,34545L,34546L,34547L,34548L,34549L,34550L, -34551L,34552L,34553L,34554L,34555L,34556L,34557L,34558L,34559L,34560L, -34561L,34562L,34563L,34564L,34565L,34566L,34567L,34568L,34569L,34570L, -34571L,34572L,34573L,34574L,34575L,34576L,34577L,34578L,34579L,34580L, -34581L,34582L,34583L,34584L,34585L,34586L,34587L,34588L,34589L,34590L, -34591L,34592L,34593L,34594L,34595L,34596L,34597L,34598L,34599L,34600L, -34601L,34602L,34603L,34604L,34605L,34606L,34607L,34608L,34609L,34610L, -34611L,34612L,34613L,34614L,34615L,34616L,34617L,34618L,34619L,34620L, -34621L,34622L,34623L,34624L,34625L,34626L,34627L,34628L,34629L,34630L, -34631L,34632L,34633L,34634L,34635L,34636L,34637L,34638L,34639L,34640L, -34641L,34642L,34643L,34644L,34645L,34646L,34647L,34648L,34649L,34650L, -34651L,34652L,34653L,34654L,34655L,34656L,34657L,34658L,34659L,34660L, -34661L,34662L,34663L,34664L,34665L,34666L,34667L,34668L,34669L,34670L, -34671L,34672L,34673L,34674L,34675L,34676L,34677L,34678L,34679L,34680L, -34681L,34682L,34683L,34684L,34685L,34686L,34687L,34688L,34689L,34690L, -34691L,34692L,34693L,34694L,34695L,34696L,34697L,34698L,34699L,34700L, -34701L,34702L,34703L,34704L,34705L,34706L,34707L,34708L,34709L,34710L, -34711L,34712L,34713L,34714L,34715L,34716L,34717L,34718L,34719L,34720L, -34721L,34722L,34723L,34724L,34725L,34726L,34727L,34728L,34729L,34730L, -34731L,34732L,34733L,34734L,34735L,34736L,34737L,34738L,34739L,34740L, -34741L,34742L,34743L,34744L,34745L,34746L,34747L,34748L,34749L,34750L, -34751L,34752L,34753L,34754L,34755L,34756L,34757L,34758L,34759L,34760L, -34761L,34762L,34763L,34764L,34765L,34766L,34767L,34768L,34769L,34770L, -34771L,34772L,34773L,34774L,34775L,34776L,34777L,34778L,34779L,34780L, -34781L,34782L,34783L,34784L,34785L,34786L,34787L,34788L,34789L,34790L, -34791L,34792L,34793L,34794L,34795L,34796L,34797L,34798L,34799L,34800L, -34801L,34802L,34803L,34804L,34805L,34806L,34807L,34808L,34809L,34810L, -34811L,34812L,34813L,34814L,34815L,34816L,34817L,34818L,34819L,34820L, -34821L,34822L,34823L,34824L,34825L,34826L,34827L,34828L,34829L,34830L, -34831L,34832L,34833L,34834L,34835L,34836L,34837L,34838L,34839L,34840L, -34841L,34842L,34843L,34844L,34845L,34846L,34847L,34848L,34849L,34850L, -34851L,34852L,34853L,34854L,34855L,34856L,34857L,34858L,34859L,34860L, -34861L,34862L,34863L,34864L,34865L,34866L,34867L,34868L,34869L,34870L, -34871L,34872L,34873L,34874L,34875L,34876L,34877L,34878L,34879L,34880L, -34881L,34882L,34883L,34884L,34885L,34886L,34887L,34888L,34889L,34890L, -34891L,34892L,34893L,34894L,34895L,34896L,34897L,34898L,34899L,34900L, -34901L,34902L,34903L,34904L,34905L,34906L,34907L,34908L,34909L,34910L, -34911L,34912L,34913L,34914L,34915L,34916L,34917L,34918L,34919L,34920L, -34921L,34922L,34923L,34924L,34925L,34926L,34927L,34928L,34929L,34930L, -34931L,34932L,34933L,34934L,34935L,34936L,34937L,34938L,34939L,34940L, -34941L,34942L,34943L,34944L,34945L,34946L,34947L,34948L,34949L,34950L, -34951L,34952L,34953L,34954L,34955L,34956L,34957L,34958L,34959L,34960L, -34961L,34962L,34963L,34964L,34965L,34966L,34967L,34968L,34969L,34970L, -34971L,34972L,34973L,34974L,34975L,34976L,34977L,34978L,34979L,34980L, -34981L,34982L,34983L,34984L,34985L,34986L,34987L,34988L,34989L,34990L, -34991L,34992L,34993L,34994L,34995L,34996L,34997L,34998L,34999L,35000L, -35001L,35002L,35003L,35004L,35005L,35006L,35007L,35008L,35009L,35010L, -35011L,35012L,35013L,35014L,35015L,35016L,35017L,35018L,35019L,35020L, -35021L,35022L,35023L,35024L,35025L,35026L,35027L,35028L,35029L,35030L, -35031L,35032L,35033L,35034L,35035L,35036L,35037L,35038L,35039L,35040L, -35041L,35042L,35043L,35044L,35045L,35046L,35047L,35048L,35049L,35050L, -35051L,35052L,35053L,35054L,35055L,35056L,35057L,35058L,35059L,35060L, -35061L,35062L,35063L,35064L,35065L,35066L,35067L,35068L,35069L,35070L, -35071L,35072L,35073L,35074L,35075L,35076L,35077L,35078L,35079L,35080L, -35081L,35082L,35083L,35084L,35085L,35086L,35087L,35088L,35089L,35090L, -35091L,35092L,35093L,35094L,35095L,35096L,35097L,35098L,35099L,35100L, -35101L,35102L,35103L,35104L,35105L,35106L,35107L,35108L,35109L,35110L, -35111L,35112L,35113L,35114L,35115L,35116L,35117L,35118L,35119L,35120L, -35121L,35122L,35123L,35124L,35125L,35126L,35127L,35128L,35129L,35130L, -35131L,35132L,35133L,35134L,35135L,35136L,35137L,35138L,35139L,35140L, -35141L,35142L,35143L,35144L,35145L,35146L,35147L,35148L,35149L,35150L, -35151L,35152L,35153L,35154L,35155L,35156L,35157L,35158L,35159L,35160L, -35161L,35162L,35163L,35164L,35165L,35166L,35167L,35168L,35169L,35170L, -35171L,35172L,35173L,35174L,35175L,35176L,35177L,35178L,35179L,35180L, -35181L,35182L,35183L,35184L,35185L,35186L,35187L,35188L,35189L,35190L, -35191L,35192L,35193L,35194L,35195L,35196L,35197L,35198L,35199L,35200L, -35201L,35202L,35203L,35204L,35205L,35206L,35207L,35208L,35209L,35210L, -35211L,35212L,35213L,35214L,35215L,35216L,35217L,35218L,35219L,35220L, -35221L,35222L,35223L,35224L,35225L,35226L,35227L,35228L,35229L,35230L, -35231L,35232L,35233L,35234L,35235L,35236L,35237L,35238L,35239L,35240L, -35241L,35242L,35243L,35244L,35245L,35246L,35247L,35248L,35249L,35250L, -35251L,35252L,35253L,35254L,35255L,35256L,35257L,35258L,35259L,35260L, -35261L,35262L,35263L,35264L,35265L,35266L,35267L,35268L,35269L,35270L, -35271L,35272L,35273L,35274L,35275L,35276L,35277L,35278L,35279L,35280L, -35281L,35282L,35283L,35284L,35285L,35286L,35287L,35288L,35289L,35290L, -35291L,35292L,35293L,35294L,35295L,35296L,35297L,35298L,35299L,35300L, -35301L,35302L,35303L,35304L,35305L,35306L,35307L,35308L,35309L,35310L, -35311L,35312L,35313L,35314L,35315L,35316L,35317L,35318L,35319L,35320L, -35321L,35322L,35323L,35324L,35325L,35326L,35327L,35328L,35329L,35330L, -35331L,35332L,35333L,35334L,35335L,35336L,35337L,35338L,35339L,35340L, -35341L,35342L,35343L,35344L,35345L,35346L,35347L,35348L,35349L,35350L, -35351L,35352L,35353L,35354L,35355L,35356L,35357L,35358L,35359L,35360L, -35361L,35362L,35363L,35364L,35365L,35366L,35367L,35368L,35369L,35370L, -35371L,35372L,35373L,35374L,35375L,35376L,35377L,35378L,35379L,35380L, -35381L,35382L,35383L,35384L,35385L,35386L,35387L,35388L,35389L,35390L, -35391L,35392L,35393L,35394L,35395L,35396L,35397L,35398L,35399L,35400L, -35401L,35402L,35403L,35404L,35405L,35406L,35407L,35408L,35409L,35410L, -35411L,35412L,35413L,35414L,35415L,35416L,35417L,35418L,35419L,35420L, -35421L,35422L,35423L,35424L,35425L,35426L,35427L,35428L,35429L,35430L, -35431L,35432L,35433L,35434L,35435L,35436L,35437L,35438L,35439L,35440L, -35441L,35442L,35443L,35444L,35445L,35446L,35447L,35448L,35449L,35450L, -35451L,35452L,35453L,35454L,35455L,35456L,35457L,35458L,35459L,35460L, -35461L,35462L,35463L,35464L,35465L,35466L,35467L,35468L,35469L,35470L, -35471L,35472L,35473L,35474L,35475L,35476L,35477L,35478L,35479L,35480L, -35481L,35482L,35483L,35484L,35485L,35486L,35487L,35488L,35489L,35490L, -35491L,35492L,35493L,35494L,35495L,35496L,35497L,35498L,35499L,35500L, -35501L,35502L,35503L,35504L,35505L,35506L,35507L,35508L,35509L,35510L, -35511L,35512L,35513L,35514L,35515L,35516L,35517L,35518L,35519L,35520L, -35521L,35522L,35523L,35524L,35525L,35526L,35527L,35528L,35529L,35530L, -35531L,35532L,35533L,35534L,35535L,35536L,35537L,35538L,35539L,35540L, -35541L,35542L,35543L,35544L,35545L,35546L,35547L,35548L,35549L,35550L, -35551L,35552L,35553L,35554L,35555L,35556L,35557L,35558L,35559L,35560L, -35561L,35562L,35563L,35564L,35565L,35566L,35567L,35568L,35569L,35570L, -35571L,35572L,35573L,35574L,35575L,35576L,35577L,35578L,35579L,35580L, -35581L,35582L,35583L,35584L,35585L,35586L,35587L,35588L,35589L,35590L, -35591L,35592L,35593L,35594L,35595L,35596L,35597L,35598L,35599L,35600L, -35601L,35602L,35603L,35604L,35605L,35606L,35607L,35608L,35609L,35610L, -35611L,35612L,35613L,35614L,35615L,35616L,35617L,35618L,35619L,35620L, -35621L,35622L,35623L,35624L,35625L,35626L,35627L,35628L,35629L,35630L, -35631L,35632L,35633L,35634L,35635L,35636L,35637L,35638L,35639L,35640L, -35641L,35642L,35643L,35644L,35645L,35646L,35647L,35648L,35649L,35650L, -35651L,35652L,35653L,35654L,35655L,35656L,35657L,35658L,35659L,35660L, -35661L,35662L,35663L,35664L,35665L,35666L,35667L,35668L,35669L,35670L, -35671L,35672L,35673L,35674L,35675L,35676L,35677L,35678L,35679L,35680L, -35681L,35682L,35683L,35684L,35685L,35686L,35687L,35688L,35689L,35690L, -35691L,35692L,35693L,35694L,35695L,35696L,35697L,35698L,35699L,35700L, -35701L,35702L,35703L,35704L,35705L,35706L,35707L,35708L,35709L,35710L, -35711L,35712L,35713L,35714L,35715L,35716L,35717L,35718L,35719L,35720L, -35721L,35722L,35723L,35724L,35725L,35726L,35727L,35728L,35729L,35730L, -35731L,35732L,35733L,35734L,35735L,35736L,35737L,35738L,35739L,35740L, -35741L,35742L,35743L,35744L,35745L,35746L,35747L,35748L,35749L,35750L, -35751L,35752L,35753L,35754L,35755L,35756L,35757L,35758L,35759L,35760L, -35761L,35762L,35763L,35764L,35765L,35766L,35767L,35768L,35769L,35770L, -35771L,35772L,35773L,35774L,35775L,35776L,35777L,35778L,35779L,35780L, -35781L,35782L,35783L,35784L,35785L,35786L,35787L,35788L,35789L,35790L, -35791L,35792L,35793L,35794L,35795L,35796L,35797L,35798L,35799L,35800L, -35801L,35802L,35803L,35804L,35805L,35806L,35807L,35808L,35809L,35810L, -35811L,35812L,35813L,35814L,35815L,35816L,35817L,35818L,35819L,35820L, -35821L,35822L,35823L,35824L,35825L,35826L,35827L,35828L,35829L,35830L, -35831L,35832L,35833L,35834L,35835L,35836L,35837L,35838L,35839L,35840L, -35841L,35842L,35843L,35844L,35845L,35846L,35847L,35848L,35849L,35850L, -35851L,35852L,35853L,35854L,35855L,35856L,35857L,35858L,35859L,35860L, -35861L,35862L,35863L,35864L,35865L,35866L,35867L,35868L,35869L,35870L, -35871L,35872L,35873L,35874L,35875L,35876L,35877L,35878L,35879L,35880L, -35881L,35882L,35883L,35884L,35885L,35886L,35887L,35888L,35889L,35890L, -35891L,35892L,35893L,35894L,35895L,35896L,35897L,35898L,35899L,35900L, -35901L,35902L,35903L,35904L,35905L,35906L,35907L,35908L,35909L,35910L, -35911L,35912L,35913L,35914L,35915L,35916L,35917L,35918L,35919L,35920L, -35921L,35922L,35923L,35924L,35925L,35926L,35927L,35928L,35929L,35930L, -35931L,35932L,35933L,35934L,35935L,35936L,35937L,35938L,35939L,35940L, -35941L,35942L,35943L,35944L,35945L,35946L,35947L,35948L,35949L,35950L, -35951L,35952L,35953L,35954L,35955L,35956L,35957L,35958L,35959L,35960L, -35961L,35962L,35963L,35964L,35965L,35966L,35967L,35968L,35969L,35970L, -35971L,35972L,35973L,35974L,35975L,35976L,35977L,35978L,35979L,35980L, -35981L,35982L,35983L,35984L,35985L,35986L,35987L,35988L,35989L,35990L, -35991L,35992L,35993L,35994L,35995L,35996L,35997L,35998L,35999L,36000L, -36001L,36002L,36003L,36004L,36005L,36006L,36007L,36008L,36009L,36010L, -36011L,36012L,36013L,36014L,36015L,36016L,36017L,36018L,36019L,36020L, -36021L,36022L,36023L,36024L,36025L,36026L,36027L,36028L,36029L,36030L, -36031L,36032L,36033L,36034L,36035L,36036L,36037L,36038L,36039L,36040L, -36041L,36042L,36043L,36044L,36045L,36046L,36047L,36048L,36049L,36050L, -36051L,36052L,36053L,36054L,36055L,36056L,36057L,36058L,36059L,36060L, -36061L,36062L,36063L,36064L,36065L,36066L,36067L,36068L,36069L,36070L, -36071L,36072L,36073L,36074L,36075L,36076L,36077L,36078L,36079L,36080L, -36081L,36082L,36083L,36084L,36085L,36086L,36087L,36088L,36089L,36090L, -36091L,36092L,36093L,36094L,36095L,36096L,36097L,36098L,36099L,36100L, -36101L,36102L,36103L,36104L,36105L,36106L,36107L,36108L,36109L,36110L, -36111L,36112L,36113L,36114L,36115L,36116L,36117L,36118L,36119L,36120L, -36121L,36122L,36123L,36124L,36125L,36126L,36127L,36128L,36129L,36130L, -36131L,36132L,36133L,36134L,36135L,36136L,36137L,36138L,36139L,36140L, -36141L,36142L,36143L,36144L,36145L,36146L,36147L,36148L,36149L,36150L, -36151L,36152L,36153L,36154L,36155L,36156L,36157L,36158L,36159L,36160L, -36161L,36162L,36163L,36164L,36165L,36166L,36167L,36168L,36169L,36170L, -36171L,36172L,36173L,36174L,36175L,36176L,36177L,36178L,36179L,36180L, -36181L,36182L,36183L,36184L,36185L,36186L,36187L,36188L,36189L,36190L, -36191L,36192L,36193L,36194L,36195L,36196L,36197L,36198L,36199L,36200L, -36201L,36202L,36203L,36204L,36205L,36206L,36207L,36208L,36209L,36210L, -36211L,36212L,36213L,36214L,36215L,36216L,36217L,36218L,36219L,36220L, -36221L,36222L,36223L,36224L,36225L,36226L,36227L,36228L,36229L,36230L, -36231L,36232L,36233L,36234L,36235L,36236L,36237L,36238L,36239L,36240L, -36241L,36242L,36243L,36244L,36245L,36246L,36247L,36248L,36249L,36250L, -36251L,36252L,36253L,36254L,36255L,36256L,36257L,36258L,36259L,36260L, -36261L,36262L,36263L,36264L,36265L,36266L,36267L,36268L,36269L,36270L, -36271L,36272L,36273L,36274L,36275L,36276L,36277L,36278L,36279L,36280L, -36281L,36282L,36283L,36284L,36285L,36286L,36287L,36288L,36289L,36290L, -36291L,36292L,36293L,36294L,36295L,36296L,36297L,36298L,36299L,36300L, -36301L,36302L,36303L,36304L,36305L,36306L,36307L,36308L,36309L,36310L, -36311L,36312L,36313L,36314L,36315L,36316L,36317L,36318L,36319L,36320L, -36321L,36322L,36323L,36324L,36325L,36326L,36327L,36328L,36329L,36330L, -36331L,36332L,36333L,36334L,36335L,36336L,36337L,36338L,36339L,36340L, -36341L,36342L,36343L,36344L,36345L,36346L,36347L,36348L,36349L,36350L, -36351L,36352L,36353L,36354L,36355L,36356L,36357L,36358L,36359L,36360L, -36361L,36362L,36363L,36364L,36365L,36366L,36367L,36368L,36369L,36370L, -36371L,36372L,36373L,36374L,36375L,36376L,36377L,36378L,36379L,36380L, -36381L,36382L,36383L,36384L,36385L,36386L,36387L,36388L,36389L,36390L, -36391L,36392L,36393L,36394L,36395L,36396L,36397L,36398L,36399L,36400L, -36401L,36402L,36403L,36404L,36405L,36406L,36407L,36408L,36409L,36410L, -36411L,36412L,36413L,36414L,36415L,36416L,36417L,36418L,36419L,36420L, -36421L,36422L,36423L,36424L,36425L,36426L,36427L,36428L,36429L,36430L, -36431L,36432L,36433L,36434L,36435L,36436L,36437L,36438L,36439L,36440L, -36441L,36442L,36443L,36444L,36445L,36446L,36447L,36448L,36449L,36450L, -36451L,36452L,36453L,36454L,36455L,36456L,36457L,36458L,36459L,36460L, -36461L,36462L,36463L,36464L,36465L,36466L,36467L,36468L,36469L,36470L, -36471L,36472L,36473L,36474L,36475L,36476L,36477L,36478L,36479L,36480L, -36481L,36482L,36483L,36484L,36485L,36486L,36487L,36488L,36489L,36490L, -36491L,36492L,36493L,36494L,36495L,36496L,36497L,36498L,36499L,36500L, -36501L,36502L,36503L,36504L,36505L,36506L,36507L,36508L,36509L,36510L, -36511L,36512L,36513L,36514L,36515L,36516L,36517L,36518L,36519L,36520L, -36521L,36522L,36523L,36524L,36525L,36526L,36527L,36528L,36529L,36530L, -36531L,36532L,36533L,36534L,36535L,36536L,36537L,36538L,36539L,36540L, -36541L,36542L,36543L,36544L,36545L,36546L,36547L,36548L,36549L,36550L, -36551L,36552L,36553L,36554L,36555L,36556L,36557L,36558L,36559L,36560L, -36561L,36562L,36563L,36564L,36565L,36566L,36567L,36568L,36569L,36570L, -36571L,36572L,36573L,36574L,36575L,36576L,36577L,36578L,36579L,36580L, -36581L,36582L,36583L,36584L,36585L,36586L,36587L,36588L,36589L,36590L, -36591L,36592L,36593L,36594L,36595L,36596L,36597L,36598L,36599L,36600L, -36601L,36602L,36603L,36604L,36605L,36606L,36607L,36608L,36609L,36610L, -36611L,36612L,36613L,36614L,36615L,36616L,36617L,36618L,36619L,36620L, -36621L,36622L,36623L,36624L,36625L,36626L,36627L,36628L,36629L,36630L, -36631L,36632L,36633L,36634L,36635L,36636L,36637L,36638L,36639L,36640L, -36641L,36642L,36643L,36644L,36645L,36646L,36647L,36648L,36649L,36650L, -36651L,36652L,36653L,36654L,36655L,36656L,36657L,36658L,36659L,36660L, -36661L,36662L,36663L,36664L,36665L,36666L,36667L,36668L,36669L,36670L, -36671L,36672L,36673L,36674L,36675L,36676L,36677L,36678L,36679L,36680L, -36681L,36682L,36683L,36684L,36685L,36686L,36687L,36688L,36689L,36690L, -36691L,36692L,36693L,36694L,36695L,36696L,36697L,36698L,36699L,36700L, -36701L,36702L,36703L,36704L,36705L,36706L,36707L,36708L,36709L,36710L, -36711L,36712L,36713L,36714L,36715L,36716L,36717L,36718L,36719L,36720L, -36721L,36722L,36723L,36724L,36725L,36726L,36727L,36728L,36729L,36730L, -36731L,36732L,36733L,36734L,36735L,36736L,36737L,36738L,36739L,36740L, -36741L,36742L,36743L,36744L,36745L,36746L,36747L,36748L,36749L,36750L, -36751L,36752L,36753L,36754L,36755L,36756L,36757L,36758L,36759L,36760L, -36761L,36762L,36763L,36764L,36765L,36766L,36767L,36768L,36769L,36770L, -36771L,36772L,36773L,36774L,36775L,36776L,36777L,36778L,36779L,36780L, -36781L,36782L,36783L,36784L,36785L,36786L,36787L,36788L,36789L,36790L, -36791L,36792L,36793L,36794L,36795L,36796L,36797L,36798L,36799L,36800L, -36801L,36802L,36803L,36804L,36805L,36806L,36807L,36808L,36809L,36810L, -36811L,36812L,36813L,36814L,36815L,36816L,36817L,36818L,36819L,36820L, -36821L,36822L,36823L,36824L,36825L,36826L,36827L,36828L,36829L,36830L, -36831L,36832L,36833L,36834L,36835L,36836L,36837L,36838L,36839L,36840L, -36841L,36842L,36843L,36844L,36845L,36846L,36847L,36848L,36849L,36850L, -36851L,36852L,36853L,36854L,36855L,36856L,36857L,36858L,36859L,36860L, -36861L,36862L,36863L,36864L,36865L,36866L,36867L,36868L,36869L,36870L, -36871L,36872L,36873L,36874L,36875L,36876L,36877L,36878L,36879L,36880L, -36881L,36882L,36883L,36884L,36885L,36886L,36887L,36888L,36889L,36890L, -36891L,36892L,36893L,36894L,36895L,36896L,36897L,36898L,36899L,36900L, -36901L,36902L,36903L,36904L,36905L,36906L,36907L,36908L,36909L,36910L, -36911L,36912L,36913L,36914L,36915L,36916L,36917L,36918L,36919L,36920L, -36921L,36922L,36923L,36924L,36925L,36926L,36927L,36928L,36929L,36930L, -36931L,36932L,36933L,36934L,36935L,36936L,36937L,36938L,36939L,36940L, -36941L,36942L,36943L,36944L,36945L,36946L,36947L,36948L,36949L,36950L, -36951L,36952L,36953L,36954L,36955L,36956L,36957L,36958L,36959L,36960L, -36961L,36962L,36963L,36964L,36965L,36966L,36967L,36968L,36969L,36970L, -36971L,36972L,36973L,36974L,36975L,36976L,36977L,36978L,36979L,36980L, -36981L,36982L,36983L,36984L,36985L,36986L,36987L,36988L,36989L,36990L, -36991L,36992L,36993L,36994L,36995L,36996L,36997L,36998L,36999L,37000L, -37001L,37002L,37003L,37004L,37005L,37006L,37007L,37008L,37009L,37010L, -37011L,37012L,37013L,37014L,37015L,37016L,37017L,37018L,37019L,37020L, -37021L,37022L,37023L,37024L,37025L,37026L,37027L,37028L,37029L,37030L, -37031L,37032L,37033L,37034L,37035L,37036L,37037L,37038L,37039L,37040L, -37041L,37042L,37043L,37044L,37045L,37046L,37047L,37048L,37049L,37050L, -37051L,37052L,37053L,37054L,37055L,37056L,37057L,37058L,37059L,37060L, -37061L,37062L,37063L,37064L,37065L,37066L,37067L,37068L,37069L,37070L, -37071L,37072L,37073L,37074L,37075L,37076L,37077L,37078L,37079L,37080L, -37081L,37082L,37083L,37084L,37085L,37086L,37087L,37088L,37089L,37090L, -37091L,37092L,37093L,37094L,37095L,37096L,37097L,37098L,37099L,37100L, -37101L,37102L,37103L,37104L,37105L,37106L,37107L,37108L,37109L,37110L, -37111L,37112L,37113L,37114L,37115L,37116L,37117L,37118L,37119L,37120L, -37121L,37122L,37123L,37124L,37125L,37126L,37127L,37128L,37129L,37130L, -37131L,37132L,37133L,37134L,37135L,37136L,37137L,37138L,37139L,37140L, -37141L,37142L,37143L,37144L,37145L,37146L,37147L,37148L,37149L,37150L, -37151L,37152L,37153L,37154L,37155L,37156L,37157L,37158L,37159L,37160L, -37161L,37162L,37163L,37164L,37165L,37166L,37167L,37168L,37169L,37170L, -37171L,37172L,37173L,37174L,37175L,37176L,37177L,37178L,37179L,37180L, -37181L,37182L,37183L,37184L,37185L,37186L,37187L,37188L,37189L,37190L, -37191L,37192L,37193L,37194L,37195L,37196L,37197L,37198L,37199L,37200L, -37201L,37202L,37203L,37204L,37205L,37206L,37207L,37208L,37209L,37210L, -37211L,37212L,37213L,37214L,37215L,37216L,37217L,37218L,37219L,37220L, -37221L,37222L,37223L,37224L,37225L,37226L,37227L,37228L,37229L,37230L, -37231L,37232L,37233L,37234L,37235L,37236L,37237L,37238L,37239L,37240L, -37241L,37242L,37243L,37244L,37245L,37246L,37247L,37248L,37249L,37250L, -37251L,37252L,37253L,37254L,37255L,37256L,37257L,37258L,37259L,37260L, -37261L,37262L,37263L,37264L,37265L,37266L,37267L,37268L,37269L,37270L, -37271L,37272L,37273L,37274L,37275L,37276L,37277L,37278L,37279L,37280L, -37281L,37282L,37283L,37284L,37285L,37286L,37287L,37288L,37289L,37290L, -37291L,37292L,37293L,37294L,37295L,37296L,37297L,37298L,37299L,37300L, -37301L,37302L,37303L,37304L,37305L,37306L,37307L,37308L,37309L,37310L, -37311L,37312L,37313L,37314L,37315L,37316L,37317L,37318L,37319L,37320L, -37321L,37322L,37323L,37324L,37325L,37326L,37327L,37328L,37329L,37330L, -37331L,37332L,37333L,37334L,37335L,37336L,37337L,37338L,37339L,37340L, -37341L,37342L,37343L,37344L,37345L,37346L,37347L,37348L,37349L,37350L, -37351L,37352L,37353L,37354L,37355L,37356L,37357L,37358L,37359L,37360L, -37361L,37362L,37363L,37364L,37365L,37366L,37367L,37368L,37369L,37370L, -37371L,37372L,37373L,37374L,37375L,37376L,37377L,37378L,37379L,37380L, -37381L,37382L,37383L,37384L,37385L,37386L,37387L,37388L,37389L,37390L, -37391L,37392L,37393L,37394L,37395L,37396L,37397L,37398L,37399L,37400L, -37401L,37402L,37403L,37404L,37405L,37406L,37407L,37408L,37409L,37410L, -37411L,37412L,37413L,37414L,37415L,37416L,37417L,37418L,37419L,37420L, -37421L,37422L,37423L,37424L,37425L,37426L,37427L,37428L,37429L,37430L, -37431L,37432L,37433L,37434L,37435L,37436L,37437L,37438L,37439L,37440L, -37441L,37442L,37443L,37444L,37445L,37446L,37447L,37448L,37449L,37450L, -37451L,37452L,37453L,37454L,37455L,37456L,37457L,37458L,37459L,37460L, -37461L,37462L,37463L,37464L,37465L,37466L,37467L,37468L,37469L,37470L, -37471L,37472L,37473L,37474L,37475L,37476L,37477L,37478L,37479L,37480L, -37481L,37482L,37483L,37484L,37485L,37486L,37487L,37488L,37489L,37490L, -37491L,37492L,37493L,37494L,37495L,37496L,37497L,37498L,37499L,37500L, -37501L,37502L,37503L,37504L,37505L,37506L,37507L,37508L,37509L,37510L, -37511L,37512L,37513L,37514L,37515L,37516L,37517L,37518L,37519L,37520L, -37521L,37522L,37523L,37524L,37525L,37526L,37527L,37528L,37529L,37530L, -37531L,37532L,37533L,37534L,37535L,37536L,37537L,37538L,37539L,37540L, -37541L,37542L,37543L,37544L,37545L,37546L,37547L,37548L,37549L,37550L, -37551L,37552L,37553L,37554L,37555L,37556L,37557L,37558L,37559L,37560L, -37561L,37562L,37563L,37564L,37565L,37566L,37567L,37568L,37569L,37570L, -37571L,37572L,37573L,37574L,37575L,37576L,37577L,37578L,37579L,37580L, -37581L,37582L,37583L,37584L,37585L,37586L,37587L,37588L,37589L,37590L, -37591L,37592L,37593L,37594L,37595L,37596L,37597L,37598L,37599L,37600L, -37601L,37602L,37603L,37604L,37605L,37606L,37607L,37608L,37609L,37610L, -37611L,37612L,37613L,37614L,37615L,37616L,37617L,37618L,37619L,37620L, -37621L,37622L,37623L,37624L,37625L,37626L,37627L,37628L,37629L,37630L, -37631L,37632L,37633L,37634L,37635L,37636L,37637L,37638L,37639L,37640L, -37641L,37642L,37643L,37644L,37645L,37646L,37647L,37648L,37649L,37650L, -37651L,37652L,37653L,37654L,37655L,37656L,37657L,37658L,37659L,37660L, -37661L,37662L,37663L,37664L,37665L,37666L,37667L,37668L,37669L,37670L, -37671L,37672L,37673L,37674L,37675L,37676L,37677L,37678L,37679L,37680L, -37681L,37682L,37683L,37684L,37685L,37686L,37687L,37688L,37689L,37690L, -37691L,37692L,37693L,37694L,37695L,37696L,37697L,37698L,37699L,37700L, -37701L,37702L,37703L,37704L,37705L,37706L,37707L,37708L,37709L,37710L, -37711L,37712L,37713L,37714L,37715L,37716L,37717L,37718L,37719L,37720L, -37721L,37722L,37723L,37724L,37725L,37726L,37727L,37728L,37729L,37730L, -37731L,37732L,37733L,37734L,37735L,37736L,37737L,37738L,37739L,37740L, -37741L,37742L,37743L,37744L,37745L,37746L,37747L,37748L,37749L,37750L, -37751L,37752L,37753L,37754L,37755L,37756L,37757L,37758L,37759L,37760L, -37761L,37762L,37763L,37764L,37765L,37766L,37767L,37768L,37769L,37770L, -37771L,37772L,37773L,37774L,37775L,37776L,37777L,37778L,37779L,37780L, -37781L,37782L,37783L,37784L,37785L,37786L,37787L,37788L,37789L,37790L, -37791L,37792L,37793L,37794L,37795L,37796L,37797L,37798L,37799L,37800L, -37801L,37802L,37803L,37804L,37805L,37806L,37807L,37808L,37809L,37810L, -37811L,37812L,37813L,37814L,37815L,37816L,37817L,37818L,37819L,37820L, -37821L,37822L,37823L,37824L,37825L,37826L,37827L,37828L,37829L,37830L, -37831L,37832L,37833L,37834L,37835L,37836L,37837L,37838L,37839L,37840L, -37841L,37842L,37843L,37844L,37845L,37846L,37847L,37848L,37849L,37850L, -37851L,37852L,37853L,37854L,37855L,37856L,37857L,37858L,37859L,37860L, -37861L,37862L,37863L,37864L,37865L,37866L,37867L,37868L,37869L,37870L, -37871L,37872L,37873L,37874L,37875L,37876L,37877L,37878L,37879L,37880L, -37881L,37882L,37883L,37884L,37885L,37886L,37887L,37888L,37889L,37890L, -37891L,37892L,37893L,37894L,37895L,37896L,37897L,37898L,37899L,37900L, -37901L,37902L,37903L,37904L,37905L,37906L,37907L,37908L,37909L,37910L, -37911L,37912L,37913L,37914L,37915L,37916L,37917L,37918L,37919L,37920L, -37921L,37922L,37923L,37924L,37925L,37926L,37927L,37928L,37929L,37930L, -37931L,37932L,37933L,37934L,37935L,37936L,37937L,37938L,37939L,37940L, -37941L,37942L,37943L,37944L,37945L,37946L,37947L,37948L,37949L,37950L, -37951L,37952L,37953L,37954L,37955L,37956L,37957L,37958L,37959L,37960L, -37961L,37962L,37963L,37964L,37965L,37966L,37967L,37968L,37969L,37970L, -37971L,37972L,37973L,37974L,37975L,37976L,37977L,37978L,37979L,37980L, -37981L,37982L,37983L,37984L,37985L,37986L,37987L,37988L,37989L,37990L, -37991L,37992L,37993L,37994L,37995L,37996L,37997L,37998L,37999L,38000L, -38001L,38002L,38003L,38004L,38005L,38006L,38007L,38008L,38009L,38010L, -38011L,38012L,38013L,38014L,38015L,38016L,38017L,38018L,38019L,38020L, -38021L,38022L,38023L,38024L,38025L,38026L,38027L,38028L,38029L,38030L, -38031L,38032L,38033L,38034L,38035L,38036L,38037L,38038L,38039L,38040L, -38041L,38042L,38043L,38044L,38045L,38046L,38047L,38048L,38049L,38050L, -38051L,38052L,38053L,38054L,38055L,38056L,38057L,38058L,38059L,38060L, -38061L,38062L,38063L,38064L,38065L,38066L,38067L,38068L,38069L,38070L, -38071L,38072L,38073L,38074L,38075L,38076L,38077L,38078L,38079L,38080L, -38081L,38082L,38083L,38084L,38085L,38086L,38087L,38088L,38089L,38090L, -38091L,38092L,38093L,38094L,38095L,38096L,38097L,38098L,38099L,38100L, -38101L,38102L,38103L,38104L,38105L,38106L,38107L,38108L,38109L,38110L, -38111L,38112L,38113L,38114L,38115L,38116L,38117L,38118L,38119L,38120L, -38121L,38122L,38123L,38124L,38125L,38126L,38127L,38128L,38129L,38130L, -38131L,38132L,38133L,38134L,38135L,38136L,38137L,38138L,38139L,38140L, -38141L,38142L,38143L,38144L,38145L,38146L,38147L,38148L,38149L,38150L, -38151L,38152L,38153L,38154L,38155L,38156L,38157L,38158L,38159L,38160L, -38161L,38162L,38163L,38164L,38165L,38166L,38167L,38168L,38169L,38170L, -38171L,38172L,38173L,38174L,38175L,38176L,38177L,38178L,38179L,38180L, -38181L,38182L,38183L,38184L,38185L,38186L,38187L,38188L,38189L,38190L, -38191L,38192L,38193L,38194L,38195L,38196L,38197L,38198L,38199L,38200L, -38201L,38202L,38203L,38204L,38205L,38206L,38207L,38208L,38209L,38210L, -38211L,38212L,38213L,38214L,38215L,38216L,38217L,38218L,38219L,38220L, -38221L,38222L,38223L,38224L,38225L,38226L,38227L,38228L,38229L,38230L, -38231L,38232L,38233L,38234L,38235L,38236L,38237L,38238L,38239L,38240L, -38241L,38242L,38243L,38244L,38245L,38246L,38247L,38248L,38249L,38250L, -38251L,38252L,38253L,38254L,38255L,38256L,38257L,38258L,38259L,38260L, -38261L,38262L,38263L,38264L,38265L,38266L,38267L,38268L,38269L,38270L, -38271L,38272L,38273L,38274L,38275L,38276L,38277L,38278L,38279L,38280L, -38281L,38282L,38283L,38284L,38285L,38286L,38287L,38288L,38289L,38290L, -38291L,38292L,38293L,38294L,38295L,38296L,38297L,38298L,38299L,38300L, -38301L,38302L,38303L,38304L,38305L,38306L,38307L,38308L,38309L,38310L, -38311L,38312L,38313L,38314L,38315L,38316L,38317L,38318L,38319L,38320L, -38321L,38322L,38323L,38324L,38325L,38326L,38327L,38328L,38329L,38330L, -38331L,38332L,38333L,38334L,38335L,38336L,38337L,38338L,38339L,38340L, -38341L,38342L,38343L,38344L,38345L,38346L,38347L,38348L,38349L,38350L, -38351L,38352L,38353L,38354L,38355L,38356L,38357L,38358L,38359L,38360L, -38361L,38362L,38363L,38364L,38365L,38366L,38367L,38368L,38369L,38370L, -38371L,38372L,38373L,38374L,38375L,38376L,38377L,38378L,38379L,38380L, -38381L,38382L,38383L,38384L,38385L,38386L,38387L,38388L,38389L,38390L, -38391L,38392L,38393L,38394L,38395L,38396L,38397L,38398L,38399L,38400L, -38401L,38402L,38403L,38404L,38405L,38406L,38407L,38408L,38409L,38410L, -38411L,38412L,38413L,38414L,38415L,38416L,38417L,38418L,38419L,38420L, -38421L,38422L,38423L,38424L,38425L,38426L,38427L,38428L,38429L,38430L, -38431L,38432L,38433L,38434L,38435L,38436L,38437L,38438L,38439L,38440L, -38441L,38442L,38443L,38444L,38445L,38446L,38447L,38448L,38449L,38450L, -38451L,38452L,38453L,38454L,38455L,38456L,38457L,38458L,38459L,38460L, -38461L,38462L,38463L,38464L,38465L,38466L,38467L,38468L,38469L,38470L, -38471L,38472L,38473L,38474L,38475L,38476L,38477L,38478L,38479L,38480L, -38481L,38482L,38483L,38484L,38485L,38486L,38487L,38488L,38489L,38490L, -38491L,38492L,38493L,38494L,38495L,38496L,38497L,38498L,38499L,38500L, -38501L,38502L,38503L,38504L,38505L,38506L,38507L,38508L,38509L,38510L, -38511L,38512L,38513L,38514L,38515L,38516L,38517L,38518L,38519L,38520L, -38521L,38522L,38523L,38524L,38525L,38526L,38527L,38528L,38529L,38530L, -38531L,38532L,38533L,38534L,38535L,38536L,38537L,38538L,38539L,38540L, -38541L,38542L,38543L,38544L,38545L,38546L,38547L,38548L,38549L,38550L, -38551L,38552L,38553L,38554L,38555L,38556L,38557L,38558L,38559L,38560L, -38561L,38562L,38563L,38564L,38565L,38566L,38567L,38568L,38569L,38570L, -38571L,38572L,38573L,38574L,38575L,38576L,38577L,38578L,38579L,38580L, -38581L,38582L,38583L,38584L,38585L,38586L,38587L,38588L,38589L,38590L, -38591L,38592L,38593L,38594L,38595L,38596L,38597L,38598L,38599L,38600L, -38601L,38602L,38603L,38604L,38605L,38606L,38607L,38608L,38609L,38610L, -38611L,38612L,38613L,38614L,38615L,38616L,38617L,38618L,38619L,38620L, -38621L,38622L,38623L,38624L,38625L,38626L,38627L,38628L,38629L,38630L, -38631L,38632L,38633L,38634L,38635L,38636L,38637L,38638L,38639L,38640L, -38641L,38642L,38643L,38644L,38645L,38646L,38647L,38648L,38649L,38650L, -38651L,38652L,38653L,38654L,38655L,38656L,38657L,38658L,38659L,38660L, -38661L,38662L,38663L,38664L,38665L,38666L,38667L,38668L,38669L,38670L, -38671L,38672L,38673L,38674L,38675L,38676L,38677L,38678L,38679L,38680L, -38681L,38682L,38683L,38684L,38685L,38686L,38687L,38688L,38689L,38690L, -38691L,38692L,38693L,38694L,38695L,38696L,38697L,38698L,38699L,38700L, -38701L,38702L,38703L,38704L,38705L,38706L,38707L,38708L,38709L,38710L, -38711L,38712L,38713L,38714L,38715L,38716L,38717L,38718L,38719L,38720L, -38721L,38722L,38723L,38724L,38725L,38726L,38727L,38728L,38729L,38730L, -38731L,38732L,38733L,38734L,38735L,38736L,38737L,38738L,38739L,38740L, -38741L,38742L,38743L,38744L,38745L,38746L,38747L,38748L,38749L,38750L, -38751L,38752L,38753L,38754L,38755L,38756L,38757L,38758L,38759L,38760L, -38761L,38762L,38763L,38764L,38765L,38766L,38767L,38768L,38769L,38770L, -38771L,38772L,38773L,38774L,38775L,38776L,38777L,38778L,38779L,38780L, -38781L,38782L,38783L,38784L,38785L,38786L,38787L,38788L,38789L,38790L, -38791L,38792L,38793L,38794L,38795L,38796L,38797L,38798L,38799L,38800L, -38801L,38802L,38803L,38804L,38805L,38806L,38807L,38808L,38809L,38810L, -38811L,38812L,38813L,38814L,38815L,38816L,38817L,38818L,38819L,38820L, -38821L,38822L,38823L,38824L,38825L,38826L,38827L,38828L,38829L,38830L, -38831L,38832L,38833L,38834L,38835L,38836L,38837L,38838L,38839L,38840L, -38841L,38842L,38843L,38844L,38845L,38846L,38847L,38848L,38849L,38850L, -38851L,38852L,38853L,38854L,38855L,38856L,38857L,38858L,38859L,38860L, -38861L,38862L,38863L,38864L,38865L,38866L,38867L,38868L,38869L,38870L, -38871L,38872L,38873L,38874L,38875L,38876L,38877L,38878L,38879L,38880L, -38881L,38882L,38883L,38884L,38885L,38886L,38887L,38888L,38889L,38890L, -38891L,38892L,38893L,38894L,38895L,38896L,38897L,38898L,38899L,38900L, -38901L,38902L,38903L,38904L,38905L,38906L,38907L,38908L,38909L,38910L, -38911L,38912L,38913L,38914L,38915L,38916L,38917L,38918L,38919L,38920L, -38921L,38922L,38923L,38924L,38925L,38926L,38927L,38928L,38929L,38930L, -38931L,38932L,38933L,38934L,38935L,38936L,38937L,38938L,38939L,38940L, -38941L,38942L,38943L,38944L,38945L,38946L,38947L,38948L,38949L,38950L, -38951L,38952L,38953L,38954L,38955L,38956L,38957L,38958L,38959L,38960L, -38961L,38962L,38963L,38964L,38965L,38966L,38967L,38968L,38969L,38970L, -38971L,38972L,38973L,38974L,38975L,38976L,38977L,38978L,38979L,38980L, -38981L,38982L,38983L,38984L,38985L,38986L,38987L,38988L,38989L,38990L, -38991L,38992L,38993L,38994L,38995L,38996L,38997L,38998L,38999L,39000L, -39001L,39002L,39003L,39004L,39005L,39006L,39007L,39008L,39009L,39010L, -39011L,39012L,39013L,39014L,39015L,39016L,39017L,39018L,39019L,39020L, -39021L,39022L,39023L,39024L,39025L,39026L,39027L,39028L,39029L,39030L, -39031L,39032L,39033L,39034L,39035L,39036L,39037L,39038L,39039L,39040L, -39041L,39042L,39043L,39044L,39045L,39046L,39047L,39048L,39049L,39050L, -39051L,39052L,39053L,39054L,39055L,39056L,39057L,39058L,39059L,39060L, -39061L,39062L,39063L,39064L,39065L,39066L,39067L,39068L,39069L,39070L, -39071L,39072L,39073L,39074L,39075L,39076L,39077L,39078L,39079L,39080L, -39081L,39082L,39083L,39084L,39085L,39086L,39087L,39088L,39089L,39090L, -39091L,39092L,39093L,39094L,39095L,39096L,39097L,39098L,39099L,39100L, -39101L,39102L,39103L,39104L,39105L,39106L,39107L,39108L,39109L,39110L, -39111L,39112L,39113L,39114L,39115L,39116L,39117L,39118L,39119L,39120L, -39121L,39122L,39123L,39124L,39125L,39126L,39127L,39128L,39129L,39130L, -39131L,39132L,39133L,39134L,39135L,39136L,39137L,39138L,39139L,39140L, -39141L,39142L,39143L,39144L,39145L,39146L,39147L,39148L,39149L,39150L, -39151L,39152L,39153L,39154L,39155L,39156L,39157L,39158L,39159L,39160L, -39161L,39162L,39163L,39164L,39165L,39166L,39167L,39168L,39169L,39170L, -39171L,39172L,39173L,39174L,39175L,39176L,39177L,39178L,39179L,39180L, -39181L,39182L,39183L,39184L,39185L,39186L,39187L,39188L,39189L,39190L, -39191L,39192L,39193L,39194L,39195L,39196L,39197L,39198L,39199L,39200L, -39201L,39202L,39203L,39204L,39205L,39206L,39207L,39208L,39209L,39210L, -39211L,39212L,39213L,39214L,39215L,39216L,39217L,39218L,39219L,39220L, -39221L,39222L,39223L,39224L,39225L,39226L,39227L,39228L,39229L,39230L, -39231L,39232L,39233L,39234L,39235L,39236L,39237L,39238L,39239L,39240L, -39241L,39242L,39243L,39244L,39245L,39246L,39247L,39248L,39249L,39250L, -39251L,39252L,39253L,39254L,39255L,39256L,39257L,39258L,39259L,39260L, -39261L,39262L,39263L,39264L,39265L,39266L,39267L,39268L,39269L,39270L, -39271L,39272L,39273L,39274L,39275L,39276L,39277L,39278L,39279L,39280L, -39281L,39282L,39283L,39284L,39285L,39286L,39287L,39288L,39289L,39290L, -39291L,39292L,39293L,39294L,39295L,39296L,39297L,39298L,39299L,39300L, -39301L,39302L,39303L,39304L,39305L,39306L,39307L,39308L,39309L,39310L, -39311L,39312L,39313L,39314L,39315L,39316L,39317L,39318L,39319L,39320L, -39321L,39322L,39323L,39324L,39325L,39326L,39327L,39328L,39329L,39330L, -39331L,39332L,39333L,39334L,39335L,39336L,39337L,39338L,39339L,39340L, -39341L,39342L,39343L,39344L,39345L,39346L,39347L,39348L,39349L,39350L, -39351L,39352L,39353L,39354L,39355L,39356L,39357L,39358L,39359L,39360L, -39361L,39362L,39363L,39364L,39365L,39366L,39367L,39368L,39369L,39370L, -39371L,39372L,39373L,39374L,39375L,39376L,39377L,39378L,39379L,39380L, -39381L,39382L,39383L,39384L,39385L,39386L,39387L,39388L,39389L,39390L, -39391L,39392L,39393L,39394L,39395L,39396L,39397L,39398L,39399L,39400L, -39401L,39402L,39403L,39404L,39405L,39406L,39407L,39408L,39409L,39410L, -39411L,39412L,39413L,39414L,39415L,39416L,39417L,39418L,39419L,39420L, -39421L,39422L,39423L,39424L,39425L,39426L,39427L,39428L,39429L,39430L, -39431L,39432L,39433L,39434L,39435L,39436L,39437L,39438L,39439L,39440L, -39441L,39442L,39443L,39444L,39445L,39446L,39447L,39448L,39449L,39450L, -39451L,39452L,39453L,39454L,39455L,39456L,39457L,39458L,39459L,39460L, -39461L,39462L,39463L,39464L,39465L,39466L,39467L,39468L,39469L,39470L, -39471L,39472L,39473L,39474L,39475L,39476L,39477L,39478L,39479L,39480L, -39481L,39482L,39483L,39484L,39485L,39486L,39487L,39488L,39489L,39490L, -39491L,39492L,39493L,39494L,39495L,39496L,39497L,39498L,39499L,39500L, -39501L,39502L,39503L,39504L,39505L,39506L,39507L,39508L,39509L,39510L, -39511L,39512L,39513L,39514L,39515L,39516L,39517L,39518L,39519L,39520L, -39521L,39522L,39523L,39524L,39525L,39526L,39527L,39528L,39529L,39530L, -39531L,39532L,39533L,39534L,39535L,39536L,39537L,39538L,39539L,39540L, -39541L,39542L,39543L,39544L,39545L,39546L,39547L,39548L,39549L,39550L, -39551L,39552L,39553L,39554L,39555L,39556L,39557L,39558L,39559L,39560L, -39561L,39562L,39563L,39564L,39565L,39566L,39567L,39568L,39569L,39570L, -39571L,39572L,39573L,39574L,39575L,39576L,39577L,39578L,39579L,39580L, -39581L,39582L,39583L,39584L,39585L,39586L,39587L,39588L,39589L,39590L, -39591L,39592L,39593L,39594L,39595L,39596L,39597L,39598L,39599L,39600L, -39601L,39602L,39603L,39604L,39605L,39606L,39607L,39608L,39609L,39610L, -39611L,39612L,39613L,39614L,39615L,39616L,39617L,39618L,39619L,39620L, -39621L,39622L,39623L,39624L,39625L,39626L,39627L,39628L,39629L,39630L, -39631L,39632L,39633L,39634L,39635L,39636L,39637L,39638L,39639L,39640L, -39641L,39642L,39643L,39644L,39645L,39646L,39647L,39648L,39649L,39650L, -39651L,39652L,39653L,39654L,39655L,39656L,39657L,39658L,39659L,39660L, -39661L,39662L,39663L,39664L,39665L,39666L,39667L,39668L,39669L,39670L, -39671L,39672L,39673L,39674L,39675L,39676L,39677L,39678L,39679L,39680L, -39681L,39682L,39683L,39684L,39685L,39686L,39687L,39688L,39689L,39690L, -39691L,39692L,39693L,39694L,39695L,39696L,39697L,39698L,39699L,39700L, -39701L,39702L,39703L,39704L,39705L,39706L,39707L,39708L,39709L,39710L, -39711L,39712L,39713L,39714L,39715L,39716L,39717L,39718L,39719L,39720L, -39721L,39722L,39723L,39724L,39725L,39726L,39727L,39728L,39729L,39730L, -39731L,39732L,39733L,39734L,39735L,39736L,39737L,39738L,39739L,39740L, -39741L,39742L,39743L,39744L,39745L,39746L,39747L,39748L,39749L,39750L, -39751L,39752L,39753L,39754L,39755L,39756L,39757L,39758L,39759L,39760L, -39761L,39762L,39763L,39764L,39765L,39766L,39767L,39768L,39769L,39770L, -39771L,39772L,39773L,39774L,39775L,39776L,39777L,39778L,39779L,39780L, -39781L,39782L,39783L,39784L,39785L,39786L,39787L,39788L,39789L,39790L, -39791L,39792L,39793L,39794L,39795L,39796L,39797L,39798L,39799L,39800L, -39801L,39802L,39803L,39804L,39805L,39806L,39807L,39808L,39809L,39810L, -39811L,39812L,39813L,39814L,39815L,39816L,39817L,39818L,39819L,39820L, -39821L,39822L,39823L,39824L,39825L,39826L,39827L,39828L,39829L,39830L, -39831L,39832L,39833L,39834L,39835L,39836L,39837L,39838L,39839L,39840L, -39841L,39842L,39843L,39844L,39845L,39846L,39847L,39848L,39849L,39850L, -39851L,39852L,39853L,39854L,39855L,39856L,39857L,39858L,39859L,39860L, -39861L,39862L,39863L,39864L,39865L,39866L,39867L,39868L,39869L,39870L, -39871L,39872L,39873L,39874L,39875L,39876L,39877L,39878L,39879L,39880L, -39881L,39882L,39883L,39884L,39885L,39886L,39887L,39888L,39889L,39890L, -39891L,39892L,39893L,39894L,39895L,39896L,39897L,39898L,39899L,39900L, -39901L,39902L,39903L,39904L,39905L,39906L,39907L,39908L,39909L,39910L, -39911L,39912L,39913L,39914L,39915L,39916L,39917L,39918L,39919L,39920L, -39921L,39922L,39923L,39924L,39925L,39926L,39927L,39928L,39929L,39930L, -39931L,39932L,39933L,39934L,39935L,39936L,39937L,39938L,39939L,39940L, -39941L,39942L,39943L,39944L,39945L,39946L,39947L,39948L,39949L,39950L, -39951L,39952L,39953L,39954L,39955L,39956L,39957L,39958L,39959L,39960L, -39961L,39962L,39963L,39964L,39965L,39966L,39967L,39968L,39969L,39970L, -39971L,39972L,39973L,39974L,39975L,39976L,39977L,39978L,39979L,39980L, -39981L,39982L,39983L,39984L,39985L,39986L,39987L,39988L,39989L,39990L, -39991L,39992L,39993L,39994L,39995L,39996L,39997L,39998L,39999L,40000L, -40001L,40002L,40003L,40004L,40005L,40006L,40007L,40008L,40009L,40010L, -40011L,40012L,40013L,40014L,40015L,40016L,40017L,40018L,40019L,40020L, -40021L,40022L,40023L,40024L,40025L,40026L,40027L,40028L,40029L,40030L, -40031L,40032L,40033L,40034L,40035L,40036L,40037L,40038L,40039L,40040L, -40041L,40042L,40043L,40044L,40045L,40046L,40047L,40048L,40049L,40050L, -40051L,40052L,40053L,40054L,40055L,40056L,40057L,40058L,40059L,40060L, -40061L,40062L,40063L,40064L,40065L,40066L,40067L,40068L,40069L,40070L, -40071L,40072L,40073L,40074L,40075L,40076L,40077L,40078L,40079L,40080L, -40081L,40082L,40083L,40084L,40085L,40086L,40087L,40088L,40089L,40090L, -40091L,40092L,40093L,40094L,40095L,40096L,40097L,40098L,40099L,40100L, -40101L,40102L,40103L,40104L,40105L,40106L,40107L,40108L,40109L,40110L, -40111L,40112L,40113L,40114L,40115L,40116L,40117L,40118L,40119L,40120L, -40121L,40122L,40123L,40124L,40125L,40126L,40127L,40128L,40129L,40130L, -40131L,40132L,40133L,40134L,40135L,40136L,40137L,40138L,40139L,40140L, -40141L,40142L,40143L,40144L,40145L,40146L,40147L,40148L,40149L,40150L, -40151L,40152L,40153L,40154L,40155L,40156L,40157L,40158L,40159L,40160L, -40161L,40162L,40163L,40164L,40165L,40166L,40167L,40168L,40169L,40170L, -40171L,40172L,40173L,40174L,40175L,40176L,40177L,40178L,40179L,40180L, -40181L,40182L,40183L,40184L,40185L,40186L,40187L,40188L,40189L,40190L, -40191L,40192L,40193L,40194L,40195L,40196L,40197L,40198L,40199L,40200L, -40201L,40202L,40203L,40204L,40205L,40206L,40207L,40208L,40209L,40210L, -40211L,40212L,40213L,40214L,40215L,40216L,40217L,40218L,40219L,40220L, -40221L,40222L,40223L,40224L,40225L,40226L,40227L,40228L,40229L,40230L, -40231L,40232L,40233L,40234L,40235L,40236L,40237L,40238L,40239L,40240L, -40241L,40242L,40243L,40244L,40245L,40246L,40247L,40248L,40249L,40250L, -40251L,40252L,40253L,40254L,40255L,40256L,40257L,40258L,40259L,40260L, -40261L,40262L,40263L,40264L,40265L,40266L,40267L,40268L,40269L,40270L, -40271L,40272L,40273L,40274L,40275L,40276L,40277L,40278L,40279L,40280L, -40281L,40282L,40283L,40284L,40285L,40286L,40287L,40288L,40289L,40290L, -40291L,40292L,40293L,40294L,40295L,40296L,40297L,40298L,40299L,40300L, -40301L,40302L,40303L,40304L,40305L,40306L,40307L,40308L,40309L,40310L, -40311L,40312L,40313L,40314L,40315L,40316L,40317L,40318L,40319L,40320L, -40321L,40322L,40323L,40324L,40325L,40326L,40327L,40328L,40329L,40330L, -40331L,40332L,40333L,40334L,40335L,40336L,40337L,40338L,40339L,40340L, -40341L,40342L,40343L,40344L,40345L,40346L,40347L,40348L,40349L,40350L, -40351L,40352L,40353L,40354L,40355L,40356L,40357L,40358L,40359L,40360L, -40361L,40362L,40363L,40364L,40365L,40366L,40367L,40368L,40369L,40370L, -40371L,40372L,40373L,40374L,40375L,40376L,40377L,40378L,40379L,40380L, -40381L,40382L,40383L,40384L,40385L,40386L,40387L,40388L,40389L,40390L, -40391L,40392L,40393L,40394L,40395L,40396L,40397L,40398L,40399L,40400L, -40401L,40402L,40403L,40404L,40405L,40406L,40407L,40408L,40409L,40410L, -40411L,40412L,40413L,40414L,40415L,40416L,40417L,40418L,40419L,40420L, -40421L,40422L,40423L,40424L,40425L,40426L,40427L,40428L,40429L,40430L, -40431L,40432L,40433L,40434L,40435L,40436L,40437L,40438L,40439L,40440L, -40441L,40442L,40443L,40444L,40445L,40446L,40447L,40448L,40449L,40450L, -40451L,40452L,40453L,40454L,40455L,40456L,40457L,40458L,40459L,40460L, -40461L,40462L,40463L,40464L,40465L,40466L,40467L,40468L,40469L,40470L, -40471L,40472L,40473L,40474L,40475L,40476L,40477L,40478L,40479L,40480L, -40481L,40482L,40483L,40484L,40485L,40486L,40487L,40488L,40489L,40490L, -40491L,40492L,40493L,40494L,40495L,40496L,40497L,40498L,40499L,40500L, -40501L,40502L,40503L,40504L,40505L,40506L,40507L,40508L,40509L,40510L, -40511L,40512L,40513L,40514L,40515L,40516L,40517L,40518L,40519L,40520L, -40521L,40522L,40523L,40524L,40525L,40526L,40527L,40528L,40529L,40530L, -40531L,40532L,40533L,40534L,40535L,40536L,40537L,40538L,40539L,40540L, -40541L,40542L,40543L,40544L,40545L,40546L,40547L,40548L,40549L,40550L, -40551L,40552L,40553L,40554L,40555L,40556L,40557L,40558L,40559L,40560L, -40561L,40562L,40563L,40564L,40565L,40566L,40567L,40568L,40569L,40570L, -40571L,40572L,40573L,40574L,40575L,40576L,40577L,40578L,40579L,40580L, -40581L,40582L,40583L,40584L,40585L,40586L,40587L,40588L,40589L,40590L, -40591L,40592L,40593L,40594L,40595L,40596L,40597L,40598L,40599L,40600L, -40601L,40602L,40603L,40604L,40605L,40606L,40607L,40608L,40609L,40610L, -40611L,40612L,40613L,40614L,40615L,40616L,40617L,40618L,40619L,40620L, -40621L,40622L,40623L,40624L,40625L,40626L,40627L,40628L,40629L,40630L, -40631L,40632L,40633L,40634L,40635L,40636L,40637L,40638L,40639L,40640L, -40641L,40642L,40643L,40644L,40645L,40646L,40647L,40648L,40649L,40650L, -40651L,40652L,40653L,40654L,40655L,40656L,40657L,40658L,40659L,40660L, -40661L,40662L,40663L,40664L,40665L,40666L,40667L,40668L,40669L,40670L, -40671L,40672L,40673L,40674L,40675L,40676L,40677L,40678L,40679L,40680L, -40681L,40682L,40683L,40684L,40685L,40686L,40687L,40688L,40689L,40690L, -40691L,40692L,40693L,40694L,40695L,40696L,40697L,40698L,40699L,40700L, -40701L,40702L,40703L,40704L,40705L,40706L,40707L,40708L,40709L,40710L, -40711L,40712L,40713L,40714L,40715L,40716L,40717L,40718L,40719L,40720L, -40721L,40722L,40723L,40724L,40725L,40726L,40727L,40728L,40729L,40730L, -40731L,40732L,40733L,40734L,40735L,40736L,40737L,40738L,40739L,40740L, -40741L,40742L,40743L,40744L,40745L,40746L,40747L,40748L,40749L,40750L, -40751L,40752L,40753L,40754L,40755L,40756L,40757L,40758L,40759L,40760L, -40761L,40762L,40763L,40764L,40765L,40766L,40767L,40768L,40769L,40770L, -40771L,40772L,40773L,40774L,40775L,40776L,40777L,40778L,40779L,40780L, -40781L,40782L,40783L,40784L,40785L,40786L,40787L,40788L,40789L,40790L, -40791L,40792L,40793L,40794L,40795L,40796L,40797L,40798L,40799L,40800L, -40801L,40802L,40803L,40804L,40805L,40806L,40807L,40808L,40809L,40810L, -40811L,40812L,40813L,40814L,40815L,40816L,40817L,40818L,40819L,40820L, -40821L,40822L,40823L,40824L,40825L,40826L,40827L,40828L,40829L,40830L, -40831L,40832L,40833L,40834L,40835L,40836L,40837L,40838L,40839L,40840L, -40841L,40842L,40843L,40844L,40845L,40846L,40847L,40848L,40849L,40850L, -40851L,40852L,40853L,40854L,40855L,40856L,40857L,40858L,40859L,40860L, -40861L,40862L,40863L,40864L,40865L,40866L,40867L,40868L,40869L,40870L, -40871L,40872L,40873L,40874L,40875L,40876L,40877L,40878L,40879L,40880L, -40881L,40882L,40883L,40884L,40885L,40886L,40887L,40888L,40889L,40890L, -40891L,40892L,40893L,40894L,40895L,40896L,40897L,40898L,40899L,40900L, -40901L,40902L,40903L,40904L,40905L,40906L,40907L,40908L,40909L,40910L, -40911L,40912L,40913L,40914L,40915L,40916L,40917L,40918L,40919L,40920L, -40921L,40922L,40923L,40924L,40925L,40926L,40927L,40928L,40929L,40930L, -40931L,40932L,40933L,40934L,40935L,40936L,40937L,40938L,40939L,40940L, -40941L,40942L,40943L,40944L,40945L,40946L,40947L,40948L,40949L,40950L, -40951L,40952L,40953L,40954L,40955L,40956L,40957L,40958L,40959L,40960L, -40961L,40962L,40963L,40964L,40965L,40966L,40967L,40968L,40969L,40970L, -40971L,40972L,40973L,40974L,40975L,40976L,40977L,40978L,40979L,40980L, -40981L,40982L,40983L,40984L,40985L,40986L,40987L,40988L,40989L,40990L, -40991L,40992L,40993L,40994L,40995L,40996L,40997L,40998L,40999L,41000L, -41001L,41002L,41003L,41004L,41005L,41006L,41007L,41008L,41009L,41010L, -41011L,41012L,41013L,41014L,41015L,41016L,41017L,41018L,41019L,41020L, -41021L,41022L,41023L,41024L,41025L,41026L,41027L,41028L,41029L,41030L, -41031L,41032L,41033L,41034L,41035L,41036L,41037L,41038L,41039L,41040L, -41041L,41042L,41043L,41044L,41045L,41046L,41047L,41048L,41049L,41050L, -41051L,41052L,41053L,41054L,41055L,41056L,41057L,41058L,41059L,41060L, -41061L,41062L,41063L,41064L,41065L,41066L,41067L,41068L,41069L,41070L, -41071L,41072L,41073L,41074L,41075L,41076L,41077L,41078L,41079L,41080L, -41081L,41082L,41083L,41084L,41085L,41086L,41087L,41088L,41089L,41090L, -41091L,41092L,41093L,41094L,41095L,41096L,41097L,41098L,41099L,41100L, -41101L,41102L,41103L,41104L,41105L,41106L,41107L,41108L,41109L,41110L, -41111L,41112L,41113L,41114L,41115L,41116L,41117L,41118L,41119L,41120L, -41121L,41122L,41123L,41124L,41125L,41126L,41127L,41128L,41129L,41130L, -41131L,41132L,41133L,41134L,41135L,41136L,41137L,41138L,41139L,41140L, -41141L,41142L,41143L,41144L,41145L,41146L,41147L,41148L,41149L,41150L, -41151L,41152L,41153L,41154L,41155L,41156L,41157L,41158L,41159L,41160L, -41161L,41162L,41163L,41164L,41165L,41166L,41167L,41168L,41169L,41170L, -41171L,41172L,41173L,41174L,41175L,41176L,41177L,41178L,41179L,41180L, -41181L,41182L,41183L,41184L,41185L,41186L,41187L,41188L,41189L,41190L, -41191L,41192L,41193L,41194L,41195L,41196L,41197L,41198L,41199L,41200L, -41201L,41202L,41203L,41204L,41205L,41206L,41207L,41208L,41209L,41210L, -41211L,41212L,41213L,41214L,41215L,41216L,41217L,41218L,41219L,41220L, -41221L,41222L,41223L,41224L,41225L,41226L,41227L,41228L,41229L,41230L, -41231L,41232L,41233L,41234L,41235L,41236L,41237L,41238L,41239L,41240L, -41241L,41242L,41243L,41244L,41245L,41246L,41247L,41248L,41249L,41250L, -41251L,41252L,41253L,41254L,41255L,41256L,41257L,41258L,41259L,41260L, -41261L,41262L,41263L,41264L,41265L,41266L,41267L,41268L,41269L,41270L, -41271L,41272L,41273L,41274L,41275L,41276L,41277L,41278L,41279L,41280L, -41281L,41282L,41283L,41284L,41285L,41286L,41287L,41288L,41289L,41290L, -41291L,41292L,41293L,41294L,41295L,41296L,41297L,41298L,41299L,41300L, -41301L,41302L,41303L,41304L,41305L,41306L,41307L,41308L,41309L,41310L, -41311L,41312L,41313L,41314L,41315L,41316L,41317L,41318L,41319L,41320L, -41321L,41322L,41323L,41324L,41325L,41326L,41327L,41328L,41329L,41330L, -41331L,41332L,41333L,41334L,41335L,41336L,41337L,41338L,41339L,41340L, -41341L,41342L,41343L,41344L,41345L,41346L,41347L,41348L,41349L,41350L, -41351L,41352L,41353L,41354L,41355L,41356L,41357L,41358L,41359L,41360L, -41361L,41362L,41363L,41364L,41365L,41366L,41367L,41368L,41369L,41370L, -41371L,41372L,41373L,41374L,41375L,41376L,41377L,41378L,41379L,41380L, -41381L,41382L,41383L,41384L,41385L,41386L,41387L,41388L,41389L,41390L, -41391L,41392L,41393L,41394L,41395L,41396L,41397L,41398L,41399L,41400L, -41401L,41402L,41403L,41404L,41405L,41406L,41407L,41408L,41409L,41410L, -41411L,41412L,41413L,41414L,41415L,41416L,41417L,41418L,41419L,41420L, -41421L,41422L,41423L,41424L,41425L,41426L,41427L,41428L,41429L,41430L, -41431L,41432L,41433L,41434L,41435L,41436L,41437L,41438L,41439L,41440L, -41441L,41442L,41443L,41444L,41445L,41446L,41447L,41448L,41449L,41450L, -41451L,41452L,41453L,41454L,41455L,41456L,41457L,41458L,41459L,41460L, -41461L,41462L,41463L,41464L,41465L,41466L,41467L,41468L,41469L,41470L, -41471L,41472L,41473L,41474L,41475L,41476L,41477L,41478L,41479L,41480L, -41481L,41482L,41483L,41484L,41485L,41486L,41487L,41488L,41489L,41490L, -41491L,41492L,41493L,41494L,41495L,41496L,41497L,41498L,41499L,41500L, -41501L,41502L,41503L,41504L,41505L,41506L,41507L,41508L,41509L,41510L, -41511L,41512L,41513L,41514L,41515L,41516L,41517L,41518L,41519L,41520L, -41521L,41522L,41523L,41524L,41525L,41526L,41527L,41528L,41529L,41530L, -41531L,41532L,41533L,41534L,41535L,41536L,41537L,41538L,41539L,41540L, -41541L,41542L,41543L,41544L,41545L,41546L,41547L,41548L,41549L,41550L, -41551L,41552L,41553L,41554L,41555L,41556L,41557L,41558L,41559L,41560L, -41561L,41562L,41563L,41564L,41565L,41566L,41567L,41568L,41569L,41570L, -41571L,41572L,41573L,41574L,41575L,41576L,41577L,41578L,41579L,41580L, -41581L,41582L,41583L,41584L,41585L,41586L,41587L,41588L,41589L,41590L, -41591L,41592L,41593L,41594L,41595L,41596L,41597L,41598L,41599L,41600L, -41601L,41602L,41603L,41604L,41605L,41606L,41607L,41608L,41609L,41610L, -41611L,41612L,41613L,41614L,41615L,41616L,41617L,41618L,41619L,41620L, -41621L,41622L,41623L,41624L,41625L,41626L,41627L,41628L,41629L,41630L, -41631L,41632L,41633L,41634L,41635L,41636L,41637L,41638L,41639L,41640L, -41641L,41642L,41643L,41644L,41645L,41646L,41647L,41648L,41649L,41650L, -41651L,41652L,41653L,41654L,41655L,41656L,41657L,41658L,41659L,41660L, -41661L,41662L,41663L,41664L,41665L,41666L,41667L,41668L,41669L,41670L, -41671L,41672L,41673L,41674L,41675L,41676L,41677L,41678L,41679L,41680L, -41681L,41682L,41683L,41684L,41685L,41686L,41687L,41688L,41689L,41690L, -41691L,41692L,41693L,41694L,41695L,41696L,41697L,41698L,41699L,41700L, -41701L,41702L,41703L,41704L,41705L,41706L,41707L,41708L,41709L,41710L, -41711L,41712L,41713L,41714L,41715L,41716L,41717L,41718L,41719L,41720L, -41721L,41722L,41723L,41724L,41725L,41726L,41727L,41728L,41729L,41730L, -41731L,41732L,41733L,41734L,41735L,41736L,41737L,41738L,41739L,41740L, -41741L,41742L,41743L,41744L,41745L,41746L,41747L,41748L,41749L,41750L, -41751L,41752L,41753L,41754L,41755L,41756L,41757L,41758L,41759L,41760L, -41761L,41762L,41763L,41764L,41765L,41766L,41767L,41768L,41769L,41770L, -41771L,41772L,41773L,41774L,41775L,41776L,41777L,41778L,41779L,41780L, -41781L,41782L,41783L,41784L,41785L,41786L,41787L,41788L,41789L,41790L, -41791L,41792L,41793L,41794L,41795L,41796L,41797L,41798L,41799L,41800L, -41801L,41802L,41803L,41804L,41805L,41806L,41807L,41808L,41809L,41810L, -41811L,41812L,41813L,41814L,41815L,41816L,41817L,41818L,41819L,41820L, -41821L,41822L,41823L,41824L,41825L,41826L,41827L,41828L,41829L,41830L, -41831L,41832L,41833L,41834L,41835L,41836L,41837L,41838L,41839L,41840L, -41841L,41842L,41843L,41844L,41845L,41846L,41847L,41848L,41849L,41850L, -41851L,41852L,41853L,41854L,41855L,41856L,41857L,41858L,41859L,41860L, -41861L,41862L,41863L,41864L,41865L,41866L,41867L,41868L,41869L,41870L, -41871L,41872L,41873L,41874L,41875L,41876L,41877L,41878L,41879L,41880L, -41881L,41882L,41883L,41884L,41885L,41886L,41887L,41888L,41889L,41890L, -41891L,41892L,41893L,41894L,41895L,41896L,41897L,41898L,41899L,41900L, -41901L,41902L,41903L,41904L,41905L,41906L,41907L,41908L,41909L,41910L, -41911L,41912L,41913L,41914L,41915L,41916L,41917L,41918L,41919L,41920L, -41921L,41922L,41923L,41924L,41925L,41926L,41927L,41928L,41929L,41930L, -41931L,41932L,41933L,41934L,41935L,41936L,41937L,41938L,41939L,41940L, -41941L,41942L,41943L,41944L,41945L,41946L,41947L,41948L,41949L,41950L, -41951L,41952L,41953L,41954L,41955L,41956L,41957L,41958L,41959L,41960L, -41961L,41962L,41963L,41964L,41965L,41966L,41967L,41968L,41969L,41970L, -41971L,41972L,41973L,41974L,41975L,41976L,41977L,41978L,41979L,41980L, -41981L,41982L,41983L,41984L,41985L,41986L,41987L,41988L,41989L,41990L, -41991L,41992L,41993L,41994L,41995L,41996L,41997L,41998L,41999L,42000L, -42001L,42002L,42003L,42004L,42005L,42006L,42007L,42008L,42009L,42010L, -42011L,42012L,42013L,42014L,42015L,42016L,42017L,42018L,42019L,42020L, -42021L,42022L,42023L,42024L,42025L,42026L,42027L,42028L,42029L,42030L, -42031L,42032L,42033L,42034L,42035L,42036L,42037L,42038L,42039L,42040L, -42041L,42042L,42043L,42044L,42045L,42046L,42047L,42048L,42049L,42050L, -42051L,42052L,42053L,42054L,42055L,42056L,42057L,42058L,42059L,42060L, -42061L,42062L,42063L,42064L,42065L,42066L,42067L,42068L,42069L,42070L, -42071L,42072L,42073L,42074L,42075L,42076L,42077L,42078L,42079L,42080L, -42081L,42082L,42083L,42084L,42085L,42086L,42087L,42088L,42089L,42090L, -42091L,42092L,42093L,42094L,42095L,42096L,42097L,42098L,42099L,42100L, -42101L,42102L,42103L,42104L,42105L,42106L,42107L,42108L,42109L,42110L, -42111L,42112L,42113L,42114L,42115L,42116L,42117L,42118L,42119L,42120L, -42121L,42122L,42123L,42124L,42125L,42126L,42127L,42128L,42129L,42130L, -42131L,42132L,42133L,42134L,42135L,42136L,42137L,42138L,42139L,42140L, -42141L,42142L,42143L,42144L,42145L,42146L,42147L,42148L,42149L,42150L, -42151L,42152L,42153L,42154L,42155L,42156L,42157L,42158L,42159L,42160L, -42161L,42162L,42163L,42164L,42165L,42166L,42167L,42168L,42169L,42170L, -42171L,42172L,42173L,42174L,42175L,42176L,42177L,42178L,42179L,42180L, -42181L,42182L,42183L,42184L,42185L,42186L,42187L,42188L,42189L,42190L, -42191L,42192L,42193L,42194L,42195L,42196L,42197L,42198L,42199L,42200L, -42201L,42202L,42203L,42204L,42205L,42206L,42207L,42208L,42209L,42210L, -42211L,42212L,42213L,42214L,42215L,42216L,42217L,42218L,42219L,42220L, -42221L,42222L,42223L,42224L,42225L,42226L,42227L,42228L,42229L,42230L, -42231L,42232L,42233L,42234L,42235L,42236L,42237L,42238L,42239L,42240L, -42241L,42242L,42243L,42244L,42245L,42246L,42247L,42248L,42249L,42250L, -42251L,42252L,42253L,42254L,42255L,42256L,42257L,42258L,42259L,42260L, -42261L,42262L,42263L,42264L,42265L,42266L,42267L,42268L,42269L,42270L, -42271L,42272L,42273L,42274L,42275L,42276L,42277L,42278L,42279L,42280L, -42281L,42282L,42283L,42284L,42285L,42286L,42287L,42288L,42289L,42290L, -42291L,42292L,42293L,42294L,42295L,42296L,42297L,42298L,42299L,42300L, -42301L,42302L,42303L,42304L,42305L,42306L,42307L,42308L,42309L,42310L, -42311L,42312L,42313L,42314L,42315L,42316L,42317L,42318L,42319L,42320L, -42321L,42322L,42323L,42324L,42325L,42326L,42327L,42328L,42329L,42330L, -42331L,42332L,42333L,42334L,42335L,42336L,42337L,42338L,42339L,42340L, -42341L,42342L,42343L,42344L,42345L,42346L,42347L,42348L,42349L,42350L, -42351L,42352L,42353L,42354L,42355L,42356L,42357L,42358L,42359L,42360L, -42361L,42362L,42363L,42364L,42365L,42366L,42367L,42368L,42369L,42370L, -42371L,42372L,42373L,42374L,42375L,42376L,42377L,42378L,42379L,42380L, -42381L,42382L,42383L,42384L,42385L,42386L,42387L,42388L,42389L,42390L, -42391L,42392L,42393L,42394L,42395L,42396L,42397L,42398L,42399L,42400L, -42401L,42402L,42403L,42404L,42405L,42406L,42407L,42408L,42409L,42410L, -42411L,42412L,42413L,42414L,42415L,42416L,42417L,42418L,42419L,42420L, -42421L,42422L,42423L,42424L,42425L,42426L,42427L,42428L,42429L,42430L, -42431L,42432L,42433L,42434L,42435L,42436L,42437L,42438L,42439L,42440L, -42441L,42442L,42443L,42444L,42445L,42446L,42447L,42448L,42449L,42450L, -42451L,42452L,42453L,42454L,42455L,42456L,42457L,42458L,42459L,42460L, -42461L,42462L,42463L,42464L,42465L,42466L,42467L,42468L,42469L,42470L, -42471L,42472L,42473L,42474L,42475L,42476L,42477L,42478L,42479L,42480L, -42481L,42482L,42483L,42484L,42485L,42486L,42487L,42488L,42489L,42490L, -42491L,42492L,42493L,42494L,42495L,42496L,42497L,42498L,42499L,42500L, -42501L,42502L,42503L,42504L,42505L,42506L,42507L,42508L,42509L,42510L, -42511L,42512L,42513L,42514L,42515L,42516L,42517L,42518L,42519L,42520L, -42521L,42522L,42523L,42524L,42525L,42526L,42527L,42528L,42529L,42530L, -42531L,42532L,42533L,42534L,42535L,42536L,42537L,42538L,42539L,42540L, -42541L,42542L,42543L,42544L,42545L,42546L,42547L,42548L,42549L,42550L, -42551L,42552L,42553L,42554L,42555L,42556L,42557L,42558L,42559L,42560L, -42560L,42562L,42562L,42564L,42564L,42566L,42566L,42568L,42568L,42570L, -42570L,42572L,42572L,42574L,42574L,42576L,42576L,42578L,42578L,42580L, -42580L,42582L,42582L,42584L,42584L,42586L,42586L,42588L,42588L,42590L, -42590L,42592L,42592L,42594L,42594L,42596L,42596L,42598L,42598L,42600L, -42600L,42602L,42602L,42604L,42604L,42606L,42607L,42608L,42609L,42610L, -42611L,42612L,42613L,42614L,42615L,42616L,42617L,42618L,42619L,42620L, -42621L,42622L,42623L,42624L,42624L,42626L,42626L,42628L,42628L,42630L, -42630L,42632L,42632L,42634L,42634L,42636L,42636L,42638L,42638L,42640L, -42640L,42642L,42642L,42644L,42644L,42646L,42646L,42648L,42648L,42650L, -42650L,42652L,42653L,42654L,42655L,42656L,42657L,42658L,42659L,42660L, -42661L,42662L,42663L,42664L,42665L,42666L,42667L,42668L,42669L,42670L, -42671L,42672L,42673L,42674L,42675L,42676L,42677L,42678L,42679L,42680L, -42681L,42682L,42683L,42684L,42685L,42686L,42687L,42688L,42689L,42690L, -42691L,42692L,42693L,42694L,42695L,42696L,42697L,42698L,42699L,42700L, -42701L,42702L,42703L,42704L,42705L,42706L,42707L,42708L,42709L,42710L, -42711L,42712L,42713L,42714L,42715L,42716L,42717L,42718L,42719L,42720L, -42721L,42722L,42723L,42724L,42725L,42726L,42727L,42728L,42729L,42730L, -42731L,42732L,42733L,42734L,42735L,42736L,42737L,42738L,42739L,42740L, -42741L,42742L,42743L,42744L,42745L,42746L,42747L,42748L,42749L,42750L, -42751L,42752L,42753L,42754L,42755L,42756L,42757L,42758L,42759L,42760L, -42761L,42762L,42763L,42764L,42765L,42766L,42767L,42768L,42769L,42770L, -42771L,42772L,42773L,42774L,42775L,42776L,42777L,42778L,42779L,42780L, -42781L,42782L,42783L,42784L,42785L,42786L,42786L,42788L,42788L,42790L, -42790L,42792L,42792L,42794L,42794L,42796L,42796L,42798L,42798L,42800L, -42801L,42802L,42802L,42804L,42804L,42806L,42806L,42808L,42808L,42810L, -42810L,42812L,42812L,42814L,42814L,42816L,42816L,42818L,42818L,42820L, -42820L,42822L,42822L,42824L,42824L,42826L,42826L,42828L,42828L,42830L, -42830L,42832L,42832L,42834L,42834L,42836L,42836L,42838L,42838L,42840L, -42840L,42842L,42842L,42844L,42844L,42846L,42846L,42848L,42848L,42850L, -42850L,42852L,42852L,42854L,42854L,42856L,42856L,42858L,42858L,42860L, -42860L,42862L,42862L,42864L,42865L,42866L,42867L,42868L,42869L,42870L, -42871L,42872L,42873L,42873L,42875L,42875L,42877L,42878L,42878L,42880L, -42880L,42882L,42882L,42884L,42884L,42886L,42886L,42888L,42889L,42890L, -42891L,42891L,42893L,42894L,42895L,42896L,42896L,42898L,42898L,42900L, -42901L,42902L,42902L,42904L,42904L,42906L,42906L,42908L,42908L,42910L, -42910L,42912L,42912L,42914L,42914L,42916L,42916L,42918L,42918L,42920L, -42920L,42922L,42923L,42924L,42925L,42926L,42927L,42928L,42929L,42930L, -42931L,42932L,42932L,42934L,42934L,42936L,42937L,42938L,42939L,42940L, -42941L,42942L,42943L,42944L,42945L,42946L,42947L,42948L,42949L,42950L, -42951L,42952L,42953L,42954L,42955L,42956L,42957L,42958L,42959L,42960L, -42961L,42962L,42963L,42964L,42965L,42966L,42967L,42968L,42969L,42970L, -42971L,42972L,42973L,42974L,42975L,42976L,42977L,42978L,42979L,42980L, -42981L,42982L,42983L,42984L,42985L,42986L,42987L,42988L,42989L,42990L, -42991L,42992L,42993L,42994L,42995L,42996L,42997L,42998L,42999L,43000L, -43001L,43002L,43003L,43004L,43005L,43006L,43007L,43008L,43009L,43010L, -43011L,43012L,43013L,43014L,43015L,43016L,43017L,43018L,43019L,43020L, -43021L,43022L,43023L,43024L,43025L,43026L,43027L,43028L,43029L,43030L, -43031L,43032L,43033L,43034L,43035L,43036L,43037L,43038L,43039L,43040L, -43041L,43042L,43043L,43044L,43045L,43046L,43047L,43048L,43049L,43050L, -43051L,43052L,43053L,43054L,43055L,43056L,43057L,43058L,43059L,43060L, -43061L,43062L,43063L,43064L,43065L,43066L,43067L,43068L,43069L,43070L, -43071L,43072L,43073L,43074L,43075L,43076L,43077L,43078L,43079L,43080L, -43081L,43082L,43083L,43084L,43085L,43086L,43087L,43088L,43089L,43090L, -43091L,43092L,43093L,43094L,43095L,43096L,43097L,43098L,43099L,43100L, -43101L,43102L,43103L,43104L,43105L,43106L,43107L,43108L,43109L,43110L, -43111L,43112L,43113L,43114L,43115L,43116L,43117L,43118L,43119L,43120L, -43121L,43122L,43123L,43124L,43125L,43126L,43127L,43128L,43129L,43130L, -43131L,43132L,43133L,43134L,43135L,43136L,43137L,43138L,43139L,43140L, -43141L,43142L,43143L,43144L,43145L,43146L,43147L,43148L,43149L,43150L, -43151L,43152L,43153L,43154L,43155L,43156L,43157L,43158L,43159L,43160L, -43161L,43162L,43163L,43164L,43165L,43166L,43167L,43168L,43169L,43170L, -43171L,43172L,43173L,43174L,43175L,43176L,43177L,43178L,43179L,43180L, -43181L,43182L,43183L,43184L,43185L,43186L,43187L,43188L,43189L,43190L, -43191L,43192L,43193L,43194L,43195L,43196L,43197L,43198L,43199L,43200L, -43201L,43202L,43203L,43204L,43205L,43206L,43207L,43208L,43209L,43210L, -43211L,43212L,43213L,43214L,43215L,43216L,43217L,43218L,43219L,43220L, -43221L,43222L,43223L,43224L,43225L,43226L,43227L,43228L,43229L,43230L, -43231L,43232L,43233L,43234L,43235L,43236L,43237L,43238L,43239L,43240L, -43241L,43242L,43243L,43244L,43245L,43246L,43247L,43248L,43249L,43250L, -43251L,43252L,43253L,43254L,43255L,43256L,43257L,43258L,43259L,43260L, -43261L,43262L,43263L,43264L,43265L,43266L,43267L,43268L,43269L,43270L, -43271L,43272L,43273L,43274L,43275L,43276L,43277L,43278L,43279L,43280L, -43281L,43282L,43283L,43284L,43285L,43286L,43287L,43288L,43289L,43290L, -43291L,43292L,43293L,43294L,43295L,43296L,43297L,43298L,43299L,43300L, -43301L,43302L,43303L,43304L,43305L,43306L,43307L,43308L,43309L,43310L, -43311L,43312L,43313L,43314L,43315L,43316L,43317L,43318L,43319L,43320L, -43321L,43322L,43323L,43324L,43325L,43326L,43327L,43328L,43329L,43330L, -43331L,43332L,43333L,43334L,43335L,43336L,43337L,43338L,43339L,43340L, -43341L,43342L,43343L,43344L,43345L,43346L,43347L,43348L,43349L,43350L, -43351L,43352L,43353L,43354L,43355L,43356L,43357L,43358L,43359L,43360L, -43361L,43362L,43363L,43364L,43365L,43366L,43367L,43368L,43369L,43370L, -43371L,43372L,43373L,43374L,43375L,43376L,43377L,43378L,43379L,43380L, -43381L,43382L,43383L,43384L,43385L,43386L,43387L,43388L,43389L,43390L, -43391L,43392L,43393L,43394L,43395L,43396L,43397L,43398L,43399L,43400L, -43401L,43402L,43403L,43404L,43405L,43406L,43407L,43408L,43409L,43410L, -43411L,43412L,43413L,43414L,43415L,43416L,43417L,43418L,43419L,43420L, -43421L,43422L,43423L,43424L,43425L,43426L,43427L,43428L,43429L,43430L, -43431L,43432L,43433L,43434L,43435L,43436L,43437L,43438L,43439L,43440L, -43441L,43442L,43443L,43444L,43445L,43446L,43447L,43448L,43449L,43450L, -43451L,43452L,43453L,43454L,43455L,43456L,43457L,43458L,43459L,43460L, -43461L,43462L,43463L,43464L,43465L,43466L,43467L,43468L,43469L,43470L, -43471L,43472L,43473L,43474L,43475L,43476L,43477L,43478L,43479L,43480L, -43481L,43482L,43483L,43484L,43485L,43486L,43487L,43488L,43489L,43490L, -43491L,43492L,43493L,43494L,43495L,43496L,43497L,43498L,43499L,43500L, -43501L,43502L,43503L,43504L,43505L,43506L,43507L,43508L,43509L,43510L, -43511L,43512L,43513L,43514L,43515L,43516L,43517L,43518L,43519L,43520L, -43521L,43522L,43523L,43524L,43525L,43526L,43527L,43528L,43529L,43530L, -43531L,43532L,43533L,43534L,43535L,43536L,43537L,43538L,43539L,43540L, -43541L,43542L,43543L,43544L,43545L,43546L,43547L,43548L,43549L,43550L, -43551L,43552L,43553L,43554L,43555L,43556L,43557L,43558L,43559L,43560L, -43561L,43562L,43563L,43564L,43565L,43566L,43567L,43568L,43569L,43570L, -43571L,43572L,43573L,43574L,43575L,43576L,43577L,43578L,43579L,43580L, -43581L,43582L,43583L,43584L,43585L,43586L,43587L,43588L,43589L,43590L, -43591L,43592L,43593L,43594L,43595L,43596L,43597L,43598L,43599L,43600L, -43601L,43602L,43603L,43604L,43605L,43606L,43607L,43608L,43609L,43610L, -43611L,43612L,43613L,43614L,43615L,43616L,43617L,43618L,43619L,43620L, -43621L,43622L,43623L,43624L,43625L,43626L,43627L,43628L,43629L,43630L, -43631L,43632L,43633L,43634L,43635L,43636L,43637L,43638L,43639L,43640L, -43641L,43642L,43643L,43644L,43645L,43646L,43647L,43648L,43649L,43650L, -43651L,43652L,43653L,43654L,43655L,43656L,43657L,43658L,43659L,43660L, -43661L,43662L,43663L,43664L,43665L,43666L,43667L,43668L,43669L,43670L, -43671L,43672L,43673L,43674L,43675L,43676L,43677L,43678L,43679L,43680L, -43681L,43682L,43683L,43684L,43685L,43686L,43687L,43688L,43689L,43690L, -43691L,43692L,43693L,43694L,43695L,43696L,43697L,43698L,43699L,43700L, -43701L,43702L,43703L,43704L,43705L,43706L,43707L,43708L,43709L,43710L, -43711L,43712L,43713L,43714L,43715L,43716L,43717L,43718L,43719L,43720L, -43721L,43722L,43723L,43724L,43725L,43726L,43727L,43728L,43729L,43730L, -43731L,43732L,43733L,43734L,43735L,43736L,43737L,43738L,43739L,43740L, -43741L,43742L,43743L,43744L,43745L,43746L,43747L,43748L,43749L,43750L, -43751L,43752L,43753L,43754L,43755L,43756L,43757L,43758L,43759L,43760L, -43761L,43762L,43763L,43764L,43765L,43766L,43767L,43768L,43769L,43770L, -43771L,43772L,43773L,43774L,43775L,43776L,43777L,43778L,43779L,43780L, -43781L,43782L,43783L,43784L,43785L,43786L,43787L,43788L,43789L,43790L, -43791L,43792L,43793L,43794L,43795L,43796L,43797L,43798L,43799L,43800L, -43801L,43802L,43803L,43804L,43805L,43806L,43807L,43808L,43809L,43810L, -43811L,43812L,43813L,43814L,43815L,43816L,43817L,43818L,43819L,43820L, -43821L,43822L,43823L,43824L,43825L,43826L,43827L,43828L,43829L,43830L, -43831L,43832L,43833L,43834L,43835L,43836L,43837L,43838L,43839L,43840L, -43841L,43842L,43843L,43844L,43845L,43846L,43847L,43848L,43849L,43850L, -43851L,43852L,43853L,43854L,43855L,43856L,43857L,43858L,42931L,43860L, -43861L,43862L,43863L,43864L,43865L,43866L,43867L,43868L,43869L,43870L, -43871L,43872L,43873L,43874L,43875L,43876L,43877L,43878L,43879L,43880L, -43881L,43882L,43883L,43884L,43885L,43886L,43887L,5024,5025,5026,5027,5028, -5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043, -5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058, -5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073, -5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088, -5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103, -43968L,43969L,43970L,43971L,43972L,43973L,43974L,43975L,43976L,43977L, -43978L,43979L,43980L,43981L,43982L,43983L,43984L,43985L,43986L,43987L, -43988L,43989L,43990L,43991L,43992L,43993L,43994L,43995L,43996L,43997L, -43998L,43999L,44000L,44001L,44002L,44003L,44004L,44005L,44006L,44007L, -44008L,44009L,44010L,44011L,44012L,44013L,44014L,44015L,44016L,44017L, -44018L,44019L,44020L,44021L,44022L,44023L,44024L,44025L,44026L,44027L, -44028L,44029L,44030L,44031L,44032L,44033L,44034L,44035L,44036L,44037L, -44038L,44039L,44040L,44041L,44042L,44043L,44044L,44045L,44046L,44047L, -44048L,44049L,44050L,44051L,44052L,44053L,44054L,44055L,44056L,44057L, -44058L,44059L,44060L,44061L,44062L,44063L,44064L,44065L,44066L,44067L, -44068L,44069L,44070L,44071L,44072L,44073L,44074L,44075L,44076L,44077L, -44078L,44079L,44080L,44081L,44082L,44083L,44084L,44085L,44086L,44087L, -44088L,44089L,44090L,44091L,44092L,44093L,44094L,44095L,44096L,44097L, -44098L,44099L,44100L,44101L,44102L,44103L,44104L,44105L,44106L,44107L, -44108L,44109L,44110L,44111L,44112L,44113L,44114L,44115L,44116L,44117L, -44118L,44119L,44120L,44121L,44122L,44123L,44124L,44125L,44126L,44127L, -44128L,44129L,44130L,44131L,44132L,44133L,44134L,44135L,44136L,44137L, -44138L,44139L,44140L,44141L,44142L,44143L,44144L,44145L,44146L,44147L, -44148L,44149L,44150L,44151L,44152L,44153L,44154L,44155L,44156L,44157L, -44158L,44159L,44160L,44161L,44162L,44163L,44164L,44165L,44166L,44167L, -44168L,44169L,44170L,44171L,44172L,44173L,44174L,44175L,44176L,44177L, -44178L,44179L,44180L,44181L,44182L,44183L,44184L,44185L,44186L,44187L, -44188L,44189L,44190L,44191L,44192L,44193L,44194L,44195L,44196L,44197L, -44198L,44199L,44200L,44201L,44202L,44203L,44204L,44205L,44206L,44207L, -44208L,44209L,44210L,44211L,44212L,44213L,44214L,44215L,44216L,44217L, -44218L,44219L,44220L,44221L,44222L,44223L,44224L,44225L,44226L,44227L, -44228L,44229L,44230L,44231L,44232L,44233L,44234L,44235L,44236L,44237L, -44238L,44239L,44240L,44241L,44242L,44243L,44244L,44245L,44246L,44247L, -44248L,44249L,44250L,44251L,44252L,44253L,44254L,44255L,44256L,44257L, -44258L,44259L,44260L,44261L,44262L,44263L,44264L,44265L,44266L,44267L, -44268L,44269L,44270L,44271L,44272L,44273L,44274L,44275L,44276L,44277L, -44278L,44279L,44280L,44281L,44282L,44283L,44284L,44285L,44286L,44287L, -44288L,44289L,44290L,44291L,44292L,44293L,44294L,44295L,44296L,44297L, -44298L,44299L,44300L,44301L,44302L,44303L,44304L,44305L,44306L,44307L, -44308L,44309L,44310L,44311L,44312L,44313L,44314L,44315L,44316L,44317L, -44318L,44319L,44320L,44321L,44322L,44323L,44324L,44325L,44326L,44327L, -44328L,44329L,44330L,44331L,44332L,44333L,44334L,44335L,44336L,44337L, -44338L,44339L,44340L,44341L,44342L,44343L,44344L,44345L,44346L,44347L, -44348L,44349L,44350L,44351L,44352L,44353L,44354L,44355L,44356L,44357L, -44358L,44359L,44360L,44361L,44362L,44363L,44364L,44365L,44366L,44367L, -44368L,44369L,44370L,44371L,44372L,44373L,44374L,44375L,44376L,44377L, -44378L,44379L,44380L,44381L,44382L,44383L,44384L,44385L,44386L,44387L, -44388L,44389L,44390L,44391L,44392L,44393L,44394L,44395L,44396L,44397L, -44398L,44399L,44400L,44401L,44402L,44403L,44404L,44405L,44406L,44407L, -44408L,44409L,44410L,44411L,44412L,44413L,44414L,44415L,44416L,44417L, -44418L,44419L,44420L,44421L,44422L,44423L,44424L,44425L,44426L,44427L, -44428L,44429L,44430L,44431L,44432L,44433L,44434L,44435L,44436L,44437L, -44438L,44439L,44440L,44441L,44442L,44443L,44444L,44445L,44446L,44447L, -44448L,44449L,44450L,44451L,44452L,44453L,44454L,44455L,44456L,44457L, -44458L,44459L,44460L,44461L,44462L,44463L,44464L,44465L,44466L,44467L, -44468L,44469L,44470L,44471L,44472L,44473L,44474L,44475L,44476L,44477L, -44478L,44479L,44480L,44481L,44482L,44483L,44484L,44485L,44486L,44487L, -44488L,44489L,44490L,44491L,44492L,44493L,44494L,44495L,44496L,44497L, -44498L,44499L,44500L,44501L,44502L,44503L,44504L,44505L,44506L,44507L, -44508L,44509L,44510L,44511L,44512L,44513L,44514L,44515L,44516L,44517L, -44518L,44519L,44520L,44521L,44522L,44523L,44524L,44525L,44526L,44527L, -44528L,44529L,44530L,44531L,44532L,44533L,44534L,44535L,44536L,44537L, -44538L,44539L,44540L,44541L,44542L,44543L,44544L,44545L,44546L,44547L, -44548L,44549L,44550L,44551L,44552L,44553L,44554L,44555L,44556L,44557L, -44558L,44559L,44560L,44561L,44562L,44563L,44564L,44565L,44566L,44567L, -44568L,44569L,44570L,44571L,44572L,44573L,44574L,44575L,44576L,44577L, -44578L,44579L,44580L,44581L,44582L,44583L,44584L,44585L,44586L,44587L, -44588L,44589L,44590L,44591L,44592L,44593L,44594L,44595L,44596L,44597L, -44598L,44599L,44600L,44601L,44602L,44603L,44604L,44605L,44606L,44607L, -44608L,44609L,44610L,44611L,44612L,44613L,44614L,44615L,44616L,44617L, -44618L,44619L,44620L,44621L,44622L,44623L,44624L,44625L,44626L,44627L, -44628L,44629L,44630L,44631L,44632L,44633L,44634L,44635L,44636L,44637L, -44638L,44639L,44640L,44641L,44642L,44643L,44644L,44645L,44646L,44647L, -44648L,44649L,44650L,44651L,44652L,44653L,44654L,44655L,44656L,44657L, -44658L,44659L,44660L,44661L,44662L,44663L,44664L,44665L,44666L,44667L, -44668L,44669L,44670L,44671L,44672L,44673L,44674L,44675L,44676L,44677L, -44678L,44679L,44680L,44681L,44682L,44683L,44684L,44685L,44686L,44687L, -44688L,44689L,44690L,44691L,44692L,44693L,44694L,44695L,44696L,44697L, -44698L,44699L,44700L,44701L,44702L,44703L,44704L,44705L,44706L,44707L, -44708L,44709L,44710L,44711L,44712L,44713L,44714L,44715L,44716L,44717L, -44718L,44719L,44720L,44721L,44722L,44723L,44724L,44725L,44726L,44727L, -44728L,44729L,44730L,44731L,44732L,44733L,44734L,44735L,44736L,44737L, -44738L,44739L,44740L,44741L,44742L,44743L,44744L,44745L,44746L,44747L, -44748L,44749L,44750L,44751L,44752L,44753L,44754L,44755L,44756L,44757L, -44758L,44759L,44760L,44761L,44762L,44763L,44764L,44765L,44766L,44767L, -44768L,44769L,44770L,44771L,44772L,44773L,44774L,44775L,44776L,44777L, -44778L,44779L,44780L,44781L,44782L,44783L,44784L,44785L,44786L,44787L, -44788L,44789L,44790L,44791L,44792L,44793L,44794L,44795L,44796L,44797L, -44798L,44799L,44800L,44801L,44802L,44803L,44804L,44805L,44806L,44807L, -44808L,44809L,44810L,44811L,44812L,44813L,44814L,44815L,44816L,44817L, -44818L,44819L,44820L,44821L,44822L,44823L,44824L,44825L,44826L,44827L, -44828L,44829L,44830L,44831L,44832L,44833L,44834L,44835L,44836L,44837L, -44838L,44839L,44840L,44841L,44842L,44843L,44844L,44845L,44846L,44847L, -44848L,44849L,44850L,44851L,44852L,44853L,44854L,44855L,44856L,44857L, -44858L,44859L,44860L,44861L,44862L,44863L,44864L,44865L,44866L,44867L, -44868L,44869L,44870L,44871L,44872L,44873L,44874L,44875L,44876L,44877L, -44878L,44879L,44880L,44881L,44882L,44883L,44884L,44885L,44886L,44887L, -44888L,44889L,44890L,44891L,44892L,44893L,44894L,44895L,44896L,44897L, -44898L,44899L,44900L,44901L,44902L,44903L,44904L,44905L,44906L,44907L, -44908L,44909L,44910L,44911L,44912L,44913L,44914L,44915L,44916L,44917L, -44918L,44919L,44920L,44921L,44922L,44923L,44924L,44925L,44926L,44927L, -44928L,44929L,44930L,44931L,44932L,44933L,44934L,44935L,44936L,44937L, -44938L,44939L,44940L,44941L,44942L,44943L,44944L,44945L,44946L,44947L, -44948L,44949L,44950L,44951L,44952L,44953L,44954L,44955L,44956L,44957L, -44958L,44959L,44960L,44961L,44962L,44963L,44964L,44965L,44966L,44967L, -44968L,44969L,44970L,44971L,44972L,44973L,44974L,44975L,44976L,44977L, -44978L,44979L,44980L,44981L,44982L,44983L,44984L,44985L,44986L,44987L, -44988L,44989L,44990L,44991L,44992L,44993L,44994L,44995L,44996L,44997L, -44998L,44999L,45000L,45001L,45002L,45003L,45004L,45005L,45006L,45007L, -45008L,45009L,45010L,45011L,45012L,45013L,45014L,45015L,45016L,45017L, -45018L,45019L,45020L,45021L,45022L,45023L,45024L,45025L,45026L,45027L, -45028L,45029L,45030L,45031L,45032L,45033L,45034L,45035L,45036L,45037L, -45038L,45039L,45040L,45041L,45042L,45043L,45044L,45045L,45046L,45047L, -45048L,45049L,45050L,45051L,45052L,45053L,45054L,45055L,45056L,45057L, -45058L,45059L,45060L,45061L,45062L,45063L,45064L,45065L,45066L,45067L, -45068L,45069L,45070L,45071L,45072L,45073L,45074L,45075L,45076L,45077L, -45078L,45079L,45080L,45081L,45082L,45083L,45084L,45085L,45086L,45087L, -45088L,45089L,45090L,45091L,45092L,45093L,45094L,45095L,45096L,45097L, -45098L,45099L,45100L,45101L,45102L,45103L,45104L,45105L,45106L,45107L, -45108L,45109L,45110L,45111L,45112L,45113L,45114L,45115L,45116L,45117L, -45118L,45119L,45120L,45121L,45122L,45123L,45124L,45125L,45126L,45127L, -45128L,45129L,45130L,45131L,45132L,45133L,45134L,45135L,45136L,45137L, -45138L,45139L,45140L,45141L,45142L,45143L,45144L,45145L,45146L,45147L, -45148L,45149L,45150L,45151L,45152L,45153L,45154L,45155L,45156L,45157L, -45158L,45159L,45160L,45161L,45162L,45163L,45164L,45165L,45166L,45167L, -45168L,45169L,45170L,45171L,45172L,45173L,45174L,45175L,45176L,45177L, -45178L,45179L,45180L,45181L,45182L,45183L,45184L,45185L,45186L,45187L, -45188L,45189L,45190L,45191L,45192L,45193L,45194L,45195L,45196L,45197L, -45198L,45199L,45200L,45201L,45202L,45203L,45204L,45205L,45206L,45207L, -45208L,45209L,45210L,45211L,45212L,45213L,45214L,45215L,45216L,45217L, -45218L,45219L,45220L,45221L,45222L,45223L,45224L,45225L,45226L,45227L, -45228L,45229L,45230L,45231L,45232L,45233L,45234L,45235L,45236L,45237L, -45238L,45239L,45240L,45241L,45242L,45243L,45244L,45245L,45246L,45247L, -45248L,45249L,45250L,45251L,45252L,45253L,45254L,45255L,45256L,45257L, -45258L,45259L,45260L,45261L,45262L,45263L,45264L,45265L,45266L,45267L, -45268L,45269L,45270L,45271L,45272L,45273L,45274L,45275L,45276L,45277L, -45278L,45279L,45280L,45281L,45282L,45283L,45284L,45285L,45286L,45287L, -45288L,45289L,45290L,45291L,45292L,45293L,45294L,45295L,45296L,45297L, -45298L,45299L,45300L,45301L,45302L,45303L,45304L,45305L,45306L,45307L, -45308L,45309L,45310L,45311L,45312L,45313L,45314L,45315L,45316L,45317L, -45318L,45319L,45320L,45321L,45322L,45323L,45324L,45325L,45326L,45327L, -45328L,45329L,45330L,45331L,45332L,45333L,45334L,45335L,45336L,45337L, -45338L,45339L,45340L,45341L,45342L,45343L,45344L,45345L,45346L,45347L, -45348L,45349L,45350L,45351L,45352L,45353L,45354L,45355L,45356L,45357L, -45358L,45359L,45360L,45361L,45362L,45363L,45364L,45365L,45366L,45367L, -45368L,45369L,45370L,45371L,45372L,45373L,45374L,45375L,45376L,45377L, -45378L,45379L,45380L,45381L,45382L,45383L,45384L,45385L,45386L,45387L, -45388L,45389L,45390L,45391L,45392L,45393L,45394L,45395L,45396L,45397L, -45398L,45399L,45400L,45401L,45402L,45403L,45404L,45405L,45406L,45407L, -45408L,45409L,45410L,45411L,45412L,45413L,45414L,45415L,45416L,45417L, -45418L,45419L,45420L,45421L,45422L,45423L,45424L,45425L,45426L,45427L, -45428L,45429L,45430L,45431L,45432L,45433L,45434L,45435L,45436L,45437L, -45438L,45439L,45440L,45441L,45442L,45443L,45444L,45445L,45446L,45447L, -45448L,45449L,45450L,45451L,45452L,45453L,45454L,45455L,45456L,45457L, -45458L,45459L,45460L,45461L,45462L,45463L,45464L,45465L,45466L,45467L, -45468L,45469L,45470L,45471L,45472L,45473L,45474L,45475L,45476L,45477L, -45478L,45479L,45480L,45481L,45482L,45483L,45484L,45485L,45486L,45487L, -45488L,45489L,45490L,45491L,45492L,45493L,45494L,45495L,45496L,45497L, -45498L,45499L,45500L,45501L,45502L,45503L,45504L,45505L,45506L,45507L, -45508L,45509L,45510L,45511L,45512L,45513L,45514L,45515L,45516L,45517L, -45518L,45519L,45520L,45521L,45522L,45523L,45524L,45525L,45526L,45527L, -45528L,45529L,45530L,45531L,45532L,45533L,45534L,45535L,45536L,45537L, -45538L,45539L,45540L,45541L,45542L,45543L,45544L,45545L,45546L,45547L, -45548L,45549L,45550L,45551L,45552L,45553L,45554L,45555L,45556L,45557L, -45558L,45559L,45560L,45561L,45562L,45563L,45564L,45565L,45566L,45567L, -45568L,45569L,45570L,45571L,45572L,45573L,45574L,45575L,45576L,45577L, -45578L,45579L,45580L,45581L,45582L,45583L,45584L,45585L,45586L,45587L, -45588L,45589L,45590L,45591L,45592L,45593L,45594L,45595L,45596L,45597L, -45598L,45599L,45600L,45601L,45602L,45603L,45604L,45605L,45606L,45607L, -45608L,45609L,45610L,45611L,45612L,45613L,45614L,45615L,45616L,45617L, -45618L,45619L,45620L,45621L,45622L,45623L,45624L,45625L,45626L,45627L, -45628L,45629L,45630L,45631L,45632L,45633L,45634L,45635L,45636L,45637L, -45638L,45639L,45640L,45641L,45642L,45643L,45644L,45645L,45646L,45647L, -45648L,45649L,45650L,45651L,45652L,45653L,45654L,45655L,45656L,45657L, -45658L,45659L,45660L,45661L,45662L,45663L,45664L,45665L,45666L,45667L, -45668L,45669L,45670L,45671L,45672L,45673L,45674L,45675L,45676L,45677L, -45678L,45679L,45680L,45681L,45682L,45683L,45684L,45685L,45686L,45687L, -45688L,45689L,45690L,45691L,45692L,45693L,45694L,45695L,45696L,45697L, -45698L,45699L,45700L,45701L,45702L,45703L,45704L,45705L,45706L,45707L, -45708L,45709L,45710L,45711L,45712L,45713L,45714L,45715L,45716L,45717L, -45718L,45719L,45720L,45721L,45722L,45723L,45724L,45725L,45726L,45727L, -45728L,45729L,45730L,45731L,45732L,45733L,45734L,45735L,45736L,45737L, -45738L,45739L,45740L,45741L,45742L,45743L,45744L,45745L,45746L,45747L, -45748L,45749L,45750L,45751L,45752L,45753L,45754L,45755L,45756L,45757L, -45758L,45759L,45760L,45761L,45762L,45763L,45764L,45765L,45766L,45767L, -45768L,45769L,45770L,45771L,45772L,45773L,45774L,45775L,45776L,45777L, -45778L,45779L,45780L,45781L,45782L,45783L,45784L,45785L,45786L,45787L, -45788L,45789L,45790L,45791L,45792L,45793L,45794L,45795L,45796L,45797L, -45798L,45799L,45800L,45801L,45802L,45803L,45804L,45805L,45806L,45807L, -45808L,45809L,45810L,45811L,45812L,45813L,45814L,45815L,45816L,45817L, -45818L,45819L,45820L,45821L,45822L,45823L,45824L,45825L,45826L,45827L, -45828L,45829L,45830L,45831L,45832L,45833L,45834L,45835L,45836L,45837L, -45838L,45839L,45840L,45841L,45842L,45843L,45844L,45845L,45846L,45847L, -45848L,45849L,45850L,45851L,45852L,45853L,45854L,45855L,45856L,45857L, -45858L,45859L,45860L,45861L,45862L,45863L,45864L,45865L,45866L,45867L, -45868L,45869L,45870L,45871L,45872L,45873L,45874L,45875L,45876L,45877L, -45878L,45879L,45880L,45881L,45882L,45883L,45884L,45885L,45886L,45887L, -45888L,45889L,45890L,45891L,45892L,45893L,45894L,45895L,45896L,45897L, -45898L,45899L,45900L,45901L,45902L,45903L,45904L,45905L,45906L,45907L, -45908L,45909L,45910L,45911L,45912L,45913L,45914L,45915L,45916L,45917L, -45918L,45919L,45920L,45921L,45922L,45923L,45924L,45925L,45926L,45927L, -45928L,45929L,45930L,45931L,45932L,45933L,45934L,45935L,45936L,45937L, -45938L,45939L,45940L,45941L,45942L,45943L,45944L,45945L,45946L,45947L, -45948L,45949L,45950L,45951L,45952L,45953L,45954L,45955L,45956L,45957L, -45958L,45959L,45960L,45961L,45962L,45963L,45964L,45965L,45966L,45967L, -45968L,45969L,45970L,45971L,45972L,45973L,45974L,45975L,45976L,45977L, -45978L,45979L,45980L,45981L,45982L,45983L,45984L,45985L,45986L,45987L, -45988L,45989L,45990L,45991L,45992L,45993L,45994L,45995L,45996L,45997L, -45998L,45999L,46000L,46001L,46002L,46003L,46004L,46005L,46006L,46007L, -46008L,46009L,46010L,46011L,46012L,46013L,46014L,46015L,46016L,46017L, -46018L,46019L,46020L,46021L,46022L,46023L,46024L,46025L,46026L,46027L, -46028L,46029L,46030L,46031L,46032L,46033L,46034L,46035L,46036L,46037L, -46038L,46039L,46040L,46041L,46042L,46043L,46044L,46045L,46046L,46047L, -46048L,46049L,46050L,46051L,46052L,46053L,46054L,46055L,46056L,46057L, -46058L,46059L,46060L,46061L,46062L,46063L,46064L,46065L,46066L,46067L, -46068L,46069L,46070L,46071L,46072L,46073L,46074L,46075L,46076L,46077L, -46078L,46079L,46080L,46081L,46082L,46083L,46084L,46085L,46086L,46087L, -46088L,46089L,46090L,46091L,46092L,46093L,46094L,46095L,46096L,46097L, -46098L,46099L,46100L,46101L,46102L,46103L,46104L,46105L,46106L,46107L, -46108L,46109L,46110L,46111L,46112L,46113L,46114L,46115L,46116L,46117L, -46118L,46119L,46120L,46121L,46122L,46123L,46124L,46125L,46126L,46127L, -46128L,46129L,46130L,46131L,46132L,46133L,46134L,46135L,46136L,46137L, -46138L,46139L,46140L,46141L,46142L,46143L,46144L,46145L,46146L,46147L, -46148L,46149L,46150L,46151L,46152L,46153L,46154L,46155L,46156L,46157L, -46158L,46159L,46160L,46161L,46162L,46163L,46164L,46165L,46166L,46167L, -46168L,46169L,46170L,46171L,46172L,46173L,46174L,46175L,46176L,46177L, -46178L,46179L,46180L,46181L,46182L,46183L,46184L,46185L,46186L,46187L, -46188L,46189L,46190L,46191L,46192L,46193L,46194L,46195L,46196L,46197L, -46198L,46199L,46200L,46201L,46202L,46203L,46204L,46205L,46206L,46207L, -46208L,46209L,46210L,46211L,46212L,46213L,46214L,46215L,46216L,46217L, -46218L,46219L,46220L,46221L,46222L,46223L,46224L,46225L,46226L,46227L, -46228L,46229L,46230L,46231L,46232L,46233L,46234L,46235L,46236L,46237L, -46238L,46239L,46240L,46241L,46242L,46243L,46244L,46245L,46246L,46247L, -46248L,46249L,46250L,46251L,46252L,46253L,46254L,46255L,46256L,46257L, -46258L,46259L,46260L,46261L,46262L,46263L,46264L,46265L,46266L,46267L, -46268L,46269L,46270L,46271L,46272L,46273L,46274L,46275L,46276L,46277L, -46278L,46279L,46280L,46281L,46282L,46283L,46284L,46285L,46286L,46287L, -46288L,46289L,46290L,46291L,46292L,46293L,46294L,46295L,46296L,46297L, -46298L,46299L,46300L,46301L,46302L,46303L,46304L,46305L,46306L,46307L, -46308L,46309L,46310L,46311L,46312L,46313L,46314L,46315L,46316L,46317L, -46318L,46319L,46320L,46321L,46322L,46323L,46324L,46325L,46326L,46327L, -46328L,46329L,46330L,46331L,46332L,46333L,46334L,46335L,46336L,46337L, -46338L,46339L,46340L,46341L,46342L,46343L,46344L,46345L,46346L,46347L, -46348L,46349L,46350L,46351L,46352L,46353L,46354L,46355L,46356L,46357L, -46358L,46359L,46360L,46361L,46362L,46363L,46364L,46365L,46366L,46367L, -46368L,46369L,46370L,46371L,46372L,46373L,46374L,46375L,46376L,46377L, -46378L,46379L,46380L,46381L,46382L,46383L,46384L,46385L,46386L,46387L, -46388L,46389L,46390L,46391L,46392L,46393L,46394L,46395L,46396L,46397L, -46398L,46399L,46400L,46401L,46402L,46403L,46404L,46405L,46406L,46407L, -46408L,46409L,46410L,46411L,46412L,46413L,46414L,46415L,46416L,46417L, -46418L,46419L,46420L,46421L,46422L,46423L,46424L,46425L,46426L,46427L, -46428L,46429L,46430L,46431L,46432L,46433L,46434L,46435L,46436L,46437L, -46438L,46439L,46440L,46441L,46442L,46443L,46444L,46445L,46446L,46447L, -46448L,46449L,46450L,46451L,46452L,46453L,46454L,46455L,46456L,46457L, -46458L,46459L,46460L,46461L,46462L,46463L,46464L,46465L,46466L,46467L, -46468L,46469L,46470L,46471L,46472L,46473L,46474L,46475L,46476L,46477L, -46478L,46479L,46480L,46481L,46482L,46483L,46484L,46485L,46486L,46487L, -46488L,46489L,46490L,46491L,46492L,46493L,46494L,46495L,46496L,46497L, -46498L,46499L,46500L,46501L,46502L,46503L,46504L,46505L,46506L,46507L, -46508L,46509L,46510L,46511L,46512L,46513L,46514L,46515L,46516L,46517L, -46518L,46519L,46520L,46521L,46522L,46523L,46524L,46525L,46526L,46527L, -46528L,46529L,46530L,46531L,46532L,46533L,46534L,46535L,46536L,46537L, -46538L,46539L,46540L,46541L,46542L,46543L,46544L,46545L,46546L,46547L, -46548L,46549L,46550L,46551L,46552L,46553L,46554L,46555L,46556L,46557L, -46558L,46559L,46560L,46561L,46562L,46563L,46564L,46565L,46566L,46567L, -46568L,46569L,46570L,46571L,46572L,46573L,46574L,46575L,46576L,46577L, -46578L,46579L,46580L,46581L,46582L,46583L,46584L,46585L,46586L,46587L, -46588L,46589L,46590L,46591L,46592L,46593L,46594L,46595L,46596L,46597L, -46598L,46599L,46600L,46601L,46602L,46603L,46604L,46605L,46606L,46607L, -46608L,46609L,46610L,46611L,46612L,46613L,46614L,46615L,46616L,46617L, -46618L,46619L,46620L,46621L,46622L,46623L,46624L,46625L,46626L,46627L, -46628L,46629L,46630L,46631L,46632L,46633L,46634L,46635L,46636L,46637L, -46638L,46639L,46640L,46641L,46642L,46643L,46644L,46645L,46646L,46647L, -46648L,46649L,46650L,46651L,46652L,46653L,46654L,46655L,46656L,46657L, -46658L,46659L,46660L,46661L,46662L,46663L,46664L,46665L,46666L,46667L, -46668L,46669L,46670L,46671L,46672L,46673L,46674L,46675L,46676L,46677L, -46678L,46679L,46680L,46681L,46682L,46683L,46684L,46685L,46686L,46687L, -46688L,46689L,46690L,46691L,46692L,46693L,46694L,46695L,46696L,46697L, -46698L,46699L,46700L,46701L,46702L,46703L,46704L,46705L,46706L,46707L, -46708L,46709L,46710L,46711L,46712L,46713L,46714L,46715L,46716L,46717L, -46718L,46719L,46720L,46721L,46722L,46723L,46724L,46725L,46726L,46727L, -46728L,46729L,46730L,46731L,46732L,46733L,46734L,46735L,46736L,46737L, -46738L,46739L,46740L,46741L,46742L,46743L,46744L,46745L,46746L,46747L, -46748L,46749L,46750L,46751L,46752L,46753L,46754L,46755L,46756L,46757L, -46758L,46759L,46760L,46761L,46762L,46763L,46764L,46765L,46766L,46767L, -46768L,46769L,46770L,46771L,46772L,46773L,46774L,46775L,46776L,46777L, -46778L,46779L,46780L,46781L,46782L,46783L,46784L,46785L,46786L,46787L, -46788L,46789L,46790L,46791L,46792L,46793L,46794L,46795L,46796L,46797L, -46798L,46799L,46800L,46801L,46802L,46803L,46804L,46805L,46806L,46807L, -46808L,46809L,46810L,46811L,46812L,46813L,46814L,46815L,46816L,46817L, -46818L,46819L,46820L,46821L,46822L,46823L,46824L,46825L,46826L,46827L, -46828L,46829L,46830L,46831L,46832L,46833L,46834L,46835L,46836L,46837L, -46838L,46839L,46840L,46841L,46842L,46843L,46844L,46845L,46846L,46847L, -46848L,46849L,46850L,46851L,46852L,46853L,46854L,46855L,46856L,46857L, -46858L,46859L,46860L,46861L,46862L,46863L,46864L,46865L,46866L,46867L, -46868L,46869L,46870L,46871L,46872L,46873L,46874L,46875L,46876L,46877L, -46878L,46879L,46880L,46881L,46882L,46883L,46884L,46885L,46886L,46887L, -46888L,46889L,46890L,46891L,46892L,46893L,46894L,46895L,46896L,46897L, -46898L,46899L,46900L,46901L,46902L,46903L,46904L,46905L,46906L,46907L, -46908L,46909L,46910L,46911L,46912L,46913L,46914L,46915L,46916L,46917L, -46918L,46919L,46920L,46921L,46922L,46923L,46924L,46925L,46926L,46927L, -46928L,46929L,46930L,46931L,46932L,46933L,46934L,46935L,46936L,46937L, -46938L,46939L,46940L,46941L,46942L,46943L,46944L,46945L,46946L,46947L, -46948L,46949L,46950L,46951L,46952L,46953L,46954L,46955L,46956L,46957L, -46958L,46959L,46960L,46961L,46962L,46963L,46964L,46965L,46966L,46967L, -46968L,46969L,46970L,46971L,46972L,46973L,46974L,46975L,46976L,46977L, -46978L,46979L,46980L,46981L,46982L,46983L,46984L,46985L,46986L,46987L, -46988L,46989L,46990L,46991L,46992L,46993L,46994L,46995L,46996L,46997L, -46998L,46999L,47000L,47001L,47002L,47003L,47004L,47005L,47006L,47007L, -47008L,47009L,47010L,47011L,47012L,47013L,47014L,47015L,47016L,47017L, -47018L,47019L,47020L,47021L,47022L,47023L,47024L,47025L,47026L,47027L, -47028L,47029L,47030L,47031L,47032L,47033L,47034L,47035L,47036L,47037L, -47038L,47039L,47040L,47041L,47042L,47043L,47044L,47045L,47046L,47047L, -47048L,47049L,47050L,47051L,47052L,47053L,47054L,47055L,47056L,47057L, -47058L,47059L,47060L,47061L,47062L,47063L,47064L,47065L,47066L,47067L, -47068L,47069L,47070L,47071L,47072L,47073L,47074L,47075L,47076L,47077L, -47078L,47079L,47080L,47081L,47082L,47083L,47084L,47085L,47086L,47087L, -47088L,47089L,47090L,47091L,47092L,47093L,47094L,47095L,47096L,47097L, -47098L,47099L,47100L,47101L,47102L,47103L,47104L,47105L,47106L,47107L, -47108L,47109L,47110L,47111L,47112L,47113L,47114L,47115L,47116L,47117L, -47118L,47119L,47120L,47121L,47122L,47123L,47124L,47125L,47126L,47127L, -47128L,47129L,47130L,47131L,47132L,47133L,47134L,47135L,47136L,47137L, -47138L,47139L,47140L,47141L,47142L,47143L,47144L,47145L,47146L,47147L, -47148L,47149L,47150L,47151L,47152L,47153L,47154L,47155L,47156L,47157L, -47158L,47159L,47160L,47161L,47162L,47163L,47164L,47165L,47166L,47167L, -47168L,47169L,47170L,47171L,47172L,47173L,47174L,47175L,47176L,47177L, -47178L,47179L,47180L,47181L,47182L,47183L,47184L,47185L,47186L,47187L, -47188L,47189L,47190L,47191L,47192L,47193L,47194L,47195L,47196L,47197L, -47198L,47199L,47200L,47201L,47202L,47203L,47204L,47205L,47206L,47207L, -47208L,47209L,47210L,47211L,47212L,47213L,47214L,47215L,47216L,47217L, -47218L,47219L,47220L,47221L,47222L,47223L,47224L,47225L,47226L,47227L, -47228L,47229L,47230L,47231L,47232L,47233L,47234L,47235L,47236L,47237L, -47238L,47239L,47240L,47241L,47242L,47243L,47244L,47245L,47246L,47247L, -47248L,47249L,47250L,47251L,47252L,47253L,47254L,47255L,47256L,47257L, -47258L,47259L,47260L,47261L,47262L,47263L,47264L,47265L,47266L,47267L, -47268L,47269L,47270L,47271L,47272L,47273L,47274L,47275L,47276L,47277L, -47278L,47279L,47280L,47281L,47282L,47283L,47284L,47285L,47286L,47287L, -47288L,47289L,47290L,47291L,47292L,47293L,47294L,47295L,47296L,47297L, -47298L,47299L,47300L,47301L,47302L,47303L,47304L,47305L,47306L,47307L, -47308L,47309L,47310L,47311L,47312L,47313L,47314L,47315L,47316L,47317L, -47318L,47319L,47320L,47321L,47322L,47323L,47324L,47325L,47326L,47327L, -47328L,47329L,47330L,47331L,47332L,47333L,47334L,47335L,47336L,47337L, -47338L,47339L,47340L,47341L,47342L,47343L,47344L,47345L,47346L,47347L, -47348L,47349L,47350L,47351L,47352L,47353L,47354L,47355L,47356L,47357L, -47358L,47359L,47360L,47361L,47362L,47363L,47364L,47365L,47366L,47367L, -47368L,47369L,47370L,47371L,47372L,47373L,47374L,47375L,47376L,47377L, -47378L,47379L,47380L,47381L,47382L,47383L,47384L,47385L,47386L,47387L, -47388L,47389L,47390L,47391L,47392L,47393L,47394L,47395L,47396L,47397L, -47398L,47399L,47400L,47401L,47402L,47403L,47404L,47405L,47406L,47407L, -47408L,47409L,47410L,47411L,47412L,47413L,47414L,47415L,47416L,47417L, -47418L,47419L,47420L,47421L,47422L,47423L,47424L,47425L,47426L,47427L, -47428L,47429L,47430L,47431L,47432L,47433L,47434L,47435L,47436L,47437L, -47438L,47439L,47440L,47441L,47442L,47443L,47444L,47445L,47446L,47447L, -47448L,47449L,47450L,47451L,47452L,47453L,47454L,47455L,47456L,47457L, -47458L,47459L,47460L,47461L,47462L,47463L,47464L,47465L,47466L,47467L, -47468L,47469L,47470L,47471L,47472L,47473L,47474L,47475L,47476L,47477L, -47478L,47479L,47480L,47481L,47482L,47483L,47484L,47485L,47486L,47487L, -47488L,47489L,47490L,47491L,47492L,47493L,47494L,47495L,47496L,47497L, -47498L,47499L,47500L,47501L,47502L,47503L,47504L,47505L,47506L,47507L, -47508L,47509L,47510L,47511L,47512L,47513L,47514L,47515L,47516L,47517L, -47518L,47519L,47520L,47521L,47522L,47523L,47524L,47525L,47526L,47527L, -47528L,47529L,47530L,47531L,47532L,47533L,47534L,47535L,47536L,47537L, -47538L,47539L,47540L,47541L,47542L,47543L,47544L,47545L,47546L,47547L, -47548L,47549L,47550L,47551L,47552L,47553L,47554L,47555L,47556L,47557L, -47558L,47559L,47560L,47561L,47562L,47563L,47564L,47565L,47566L,47567L, -47568L,47569L,47570L,47571L,47572L,47573L,47574L,47575L,47576L,47577L, -47578L,47579L,47580L,47581L,47582L,47583L,47584L,47585L,47586L,47587L, -47588L,47589L,47590L,47591L,47592L,47593L,47594L,47595L,47596L,47597L, -47598L,47599L,47600L,47601L,47602L,47603L,47604L,47605L,47606L,47607L, -47608L,47609L,47610L,47611L,47612L,47613L,47614L,47615L,47616L,47617L, -47618L,47619L,47620L,47621L,47622L,47623L,47624L,47625L,47626L,47627L, -47628L,47629L,47630L,47631L,47632L,47633L,47634L,47635L,47636L,47637L, -47638L,47639L,47640L,47641L,47642L,47643L,47644L,47645L,47646L,47647L, -47648L,47649L,47650L,47651L,47652L,47653L,47654L,47655L,47656L,47657L, -47658L,47659L,47660L,47661L,47662L,47663L,47664L,47665L,47666L,47667L, -47668L,47669L,47670L,47671L,47672L,47673L,47674L,47675L,47676L,47677L, -47678L,47679L,47680L,47681L,47682L,47683L,47684L,47685L,47686L,47687L, -47688L,47689L,47690L,47691L,47692L,47693L,47694L,47695L,47696L,47697L, -47698L,47699L,47700L,47701L,47702L,47703L,47704L,47705L,47706L,47707L, -47708L,47709L,47710L,47711L,47712L,47713L,47714L,47715L,47716L,47717L, -47718L,47719L,47720L,47721L,47722L,47723L,47724L,47725L,47726L,47727L, -47728L,47729L,47730L,47731L,47732L,47733L,47734L,47735L,47736L,47737L, -47738L,47739L,47740L,47741L,47742L,47743L,47744L,47745L,47746L,47747L, -47748L,47749L,47750L,47751L,47752L,47753L,47754L,47755L,47756L,47757L, -47758L,47759L,47760L,47761L,47762L,47763L,47764L,47765L,47766L,47767L, -47768L,47769L,47770L,47771L,47772L,47773L,47774L,47775L,47776L,47777L, -47778L,47779L,47780L,47781L,47782L,47783L,47784L,47785L,47786L,47787L, -47788L,47789L,47790L,47791L,47792L,47793L,47794L,47795L,47796L,47797L, -47798L,47799L,47800L,47801L,47802L,47803L,47804L,47805L,47806L,47807L, -47808L,47809L,47810L,47811L,47812L,47813L,47814L,47815L,47816L,47817L, -47818L,47819L,47820L,47821L,47822L,47823L,47824L,47825L,47826L,47827L, -47828L,47829L,47830L,47831L,47832L,47833L,47834L,47835L,47836L,47837L, -47838L,47839L,47840L,47841L,47842L,47843L,47844L,47845L,47846L,47847L, -47848L,47849L,47850L,47851L,47852L,47853L,47854L,47855L,47856L,47857L, -47858L,47859L,47860L,47861L,47862L,47863L,47864L,47865L,47866L,47867L, -47868L,47869L,47870L,47871L,47872L,47873L,47874L,47875L,47876L,47877L, -47878L,47879L,47880L,47881L,47882L,47883L,47884L,47885L,47886L,47887L, -47888L,47889L,47890L,47891L,47892L,47893L,47894L,47895L,47896L,47897L, -47898L,47899L,47900L,47901L,47902L,47903L,47904L,47905L,47906L,47907L, -47908L,47909L,47910L,47911L,47912L,47913L,47914L,47915L,47916L,47917L, -47918L,47919L,47920L,47921L,47922L,47923L,47924L,47925L,47926L,47927L, -47928L,47929L,47930L,47931L,47932L,47933L,47934L,47935L,47936L,47937L, -47938L,47939L,47940L,47941L,47942L,47943L,47944L,47945L,47946L,47947L, -47948L,47949L,47950L,47951L,47952L,47953L,47954L,47955L,47956L,47957L, -47958L,47959L,47960L,47961L,47962L,47963L,47964L,47965L,47966L,47967L, -47968L,47969L,47970L,47971L,47972L,47973L,47974L,47975L,47976L,47977L, -47978L,47979L,47980L,47981L,47982L,47983L,47984L,47985L,47986L,47987L, -47988L,47989L,47990L,47991L,47992L,47993L,47994L,47995L,47996L,47997L, -47998L,47999L,48000L,48001L,48002L,48003L,48004L,48005L,48006L,48007L, -48008L,48009L,48010L,48011L,48012L,48013L,48014L,48015L,48016L,48017L, -48018L,48019L,48020L,48021L,48022L,48023L,48024L,48025L,48026L,48027L, -48028L,48029L,48030L,48031L,48032L,48033L,48034L,48035L,48036L,48037L, -48038L,48039L,48040L,48041L,48042L,48043L,48044L,48045L,48046L,48047L, -48048L,48049L,48050L,48051L,48052L,48053L,48054L,48055L,48056L,48057L, -48058L,48059L,48060L,48061L,48062L,48063L,48064L,48065L,48066L,48067L, -48068L,48069L,48070L,48071L,48072L,48073L,48074L,48075L,48076L,48077L, -48078L,48079L,48080L,48081L,48082L,48083L,48084L,48085L,48086L,48087L, -48088L,48089L,48090L,48091L,48092L,48093L,48094L,48095L,48096L,48097L, -48098L,48099L,48100L,48101L,48102L,48103L,48104L,48105L,48106L,48107L, -48108L,48109L,48110L,48111L,48112L,48113L,48114L,48115L,48116L,48117L, -48118L,48119L,48120L,48121L,48122L,48123L,48124L,48125L,48126L,48127L, -48128L,48129L,48130L,48131L,48132L,48133L,48134L,48135L,48136L,48137L, -48138L,48139L,48140L,48141L,48142L,48143L,48144L,48145L,48146L,48147L, -48148L,48149L,48150L,48151L,48152L,48153L,48154L,48155L,48156L,48157L, -48158L,48159L,48160L,48161L,48162L,48163L,48164L,48165L,48166L,48167L, -48168L,48169L,48170L,48171L,48172L,48173L,48174L,48175L,48176L,48177L, -48178L,48179L,48180L,48181L,48182L,48183L,48184L,48185L,48186L,48187L, -48188L,48189L,48190L,48191L,48192L,48193L,48194L,48195L,48196L,48197L, -48198L,48199L,48200L,48201L,48202L,48203L,48204L,48205L,48206L,48207L, -48208L,48209L,48210L,48211L,48212L,48213L,48214L,48215L,48216L,48217L, -48218L,48219L,48220L,48221L,48222L,48223L,48224L,48225L,48226L,48227L, -48228L,48229L,48230L,48231L,48232L,48233L,48234L,48235L,48236L,48237L, -48238L,48239L,48240L,48241L,48242L,48243L,48244L,48245L,48246L,48247L, -48248L,48249L,48250L,48251L,48252L,48253L,48254L,48255L,48256L,48257L, -48258L,48259L,48260L,48261L,48262L,48263L,48264L,48265L,48266L,48267L, -48268L,48269L,48270L,48271L,48272L,48273L,48274L,48275L,48276L,48277L, -48278L,48279L,48280L,48281L,48282L,48283L,48284L,48285L,48286L,48287L, -48288L,48289L,48290L,48291L,48292L,48293L,48294L,48295L,48296L,48297L, -48298L,48299L,48300L,48301L,48302L,48303L,48304L,48305L,48306L,48307L, -48308L,48309L,48310L,48311L,48312L,48313L,48314L,48315L,48316L,48317L, -48318L,48319L,48320L,48321L,48322L,48323L,48324L,48325L,48326L,48327L, -48328L,48329L,48330L,48331L,48332L,48333L,48334L,48335L,48336L,48337L, -48338L,48339L,48340L,48341L,48342L,48343L,48344L,48345L,48346L,48347L, -48348L,48349L,48350L,48351L,48352L,48353L,48354L,48355L,48356L,48357L, -48358L,48359L,48360L,48361L,48362L,48363L,48364L,48365L,48366L,48367L, -48368L,48369L,48370L,48371L,48372L,48373L,48374L,48375L,48376L,48377L, -48378L,48379L,48380L,48381L,48382L,48383L,48384L,48385L,48386L,48387L, -48388L,48389L,48390L,48391L,48392L,48393L,48394L,48395L,48396L,48397L, -48398L,48399L,48400L,48401L,48402L,48403L,48404L,48405L,48406L,48407L, -48408L,48409L,48410L,48411L,48412L,48413L,48414L,48415L,48416L,48417L, -48418L,48419L,48420L,48421L,48422L,48423L,48424L,48425L,48426L,48427L, -48428L,48429L,48430L,48431L,48432L,48433L,48434L,48435L,48436L,48437L, -48438L,48439L,48440L,48441L,48442L,48443L,48444L,48445L,48446L,48447L, -48448L,48449L,48450L,48451L,48452L,48453L,48454L,48455L,48456L,48457L, -48458L,48459L,48460L,48461L,48462L,48463L,48464L,48465L,48466L,48467L, -48468L,48469L,48470L,48471L,48472L,48473L,48474L,48475L,48476L,48477L, -48478L,48479L,48480L,48481L,48482L,48483L,48484L,48485L,48486L,48487L, -48488L,48489L,48490L,48491L,48492L,48493L,48494L,48495L,48496L,48497L, -48498L,48499L,48500L,48501L,48502L,48503L,48504L,48505L,48506L,48507L, -48508L,48509L,48510L,48511L,48512L,48513L,48514L,48515L,48516L,48517L, -48518L,48519L,48520L,48521L,48522L,48523L,48524L,48525L,48526L,48527L, -48528L,48529L,48530L,48531L,48532L,48533L,48534L,48535L,48536L,48537L, -48538L,48539L,48540L,48541L,48542L,48543L,48544L,48545L,48546L,48547L, -48548L,48549L,48550L,48551L,48552L,48553L,48554L,48555L,48556L,48557L, -48558L,48559L,48560L,48561L,48562L,48563L,48564L,48565L,48566L,48567L, -48568L,48569L,48570L,48571L,48572L,48573L,48574L,48575L,48576L,48577L, -48578L,48579L,48580L,48581L,48582L,48583L,48584L,48585L,48586L,48587L, -48588L,48589L,48590L,48591L,48592L,48593L,48594L,48595L,48596L,48597L, -48598L,48599L,48600L,48601L,48602L,48603L,48604L,48605L,48606L,48607L, -48608L,48609L,48610L,48611L,48612L,48613L,48614L,48615L,48616L,48617L, -48618L,48619L,48620L,48621L,48622L,48623L,48624L,48625L,48626L,48627L, -48628L,48629L,48630L,48631L,48632L,48633L,48634L,48635L,48636L,48637L, -48638L,48639L,48640L,48641L,48642L,48643L,48644L,48645L,48646L,48647L, -48648L,48649L,48650L,48651L,48652L,48653L,48654L,48655L,48656L,48657L, -48658L,48659L,48660L,48661L,48662L,48663L,48664L,48665L,48666L,48667L, -48668L,48669L,48670L,48671L,48672L,48673L,48674L,48675L,48676L,48677L, -48678L,48679L,48680L,48681L,48682L,48683L,48684L,48685L,48686L,48687L, -48688L,48689L,48690L,48691L,48692L,48693L,48694L,48695L,48696L,48697L, -48698L,48699L,48700L,48701L,48702L,48703L,48704L,48705L,48706L,48707L, -48708L,48709L,48710L,48711L,48712L,48713L,48714L,48715L,48716L,48717L, -48718L,48719L,48720L,48721L,48722L,48723L,48724L,48725L,48726L,48727L, -48728L,48729L,48730L,48731L,48732L,48733L,48734L,48735L,48736L,48737L, -48738L,48739L,48740L,48741L,48742L,48743L,48744L,48745L,48746L,48747L, -48748L,48749L,48750L,48751L,48752L,48753L,48754L,48755L,48756L,48757L, -48758L,48759L,48760L,48761L,48762L,48763L,48764L,48765L,48766L,48767L, -48768L,48769L,48770L,48771L,48772L,48773L,48774L,48775L,48776L,48777L, -48778L,48779L,48780L,48781L,48782L,48783L,48784L,48785L,48786L,48787L, -48788L,48789L,48790L,48791L,48792L,48793L,48794L,48795L,48796L,48797L, -48798L,48799L,48800L,48801L,48802L,48803L,48804L,48805L,48806L,48807L, -48808L,48809L,48810L,48811L,48812L,48813L,48814L,48815L,48816L,48817L, -48818L,48819L,48820L,48821L,48822L,48823L,48824L,48825L,48826L,48827L, -48828L,48829L,48830L,48831L,48832L,48833L,48834L,48835L,48836L,48837L, -48838L,48839L,48840L,48841L,48842L,48843L,48844L,48845L,48846L,48847L, -48848L,48849L,48850L,48851L,48852L,48853L,48854L,48855L,48856L,48857L, -48858L,48859L,48860L,48861L,48862L,48863L,48864L,48865L,48866L,48867L, -48868L,48869L,48870L,48871L,48872L,48873L,48874L,48875L,48876L,48877L, -48878L,48879L,48880L,48881L,48882L,48883L,48884L,48885L,48886L,48887L, -48888L,48889L,48890L,48891L,48892L,48893L,48894L,48895L,48896L,48897L, -48898L,48899L,48900L,48901L,48902L,48903L,48904L,48905L,48906L,48907L, -48908L,48909L,48910L,48911L,48912L,48913L,48914L,48915L,48916L,48917L, -48918L,48919L,48920L,48921L,48922L,48923L,48924L,48925L,48926L,48927L, -48928L,48929L,48930L,48931L,48932L,48933L,48934L,48935L,48936L,48937L, -48938L,48939L,48940L,48941L,48942L,48943L,48944L,48945L,48946L,48947L, -48948L,48949L,48950L,48951L,48952L,48953L,48954L,48955L,48956L,48957L, -48958L,48959L,48960L,48961L,48962L,48963L,48964L,48965L,48966L,48967L, -48968L,48969L,48970L,48971L,48972L,48973L,48974L,48975L,48976L,48977L, -48978L,48979L,48980L,48981L,48982L,48983L,48984L,48985L,48986L,48987L, -48988L,48989L,48990L,48991L,48992L,48993L,48994L,48995L,48996L,48997L, -48998L,48999L,49000L,49001L,49002L,49003L,49004L,49005L,49006L,49007L, -49008L,49009L,49010L,49011L,49012L,49013L,49014L,49015L,49016L,49017L, -49018L,49019L,49020L,49021L,49022L,49023L,49024L,49025L,49026L,49027L, -49028L,49029L,49030L,49031L,49032L,49033L,49034L,49035L,49036L,49037L, -49038L,49039L,49040L,49041L,49042L,49043L,49044L,49045L,49046L,49047L, -49048L,49049L,49050L,49051L,49052L,49053L,49054L,49055L,49056L,49057L, -49058L,49059L,49060L,49061L,49062L,49063L,49064L,49065L,49066L,49067L, -49068L,49069L,49070L,49071L,49072L,49073L,49074L,49075L,49076L,49077L, -49078L,49079L,49080L,49081L,49082L,49083L,49084L,49085L,49086L,49087L, -49088L,49089L,49090L,49091L,49092L,49093L,49094L,49095L,49096L,49097L, -49098L,49099L,49100L,49101L,49102L,49103L,49104L,49105L,49106L,49107L, -49108L,49109L,49110L,49111L,49112L,49113L,49114L,49115L,49116L,49117L, -49118L,49119L,49120L,49121L,49122L,49123L,49124L,49125L,49126L,49127L, -49128L,49129L,49130L,49131L,49132L,49133L,49134L,49135L,49136L,49137L, -49138L,49139L,49140L,49141L,49142L,49143L,49144L,49145L,49146L,49147L, -49148L,49149L,49150L,49151L,49152L,49153L,49154L,49155L,49156L,49157L, -49158L,49159L,49160L,49161L,49162L,49163L,49164L,49165L,49166L,49167L, -49168L,49169L,49170L,49171L,49172L,49173L,49174L,49175L,49176L,49177L, -49178L,49179L,49180L,49181L,49182L,49183L,49184L,49185L,49186L,49187L, -49188L,49189L,49190L,49191L,49192L,49193L,49194L,49195L,49196L,49197L, -49198L,49199L,49200L,49201L,49202L,49203L,49204L,49205L,49206L,49207L, -49208L,49209L,49210L,49211L,49212L,49213L,49214L,49215L,49216L,49217L, -49218L,49219L,49220L,49221L,49222L,49223L,49224L,49225L,49226L,49227L, -49228L,49229L,49230L,49231L,49232L,49233L,49234L,49235L,49236L,49237L, -49238L,49239L,49240L,49241L,49242L,49243L,49244L,49245L,49246L,49247L, -49248L,49249L,49250L,49251L,49252L,49253L,49254L,49255L,49256L,49257L, -49258L,49259L,49260L,49261L,49262L,49263L,49264L,49265L,49266L,49267L, -49268L,49269L,49270L,49271L,49272L,49273L,49274L,49275L,49276L,49277L, -49278L,49279L,49280L,49281L,49282L,49283L,49284L,49285L,49286L,49287L, -49288L,49289L,49290L,49291L,49292L,49293L,49294L,49295L,49296L,49297L, -49298L,49299L,49300L,49301L,49302L,49303L,49304L,49305L,49306L,49307L, -49308L,49309L,49310L,49311L,49312L,49313L,49314L,49315L,49316L,49317L, -49318L,49319L,49320L,49321L,49322L,49323L,49324L,49325L,49326L,49327L, -49328L,49329L,49330L,49331L,49332L,49333L,49334L,49335L,49336L,49337L, -49338L,49339L,49340L,49341L,49342L,49343L,49344L,49345L,49346L,49347L, -49348L,49349L,49350L,49351L,49352L,49353L,49354L,49355L,49356L,49357L, -49358L,49359L,49360L,49361L,49362L,49363L,49364L,49365L,49366L,49367L, -49368L,49369L,49370L,49371L,49372L,49373L,49374L,49375L,49376L,49377L, -49378L,49379L,49380L,49381L,49382L,49383L,49384L,49385L,49386L,49387L, -49388L,49389L,49390L,49391L,49392L,49393L,49394L,49395L,49396L,49397L, -49398L,49399L,49400L,49401L,49402L,49403L,49404L,49405L,49406L,49407L, -49408L,49409L,49410L,49411L,49412L,49413L,49414L,49415L,49416L,49417L, -49418L,49419L,49420L,49421L,49422L,49423L,49424L,49425L,49426L,49427L, -49428L,49429L,49430L,49431L,49432L,49433L,49434L,49435L,49436L,49437L, -49438L,49439L,49440L,49441L,49442L,49443L,49444L,49445L,49446L,49447L, -49448L,49449L,49450L,49451L,49452L,49453L,49454L,49455L,49456L,49457L, -49458L,49459L,49460L,49461L,49462L,49463L,49464L,49465L,49466L,49467L, -49468L,49469L,49470L,49471L,49472L,49473L,49474L,49475L,49476L,49477L, -49478L,49479L,49480L,49481L,49482L,49483L,49484L,49485L,49486L,49487L, -49488L,49489L,49490L,49491L,49492L,49493L,49494L,49495L,49496L,49497L, -49498L,49499L,49500L,49501L,49502L,49503L,49504L,49505L,49506L,49507L, -49508L,49509L,49510L,49511L,49512L,49513L,49514L,49515L,49516L,49517L, -49518L,49519L,49520L,49521L,49522L,49523L,49524L,49525L,49526L,49527L, -49528L,49529L,49530L,49531L,49532L,49533L,49534L,49535L,49536L,49537L, -49538L,49539L,49540L,49541L,49542L,49543L,49544L,49545L,49546L,49547L, -49548L,49549L,49550L,49551L,49552L,49553L,49554L,49555L,49556L,49557L, -49558L,49559L,49560L,49561L,49562L,49563L,49564L,49565L,49566L,49567L, -49568L,49569L,49570L,49571L,49572L,49573L,49574L,49575L,49576L,49577L, -49578L,49579L,49580L,49581L,49582L,49583L,49584L,49585L,49586L,49587L, -49588L,49589L,49590L,49591L,49592L,49593L,49594L,49595L,49596L,49597L, -49598L,49599L,49600L,49601L,49602L,49603L,49604L,49605L,49606L,49607L, -49608L,49609L,49610L,49611L,49612L,49613L,49614L,49615L,49616L,49617L, -49618L,49619L,49620L,49621L,49622L,49623L,49624L,49625L,49626L,49627L, -49628L,49629L,49630L,49631L,49632L,49633L,49634L,49635L,49636L,49637L, -49638L,49639L,49640L,49641L,49642L,49643L,49644L,49645L,49646L,49647L, -49648L,49649L,49650L,49651L,49652L,49653L,49654L,49655L,49656L,49657L, -49658L,49659L,49660L,49661L,49662L,49663L,49664L,49665L,49666L,49667L, -49668L,49669L,49670L,49671L,49672L,49673L,49674L,49675L,49676L,49677L, -49678L,49679L,49680L,49681L,49682L,49683L,49684L,49685L,49686L,49687L, -49688L,49689L,49690L,49691L,49692L,49693L,49694L,49695L,49696L,49697L, -49698L,49699L,49700L,49701L,49702L,49703L,49704L,49705L,49706L,49707L, -49708L,49709L,49710L,49711L,49712L,49713L,49714L,49715L,49716L,49717L, -49718L,49719L,49720L,49721L,49722L,49723L,49724L,49725L,49726L,49727L, -49728L,49729L,49730L,49731L,49732L,49733L,49734L,49735L,49736L,49737L, -49738L,49739L,49740L,49741L,49742L,49743L,49744L,49745L,49746L,49747L, -49748L,49749L,49750L,49751L,49752L,49753L,49754L,49755L,49756L,49757L, -49758L,49759L,49760L,49761L,49762L,49763L,49764L,49765L,49766L,49767L, -49768L,49769L,49770L,49771L,49772L,49773L,49774L,49775L,49776L,49777L, -49778L,49779L,49780L,49781L,49782L,49783L,49784L,49785L,49786L,49787L, -49788L,49789L,49790L,49791L,49792L,49793L,49794L,49795L,49796L,49797L, -49798L,49799L,49800L,49801L,49802L,49803L,49804L,49805L,49806L,49807L, -49808L,49809L,49810L,49811L,49812L,49813L,49814L,49815L,49816L,49817L, -49818L,49819L,49820L,49821L,49822L,49823L,49824L,49825L,49826L,49827L, -49828L,49829L,49830L,49831L,49832L,49833L,49834L,49835L,49836L,49837L, -49838L,49839L,49840L,49841L,49842L,49843L,49844L,49845L,49846L,49847L, -49848L,49849L,49850L,49851L,49852L,49853L,49854L,49855L,49856L,49857L, -49858L,49859L,49860L,49861L,49862L,49863L,49864L,49865L,49866L,49867L, -49868L,49869L,49870L,49871L,49872L,49873L,49874L,49875L,49876L,49877L, -49878L,49879L,49880L,49881L,49882L,49883L,49884L,49885L,49886L,49887L, -49888L,49889L,49890L,49891L,49892L,49893L,49894L,49895L,49896L,49897L, -49898L,49899L,49900L,49901L,49902L,49903L,49904L,49905L,49906L,49907L, -49908L,49909L,49910L,49911L,49912L,49913L,49914L,49915L,49916L,49917L, -49918L,49919L,49920L,49921L,49922L,49923L,49924L,49925L,49926L,49927L, -49928L,49929L,49930L,49931L,49932L,49933L,49934L,49935L,49936L,49937L, -49938L,49939L,49940L,49941L,49942L,49943L,49944L,49945L,49946L,49947L, -49948L,49949L,49950L,49951L,49952L,49953L,49954L,49955L,49956L,49957L, -49958L,49959L,49960L,49961L,49962L,49963L,49964L,49965L,49966L,49967L, -49968L,49969L,49970L,49971L,49972L,49973L,49974L,49975L,49976L,49977L, -49978L,49979L,49980L,49981L,49982L,49983L,49984L,49985L,49986L,49987L, -49988L,49989L,49990L,49991L,49992L,49993L,49994L,49995L,49996L,49997L, -49998L,49999L,50000L,50001L,50002L,50003L,50004L,50005L,50006L,50007L, -50008L,50009L,50010L,50011L,50012L,50013L,50014L,50015L,50016L,50017L, -50018L,50019L,50020L,50021L,50022L,50023L,50024L,50025L,50026L,50027L, -50028L,50029L,50030L,50031L,50032L,50033L,50034L,50035L,50036L,50037L, -50038L,50039L,50040L,50041L,50042L,50043L,50044L,50045L,50046L,50047L, -50048L,50049L,50050L,50051L,50052L,50053L,50054L,50055L,50056L,50057L, -50058L,50059L,50060L,50061L,50062L,50063L,50064L,50065L,50066L,50067L, -50068L,50069L,50070L,50071L,50072L,50073L,50074L,50075L,50076L,50077L, -50078L,50079L,50080L,50081L,50082L,50083L,50084L,50085L,50086L,50087L, -50088L,50089L,50090L,50091L,50092L,50093L,50094L,50095L,50096L,50097L, -50098L,50099L,50100L,50101L,50102L,50103L,50104L,50105L,50106L,50107L, -50108L,50109L,50110L,50111L,50112L,50113L,50114L,50115L,50116L,50117L, -50118L,50119L,50120L,50121L,50122L,50123L,50124L,50125L,50126L,50127L, -50128L,50129L,50130L,50131L,50132L,50133L,50134L,50135L,50136L,50137L, -50138L,50139L,50140L,50141L,50142L,50143L,50144L,50145L,50146L,50147L, -50148L,50149L,50150L,50151L,50152L,50153L,50154L,50155L,50156L,50157L, -50158L,50159L,50160L,50161L,50162L,50163L,50164L,50165L,50166L,50167L, -50168L,50169L,50170L,50171L,50172L,50173L,50174L,50175L,50176L,50177L, -50178L,50179L,50180L,50181L,50182L,50183L,50184L,50185L,50186L,50187L, -50188L,50189L,50190L,50191L,50192L,50193L,50194L,50195L,50196L,50197L, -50198L,50199L,50200L,50201L,50202L,50203L,50204L,50205L,50206L,50207L, -50208L,50209L,50210L,50211L,50212L,50213L,50214L,50215L,50216L,50217L, -50218L,50219L,50220L,50221L,50222L,50223L,50224L,50225L,50226L,50227L, -50228L,50229L,50230L,50231L,50232L,50233L,50234L,50235L,50236L,50237L, -50238L,50239L,50240L,50241L,50242L,50243L,50244L,50245L,50246L,50247L, -50248L,50249L,50250L,50251L,50252L,50253L,50254L,50255L,50256L,50257L, -50258L,50259L,50260L,50261L,50262L,50263L,50264L,50265L,50266L,50267L, -50268L,50269L,50270L,50271L,50272L,50273L,50274L,50275L,50276L,50277L, -50278L,50279L,50280L,50281L,50282L,50283L,50284L,50285L,50286L,50287L, -50288L,50289L,50290L,50291L,50292L,50293L,50294L,50295L,50296L,50297L, -50298L,50299L,50300L,50301L,50302L,50303L,50304L,50305L,50306L,50307L, -50308L,50309L,50310L,50311L,50312L,50313L,50314L,50315L,50316L,50317L, -50318L,50319L,50320L,50321L,50322L,50323L,50324L,50325L,50326L,50327L, -50328L,50329L,50330L,50331L,50332L,50333L,50334L,50335L,50336L,50337L, -50338L,50339L,50340L,50341L,50342L,50343L,50344L,50345L,50346L,50347L, -50348L,50349L,50350L,50351L,50352L,50353L,50354L,50355L,50356L,50357L, -50358L,50359L,50360L,50361L,50362L,50363L,50364L,50365L,50366L,50367L, -50368L,50369L,50370L,50371L,50372L,50373L,50374L,50375L,50376L,50377L, -50378L,50379L,50380L,50381L,50382L,50383L,50384L,50385L,50386L,50387L, -50388L,50389L,50390L,50391L,50392L,50393L,50394L,50395L,50396L,50397L, -50398L,50399L,50400L,50401L,50402L,50403L,50404L,50405L,50406L,50407L, -50408L,50409L,50410L,50411L,50412L,50413L,50414L,50415L,50416L,50417L, -50418L,50419L,50420L,50421L,50422L,50423L,50424L,50425L,50426L,50427L, -50428L,50429L,50430L,50431L,50432L,50433L,50434L,50435L,50436L,50437L, -50438L,50439L,50440L,50441L,50442L,50443L,50444L,50445L,50446L,50447L, -50448L,50449L,50450L,50451L,50452L,50453L,50454L,50455L,50456L,50457L, -50458L,50459L,50460L,50461L,50462L,50463L,50464L,50465L,50466L,50467L, -50468L,50469L,50470L,50471L,50472L,50473L,50474L,50475L,50476L,50477L, -50478L,50479L,50480L,50481L,50482L,50483L,50484L,50485L,50486L,50487L, -50488L,50489L,50490L,50491L,50492L,50493L,50494L,50495L,50496L,50497L, -50498L,50499L,50500L,50501L,50502L,50503L,50504L,50505L,50506L,50507L, -50508L,50509L,50510L,50511L,50512L,50513L,50514L,50515L,50516L,50517L, -50518L,50519L,50520L,50521L,50522L,50523L,50524L,50525L,50526L,50527L, -50528L,50529L,50530L,50531L,50532L,50533L,50534L,50535L,50536L,50537L, -50538L,50539L,50540L,50541L,50542L,50543L,50544L,50545L,50546L,50547L, -50548L,50549L,50550L,50551L,50552L,50553L,50554L,50555L,50556L,50557L, -50558L,50559L,50560L,50561L,50562L,50563L,50564L,50565L,50566L,50567L, -50568L,50569L,50570L,50571L,50572L,50573L,50574L,50575L,50576L,50577L, -50578L,50579L,50580L,50581L,50582L,50583L,50584L,50585L,50586L,50587L, -50588L,50589L,50590L,50591L,50592L,50593L,50594L,50595L,50596L,50597L, -50598L,50599L,50600L,50601L,50602L,50603L,50604L,50605L,50606L,50607L, -50608L,50609L,50610L,50611L,50612L,50613L,50614L,50615L,50616L,50617L, -50618L,50619L,50620L,50621L,50622L,50623L,50624L,50625L,50626L,50627L, -50628L,50629L,50630L,50631L,50632L,50633L,50634L,50635L,50636L,50637L, -50638L,50639L,50640L,50641L,50642L,50643L,50644L,50645L,50646L,50647L, -50648L,50649L,50650L,50651L,50652L,50653L,50654L,50655L,50656L,50657L, -50658L,50659L,50660L,50661L,50662L,50663L,50664L,50665L,50666L,50667L, -50668L,50669L,50670L,50671L,50672L,50673L,50674L,50675L,50676L,50677L, -50678L,50679L,50680L,50681L,50682L,50683L,50684L,50685L,50686L,50687L, -50688L,50689L,50690L,50691L,50692L,50693L,50694L,50695L,50696L,50697L, -50698L,50699L,50700L,50701L,50702L,50703L,50704L,50705L,50706L,50707L, -50708L,50709L,50710L,50711L,50712L,50713L,50714L,50715L,50716L,50717L, -50718L,50719L,50720L,50721L,50722L,50723L,50724L,50725L,50726L,50727L, -50728L,50729L,50730L,50731L,50732L,50733L,50734L,50735L,50736L,50737L, -50738L,50739L,50740L,50741L,50742L,50743L,50744L,50745L,50746L,50747L, -50748L,50749L,50750L,50751L,50752L,50753L,50754L,50755L,50756L,50757L, -50758L,50759L,50760L,50761L,50762L,50763L,50764L,50765L,50766L,50767L, -50768L,50769L,50770L,50771L,50772L,50773L,50774L,50775L,50776L,50777L, -50778L,50779L,50780L,50781L,50782L,50783L,50784L,50785L,50786L,50787L, -50788L,50789L,50790L,50791L,50792L,50793L,50794L,50795L,50796L,50797L, -50798L,50799L,50800L,50801L,50802L,50803L,50804L,50805L,50806L,50807L, -50808L,50809L,50810L,50811L,50812L,50813L,50814L,50815L,50816L,50817L, -50818L,50819L,50820L,50821L,50822L,50823L,50824L,50825L,50826L,50827L, -50828L,50829L,50830L,50831L,50832L,50833L,50834L,50835L,50836L,50837L, -50838L,50839L,50840L,50841L,50842L,50843L,50844L,50845L,50846L,50847L, -50848L,50849L,50850L,50851L,50852L,50853L,50854L,50855L,50856L,50857L, -50858L,50859L,50860L,50861L,50862L,50863L,50864L,50865L,50866L,50867L, -50868L,50869L,50870L,50871L,50872L,50873L,50874L,50875L,50876L,50877L, -50878L,50879L,50880L,50881L,50882L,50883L,50884L,50885L,50886L,50887L, -50888L,50889L,50890L,50891L,50892L,50893L,50894L,50895L,50896L,50897L, -50898L,50899L,50900L,50901L,50902L,50903L,50904L,50905L,50906L,50907L, -50908L,50909L,50910L,50911L,50912L,50913L,50914L,50915L,50916L,50917L, -50918L,50919L,50920L,50921L,50922L,50923L,50924L,50925L,50926L,50927L, -50928L,50929L,50930L,50931L,50932L,50933L,50934L,50935L,50936L,50937L, -50938L,50939L,50940L,50941L,50942L,50943L,50944L,50945L,50946L,50947L, -50948L,50949L,50950L,50951L,50952L,50953L,50954L,50955L,50956L,50957L, -50958L,50959L,50960L,50961L,50962L,50963L,50964L,50965L,50966L,50967L, -50968L,50969L,50970L,50971L,50972L,50973L,50974L,50975L,50976L,50977L, -50978L,50979L,50980L,50981L,50982L,50983L,50984L,50985L,50986L,50987L, -50988L,50989L,50990L,50991L,50992L,50993L,50994L,50995L,50996L,50997L, -50998L,50999L,51000L,51001L,51002L,51003L,51004L,51005L,51006L,51007L, -51008L,51009L,51010L,51011L,51012L,51013L,51014L,51015L,51016L,51017L, -51018L,51019L,51020L,51021L,51022L,51023L,51024L,51025L,51026L,51027L, -51028L,51029L,51030L,51031L,51032L,51033L,51034L,51035L,51036L,51037L, -51038L,51039L,51040L,51041L,51042L,51043L,51044L,51045L,51046L,51047L, -51048L,51049L,51050L,51051L,51052L,51053L,51054L,51055L,51056L,51057L, -51058L,51059L,51060L,51061L,51062L,51063L,51064L,51065L,51066L,51067L, -51068L,51069L,51070L,51071L,51072L,51073L,51074L,51075L,51076L,51077L, -51078L,51079L,51080L,51081L,51082L,51083L,51084L,51085L,51086L,51087L, -51088L,51089L,51090L,51091L,51092L,51093L,51094L,51095L,51096L,51097L, -51098L,51099L,51100L,51101L,51102L,51103L,51104L,51105L,51106L,51107L, -51108L,51109L,51110L,51111L,51112L,51113L,51114L,51115L,51116L,51117L, -51118L,51119L,51120L,51121L,51122L,51123L,51124L,51125L,51126L,51127L, -51128L,51129L,51130L,51131L,51132L,51133L,51134L,51135L,51136L,51137L, -51138L,51139L,51140L,51141L,51142L,51143L,51144L,51145L,51146L,51147L, -51148L,51149L,51150L,51151L,51152L,51153L,51154L,51155L,51156L,51157L, -51158L,51159L,51160L,51161L,51162L,51163L,51164L,51165L,51166L,51167L, -51168L,51169L,51170L,51171L,51172L,51173L,51174L,51175L,51176L,51177L, -51178L,51179L,51180L,51181L,51182L,51183L,51184L,51185L,51186L,51187L, -51188L,51189L,51190L,51191L,51192L,51193L,51194L,51195L,51196L,51197L, -51198L,51199L,51200L,51201L,51202L,51203L,51204L,51205L,51206L,51207L, -51208L,51209L,51210L,51211L,51212L,51213L,51214L,51215L,51216L,51217L, -51218L,51219L,51220L,51221L,51222L,51223L,51224L,51225L,51226L,51227L, -51228L,51229L,51230L,51231L,51232L,51233L,51234L,51235L,51236L,51237L, -51238L,51239L,51240L,51241L,51242L,51243L,51244L,51245L,51246L,51247L, -51248L,51249L,51250L,51251L,51252L,51253L,51254L,51255L,51256L,51257L, -51258L,51259L,51260L,51261L,51262L,51263L,51264L,51265L,51266L,51267L, -51268L,51269L,51270L,51271L,51272L,51273L,51274L,51275L,51276L,51277L, -51278L,51279L,51280L,51281L,51282L,51283L,51284L,51285L,51286L,51287L, -51288L,51289L,51290L,51291L,51292L,51293L,51294L,51295L,51296L,51297L, -51298L,51299L,51300L,51301L,51302L,51303L,51304L,51305L,51306L,51307L, -51308L,51309L,51310L,51311L,51312L,51313L,51314L,51315L,51316L,51317L, -51318L,51319L,51320L,51321L,51322L,51323L,51324L,51325L,51326L,51327L, -51328L,51329L,51330L,51331L,51332L,51333L,51334L,51335L,51336L,51337L, -51338L,51339L,51340L,51341L,51342L,51343L,51344L,51345L,51346L,51347L, -51348L,51349L,51350L,51351L,51352L,51353L,51354L,51355L,51356L,51357L, -51358L,51359L,51360L,51361L,51362L,51363L,51364L,51365L,51366L,51367L, -51368L,51369L,51370L,51371L,51372L,51373L,51374L,51375L,51376L,51377L, -51378L,51379L,51380L,51381L,51382L,51383L,51384L,51385L,51386L,51387L, -51388L,51389L,51390L,51391L,51392L,51393L,51394L,51395L,51396L,51397L, -51398L,51399L,51400L,51401L,51402L,51403L,51404L,51405L,51406L,51407L, -51408L,51409L,51410L,51411L,51412L,51413L,51414L,51415L,51416L,51417L, -51418L,51419L,51420L,51421L,51422L,51423L,51424L,51425L,51426L,51427L, -51428L,51429L,51430L,51431L,51432L,51433L,51434L,51435L,51436L,51437L, -51438L,51439L,51440L,51441L,51442L,51443L,51444L,51445L,51446L,51447L, -51448L,51449L,51450L,51451L,51452L,51453L,51454L,51455L,51456L,51457L, -51458L,51459L,51460L,51461L,51462L,51463L,51464L,51465L,51466L,51467L, -51468L,51469L,51470L,51471L,51472L,51473L,51474L,51475L,51476L,51477L, -51478L,51479L,51480L,51481L,51482L,51483L,51484L,51485L,51486L,51487L, -51488L,51489L,51490L,51491L,51492L,51493L,51494L,51495L,51496L,51497L, -51498L,51499L,51500L,51501L,51502L,51503L,51504L,51505L,51506L,51507L, -51508L,51509L,51510L,51511L,51512L,51513L,51514L,51515L,51516L,51517L, -51518L,51519L,51520L,51521L,51522L,51523L,51524L,51525L,51526L,51527L, -51528L,51529L,51530L,51531L,51532L,51533L,51534L,51535L,51536L,51537L, -51538L,51539L,51540L,51541L,51542L,51543L,51544L,51545L,51546L,51547L, -51548L,51549L,51550L,51551L,51552L,51553L,51554L,51555L,51556L,51557L, -51558L,51559L,51560L,51561L,51562L,51563L,51564L,51565L,51566L,51567L, -51568L,51569L,51570L,51571L,51572L,51573L,51574L,51575L,51576L,51577L, -51578L,51579L,51580L,51581L,51582L,51583L,51584L,51585L,51586L,51587L, -51588L,51589L,51590L,51591L,51592L,51593L,51594L,51595L,51596L,51597L, -51598L,51599L,51600L,51601L,51602L,51603L,51604L,51605L,51606L,51607L, -51608L,51609L,51610L,51611L,51612L,51613L,51614L,51615L,51616L,51617L, -51618L,51619L,51620L,51621L,51622L,51623L,51624L,51625L,51626L,51627L, -51628L,51629L,51630L,51631L,51632L,51633L,51634L,51635L,51636L,51637L, -51638L,51639L,51640L,51641L,51642L,51643L,51644L,51645L,51646L,51647L, -51648L,51649L,51650L,51651L,51652L,51653L,51654L,51655L,51656L,51657L, -51658L,51659L,51660L,51661L,51662L,51663L,51664L,51665L,51666L,51667L, -51668L,51669L,51670L,51671L,51672L,51673L,51674L,51675L,51676L,51677L, -51678L,51679L,51680L,51681L,51682L,51683L,51684L,51685L,51686L,51687L, -51688L,51689L,51690L,51691L,51692L,51693L,51694L,51695L,51696L,51697L, -51698L,51699L,51700L,51701L,51702L,51703L,51704L,51705L,51706L,51707L, -51708L,51709L,51710L,51711L,51712L,51713L,51714L,51715L,51716L,51717L, -51718L,51719L,51720L,51721L,51722L,51723L,51724L,51725L,51726L,51727L, -51728L,51729L,51730L,51731L,51732L,51733L,51734L,51735L,51736L,51737L, -51738L,51739L,51740L,51741L,51742L,51743L,51744L,51745L,51746L,51747L, -51748L,51749L,51750L,51751L,51752L,51753L,51754L,51755L,51756L,51757L, -51758L,51759L,51760L,51761L,51762L,51763L,51764L,51765L,51766L,51767L, -51768L,51769L,51770L,51771L,51772L,51773L,51774L,51775L,51776L,51777L, -51778L,51779L,51780L,51781L,51782L,51783L,51784L,51785L,51786L,51787L, -51788L,51789L,51790L,51791L,51792L,51793L,51794L,51795L,51796L,51797L, -51798L,51799L,51800L,51801L,51802L,51803L,51804L,51805L,51806L,51807L, -51808L,51809L,51810L,51811L,51812L,51813L,51814L,51815L,51816L,51817L, -51818L,51819L,51820L,51821L,51822L,51823L,51824L,51825L,51826L,51827L, -51828L,51829L,51830L,51831L,51832L,51833L,51834L,51835L,51836L,51837L, -51838L,51839L,51840L,51841L,51842L,51843L,51844L,51845L,51846L,51847L, -51848L,51849L,51850L,51851L,51852L,51853L,51854L,51855L,51856L,51857L, -51858L,51859L,51860L,51861L,51862L,51863L,51864L,51865L,51866L,51867L, -51868L,51869L,51870L,51871L,51872L,51873L,51874L,51875L,51876L,51877L, -51878L,51879L,51880L,51881L,51882L,51883L,51884L,51885L,51886L,51887L, -51888L,51889L,51890L,51891L,51892L,51893L,51894L,51895L,51896L,51897L, -51898L,51899L,51900L,51901L,51902L,51903L,51904L,51905L,51906L,51907L, -51908L,51909L,51910L,51911L,51912L,51913L,51914L,51915L,51916L,51917L, -51918L,51919L,51920L,51921L,51922L,51923L,51924L,51925L,51926L,51927L, -51928L,51929L,51930L,51931L,51932L,51933L,51934L,51935L,51936L,51937L, -51938L,51939L,51940L,51941L,51942L,51943L,51944L,51945L,51946L,51947L, -51948L,51949L,51950L,51951L,51952L,51953L,51954L,51955L,51956L,51957L, -51958L,51959L,51960L,51961L,51962L,51963L,51964L,51965L,51966L,51967L, -51968L,51969L,51970L,51971L,51972L,51973L,51974L,51975L,51976L,51977L, -51978L,51979L,51980L,51981L,51982L,51983L,51984L,51985L,51986L,51987L, -51988L,51989L,51990L,51991L,51992L,51993L,51994L,51995L,51996L,51997L, -51998L,51999L,52000L,52001L,52002L,52003L,52004L,52005L,52006L,52007L, -52008L,52009L,52010L,52011L,52012L,52013L,52014L,52015L,52016L,52017L, -52018L,52019L,52020L,52021L,52022L,52023L,52024L,52025L,52026L,52027L, -52028L,52029L,52030L,52031L,52032L,52033L,52034L,52035L,52036L,52037L, -52038L,52039L,52040L,52041L,52042L,52043L,52044L,52045L,52046L,52047L, -52048L,52049L,52050L,52051L,52052L,52053L,52054L,52055L,52056L,52057L, -52058L,52059L,52060L,52061L,52062L,52063L,52064L,52065L,52066L,52067L, -52068L,52069L,52070L,52071L,52072L,52073L,52074L,52075L,52076L,52077L, -52078L,52079L,52080L,52081L,52082L,52083L,52084L,52085L,52086L,52087L, -52088L,52089L,52090L,52091L,52092L,52093L,52094L,52095L,52096L,52097L, -52098L,52099L,52100L,52101L,52102L,52103L,52104L,52105L,52106L,52107L, -52108L,52109L,52110L,52111L,52112L,52113L,52114L,52115L,52116L,52117L, -52118L,52119L,52120L,52121L,52122L,52123L,52124L,52125L,52126L,52127L, -52128L,52129L,52130L,52131L,52132L,52133L,52134L,52135L,52136L,52137L, -52138L,52139L,52140L,52141L,52142L,52143L,52144L,52145L,52146L,52147L, -52148L,52149L,52150L,52151L,52152L,52153L,52154L,52155L,52156L,52157L, -52158L,52159L,52160L,52161L,52162L,52163L,52164L,52165L,52166L,52167L, -52168L,52169L,52170L,52171L,52172L,52173L,52174L,52175L,52176L,52177L, -52178L,52179L,52180L,52181L,52182L,52183L,52184L,52185L,52186L,52187L, -52188L,52189L,52190L,52191L,52192L,52193L,52194L,52195L,52196L,52197L, -52198L,52199L,52200L,52201L,52202L,52203L,52204L,52205L,52206L,52207L, -52208L,52209L,52210L,52211L,52212L,52213L,52214L,52215L,52216L,52217L, -52218L,52219L,52220L,52221L,52222L,52223L,52224L,52225L,52226L,52227L, -52228L,52229L,52230L,52231L,52232L,52233L,52234L,52235L,52236L,52237L, -52238L,52239L,52240L,52241L,52242L,52243L,52244L,52245L,52246L,52247L, -52248L,52249L,52250L,52251L,52252L,52253L,52254L,52255L,52256L,52257L, -52258L,52259L,52260L,52261L,52262L,52263L,52264L,52265L,52266L,52267L, -52268L,52269L,52270L,52271L,52272L,52273L,52274L,52275L,52276L,52277L, -52278L,52279L,52280L,52281L,52282L,52283L,52284L,52285L,52286L,52287L, -52288L,52289L,52290L,52291L,52292L,52293L,52294L,52295L,52296L,52297L, -52298L,52299L,52300L,52301L,52302L,52303L,52304L,52305L,52306L,52307L, -52308L,52309L,52310L,52311L,52312L,52313L,52314L,52315L,52316L,52317L, -52318L,52319L,52320L,52321L,52322L,52323L,52324L,52325L,52326L,52327L, -52328L,52329L,52330L,52331L,52332L,52333L,52334L,52335L,52336L,52337L, -52338L,52339L,52340L,52341L,52342L,52343L,52344L,52345L,52346L,52347L, -52348L,52349L,52350L,52351L,52352L,52353L,52354L,52355L,52356L,52357L, -52358L,52359L,52360L,52361L,52362L,52363L,52364L,52365L,52366L,52367L, -52368L,52369L,52370L,52371L,52372L,52373L,52374L,52375L,52376L,52377L, -52378L,52379L,52380L,52381L,52382L,52383L,52384L,52385L,52386L,52387L, -52388L,52389L,52390L,52391L,52392L,52393L,52394L,52395L,52396L,52397L, -52398L,52399L,52400L,52401L,52402L,52403L,52404L,52405L,52406L,52407L, -52408L,52409L,52410L,52411L,52412L,52413L,52414L,52415L,52416L,52417L, -52418L,52419L,52420L,52421L,52422L,52423L,52424L,52425L,52426L,52427L, -52428L,52429L,52430L,52431L,52432L,52433L,52434L,52435L,52436L,52437L, -52438L,52439L,52440L,52441L,52442L,52443L,52444L,52445L,52446L,52447L, -52448L,52449L,52450L,52451L,52452L,52453L,52454L,52455L,52456L,52457L, -52458L,52459L,52460L,52461L,52462L,52463L,52464L,52465L,52466L,52467L, -52468L,52469L,52470L,52471L,52472L,52473L,52474L,52475L,52476L,52477L, -52478L,52479L,52480L,52481L,52482L,52483L,52484L,52485L,52486L,52487L, -52488L,52489L,52490L,52491L,52492L,52493L,52494L,52495L,52496L,52497L, -52498L,52499L,52500L,52501L,52502L,52503L,52504L,52505L,52506L,52507L, -52508L,52509L,52510L,52511L,52512L,52513L,52514L,52515L,52516L,52517L, -52518L,52519L,52520L,52521L,52522L,52523L,52524L,52525L,52526L,52527L, -52528L,52529L,52530L,52531L,52532L,52533L,52534L,52535L,52536L,52537L, -52538L,52539L,52540L,52541L,52542L,52543L,52544L,52545L,52546L,52547L, -52548L,52549L,52550L,52551L,52552L,52553L,52554L,52555L,52556L,52557L, -52558L,52559L,52560L,52561L,52562L,52563L,52564L,52565L,52566L,52567L, -52568L,52569L,52570L,52571L,52572L,52573L,52574L,52575L,52576L,52577L, -52578L,52579L,52580L,52581L,52582L,52583L,52584L,52585L,52586L,52587L, -52588L,52589L,52590L,52591L,52592L,52593L,52594L,52595L,52596L,52597L, -52598L,52599L,52600L,52601L,52602L,52603L,52604L,52605L,52606L,52607L, -52608L,52609L,52610L,52611L,52612L,52613L,52614L,52615L,52616L,52617L, -52618L,52619L,52620L,52621L,52622L,52623L,52624L,52625L,52626L,52627L, -52628L,52629L,52630L,52631L,52632L,52633L,52634L,52635L,52636L,52637L, -52638L,52639L,52640L,52641L,52642L,52643L,52644L,52645L,52646L,52647L, -52648L,52649L,52650L,52651L,52652L,52653L,52654L,52655L,52656L,52657L, -52658L,52659L,52660L,52661L,52662L,52663L,52664L,52665L,52666L,52667L, -52668L,52669L,52670L,52671L,52672L,52673L,52674L,52675L,52676L,52677L, -52678L,52679L,52680L,52681L,52682L,52683L,52684L,52685L,52686L,52687L, -52688L,52689L,52690L,52691L,52692L,52693L,52694L,52695L,52696L,52697L, -52698L,52699L,52700L,52701L,52702L,52703L,52704L,52705L,52706L,52707L, -52708L,52709L,52710L,52711L,52712L,52713L,52714L,52715L,52716L,52717L, -52718L,52719L,52720L,52721L,52722L,52723L,52724L,52725L,52726L,52727L, -52728L,52729L,52730L,52731L,52732L,52733L,52734L,52735L,52736L,52737L, -52738L,52739L,52740L,52741L,52742L,52743L,52744L,52745L,52746L,52747L, -52748L,52749L,52750L,52751L,52752L,52753L,52754L,52755L,52756L,52757L, -52758L,52759L,52760L,52761L,52762L,52763L,52764L,52765L,52766L,52767L, -52768L,52769L,52770L,52771L,52772L,52773L,52774L,52775L,52776L,52777L, -52778L,52779L,52780L,52781L,52782L,52783L,52784L,52785L,52786L,52787L, -52788L,52789L,52790L,52791L,52792L,52793L,52794L,52795L,52796L,52797L, -52798L,52799L,52800L,52801L,52802L,52803L,52804L,52805L,52806L,52807L, -52808L,52809L,52810L,52811L,52812L,52813L,52814L,52815L,52816L,52817L, -52818L,52819L,52820L,52821L,52822L,52823L,52824L,52825L,52826L,52827L, -52828L,52829L,52830L,52831L,52832L,52833L,52834L,52835L,52836L,52837L, -52838L,52839L,52840L,52841L,52842L,52843L,52844L,52845L,52846L,52847L, -52848L,52849L,52850L,52851L,52852L,52853L,52854L,52855L,52856L,52857L, -52858L,52859L,52860L,52861L,52862L,52863L,52864L,52865L,52866L,52867L, -52868L,52869L,52870L,52871L,52872L,52873L,52874L,52875L,52876L,52877L, -52878L,52879L,52880L,52881L,52882L,52883L,52884L,52885L,52886L,52887L, -52888L,52889L,52890L,52891L,52892L,52893L,52894L,52895L,52896L,52897L, -52898L,52899L,52900L,52901L,52902L,52903L,52904L,52905L,52906L,52907L, -52908L,52909L,52910L,52911L,52912L,52913L,52914L,52915L,52916L,52917L, -52918L,52919L,52920L,52921L,52922L,52923L,52924L,52925L,52926L,52927L, -52928L,52929L,52930L,52931L,52932L,52933L,52934L,52935L,52936L,52937L, -52938L,52939L,52940L,52941L,52942L,52943L,52944L,52945L,52946L,52947L, -52948L,52949L,52950L,52951L,52952L,52953L,52954L,52955L,52956L,52957L, -52958L,52959L,52960L,52961L,52962L,52963L,52964L,52965L,52966L,52967L, -52968L,52969L,52970L,52971L,52972L,52973L,52974L,52975L,52976L,52977L, -52978L,52979L,52980L,52981L,52982L,52983L,52984L,52985L,52986L,52987L, -52988L,52989L,52990L,52991L,52992L,52993L,52994L,52995L,52996L,52997L, -52998L,52999L,53000L,53001L,53002L,53003L,53004L,53005L,53006L,53007L, -53008L,53009L,53010L,53011L,53012L,53013L,53014L,53015L,53016L,53017L, -53018L,53019L,53020L,53021L,53022L,53023L,53024L,53025L,53026L,53027L, -53028L,53029L,53030L,53031L,53032L,53033L,53034L,53035L,53036L,53037L, -53038L,53039L,53040L,53041L,53042L,53043L,53044L,53045L,53046L,53047L, -53048L,53049L,53050L,53051L,53052L,53053L,53054L,53055L,53056L,53057L, -53058L,53059L,53060L,53061L,53062L,53063L,53064L,53065L,53066L,53067L, -53068L,53069L,53070L,53071L,53072L,53073L,53074L,53075L,53076L,53077L, -53078L,53079L,53080L,53081L,53082L,53083L,53084L,53085L,53086L,53087L, -53088L,53089L,53090L,53091L,53092L,53093L,53094L,53095L,53096L,53097L, -53098L,53099L,53100L,53101L,53102L,53103L,53104L,53105L,53106L,53107L, -53108L,53109L,53110L,53111L,53112L,53113L,53114L,53115L,53116L,53117L, -53118L,53119L,53120L,53121L,53122L,53123L,53124L,53125L,53126L,53127L, -53128L,53129L,53130L,53131L,53132L,53133L,53134L,53135L,53136L,53137L, -53138L,53139L,53140L,53141L,53142L,53143L,53144L,53145L,53146L,53147L, -53148L,53149L,53150L,53151L,53152L,53153L,53154L,53155L,53156L,53157L, -53158L,53159L,53160L,53161L,53162L,53163L,53164L,53165L,53166L,53167L, -53168L,53169L,53170L,53171L,53172L,53173L,53174L,53175L,53176L,53177L, -53178L,53179L,53180L,53181L,53182L,53183L,53184L,53185L,53186L,53187L, -53188L,53189L,53190L,53191L,53192L,53193L,53194L,53195L,53196L,53197L, -53198L,53199L,53200L,53201L,53202L,53203L,53204L,53205L,53206L,53207L, -53208L,53209L,53210L,53211L,53212L,53213L,53214L,53215L,53216L,53217L, -53218L,53219L,53220L,53221L,53222L,53223L,53224L,53225L,53226L,53227L, -53228L,53229L,53230L,53231L,53232L,53233L,53234L,53235L,53236L,53237L, -53238L,53239L,53240L,53241L,53242L,53243L,53244L,53245L,53246L,53247L, -53248L,53249L,53250L,53251L,53252L,53253L,53254L,53255L,53256L,53257L, -53258L,53259L,53260L,53261L,53262L,53263L,53264L,53265L,53266L,53267L, -53268L,53269L,53270L,53271L,53272L,53273L,53274L,53275L,53276L,53277L, -53278L,53279L,53280L,53281L,53282L,53283L,53284L,53285L,53286L,53287L, -53288L,53289L,53290L,53291L,53292L,53293L,53294L,53295L,53296L,53297L, -53298L,53299L,53300L,53301L,53302L,53303L,53304L,53305L,53306L,53307L, -53308L,53309L,53310L,53311L,53312L,53313L,53314L,53315L,53316L,53317L, -53318L,53319L,53320L,53321L,53322L,53323L,53324L,53325L,53326L,53327L, -53328L,53329L,53330L,53331L,53332L,53333L,53334L,53335L,53336L,53337L, -53338L,53339L,53340L,53341L,53342L,53343L,53344L,53345L,53346L,53347L, -53348L,53349L,53350L,53351L,53352L,53353L,53354L,53355L,53356L,53357L, -53358L,53359L,53360L,53361L,53362L,53363L,53364L,53365L,53366L,53367L, -53368L,53369L,53370L,53371L,53372L,53373L,53374L,53375L,53376L,53377L, -53378L,53379L,53380L,53381L,53382L,53383L,53384L,53385L,53386L,53387L, -53388L,53389L,53390L,53391L,53392L,53393L,53394L,53395L,53396L,53397L, -53398L,53399L,53400L,53401L,53402L,53403L,53404L,53405L,53406L,53407L, -53408L,53409L,53410L,53411L,53412L,53413L,53414L,53415L,53416L,53417L, -53418L,53419L,53420L,53421L,53422L,53423L,53424L,53425L,53426L,53427L, -53428L,53429L,53430L,53431L,53432L,53433L,53434L,53435L,53436L,53437L, -53438L,53439L,53440L,53441L,53442L,53443L,53444L,53445L,53446L,53447L, -53448L,53449L,53450L,53451L,53452L,53453L,53454L,53455L,53456L,53457L, -53458L,53459L,53460L,53461L,53462L,53463L,53464L,53465L,53466L,53467L, -53468L,53469L,53470L,53471L,53472L,53473L,53474L,53475L,53476L,53477L, -53478L,53479L,53480L,53481L,53482L,53483L,53484L,53485L,53486L,53487L, -53488L,53489L,53490L,53491L,53492L,53493L,53494L,53495L,53496L,53497L, -53498L,53499L,53500L,53501L,53502L,53503L,53504L,53505L,53506L,53507L, -53508L,53509L,53510L,53511L,53512L,53513L,53514L,53515L,53516L,53517L, -53518L,53519L,53520L,53521L,53522L,53523L,53524L,53525L,53526L,53527L, -53528L,53529L,53530L,53531L,53532L,53533L,53534L,53535L,53536L,53537L, -53538L,53539L,53540L,53541L,53542L,53543L,53544L,53545L,53546L,53547L, -53548L,53549L,53550L,53551L,53552L,53553L,53554L,53555L,53556L,53557L, -53558L,53559L,53560L,53561L,53562L,53563L,53564L,53565L,53566L,53567L, -53568L,53569L,53570L,53571L,53572L,53573L,53574L,53575L,53576L,53577L, -53578L,53579L,53580L,53581L,53582L,53583L,53584L,53585L,53586L,53587L, -53588L,53589L,53590L,53591L,53592L,53593L,53594L,53595L,53596L,53597L, -53598L,53599L,53600L,53601L,53602L,53603L,53604L,53605L,53606L,53607L, -53608L,53609L,53610L,53611L,53612L,53613L,53614L,53615L,53616L,53617L, -53618L,53619L,53620L,53621L,53622L,53623L,53624L,53625L,53626L,53627L, -53628L,53629L,53630L,53631L,53632L,53633L,53634L,53635L,53636L,53637L, -53638L,53639L,53640L,53641L,53642L,53643L,53644L,53645L,53646L,53647L, -53648L,53649L,53650L,53651L,53652L,53653L,53654L,53655L,53656L,53657L, -53658L,53659L,53660L,53661L,53662L,53663L,53664L,53665L,53666L,53667L, -53668L,53669L,53670L,53671L,53672L,53673L,53674L,53675L,53676L,53677L, -53678L,53679L,53680L,53681L,53682L,53683L,53684L,53685L,53686L,53687L, -53688L,53689L,53690L,53691L,53692L,53693L,53694L,53695L,53696L,53697L, -53698L,53699L,53700L,53701L,53702L,53703L,53704L,53705L,53706L,53707L, -53708L,53709L,53710L,53711L,53712L,53713L,53714L,53715L,53716L,53717L, -53718L,53719L,53720L,53721L,53722L,53723L,53724L,53725L,53726L,53727L, -53728L,53729L,53730L,53731L,53732L,53733L,53734L,53735L,53736L,53737L, -53738L,53739L,53740L,53741L,53742L,53743L,53744L,53745L,53746L,53747L, -53748L,53749L,53750L,53751L,53752L,53753L,53754L,53755L,53756L,53757L, -53758L,53759L,53760L,53761L,53762L,53763L,53764L,53765L,53766L,53767L, -53768L,53769L,53770L,53771L,53772L,53773L,53774L,53775L,53776L,53777L, -53778L,53779L,53780L,53781L,53782L,53783L,53784L,53785L,53786L,53787L, -53788L,53789L,53790L,53791L,53792L,53793L,53794L,53795L,53796L,53797L, -53798L,53799L,53800L,53801L,53802L,53803L,53804L,53805L,53806L,53807L, -53808L,53809L,53810L,53811L,53812L,53813L,53814L,53815L,53816L,53817L, -53818L,53819L,53820L,53821L,53822L,53823L,53824L,53825L,53826L,53827L, -53828L,53829L,53830L,53831L,53832L,53833L,53834L,53835L,53836L,53837L, -53838L,53839L,53840L,53841L,53842L,53843L,53844L,53845L,53846L,53847L, -53848L,53849L,53850L,53851L,53852L,53853L,53854L,53855L,53856L,53857L, -53858L,53859L,53860L,53861L,53862L,53863L,53864L,53865L,53866L,53867L, -53868L,53869L,53870L,53871L,53872L,53873L,53874L,53875L,53876L,53877L, -53878L,53879L,53880L,53881L,53882L,53883L,53884L,53885L,53886L,53887L, -53888L,53889L,53890L,53891L,53892L,53893L,53894L,53895L,53896L,53897L, -53898L,53899L,53900L,53901L,53902L,53903L,53904L,53905L,53906L,53907L, -53908L,53909L,53910L,53911L,53912L,53913L,53914L,53915L,53916L,53917L, -53918L,53919L,53920L,53921L,53922L,53923L,53924L,53925L,53926L,53927L, -53928L,53929L,53930L,53931L,53932L,53933L,53934L,53935L,53936L,53937L, -53938L,53939L,53940L,53941L,53942L,53943L,53944L,53945L,53946L,53947L, -53948L,53949L,53950L,53951L,53952L,53953L,53954L,53955L,53956L,53957L, -53958L,53959L,53960L,53961L,53962L,53963L,53964L,53965L,53966L,53967L, -53968L,53969L,53970L,53971L,53972L,53973L,53974L,53975L,53976L,53977L, -53978L,53979L,53980L,53981L,53982L,53983L,53984L,53985L,53986L,53987L, -53988L,53989L,53990L,53991L,53992L,53993L,53994L,53995L,53996L,53997L, -53998L,53999L,54000L,54001L,54002L,54003L,54004L,54005L,54006L,54007L, -54008L,54009L,54010L,54011L,54012L,54013L,54014L,54015L,54016L,54017L, -54018L,54019L,54020L,54021L,54022L,54023L,54024L,54025L,54026L,54027L, -54028L,54029L,54030L,54031L,54032L,54033L,54034L,54035L,54036L,54037L, -54038L,54039L,54040L,54041L,54042L,54043L,54044L,54045L,54046L,54047L, -54048L,54049L,54050L,54051L,54052L,54053L,54054L,54055L,54056L,54057L, -54058L,54059L,54060L,54061L,54062L,54063L,54064L,54065L,54066L,54067L, -54068L,54069L,54070L,54071L,54072L,54073L,54074L,54075L,54076L,54077L, -54078L,54079L,54080L,54081L,54082L,54083L,54084L,54085L,54086L,54087L, -54088L,54089L,54090L,54091L,54092L,54093L,54094L,54095L,54096L,54097L, -54098L,54099L,54100L,54101L,54102L,54103L,54104L,54105L,54106L,54107L, -54108L,54109L,54110L,54111L,54112L,54113L,54114L,54115L,54116L,54117L, -54118L,54119L,54120L,54121L,54122L,54123L,54124L,54125L,54126L,54127L, -54128L,54129L,54130L,54131L,54132L,54133L,54134L,54135L,54136L,54137L, -54138L,54139L,54140L,54141L,54142L,54143L,54144L,54145L,54146L,54147L, -54148L,54149L,54150L,54151L,54152L,54153L,54154L,54155L,54156L,54157L, -54158L,54159L,54160L,54161L,54162L,54163L,54164L,54165L,54166L,54167L, -54168L,54169L,54170L,54171L,54172L,54173L,54174L,54175L,54176L,54177L, -54178L,54179L,54180L,54181L,54182L,54183L,54184L,54185L,54186L,54187L, -54188L,54189L,54190L,54191L,54192L,54193L,54194L,54195L,54196L,54197L, -54198L,54199L,54200L,54201L,54202L,54203L,54204L,54205L,54206L,54207L, -54208L,54209L,54210L,54211L,54212L,54213L,54214L,54215L,54216L,54217L, -54218L,54219L,54220L,54221L,54222L,54223L,54224L,54225L,54226L,54227L, -54228L,54229L,54230L,54231L,54232L,54233L,54234L,54235L,54236L,54237L, -54238L,54239L,54240L,54241L,54242L,54243L,54244L,54245L,54246L,54247L, -54248L,54249L,54250L,54251L,54252L,54253L,54254L,54255L,54256L,54257L, -54258L,54259L,54260L,54261L,54262L,54263L,54264L,54265L,54266L,54267L, -54268L,54269L,54270L,54271L,54272L,54273L,54274L,54275L,54276L,54277L, -54278L,54279L,54280L,54281L,54282L,54283L,54284L,54285L,54286L,54287L, -54288L,54289L,54290L,54291L,54292L,54293L,54294L,54295L,54296L,54297L, -54298L,54299L,54300L,54301L,54302L,54303L,54304L,54305L,54306L,54307L, -54308L,54309L,54310L,54311L,54312L,54313L,54314L,54315L,54316L,54317L, -54318L,54319L,54320L,54321L,54322L,54323L,54324L,54325L,54326L,54327L, -54328L,54329L,54330L,54331L,54332L,54333L,54334L,54335L,54336L,54337L, -54338L,54339L,54340L,54341L,54342L,54343L,54344L,54345L,54346L,54347L, -54348L,54349L,54350L,54351L,54352L,54353L,54354L,54355L,54356L,54357L, -54358L,54359L,54360L,54361L,54362L,54363L,54364L,54365L,54366L,54367L, -54368L,54369L,54370L,54371L,54372L,54373L,54374L,54375L,54376L,54377L, -54378L,54379L,54380L,54381L,54382L,54383L,54384L,54385L,54386L,54387L, -54388L,54389L,54390L,54391L,54392L,54393L,54394L,54395L,54396L,54397L, -54398L,54399L,54400L,54401L,54402L,54403L,54404L,54405L,54406L,54407L, -54408L,54409L,54410L,54411L,54412L,54413L,54414L,54415L,54416L,54417L, -54418L,54419L,54420L,54421L,54422L,54423L,54424L,54425L,54426L,54427L, -54428L,54429L,54430L,54431L,54432L,54433L,54434L,54435L,54436L,54437L, -54438L,54439L,54440L,54441L,54442L,54443L,54444L,54445L,54446L,54447L, -54448L,54449L,54450L,54451L,54452L,54453L,54454L,54455L,54456L,54457L, -54458L,54459L,54460L,54461L,54462L,54463L,54464L,54465L,54466L,54467L, -54468L,54469L,54470L,54471L,54472L,54473L,54474L,54475L,54476L,54477L, -54478L,54479L,54480L,54481L,54482L,54483L,54484L,54485L,54486L,54487L, -54488L,54489L,54490L,54491L,54492L,54493L,54494L,54495L,54496L,54497L, -54498L,54499L,54500L,54501L,54502L,54503L,54504L,54505L,54506L,54507L, -54508L,54509L,54510L,54511L,54512L,54513L,54514L,54515L,54516L,54517L, -54518L,54519L,54520L,54521L,54522L,54523L,54524L,54525L,54526L,54527L, -54528L,54529L,54530L,54531L,54532L,54533L,54534L,54535L,54536L,54537L, -54538L,54539L,54540L,54541L,54542L,54543L,54544L,54545L,54546L,54547L, -54548L,54549L,54550L,54551L,54552L,54553L,54554L,54555L,54556L,54557L, -54558L,54559L,54560L,54561L,54562L,54563L,54564L,54565L,54566L,54567L, -54568L,54569L,54570L,54571L,54572L,54573L,54574L,54575L,54576L,54577L, -54578L,54579L,54580L,54581L,54582L,54583L,54584L,54585L,54586L,54587L, -54588L,54589L,54590L,54591L,54592L,54593L,54594L,54595L,54596L,54597L, -54598L,54599L,54600L,54601L,54602L,54603L,54604L,54605L,54606L,54607L, -54608L,54609L,54610L,54611L,54612L,54613L,54614L,54615L,54616L,54617L, -54618L,54619L,54620L,54621L,54622L,54623L,54624L,54625L,54626L,54627L, -54628L,54629L,54630L,54631L,54632L,54633L,54634L,54635L,54636L,54637L, -54638L,54639L,54640L,54641L,54642L,54643L,54644L,54645L,54646L,54647L, -54648L,54649L,54650L,54651L,54652L,54653L,54654L,54655L,54656L,54657L, -54658L,54659L,54660L,54661L,54662L,54663L,54664L,54665L,54666L,54667L, -54668L,54669L,54670L,54671L,54672L,54673L,54674L,54675L,54676L,54677L, -54678L,54679L,54680L,54681L,54682L,54683L,54684L,54685L,54686L,54687L, -54688L,54689L,54690L,54691L,54692L,54693L,54694L,54695L,54696L,54697L, -54698L,54699L,54700L,54701L,54702L,54703L,54704L,54705L,54706L,54707L, -54708L,54709L,54710L,54711L,54712L,54713L,54714L,54715L,54716L,54717L, -54718L,54719L,54720L,54721L,54722L,54723L,54724L,54725L,54726L,54727L, -54728L,54729L,54730L,54731L,54732L,54733L,54734L,54735L,54736L,54737L, -54738L,54739L,54740L,54741L,54742L,54743L,54744L,54745L,54746L,54747L, -54748L,54749L,54750L,54751L,54752L,54753L,54754L,54755L,54756L,54757L, -54758L,54759L,54760L,54761L,54762L,54763L,54764L,54765L,54766L,54767L, -54768L,54769L,54770L,54771L,54772L,54773L,54774L,54775L,54776L,54777L, -54778L,54779L,54780L,54781L,54782L,54783L,54784L,54785L,54786L,54787L, -54788L,54789L,54790L,54791L,54792L,54793L,54794L,54795L,54796L,54797L, -54798L,54799L,54800L,54801L,54802L,54803L,54804L,54805L,54806L,54807L, -54808L,54809L,54810L,54811L,54812L,54813L,54814L,54815L,54816L,54817L, -54818L,54819L,54820L,54821L,54822L,54823L,54824L,54825L,54826L,54827L, -54828L,54829L,54830L,54831L,54832L,54833L,54834L,54835L,54836L,54837L, -54838L,54839L,54840L,54841L,54842L,54843L,54844L,54845L,54846L,54847L, -54848L,54849L,54850L,54851L,54852L,54853L,54854L,54855L,54856L,54857L, -54858L,54859L,54860L,54861L,54862L,54863L,54864L,54865L,54866L,54867L, -54868L,54869L,54870L,54871L,54872L,54873L,54874L,54875L,54876L,54877L, -54878L,54879L,54880L,54881L,54882L,54883L,54884L,54885L,54886L,54887L, -54888L,54889L,54890L,54891L,54892L,54893L,54894L,54895L,54896L,54897L, -54898L,54899L,54900L,54901L,54902L,54903L,54904L,54905L,54906L,54907L, -54908L,54909L,54910L,54911L,54912L,54913L,54914L,54915L,54916L,54917L, -54918L,54919L,54920L,54921L,54922L,54923L,54924L,54925L,54926L,54927L, -54928L,54929L,54930L,54931L,54932L,54933L,54934L,54935L,54936L,54937L, -54938L,54939L,54940L,54941L,54942L,54943L,54944L,54945L,54946L,54947L, -54948L,54949L,54950L,54951L,54952L,54953L,54954L,54955L,54956L,54957L, -54958L,54959L,54960L,54961L,54962L,54963L,54964L,54965L,54966L,54967L, -54968L,54969L,54970L,54971L,54972L,54973L,54974L,54975L,54976L,54977L, -54978L,54979L,54980L,54981L,54982L,54983L,54984L,54985L,54986L,54987L, -54988L,54989L,54990L,54991L,54992L,54993L,54994L,54995L,54996L,54997L, -54998L,54999L,55000L,55001L,55002L,55003L,55004L,55005L,55006L,55007L, -55008L,55009L,55010L,55011L,55012L,55013L,55014L,55015L,55016L,55017L, -55018L,55019L,55020L,55021L,55022L,55023L,55024L,55025L,55026L,55027L, -55028L,55029L,55030L,55031L,55032L,55033L,55034L,55035L,55036L,55037L, -55038L,55039L,55040L,55041L,55042L,55043L,55044L,55045L,55046L,55047L, -55048L,55049L,55050L,55051L,55052L,55053L,55054L,55055L,55056L,55057L, -55058L,55059L,55060L,55061L,55062L,55063L,55064L,55065L,55066L,55067L, -55068L,55069L,55070L,55071L,55072L,55073L,55074L,55075L,55076L,55077L, -55078L,55079L,55080L,55081L,55082L,55083L,55084L,55085L,55086L,55087L, -55088L,55089L,55090L,55091L,55092L,55093L,55094L,55095L,55096L,55097L, -55098L,55099L,55100L,55101L,55102L,55103L,55104L,55105L,55106L,55107L, -55108L,55109L,55110L,55111L,55112L,55113L,55114L,55115L,55116L,55117L, -55118L,55119L,55120L,55121L,55122L,55123L,55124L,55125L,55126L,55127L, -55128L,55129L,55130L,55131L,55132L,55133L,55134L,55135L,55136L,55137L, -55138L,55139L,55140L,55141L,55142L,55143L,55144L,55145L,55146L,55147L, -55148L,55149L,55150L,55151L,55152L,55153L,55154L,55155L,55156L,55157L, -55158L,55159L,55160L,55161L,55162L,55163L,55164L,55165L,55166L,55167L, -55168L,55169L,55170L,55171L,55172L,55173L,55174L,55175L,55176L,55177L, -55178L,55179L,55180L,55181L,55182L,55183L,55184L,55185L,55186L,55187L, -55188L,55189L,55190L,55191L,55192L,55193L,55194L,55195L,55196L,55197L, -55198L,55199L,55200L,55201L,55202L,55203L,55204L,55205L,55206L,55207L, -55208L,55209L,55210L,55211L,55212L,55213L,55214L,55215L,55216L,55217L, -55218L,55219L,55220L,55221L,55222L,55223L,55224L,55225L,55226L,55227L, -55228L,55229L,55230L,55231L,55232L,55233L,55234L,55235L,55236L,55237L, -55238L,55239L,55240L,55241L,55242L,55243L,55244L,55245L,55246L,55247L, -55248L,55249L,55250L,55251L,55252L,55253L,55254L,55255L,55256L,55257L, -55258L,55259L,55260L,55261L,55262L,55263L,55264L,55265L,55266L,55267L, -55268L,55269L,55270L,55271L,55272L,55273L,55274L,55275L,55276L,55277L, -55278L,55279L,55280L,55281L,55282L,55283L,55284L,55285L,55286L,55287L, -55288L,55289L,55290L,55291L,55292L,55293L,55294L,55295L,55296L,55297L, -55298L,55299L,55300L,55301L,55302L,55303L,55304L,55305L,55306L,55307L, -55308L,55309L,55310L,55311L,55312L,55313L,55314L,55315L,55316L,55317L, -55318L,55319L,55320L,55321L,55322L,55323L,55324L,55325L,55326L,55327L, -55328L,55329L,55330L,55331L,55332L,55333L,55334L,55335L,55336L,55337L, -55338L,55339L,55340L,55341L,55342L,55343L,55344L,55345L,55346L,55347L, -55348L,55349L,55350L,55351L,55352L,55353L,55354L,55355L,55356L,55357L, -55358L,55359L,55360L,55361L,55362L,55363L,55364L,55365L,55366L,55367L, -55368L,55369L,55370L,55371L,55372L,55373L,55374L,55375L,55376L,55377L, -55378L,55379L,55380L,55381L,55382L,55383L,55384L,55385L,55386L,55387L, -55388L,55389L,55390L,55391L,55392L,55393L,55394L,55395L,55396L,55397L, -55398L,55399L,55400L,55401L,55402L,55403L,55404L,55405L,55406L,55407L, -55408L,55409L,55410L,55411L,55412L,55413L,55414L,55415L,55416L,55417L, -55418L,55419L,55420L,55421L,55422L,55423L,55424L,55425L,55426L,55427L, -55428L,55429L,55430L,55431L,55432L,55433L,55434L,55435L,55436L,55437L, -55438L,55439L,55440L,55441L,55442L,55443L,55444L,55445L,55446L,55447L, -55448L,55449L,55450L,55451L,55452L,55453L,55454L,55455L,55456L,55457L, -55458L,55459L,55460L,55461L,55462L,55463L,55464L,55465L,55466L,55467L, -55468L,55469L,55470L,55471L,55472L,55473L,55474L,55475L,55476L,55477L, -55478L,55479L,55480L,55481L,55482L,55483L,55484L,55485L,55486L,55487L, -55488L,55489L,55490L,55491L,55492L,55493L,55494L,55495L,55496L,55497L, -55498L,55499L,55500L,55501L,55502L,55503L,55504L,55505L,55506L,55507L, -55508L,55509L,55510L,55511L,55512L,55513L,55514L,55515L,55516L,55517L, -55518L,55519L,55520L,55521L,55522L,55523L,55524L,55525L,55526L,55527L, -55528L,55529L,55530L,55531L,55532L,55533L,55534L,55535L,55536L,55537L, -55538L,55539L,55540L,55541L,55542L,55543L,55544L,55545L,55546L,55547L, -55548L,55549L,55550L,55551L,55552L,55553L,55554L,55555L,55556L,55557L, -55558L,55559L,55560L,55561L,55562L,55563L,55564L,55565L,55566L,55567L, -55568L,55569L,55570L,55571L,55572L,55573L,55574L,55575L,55576L,55577L, -55578L,55579L,55580L,55581L,55582L,55583L,55584L,55585L,55586L,55587L, -55588L,55589L,55590L,55591L,55592L,55593L,55594L,55595L,55596L,55597L, -55598L,55599L,55600L,55601L,55602L,55603L,55604L,55605L,55606L,55607L, -55608L,55609L,55610L,55611L,55612L,55613L,55614L,55615L,55616L,55617L, -55618L,55619L,55620L,55621L,55622L,55623L,55624L,55625L,55626L,55627L, -55628L,55629L,55630L,55631L,55632L,55633L,55634L,55635L,55636L,55637L, -55638L,55639L,55640L,55641L,55642L,55643L,55644L,55645L,55646L,55647L, -55648L,55649L,55650L,55651L,55652L,55653L,55654L,55655L,55656L,55657L, -55658L,55659L,55660L,55661L,55662L,55663L,55664L,55665L,55666L,55667L, -55668L,55669L,55670L,55671L,55672L,55673L,55674L,55675L,55676L,55677L, -55678L,55679L,55680L,55681L,55682L,55683L,55684L,55685L,55686L,55687L, -55688L,55689L,55690L,55691L,55692L,55693L,55694L,55695L,55696L,55697L, -55698L,55699L,55700L,55701L,55702L,55703L,55704L,55705L,55706L,55707L, -55708L,55709L,55710L,55711L,55712L,55713L,55714L,55715L,55716L,55717L, -55718L,55719L,55720L,55721L,55722L,55723L,55724L,55725L,55726L,55727L, -55728L,55729L,55730L,55731L,55732L,55733L,55734L,55735L,55736L,55737L, -55738L,55739L,55740L,55741L,55742L,55743L,55744L,55745L,55746L,55747L, -55748L,55749L,55750L,55751L,55752L,55753L,55754L,55755L,55756L,55757L, -55758L,55759L,55760L,55761L,55762L,55763L,55764L,55765L,55766L,55767L, -55768L,55769L,55770L,55771L,55772L,55773L,55774L,55775L,55776L,55777L, -55778L,55779L,55780L,55781L,55782L,55783L,55784L,55785L,55786L,55787L, -55788L,55789L,55790L,55791L,55792L,55793L,55794L,55795L,55796L,55797L, -55798L,55799L,55800L,55801L,55802L,55803L,55804L,55805L,55806L,55807L, -55808L,55809L,55810L,55811L,55812L,55813L,55814L,55815L,55816L,55817L, -55818L,55819L,55820L,55821L,55822L,55823L,55824L,55825L,55826L,55827L, -55828L,55829L,55830L,55831L,55832L,55833L,55834L,55835L,55836L,55837L, -55838L,55839L,55840L,55841L,55842L,55843L,55844L,55845L,55846L,55847L, -55848L,55849L,55850L,55851L,55852L,55853L,55854L,55855L,55856L,55857L, -55858L,55859L,55860L,55861L,55862L,55863L,55864L,55865L,55866L,55867L, -55868L,55869L,55870L,55871L,55872L,55873L,55874L,55875L,55876L,55877L, -55878L,55879L,55880L,55881L,55882L,55883L,55884L,55885L,55886L,55887L, -55888L,55889L,55890L,55891L,55892L,55893L,55894L,55895L,55896L,55897L, -55898L,55899L,55900L,55901L,55902L,55903L,55904L,55905L,55906L,55907L, -55908L,55909L,55910L,55911L,55912L,55913L,55914L,55915L,55916L,55917L, -55918L,55919L,55920L,55921L,55922L,55923L,55924L,55925L,55926L,55927L, -55928L,55929L,55930L,55931L,55932L,55933L,55934L,55935L,55936L,55937L, -55938L,55939L,55940L,55941L,55942L,55943L,55944L,55945L,55946L,55947L, -55948L,55949L,55950L,55951L,55952L,55953L,55954L,55955L,55956L,55957L, -55958L,55959L,55960L,55961L,55962L,55963L,55964L,55965L,55966L,55967L, -55968L,55969L,55970L,55971L,55972L,55973L,55974L,55975L,55976L,55977L, -55978L,55979L,55980L,55981L,55982L,55983L,55984L,55985L,55986L,55987L, -55988L,55989L,55990L,55991L,55992L,55993L,55994L,55995L,55996L,55997L, -55998L,55999L,56000L,56001L,56002L,56003L,56004L,56005L,56006L,56007L, -56008L,56009L,56010L,56011L,56012L,56013L,56014L,56015L,56016L,56017L, -56018L,56019L,56020L,56021L,56022L,56023L,56024L,56025L,56026L,56027L, -56028L,56029L,56030L,56031L,56032L,56033L,56034L,56035L,56036L,56037L, -56038L,56039L,56040L,56041L,56042L,56043L,56044L,56045L,56046L,56047L, -56048L,56049L,56050L,56051L,56052L,56053L,56054L,56055L,56056L,56057L, -56058L,56059L,56060L,56061L,56062L,56063L,56064L,56065L,56066L,56067L, -56068L,56069L,56070L,56071L,56072L,56073L,56074L,56075L,56076L,56077L, -56078L,56079L,56080L,56081L,56082L,56083L,56084L,56085L,56086L,56087L, -56088L,56089L,56090L,56091L,56092L,56093L,56094L,56095L,56096L,56097L, -56098L,56099L,56100L,56101L,56102L,56103L,56104L,56105L,56106L,56107L, -56108L,56109L,56110L,56111L,56112L,56113L,56114L,56115L,56116L,56117L, -56118L,56119L,56120L,56121L,56122L,56123L,56124L,56125L,56126L,56127L, -56128L,56129L,56130L,56131L,56132L,56133L,56134L,56135L,56136L,56137L, -56138L,56139L,56140L,56141L,56142L,56143L,56144L,56145L,56146L,56147L, -56148L,56149L,56150L,56151L,56152L,56153L,56154L,56155L,56156L,56157L, -56158L,56159L,56160L,56161L,56162L,56163L,56164L,56165L,56166L,56167L, -56168L,56169L,56170L,56171L,56172L,56173L,56174L,56175L,56176L,56177L, -56178L,56179L,56180L,56181L,56182L,56183L,56184L,56185L,56186L,56187L, -56188L,56189L,56190L,56191L,56192L,56193L,56194L,56195L,56196L,56197L, -56198L,56199L,56200L,56201L,56202L,56203L,56204L,56205L,56206L,56207L, -56208L,56209L,56210L,56211L,56212L,56213L,56214L,56215L,56216L,56217L, -56218L,56219L,56220L,56221L,56222L,56223L,56224L,56225L,56226L,56227L, -56228L,56229L,56230L,56231L,56232L,56233L,56234L,56235L,56236L,56237L, -56238L,56239L,56240L,56241L,56242L,56243L,56244L,56245L,56246L,56247L, -56248L,56249L,56250L,56251L,56252L,56253L,56254L,56255L,56256L,56257L, -56258L,56259L,56260L,56261L,56262L,56263L,56264L,56265L,56266L,56267L, -56268L,56269L,56270L,56271L,56272L,56273L,56274L,56275L,56276L,56277L, -56278L,56279L,56280L,56281L,56282L,56283L,56284L,56285L,56286L,56287L, -56288L,56289L,56290L,56291L,56292L,56293L,56294L,56295L,56296L,56297L, -56298L,56299L,56300L,56301L,56302L,56303L,56304L,56305L,56306L,56307L, -56308L,56309L,56310L,56311L,56312L,56313L,56314L,56315L,56316L,56317L, -56318L,56319L,56320L,56321L,56322L,56323L,56324L,56325L,56326L,56327L, -56328L,56329L,56330L,56331L,56332L,56333L,56334L,56335L,56336L,56337L, -56338L,56339L,56340L,56341L,56342L,56343L,56344L,56345L,56346L,56347L, -56348L,56349L,56350L,56351L,56352L,56353L,56354L,56355L,56356L,56357L, -56358L,56359L,56360L,56361L,56362L,56363L,56364L,56365L,56366L,56367L, -56368L,56369L,56370L,56371L,56372L,56373L,56374L,56375L,56376L,56377L, -56378L,56379L,56380L,56381L,56382L,56383L,56384L,56385L,56386L,56387L, -56388L,56389L,56390L,56391L,56392L,56393L,56394L,56395L,56396L,56397L, -56398L,56399L,56400L,56401L,56402L,56403L,56404L,56405L,56406L,56407L, -56408L,56409L,56410L,56411L,56412L,56413L,56414L,56415L,56416L,56417L, -56418L,56419L,56420L,56421L,56422L,56423L,56424L,56425L,56426L,56427L, -56428L,56429L,56430L,56431L,56432L,56433L,56434L,56435L,56436L,56437L, -56438L,56439L,56440L,56441L,56442L,56443L,56444L,56445L,56446L,56447L, -56448L,56449L,56450L,56451L,56452L,56453L,56454L,56455L,56456L,56457L, -56458L,56459L,56460L,56461L,56462L,56463L,56464L,56465L,56466L,56467L, -56468L,56469L,56470L,56471L,56472L,56473L,56474L,56475L,56476L,56477L, -56478L,56479L,56480L,56481L,56482L,56483L,56484L,56485L,56486L,56487L, -56488L,56489L,56490L,56491L,56492L,56493L,56494L,56495L,56496L,56497L, -56498L,56499L,56500L,56501L,56502L,56503L,56504L,56505L,56506L,56507L, -56508L,56509L,56510L,56511L,56512L,56513L,56514L,56515L,56516L,56517L, -56518L,56519L,56520L,56521L,56522L,56523L,56524L,56525L,56526L,56527L, -56528L,56529L,56530L,56531L,56532L,56533L,56534L,56535L,56536L,56537L, -56538L,56539L,56540L,56541L,56542L,56543L,56544L,56545L,56546L,56547L, -56548L,56549L,56550L,56551L,56552L,56553L,56554L,56555L,56556L,56557L, -56558L,56559L,56560L,56561L,56562L,56563L,56564L,56565L,56566L,56567L, -56568L,56569L,56570L,56571L,56572L,56573L,56574L,56575L,56576L,56577L, -56578L,56579L,56580L,56581L,56582L,56583L,56584L,56585L,56586L,56587L, -56588L,56589L,56590L,56591L,56592L,56593L,56594L,56595L,56596L,56597L, -56598L,56599L,56600L,56601L,56602L,56603L,56604L,56605L,56606L,56607L, -56608L,56609L,56610L,56611L,56612L,56613L,56614L,56615L,56616L,56617L, -56618L,56619L,56620L,56621L,56622L,56623L,56624L,56625L,56626L,56627L, -56628L,56629L,56630L,56631L,56632L,56633L,56634L,56635L,56636L,56637L, -56638L,56639L,56640L,56641L,56642L,56643L,56644L,56645L,56646L,56647L, -56648L,56649L,56650L,56651L,56652L,56653L,56654L,56655L,56656L,56657L, -56658L,56659L,56660L,56661L,56662L,56663L,56664L,56665L,56666L,56667L, -56668L,56669L,56670L,56671L,56672L,56673L,56674L,56675L,56676L,56677L, -56678L,56679L,56680L,56681L,56682L,56683L,56684L,56685L,56686L,56687L, -56688L,56689L,56690L,56691L,56692L,56693L,56694L,56695L,56696L,56697L, -56698L,56699L,56700L,56701L,56702L,56703L,56704L,56705L,56706L,56707L, -56708L,56709L,56710L,56711L,56712L,56713L,56714L,56715L,56716L,56717L, -56718L,56719L,56720L,56721L,56722L,56723L,56724L,56725L,56726L,56727L, -56728L,56729L,56730L,56731L,56732L,56733L,56734L,56735L,56736L,56737L, -56738L,56739L,56740L,56741L,56742L,56743L,56744L,56745L,56746L,56747L, -56748L,56749L,56750L,56751L,56752L,56753L,56754L,56755L,56756L,56757L, -56758L,56759L,56760L,56761L,56762L,56763L,56764L,56765L,56766L,56767L, -56768L,56769L,56770L,56771L,56772L,56773L,56774L,56775L,56776L,56777L, -56778L,56779L,56780L,56781L,56782L,56783L,56784L,56785L,56786L,56787L, -56788L,56789L,56790L,56791L,56792L,56793L,56794L,56795L,56796L,56797L, -56798L,56799L,56800L,56801L,56802L,56803L,56804L,56805L,56806L,56807L, -56808L,56809L,56810L,56811L,56812L,56813L,56814L,56815L,56816L,56817L, -56818L,56819L,56820L,56821L,56822L,56823L,56824L,56825L,56826L,56827L, -56828L,56829L,56830L,56831L,56832L,56833L,56834L,56835L,56836L,56837L, -56838L,56839L,56840L,56841L,56842L,56843L,56844L,56845L,56846L,56847L, -56848L,56849L,56850L,56851L,56852L,56853L,56854L,56855L,56856L,56857L, -56858L,56859L,56860L,56861L,56862L,56863L,56864L,56865L,56866L,56867L, -56868L,56869L,56870L,56871L,56872L,56873L,56874L,56875L,56876L,56877L, -56878L,56879L,56880L,56881L,56882L,56883L,56884L,56885L,56886L,56887L, -56888L,56889L,56890L,56891L,56892L,56893L,56894L,56895L,56896L,56897L, -56898L,56899L,56900L,56901L,56902L,56903L,56904L,56905L,56906L,56907L, -56908L,56909L,56910L,56911L,56912L,56913L,56914L,56915L,56916L,56917L, -56918L,56919L,56920L,56921L,56922L,56923L,56924L,56925L,56926L,56927L, -56928L,56929L,56930L,56931L,56932L,56933L,56934L,56935L,56936L,56937L, -56938L,56939L,56940L,56941L,56942L,56943L,56944L,56945L,56946L,56947L, -56948L,56949L,56950L,56951L,56952L,56953L,56954L,56955L,56956L,56957L, -56958L,56959L,56960L,56961L,56962L,56963L,56964L,56965L,56966L,56967L, -56968L,56969L,56970L,56971L,56972L,56973L,56974L,56975L,56976L,56977L, -56978L,56979L,56980L,56981L,56982L,56983L,56984L,56985L,56986L,56987L, -56988L,56989L,56990L,56991L,56992L,56993L,56994L,56995L,56996L,56997L, -56998L,56999L,57000L,57001L,57002L,57003L,57004L,57005L,57006L,57007L, -57008L,57009L,57010L,57011L,57012L,57013L,57014L,57015L,57016L,57017L, -57018L,57019L,57020L,57021L,57022L,57023L,57024L,57025L,57026L,57027L, -57028L,57029L,57030L,57031L,57032L,57033L,57034L,57035L,57036L,57037L, -57038L,57039L,57040L,57041L,57042L,57043L,57044L,57045L,57046L,57047L, -57048L,57049L,57050L,57051L,57052L,57053L,57054L,57055L,57056L,57057L, -57058L,57059L,57060L,57061L,57062L,57063L,57064L,57065L,57066L,57067L, -57068L,57069L,57070L,57071L,57072L,57073L,57074L,57075L,57076L,57077L, -57078L,57079L,57080L,57081L,57082L,57083L,57084L,57085L,57086L,57087L, -57088L,57089L,57090L,57091L,57092L,57093L,57094L,57095L,57096L,57097L, -57098L,57099L,57100L,57101L,57102L,57103L,57104L,57105L,57106L,57107L, -57108L,57109L,57110L,57111L,57112L,57113L,57114L,57115L,57116L,57117L, -57118L,57119L,57120L,57121L,57122L,57123L,57124L,57125L,57126L,57127L, -57128L,57129L,57130L,57131L,57132L,57133L,57134L,57135L,57136L,57137L, -57138L,57139L,57140L,57141L,57142L,57143L,57144L,57145L,57146L,57147L, -57148L,57149L,57150L,57151L,57152L,57153L,57154L,57155L,57156L,57157L, -57158L,57159L,57160L,57161L,57162L,57163L,57164L,57165L,57166L,57167L, -57168L,57169L,57170L,57171L,57172L,57173L,57174L,57175L,57176L,57177L, -57178L,57179L,57180L,57181L,57182L,57183L,57184L,57185L,57186L,57187L, -57188L,57189L,57190L,57191L,57192L,57193L,57194L,57195L,57196L,57197L, -57198L,57199L,57200L,57201L,57202L,57203L,57204L,57205L,57206L,57207L, -57208L,57209L,57210L,57211L,57212L,57213L,57214L,57215L,57216L,57217L, -57218L,57219L,57220L,57221L,57222L,57223L,57224L,57225L,57226L,57227L, -57228L,57229L,57230L,57231L,57232L,57233L,57234L,57235L,57236L,57237L, -57238L,57239L,57240L,57241L,57242L,57243L,57244L,57245L,57246L,57247L, -57248L,57249L,57250L,57251L,57252L,57253L,57254L,57255L,57256L,57257L, -57258L,57259L,57260L,57261L,57262L,57263L,57264L,57265L,57266L,57267L, -57268L,57269L,57270L,57271L,57272L,57273L,57274L,57275L,57276L,57277L, -57278L,57279L,57280L,57281L,57282L,57283L,57284L,57285L,57286L,57287L, -57288L,57289L,57290L,57291L,57292L,57293L,57294L,57295L,57296L,57297L, -57298L,57299L,57300L,57301L,57302L,57303L,57304L,57305L,57306L,57307L, -57308L,57309L,57310L,57311L,57312L,57313L,57314L,57315L,57316L,57317L, -57318L,57319L,57320L,57321L,57322L,57323L,57324L,57325L,57326L,57327L, -57328L,57329L,57330L,57331L,57332L,57333L,57334L,57335L,57336L,57337L, -57338L,57339L,57340L,57341L,57342L,57343L,57344L,57345L,57346L,57347L, -57348L,57349L,57350L,57351L,57352L,57353L,57354L,57355L,57356L,57357L, -57358L,57359L,57360L,57361L,57362L,57363L,57364L,57365L,57366L,57367L, -57368L,57369L,57370L,57371L,57372L,57373L,57374L,57375L,57376L,57377L, -57378L,57379L,57380L,57381L,57382L,57383L,57384L,57385L,57386L,57387L, -57388L,57389L,57390L,57391L,57392L,57393L,57394L,57395L,57396L,57397L, -57398L,57399L,57400L,57401L,57402L,57403L,57404L,57405L,57406L,57407L, -57408L,57409L,57410L,57411L,57412L,57413L,57414L,57415L,57416L,57417L, -57418L,57419L,57420L,57421L,57422L,57423L,57424L,57425L,57426L,57427L, -57428L,57429L,57430L,57431L,57432L,57433L,57434L,57435L,57436L,57437L, -57438L,57439L,57440L,57441L,57442L,57443L,57444L,57445L,57446L,57447L, -57448L,57449L,57450L,57451L,57452L,57453L,57454L,57455L,57456L,57457L, -57458L,57459L,57460L,57461L,57462L,57463L,57464L,57465L,57466L,57467L, -57468L,57469L,57470L,57471L,57472L,57473L,57474L,57475L,57476L,57477L, -57478L,57479L,57480L,57481L,57482L,57483L,57484L,57485L,57486L,57487L, -57488L,57489L,57490L,57491L,57492L,57493L,57494L,57495L,57496L,57497L, -57498L,57499L,57500L,57501L,57502L,57503L,57504L,57505L,57506L,57507L, -57508L,57509L,57510L,57511L,57512L,57513L,57514L,57515L,57516L,57517L, -57518L,57519L,57520L,57521L,57522L,57523L,57524L,57525L,57526L,57527L, -57528L,57529L,57530L,57531L,57532L,57533L,57534L,57535L,57536L,57537L, -57538L,57539L,57540L,57541L,57542L,57543L,57544L,57545L,57546L,57547L, -57548L,57549L,57550L,57551L,57552L,57553L,57554L,57555L,57556L,57557L, -57558L,57559L,57560L,57561L,57562L,57563L,57564L,57565L,57566L,57567L, -57568L,57569L,57570L,57571L,57572L,57573L,57574L,57575L,57576L,57577L, -57578L,57579L,57580L,57581L,57582L,57583L,57584L,57585L,57586L,57587L, -57588L,57589L,57590L,57591L,57592L,57593L,57594L,57595L,57596L,57597L, -57598L,57599L,57600L,57601L,57602L,57603L,57604L,57605L,57606L,57607L, -57608L,57609L,57610L,57611L,57612L,57613L,57614L,57615L,57616L,57617L, -57618L,57619L,57620L,57621L,57622L,57623L,57624L,57625L,57626L,57627L, -57628L,57629L,57630L,57631L,57632L,57633L,57634L,57635L,57636L,57637L, -57638L,57639L,57640L,57641L,57642L,57643L,57644L,57645L,57646L,57647L, -57648L,57649L,57650L,57651L,57652L,57653L,57654L,57655L,57656L,57657L, -57658L,57659L,57660L,57661L,57662L,57663L,57664L,57665L,57666L,57667L, -57668L,57669L,57670L,57671L,57672L,57673L,57674L,57675L,57676L,57677L, -57678L,57679L,57680L,57681L,57682L,57683L,57684L,57685L,57686L,57687L, -57688L,57689L,57690L,57691L,57692L,57693L,57694L,57695L,57696L,57697L, -57698L,57699L,57700L,57701L,57702L,57703L,57704L,57705L,57706L,57707L, -57708L,57709L,57710L,57711L,57712L,57713L,57714L,57715L,57716L,57717L, -57718L,57719L,57720L,57721L,57722L,57723L,57724L,57725L,57726L,57727L, -57728L,57729L,57730L,57731L,57732L,57733L,57734L,57735L,57736L,57737L, -57738L,57739L,57740L,57741L,57742L,57743L,57744L,57745L,57746L,57747L, -57748L,57749L,57750L,57751L,57752L,57753L,57754L,57755L,57756L,57757L, -57758L,57759L,57760L,57761L,57762L,57763L,57764L,57765L,57766L,57767L, -57768L,57769L,57770L,57771L,57772L,57773L,57774L,57775L,57776L,57777L, -57778L,57779L,57780L,57781L,57782L,57783L,57784L,57785L,57786L,57787L, -57788L,57789L,57790L,57791L,57792L,57793L,57794L,57795L,57796L,57797L, -57798L,57799L,57800L,57801L,57802L,57803L,57804L,57805L,57806L,57807L, -57808L,57809L,57810L,57811L,57812L,57813L,57814L,57815L,57816L,57817L, -57818L,57819L,57820L,57821L,57822L,57823L,57824L,57825L,57826L,57827L, -57828L,57829L,57830L,57831L,57832L,57833L,57834L,57835L,57836L,57837L, -57838L,57839L,57840L,57841L,57842L,57843L,57844L,57845L,57846L,57847L, -57848L,57849L,57850L,57851L,57852L,57853L,57854L,57855L,57856L,57857L, -57858L,57859L,57860L,57861L,57862L,57863L,57864L,57865L,57866L,57867L, -57868L,57869L,57870L,57871L,57872L,57873L,57874L,57875L,57876L,57877L, -57878L,57879L,57880L,57881L,57882L,57883L,57884L,57885L,57886L,57887L, -57888L,57889L,57890L,57891L,57892L,57893L,57894L,57895L,57896L,57897L, -57898L,57899L,57900L,57901L,57902L,57903L,57904L,57905L,57906L,57907L, -57908L,57909L,57910L,57911L,57912L,57913L,57914L,57915L,57916L,57917L, -57918L,57919L,57920L,57921L,57922L,57923L,57924L,57925L,57926L,57927L, -57928L,57929L,57930L,57931L,57932L,57933L,57934L,57935L,57936L,57937L, -57938L,57939L,57940L,57941L,57942L,57943L,57944L,57945L,57946L,57947L, -57948L,57949L,57950L,57951L,57952L,57953L,57954L,57955L,57956L,57957L, -57958L,57959L,57960L,57961L,57962L,57963L,57964L,57965L,57966L,57967L, -57968L,57969L,57970L,57971L,57972L,57973L,57974L,57975L,57976L,57977L, -57978L,57979L,57980L,57981L,57982L,57983L,57984L,57985L,57986L,57987L, -57988L,57989L,57990L,57991L,57992L,57993L,57994L,57995L,57996L,57997L, -57998L,57999L,58000L,58001L,58002L,58003L,58004L,58005L,58006L,58007L, -58008L,58009L,58010L,58011L,58012L,58013L,58014L,58015L,58016L,58017L, -58018L,58019L,58020L,58021L,58022L,58023L,58024L,58025L,58026L,58027L, -58028L,58029L,58030L,58031L,58032L,58033L,58034L,58035L,58036L,58037L, -58038L,58039L,58040L,58041L,58042L,58043L,58044L,58045L,58046L,58047L, -58048L,58049L,58050L,58051L,58052L,58053L,58054L,58055L,58056L,58057L, -58058L,58059L,58060L,58061L,58062L,58063L,58064L,58065L,58066L,58067L, -58068L,58069L,58070L,58071L,58072L,58073L,58074L,58075L,58076L,58077L, -58078L,58079L,58080L,58081L,58082L,58083L,58084L,58085L,58086L,58087L, -58088L,58089L,58090L,58091L,58092L,58093L,58094L,58095L,58096L,58097L, -58098L,58099L,58100L,58101L,58102L,58103L,58104L,58105L,58106L,58107L, -58108L,58109L,58110L,58111L,58112L,58113L,58114L,58115L,58116L,58117L, -58118L,58119L,58120L,58121L,58122L,58123L,58124L,58125L,58126L,58127L, -58128L,58129L,58130L,58131L,58132L,58133L,58134L,58135L,58136L,58137L, -58138L,58139L,58140L,58141L,58142L,58143L,58144L,58145L,58146L,58147L, -58148L,58149L,58150L,58151L,58152L,58153L,58154L,58155L,58156L,58157L, -58158L,58159L,58160L,58161L,58162L,58163L,58164L,58165L,58166L,58167L, -58168L,58169L,58170L,58171L,58172L,58173L,58174L,58175L,58176L,58177L, -58178L,58179L,58180L,58181L,58182L,58183L,58184L,58185L,58186L,58187L, -58188L,58189L,58190L,58191L,58192L,58193L,58194L,58195L,58196L,58197L, -58198L,58199L,58200L,58201L,58202L,58203L,58204L,58205L,58206L,58207L, -58208L,58209L,58210L,58211L,58212L,58213L,58214L,58215L,58216L,58217L, -58218L,58219L,58220L,58221L,58222L,58223L,58224L,58225L,58226L,58227L, -58228L,58229L,58230L,58231L,58232L,58233L,58234L,58235L,58236L,58237L, -58238L,58239L,58240L,58241L,58242L,58243L,58244L,58245L,58246L,58247L, -58248L,58249L,58250L,58251L,58252L,58253L,58254L,58255L,58256L,58257L, -58258L,58259L,58260L,58261L,58262L,58263L,58264L,58265L,58266L,58267L, -58268L,58269L,58270L,58271L,58272L,58273L,58274L,58275L,58276L,58277L, -58278L,58279L,58280L,58281L,58282L,58283L,58284L,58285L,58286L,58287L, -58288L,58289L,58290L,58291L,58292L,58293L,58294L,58295L,58296L,58297L, -58298L,58299L,58300L,58301L,58302L,58303L,58304L,58305L,58306L,58307L, -58308L,58309L,58310L,58311L,58312L,58313L,58314L,58315L,58316L,58317L, -58318L,58319L,58320L,58321L,58322L,58323L,58324L,58325L,58326L,58327L, -58328L,58329L,58330L,58331L,58332L,58333L,58334L,58335L,58336L,58337L, -58338L,58339L,58340L,58341L,58342L,58343L,58344L,58345L,58346L,58347L, -58348L,58349L,58350L,58351L,58352L,58353L,58354L,58355L,58356L,58357L, -58358L,58359L,58360L,58361L,58362L,58363L,58364L,58365L,58366L,58367L, -58368L,58369L,58370L,58371L,58372L,58373L,58374L,58375L,58376L,58377L, -58378L,58379L,58380L,58381L,58382L,58383L,58384L,58385L,58386L,58387L, -58388L,58389L,58390L,58391L,58392L,58393L,58394L,58395L,58396L,58397L, -58398L,58399L,58400L,58401L,58402L,58403L,58404L,58405L,58406L,58407L, -58408L,58409L,58410L,58411L,58412L,58413L,58414L,58415L,58416L,58417L, -58418L,58419L,58420L,58421L,58422L,58423L,58424L,58425L,58426L,58427L, -58428L,58429L,58430L,58431L,58432L,58433L,58434L,58435L,58436L,58437L, -58438L,58439L,58440L,58441L,58442L,58443L,58444L,58445L,58446L,58447L, -58448L,58449L,58450L,58451L,58452L,58453L,58454L,58455L,58456L,58457L, -58458L,58459L,58460L,58461L,58462L,58463L,58464L,58465L,58466L,58467L, -58468L,58469L,58470L,58471L,58472L,58473L,58474L,58475L,58476L,58477L, -58478L,58479L,58480L,58481L,58482L,58483L,58484L,58485L,58486L,58487L, -58488L,58489L,58490L,58491L,58492L,58493L,58494L,58495L,58496L,58497L, -58498L,58499L,58500L,58501L,58502L,58503L,58504L,58505L,58506L,58507L, -58508L,58509L,58510L,58511L,58512L,58513L,58514L,58515L,58516L,58517L, -58518L,58519L,58520L,58521L,58522L,58523L,58524L,58525L,58526L,58527L, -58528L,58529L,58530L,58531L,58532L,58533L,58534L,58535L,58536L,58537L, -58538L,58539L,58540L,58541L,58542L,58543L,58544L,58545L,58546L,58547L, -58548L,58549L,58550L,58551L,58552L,58553L,58554L,58555L,58556L,58557L, -58558L,58559L,58560L,58561L,58562L,58563L,58564L,58565L,58566L,58567L, -58568L,58569L,58570L,58571L,58572L,58573L,58574L,58575L,58576L,58577L, -58578L,58579L,58580L,58581L,58582L,58583L,58584L,58585L,58586L,58587L, -58588L,58589L,58590L,58591L,58592L,58593L,58594L,58595L,58596L,58597L, -58598L,58599L,58600L,58601L,58602L,58603L,58604L,58605L,58606L,58607L, -58608L,58609L,58610L,58611L,58612L,58613L,58614L,58615L,58616L,58617L, -58618L,58619L,58620L,58621L,58622L,58623L,58624L,58625L,58626L,58627L, -58628L,58629L,58630L,58631L,58632L,58633L,58634L,58635L,58636L,58637L, -58638L,58639L,58640L,58641L,58642L,58643L,58644L,58645L,58646L,58647L, -58648L,58649L,58650L,58651L,58652L,58653L,58654L,58655L,58656L,58657L, -58658L,58659L,58660L,58661L,58662L,58663L,58664L,58665L,58666L,58667L, -58668L,58669L,58670L,58671L,58672L,58673L,58674L,58675L,58676L,58677L, -58678L,58679L,58680L,58681L,58682L,58683L,58684L,58685L,58686L,58687L, -58688L,58689L,58690L,58691L,58692L,58693L,58694L,58695L,58696L,58697L, -58698L,58699L,58700L,58701L,58702L,58703L,58704L,58705L,58706L,58707L, -58708L,58709L,58710L,58711L,58712L,58713L,58714L,58715L,58716L,58717L, -58718L,58719L,58720L,58721L,58722L,58723L,58724L,58725L,58726L,58727L, -58728L,58729L,58730L,58731L,58732L,58733L,58734L,58735L,58736L,58737L, -58738L,58739L,58740L,58741L,58742L,58743L,58744L,58745L,58746L,58747L, -58748L,58749L,58750L,58751L,58752L,58753L,58754L,58755L,58756L,58757L, -58758L,58759L,58760L,58761L,58762L,58763L,58764L,58765L,58766L,58767L, -58768L,58769L,58770L,58771L,58772L,58773L,58774L,58775L,58776L,58777L, -58778L,58779L,58780L,58781L,58782L,58783L,58784L,58785L,58786L,58787L, -58788L,58789L,58790L,58791L,58792L,58793L,58794L,58795L,58796L,58797L, -58798L,58799L,58800L,58801L,58802L,58803L,58804L,58805L,58806L,58807L, -58808L,58809L,58810L,58811L,58812L,58813L,58814L,58815L,58816L,58817L, -58818L,58819L,58820L,58821L,58822L,58823L,58824L,58825L,58826L,58827L, -58828L,58829L,58830L,58831L,58832L,58833L,58834L,58835L,58836L,58837L, -58838L,58839L,58840L,58841L,58842L,58843L,58844L,58845L,58846L,58847L, -58848L,58849L,58850L,58851L,58852L,58853L,58854L,58855L,58856L,58857L, -58858L,58859L,58860L,58861L,58862L,58863L,58864L,58865L,58866L,58867L, -58868L,58869L,58870L,58871L,58872L,58873L,58874L,58875L,58876L,58877L, -58878L,58879L,58880L,58881L,58882L,58883L,58884L,58885L,58886L,58887L, -58888L,58889L,58890L,58891L,58892L,58893L,58894L,58895L,58896L,58897L, -58898L,58899L,58900L,58901L,58902L,58903L,58904L,58905L,58906L,58907L, -58908L,58909L,58910L,58911L,58912L,58913L,58914L,58915L,58916L,58917L, -58918L,58919L,58920L,58921L,58922L,58923L,58924L,58925L,58926L,58927L, -58928L,58929L,58930L,58931L,58932L,58933L,58934L,58935L,58936L,58937L, -58938L,58939L,58940L,58941L,58942L,58943L,58944L,58945L,58946L,58947L, -58948L,58949L,58950L,58951L,58952L,58953L,58954L,58955L,58956L,58957L, -58958L,58959L,58960L,58961L,58962L,58963L,58964L,58965L,58966L,58967L, -58968L,58969L,58970L,58971L,58972L,58973L,58974L,58975L,58976L,58977L, -58978L,58979L,58980L,58981L,58982L,58983L,58984L,58985L,58986L,58987L, -58988L,58989L,58990L,58991L,58992L,58993L,58994L,58995L,58996L,58997L, -58998L,58999L,59000L,59001L,59002L,59003L,59004L,59005L,59006L,59007L, -59008L,59009L,59010L,59011L,59012L,59013L,59014L,59015L,59016L,59017L, -59018L,59019L,59020L,59021L,59022L,59023L,59024L,59025L,59026L,59027L, -59028L,59029L,59030L,59031L,59032L,59033L,59034L,59035L,59036L,59037L, -59038L,59039L,59040L,59041L,59042L,59043L,59044L,59045L,59046L,59047L, -59048L,59049L,59050L,59051L,59052L,59053L,59054L,59055L,59056L,59057L, -59058L,59059L,59060L,59061L,59062L,59063L,59064L,59065L,59066L,59067L, -59068L,59069L,59070L,59071L,59072L,59073L,59074L,59075L,59076L,59077L, -59078L,59079L,59080L,59081L,59082L,59083L,59084L,59085L,59086L,59087L, -59088L,59089L,59090L,59091L,59092L,59093L,59094L,59095L,59096L,59097L, -59098L,59099L,59100L,59101L,59102L,59103L,59104L,59105L,59106L,59107L, -59108L,59109L,59110L,59111L,59112L,59113L,59114L,59115L,59116L,59117L, -59118L,59119L,59120L,59121L,59122L,59123L,59124L,59125L,59126L,59127L, -59128L,59129L,59130L,59131L,59132L,59133L,59134L,59135L,59136L,59137L, -59138L,59139L,59140L,59141L,59142L,59143L,59144L,59145L,59146L,59147L, -59148L,59149L,59150L,59151L,59152L,59153L,59154L,59155L,59156L,59157L, -59158L,59159L,59160L,59161L,59162L,59163L,59164L,59165L,59166L,59167L, -59168L,59169L,59170L,59171L,59172L,59173L,59174L,59175L,59176L,59177L, -59178L,59179L,59180L,59181L,59182L,59183L,59184L,59185L,59186L,59187L, -59188L,59189L,59190L,59191L,59192L,59193L,59194L,59195L,59196L,59197L, -59198L,59199L,59200L,59201L,59202L,59203L,59204L,59205L,59206L,59207L, -59208L,59209L,59210L,59211L,59212L,59213L,59214L,59215L,59216L,59217L, -59218L,59219L,59220L,59221L,59222L,59223L,59224L,59225L,59226L,59227L, -59228L,59229L,59230L,59231L,59232L,59233L,59234L,59235L,59236L,59237L, -59238L,59239L,59240L,59241L,59242L,59243L,59244L,59245L,59246L,59247L, -59248L,59249L,59250L,59251L,59252L,59253L,59254L,59255L,59256L,59257L, -59258L,59259L,59260L,59261L,59262L,59263L,59264L,59265L,59266L,59267L, -59268L,59269L,59270L,59271L,59272L,59273L,59274L,59275L,59276L,59277L, -59278L,59279L,59280L,59281L,59282L,59283L,59284L,59285L,59286L,59287L, -59288L,59289L,59290L,59291L,59292L,59293L,59294L,59295L,59296L,59297L, -59298L,59299L,59300L,59301L,59302L,59303L,59304L,59305L,59306L,59307L, -59308L,59309L,59310L,59311L,59312L,59313L,59314L,59315L,59316L,59317L, -59318L,59319L,59320L,59321L,59322L,59323L,59324L,59325L,59326L,59327L, -59328L,59329L,59330L,59331L,59332L,59333L,59334L,59335L,59336L,59337L, -59338L,59339L,59340L,59341L,59342L,59343L,59344L,59345L,59346L,59347L, -59348L,59349L,59350L,59351L,59352L,59353L,59354L,59355L,59356L,59357L, -59358L,59359L,59360L,59361L,59362L,59363L,59364L,59365L,59366L,59367L, -59368L,59369L,59370L,59371L,59372L,59373L,59374L,59375L,59376L,59377L, -59378L,59379L,59380L,59381L,59382L,59383L,59384L,59385L,59386L,59387L, -59388L,59389L,59390L,59391L,59392L,59393L,59394L,59395L,59396L,59397L, -59398L,59399L,59400L,59401L,59402L,59403L,59404L,59405L,59406L,59407L, -59408L,59409L,59410L,59411L,59412L,59413L,59414L,59415L,59416L,59417L, -59418L,59419L,59420L,59421L,59422L,59423L,59424L,59425L,59426L,59427L, -59428L,59429L,59430L,59431L,59432L,59433L,59434L,59435L,59436L,59437L, -59438L,59439L,59440L,59441L,59442L,59443L,59444L,59445L,59446L,59447L, -59448L,59449L,59450L,59451L,59452L,59453L,59454L,59455L,59456L,59457L, -59458L,59459L,59460L,59461L,59462L,59463L,59464L,59465L,59466L,59467L, -59468L,59469L,59470L,59471L,59472L,59473L,59474L,59475L,59476L,59477L, -59478L,59479L,59480L,59481L,59482L,59483L,59484L,59485L,59486L,59487L, -59488L,59489L,59490L,59491L,59492L,59493L,59494L,59495L,59496L,59497L, -59498L,59499L,59500L,59501L,59502L,59503L,59504L,59505L,59506L,59507L, -59508L,59509L,59510L,59511L,59512L,59513L,59514L,59515L,59516L,59517L, -59518L,59519L,59520L,59521L,59522L,59523L,59524L,59525L,59526L,59527L, -59528L,59529L,59530L,59531L,59532L,59533L,59534L,59535L,59536L,59537L, -59538L,59539L,59540L,59541L,59542L,59543L,59544L,59545L,59546L,59547L, -59548L,59549L,59550L,59551L,59552L,59553L,59554L,59555L,59556L,59557L, -59558L,59559L,59560L,59561L,59562L,59563L,59564L,59565L,59566L,59567L, -59568L,59569L,59570L,59571L,59572L,59573L,59574L,59575L,59576L,59577L, -59578L,59579L,59580L,59581L,59582L,59583L,59584L,59585L,59586L,59587L, -59588L,59589L,59590L,59591L,59592L,59593L,59594L,59595L,59596L,59597L, -59598L,59599L,59600L,59601L,59602L,59603L,59604L,59605L,59606L,59607L, -59608L,59609L,59610L,59611L,59612L,59613L,59614L,59615L,59616L,59617L, -59618L,59619L,59620L,59621L,59622L,59623L,59624L,59625L,59626L,59627L, -59628L,59629L,59630L,59631L,59632L,59633L,59634L,59635L,59636L,59637L, -59638L,59639L,59640L,59641L,59642L,59643L,59644L,59645L,59646L,59647L, -59648L,59649L,59650L,59651L,59652L,59653L,59654L,59655L,59656L,59657L, -59658L,59659L,59660L,59661L,59662L,59663L,59664L,59665L,59666L,59667L, -59668L,59669L,59670L,59671L,59672L,59673L,59674L,59675L,59676L,59677L, -59678L,59679L,59680L,59681L,59682L,59683L,59684L,59685L,59686L,59687L, -59688L,59689L,59690L,59691L,59692L,59693L,59694L,59695L,59696L,59697L, -59698L,59699L,59700L,59701L,59702L,59703L,59704L,59705L,59706L,59707L, -59708L,59709L,59710L,59711L,59712L,59713L,59714L,59715L,59716L,59717L, -59718L,59719L,59720L,59721L,59722L,59723L,59724L,59725L,59726L,59727L, -59728L,59729L,59730L,59731L,59732L,59733L,59734L,59735L,59736L,59737L, -59738L,59739L,59740L,59741L,59742L,59743L,59744L,59745L,59746L,59747L, -59748L,59749L,59750L,59751L,59752L,59753L,59754L,59755L,59756L,59757L, -59758L,59759L,59760L,59761L,59762L,59763L,59764L,59765L,59766L,59767L, -59768L,59769L,59770L,59771L,59772L,59773L,59774L,59775L,59776L,59777L, -59778L,59779L,59780L,59781L,59782L,59783L,59784L,59785L,59786L,59787L, -59788L,59789L,59790L,59791L,59792L,59793L,59794L,59795L,59796L,59797L, -59798L,59799L,59800L,59801L,59802L,59803L,59804L,59805L,59806L,59807L, -59808L,59809L,59810L,59811L,59812L,59813L,59814L,59815L,59816L,59817L, -59818L,59819L,59820L,59821L,59822L,59823L,59824L,59825L,59826L,59827L, -59828L,59829L,59830L,59831L,59832L,59833L,59834L,59835L,59836L,59837L, -59838L,59839L,59840L,59841L,59842L,59843L,59844L,59845L,59846L,59847L, -59848L,59849L,59850L,59851L,59852L,59853L,59854L,59855L,59856L,59857L, -59858L,59859L,59860L,59861L,59862L,59863L,59864L,59865L,59866L,59867L, -59868L,59869L,59870L,59871L,59872L,59873L,59874L,59875L,59876L,59877L, -59878L,59879L,59880L,59881L,59882L,59883L,59884L,59885L,59886L,59887L, -59888L,59889L,59890L,59891L,59892L,59893L,59894L,59895L,59896L,59897L, -59898L,59899L,59900L,59901L,59902L,59903L,59904L,59905L,59906L,59907L, -59908L,59909L,59910L,59911L,59912L,59913L,59914L,59915L,59916L,59917L, -59918L,59919L,59920L,59921L,59922L,59923L,59924L,59925L,59926L,59927L, -59928L,59929L,59930L,59931L,59932L,59933L,59934L,59935L,59936L,59937L, -59938L,59939L,59940L,59941L,59942L,59943L,59944L,59945L,59946L,59947L, -59948L,59949L,59950L,59951L,59952L,59953L,59954L,59955L,59956L,59957L, -59958L,59959L,59960L,59961L,59962L,59963L,59964L,59965L,59966L,59967L, -59968L,59969L,59970L,59971L,59972L,59973L,59974L,59975L,59976L,59977L, -59978L,59979L,59980L,59981L,59982L,59983L,59984L,59985L,59986L,59987L, -59988L,59989L,59990L,59991L,59992L,59993L,59994L,59995L,59996L,59997L, -59998L,59999L,60000L,60001L,60002L,60003L,60004L,60005L,60006L,60007L, -60008L,60009L,60010L,60011L,60012L,60013L,60014L,60015L,60016L,60017L, -60018L,60019L,60020L,60021L,60022L,60023L,60024L,60025L,60026L,60027L, -60028L,60029L,60030L,60031L,60032L,60033L,60034L,60035L,60036L,60037L, -60038L,60039L,60040L,60041L,60042L,60043L,60044L,60045L,60046L,60047L, -60048L,60049L,60050L,60051L,60052L,60053L,60054L,60055L,60056L,60057L, -60058L,60059L,60060L,60061L,60062L,60063L,60064L,60065L,60066L,60067L, -60068L,60069L,60070L,60071L,60072L,60073L,60074L,60075L,60076L,60077L, -60078L,60079L,60080L,60081L,60082L,60083L,60084L,60085L,60086L,60087L, -60088L,60089L,60090L,60091L,60092L,60093L,60094L,60095L,60096L,60097L, -60098L,60099L,60100L,60101L,60102L,60103L,60104L,60105L,60106L,60107L, -60108L,60109L,60110L,60111L,60112L,60113L,60114L,60115L,60116L,60117L, -60118L,60119L,60120L,60121L,60122L,60123L,60124L,60125L,60126L,60127L, -60128L,60129L,60130L,60131L,60132L,60133L,60134L,60135L,60136L,60137L, -60138L,60139L,60140L,60141L,60142L,60143L,60144L,60145L,60146L,60147L, -60148L,60149L,60150L,60151L,60152L,60153L,60154L,60155L,60156L,60157L, -60158L,60159L,60160L,60161L,60162L,60163L,60164L,60165L,60166L,60167L, -60168L,60169L,60170L,60171L,60172L,60173L,60174L,60175L,60176L,60177L, -60178L,60179L,60180L,60181L,60182L,60183L,60184L,60185L,60186L,60187L, -60188L,60189L,60190L,60191L,60192L,60193L,60194L,60195L,60196L,60197L, -60198L,60199L,60200L,60201L,60202L,60203L,60204L,60205L,60206L,60207L, -60208L,60209L,60210L,60211L,60212L,60213L,60214L,60215L,60216L,60217L, -60218L,60219L,60220L,60221L,60222L,60223L,60224L,60225L,60226L,60227L, -60228L,60229L,60230L,60231L,60232L,60233L,60234L,60235L,60236L,60237L, -60238L,60239L,60240L,60241L,60242L,60243L,60244L,60245L,60246L,60247L, -60248L,60249L,60250L,60251L,60252L,60253L,60254L,60255L,60256L,60257L, -60258L,60259L,60260L,60261L,60262L,60263L,60264L,60265L,60266L,60267L, -60268L,60269L,60270L,60271L,60272L,60273L,60274L,60275L,60276L,60277L, -60278L,60279L,60280L,60281L,60282L,60283L,60284L,60285L,60286L,60287L, -60288L,60289L,60290L,60291L,60292L,60293L,60294L,60295L,60296L,60297L, -60298L,60299L,60300L,60301L,60302L,60303L,60304L,60305L,60306L,60307L, -60308L,60309L,60310L,60311L,60312L,60313L,60314L,60315L,60316L,60317L, -60318L,60319L,60320L,60321L,60322L,60323L,60324L,60325L,60326L,60327L, -60328L,60329L,60330L,60331L,60332L,60333L,60334L,60335L,60336L,60337L, -60338L,60339L,60340L,60341L,60342L,60343L,60344L,60345L,60346L,60347L, -60348L,60349L,60350L,60351L,60352L,60353L,60354L,60355L,60356L,60357L, -60358L,60359L,60360L,60361L,60362L,60363L,60364L,60365L,60366L,60367L, -60368L,60369L,60370L,60371L,60372L,60373L,60374L,60375L,60376L,60377L, -60378L,60379L,60380L,60381L,60382L,60383L,60384L,60385L,60386L,60387L, -60388L,60389L,60390L,60391L,60392L,60393L,60394L,60395L,60396L,60397L, -60398L,60399L,60400L,60401L,60402L,60403L,60404L,60405L,60406L,60407L, -60408L,60409L,60410L,60411L,60412L,60413L,60414L,60415L,60416L,60417L, -60418L,60419L,60420L,60421L,60422L,60423L,60424L,60425L,60426L,60427L, -60428L,60429L,60430L,60431L,60432L,60433L,60434L,60435L,60436L,60437L, -60438L,60439L,60440L,60441L,60442L,60443L,60444L,60445L,60446L,60447L, -60448L,60449L,60450L,60451L,60452L,60453L,60454L,60455L,60456L,60457L, -60458L,60459L,60460L,60461L,60462L,60463L,60464L,60465L,60466L,60467L, -60468L,60469L,60470L,60471L,60472L,60473L,60474L,60475L,60476L,60477L, -60478L,60479L,60480L,60481L,60482L,60483L,60484L,60485L,60486L,60487L, -60488L,60489L,60490L,60491L,60492L,60493L,60494L,60495L,60496L,60497L, -60498L,60499L,60500L,60501L,60502L,60503L,60504L,60505L,60506L,60507L, -60508L,60509L,60510L,60511L,60512L,60513L,60514L,60515L,60516L,60517L, -60518L,60519L,60520L,60521L,60522L,60523L,60524L,60525L,60526L,60527L, -60528L,60529L,60530L,60531L,60532L,60533L,60534L,60535L,60536L,60537L, -60538L,60539L,60540L,60541L,60542L,60543L,60544L,60545L,60546L,60547L, -60548L,60549L,60550L,60551L,60552L,60553L,60554L,60555L,60556L,60557L, -60558L,60559L,60560L,60561L,60562L,60563L,60564L,60565L,60566L,60567L, -60568L,60569L,60570L,60571L,60572L,60573L,60574L,60575L,60576L,60577L, -60578L,60579L,60580L,60581L,60582L,60583L,60584L,60585L,60586L,60587L, -60588L,60589L,60590L,60591L,60592L,60593L,60594L,60595L,60596L,60597L, -60598L,60599L,60600L,60601L,60602L,60603L,60604L,60605L,60606L,60607L, -60608L,60609L,60610L,60611L,60612L,60613L,60614L,60615L,60616L,60617L, -60618L,60619L,60620L,60621L,60622L,60623L,60624L,60625L,60626L,60627L, -60628L,60629L,60630L,60631L,60632L,60633L,60634L,60635L,60636L,60637L, -60638L,60639L,60640L,60641L,60642L,60643L,60644L,60645L,60646L,60647L, -60648L,60649L,60650L,60651L,60652L,60653L,60654L,60655L,60656L,60657L, -60658L,60659L,60660L,60661L,60662L,60663L,60664L,60665L,60666L,60667L, -60668L,60669L,60670L,60671L,60672L,60673L,60674L,60675L,60676L,60677L, -60678L,60679L,60680L,60681L,60682L,60683L,60684L,60685L,60686L,60687L, -60688L,60689L,60690L,60691L,60692L,60693L,60694L,60695L,60696L,60697L, -60698L,60699L,60700L,60701L,60702L,60703L,60704L,60705L,60706L,60707L, -60708L,60709L,60710L,60711L,60712L,60713L,60714L,60715L,60716L,60717L, -60718L,60719L,60720L,60721L,60722L,60723L,60724L,60725L,60726L,60727L, -60728L,60729L,60730L,60731L,60732L,60733L,60734L,60735L,60736L,60737L, -60738L,60739L,60740L,60741L,60742L,60743L,60744L,60745L,60746L,60747L, -60748L,60749L,60750L,60751L,60752L,60753L,60754L,60755L,60756L,60757L, -60758L,60759L,60760L,60761L,60762L,60763L,60764L,60765L,60766L,60767L, -60768L,60769L,60770L,60771L,60772L,60773L,60774L,60775L,60776L,60777L, -60778L,60779L,60780L,60781L,60782L,60783L,60784L,60785L,60786L,60787L, -60788L,60789L,60790L,60791L,60792L,60793L,60794L,60795L,60796L,60797L, -60798L,60799L,60800L,60801L,60802L,60803L,60804L,60805L,60806L,60807L, -60808L,60809L,60810L,60811L,60812L,60813L,60814L,60815L,60816L,60817L, -60818L,60819L,60820L,60821L,60822L,60823L,60824L,60825L,60826L,60827L, -60828L,60829L,60830L,60831L,60832L,60833L,60834L,60835L,60836L,60837L, -60838L,60839L,60840L,60841L,60842L,60843L,60844L,60845L,60846L,60847L, -60848L,60849L,60850L,60851L,60852L,60853L,60854L,60855L,60856L,60857L, -60858L,60859L,60860L,60861L,60862L,60863L,60864L,60865L,60866L,60867L, -60868L,60869L,60870L,60871L,60872L,60873L,60874L,60875L,60876L,60877L, -60878L,60879L,60880L,60881L,60882L,60883L,60884L,60885L,60886L,60887L, -60888L,60889L,60890L,60891L,60892L,60893L,60894L,60895L,60896L,60897L, -60898L,60899L,60900L,60901L,60902L,60903L,60904L,60905L,60906L,60907L, -60908L,60909L,60910L,60911L,60912L,60913L,60914L,60915L,60916L,60917L, -60918L,60919L,60920L,60921L,60922L,60923L,60924L,60925L,60926L,60927L, -60928L,60929L,60930L,60931L,60932L,60933L,60934L,60935L,60936L,60937L, -60938L,60939L,60940L,60941L,60942L,60943L,60944L,60945L,60946L,60947L, -60948L,60949L,60950L,60951L,60952L,60953L,60954L,60955L,60956L,60957L, -60958L,60959L,60960L,60961L,60962L,60963L,60964L,60965L,60966L,60967L, -60968L,60969L,60970L,60971L,60972L,60973L,60974L,60975L,60976L,60977L, -60978L,60979L,60980L,60981L,60982L,60983L,60984L,60985L,60986L,60987L, -60988L,60989L,60990L,60991L,60992L,60993L,60994L,60995L,60996L,60997L, -60998L,60999L,61000L,61001L,61002L,61003L,61004L,61005L,61006L,61007L, -61008L,61009L,61010L,61011L,61012L,61013L,61014L,61015L,61016L,61017L, -61018L,61019L,61020L,61021L,61022L,61023L,61024L,61025L,61026L,61027L, -61028L,61029L,61030L,61031L,61032L,61033L,61034L,61035L,61036L,61037L, -61038L,61039L,61040L,61041L,61042L,61043L,61044L,61045L,61046L,61047L, -61048L,61049L,61050L,61051L,61052L,61053L,61054L,61055L,61056L,61057L, -61058L,61059L,61060L,61061L,61062L,61063L,61064L,61065L,61066L,61067L, -61068L,61069L,61070L,61071L,61072L,61073L,61074L,61075L,61076L,61077L, -61078L,61079L,61080L,61081L,61082L,61083L,61084L,61085L,61086L,61087L, -61088L,61089L,61090L,61091L,61092L,61093L,61094L,61095L,61096L,61097L, -61098L,61099L,61100L,61101L,61102L,61103L,61104L,61105L,61106L,61107L, -61108L,61109L,61110L,61111L,61112L,61113L,61114L,61115L,61116L,61117L, -61118L,61119L,61120L,61121L,61122L,61123L,61124L,61125L,61126L,61127L, -61128L,61129L,61130L,61131L,61132L,61133L,61134L,61135L,61136L,61137L, -61138L,61139L,61140L,61141L,61142L,61143L,61144L,61145L,61146L,61147L, -61148L,61149L,61150L,61151L,61152L,61153L,61154L,61155L,61156L,61157L, -61158L,61159L,61160L,61161L,61162L,61163L,61164L,61165L,61166L,61167L, -61168L,61169L,61170L,61171L,61172L,61173L,61174L,61175L,61176L,61177L, -61178L,61179L,61180L,61181L,61182L,61183L,61184L,61185L,61186L,61187L, -61188L,61189L,61190L,61191L,61192L,61193L,61194L,61195L,61196L,61197L, -61198L,61199L,61200L,61201L,61202L,61203L,61204L,61205L,61206L,61207L, -61208L,61209L,61210L,61211L,61212L,61213L,61214L,61215L,61216L,61217L, -61218L,61219L,61220L,61221L,61222L,61223L,61224L,61225L,61226L,61227L, -61228L,61229L,61230L,61231L,61232L,61233L,61234L,61235L,61236L,61237L, -61238L,61239L,61240L,61241L,61242L,61243L,61244L,61245L,61246L,61247L, -61248L,61249L,61250L,61251L,61252L,61253L,61254L,61255L,61256L,61257L, -61258L,61259L,61260L,61261L,61262L,61263L,61264L,61265L,61266L,61267L, -61268L,61269L,61270L,61271L,61272L,61273L,61274L,61275L,61276L,61277L, -61278L,61279L,61280L,61281L,61282L,61283L,61284L,61285L,61286L,61287L, -61288L,61289L,61290L,61291L,61292L,61293L,61294L,61295L,61296L,61297L, -61298L,61299L,61300L,61301L,61302L,61303L,61304L,61305L,61306L,61307L, -61308L,61309L,61310L,61311L,61312L,61313L,61314L,61315L,61316L,61317L, -61318L,61319L,61320L,61321L,61322L,61323L,61324L,61325L,61326L,61327L, -61328L,61329L,61330L,61331L,61332L,61333L,61334L,61335L,61336L,61337L, -61338L,61339L,61340L,61341L,61342L,61343L,61344L,61345L,61346L,61347L, -61348L,61349L,61350L,61351L,61352L,61353L,61354L,61355L,61356L,61357L, -61358L,61359L,61360L,61361L,61362L,61363L,61364L,61365L,61366L,61367L, -61368L,61369L,61370L,61371L,61372L,61373L,61374L,61375L,61376L,61377L, -61378L,61379L,61380L,61381L,61382L,61383L,61384L,61385L,61386L,61387L, -61388L,61389L,61390L,61391L,61392L,61393L,61394L,61395L,61396L,61397L, -61398L,61399L,61400L,61401L,61402L,61403L,61404L,61405L,61406L,61407L, -61408L,61409L,61410L,61411L,61412L,61413L,61414L,61415L,61416L,61417L, -61418L,61419L,61420L,61421L,61422L,61423L,61424L,61425L,61426L,61427L, -61428L,61429L,61430L,61431L,61432L,61433L,61434L,61435L,61436L,61437L, -61438L,61439L,61440L,61441L,61442L,61443L,61444L,61445L,61446L,61447L, -61448L,61449L,61450L,61451L,61452L,61453L,61454L,61455L,61456L,61457L, -61458L,61459L,61460L,61461L,61462L,61463L,61464L,61465L,61466L,61467L, -61468L,61469L,61470L,61471L,61472L,61473L,61474L,61475L,61476L,61477L, -61478L,61479L,61480L,61481L,61482L,61483L,61484L,61485L,61486L,61487L, -61488L,61489L,61490L,61491L,61492L,61493L,61494L,61495L,61496L,61497L, -61498L,61499L,61500L,61501L,61502L,61503L,61504L,61505L,61506L,61507L, -61508L,61509L,61510L,61511L,61512L,61513L,61514L,61515L,61516L,61517L, -61518L,61519L,61520L,61521L,61522L,61523L,61524L,61525L,61526L,61527L, -61528L,61529L,61530L,61531L,61532L,61533L,61534L,61535L,61536L,61537L, -61538L,61539L,61540L,61541L,61542L,61543L,61544L,61545L,61546L,61547L, -61548L,61549L,61550L,61551L,61552L,61553L,61554L,61555L,61556L,61557L, -61558L,61559L,61560L,61561L,61562L,61563L,61564L,61565L,61566L,61567L, -61568L,61569L,61570L,61571L,61572L,61573L,61574L,61575L,61576L,61577L, -61578L,61579L,61580L,61581L,61582L,61583L,61584L,61585L,61586L,61587L, -61588L,61589L,61590L,61591L,61592L,61593L,61594L,61595L,61596L,61597L, -61598L,61599L,61600L,61601L,61602L,61603L,61604L,61605L,61606L,61607L, -61608L,61609L,61610L,61611L,61612L,61613L,61614L,61615L,61616L,61617L, -61618L,61619L,61620L,61621L,61622L,61623L,61624L,61625L,61626L,61627L, -61628L,61629L,61630L,61631L,61632L,61633L,61634L,61635L,61636L,61637L, -61638L,61639L,61640L,61641L,61642L,61643L,61644L,61645L,61646L,61647L, -61648L,61649L,61650L,61651L,61652L,61653L,61654L,61655L,61656L,61657L, -61658L,61659L,61660L,61661L,61662L,61663L,61664L,61665L,61666L,61667L, -61668L,61669L,61670L,61671L,61672L,61673L,61674L,61675L,61676L,61677L, -61678L,61679L,61680L,61681L,61682L,61683L,61684L,61685L,61686L,61687L, -61688L,61689L,61690L,61691L,61692L,61693L,61694L,61695L,61696L,61697L, -61698L,61699L,61700L,61701L,61702L,61703L,61704L,61705L,61706L,61707L, -61708L,61709L,61710L,61711L,61712L,61713L,61714L,61715L,61716L,61717L, -61718L,61719L,61720L,61721L,61722L,61723L,61724L,61725L,61726L,61727L, -61728L,61729L,61730L,61731L,61732L,61733L,61734L,61735L,61736L,61737L, -61738L,61739L,61740L,61741L,61742L,61743L,61744L,61745L,61746L,61747L, -61748L,61749L,61750L,61751L,61752L,61753L,61754L,61755L,61756L,61757L, -61758L,61759L,61760L,61761L,61762L,61763L,61764L,61765L,61766L,61767L, -61768L,61769L,61770L,61771L,61772L,61773L,61774L,61775L,61776L,61777L, -61778L,61779L,61780L,61781L,61782L,61783L,61784L,61785L,61786L,61787L, -61788L,61789L,61790L,61791L,61792L,61793L,61794L,61795L,61796L,61797L, -61798L,61799L,61800L,61801L,61802L,61803L,61804L,61805L,61806L,61807L, -61808L,61809L,61810L,61811L,61812L,61813L,61814L,61815L,61816L,61817L, -61818L,61819L,61820L,61821L,61822L,61823L,61824L,61825L,61826L,61827L, -61828L,61829L,61830L,61831L,61832L,61833L,61834L,61835L,61836L,61837L, -61838L,61839L,61840L,61841L,61842L,61843L,61844L,61845L,61846L,61847L, -61848L,61849L,61850L,61851L,61852L,61853L,61854L,61855L,61856L,61857L, -61858L,61859L,61860L,61861L,61862L,61863L,61864L,61865L,61866L,61867L, -61868L,61869L,61870L,61871L,61872L,61873L,61874L,61875L,61876L,61877L, -61878L,61879L,61880L,61881L,61882L,61883L,61884L,61885L,61886L,61887L, -61888L,61889L,61890L,61891L,61892L,61893L,61894L,61895L,61896L,61897L, -61898L,61899L,61900L,61901L,61902L,61903L,61904L,61905L,61906L,61907L, -61908L,61909L,61910L,61911L,61912L,61913L,61914L,61915L,61916L,61917L, -61918L,61919L,61920L,61921L,61922L,61923L,61924L,61925L,61926L,61927L, -61928L,61929L,61930L,61931L,61932L,61933L,61934L,61935L,61936L,61937L, -61938L,61939L,61940L,61941L,61942L,61943L,61944L,61945L,61946L,61947L, -61948L,61949L,61950L,61951L,61952L,61953L,61954L,61955L,61956L,61957L, -61958L,61959L,61960L,61961L,61962L,61963L,61964L,61965L,61966L,61967L, -61968L,61969L,61970L,61971L,61972L,61973L,61974L,61975L,61976L,61977L, -61978L,61979L,61980L,61981L,61982L,61983L,61984L,61985L,61986L,61987L, -61988L,61989L,61990L,61991L,61992L,61993L,61994L,61995L,61996L,61997L, -61998L,61999L,62000L,62001L,62002L,62003L,62004L,62005L,62006L,62007L, -62008L,62009L,62010L,62011L,62012L,62013L,62014L,62015L,62016L,62017L, -62018L,62019L,62020L,62021L,62022L,62023L,62024L,62025L,62026L,62027L, -62028L,62029L,62030L,62031L,62032L,62033L,62034L,62035L,62036L,62037L, -62038L,62039L,62040L,62041L,62042L,62043L,62044L,62045L,62046L,62047L, -62048L,62049L,62050L,62051L,62052L,62053L,62054L,62055L,62056L,62057L, -62058L,62059L,62060L,62061L,62062L,62063L,62064L,62065L,62066L,62067L, -62068L,62069L,62070L,62071L,62072L,62073L,62074L,62075L,62076L,62077L, -62078L,62079L,62080L,62081L,62082L,62083L,62084L,62085L,62086L,62087L, -62088L,62089L,62090L,62091L,62092L,62093L,62094L,62095L,62096L,62097L, -62098L,62099L,62100L,62101L,62102L,62103L,62104L,62105L,62106L,62107L, -62108L,62109L,62110L,62111L,62112L,62113L,62114L,62115L,62116L,62117L, -62118L,62119L,62120L,62121L,62122L,62123L,62124L,62125L,62126L,62127L, -62128L,62129L,62130L,62131L,62132L,62133L,62134L,62135L,62136L,62137L, -62138L,62139L,62140L,62141L,62142L,62143L,62144L,62145L,62146L,62147L, -62148L,62149L,62150L,62151L,62152L,62153L,62154L,62155L,62156L,62157L, -62158L,62159L,62160L,62161L,62162L,62163L,62164L,62165L,62166L,62167L, -62168L,62169L,62170L,62171L,62172L,62173L,62174L,62175L,62176L,62177L, -62178L,62179L,62180L,62181L,62182L,62183L,62184L,62185L,62186L,62187L, -62188L,62189L,62190L,62191L,62192L,62193L,62194L,62195L,62196L,62197L, -62198L,62199L,62200L,62201L,62202L,62203L,62204L,62205L,62206L,62207L, -62208L,62209L,62210L,62211L,62212L,62213L,62214L,62215L,62216L,62217L, -62218L,62219L,62220L,62221L,62222L,62223L,62224L,62225L,62226L,62227L, -62228L,62229L,62230L,62231L,62232L,62233L,62234L,62235L,62236L,62237L, -62238L,62239L,62240L,62241L,62242L,62243L,62244L,62245L,62246L,62247L, -62248L,62249L,62250L,62251L,62252L,62253L,62254L,62255L,62256L,62257L, -62258L,62259L,62260L,62261L,62262L,62263L,62264L,62265L,62266L,62267L, -62268L,62269L,62270L,62271L,62272L,62273L,62274L,62275L,62276L,62277L, -62278L,62279L,62280L,62281L,62282L,62283L,62284L,62285L,62286L,62287L, -62288L,62289L,62290L,62291L,62292L,62293L,62294L,62295L,62296L,62297L, -62298L,62299L,62300L,62301L,62302L,62303L,62304L,62305L,62306L,62307L, -62308L,62309L,62310L,62311L,62312L,62313L,62314L,62315L,62316L,62317L, -62318L,62319L,62320L,62321L,62322L,62323L,62324L,62325L,62326L,62327L, -62328L,62329L,62330L,62331L,62332L,62333L,62334L,62335L,62336L,62337L, -62338L,62339L,62340L,62341L,62342L,62343L,62344L,62345L,62346L,62347L, -62348L,62349L,62350L,62351L,62352L,62353L,62354L,62355L,62356L,62357L, -62358L,62359L,62360L,62361L,62362L,62363L,62364L,62365L,62366L,62367L, -62368L,62369L,62370L,62371L,62372L,62373L,62374L,62375L,62376L,62377L, -62378L,62379L,62380L,62381L,62382L,62383L,62384L,62385L,62386L,62387L, -62388L,62389L,62390L,62391L,62392L,62393L,62394L,62395L,62396L,62397L, -62398L,62399L,62400L,62401L,62402L,62403L,62404L,62405L,62406L,62407L, -62408L,62409L,62410L,62411L,62412L,62413L,62414L,62415L,62416L,62417L, -62418L,62419L,62420L,62421L,62422L,62423L,62424L,62425L,62426L,62427L, -62428L,62429L,62430L,62431L,62432L,62433L,62434L,62435L,62436L,62437L, -62438L,62439L,62440L,62441L,62442L,62443L,62444L,62445L,62446L,62447L, -62448L,62449L,62450L,62451L,62452L,62453L,62454L,62455L,62456L,62457L, -62458L,62459L,62460L,62461L,62462L,62463L,62464L,62465L,62466L,62467L, -62468L,62469L,62470L,62471L,62472L,62473L,62474L,62475L,62476L,62477L, -62478L,62479L,62480L,62481L,62482L,62483L,62484L,62485L,62486L,62487L, -62488L,62489L,62490L,62491L,62492L,62493L,62494L,62495L,62496L,62497L, -62498L,62499L,62500L,62501L,62502L,62503L,62504L,62505L,62506L,62507L, -62508L,62509L,62510L,62511L,62512L,62513L,62514L,62515L,62516L,62517L, -62518L,62519L,62520L,62521L,62522L,62523L,62524L,62525L,62526L,62527L, -62528L,62529L,62530L,62531L,62532L,62533L,62534L,62535L,62536L,62537L, -62538L,62539L,62540L,62541L,62542L,62543L,62544L,62545L,62546L,62547L, -62548L,62549L,62550L,62551L,62552L,62553L,62554L,62555L,62556L,62557L, -62558L,62559L,62560L,62561L,62562L,62563L,62564L,62565L,62566L,62567L, -62568L,62569L,62570L,62571L,62572L,62573L,62574L,62575L,62576L,62577L, -62578L,62579L,62580L,62581L,62582L,62583L,62584L,62585L,62586L,62587L, -62588L,62589L,62590L,62591L,62592L,62593L,62594L,62595L,62596L,62597L, -62598L,62599L,62600L,62601L,62602L,62603L,62604L,62605L,62606L,62607L, -62608L,62609L,62610L,62611L,62612L,62613L,62614L,62615L,62616L,62617L, -62618L,62619L,62620L,62621L,62622L,62623L,62624L,62625L,62626L,62627L, -62628L,62629L,62630L,62631L,62632L,62633L,62634L,62635L,62636L,62637L, -62638L,62639L,62640L,62641L,62642L,62643L,62644L,62645L,62646L,62647L, -62648L,62649L,62650L,62651L,62652L,62653L,62654L,62655L,62656L,62657L, -62658L,62659L,62660L,62661L,62662L,62663L,62664L,62665L,62666L,62667L, -62668L,62669L,62670L,62671L,62672L,62673L,62674L,62675L,62676L,62677L, -62678L,62679L,62680L,62681L,62682L,62683L,62684L,62685L,62686L,62687L, -62688L,62689L,62690L,62691L,62692L,62693L,62694L,62695L,62696L,62697L, -62698L,62699L,62700L,62701L,62702L,62703L,62704L,62705L,62706L,62707L, -62708L,62709L,62710L,62711L,62712L,62713L,62714L,62715L,62716L,62717L, -62718L,62719L,62720L,62721L,62722L,62723L,62724L,62725L,62726L,62727L, -62728L,62729L,62730L,62731L,62732L,62733L,62734L,62735L,62736L,62737L, -62738L,62739L,62740L,62741L,62742L,62743L,62744L,62745L,62746L,62747L, -62748L,62749L,62750L,62751L,62752L,62753L,62754L,62755L,62756L,62757L, -62758L,62759L,62760L,62761L,62762L,62763L,62764L,62765L,62766L,62767L, -62768L,62769L,62770L,62771L,62772L,62773L,62774L,62775L,62776L,62777L, -62778L,62779L,62780L,62781L,62782L,62783L,62784L,62785L,62786L,62787L, -62788L,62789L,62790L,62791L,62792L,62793L,62794L,62795L,62796L,62797L, -62798L,62799L,62800L,62801L,62802L,62803L,62804L,62805L,62806L,62807L, -62808L,62809L,62810L,62811L,62812L,62813L,62814L,62815L,62816L,62817L, -62818L,62819L,62820L,62821L,62822L,62823L,62824L,62825L,62826L,62827L, -62828L,62829L,62830L,62831L,62832L,62833L,62834L,62835L,62836L,62837L, -62838L,62839L,62840L,62841L,62842L,62843L,62844L,62845L,62846L,62847L, -62848L,62849L,62850L,62851L,62852L,62853L,62854L,62855L,62856L,62857L, -62858L,62859L,62860L,62861L,62862L,62863L,62864L,62865L,62866L,62867L, -62868L,62869L,62870L,62871L,62872L,62873L,62874L,62875L,62876L,62877L, -62878L,62879L,62880L,62881L,62882L,62883L,62884L,62885L,62886L,62887L, -62888L,62889L,62890L,62891L,62892L,62893L,62894L,62895L,62896L,62897L, -62898L,62899L,62900L,62901L,62902L,62903L,62904L,62905L,62906L,62907L, -62908L,62909L,62910L,62911L,62912L,62913L,62914L,62915L,62916L,62917L, -62918L,62919L,62920L,62921L,62922L,62923L,62924L,62925L,62926L,62927L, -62928L,62929L,62930L,62931L,62932L,62933L,62934L,62935L,62936L,62937L, -62938L,62939L,62940L,62941L,62942L,62943L,62944L,62945L,62946L,62947L, -62948L,62949L,62950L,62951L,62952L,62953L,62954L,62955L,62956L,62957L, -62958L,62959L,62960L,62961L,62962L,62963L,62964L,62965L,62966L,62967L, -62968L,62969L,62970L,62971L,62972L,62973L,62974L,62975L,62976L,62977L, -62978L,62979L,62980L,62981L,62982L,62983L,62984L,62985L,62986L,62987L, -62988L,62989L,62990L,62991L,62992L,62993L,62994L,62995L,62996L,62997L, -62998L,62999L,63000L,63001L,63002L,63003L,63004L,63005L,63006L,63007L, -63008L,63009L,63010L,63011L,63012L,63013L,63014L,63015L,63016L,63017L, -63018L,63019L,63020L,63021L,63022L,63023L,63024L,63025L,63026L,63027L, -63028L,63029L,63030L,63031L,63032L,63033L,63034L,63035L,63036L,63037L, -63038L,63039L,63040L,63041L,63042L,63043L,63044L,63045L,63046L,63047L, -63048L,63049L,63050L,63051L,63052L,63053L,63054L,63055L,63056L,63057L, -63058L,63059L,63060L,63061L,63062L,63063L,63064L,63065L,63066L,63067L, -63068L,63069L,63070L,63071L,63072L,63073L,63074L,63075L,63076L,63077L, -63078L,63079L,63080L,63081L,63082L,63083L,63084L,63085L,63086L,63087L, -63088L,63089L,63090L,63091L,63092L,63093L,63094L,63095L,63096L,63097L, -63098L,63099L,63100L,63101L,63102L,63103L,63104L,63105L,63106L,63107L, -63108L,63109L,63110L,63111L,63112L,63113L,63114L,63115L,63116L,63117L, -63118L,63119L,63120L,63121L,63122L,63123L,63124L,63125L,63126L,63127L, -63128L,63129L,63130L,63131L,63132L,63133L,63134L,63135L,63136L,63137L, -63138L,63139L,63140L,63141L,63142L,63143L,63144L,63145L,63146L,63147L, -63148L,63149L,63150L,63151L,63152L,63153L,63154L,63155L,63156L,63157L, -63158L,63159L,63160L,63161L,63162L,63163L,63164L,63165L,63166L,63167L, -63168L,63169L,63170L,63171L,63172L,63173L,63174L,63175L,63176L,63177L, -63178L,63179L,63180L,63181L,63182L,63183L,63184L,63185L,63186L,63187L, -63188L,63189L,63190L,63191L,63192L,63193L,63194L,63195L,63196L,63197L, -63198L,63199L,63200L,63201L,63202L,63203L,63204L,63205L,63206L,63207L, -63208L,63209L,63210L,63211L,63212L,63213L,63214L,63215L,63216L,63217L, -63218L,63219L,63220L,63221L,63222L,63223L,63224L,63225L,63226L,63227L, -63228L,63229L,63230L,63231L,63232L,63233L,63234L,63235L,63236L,63237L, -63238L,63239L,63240L,63241L,63242L,63243L,63244L,63245L,63246L,63247L, -63248L,63249L,63250L,63251L,63252L,63253L,63254L,63255L,63256L,63257L, -63258L,63259L,63260L,63261L,63262L,63263L,63264L,63265L,63266L,63267L, -63268L,63269L,63270L,63271L,63272L,63273L,63274L,63275L,63276L,63277L, -63278L,63279L,63280L,63281L,63282L,63283L,63284L,63285L,63286L,63287L, -63288L,63289L,63290L,63291L,63292L,63293L,63294L,63295L,63296L,63297L, -63298L,63299L,63300L,63301L,63302L,63303L,63304L,63305L,63306L,63307L, -63308L,63309L,63310L,63311L,63312L,63313L,63314L,63315L,63316L,63317L, -63318L,63319L,63320L,63321L,63322L,63323L,63324L,63325L,63326L,63327L, -63328L,63329L,63330L,63331L,63332L,63333L,63334L,63335L,63336L,63337L, -63338L,63339L,63340L,63341L,63342L,63343L,63344L,63345L,63346L,63347L, -63348L,63349L,63350L,63351L,63352L,63353L,63354L,63355L,63356L,63357L, -63358L,63359L,63360L,63361L,63362L,63363L,63364L,63365L,63366L,63367L, -63368L,63369L,63370L,63371L,63372L,63373L,63374L,63375L,63376L,63377L, -63378L,63379L,63380L,63381L,63382L,63383L,63384L,63385L,63386L,63387L, -63388L,63389L,63390L,63391L,63392L,63393L,63394L,63395L,63396L,63397L, -63398L,63399L,63400L,63401L,63402L,63403L,63404L,63405L,63406L,63407L, -63408L,63409L,63410L,63411L,63412L,63413L,63414L,63415L,63416L,63417L, -63418L,63419L,63420L,63421L,63422L,63423L,63424L,63425L,63426L,63427L, -63428L,63429L,63430L,63431L,63432L,63433L,63434L,63435L,63436L,63437L, -63438L,63439L,63440L,63441L,63442L,63443L,63444L,63445L,63446L,63447L, -63448L,63449L,63450L,63451L,63452L,63453L,63454L,63455L,63456L,63457L, -63458L,63459L,63460L,63461L,63462L,63463L,63464L,63465L,63466L,63467L, -63468L,63469L,63470L,63471L,63472L,63473L,63474L,63475L,63476L,63477L, -63478L,63479L,63480L,63481L,63482L,63483L,63484L,63485L,63486L,63487L, -63488L,63489L,63490L,63491L,63492L,63493L,63494L,63495L,63496L,63497L, -63498L,63499L,63500L,63501L,63502L,63503L,63504L,63505L,63506L,63507L, -63508L,63509L,63510L,63511L,63512L,63513L,63514L,63515L,63516L,63517L, -63518L,63519L,63520L,63521L,63522L,63523L,63524L,63525L,63526L,63527L, -63528L,63529L,63530L,63531L,63532L,63533L,63534L,63535L,63536L,63537L, -63538L,63539L,63540L,63541L,63542L,63543L,63544L,63545L,63546L,63547L, -63548L,63549L,63550L,63551L,63552L,63553L,63554L,63555L,63556L,63557L, -63558L,63559L,63560L,63561L,63562L,63563L,63564L,63565L,63566L,63567L, -63568L,63569L,63570L,63571L,63572L,63573L,63574L,63575L,63576L,63577L, -63578L,63579L,63580L,63581L,63582L,63583L,63584L,63585L,63586L,63587L, -63588L,63589L,63590L,63591L,63592L,63593L,63594L,63595L,63596L,63597L, -63598L,63599L,63600L,63601L,63602L,63603L,63604L,63605L,63606L,63607L, -63608L,63609L,63610L,63611L,63612L,63613L,63614L,63615L,63616L,63617L, -63618L,63619L,63620L,63621L,63622L,63623L,63624L,63625L,63626L,63627L, -63628L,63629L,63630L,63631L,63632L,63633L,63634L,63635L,63636L,63637L, -63638L,63639L,63640L,63641L,63642L,63643L,63644L,63645L,63646L,63647L, -63648L,63649L,63650L,63651L,63652L,63653L,63654L,63655L,63656L,63657L, -63658L,63659L,63660L,63661L,63662L,63663L,63664L,63665L,63666L,63667L, -63668L,63669L,63670L,63671L,63672L,63673L,63674L,63675L,63676L,63677L, -63678L,63679L,63680L,63681L,63682L,63683L,63684L,63685L,63686L,63687L, -63688L,63689L,63690L,63691L,63692L,63693L,63694L,63695L,63696L,63697L, -63698L,63699L,63700L,63701L,63702L,63703L,63704L,63705L,63706L,63707L, -63708L,63709L,63710L,63711L,63712L,63713L,63714L,63715L,63716L,63717L, -63718L,63719L,63720L,63721L,63722L,63723L,63724L,63725L,63726L,63727L, -63728L,63729L,63730L,63731L,63732L,63733L,63734L,63735L,63736L,63737L, -63738L,63739L,63740L,63741L,63742L,63743L,63744L,63745L,63746L,63747L, -63748L,63749L,63750L,63751L,63752L,63753L,63754L,63755L,63756L,63757L, -63758L,63759L,63760L,63761L,63762L,63763L,63764L,63765L,63766L,63767L, -63768L,63769L,63770L,63771L,63772L,63773L,63774L,63775L,63776L,63777L, -63778L,63779L,63780L,63781L,63782L,63783L,63784L,63785L,63786L,63787L, -63788L,63789L,63790L,63791L,63792L,63793L,63794L,63795L,63796L,63797L, -63798L,63799L,63800L,63801L,63802L,63803L,63804L,63805L,63806L,63807L, -63808L,63809L,63810L,63811L,63812L,63813L,63814L,63815L,63816L,63817L, -63818L,63819L,63820L,63821L,63822L,63823L,63824L,63825L,63826L,63827L, -63828L,63829L,63830L,63831L,63832L,63833L,63834L,63835L,63836L,63837L, -63838L,63839L,63840L,63841L,63842L,63843L,63844L,63845L,63846L,63847L, -63848L,63849L,63850L,63851L,63852L,63853L,63854L,63855L,63856L,63857L, -63858L,63859L,63860L,63861L,63862L,63863L,63864L,63865L,63866L,63867L, -63868L,63869L,63870L,63871L,63872L,63873L,63874L,63875L,63876L,63877L, -63878L,63879L,63880L,63881L,63882L,63883L,63884L,63885L,63886L,63887L, -63888L,63889L,63890L,63891L,63892L,63893L,63894L,63895L,63896L,63897L, -63898L,63899L,63900L,63901L,63902L,63903L,63904L,63905L,63906L,63907L, -63908L,63909L,63910L,63911L,63912L,63913L,63914L,63915L,63916L,63917L, -63918L,63919L,63920L,63921L,63922L,63923L,63924L,63925L,63926L,63927L, -63928L,63929L,63930L,63931L,63932L,63933L,63934L,63935L,63936L,63937L, -63938L,63939L,63940L,63941L,63942L,63943L,63944L,63945L,63946L,63947L, -63948L,63949L,63950L,63951L,63952L,63953L,63954L,63955L,63956L,63957L, -63958L,63959L,63960L,63961L,63962L,63963L,63964L,63965L,63966L,63967L, -63968L,63969L,63970L,63971L,63972L,63973L,63974L,63975L,63976L,63977L, -63978L,63979L,63980L,63981L,63982L,63983L,63984L,63985L,63986L,63987L, -63988L,63989L,63990L,63991L,63992L,63993L,63994L,63995L,63996L,63997L, -63998L,63999L,64000L,64001L,64002L,64003L,64004L,64005L,64006L,64007L, -64008L,64009L,64010L,64011L,64012L,64013L,64014L,64015L,64016L,64017L, -64018L,64019L,64020L,64021L,64022L,64023L,64024L,64025L,64026L,64027L, -64028L,64029L,64030L,64031L,64032L,64033L,64034L,64035L,64036L,64037L, -64038L,64039L,64040L,64041L,64042L,64043L,64044L,64045L,64046L,64047L, -64048L,64049L,64050L,64051L,64052L,64053L,64054L,64055L,64056L,64057L, -64058L,64059L,64060L,64061L,64062L,64063L,64064L,64065L,64066L,64067L, -64068L,64069L,64070L,64071L,64072L,64073L,64074L,64075L,64076L,64077L, -64078L,64079L,64080L,64081L,64082L,64083L,64084L,64085L,64086L,64087L, -64088L,64089L,64090L,64091L,64092L,64093L,64094L,64095L,64096L,64097L, -64098L,64099L,64100L,64101L,64102L,64103L,64104L,64105L,64106L,64107L, -64108L,64109L,64110L,64111L,64112L,64113L,64114L,64115L,64116L,64117L, -64118L,64119L,64120L,64121L,64122L,64123L,64124L,64125L,64126L,64127L, -64128L,64129L,64130L,64131L,64132L,64133L,64134L,64135L,64136L,64137L, -64138L,64139L,64140L,64141L,64142L,64143L,64144L,64145L,64146L,64147L, -64148L,64149L,64150L,64151L,64152L,64153L,64154L,64155L,64156L,64157L, -64158L,64159L,64160L,64161L,64162L,64163L,64164L,64165L,64166L,64167L, -64168L,64169L,64170L,64171L,64172L,64173L,64174L,64175L,64176L,64177L, -64178L,64179L,64180L,64181L,64182L,64183L,64184L,64185L,64186L,64187L, -64188L,64189L,64190L,64191L,64192L,64193L,64194L,64195L,64196L,64197L, -64198L,64199L,64200L,64201L,64202L,64203L,64204L,64205L,64206L,64207L, -64208L,64209L,64210L,64211L,64212L,64213L,64214L,64215L,64216L,64217L, -64218L,64219L,64220L,64221L,64222L,64223L,64224L,64225L,64226L,64227L, -64228L,64229L,64230L,64231L,64232L,64233L,64234L,64235L,64236L,64237L, -64238L,64239L,64240L,64241L,64242L,64243L,64244L,64245L,64246L,64247L, -64248L,64249L,64250L,64251L,64252L,64253L,64254L,64255L,64256L,64257L, -64258L,64259L,64260L,64261L,64262L,64263L,64264L,64265L,64266L,64267L, -64268L,64269L,64270L,64271L,64272L,64273L,64274L,64275L,64276L,64277L, -64278L,64279L,64280L,64281L,64282L,64283L,64284L,64285L,64286L,64287L, -64288L,64289L,64290L,64291L,64292L,64293L,64294L,64295L,64296L,64297L, -64298L,64299L,64300L,64301L,64302L,64303L,64304L,64305L,64306L,64307L, -64308L,64309L,64310L,64311L,64312L,64313L,64314L,64315L,64316L,64317L, -64318L,64319L,64320L,64321L,64322L,64323L,64324L,64325L,64326L,64327L, -64328L,64329L,64330L,64331L,64332L,64333L,64334L,64335L,64336L,64337L, -64338L,64339L,64340L,64341L,64342L,64343L,64344L,64345L,64346L,64347L, -64348L,64349L,64350L,64351L,64352L,64353L,64354L,64355L,64356L,64357L, -64358L,64359L,64360L,64361L,64362L,64363L,64364L,64365L,64366L,64367L, -64368L,64369L,64370L,64371L,64372L,64373L,64374L,64375L,64376L,64377L, -64378L,64379L,64380L,64381L,64382L,64383L,64384L,64385L,64386L,64387L, -64388L,64389L,64390L,64391L,64392L,64393L,64394L,64395L,64396L,64397L, -64398L,64399L,64400L,64401L,64402L,64403L,64404L,64405L,64406L,64407L, -64408L,64409L,64410L,64411L,64412L,64413L,64414L,64415L,64416L,64417L, -64418L,64419L,64420L,64421L,64422L,64423L,64424L,64425L,64426L,64427L, -64428L,64429L,64430L,64431L,64432L,64433L,64434L,64435L,64436L,64437L, -64438L,64439L,64440L,64441L,64442L,64443L,64444L,64445L,64446L,64447L, -64448L,64449L,64450L,64451L,64452L,64453L,64454L,64455L,64456L,64457L, -64458L,64459L,64460L,64461L,64462L,64463L,64464L,64465L,64466L,64467L, -64468L,64469L,64470L,64471L,64472L,64473L,64474L,64475L,64476L,64477L, -64478L,64479L,64480L,64481L,64482L,64483L,64484L,64485L,64486L,64487L, -64488L,64489L,64490L,64491L,64492L,64493L,64494L,64495L,64496L,64497L, -64498L,64499L,64500L,64501L,64502L,64503L,64504L,64505L,64506L,64507L, -64508L,64509L,64510L,64511L,64512L,64513L,64514L,64515L,64516L,64517L, -64518L,64519L,64520L,64521L,64522L,64523L,64524L,64525L,64526L,64527L, -64528L,64529L,64530L,64531L,64532L,64533L,64534L,64535L,64536L,64537L, -64538L,64539L,64540L,64541L,64542L,64543L,64544L,64545L,64546L,64547L, -64548L,64549L,64550L,64551L,64552L,64553L,64554L,64555L,64556L,64557L, -64558L,64559L,64560L,64561L,64562L,64563L,64564L,64565L,64566L,64567L, -64568L,64569L,64570L,64571L,64572L,64573L,64574L,64575L,64576L,64577L, -64578L,64579L,64580L,64581L,64582L,64583L,64584L,64585L,64586L,64587L, -64588L,64589L,64590L,64591L,64592L,64593L,64594L,64595L,64596L,64597L, -64598L,64599L,64600L,64601L,64602L,64603L,64604L,64605L,64606L,64607L, -64608L,64609L,64610L,64611L,64612L,64613L,64614L,64615L,64616L,64617L, -64618L,64619L,64620L,64621L,64622L,64623L,64624L,64625L,64626L,64627L, -64628L,64629L,64630L,64631L,64632L,64633L,64634L,64635L,64636L,64637L, -64638L,64639L,64640L,64641L,64642L,64643L,64644L,64645L,64646L,64647L, -64648L,64649L,64650L,64651L,64652L,64653L,64654L,64655L,64656L,64657L, -64658L,64659L,64660L,64661L,64662L,64663L,64664L,64665L,64666L,64667L, -64668L,64669L,64670L,64671L,64672L,64673L,64674L,64675L,64676L,64677L, -64678L,64679L,64680L,64681L,64682L,64683L,64684L,64685L,64686L,64687L, -64688L,64689L,64690L,64691L,64692L,64693L,64694L,64695L,64696L,64697L, -64698L,64699L,64700L,64701L,64702L,64703L,64704L,64705L,64706L,64707L, -64708L,64709L,64710L,64711L,64712L,64713L,64714L,64715L,64716L,64717L, -64718L,64719L,64720L,64721L,64722L,64723L,64724L,64725L,64726L,64727L, -64728L,64729L,64730L,64731L,64732L,64733L,64734L,64735L,64736L,64737L, -64738L,64739L,64740L,64741L,64742L,64743L,64744L,64745L,64746L,64747L, -64748L,64749L,64750L,64751L,64752L,64753L,64754L,64755L,64756L,64757L, -64758L,64759L,64760L,64761L,64762L,64763L,64764L,64765L,64766L,64767L, -64768L,64769L,64770L,64771L,64772L,64773L,64774L,64775L,64776L,64777L, -64778L,64779L,64780L,64781L,64782L,64783L,64784L,64785L,64786L,64787L, -64788L,64789L,64790L,64791L,64792L,64793L,64794L,64795L,64796L,64797L, -64798L,64799L,64800L,64801L,64802L,64803L,64804L,64805L,64806L,64807L, -64808L,64809L,64810L,64811L,64812L,64813L,64814L,64815L,64816L,64817L, -64818L,64819L,64820L,64821L,64822L,64823L,64824L,64825L,64826L,64827L, -64828L,64829L,64830L,64831L,64832L,64833L,64834L,64835L,64836L,64837L, -64838L,64839L,64840L,64841L,64842L,64843L,64844L,64845L,64846L,64847L, -64848L,64849L,64850L,64851L,64852L,64853L,64854L,64855L,64856L,64857L, -64858L,64859L,64860L,64861L,64862L,64863L,64864L,64865L,64866L,64867L, -64868L,64869L,64870L,64871L,64872L,64873L,64874L,64875L,64876L,64877L, -64878L,64879L,64880L,64881L,64882L,64883L,64884L,64885L,64886L,64887L, -64888L,64889L,64890L,64891L,64892L,64893L,64894L,64895L,64896L,64897L, -64898L,64899L,64900L,64901L,64902L,64903L,64904L,64905L,64906L,64907L, -64908L,64909L,64910L,64911L,64912L,64913L,64914L,64915L,64916L,64917L, -64918L,64919L,64920L,64921L,64922L,64923L,64924L,64925L,64926L,64927L, -64928L,64929L,64930L,64931L,64932L,64933L,64934L,64935L,64936L,64937L, -64938L,64939L,64940L,64941L,64942L,64943L,64944L,64945L,64946L,64947L, -64948L,64949L,64950L,64951L,64952L,64953L,64954L,64955L,64956L,64957L, -64958L,64959L,64960L,64961L,64962L,64963L,64964L,64965L,64966L,64967L, -64968L,64969L,64970L,64971L,64972L,64973L,64974L,64975L,64976L,64977L, -64978L,64979L,64980L,64981L,64982L,64983L,64984L,64985L,64986L,64987L, -64988L,64989L,64990L,64991L,64992L,64993L,64994L,64995L,64996L,64997L, -64998L,64999L,65000L,65001L,65002L,65003L,65004L,65005L,65006L,65007L, -65008L,65009L,65010L,65011L,65012L,65013L,65014L,65015L,65016L,65017L, -65018L,65019L,65020L,65021L,65022L,65023L,65024L,65025L,65026L,65027L, -65028L,65029L,65030L,65031L,65032L,65033L,65034L,65035L,65036L,65037L, -65038L,65039L,65040L,65041L,65042L,65043L,65044L,65045L,65046L,65047L, -65048L,65049L,65050L,65051L,65052L,65053L,65054L,65055L,65056L,65057L, -65058L,65059L,65060L,65061L,65062L,65063L,65064L,65065L,65066L,65067L, -65068L,65069L,65070L,65071L,65072L,65073L,65074L,65075L,65076L,65077L, -65078L,65079L,65080L,65081L,65082L,65083L,65084L,65085L,65086L,65087L, -65088L,65089L,65090L,65091L,65092L,65093L,65094L,65095L,65096L,65097L, -65098L,65099L,65100L,65101L,65102L,65103L,65104L,65105L,65106L,65107L, -65108L,65109L,65110L,65111L,65112L,65113L,65114L,65115L,65116L,65117L, -65118L,65119L,65120L,65121L,65122L,65123L,65124L,65125L,65126L,65127L, -65128L,65129L,65130L,65131L,65132L,65133L,65134L,65135L,65136L,65137L, -65138L,65139L,65140L,65141L,65142L,65143L,65144L,65145L,65146L,65147L, -65148L,65149L,65150L,65151L,65152L,65153L,65154L,65155L,65156L,65157L, -65158L,65159L,65160L,65161L,65162L,65163L,65164L,65165L,65166L,65167L, -65168L,65169L,65170L,65171L,65172L,65173L,65174L,65175L,65176L,65177L, -65178L,65179L,65180L,65181L,65182L,65183L,65184L,65185L,65186L,65187L, -65188L,65189L,65190L,65191L,65192L,65193L,65194L,65195L,65196L,65197L, -65198L,65199L,65200L,65201L,65202L,65203L,65204L,65205L,65206L,65207L, -65208L,65209L,65210L,65211L,65212L,65213L,65214L,65215L,65216L,65217L, -65218L,65219L,65220L,65221L,65222L,65223L,65224L,65225L,65226L,65227L, -65228L,65229L,65230L,65231L,65232L,65233L,65234L,65235L,65236L,65237L, -65238L,65239L,65240L,65241L,65242L,65243L,65244L,65245L,65246L,65247L, -65248L,65249L,65250L,65251L,65252L,65253L,65254L,65255L,65256L,65257L, -65258L,65259L,65260L,65261L,65262L,65263L,65264L,65265L,65266L,65267L, -65268L,65269L,65270L,65271L,65272L,65273L,65274L,65275L,65276L,65277L, -65278L,65279L,65280L,65281L,65282L,65283L,65284L,65285L,65286L,65287L, -65288L,65289L,65290L,65291L,65292L,65293L,65294L,65295L,65296L,65297L, -65298L,65299L,65300L,65301L,65302L,65303L,65304L,65305L,65306L,65307L, -65308L,65309L,65310L,65311L,65312L,65313L,65314L,65315L,65316L,65317L, -65318L,65319L,65320L,65321L,65322L,65323L,65324L,65325L,65326L,65327L, -65328L,65329L,65330L,65331L,65332L,65333L,65334L,65335L,65336L,65337L, -65338L,65339L,65340L,65341L,65342L,65343L,65344L,65313L,65314L,65315L, -65316L,65317L,65318L,65319L,65320L,65321L,65322L,65323L,65324L,65325L, -65326L,65327L,65328L,65329L,65330L,65331L,65332L,65333L,65334L,65335L, -65336L,65337L,65338L,65371L,65372L,65373L,65374L,65375L,65376L,65377L, -65378L,65379L,65380L,65381L,65382L,65383L,65384L,65385L,65386L,65387L, -65388L,65389L,65390L,65391L,65392L,65393L,65394L,65395L,65396L,65397L, -65398L,65399L,65400L,65401L,65402L,65403L,65404L,65405L,65406L,65407L, -65408L,65409L,65410L,65411L,65412L,65413L,65414L,65415L,65416L,65417L, -65418L,65419L,65420L,65421L,65422L,65423L,65424L,65425L,65426L,65427L, -65428L,65429L,65430L,65431L,65432L,65433L,65434L,65435L,65436L,65437L, -65438L,65439L,65440L,65441L,65442L,65443L,65444L,65445L,65446L,65447L, -65448L,65449L,65450L,65451L,65452L,65453L,65454L,65455L,65456L,65457L, -65458L,65459L,65460L,65461L,65462L,65463L,65464L,65465L,65466L,65467L, -65468L,65469L,65470L,65471L,65472L,65473L,65474L,65475L,65476L,65477L, -65478L,65479L,65480L,65481L,65482L,65483L,65484L,65485L,65486L,65487L, -65488L,65489L,65490L,65491L,65492L,65493L,65494L,65495L,65496L,65497L, -65498L,65499L,65500L,65501L,65502L,65503L,65504L,65505L,65506L,65507L, -65508L,65509L,65510L,65511L,65512L,65513L,65514L,65515L,65516L,65517L, -65518L,65519L,65520L,65521L,65522L,65523L,65524L,65525L,65526L,65527L, -65528L,65529L,65530L,65531L,65532L,65533L,65534L,65535L, -}; -#endif - -#if defined(DUK_USE_REGEXP_CANON_BITMAP) -/* - * Automatically generated by extract_caseconv.py, do not edit! - */ - -const duk_uint8_t duk_unicode_re_canon_bitmap[256] = { -23,0,224,19,1,228,255,255,255,255,255,255,255,255,255,255,255,255,255,127, -255,255,255,255,255,255,255,255,231,247,0,16,255,227,255,255,63,255,255, -255,255,255,255,255,1,252,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -227,193,255,255,255,147,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,251, -}; -#endif -#line 1 "duk_util_bitdecoder.c" -/* - * Bitstream decoder. - */ - -/* #include duk_internal.h -> already included */ - -/* Decode 'bits' bits from the input stream (bits must be 1...24). - * When reading past bitstream end, zeroes are shifted in. The result - * is signed to match duk_bd_decode_flagged. - */ -DUK_INTERNAL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) { - duk_small_int_t shift; - duk_uint32_t mask; - duk_uint32_t tmp; - - /* Note: cannot read more than 24 bits without possibly shifting top bits out. - * Fixable, but adds complexity. - */ - DUK_ASSERT(bits >= 1 && bits <= 24); - - while (ctx->currbits < bits) { -#if 0 - DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)", - (long) bits, (long) ctx->currbits)); -#endif - ctx->currval <<= 8; - if (ctx->offset < ctx->length) { - /* If ctx->offset >= ctx->length, we "shift zeroes in" - * instead of croaking. - */ - ctx->currval |= ctx->data[ctx->offset++]; - } - ctx->currbits += 8; - } -#if 0 - DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx", - (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval)); -#endif - - /* Extract 'top' bits of currval; note that the extracted bits do not need - * to be cleared, we just ignore them on next round. - */ - shift = ctx->currbits - bits; - mask = (((duk_uint32_t) 1U) << bits) - 1U; - tmp = (ctx->currval >> shift) & mask; - ctx->currbits = shift; /* remaining */ - -#if 0 - DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx", - (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval)); -#endif - - return tmp; -} - -DUK_INTERNAL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) { - return (duk_small_uint_t) duk_bd_decode(ctx, 1); -} - -/* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return - * default value. - */ -DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) { - if (duk_bd_decode_flag(ctx)) { - return duk_bd_decode(ctx, bits); - } else { - return def_value; - } -} - -/* Signed variant, allows negative marker value. */ -DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) { - return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value); -} - -/* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */ -DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) { - duk_small_uint_t t; - - /* The bit encoding choices here are based on manual testing against - * the actual varuints generated by genbuiltins.py. - */ - switch (duk_bd_decode(ctx, 2)) { - case 0: - return 0; /* [0,0] */ - case 1: - return duk_bd_decode(ctx, 2) + 1; /* [1,4] */ - case 2: - return duk_bd_decode(ctx, 5) + 5; /* [5,36] */ - default: - t = duk_bd_decode(ctx, 7); - if (t == 0) { - return duk_bd_decode(ctx, 20); - } - return (t - 1) + 37; /* [37,163] */ - } -} - -/* Decode a bit packed string from a custom format used by genbuiltins.py. - * This function is here because it's used for both heap and thread inits. - * Caller must supply the output buffer whose size is NOT checked! - */ - -#define DUK__BITPACK_LETTER_LIMIT 26 -#define DUK__BITPACK_LOOKUP1 26 -#define DUK__BITPACK_LOOKUP2 27 -#define DUK__BITPACK_SWITCH1 28 -#define DUK__BITPACK_SWITCH 29 -#define DUK__BITPACK_UNUSED1 30 -#define DUK__BITPACK_EIGHTBIT 31 - -DUK_LOCAL const duk_uint8_t duk__bitpacked_lookup[16] = { - DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, - DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, - DUK_ASC_8, DUK_ASC_9, DUK_ASC_UNDERSCORE, DUK_ASC_SPACE, - 0x82, 0x80, DUK_ASC_DOUBLEQUOTE, DUK_ASC_LCURLY -}; - -DUK_INTERNAL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out) { - duk_small_uint_t len; - duk_small_uint_t mode; - duk_small_uint_t t; - duk_small_uint_t i; - - len = duk_bd_decode(bd, 5); - if (len == 31) { - len = duk_bd_decode(bd, 8); /* Support up to 256 bytes; rare. */ - } - - mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */ - for (i = 0; i < len; i++) { - t = duk_bd_decode(bd, 5); - if (t < DUK__BITPACK_LETTER_LIMIT) { - t = t + DUK_ASC_UC_A + mode; - } else if (t == DUK__BITPACK_LOOKUP1) { - t = duk__bitpacked_lookup[duk_bd_decode(bd, 3)]; - } else if (t == DUK__BITPACK_LOOKUP2) { - t = duk__bitpacked_lookup[8 + duk_bd_decode(bd, 3)]; - } else if (t == DUK__BITPACK_SWITCH1) { - t = duk_bd_decode(bd, 5); - DUK_ASSERT_DISABLE(t >= 0); /* unsigned */ - DUK_ASSERT(t <= 25); - t = t + DUK_ASC_UC_A + (mode ^ 32); - } else if (t == DUK__BITPACK_SWITCH) { - mode = mode ^ 32; - t = duk_bd_decode(bd, 5); - DUK_ASSERT_DISABLE(t >= 0); - DUK_ASSERT(t <= 25); - t = t + DUK_ASC_UC_A + mode; - } else if (t == DUK__BITPACK_EIGHTBIT) { - t = duk_bd_decode(bd, 8); - } - out[i] = (duk_uint8_t) t; - } - - return len; -} - -/* automatic undefs */ -#undef DUK__BITPACK_EIGHTBIT -#undef DUK__BITPACK_LETTER_LIMIT -#undef DUK__BITPACK_LOOKUP1 -#undef DUK__BITPACK_LOOKUP2 -#undef DUK__BITPACK_SWITCH -#undef DUK__BITPACK_SWITCH1 -#undef DUK__BITPACK_UNUSED1 -#line 1 "duk_util_bitencoder.c" -/* - * Bitstream encoder. - */ - -/* #include duk_internal.h -> already included */ - -DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) { - duk_uint8_t tmp; - - DUK_ASSERT(ctx != NULL); - DUK_ASSERT(ctx->currbits < 8); - - /* This limitation would be fixable but adds unnecessary complexity. */ - DUK_ASSERT(bits >= 1 && bits <= 24); - - ctx->currval = (ctx->currval << bits) | data; - ctx->currbits += bits; - - while (ctx->currbits >= 8) { - if (ctx->offset < ctx->length) { - tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff); - ctx->data[ctx->offset++] = tmp; - } else { - /* If buffer has been exhausted, truncate bitstream */ - ctx->truncated = 1; - } - - ctx->currbits -= 8; - } -} - -DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) { - duk_small_int_t npad; - - DUK_ASSERT(ctx != NULL); - DUK_ASSERT(ctx->currbits < 8); - - npad = (duk_small_int_t) (8 - ctx->currbits); - if (npad > 0) { - duk_be_encode(ctx, 0, npad); - } - DUK_ASSERT(ctx->currbits == 0); -} -#line 1 "duk_util_bufwriter.c" -/* - * Fast buffer writer with slack management. - */ - -/* #include duk_internal.h -> already included */ - -/* - * Macro support functions (use only macros in calling code) - */ - -DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t curr_offset, duk_size_t new_length) { - duk_uint8_t *p; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw_ctx != NULL); - DUK_UNREF(thr); - - p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf); - DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0)); - bw_ctx->p = p + curr_offset; - bw_ctx->p_base = p; - bw_ctx->p_limit = p + new_length; -} - -DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) { - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw_ctx != NULL); - DUK_ASSERT(h_buf != NULL); - - bw_ctx->buf = h_buf; - duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf)); -} - -DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw_ctx != NULL); - - (void) duk_push_dynamic_buffer(thr, buf_size); - bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1); - duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size); -} - -/* Resize target buffer for requested size. Called by the macro only when the - * fast path test (= there is space) fails. - */ -DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz) { - duk_size_t curr_off; - duk_size_t add_sz; - duk_size_t new_sz; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw_ctx != NULL); - - /* We could do this operation without caller updating bw_ctx->ptr, - * but by writing it back here we can share code better. - */ - - curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base); - add_sz = (curr_off >> DUK_BW_SLACK_SHIFT) + DUK_BW_SLACK_ADD; - new_sz = curr_off + sz + add_sz; - if (DUK_UNLIKELY(new_sz < curr_off)) { - /* overflow */ - DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); - return NULL; /* not reachable */ - } -#if 0 /* for manual torture testing: tight allocation, useful with valgrind */ - new_sz = curr_off + sz; -#endif - - /* This is important to ensure dynamic buffer data pointer is not - * NULL (which is possible if buffer size is zero), which in turn - * causes portability issues with e.g. memmove() and memcpy(). - */ - DUK_ASSERT(new_sz >= 1); - - DUK_DD(DUK_DDPRINT("resize bufferwriter from %ld to %ld (add_sz=%ld)", (long) curr_off, (long) new_sz, (long) add_sz)); - - duk_hbuffer_resize(thr, bw_ctx->buf, new_sz); - duk__bw_update_ptrs(thr, bw_ctx, curr_off, new_sz); - return bw_ctx->p; -} - -/* Make buffer compact, matching current written size. */ -DUK_INTERNAL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) { - duk_size_t len; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw_ctx != NULL); - DUK_UNREF(thr); - - len = (duk_size_t) (bw_ctx->p - bw_ctx->p_base); - duk_hbuffer_resize(thr, bw_ctx->buf, len); - duk__bw_update_ptrs(thr, bw_ctx, len, len); -} - -DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) { - duk_uint8_t *p_base; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw)); - DUK_UNREF(thr); - - p_base = bw->p_base; - DUK_MEMCPY((void *) bw->p, - (const void *) (p_base + src_off), - (size_t) len); - bw->p += len; -} - -DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw)); - - DUK_BW_ENSURE(thr, bw, len); - duk_bw_write_raw_slice(thr, bw, src_off, len); -} - -DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len) { - duk_uint8_t *p_base; - duk_size_t buf_sz, move_sz; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(buf != NULL); - DUK_UNREF(thr); - - p_base = bw->p_base; - buf_sz = (duk_size_t) (bw->p - p_base); /* constrained by maximum buffer size */ - move_sz = buf_sz - dst_off; - - DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */ - DUK_MEMMOVE((void *) (p_base + dst_off + len), - (const void *) (p_base + dst_off), - (size_t) move_sz); - DUK_MEMCPY((void *) (p_base + dst_off), - (const void *) buf, - (size_t) len); - bw->p += len; -} - -DUK_INTERNAL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(buf != NULL); - - DUK_BW_ENSURE(thr, bw, len); - duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len); -} - -DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len) { - duk_uint8_t *p_base; - duk_size_t buf_sz, move_sz; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw)); - DUK_UNREF(thr); - - p_base = bw->p_base; - - /* Don't support "straddled" source now. */ - DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len); - - if (dst_off <= src_off) { - /* Target is before source. Source offset is expressed as - * a "before change" offset. Account for the memmove. - */ - src_off += len; - } - - buf_sz = (duk_size_t) (bw->p - p_base); - move_sz = buf_sz - dst_off; - - DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */ - DUK_MEMMOVE((void *) (p_base + dst_off + len), - (const void *) (p_base + dst_off), - (size_t) move_sz); - DUK_MEMCPY((void *) (p_base + dst_off), - (const void *) (p_base + src_off), - (size_t) len); - bw->p += len; -} - -DUK_INTERNAL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw)); - - /* Don't support "straddled" source now. */ - DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len); - - DUK_BW_ENSURE(thr, bw, len); - duk_bw_insert_raw_slice(thr, bw, dst_off, src_off, len); -} - -DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) { - duk_uint8_t *p_base, *p_dst, *p_src; - duk_size_t buf_sz, move_sz; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_UNREF(thr); - - p_base = bw->p_base; - buf_sz = (duk_size_t) (bw->p - p_base); - move_sz = buf_sz - off; - p_dst = p_base + off + len; - p_src = p_base + off; - DUK_MEMMOVE((void *) p_dst, (const void *) p_src, (size_t) move_sz); - return p_src; /* point to start of 'reserved area' */ -} - -DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw)); - - DUK_BW_ENSURE(thr, bw, len); - return duk_bw_insert_raw_area(thr, bw, off, len); -} - -DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) { - duk_size_t move_sz; - - duk_uint8_t *p_base; - duk_uint8_t *p_src; - duk_uint8_t *p_dst; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(bw != NULL); - DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); - DUK_ASSERT(off + len <= DUK_BW_GET_SIZE(thr, bw)); - DUK_UNREF(thr); - - p_base = bw->p_base; - p_dst = p_base + off; - p_src = p_dst + len; - move_sz = (duk_size_t) (bw->p - p_src); - DUK_MEMMOVE((void *) p_dst, - (const void *) p_src, - (size_t) move_sz); - bw->p -= len; -} - -/* - * Macro support functions for reading/writing raw data. - * - * These are done using mempcy to ensure they're valid even for unaligned - * reads/writes on platforms where alignment counts. On x86 at least gcc - * is able to compile these into a bswap+mov. "Always inline" is used to - * ensure these macros compile to minimal code. - * - * Not really bufwriter related, but currently used together. - */ - -DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p) { - union { - duk_uint8_t b[2]; - duk_uint16_t x; - } u; - - DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 2); - u.x = DUK_NTOH16(u.x); - *p += 2; - return u.x; -} - -DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p) { - union { - duk_uint8_t b[4]; - duk_uint32_t x; - } u; - - DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4); - u.x = DUK_NTOH32(u.x); - *p += 4; - return u.x; -} - -DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p) { - duk_double_union du; - union { - duk_uint8_t b[4]; - duk_uint32_t x; - } u; - - DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4); - u.x = DUK_NTOH32(u.x); - du.ui[DUK_DBL_IDX_UI0] = u.x; - DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), (size_t) 4); - u.x = DUK_NTOH32(u.x); - du.ui[DUK_DBL_IDX_UI1] = u.x; - *p += 8; - - return du.d; -} - -DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val) { - union { - duk_uint8_t b[2]; - duk_uint16_t x; - } u; - - u.x = DUK_HTON16(val); - DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 2); - *p += 2; -} - -DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val) { - union { - duk_uint8_t b[4]; - duk_uint32_t x; - } u; - - u.x = DUK_HTON32(val); - DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4); - *p += 4; -} - -DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val) { - duk_double_union du; - union { - duk_uint8_t b[4]; - duk_uint32_t x; - } u; - - du.d = val; - u.x = du.ui[DUK_DBL_IDX_UI0]; - u.x = DUK_HTON32(u.x); - DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4); - u.x = du.ui[DUK_DBL_IDX_UI1]; - u.x = DUK_HTON32(u.x); - DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4); - *p += 8; -} -#line 1 "duk_util_hashbytes.c" -/* - * Hash function duk_util_hashbytes(). - * - * Currently, 32-bit MurmurHash2. - * - * Don't rely on specific hash values; hash function may be endianness - * dependent, for instance. - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_STRHASH_DENSE) -/* 'magic' constants for Murmurhash2 */ -#define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL) -#define DUK__MAGIC_R 24 - -DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) { - duk_uint32_t h = seed ^ ((duk_uint32_t) len); - - while (len >= 4) { - /* Portability workaround is required for platforms without - * unaligned access. The replacement code emulates little - * endian access even on big endian architectures, which is - * OK as long as it is consistent for a build. - */ -#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS) - duk_uint32_t k = *((const duk_uint32_t *) (const void *) data); -#else - duk_uint32_t k = ((duk_uint32_t) data[0]) | - (((duk_uint32_t) data[1]) << 8) | - (((duk_uint32_t) data[2]) << 16) | - (((duk_uint32_t) data[3]) << 24); -#endif - - k *= DUK__MAGIC_M; - k ^= k >> DUK__MAGIC_R; - k *= DUK__MAGIC_M; - h *= DUK__MAGIC_M; - h ^= k; - data += 4; - len -= 4; - } - - switch (len) { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; - h *= DUK__MAGIC_M; - } - - h ^= h >> 13; - h *= DUK__MAGIC_M; - h ^= h >> 15; - - return h; -} -#endif /* DUK_USE_STRHASH_DENSE */ - -/* automatic undefs */ -#undef DUK__MAGIC_M -#undef DUK__MAGIC_R -#line 1 "duk_util_tinyrandom.c" -/* - * A tiny random number generator used for Math.random() and other internals. - * - * Default algorithm is xoroshiro128+: http://xoroshiro.di.unimi.it/xoroshiro128plus.c - * with SplitMix64 seed preparation: http://xorshift.di.unimi.it/splitmix64.c. - * - * Low memory targets and targets without 64-bit types use a slightly smaller - * (but slower) algorithm by Adi Shamir: - * http://www.woodmann.com/forum/archive/index.php/t-3100.html. - * - */ - -/* #include duk_internal.h -> already included */ - -#if !defined(DUK_USE_GET_RANDOM_DOUBLE) - -#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS) -#define DUK__RANDOM_SHAMIR3OP -#else -#define DUK__RANDOM_XOROSHIRO128PLUS -#endif - -#if defined(DUK__RANDOM_SHAMIR3OP) -#define DUK__UPDATE_RND(rnd) do { \ - (rnd) += ((rnd) * (rnd)) | 0x05UL; \ - (rnd) = ((rnd) & 0xffffffffUL); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \ - } while (0) - -#define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */ - -DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) { - DUK_UNREF(thr); /* Nothing now. */ -} - -DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) { - duk_double_t t; - duk_small_int_t n; - duk_uint32_t rnd; - - rnd = thr->heap->rnd_state; - - n = 53; /* enough to cover the whole mantissa */ - t = 0.0; - - do { - DUK__UPDATE_RND(rnd); - t += DUK__RND_BIT(rnd); - t /= 2.0; - } while (--n); - - thr->heap->rnd_state = rnd; - - DUK_ASSERT(t >= (duk_double_t) 0.0); - DUK_ASSERT(t < (duk_double_t) 1.0); - - return t; -} -#endif /* DUK__RANDOM_SHAMIR3OP */ - -#if defined(DUK__RANDOM_XOROSHIRO128PLUS) -DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_splitmix64(duk_uint64_t *x) { - duk_uint64_t z; - z = (*x += DUK_U64_CONSTANT(0x9E3779B97F4A7C15)); - z = (z ^ (z >> 30U)) * DUK_U64_CONSTANT(0xBF58476D1CE4E5B9); - z = (z ^ (z >> 27U)) * DUK_U64_CONSTANT(0x94D049BB133111EB); - return z ^ (z >> 31U); -} - -DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_rotl(const duk_uint64_t x, duk_small_uint_t k) { - return (x << k) | (x >> (64U - k)); -} - -DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__xoroshiro128plus(duk_uint64_t *s) { - duk_uint64_t s0; - duk_uint64_t s1; - duk_uint64_t res; - - s0 = s[0]; - s1 = s[1]; - res = s0 + s1; - s1 ^= s0; - s[0] = duk__rnd_rotl(s0, 55) ^ s1 ^ (s1 << 14U); - s[1] = duk__rnd_rotl(s1, 36); - - return res; -} - -DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) { - duk_small_uint_t i; - duk_uint64_t x; - - /* Mix both halves of the initial seed with SplitMix64. The intent - * is to ensure that very similar raw seeds (which is usually the case - * because current seed is Date.now()) result in different xoroshiro128+ - * seeds. - */ - x = thr->heap->rnd_state[0]; /* Only [0] is used as input here. */ - for (i = 0; i < 64; i++) { - thr->heap->rnd_state[i & 0x01] = duk__rnd_splitmix64(&x); /* Keep last 2 values. */ - } -} - -DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) { - duk_uint64_t v; - duk_double_union du; - - /* For big and little endian the integer and IEEE double byte order - * is the same so a direct assignment works. For mixed endian the - * 32-bit parts must be swapped. - */ - v = (DUK_U64_CONSTANT(0x3ff) << 52U) | (duk__xoroshiro128plus((duk_uint64_t *) thr->heap->rnd_state) >> 12U); - du.ull[0] = v; -#if defined(DUK_USE_DOUBLE_ME) - do { - duk_uint32_t tmp; - tmp = du.ui[0]; - du.ui[0] = du.ui[1]; - du.ui[1] = tmp; - } while (0); -#endif - return du.d - 1.0; -} -#endif /* DUK__RANDOM_XOROSHIRO128PLUS */ - -#endif /* !DUK_USE_GET_RANDOM_DOUBLE */ - -/* automatic undefs */ -#undef DUK__RANDOM_SHAMIR3OP -#undef DUK__RANDOM_XOROSHIRO128PLUS -#undef DUK__RND_BIT -#undef DUK__UPDATE_RND diff --git a/dep/duktape/duktape/duktape.h b/dep/duktape/duktape/duktape.h deleted file mode 100644 index 848b1eea4c3..00000000000 --- a/dep/duktape/duktape/duktape.h +++ /dev/null @@ -1,1349 +0,0 @@ -/* - * Duktape public API for Duktape 2.2.0. - * - * See the API reference for documentation on call semantics. The exposed, - * supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API" - * comments. Other parts of the header are Duktape internal and related to - * e.g. platform/compiler/feature detection. - * - * Git commit a459cf3c9bd1779fc01b435d69302b742675a08f (v2.2.0). - * Git branch master. - * - * See Duktape AUTHORS.rst and LICENSE.txt for copyright and - * licensing information. - */ - -/* LICENSE.txt */ -/* - * =============== - * Duktape license - * =============== - * - * (http://opensource.org/licenses/MIT) - * - * Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst) - * - * 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. - */ - -/* AUTHORS.rst */ -/* - * =============== - * Duktape authors - * =============== - * - * Copyright - * ========= - * - * Duktape copyrights are held by its authors. Each author has a copyright - * to their contribution, and agrees to irrevocably license the contribution - * under the Duktape ``LICENSE.txt``. - * - * Authors - * ======= - * - * Please include an e-mail address, a link to your GitHub profile, or something - * similar to allow your contribution to be identified accurately. - * - * The following people have contributed code, website contents, or Wiki contents, - * and agreed to irrevocably license their contributions under the Duktape - * ``LICENSE.txt`` (in order of appearance): - * - * * Sami Vaarala - * * Niki Dobrev - * * Andreas \u00d6man - * * L\u00e1szl\u00f3 Lang\u00f3 - * * Legimet - * * Karl Skomski - * * Bruce Pascoe - * * Ren\u00e9 Hollander - * * Julien Hamaide (https://github.com/crazyjul) - * * Sebastian G\u00f6tte (https://github.com/jaseg) - * * Tomasz Magulski (https://github.com/magul) - * * \D. Bohdan (https://github.com/dbohdan) - * * Ond\u0159ej Jirman (https://github.com/megous) - * * Sa\u00fal Ibarra Corretg\u00e9 - * * Jeremy HU - * * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr) - * * Harold Brenes (https://github.com/harold-b) - * * Oliver Crow (https://github.com/ocrow) - * * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski) - * * Brett Vickers (https://github.com/beevik) - * * Dominik Okwieka (https://github.com/okitec) - * * Remko Tron\u00e7on (https://el-tramo.be) - * * Romero Malaquias (rbsm@ic.ufal.br) - * * Michael Drake - * * Steven Don (https://github.com/shdon) - * * Simon Stone (https://github.com/sstone1) - * * \J. McC. (https://github.com/jmhmccr) - * - * Other contributions - * =================== - * - * The following people have contributed something other than code (e.g. reported - * bugs, provided ideas, etc; roughly in order of appearance): - * - * * Greg Burns - * * Anthony Rabine - * * Carlos Costa - * * Aur\u00e9lien Bouilland - * * Preet Desai (Pris Matic) - * * judofyr (http://www.reddit.com/user/judofyr) - * * Jason Woofenden - * * Micha\u0142 Przyby\u015b - * * Anthony Howe - * * Conrad Pankoff - * * Jim Schimpf - * * Rajaran Gaunker (https://github.com/zimbabao) - * * Andreas \u00d6man - * * Doug Sanden - * * Josh Engebretson (https://github.com/JoshEngebretson) - * * Remo Eichenberger (https://github.com/remoe) - * * Mamod Mehyar (https://github.com/mamod) - * * David Demelier (https://github.com/markand) - * * Tim Caswell (https://github.com/creationix) - * * Mitchell Blank Jr (https://github.com/mitchblank) - * * https://github.com/yushli - * * Seo Sanghyeon (https://github.com/sanxiyn) - * * Han ChoongWoo (https://github.com/tunz) - * * Joshua Peek (https://github.com/josh) - * * Bruce E. Pascoe (https://github.com/fatcerberus) - * * https://github.com/Kelledin - * * https://github.com/sstruchtrup - * * Michael Drake (https://github.com/tlsa) - * * https://github.com/chris-y - * * Laurent Zubiaur (https://github.com/lzubiaur) - * * Neil Kolban (https://github.com/nkolban) - * - * If you are accidentally missing from this list, send me an e-mail - * (``sami.vaarala@iki.fi``) and I'll fix the omission. - */ - -#if !defined(DUKTAPE_H_INCLUDED) -#define DUKTAPE_H_INCLUDED - -#define DUK_SINGLE_FILE - -/* - * BEGIN PUBLIC API - */ - -/* - * Version and Git commit identification - */ - -/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code - * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value - * is also available to Ecmascript code in Duktape.version. Unofficial - * development snapshots have 99 for patch level (e.g. 0.10.99 would be a - * development version after 0.10.0 but before the next official release). - */ -#define DUK_VERSION 20200L - -/* Git commit, describe, and branch for Duktape build. Useful for - * non-official snapshot builds so that application code can easily log - * which Duktape snapshot was used. Not available in the Ecmascript - * environment. - */ -#define DUK_GIT_COMMIT "a459cf3c9bd1779fc01b435d69302b742675a08f" -#define DUK_GIT_DESCRIBE "v2.2.0" -#define DUK_GIT_BRANCH "master" - -/* External duk_config.h provides platform/compiler/OS dependent - * typedefs and macros, and DUK_USE_xxx config options so that - * the rest of Duktape doesn't need to do any feature detection. - * DUK_VERSION is defined before including so that configuration - * snippets can react to it. - */ -#include "duk_config.h" - -/* - * Avoid C++ name mangling - */ - -#if defined(__cplusplus) -extern "C" { -#endif - -/* - * Some defines forwarded from feature detection - */ - -#undef DUK_API_VARIADIC_MACROS -#if defined(DUK_USE_VARIADIC_MACROS) -#define DUK_API_VARIADIC_MACROS -#endif - -#define DUK_API_NORETURN(decl) DUK_NORETURN(decl) - -/* - * Public API specific typedefs - * - * Many types are wrapped by Duktape for portability to rare platforms - * where e.g. 'int' is a 16-bit type. See practical typing discussion - * in Duktape web documentation. - */ - -struct duk_thread_state; -struct duk_memory_functions; -struct duk_function_list_entry; -struct duk_number_list_entry; -struct duk_time_components; - -/* duk_context is now defined in duk_config.h because it may also be - * referenced there by prototypes. - */ -typedef struct duk_thread_state duk_thread_state; -typedef struct duk_memory_functions duk_memory_functions; -typedef struct duk_function_list_entry duk_function_list_entry; -typedef struct duk_number_list_entry duk_number_list_entry; -typedef struct duk_time_components duk_time_components; - -typedef duk_ret_t (*duk_c_function)(duk_context *ctx); -typedef void *(*duk_alloc_function) (void *udata, duk_size_t size); -typedef void *(*duk_realloc_function) (void *udata, void *ptr, duk_size_t size); -typedef void (*duk_free_function) (void *udata, void *ptr); -typedef void (*duk_fatal_function) (void *udata, const char *msg); -typedef void (*duk_decode_char_function) (void *udata, duk_codepoint_t codepoint); -typedef duk_codepoint_t (*duk_map_char_function) (void *udata, duk_codepoint_t codepoint); -typedef duk_ret_t (*duk_safe_call_function) (duk_context *ctx, void *udata); -typedef duk_size_t (*duk_debug_read_function) (void *udata, char *buffer, duk_size_t length); -typedef duk_size_t (*duk_debug_write_function) (void *udata, const char *buffer, duk_size_t length); -typedef duk_size_t (*duk_debug_peek_function) (void *udata); -typedef void (*duk_debug_read_flush_function) (void *udata); -typedef void (*duk_debug_write_flush_function) (void *udata); -typedef duk_idx_t (*duk_debug_request_function) (duk_context *ctx, void *udata, duk_idx_t nvalues); -typedef void (*duk_debug_detached_function) (duk_context *ctx, void *udata); - -struct duk_thread_state { - /* XXX: Enough space to hold internal suspend/resume structure. - * This is rather awkward and to be fixed when the internal - * structure is visible for the public API header. - */ - char data[128]; -}; - -struct duk_memory_functions { - duk_alloc_function alloc_func; - duk_realloc_function realloc_func; - duk_free_function free_func; - void *udata; -}; - -struct duk_function_list_entry { - const char *key; - duk_c_function value; - duk_idx_t nargs; -}; - -struct duk_number_list_entry { - const char *key; - duk_double_t value; -}; - -struct duk_time_components { - duk_double_t year; /* year, e.g. 2016, Ecmascript year range */ - duk_double_t month; /* month: 1-12 */ - duk_double_t day; /* day: 1-31 */ - duk_double_t hours; /* hour: 0-59 */ - duk_double_t minutes; /* minute: 0-59 */ - duk_double_t seconds; /* second: 0-59 (in POSIX time no leap second) */ - duk_double_t milliseconds; /* may contain sub-millisecond fractions */ - duk_double_t weekday; /* weekday: 0-6, 0=Sunday, 1=Monday, ..., 6=Saturday */ -}; - -/* - * Constants - */ - -/* Duktape debug protocol version used by this build. */ -#define DUK_DEBUG_PROTOCOL_VERSION 2 - -/* Used to represent invalid index; if caller uses this without checking, - * this index will map to a non-existent stack entry. Also used in some - * API calls as a marker to denote "no value". - */ -#define DUK_INVALID_INDEX DUK_IDX_MIN - -/* Indicates that a native function does not have a fixed number of args, - * and the argument stack should not be capped/extended at all. - */ -#define DUK_VARARGS ((duk_int_t) (-1)) - -/* Number of value stack entries (in addition to actual call arguments) - * guaranteed to be allocated on entry to a Duktape/C function. - */ -#define DUK_API_ENTRY_STACK 64U - -/* Value types, used by e.g. duk_get_type() */ -#define DUK_TYPE_MIN 0U -#define DUK_TYPE_NONE 0U /* no value, e.g. invalid index */ -#define DUK_TYPE_UNDEFINED 1U /* Ecmascript undefined */ -#define DUK_TYPE_NULL 2U /* Ecmascript null */ -#define DUK_TYPE_BOOLEAN 3U /* Ecmascript boolean: 0 or 1 */ -#define DUK_TYPE_NUMBER 4U /* Ecmascript number: double */ -#define DUK_TYPE_STRING 5U /* Ecmascript string: CESU-8 / extended UTF-8 encoded */ -#define DUK_TYPE_OBJECT 6U /* Ecmascript object: includes objects, arrays, functions, threads */ -#define DUK_TYPE_BUFFER 7U /* fixed or dynamic, garbage collected byte buffer */ -#define DUK_TYPE_POINTER 8U /* raw void pointer */ -#define DUK_TYPE_LIGHTFUNC 9U /* lightweight function pointer */ -#define DUK_TYPE_MAX 9U - -/* Value mask types, used by e.g. duk_get_type_mask() */ -#define DUK_TYPE_MASK_NONE (1U << DUK_TYPE_NONE) -#define DUK_TYPE_MASK_UNDEFINED (1U << DUK_TYPE_UNDEFINED) -#define DUK_TYPE_MASK_NULL (1U << DUK_TYPE_NULL) -#define DUK_TYPE_MASK_BOOLEAN (1U << DUK_TYPE_BOOLEAN) -#define DUK_TYPE_MASK_NUMBER (1U << DUK_TYPE_NUMBER) -#define DUK_TYPE_MASK_STRING (1U << DUK_TYPE_STRING) -#define DUK_TYPE_MASK_OBJECT (1U << DUK_TYPE_OBJECT) -#define DUK_TYPE_MASK_BUFFER (1U << DUK_TYPE_BUFFER) -#define DUK_TYPE_MASK_POINTER (1U << DUK_TYPE_POINTER) -#define DUK_TYPE_MASK_LIGHTFUNC (1U << DUK_TYPE_LIGHTFUNC) -#define DUK_TYPE_MASK_THROW (1U << 10) /* internal flag value: throw if mask doesn't match */ -#define DUK_TYPE_MASK_PROMOTE (1U << 11) /* internal flag value: promote to object if mask matches */ - -/* Coercion hints */ -#define DUK_HINT_NONE 0 /* prefer number, unless input is a Date, in which - * case prefer string (E5 Section 8.12.8) - */ -#define DUK_HINT_STRING 1 /* prefer string */ -#define DUK_HINT_NUMBER 2 /* prefer number */ - -/* Enumeration flags for duk_enum() */ -#define DUK_ENUM_INCLUDE_NONENUMERABLE (1U << 0) /* enumerate non-numerable properties in addition to enumerable */ -#define DUK_ENUM_INCLUDE_HIDDEN (1U << 1) /* enumerate hidden symbols too (in Duktape 1.x called internal properties) */ -#define DUK_ENUM_INCLUDE_SYMBOLS (1U << 2) /* enumerate symbols */ -#define DUK_ENUM_EXCLUDE_STRINGS (1U << 3) /* exclude strings */ -#define DUK_ENUM_OWN_PROPERTIES_ONLY (1U << 4) /* don't walk prototype chain, only check own properties */ -#define DUK_ENUM_ARRAY_INDICES_ONLY (1U << 5) /* only enumerate array indices */ -/* XXX: misleading name */ -#define DUK_ENUM_SORT_ARRAY_INDICES (1U << 6) /* sort array indices (applied to full enumeration result, including inherited array indices); XXX: misleading name */ -#define DUK_ENUM_NO_PROXY_BEHAVIOR (1U << 7) /* enumerate a proxy object itself without invoking proxy behavior */ - -/* Compilation flags for duk_compile() and duk_eval() */ -/* DUK_COMPILE_xxx bits 0-2 are reserved for an internal 'nargs' argument. - */ -#define DUK_COMPILE_EVAL (1U << 3) /* compile eval code (instead of global code) */ -#define DUK_COMPILE_FUNCTION (1U << 4) /* compile function code (instead of global code) */ -#define DUK_COMPILE_STRICT (1U << 5) /* use strict (outer) context for global, eval, or function code */ -#define DUK_COMPILE_SHEBANG (1U << 6) /* allow shebang ('#! ...') comment on first line of source */ -#define DUK_COMPILE_SAFE (1U << 7) /* (internal) catch compilation errors */ -#define DUK_COMPILE_NORESULT (1U << 8) /* (internal) omit eval result */ -#define DUK_COMPILE_NOSOURCE (1U << 9) /* (internal) no source string on stack */ -#define DUK_COMPILE_STRLEN (1U << 10) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ -#define DUK_COMPILE_NOFILENAME (1U << 11) /* (internal) no filename on stack */ -#define DUK_COMPILE_FUNCEXPR (1U << 12) /* (internal) source is a function expression (used for Function constructor) */ - -/* Flags for duk_def_prop() and its variants; base flags + a lot of convenience shorthands */ -#define DUK_DEFPROP_WRITABLE (1U << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */ -#define DUK_DEFPROP_ENUMERABLE (1U << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */ -#define DUK_DEFPROP_CONFIGURABLE (1U << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */ -#define DUK_DEFPROP_HAVE_WRITABLE (1U << 3) /* set/clear writable */ -#define DUK_DEFPROP_HAVE_ENUMERABLE (1U << 4) /* set/clear enumerable */ -#define DUK_DEFPROP_HAVE_CONFIGURABLE (1U << 5) /* set/clear configurable */ -#define DUK_DEFPROP_HAVE_VALUE (1U << 6) /* set value (given on value stack) */ -#define DUK_DEFPROP_HAVE_GETTER (1U << 7) /* set getter (given on value stack) */ -#define DUK_DEFPROP_HAVE_SETTER (1U << 8) /* set setter (given on value stack) */ -#define DUK_DEFPROP_FORCE (1U << 9) /* force change if possible, may still fail for e.g. virtual properties */ -#define DUK_DEFPROP_SET_WRITABLE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE) -#define DUK_DEFPROP_CLEAR_WRITABLE DUK_DEFPROP_HAVE_WRITABLE -#define DUK_DEFPROP_SET_ENUMERABLE (DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE) -#define DUK_DEFPROP_CLEAR_ENUMERABLE DUK_DEFPROP_HAVE_ENUMERABLE -#define DUK_DEFPROP_SET_CONFIGURABLE (DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE) -#define DUK_DEFPROP_CLEAR_CONFIGURABLE DUK_DEFPROP_HAVE_CONFIGURABLE -#define DUK_DEFPROP_W DUK_DEFPROP_WRITABLE -#define DUK_DEFPROP_E DUK_DEFPROP_ENUMERABLE -#define DUK_DEFPROP_C DUK_DEFPROP_CONFIGURABLE -#define DUK_DEFPROP_WE (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_ENUMERABLE) -#define DUK_DEFPROP_WC (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_CONFIGURABLE) -#define DUK_DEFPROP_WEC (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_CONFIGURABLE) -#define DUK_DEFPROP_HAVE_W DUK_DEFPROP_HAVE_WRITABLE -#define DUK_DEFPROP_HAVE_E DUK_DEFPROP_HAVE_ENUMERABLE -#define DUK_DEFPROP_HAVE_C DUK_DEFPROP_HAVE_CONFIGURABLE -#define DUK_DEFPROP_HAVE_WE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE) -#define DUK_DEFPROP_HAVE_WC (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_CONFIGURABLE) -#define DUK_DEFPROP_HAVE_WEC (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE) -#define DUK_DEFPROP_SET_W DUK_DEFPROP_SET_WRITABLE -#define DUK_DEFPROP_SET_E DUK_DEFPROP_SET_ENUMERABLE -#define DUK_DEFPROP_SET_C DUK_DEFPROP_SET_CONFIGURABLE -#define DUK_DEFPROP_SET_WE (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_ENUMERABLE) -#define DUK_DEFPROP_SET_WC (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_CONFIGURABLE) -#define DUK_DEFPROP_SET_WEC (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_ENUMERABLE | DUK_DEFPROP_SET_CONFIGURABLE) -#define DUK_DEFPROP_CLEAR_W DUK_DEFPROP_CLEAR_WRITABLE -#define DUK_DEFPROP_CLEAR_E DUK_DEFPROP_CLEAR_ENUMERABLE -#define DUK_DEFPROP_CLEAR_C DUK_DEFPROP_CLEAR_CONFIGURABLE -#define DUK_DEFPROP_CLEAR_WE (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_ENUMERABLE) -#define DUK_DEFPROP_CLEAR_WC (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_CONFIGURABLE) -#define DUK_DEFPROP_CLEAR_WEC (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_ENUMERABLE | DUK_DEFPROP_CLEAR_CONFIGURABLE) -#define DUK_DEFPROP_ATTR_W (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_W) -#define DUK_DEFPROP_ATTR_E (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_E) -#define DUK_DEFPROP_ATTR_C (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_C) -#define DUK_DEFPROP_ATTR_WE (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WE) -#define DUK_DEFPROP_ATTR_WC (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WC) -#define DUK_DEFPROP_ATTR_WEC (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WEC) - -/* Flags for duk_push_thread_raw() */ -#define DUK_THREAD_NEW_GLOBAL_ENV (1U << 0) /* create a new global environment */ - -/* Flags for duk_gc() */ -#define DUK_GC_COMPACT (1U << 0) /* compact heap objects */ - -/* Error codes (must be 8 bits at most, see duk_error.h) */ -#define DUK_ERR_NONE 0 /* no error (e.g. from duk_get_error_code()) */ -#define DUK_ERR_ERROR 1 /* Error */ -#define DUK_ERR_EVAL_ERROR 2 /* EvalError */ -#define DUK_ERR_RANGE_ERROR 3 /* RangeError */ -#define DUK_ERR_REFERENCE_ERROR 4 /* ReferenceError */ -#define DUK_ERR_SYNTAX_ERROR 5 /* SyntaxError */ -#define DUK_ERR_TYPE_ERROR 6 /* TypeError */ -#define DUK_ERR_URI_ERROR 7 /* URIError */ - -/* Return codes for C functions (shortcut for throwing an error) */ -#define DUK_RET_ERROR (-DUK_ERR_ERROR) -#define DUK_RET_EVAL_ERROR (-DUK_ERR_EVAL_ERROR) -#define DUK_RET_RANGE_ERROR (-DUK_ERR_RANGE_ERROR) -#define DUK_RET_REFERENCE_ERROR (-DUK_ERR_REFERENCE_ERROR) -#define DUK_RET_SYNTAX_ERROR (-DUK_ERR_SYNTAX_ERROR) -#define DUK_RET_TYPE_ERROR (-DUK_ERR_TYPE_ERROR) -#define DUK_RET_URI_ERROR (-DUK_ERR_URI_ERROR) - -/* Return codes for protected calls (duk_safe_call(), duk_pcall()) */ -#define DUK_EXEC_SUCCESS 0 -#define DUK_EXEC_ERROR 1 - -/* Debug levels for DUK_USE_DEBUG_WRITE(). */ -#define DUK_LEVEL_DEBUG 0 -#define DUK_LEVEL_DDEBUG 1 -#define DUK_LEVEL_DDDEBUG 2 - -/* - * Macros to create Symbols as C statically constructed strings. - * - * Call e.g. as DUK_HIDDEN_SYMBOL("myProperty") <=> ("\xFF" "myProperty"). - * Local symbols have a unique suffix, caller should take care to avoid - * conflicting with the Duktape internal representation by e.g. prepending - * a '!' character: DUK_LOCAL_SYMBOL("myLocal", "!123"). - * - * Note that these can only be used for string constants, not dynamically - * created strings. - */ - -#define DUK_HIDDEN_SYMBOL(x) ("\xFF" x) -#define DUK_GLOBAL_SYMBOL(x) ("\x80" x) -#define DUK_LOCAL_SYMBOL(x,uniq) ("\x81" x "\xff" uniq) -#define DUK_WELLKNOWN_SYMBOL(x) ("\x81" x "\xff") - -/* - * If no variadic macros, __FILE__ and __LINE__ are passed through globals - * which is ugly and not thread safe. - */ - -#if !defined(DUK_API_VARIADIC_MACROS) -DUK_EXTERNAL_DECL const char *duk_api_global_filename; -DUK_EXTERNAL_DECL duk_int_t duk_api_global_line; -#endif - -/* - * Context management - */ - -DUK_EXTERNAL_DECL -duk_context *duk_create_heap(duk_alloc_function alloc_func, - duk_realloc_function realloc_func, - duk_free_function free_func, - void *heap_udata, - duk_fatal_function fatal_handler); -DUK_EXTERNAL_DECL void duk_destroy_heap(duk_context *ctx); - -DUK_EXTERNAL_DECL void duk_suspend(duk_context *ctx, duk_thread_state *state); -DUK_EXTERNAL_DECL void duk_resume(duk_context *ctx, const duk_thread_state *state); - -#define duk_create_heap_default() \ - duk_create_heap(NULL, NULL, NULL, NULL, NULL) - -/* - * Memory management - * - * Raw functions have no side effects (cannot trigger GC). - */ - -DUK_EXTERNAL_DECL void *duk_alloc_raw(duk_context *ctx, duk_size_t size); -DUK_EXTERNAL_DECL void duk_free_raw(duk_context *ctx, void *ptr); -DUK_EXTERNAL_DECL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size); -DUK_EXTERNAL_DECL void *duk_alloc(duk_context *ctx, duk_size_t size); -DUK_EXTERNAL_DECL void duk_free(duk_context *ctx, void *ptr); -DUK_EXTERNAL_DECL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size); -DUK_EXTERNAL_DECL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs); -DUK_EXTERNAL_DECL void duk_gc(duk_context *ctx, duk_uint_t flags); - -/* - * Error handling - */ - -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_throw_raw(duk_context *ctx)); -#define duk_throw(ctx) \ - (duk_throw_raw((ctx)), (duk_ret_t) 0) -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal_raw(duk_context *ctx, const char *err_msg)); -#define duk_fatal(ctx,err_msg) \ - (duk_fatal_raw((ctx), (err_msg)), (duk_ret_t) 0) -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); - -#if defined(DUK_API_VARIADIC_MACROS) -#define duk_error(ctx,err_code,...) \ - (duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_generic_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_eval_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_EVAL_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_range_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_RANGE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_reference_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_REFERENCE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_syntax_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_SYNTAX_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_type_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_TYPE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_uri_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_URI_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#else /* DUK_API_VARIADIC_MACROS */ -/* For legacy compilers without variadic macros a macro hack is used to allow - * variable arguments. While the macro allows "return duk_error(...)", it - * will fail with e.g. "(void) duk_error(...)". The calls are noreturn but - * with a return value to allow the "return duk_error(...)" idiom. This may - * cause some compiler warnings, but without noreturn the generated code is - * often worse. The same approach as with variadic macros (using - * "(duk_error(...), 0)") won't work due to the macro hack structure. - */ -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_generic_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_eval_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_range_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_reference_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_syntax_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_type_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_uri_error_stash(duk_context *ctx, const char *fmt, ...)); -#define duk_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_error_stash) /* last value is func pointer, arguments follow in parens */ -#define duk_generic_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_generic_error_stash) -#define duk_eval_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_eval_error_stash) -#define duk_range_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_range_error_stash) -#define duk_reference_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_reference_error_stash) -#define duk_syntax_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_syntax_error_stash) -#define duk_type_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_type_error_stash) -#define duk_uri_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_uri_error_stash) -#endif /* DUK_API_VARIADIC_MACROS */ - -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap)); - -#define duk_error_va(ctx,err_code,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_generic_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_eval_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_EVAL_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_range_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_RANGE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_reference_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_REFERENCE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_syntax_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_SYNTAX_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_type_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_TYPE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_uri_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_URI_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) - -/* - * Other state related functions - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_is_strict_call(duk_context *ctx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_constructor_call(duk_context *ctx); - -/* - * Stack management - */ - -DUK_EXTERNAL_DECL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_require_valid_index(duk_context *ctx, duk_idx_t idx); - -DUK_EXTERNAL_DECL duk_idx_t duk_get_top(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_set_top(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_idx_t duk_get_top_index(duk_context *ctx); -DUK_EXTERNAL_DECL duk_idx_t duk_require_top_index(duk_context *ctx); - -/* Although extra/top could be an unsigned type here, using a signed type - * makes the API more robust to calling code calculation errors or corner - * cases (where caller might occasionally come up with negative values). - * Negative values are treated as zero, which is better than casting them - * to a large unsigned number. (This principle is used elsewhere in the - * API too.) - */ -DUK_EXTERNAL_DECL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra); -DUK_EXTERNAL_DECL void duk_require_stack(duk_context *ctx, duk_idx_t extra); -DUK_EXTERNAL_DECL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top); -DUK_EXTERNAL_DECL void duk_require_stack_top(duk_context *ctx, duk_idx_t top); - -/* - * Stack manipulation (other than push/pop) - */ - -DUK_EXTERNAL_DECL void duk_swap(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); -DUK_EXTERNAL_DECL void duk_swap_top(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_dup(duk_context *ctx, duk_idx_t from_idx); -DUK_EXTERNAL_DECL void duk_dup_top(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_insert(duk_context *ctx, duk_idx_t to_idx); -DUK_EXTERNAL_DECL void duk_replace(duk_context *ctx, duk_idx_t to_idx); -DUK_EXTERNAL_DECL void duk_copy(duk_context *ctx, duk_idx_t from_idx, duk_idx_t to_idx); -DUK_EXTERNAL_DECL void duk_remove(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy); - -#define duk_xmove_top(to_ctx,from_ctx,count) \ - duk_xcopymove_raw((to_ctx), (from_ctx), (count), 0 /*is_copy*/) -#define duk_xcopy_top(to_ctx,from_ctx,count) \ - duk_xcopymove_raw((to_ctx), (from_ctx), (count), 1 /*is_copy*/) - -/* - * Push operations - * - * Push functions return the absolute (relative to bottom of frame) - * position of the pushed value for convenience. - * - * Note: duk_dup() is technically a push. - */ - -DUK_EXTERNAL_DECL void duk_push_undefined(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_null(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_boolean(duk_context *ctx, duk_bool_t val); -DUK_EXTERNAL_DECL void duk_push_true(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_false(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_number(duk_context *ctx, duk_double_t val); -DUK_EXTERNAL_DECL void duk_push_nan(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_int(duk_context *ctx, duk_int_t val); -DUK_EXTERNAL_DECL void duk_push_uint(duk_context *ctx, duk_uint_t val); -DUK_EXTERNAL_DECL const char *duk_push_string(duk_context *ctx, const char *str); -DUK_EXTERNAL_DECL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len); -DUK_EXTERNAL_DECL void duk_push_pointer(duk_context *ctx, void *p); -DUK_EXTERNAL_DECL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...); -DUK_EXTERNAL_DECL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap); - -DUK_EXTERNAL_DECL void duk_push_this(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_current_function(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_current_thread(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_global_object(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_heap_stash(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_global_stash(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx); - -DUK_EXTERNAL_DECL duk_idx_t duk_push_object(duk_context *ctx); -DUK_EXTERNAL_DECL duk_idx_t duk_push_bare_object(duk_context *ctx); -DUK_EXTERNAL_DECL duk_idx_t duk_push_array(duk_context *ctx); -DUK_EXTERNAL_DECL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic); -DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags); -DUK_EXTERNAL_DECL duk_idx_t duk_push_proxy(duk_context *ctx, duk_uint_t proxy_flags); - -#define duk_push_thread(ctx) \ - duk_push_thread_raw((ctx), 0 /*flags*/) - -#define duk_push_thread_new_globalenv(ctx) \ - duk_push_thread_raw((ctx), DUK_THREAD_NEW_GLOBAL_ENV /*flags*/) - -DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...); - -#if defined(DUK_API_VARIADIC_MACROS) -#define duk_push_error_object(ctx,err_code,...) \ - duk_push_error_object_raw((ctx), (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__) -#else -DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...); -/* Note: parentheses are required so that the comma expression works in assignments. */ -#define duk_push_error_object \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_push_error_object_stash) /* last value is func pointer, arguments follow in parens */ -#endif - -DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap); -#define duk_push_error_object_va(ctx,err_code,fmt,ap) \ - duk_push_error_object_va_raw((ctx), (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)) - -#define DUK_BUF_FLAG_DYNAMIC (1 << 0) /* internal flag: dynamic buffer */ -#define DUK_BUF_FLAG_EXTERNAL (1 << 1) /* internal flag: external buffer */ -#define DUK_BUF_FLAG_NOZERO (1 << 2) /* internal flag: don't zero allocated buffer */ - -DUK_EXTERNAL_DECL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags); - -#define duk_push_buffer(ctx,size,dynamic) \ - duk_push_buffer_raw((ctx), (size), (dynamic) ? DUK_BUF_FLAG_DYNAMIC : 0) -#define duk_push_fixed_buffer(ctx,size) \ - duk_push_buffer_raw((ctx), (size), 0 /*flags*/) -#define duk_push_dynamic_buffer(ctx,size) \ - duk_push_buffer_raw((ctx), (size), DUK_BUF_FLAG_DYNAMIC /*flags*/) -#define duk_push_external_buffer(ctx) \ - ((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL)) - -#define DUK_BUFOBJ_ARRAYBUFFER 0 -#define DUK_BUFOBJ_NODEJS_BUFFER 1 -#define DUK_BUFOBJ_DATAVIEW 2 -#define DUK_BUFOBJ_INT8ARRAY 3 -#define DUK_BUFOBJ_UINT8ARRAY 4 -#define DUK_BUFOBJ_UINT8CLAMPEDARRAY 5 -#define DUK_BUFOBJ_INT16ARRAY 6 -#define DUK_BUFOBJ_UINT16ARRAY 7 -#define DUK_BUFOBJ_INT32ARRAY 8 -#define DUK_BUFOBJ_UINT32ARRAY 9 -#define DUK_BUFOBJ_FLOAT32ARRAY 10 -#define DUK_BUFOBJ_FLOAT64ARRAY 11 - -DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags); - -DUK_EXTERNAL_DECL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr); - -/* - * Pop operations - */ - -DUK_EXTERNAL_DECL void duk_pop(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_pop_n(duk_context *ctx, duk_idx_t count); -DUK_EXTERNAL_DECL void duk_pop_2(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_pop_3(duk_context *ctx); - -/* - * Type checks - * - * duk_is_none(), which would indicate whether index it outside of stack, - * is not needed; duk_is_valid_index() gives the same information. - */ - -DUK_EXTERNAL_DECL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t idx, duk_int_t type); -DUK_EXTERNAL_DECL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t mask); - -DUK_EXTERNAL_DECL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t idx); -#define duk_is_null_or_undefined(ctx, idx) \ - ((duk_get_type_mask((ctx), (idx)) & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) ? 1 : 0) - -DUK_EXTERNAL_DECL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t idx); - -DUK_EXTERNAL_DECL duk_bool_t duk_is_symbol(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx); - -#define duk_is_callable(ctx,idx) \ - duk_is_function((ctx), (idx)) -DUK_EXTERNAL_DECL duk_bool_t duk_is_constructable(duk_context *ctx, duk_idx_t idx); - -DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx); - -/* Buffers and lightfuncs are not considered primitive because they mimic - * objects and e.g. duk_to_primitive() will coerce them instead of returning - * them as is. Symbols are represented as strings internally. - */ -#define duk_is_primitive(ctx,idx) \ - duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_UNDEFINED | \ - DUK_TYPE_MASK_NULL | \ - DUK_TYPE_MASK_BOOLEAN | \ - DUK_TYPE_MASK_NUMBER | \ - DUK_TYPE_MASK_STRING | \ - DUK_TYPE_MASK_POINTER) - -/* Symbols are object coercible, covered by DUK_TYPE_MASK_STRING. */ -#define duk_is_object_coercible(ctx,idx) \ - duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_BOOLEAN | \ - DUK_TYPE_MASK_NUMBER | \ - DUK_TYPE_MASK_STRING | \ - DUK_TYPE_MASK_OBJECT | \ - DUK_TYPE_MASK_BUFFER | \ - DUK_TYPE_MASK_POINTER | \ - DUK_TYPE_MASK_LIGHTFUNC) - -DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t idx); -#define duk_is_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) != 0) -#define duk_is_eval_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_EVAL_ERROR) -#define duk_is_range_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_RANGE_ERROR) -#define duk_is_reference_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_REFERENCE_ERROR) -#define duk_is_syntax_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_SYNTAX_ERROR) -#define duk_is_type_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_TYPE_ERROR) -#define duk_is_uri_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_URI_ERROR) - -/* - * Get operations: no coercion, returns default value for invalid - * indices and invalid value types. - * - * duk_get_undefined() and duk_get_null() would be pointless and - * are not included. - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_get_string(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); -DUK_EXTERNAL_DECL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx); - -/* - * Get-with-explicit default operations: like get operations but with an - * explicit default value. - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); -DUK_EXTERNAL_DECL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); -DUK_EXTERNAL_DECL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); -DUK_EXTERNAL_DECL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); -DUK_EXTERNAL_DECL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value); -DUK_EXTERNAL_DECL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); -DUK_EXTERNAL_DECL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); -DUK_EXTERNAL_DECL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); -DUK_EXTERNAL_DECL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value); -DUK_EXTERNAL_DECL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); -DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value); -DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value); - -/* - * Opt operations: like require operations but with an explicit default value - * when value is undefined or index is invalid, null and non-matching types - * cause a TypeError. - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); -DUK_EXTERNAL_DECL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); -DUK_EXTERNAL_DECL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); -DUK_EXTERNAL_DECL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); -DUK_EXTERNAL_DECL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr); -DUK_EXTERNAL_DECL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); -DUK_EXTERNAL_DECL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); -DUK_EXTERNAL_DECL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); -DUK_EXTERNAL_DECL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value); -DUK_EXTERNAL_DECL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); -DUK_EXTERNAL_DECL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value); -DUK_EXTERNAL_DECL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value); - -/* - * Require operations: no coercion, throw error if index or type - * is incorrect. No defaulting. - */ - -#define duk_require_type_mask(ctx,idx,mask) \ - ((void) duk_check_type_mask((ctx), (idx), (mask) | DUK_TYPE_MASK_THROW)) - -DUK_EXTERNAL_DECL void duk_require_undefined(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_require_null(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); -DUK_EXTERNAL_DECL void duk_require_object(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_require_function(duk_context *ctx, duk_idx_t idx); -#define duk_require_callable(ctx,idx) \ - duk_require_function((ctx), (idx)) -DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx); - -/* Symbols are object coercible and covered by DUK_TYPE_MASK_STRING. */ -#define duk_require_object_coercible(ctx,idx) \ - ((void) duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_BOOLEAN | \ - DUK_TYPE_MASK_NUMBER | \ - DUK_TYPE_MASK_STRING | \ - DUK_TYPE_MASK_OBJECT | \ - DUK_TYPE_MASK_BUFFER | \ - DUK_TYPE_MASK_POINTER | \ - DUK_TYPE_MASK_LIGHTFUNC | \ - DUK_TYPE_MASK_THROW)) - -/* - * Coercion operations: in-place coercion, return coerced value where - * applicable. If index is invalid, throw error. Some coercions may - * throw an expected error (e.g. from a toString() or valueOf() call) - * or an internal error (e.g. from out of memory). - */ - -DUK_EXTERNAL_DECL void duk_to_undefined(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_to_null(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_to_string(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); -DUK_EXTERNAL_DECL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_uint_t flags); -DUK_EXTERNAL_DECL void *duk_to_pointer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_to_object(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hint); - -#define DUK_BUF_MODE_FIXED 0 /* internal: request fixed buffer result */ -#define DUK_BUF_MODE_DYNAMIC 1 /* internal: request dynamic buffer result */ -#define DUK_BUF_MODE_DONTCARE 2 /* internal: don't care about fixed/dynamic nature */ - -#define duk_to_buffer(ctx,idx,out_size) \ - duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_DONTCARE) -#define duk_to_fixed_buffer(ctx,idx,out_size) \ - duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_FIXED) -#define duk_to_dynamic_buffer(ctx,idx,out_size) \ - duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_DYNAMIC) - -/* safe variants of a few coercion operations */ -DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); -#define duk_safe_to_string(ctx,idx) \ - duk_safe_to_lstring((ctx), (idx), NULL) - -/* - * Value length - */ - -DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); -#if 0 -/* duk_require_length()? */ -/* duk_opt_length()? */ -#endif - -/* - * Misc conversion - */ - -DUK_EXTERNAL_DECL const char *duk_base64_encode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_base64_decode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_hex_decode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_json_decode(duk_context *ctx, duk_idx_t idx); - -DUK_EXTERNAL_DECL const char *duk_buffer_to_string(duk_context *ctx, duk_idx_t idx); - -/* - * Buffer - */ - -DUK_EXTERNAL_DECL void *duk_resize_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t new_size); -DUK_EXTERNAL_DECL void *duk_steal_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void *ptr, duk_size_t len); - -/* - * Property access - * - * The basic function assumes key is on stack. The _string variant takes - * a C string as a property name, while the _index variant takes an array - * index as a property name (e.g. 123 is equivalent to the key "123"). - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr); - -DUK_EXTERNAL_DECL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags); -DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags); - -DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_get_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len); - -/* - * Inspection - */ - -DUK_EXTERNAL_DECL void duk_inspect_value(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_inspect_callstack_entry(duk_context *ctx, duk_int_t level); - -/* - * Object prototype - */ - -DUK_EXTERNAL_DECL void duk_get_prototype(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_prototype(duk_context *ctx, duk_idx_t idx); - -/* - * Object finalizer - */ - -DUK_EXTERNAL_DECL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx); - -/* - * Global object - */ - -DUK_EXTERNAL_DECL void duk_set_global_object(duk_context *ctx); - -/* - * Duktape/C function magic value - */ - -DUK_EXTERNAL_DECL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic); -DUK_EXTERNAL_DECL duk_int_t duk_get_current_magic(duk_context *ctx); - -/* - * Module helpers: put multiple function or constant properties - */ - -DUK_EXTERNAL_DECL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_idx, const duk_function_list_entry *funcs); -DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const duk_number_list_entry *numbers); - -/* - * Object operations - */ - -DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t enum_flags); -DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_idx, duk_bool_t get_value); -DUK_EXTERNAL_DECL void duk_seal(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL void duk_freeze(duk_context *ctx, duk_idx_t obj_idx); - -/* - * String manipulation - */ - -DUK_EXTERNAL_DECL void duk_concat(duk_context *ctx, duk_idx_t count); -DUK_EXTERNAL_DECL void duk_join(duk_context *ctx, duk_idx_t count); -DUK_EXTERNAL_DECL void duk_decode_string(duk_context *ctx, duk_idx_t idx, duk_decode_char_function callback, void *udata); -DUK_EXTERNAL_DECL void duk_map_string(duk_context *ctx, duk_idx_t idx, duk_map_char_function callback, void *udata); -DUK_EXTERNAL_DECL void duk_substring(duk_context *ctx, duk_idx_t idx, duk_size_t start_char_offset, duk_size_t end_char_offset); -DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, duk_size_t char_offset); - -/* - * Ecmascript operators - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); -DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); -DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); -DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); - -/* - * Function (method) calls - */ - -DUK_EXTERNAL_DECL void duk_call(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL void duk_call_method(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs); -DUK_EXTERNAL_DECL void duk_new(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets); - -/* - * Thread management - */ - -/* There are currently no native functions to yield/resume, due to the internal - * limitations on coroutine handling. These will be added later. - */ - -/* - * Compilation and evaluation - */ - -DUK_EXTERNAL_DECL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); -DUK_EXTERNAL_DECL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); - -/* plain */ -#define duk_eval(ctx) \ - ((void) duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOFILENAME)) - -#define duk_eval_noresult(ctx) \ - ((void) duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_peval(ctx) \ - (duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_noresult(ctx) \ - (duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_compile(ctx,flags) \ - ((void) duk_compile_raw((ctx), NULL, 0, 2 /*args*/ | (flags))) - -#define duk_pcompile(ctx,flags) \ - (duk_compile_raw((ctx), NULL, 0, 2 /*args*/ | (flags) | DUK_COMPILE_SAFE)) - -/* string */ -#define duk_eval_string(ctx,src) \ - ((void) duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) - -#define duk_eval_string_noresult(ctx,src) \ - ((void) duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_string(ctx,src) \ - (duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_string_noresult(ctx,src) \ - (duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_compile_string(ctx,flags,src) \ - ((void) duk_compile_raw((ctx), (src), 0, 0 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) - -#define duk_compile_string_filename(ctx,flags,src) \ - ((void) duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) - -#define duk_pcompile_string(ctx,flags,src) \ - (duk_compile_raw((ctx), (src), 0, 0 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) - -#define duk_pcompile_string_filename(ctx,flags,src) \ - (duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) - -/* lstring */ -#define duk_eval_lstring(ctx,buf,len) \ - ((void) duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) - -#define duk_eval_lstring_noresult(ctx,buf,len) \ - ((void) duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_lstring(ctx,buf,len) \ - (duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_lstring_noresult(ctx,buf,len) \ - (duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_compile_lstring(ctx,flags,buf,len) \ - ((void) duk_compile_raw((ctx), buf, len, 0 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) - -#define duk_compile_lstring_filename(ctx,flags,buf,len) \ - ((void) duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE)) - -#define duk_pcompile_lstring(ctx,flags,buf,len) \ - (duk_compile_raw((ctx), buf, len, 0 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) - -#define duk_pcompile_lstring_filename(ctx,flags,buf,len) \ - (duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE)) - -/* - * Bytecode load/dump - */ - -DUK_EXTERNAL_DECL void duk_dump_function(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_load_function(duk_context *ctx); - -/* - * Debugging - */ - -DUK_EXTERNAL_DECL void duk_push_context_dump(duk_context *ctx); - -/* - * Debugger (debug protocol) - */ - -DUK_EXTERNAL_DECL void duk_debugger_attach(duk_context *ctx, - duk_debug_read_function read_cb, - duk_debug_write_function write_cb, - duk_debug_peek_function peek_cb, - duk_debug_read_flush_function read_flush_cb, - duk_debug_write_flush_function write_flush_cb, - duk_debug_request_function request_cb, - duk_debug_detached_function detached_cb, - void *udata); -DUK_EXTERNAL_DECL void duk_debugger_detach(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_debugger_cooperate(duk_context *ctx); -DUK_EXTERNAL_DECL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues); -DUK_EXTERNAL_DECL void duk_debugger_pause(duk_context *ctx); - -/* - * Time handling - */ - -DUK_EXTERNAL_DECL duk_double_t duk_get_now(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_time_to_components(duk_context *ctx, duk_double_t timeval, duk_time_components *comp); -DUK_EXTERNAL_DECL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_components *comp); - -/* - * Date provider related constants - * - * NOTE: These are "semi public" - you should only use these if you write - * your own platform specific Date provider, see doc/datetime.rst. - */ - -/* Millisecond count constants. */ -#define DUK_DATE_MSEC_SECOND 1000L -#define DUK_DATE_MSEC_MINUTE (60L * 1000L) -#define DUK_DATE_MSEC_HOUR (60L * 60L * 1000L) -#define DUK_DATE_MSEC_DAY (24L * 60L * 60L * 1000L) - -/* Ecmascript date range is 100 million days from Epoch: - * > 100e6 * 24 * 60 * 60 * 1000 // 100M days in millisecs - * 8640000000000000 - * (= 8.64e15) - */ -#define DUK_DATE_MSEC_100M_DAYS (8.64e15) -#define DUK_DATE_MSEC_100M_DAYS_LEEWAY (8.64e15 + 24 * 3600e3) - -/* Ecmascript year range: - * > new Date(100e6 * 24 * 3600e3).toISOString() - * '+275760-09-13T00:00:00.000Z' - * > new Date(-100e6 * 24 * 3600e3).toISOString() - * '-271821-04-20T00:00:00.000Z' - */ -#define DUK_DATE_MIN_ECMA_YEAR (-271821L) -#define DUK_DATE_MAX_ECMA_YEAR 275760L - -/* Part indices for internal breakdowns. Part order from DUK_DATE_IDX_YEAR - * to DUK_DATE_IDX_MILLISECOND matches argument ordering of Ecmascript API - * calls (like Date constructor call). Some functions in duk_bi_date.c - * depend on the specific ordering, so change with care. 16 bits are not - * enough for all parts (year, specifically). - * - * Must be in-sync with genbuiltins.py. - */ -#define DUK_DATE_IDX_YEAR 0 /* year */ -#define DUK_DATE_IDX_MONTH 1 /* month: 0 to 11 */ -#define DUK_DATE_IDX_DAY 2 /* day within month: 0 to 30 */ -#define DUK_DATE_IDX_HOUR 3 -#define DUK_DATE_IDX_MINUTE 4 -#define DUK_DATE_IDX_SECOND 5 -#define DUK_DATE_IDX_MILLISECOND 6 -#define DUK_DATE_IDX_WEEKDAY 7 /* weekday: 0 to 6, 0=sunday, 1=monday, etc */ -#define DUK_DATE_IDX_NUM_PARTS 8 - -/* Internal API call flags, used for various functions in duk_bi_date.c. - * Certain flags are used by only certain functions, but since the flags - * don't overlap, a single flags value can be passed around to multiple - * functions. - * - * The unused top bits of the flags field are also used to pass values - * to helpers (duk__get_part_helper() and duk__set_part_helper()). - * - * Must be in-sync with genbuiltins.py. - */ - -/* NOTE: when writing a Date provider you only need a few specific - * flags from here, the rest are internal. Avoid using anything you - * don't need. - */ - -#define DUK_DATE_FLAG_NAN_TO_ZERO (1 << 0) /* timeval breakdown: internal time value NaN -> zero */ -#define DUK_DATE_FLAG_NAN_TO_RANGE_ERROR (1 << 1) /* timeval breakdown: internal time value NaN -> RangeError (toISOString) */ -#define DUK_DATE_FLAG_ONEBASED (1 << 2) /* timeval breakdown: convert month and day-of-month parts to one-based (default is zero-based) */ -#define DUK_DATE_FLAG_EQUIVYEAR (1 << 3) /* timeval breakdown: replace year with equivalent year in the [1971,2037] range for DST calculations */ -#define DUK_DATE_FLAG_LOCALTIME (1 << 4) /* convert time value to local time */ -#define DUK_DATE_FLAG_SUB1900 (1 << 5) /* getter: subtract 1900 from year when getting year part */ -#define DUK_DATE_FLAG_TOSTRING_DATE (1 << 6) /* include date part in string conversion result */ -#define DUK_DATE_FLAG_TOSTRING_TIME (1 << 7) /* include time part in string conversion result */ -#define DUK_DATE_FLAG_TOSTRING_LOCALE (1 << 8) /* use locale specific formatting if available */ -#define DUK_DATE_FLAG_TIMESETTER (1 << 9) /* setter: call is a time setter (affects hour, min, sec, ms); otherwise date setter (affects year, month, day-in-month) */ -#define DUK_DATE_FLAG_YEAR_FIXUP (1 << 10) /* setter: perform 2-digit year fixup (00...99 -> 1900...1999) */ -#define DUK_DATE_FLAG_SEP_T (1 << 11) /* string conversion: use 'T' instead of ' ' as a separator */ -#define DUK_DATE_FLAG_VALUE_SHIFT 12 /* additional values begin at bit 12 */ - -/* - * ROM pointer compression - */ - -/* Support array for ROM pointer compression. Only declared when ROM - * pointer compression is active. - */ -#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16) -DUK_EXTERNAL_DECL const void * const duk_rom_compressed_pointers[]; -#endif - -/* - * C++ name mangling - */ - -#if defined(__cplusplus) -/* end 'extern "C"' wrapper */ -} -#endif - -/* - * END PUBLIC API - */ - -#endif /* DUKTAPE_H_INCLUDED */ diff --git a/dep/fmt/CMakeLists.txt b/dep/fmt/CMakeLists.txt index 519fa65b7d0..fc9b1f79134 100644 --- a/dep/fmt/CMakeLists.txt +++ b/dep/fmt/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2018 TrinityCore +# This file is part of the TrinityCore Project. See AUTHORS file for Copyright information # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -8,43 +8,30 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -include(CheckSymbolExists) -if (WIN32) - check_symbol_exists(open io.h HAVE_OPEN) -else () - check_symbol_exists(open fcntl.h HAVE_OPEN) -endif () +set(FMT_HEADERS + include/fmt/args.h + include/fmt/chrono.h + include/fmt/color.h + include/fmt/compile.h + include/fmt/core.h + include/fmt/format.h + include/fmt/format-inl.h + include/fmt/os.h + include/fmt/ostream.h + include/fmt/printf.h + include/fmt/ranges.h + include/fmt/std.h + include/fmt/xchar.h) set(FMT_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/container.h - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/format.h - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/format.cc - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/ostream.h - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/ostream.cc - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/printf.h - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/printf.cc - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/string.h - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/time.h) + src/format.cc + src/os.cc) -if (HAVE_OPEN) - set(FMT_SOURCES ${FMT_SOURCES} - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/posix.h - ${CMAKE_CURRENT_SOURCE_DIR}/fmt/posix.cc) -endif() - -add_library(fmt STATIC ${FMT_SOURCES}) +add_library(fmt STATIC ${FMT_SOURCES} ${FMT_HEADERS}) target_include_directories(fmt PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}) - -target_compile_definitions(fmt - PUBLIC - -DFMT_USE_OVERRIDE - -DFMT_USE_VARIADIC_TEMPLATES - -DFMT_USE_RVALUE_REFERENCES - -DFMT_USE_DELETED_FUNCTIONS - -DFMT_USE_EXTERN_TEMPLATES) + ${CMAKE_CURRENT_SOURCE_DIR}/include) target_link_libraries(fmt PRIVATE diff --git a/dep/fmt/CONTRIBUTING.md b/dep/fmt/CONTRIBUTING.md new file mode 100644 index 00000000000..b82f145069a --- /dev/null +++ b/dep/fmt/CONTRIBUTING.md @@ -0,0 +1,20 @@ +Contributing to {fmt} +===================== + +By submitting a pull request or a patch, you represent that you have the right +to license your contribution to the {fmt} project owners and the community, +agree that your contributions are licensed under the {fmt} license, and agree +to future changes to the licensing. + +All C++ code must adhere to [Google C++ Style Guide]( +https://google.github.io/styleguide/cppguide.html) with the following +exceptions: + +* Exceptions are permitted +* snake_case should be used instead of UpperCamelCase for function and type + names + +All documentation must adhere to the [Google Developer Documentation Style +Guide](https://developers.google.com/style). + +Thanks for contributing! diff --git a/dep/fmt/CONTRIBUTING.rst b/dep/fmt/CONTRIBUTING.rst deleted file mode 100644 index 506811d4a45..00000000000 --- a/dep/fmt/CONTRIBUTING.rst +++ /dev/null @@ -1,11 +0,0 @@ -Contributing to fmt -=================== - -All C++ code must adhere to `Google C++ Style Guide -`_ with the following -exceptions: - -* Exceptions are permitted -* snake_case should be used instead of UpperCamelCase for function names - -Thanks for contributing! diff --git a/dep/fmt/ChangeLog.rst b/dep/fmt/ChangeLog.rst index 1633bac7121..9c171af0505 100644 --- a/dep/fmt/ChangeLog.rst +++ b/dep/fmt/ChangeLog.rst @@ -1,12 +1,2547 @@ -4.0.1 - TBD ------------ +7.1.3 - 2020-11-24 +------------------ + +* Fixed handling of buffer boundaries in ``format_to_n`` + (`#1996 `_, + `#2029 `_). + +* Fixed linkage errors when linking with a shared library + (`#2011 `_). + +* Reintroduced ostream support to range formatters + (`#2014 `_). + +* Worked around an issue with mixing std versions in gcc + (`#2017 `_). + +7.1.2 - 2020-11-04 +------------------ + +* Fixed floating point formatting with large precision + (`#1976 `_). + +7.1.1 - 2020-11-01 +------------------ + +* Fixed ABI compatibility with 7.0.x + (`#1961 `_). + +* Added the ``FMT_ARM_ABI_COMPATIBILITY`` macro to work around ABI + incompatibility between GCC and Clang on ARM + (`#1919 `_). + +* Worked around a SFINAE bug in GCC 8 + (`#1957 `_). + +* Fixed linkage errors when building with GCC's LTO + (`#1955 `_). + +* Fixed a compilation error when building without ``__builtin_clz`` or equivalent + (`#1968 `_). + Thanks `@tohammer (Tobias Hammer) `_. + +* Fixed a sign conversion warning + (`#1964 `_). + Thanks `@OptoCloud `_. + +7.1.0 - 2020-10-25 +------------------ + +* Switched from `Grisu3 + `_ + to `Dragonbox `_ for the default + floating-point formatting which gives the shortest decimal representation + with round-trip guarantee and correct rounding + (`#1882 `_, + `#1887 `_, + `#1894 `_). This makes {fmt} up to + 20-30x faster than common implementations of ``std::ostringstream`` and + ``sprintf`` on `dtoa-benchmark `_ + and faster than double-conversion and RyÅ«: + + .. image:: https://user-images.githubusercontent.com/576385/ + 95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png + + It is possible to get even better performance at the cost of larger binary + size by compiling with the ``FMT_USE_FULL_CACHE_DRAGONBOX`` macro set to 1. + + Thanks `@jk-jeon (Junekey Jeon) `_. + +* Added an experimental unsynchronized file output API which, together with + `format string compilation `_, + can give `5-9 times speed up compared to fprintf + `_ + on common platforms (`godbolt `__): + + .. code:: c++ + + #include + + int main() { + auto f = fmt::output_file("guide"); + f.print("The answer is {}.", 42); + } + +* Added a formatter for ``std::chrono::time_point`` + (`#1819 `_, + `#1837 `_). For example + (`godbolt `__): + + .. code:: c++ + + #include + + int main() { + auto now = std::chrono::system_clock::now(); + fmt::print("The time is {:%H:%M:%S}.\n", now); + } + + Thanks `@adamburgess (Adam Burgess) `_. + +* Added support for ranges with non-const ``begin``/``end`` to ``fmt::join`` + (`#1784 `_, + `#1786 `_). For example + (`godbolt `__): + + .. code:: c++ + + #include + #include + + int main() { + using std::literals::string_literals::operator""s; + auto strs = std::array{"a"s, "bb"s, "ccc"s}; + auto range = strs | ranges::views::filter( + [] (const std::string &x) { return x.size() != 2; } + ); + fmt::print("{}\n", fmt::join(range, "")); + } + + prints "accc". + + Thanks `@tonyelewis (Tony E Lewis) `_. + +* Added a ``memory_buffer::append`` overload that takes a range + (`#1806 `_). + Thanks `@BRevzin (Barry Revzin) `_. + +* Improved handling of single code units in ``FMT_COMPILE``. For example: + + .. code:: c++ + + #include + + char* f(char* buf) { + return fmt::format_to(buf, FMT_COMPILE("x{}"), 42); + } + + compiles to just (`godbolt `__): + + .. code:: asm + + _Z1fPc: + movb $120, (%rdi) + xorl %edx, %edx + cmpl $42, _ZN3fmt2v76detail10basic_dataIvE23zero_or_powers_of_10_32E+8(%rip) + movl $3, %eax + seta %dl + subl %edx, %eax + movzwl _ZN3fmt2v76detail10basic_dataIvE6digitsE+84(%rip), %edx + cltq + addq %rdi, %rax + movw %dx, -2(%rax) + ret + + Here a single ``mov`` instruction writes ``'x'`` (``$120``) to the output + buffer. + +* Added dynamic width support to format string compilation + (`#1809 `_). + +* Improved error reporting for unformattable types: now you'll get the type name + directly in the error message instead of the note: + + .. code:: c++ + + #include + + struct how_about_no {}; + + int main() { + fmt::print("{}", how_about_no()); + } + + Error (`godbolt `__): + + ``fmt/core.h:1438:3: error: static_assert failed due to requirement + 'fmt::v7::formattable()' "Cannot format an argument. + To make type T formattable provide a formatter specialization: + https://fmt.dev/latest/api.html#udt" + ...`` + +* Added the `make_args_checked `_ + function template that allows you to write formatting functions with + compile-time format string checks and avoid binary code bloat + (`godbolt `__): + + .. code:: c++ + + void vlog(const char* file, int line, fmt::string_view format, + fmt::format_args args) { + fmt::print("{}: {}: ", file, line); + fmt::vprint(format, args); + } + + template + void log(const char* file, int line, const S& format, Args&&... args) { + vlog(file, line, format, + fmt::make_args_checked(format, args...)); + } + + #define MY_LOG(format, ...) \ + log(__FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__) + + MY_LOG("invalid squishiness: {}", 42); + +* Replaced ``snprintf`` fallback with a faster internal IEEE 754 ``float`` and + ``double`` formatter for arbitrary precision. For example + (`godbolt `__): + + .. code:: c++ + + #include + + int main() { + fmt::print("{:.500}\n", 4.9406564584124654E-324); + } + + prints + + ``4.9406564584124654417656879286822137236505980261432476442558568250067550727020875186529983636163599237979656469544571773092665671035593979639877479601078187812630071319031140452784581716784898210368871863605699873072305000638740915356498438731247339727316961514003171538539807412623856559117102665855668676818703956031062493194527159149245532930545654440112748012970999954193198940908041656332452475714786901472678015935523861155013480352649347201937902681071074917033322268447533357208324319360923829e-324``. + +* Made ``format_to_n`` and ``formatted_size`` part of the `core API + `__ + (`godbolt `__): + + .. code:: c++ + + #include + + int main() { + char buffer[10]; + auto result = fmt::format_to_n(buffer, sizeof(buffer), "{}", 42); + } + +* Added ``fmt::format_to_n`` overload with format string compilation + (`#1764 `_, + `#1767 `_, + `#1869 `_). For example + (`godbolt `__): + + .. code:: c++ + + #include + + int main() { + char buffer[8]; + fmt::format_to_n(buffer, sizeof(buffer), FMT_COMPILE("{}"), 42); + } + + Thanks `@Kurkin (Dmitry Kurkin) `_, + `@alexezeder (Alexey Ochapov) `_. + +* Added ``fmt::format_to`` overload that take ``text_style`` + (`#1593 `_, + `#1842 `_, + `#1843 `_). For example + (`godbolt `__): + + .. code:: c++ + + #include + + int main() { + std::string out; + fmt::format_to(std::back_inserter(out), + fmt::emphasis::bold | fg(fmt::color::red), + "The answer is {}.", 42); + } + + Thanks `@Naios (Denis Blank) `_. + +* Made the ``#`` specifier emit trailing zeros in addition to the decimal point + (`#1797 `_). For example + (`godbolt `__): + + .. code:: c++ + + #include + + int main() { + fmt::print("{:#.2g}", 0.5); + } + + prints ``0.50``. + +* Changed the default floating point format to not include ``.0`` for + consistency with ``std::format`` and ``std::to_chars`` + (`#1893 `_, + `#1943 `_). It is possible to get + the decimal point and trailing zero with the ``#`` specifier. + +* Fixed an issue with floating-point formatting that could result in addition of + a non-significant trailing zero in rare cases e.g. ``1.00e-34`` instead of + ``1.0e-34`` (`#1873 `_, + `#1917 `_). + +* Made ``fmt::to_string`` fallback on ``ostream`` insertion operator if + the ``formatter`` specialization is not provided + (`#1815 `_, + `#1829 `_). + Thanks `@alexezeder (Alexey Ochapov) `_. + +* Added support for the append mode to the experimental file API and + improved ``fcntl.h`` detection. + (`#1847 `_, + `#1848 `_). + Thanks `@t-wiser `_. + +* Fixed handling of types that have both an implicit conversion operator and + an overloaded ``ostream`` insertion operator + (`#1766 `_). + +* Fixed a slicing issue in an internal iterator type + (`#1822 `_). + Thanks `@BRevzin (Barry Revzin) `_. + +* Fixed an issue in locale-specific integer formatting + (`#1927 `_). + +* Fixed handling of exotic code unit types + (`#1870 `_, + `#1932 `_). + +* Improved ``FMT_ALWAYS_INLINE`` + (`#1878 `_). + Thanks `@jk-jeon (Junekey Jeon) `_. + +* Removed dependency on ``windows.h`` + (`#1900 `_). + Thanks `@bernd5 (Bernd Baumanns) `_. + +* Optimized counting of decimal digits on MSVC + (`#1890 `_). + Thanks `@mwinterb `_. + +* Improved documentation + (`#1772 `_, + `#1775 `_, + `#1792 `_, + `#1838 `_, + `#1888 `_, + `#1918 `_, + `#1939 `_). + Thanks `@leolchat (Léonard Gérard) `_, + `@pepsiman (Malcolm Parsons) `_, + `@Klaim (Joël Lamotte) `_, + `@ravijanjam (Ravi J) `_, + `@francesco-st `_, + `@udnaan (Adnan) `_. + +* Added the ``FMT_REDUCE_INT_INSTANTIATIONS`` CMake option that reduces the + binary code size at the cost of some integer formatting performance. This can + be useful for extremely memory-constrained embedded systems + (`#1778 `_, + `#1781 `_). + Thanks `@kammce (Khalil Estell) `_. + +* Added the ``FMT_USE_INLINE_NAMESPACES`` macro to control usage of inline + namespaces (`#1945 `_). + Thanks `@darklukee `_. + +* Improved build configuration + (`#1760 `_, + `#1770 `_, + `#1779 `_, + `#1783 `_, + `#1823 `_). + Thanks `@dvetutnev (Dmitriy Vetutnev) `_, + `@xvitaly (Vitaly Zaitsev) `_, + `@tambry (Raul Tambre) `_, + `@medithe `_, + `@martinwuehrer (Martin Wührer) `_. + +* Fixed various warnings and compilation issues + (`#1790 `_, + `#1802 `_, + `#1808 `_, + `#1810 `_, + `#1811 `_, + `#1812 `_, + `#1814 `_, + `#1816 `_, + `#1817 `_, + `#1818 `_, + `#1825 `_, + `#1836 `_, + `#1855 `_, + `#1856 `_, + `#1860 `_, + `#1877 `_, + `#1879 `_, + `#1880 `_, + `#1896 `_, + `#1897 `_, + `#1898 `_, + `#1904 `_, + `#1908 `_, + `#1911 `_, + `#1912 `_, + `#1928 `_, + `#1929 `_, + `#1935 `_ + `#1937 `_, + `#1942 `_, + `#1949 `_). + Thanks `@TheQwertiest `_, + `@medithe `_, + `@martinwuehrer (Martin Wührer) `_, + `@n16h7hunt3r `_, + `@Othereum (Seokjin Lee) `_, + `@gsjaardema (Greg Sjaardema) `_, + `@AlexanderLanin (Alexander Lanin) `_, + `@gcerretani (Giovanni Cerretani) `_, + `@chronoxor (Ivan Shynkarenka) `_, + `@noizefloor (Jan Schwers) `_, + `@akohlmey (Axel Kohlmeyer) `_, + `@jk-jeon (Junekey Jeon) `_, + `@rimathia `_, + `@rglarix (Riccardo Ghetta (larix)) `_, + `@moiwi `_, + `@heckad (Kazantcev Andrey) `_, + `@MarcDirven `_. + `@BartSiwek (Bart Siwek) `_, + `@darklukee `_. + +7.0.3 - 2020-08-06 +------------------ + +* Worked around broken ``numeric_limits`` for 128-bit integers + (`#1787 `_). + +* Added error reporting on missing named arguments + (`#1796 `_). + +* Stopped using 128-bit integers with clang-cl + (`#1800 `_). + Thanks `@Kingcom `_. + +* Fixed issues in locale-specific integer formatting + (`#1782 `_, + `#1801 `_). + +7.0.2 - 2020-07-29 +------------------ + +* Worked around broken ``numeric_limits`` for 128-bit integers + (`#1725 `_). + +* Fixed compatibility with CMake 3.4 + (`#1779 `_). + +* Fixed handling of digit separators in locale-specific formatting + (`#1782 `_). + +7.0.1 - 2020-07-07 +------------------ + +* Updated the inline version namespace name. + +* Worked around a gcc bug in mangling of alias templates + (`#1753 `_). + +* Fixed a linkage error on Windows + (`#1757 `_). + Thanks `@Kurkin (Dmitry Kurkin) `_. + +* Fixed minor issues with the documentation. + +7.0.0 - 2020-07-05 +------------------ + +* Reduced the library size. For example, on macOS a stripped test binary + statically linked with {fmt} `shrank from ~368k to less than 100k + `_. + +* Added a simpler and more efficient `format string compilation API + `_: + + .. code:: c++ + + #include + + // Converts 42 into std::string using the most efficient method and no + // runtime format string processing. + std::string s = fmt::format(FMT_COMPILE("{}"), 42); + + The old ``fmt::compile`` API is now deprecated. + +* Optimized integer formatting: ``format_to`` with format string compilation + and a stack-allocated buffer is now `faster than to_chars on both + libc++ and libstdc++ + `_. + +* Optimized handling of small format strings. For example, + + .. code:: c++ + + fmt::format("Result: {}: ({},{},{},{})", str1, str2, str3, str4, str5) + + is now ~40% faster (`#1685 `_). + +* Applied extern templates to improve compile times when using the core API + and ``fmt/format.h`` (`#1452 `_). + For example, on macOS with clang the compile time of a test translation unit + dropped from 2.3s to 0.3s with ``-O2`` and from 0.6s to 0.3s with the default + settings (``-O0``). + + Before (``-O2``):: + + % time c++ -c test.cc -I include -std=c++17 -O2 + c++ -c test.cc -I include -std=c++17 -O2 2.22s user 0.08s system 99% cpu 2.311 total + + After (``-O2``):: + + % time c++ -c test.cc -I include -std=c++17 -O2 + c++ -c test.cc -I include -std=c++17 -O2 0.26s user 0.04s system 98% cpu 0.303 total + + Before (default):: + + % time c++ -c test.cc -I include -std=c++17 + c++ -c test.cc -I include -std=c++17 0.53s user 0.06s system 98% cpu 0.601 total + + After (default):: + + % time c++ -c test.cc -I include -std=c++17 + c++ -c test.cc -I include -std=c++17 0.24s user 0.06s system 98% cpu 0.301 total + + It is still recommended to use ``fmt/core.h`` instead of ``fmt/format.h`` but + the compile time difference is now smaller. Thanks + `@alex3d `_ for the suggestion. + +* Named arguments are now stored on stack (no dynamic memory allocations) and + the compiled code is more compact and efficient. For example + + .. code:: c++ + + #include + + int main() { + fmt::print("The answer is {answer}\n", fmt::arg("answer", 42)); + } + + compiles to just (`godbolt `__) + + .. code:: asm + + .LC0: + .string "answer" + .LC1: + .string "The answer is {answer}\n" + main: + sub rsp, 56 + mov edi, OFFSET FLAT:.LC1 + mov esi, 23 + movabs rdx, 4611686018427387905 + lea rax, [rsp+32] + lea rcx, [rsp+16] + mov QWORD PTR [rsp+8], 1 + mov QWORD PTR [rsp], rax + mov DWORD PTR [rsp+16], 42 + mov QWORD PTR [rsp+32], OFFSET FLAT:.LC0 + mov DWORD PTR [rsp+40], 0 + call fmt::v6::vprint(fmt::v6::basic_string_view, + fmt::v6::format_args) + xor eax, eax + add rsp, 56 + ret + + .L.str.1: + .asciz "answer" + +* Implemented compile-time checks for dynamic width and precision + (`#1614 `_): + + .. code:: c++ + + #include + + int main() { + fmt::print(FMT_STRING("{0:{1}}"), 42); + } + + now gives a compilation error because argument 1 doesn't exist:: + + In file included from test.cc:1: + include/fmt/format.h:2726:27: error: constexpr variable 'invalid_format' must be + initialized by a constant expression + FMT_CONSTEXPR_DECL bool invalid_format = + ^ + ... + include/fmt/core.h:569:26: note: in call to + '&checker(s, {}).context_->on_error(&"argument not found"[0])' + if (id >= num_args_) on_error("argument not found"); + ^ + +* Added sentinel support to ``fmt::join`` + (`#1689 `_) + + .. code:: c++ + + struct zstring_sentinel {}; + bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; } + bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; } + + struct zstring { + const char* p; + const char* begin() const { return p; } + zstring_sentinel end() const { return {}; } + }; + + auto s = fmt::format("{}", fmt::join(zstring{"hello"}, "_")); + // s == "h_e_l_l_o" + + Thanks `@BRevzin (Barry Revzin) `_. + +* Added support for named arguments, ``clear`` and ``reserve`` to + ``dynamic_format_arg_store`` + (`#1655 `_, + `#1663 `_, + `#1674 `_, + `#1677 `_). + Thanks `@vsolontsov-ll (Vladimir Solontsov) + `_. + +* Added support for the ``'c'`` format specifier to integral types for + compatibility with ``std::format`` + (`#1652 `_). + +* Replaced the ``'n'`` format specifier with ``'L'`` for compatibility with + ``std::format`` (`#1624 `_). + The ``'n'`` specifier can be enabled via the ``FMT_DEPRECATED_N_SPECIFIER`` + macro. + +* The ``'='`` format specifier is now disabled by default for compatibility with + ``std::format``. It can be enabled via the ``FMT_DEPRECATED_NUMERIC_ALIGN`` + macro. + +* Removed the following deprecated APIs: + + * ``FMT_STRING_ALIAS`` and ``fmt`` macros - replaced by ``FMT_STRING`` + * ``fmt::basic_string_view::char_type`` - replaced by + ``fmt::basic_string_view::value_type`` + * ``convert_to_int`` + * ``format_arg_store::types`` + * ``*parse_context`` - replaced by ``*format_parse_context`` + * ``FMT_DEPRECATED_INCLUDE_OS`` + * ``FMT_DEPRECATED_PERCENT`` - incompatible with ``std::format`` + * ``*writer`` - replaced by compiled format API + +* Renamed the ``internal`` namespace to ``detail`` + (`#1538 `_). The former is still + provided as an alias if the ``FMT_USE_INTERNAL`` macro is defined. + +* Improved compatibility between ``fmt::printf`` with the standard specs + (`#1595 `_, + `#1682 `_, + `#1683 `_, + `#1687 `_, + `#1699 `_). + Thanks `@rimathia `_. + +* Fixed handling of ``operator<<`` overloads that use ``copyfmt`` + (`#1666 `_). + +* Added the ``FMT_OS`` CMake option to control inclusion of OS-specific APIs + in the fmt target. This can be useful for embedded platforms + (`#1654 `_, + `#1656 `_). + Thanks `@kwesolowski (Krzysztof Wesolowski) + `_. + +* Replaced ``FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION`` with the ``FMT_FUZZ`` + macro to prevent interferring with fuzzing of projects using {fmt} + (`#1650 `_). + Thanks `@asraa (Asra Ali) `_. + +* Fixed compatibility with emscripten + (`#1636 `_, + `#1637 `_). + Thanks `@ArthurSonzogni (Arthur Sonzogni) + `_. + +* Improved documentation + (`#704 `_, + `#1643 `_, + `#1660 `_, + `#1681 `_, + `#1691 `_, + `#1706 `_, + `#1714 `_, + `#1721 `_, + `#1739 `_, + `#1740 `_, + `#1741 `_, + `#1751 `_). + Thanks `@senior7515 (Alexander Gallego) `_, + `@lsr0 (Lindsay Roberts) `_, + `@puetzk (Kevin Puetz) `_, + `@fpelliccioni (Fernando Pelliccioni) `_, + Alexey Kuzmenko, `@jelly (jelle van der Waa) `_, + `@claremacrae (Clare Macrae) `_, + `@jiapengwen (文佳é¹) `_, + `@gsjaardema (Greg Sjaardema) `_, + `@alexey-milovidov `_. + +* Implemented various build configuration fixes and improvements + (`#1603 `_, + `#1657 `_, + `#1702 `_, + `#1728 `_). + Thanks `@scramsby (Scott Ramsby) `_, + `@jtojnar (Jan Tojnar) `_, + `@orivej (Orivej Desh) `_, + `@flagarde `_. + +* Fixed various warnings and compilation issues + (`#1616 `_, + `#1620 `_, + `#1622 `_, + `#1625 `_, + `#1627 `_, + `#1628 `_, + `#1629 `_, + `#1631 `_, + `#1633 `_, + `#1649 `_, + `#1658 `_, + `#1661 `_, + `#1667 `_, + `#1668 `_, + `#1669 `_, + `#1692 `_, + `#1696 `_, + `#1697 `_, + `#1707 `_, + `#1712 `_, + `#1716 `_, + `#1722 `_, + `#1724 `_, + `#1729 `_, + `#1738 `_, + `#1742 `_, + `#1743 `_, + `#1744 `_, + `#1747 `_, + `#1750 `_). + Thanks `@gsjaardema (Greg Sjaardema) `_, + `@gabime (Gabi Melman) `_, + `@johnor (Johan) `_, + `@Kurkin (Dmitry Kurkin) `_, + `@invexed (James Beach) `_, + `@peterbell10 `_, + `@daixtrose (Markus Werle) `_, + `@petrutlucian94 (Lucian Petrut) `_, + `@Neargye (Daniil Goncharov) `_, + `@ambitslix (Attila M. Szilagyi) `_, + `@gabime (Gabi Melman) `_, + `@erthink (Leonid Yuriev) `_, + `@tohammer (Tobias Hammer) `_, + `@0x8000-0000 (Florin Iucha) `_. + +6.2.1 - 2020-05-09 +------------------ + +* Fixed ostream support in ``sprintf`` + (`#1631 `_). + +* Fixed type detection when using implicit conversion to ``string_view`` and + ostream ``operator<<`` inconsistently + (`#1662 `_). + +6.2.0 - 2020-04-05 +------------------ + +* Improved error reporting when trying to format an object of a non-formattable + type: + + .. code:: c++ + + fmt::format("{}", S()); + + now gives:: + + include/fmt/core.h:1015:5: error: static_assert failed due to requirement + 'formattable' "Cannot format argument. To make type T formattable provide a + formatter specialization: + https://fmt.dev/latest/api.html#formatting-user-defined-types" + static_assert( + ^ + ... + note: in instantiation of function template specialization + 'fmt::v6::format' requested here + fmt::format("{}", S()); + ^ + + if ``S`` is not formattable. + +* Reduced the library size by ~10%. + +* Always print decimal point if ``#`` is specified + (`#1476 `_, + `#1498 `_): + + .. code:: c++ + + fmt::print("{:#.0f}", 42.0); + + now prints ``42.`` + +* Implemented the ``'L'`` specifier for locale-specific numeric formatting to + improve compatibility with ``std::format``. The ``'n'`` specifier is now + deprecated and will be removed in the next major release. + +* Moved OS-specific APIs such as ``windows_error`` from ``fmt/format.h`` to + ``fmt/os.h``. You can define ``FMT_DEPRECATED_INCLUDE_OS`` to automatically + include ``fmt/os.h`` from ``fmt/format.h`` for compatibility but this will be + disabled in the next major release. + +* Added precision overflow detection in floating-point formatting. + +* Implemented detection of invalid use of ``fmt::arg``. + +* Used ``type_identity`` to block unnecessary template argument deduction. + Thanks Tim Song. + +* Improved UTF-8 handling + (`#1109 `_): + + .. code:: c++ + + fmt::print("┌{0:─^{2}}â”\n" + "│{1: ^{2}}│\n" + "â””{0:─^{2}}┘\n", "", "Привет, мир!", 20); + + now prints:: + + ┌────────────────────┠+ │ Привет, мир! │ + └────────────────────┘ + + on systems that support Unicode. + +* Added experimental dynamic argument storage + (`#1170 `_, + `#1584 `_): + + .. code:: c++ + + fmt::dynamic_format_arg_store store; + store.push_back("answer"); + store.push_back(42); + fmt::vprint("The {} is {}.\n", store); + + prints:: + + The answer is 42. + + Thanks `@vsolontsov-ll (Vladimir Solontsov) + `_. + +* Made ``fmt::join`` accept ``initializer_list`` + (`#1591 `_). + Thanks `@Rapotkinnik (Nikolay Rapotkin) `_. + +* Fixed handling of empty tuples + (`#1588 `_). + +* Fixed handling of output iterators in ``format_to_n`` + (`#1506 `_). + +* Fixed formatting of ``std::chrono::duration`` types to wide output + (`#1533 `_). + Thanks `@zeffy (pilao) `_. + +* Added const ``begin`` and ``end`` overload to buffers + (`#1553 `_). + Thanks `@dominicpoeschko `_. + +* Added the ability to disable floating-point formatting via ``FMT_USE_FLOAT``, + ``FMT_USE_DOUBLE`` and ``FMT_USE_LONG_DOUBLE`` macros for extremely + memory-constrained embedded system + (`#1590 `_). + Thanks `@albaguirre (Alberto Aguirre) `_. + +* Made ``FMT_STRING`` work with ``constexpr`` ``string_view`` + (`#1589 `_). + Thanks `@scramsby (Scott Ramsby) `_. + +* Implemented a minor optimization in the format string parser + (`#1560 `_). + Thanks `@IkarusDeveloper `_. + +* Improved attribute detection + (`#1469 `_, + `#1475 `_, + `#1576 `_). + Thanks `@federico-busato (Federico) `_, + `@chronoxor (Ivan Shynkarenka) `_, + `@refnum `_. + +* Improved documentation + (`#1481 `_, + `#1523 `_). + Thanks `@JackBoosY (Jack·Boos·Yu) `_, + `@imba-tjd (è°­ä¹é¼Ž) `_. + +* Fixed symbol visibility on Linux when compiling with ``-fvisibility=hidden`` + (`#1535 `_). + Thanks `@milianw (Milian Wolff) `_. + +* Implemented various build configuration fixes and improvements + (`#1264 `_, + `#1460 `_, + `#1534 `_, + `#1536 `_, + `#1545 `_, + `#1546 `_, + `#1566 `_, + `#1582 `_, + `#1597 `_, + `#1598 `_). + Thanks `@ambitslix (Attila M. Szilagyi) `_, + `@jwillikers (Jordan Williams) `_, + `@stac47 (Laurent Stacul) `_. + +* Fixed various warnings and compilation issues + (`#1433 `_, + `#1461 `_, + `#1470 `_, + `#1480 `_, + `#1485 `_, + `#1492 `_, + `#1493 `_, + `#1504 `_, + `#1505 `_, + `#1512 `_, + `#1515 `_, + `#1516 `_, + `#1518 `_, + `#1519 `_, + `#1520 `_, + `#1521 `_, + `#1522 `_, + `#1524 `_, + `#1530 `_, + `#1531 `_, + `#1532 `_, + `#1539 `_, + `#1547 `_, + `#1548 `_, + `#1554 `_, + `#1567 `_, + `#1568 `_, + `#1569 `_, + `#1571 `_, + `#1573 `_, + `#1575 `_, + `#1581 `_, + `#1583 `_, + `#1586 `_, + `#1587 `_, + `#1594 `_, + `#1596 `_, + `#1604 `_, + `#1606 `_, + `#1607 `_, + `#1609 `_). + Thanks `@marti4d (Chris Martin) `_, + `@iPherian `_, + `@parkertomatoes `_, + `@gsjaardema (Greg Sjaardema) `_, + `@chronoxor (Ivan Shynkarenka) `_, + `@DanielaE (Daniela Engert) `_, + `@torsten48 `_, + `@tohammer (Tobias Hammer) `_, + `@lefticus (Jason Turner) `_, + `@ryusakki (Haise) `_, + `@adnsv (Alex Denisov) `_, + `@fghzxm `_, + `@refnum `_, + `@pramodk (Pramod Kumbhar) `_, + `@Spirrwell `_, + `@scramsby (Scott Ramsby) `_. + +6.1.2 - 2019-12-11 +------------------ + +* Fixed ABI compatibility with ``libfmt.so.6.0.0`` + (`#1471 `_). + +* Fixed handling types convertible to ``std::string_view`` + (`#1451 `_). + Thanks `@denizevrenci (Deniz Evrenci) `_. + +* Made CUDA test an opt-in enabled via the ``FMT_CUDA_TEST`` CMake option. + +* Fixed sign conversion warnings + (`#1440 `_). + Thanks `@0x8000-0000 (Florin Iucha) `_. + +6.1.1 - 2019-12-04 +------------------ + +* Fixed shared library build on Windows + (`#1443 `_, + `#1445 `_, + `#1446 `_, + `#1450 `_). + Thanks `@egorpugin (Egor Pugin) `_, + `@bbolli (Beat Bolli) `_. + +* Added a missing decimal point in exponent notation with trailing zeros. + +* Removed deprecated ``format_arg_store::TYPES``. + +6.1.0 - 2019-12-01 +------------------ + +* {fmt} now formats IEEE 754 ``float`` and ``double`` using the shortest decimal + representation with correct rounding by default: + + .. code:: c++ + + #include + #include + + int main() { + fmt::print("{}", M_PI); + } + + prints ``3.141592653589793``. + +* Made the fast binary to decimal floating-point formatter the default, + simplified it and improved performance. {fmt} is now 15 times faster than + libc++'s ``std::ostringstream``, 11 times faster than ``printf`` and 10% + faster than double-conversion on `dtoa-benchmark + `_: + + ================== ========= ======= + Function Time (ns) Speedup + ================== ========= ======= + ostringstream 1,346.30 1.00x + ostrstream 1,195.74 1.13x + sprintf 995.08 1.35x + doubleconv 99.10 13.59x + fmt 88.34 15.24x + ================== ========= ======= + + .. image:: https://user-images.githubusercontent.com/576385/ + 69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png + +* {fmt} no longer converts ``float`` arguments to ``double``. In particular this + improves the default (shortest) representation of floats and makes + ``fmt::format`` consistent with ``std::format`` specs + (`#1336 `_, + `#1353 `_, + `#1360 `_, + `#1361 `_): + + .. code:: c++ + + fmt::print("{}", 0.1f); + + prints ``0.1`` instead of ``0.10000000149011612``. + + Thanks `@orivej (Orivej Desh) `_. + +* Made floating-point formatting output consistent with ``printf``/iostreams + (`#1376 `_, + `#1417 `_). + +* Added support for 128-bit integers + (`#1287 `_): + + .. code:: c++ + + fmt::print("{}", std::numeric_limits<__int128_t>::max()); + + prints ``170141183460469231731687303715884105727``. + + Thanks `@denizevrenci (Deniz Evrenci) `_. + +* The overload of ``print`` that takes ``text_style`` is now atomic, i.e. the + output from different threads doesn't interleave + (`#1351 `_). + Thanks `@tankiJong (Tanki Zhang) `_. + +* Made compile time in the header-only mode ~20% faster by reducing the number + of template instantiations. ``wchar_t`` overload of ``vprint`` was moved from + ``fmt/core.h`` to ``fmt/format.h``. + +* Added an overload of ``fmt::join`` that works with tuples + (`#1322 `_, + `#1330 `_): + + .. code:: c++ + + #include + #include + + int main() { + std::tuple t{'a', 1, 2.0f}; + fmt::print("{}", t); + } + + prints ``('a', 1, 2.0)``. + + Thanks `@jeremyong (Jeremy Ong) `_. + +* Changed formatting of octal zero with prefix from "00" to "0": + + .. code:: c++ + + fmt::print("{:#o}", 0); + + prints ``0``. + +* The locale is now passed to ostream insertion (``<<``) operators + (`#1406 `_): + + .. code:: c++ + + #include + #include + + struct S { + double value; + }; + + std::ostream& operator<<(std::ostream& os, S s) { + return os << s.value; + } + + int main() { + auto s = fmt::format(std::locale("fr_FR.UTF-8"), "{}", S{0.42}); + // s == "0,42" + } + + Thanks `@dlaugt (Daniel Laügt) `_. + +* Locale-specific number formatting now uses grouping + (`#1393 `_ + `#1394 `_). + Thanks `@skrdaniel `_. + +* Fixed handling of types with deleted implicit rvalue conversion to + ``const char**`` (`#1421 `_): + + .. code:: c++ + + struct mystring { + operator const char*() const&; + operator const char*() &; + operator const char*() const&& = delete; + operator const char*() && = delete; + }; + mystring str; + fmt::print("{}", str); // now compiles + +* Enums are now mapped to correct underlying types instead of ``int`` + (`#1286 `_). + Thanks `@agmt (Egor Seredin) `_. + +* Enum classes are no longer implicitly converted to ``int`` + (`#1424 `_). + +* Added ``basic_format_parse_context`` for consistency with C++20 + ``std::format`` and deprecated ``basic_parse_context``. + +* Fixed handling of UTF-8 in precision + (`#1389 `_, + `#1390 `_). + Thanks `@tajtiattila (Attila Tajti) `_. + +* {fmt} can now be installed on Linux, macOS and Windows with + `Conda `__ using its + `conda-forge `__ + `package `__ + (`#1410 `_):: + + conda install -c conda-forge fmt + + Thanks `@tdegeus (Tom de Geus) `_. + +* Added a CUDA test (`#1285 `_, + `#1317 `_). + Thanks `@luncliff (Park DongHa) `_ and + `@risa2000 `_. + +* Improved documentation (`#1276 `_, + `#1291 `_, + `#1296 `_, + `#1315 `_, + `#1332 `_, + `#1337 `_, + `#1395 `_ + `#1418 `_). + Thanks + `@waywardmonkeys (Bruce Mitchener) `_, + `@pauldreik (Paul Dreik) `_, + `@jackoalan (Jack Andersen) `_. + +* Various code improvements + (`#1358 `_, + `#1407 `_). + Thanks `@orivej (Orivej Desh) `_, + `@dpacbach (David P. Sicilia) `_, + +* Fixed compile-time format string checks for user-defined types + (`#1292 `_). + +* Worked around a false positive in ``unsigned-integer-overflow`` sanitizer + (`#1377 `_). + +* Fixed various warnings and compilation issues + (`#1273 `_, + `#1278 `_, + `#1280 `_, + `#1281 `_, + `#1288 `_, + `#1290 `_, + `#1301 `_, + `#1305 `_, + `#1306 `_, + `#1309 `_, + `#1312 `_, + `#1313 `_, + `#1316 `_, + `#1319 `_, + `#1320 `_, + `#1326 `_, + `#1328 `_, + `#1344 `_, + `#1345 `_, + `#1347 `_, + `#1349 `_, + `#1354 `_, + `#1362 `_, + `#1366 `_, + `#1364 `_, + `#1370 `_, + `#1371 `_, + `#1385 `_, + `#1388 `_, + `#1397 `_, + `#1414 `_, + `#1416 `_, + `#1422 `_ + `#1427 `_, + `#1431 `_, + `#1433 `_). + Thanks `@hhb `_, + `@gsjaardema (Greg Sjaardema) `_, + `@gabime (Gabi Melman) `_, + `@neheb (Rosen Penev) `_, + `@vedranmiletic (Vedran Miletić) `_, + `@dkavolis (Daumantas Kavolis) `_, + `@mwinterb `_, + `@orivej (Orivej Desh) `_, + `@denizevrenci (Deniz Evrenci) `_ + `@leonklingele `_, + `@chronoxor (Ivan Shynkarenka) `_, + `@kent-tri `_, + `@0x8000-0000 (Florin Iucha) `_, + `@marti4d (Chris Martin) `_. + +6.0.0 - 2019-08-26 +------------------ + +* Switched to the `MIT license + `_ + with an optional exception that allows distributing binary code without + attribution. + +* Floating-point formatting is now locale-independent by default: + + .. code:: c++ + + #include + #include + + int main() { + std::locale::global(std::locale("ru_RU.UTF-8")); + fmt::print("value = {}", 4.2); + } + + prints "value = 4.2" regardless of the locale. + + For locale-specific formatting use the ``n`` specifier: + + .. code:: c++ + + std::locale::global(std::locale("ru_RU.UTF-8")); + fmt::print("value = {:n}", 4.2); + + prints "value = 4,2". + +* Added an experimental Grisu floating-point formatting algorithm + implementation (disabled by default). To enable it compile with the + ``FMT_USE_GRISU`` macro defined to 1: + + .. code:: c++ + + #define FMT_USE_GRISU 1 + #include + + auto s = fmt::format("{}", 4.2); // formats 4.2 using Grisu + + With Grisu enabled, {fmt} is 13x faster than ``std::ostringstream`` (libc++) + and 10x faster than ``sprintf`` on `dtoa-benchmark + `_ (`full results + `_): + + .. image:: https://user-images.githubusercontent.com/576385/ + 54883977-9fe8c000-4e28-11e9-8bde-272d122e7c52.jpg + +* Separated formatting and parsing contexts for consistency with + `C++20 std::format `_, removing the + undocumented ``basic_format_context::parse_context()`` function. + +* Added `oss-fuzz `_ support + (`#1199 `_). + Thanks `@pauldreik (Paul Dreik) `_. + +* ``formatter`` specializations now always take precedence over ``operator<<`` + (`#952 `_): + + .. code:: c++ + + #include + #include + + struct S {}; + + std::ostream& operator<<(std::ostream& os, S) { + return os << 1; + } + + template <> + struct fmt::formatter : fmt::formatter { + auto format(S, format_context& ctx) { + return formatter::format(2, ctx); + } + }; + + int main() { + std::cout << S() << "\n"; // prints 1 using operator<< + fmt::print("{}\n", S()); // prints 2 using formatter + } + +* Introduced the experimental ``fmt::compile`` function that does format string + compilation (`#618 `_, + `#1169 `_, + `#1171 `_): + + .. code:: c++ + + #include + + auto f = fmt::compile("{}"); + std::string s = fmt::format(f, 42); // can be called multiple times to + // format different values + // s == "42" + + It moves the cost of parsing a format string outside of the format function + which can be beneficial when identically formatting many objects of the same + types. Thanks `@stryku (Mateusz Janek) `_. + +* Added experimental ``%`` format specifier that formats floating-point values + as percentages (`#1060 `_, + `#1069 `_, + `#1071 `_): + + .. code:: c++ + + auto s = fmt::format("{:.1%}", 0.42); // s == "42.0%" + + Thanks `@gawain-bolton (Gawain Bolton) `_. + +* Implemented precision for floating-point durations + (`#1004 `_, + `#1012 `_): + + .. code:: c++ + + auto s = fmt::format("{:.1}", std::chrono::duration(1.234)); + // s == 1.2s + + Thanks `@DanielaE (Daniela Engert) `_. + +* Implemented ``chrono`` format specifiers ``%Q`` and ``%q`` that give the value + and the unit respectively (`#1019 `_): + + .. code:: c++ + + auto value = fmt::format("{:%Q}", 42s); // value == "42" + auto unit = fmt::format("{:%q}", 42s); // unit == "s" + + Thanks `@DanielaE (Daniela Engert) `_. + +* Fixed handling of dynamic width in chrono formatter: + + .. code:: c++ + + auto s = fmt::format("{0:{1}%H:%M:%S}", std::chrono::seconds(12345), 12); + // ^ width argument index ^ width + // s == "03:25:45 " + + Thanks Howard Hinnant. + +* Removed deprecated ``fmt/time.h``. Use ``fmt/chrono.h`` instead. + +* Added ``fmt::format`` and ``fmt::vformat`` overloads that take ``text_style`` + (`#993 `_, + `#994 `_): + + .. code:: c++ + + #include + + std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), + "The answer is {}.", 42); + + Thanks `@Naios (Denis Blank) `_. + +* Removed the deprecated color API (``print_colored``). Use the new API, namely + ``print`` overloads that take ``text_style`` instead. + +* Made ``std::unique_ptr`` and ``std::shared_ptr`` formattable as pointers via + ``fmt::ptr`` (`#1121 `_): + + .. code:: c++ + + std::unique_ptr p = ...; + fmt::print("{}", fmt::ptr(p)); // prints p as a pointer + + Thanks `@sighingnow (Tao He) `_. + +* Made ``print`` and ``vprint`` report I/O errors + (`#1098 `_, + `#1099 `_). + Thanks `@BillyDonahue (Billy Donahue) `_. + +* Marked deprecated APIs with the ``[[deprecated]]`` attribute and removed + internal uses of deprecated APIs + (`#1022 `_). + Thanks `@eliaskosunen (Elias Kosunen) `_. + +* Modernized the codebase using more C++11 features and removing workarounds. + Most importantly, ``buffer_context`` is now an alias template, so + use ``buffer_context`` instead of ``buffer_context::type``. + These features require GCC 4.8 or later. + +* ``formatter`` specializations now always take precedence over implicit + conversions to ``int`` and the undocumented ``convert_to_int`` trait + is now deprecated. + +* Moved the undocumented ``basic_writer``, ``writer``, and ``wwriter`` types + to the ``internal`` namespace. + +* Removed deprecated ``basic_format_context::begin()``. Use ``out()`` instead. + +* Disallowed passing the result of ``join`` as an lvalue to prevent misuse. + +* Refactored the undocumented structs that represent parsed format specifiers + to simplify the API and allow multibyte fill. + +* Moved SFINAE to template parameters to reduce symbol sizes. + +* Switched to ``fputws`` for writing wide strings so that it's no longer + required to call ``_setmode`` on Windows + (`#1229 `_, + `#1243 `_). + Thanks `@jackoalan (Jack Andersen) `_. + +* Improved literal-based API + (`#1254 `_). + Thanks `@sylveon (Charles Milette) `_. + +* Added support for exotic platforms without ``uintptr_t`` such as IBM i + (AS/400) which has 128-bit pointers and only 64-bit integers + (`#1059 `_). + +* Added `Sublime Text syntax highlighting config + `_ + (`#1037 `_). + Thanks `@Kronuz (Germán Méndez Bravo) `_. + +* Added the ``FMT_ENFORCE_COMPILE_STRING`` macro to enforce the use of + compile-time format strings + (`#1231 `_). + Thanks `@jackoalan (Jack Andersen) `_. + +* Stopped setting ``CMAKE_BUILD_TYPE`` if {fmt} is a subproject + (`#1081 `_). + +* Various build improvements + (`#1039 `_, + `#1078 `_, + `#1091 `_, + `#1103 `_, + `#1177 `_). + Thanks `@luncliff (Park DongHa) `_, + `@jasonszang (Jason Shuo Zang) `_, + `@olafhering (Olaf Hering) `_, + `@Lecetem `_, + `@pauldreik (Paul Dreik) `_. + +* Improved documentation + (`#1049 `_, + `#1051 `_, + `#1083 `_, + `#1113 `_, + `#1114 `_, + `#1146 `_, + `#1180 `_, + `#1250 `_, + `#1252 `_, + `#1265 `_). + Thanks `@mikelui (Michael Lui) `_, + `@foonathan (Jonathan Müller) `_, + `@BillyDonahue (Billy Donahue) `_, + `@jwakely (Jonathan Wakely) `_, + `@kaisbe (Kais Ben Salah) `_, + `@sdebionne (Samuel Debionne) `_. + +* Fixed ambiguous formatter specialization in ``fmt/ranges.h`` + (`#1123 `_). + +* Fixed formatting of a non-empty ``std::filesystem::path`` which is an + infinitely deep range of its components + (`#1268 `_). + +* Fixed handling of general output iterators when formatting characters + (`#1056 `_, + `#1058 `_). + Thanks `@abolz (Alexander Bolz) `_. + +* Fixed handling of output iterators in ``formatter`` specialization for + ranges (`#1064 `_). + +* Fixed handling of exotic character types + (`#1188 `_). + +* Made chrono formatting work with exceptions disabled + (`#1062 `_). + +* Fixed DLL visibility issues + (`#1134 `_, + `#1147 `_). + Thanks `@denchat `_. + +* Disabled the use of UDL template extension on GCC 9 + (`#1148 `_). + +* Removed misplaced ``format`` compile-time checks from ``printf`` + (`#1173 `_). + +* Fixed issues in the experimental floating-point formatter + (`#1072 `_, + `#1129 `_, + `#1153 `_, + `#1155 `_, + `#1210 `_, + `#1222 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_. + +* Fixed bugs discovered by fuzzing or during fuzzing integration + (`#1124 `_, + `#1127 `_, + `#1132 `_, + `#1135 `_, + `#1136 `_, + `#1141 `_, + `#1142 `_, + `#1178 `_, + `#1179 `_, + `#1194 `_). + Thanks `@pauldreik (Paul Dreik) `_. + +* Fixed building tests on FreeBSD and Hurd + (`#1043 `_). + Thanks `@jackyf (Eugene V. Lyubimkin) `_. + +* Fixed various warnings and compilation issues + (`#998 `_, + `#1006 `_, + `#1008 `_, + `#1011 `_, + `#1025 `_, + `#1027 `_, + `#1028 `_, + `#1029 `_, + `#1030 `_, + `#1031 `_, + `#1054 `_, + `#1063 `_, + `#1068 `_, + `#1074 `_, + `#1075 `_, + `#1079 `_, + `#1086 `_, + `#1088 `_, + `#1089 `_, + `#1094 `_, + `#1101 `_, + `#1102 `_, + `#1105 `_, + `#1107 `_, + `#1115 `_, + `#1117 `_, + `#1118 `_, + `#1120 `_, + `#1123 `_, + `#1139 `_, + `#1140 `_, + `#1143 `_, + `#1144 `_, + `#1150 `_, + `#1151 `_, + `#1152 `_, + `#1154 `_, + `#1156 `_, + `#1159 `_, + `#1175 `_, + `#1181 `_, + `#1186 `_, + `#1187 `_, + `#1191 `_, + `#1197 `_, + `#1200 `_, + `#1203 `_, + `#1205 `_, + `#1206 `_, + `#1213 `_, + `#1214 `_, + `#1217 `_, + `#1228 `_, + `#1230 `_, + `#1232 `_, + `#1235 `_, + `#1236 `_, + `#1240 `_). + Thanks `@DanielaE (Daniela Engert) `_, + `@mwinterb `_, + `@eliaskosunen (Elias Kosunen) `_, + `@morinmorin `_, + `@ricco19 (Brian Ricciardelli) `_, + `@waywardmonkeys (Bruce Mitchener) `_, + `@chronoxor (Ivan Shynkarenka) `_, + `@remyabel `_, + `@pauldreik (Paul Dreik) `_, + `@gsjaardema (Greg Sjaardema) `_, + `@rcane (Ronny Krüger) `_, + `@mocabe `_, + `@denchat `_, + `@cjdb (Christopher Di Bella) `_, + `@HazardyKnusperkeks (Björn Schäpers) `_, + `@vedranmiletic (Vedran Miletić) `_, + `@jackoalan (Jack Andersen) `_, + `@DaanDeMeyer (Daan De Meyer) `_, + `@starkmapper (Mark Stapper) `_. + +5.3.0 - 2018-12-28 +------------------ + +* Introduced experimental chrono formatting support: + + .. code:: c++ + + #include + + int main() { + using namespace std::literals::chrono_literals; + fmt::print("Default format: {} {}\n", 42s, 100ms); + fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s); + } + + prints:: + + Default format: 42s 100ms + strftime-like format: 03:15:30 + +* Added experimental support for emphasis (bold, italic, underline, + strikethrough), colored output to a file stream, and improved colored + formatting API + (`#961 `_, + `#967 `_, + `#973 `_): + + .. code:: c++ + + #include + + int main() { + print(fg(fmt::color::crimson) | fmt::emphasis::bold, + "Hello, {}!\n", "world"); + print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | + fmt::emphasis::underline, "Hello, {}!\n", "мир"); + print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, + "Hello, {}!\n", "世界"); + } + + prints the following on modern terminals with RGB color support: + + .. image:: https://user-images.githubusercontent.com/576385/ + 50405788-b66e7500-076e-11e9-9592-7324d1f951d8.png + + Thanks `@Rakete1111 (Nicolas) `_. + +* Added support for 4-bit terminal colors + (`#968 `_, + `#974 `_) + + .. code:: c++ + + #include + + int main() { + print(fg(fmt::terminal_color::red), "stop\n"); + } + + Note that these colors vary by terminal: + + .. image:: https://user-images.githubusercontent.com/576385/ + 50405925-dbfc7e00-0770-11e9-9b85-333fab0af9ac.png + + Thanks `@Rakete1111 (Nicolas) `_. + +* Parameterized formatting functions on the type of the format string + (`#880 `_, + `#881 `_, + `#883 `_, + `#885 `_, + `#897 `_, + `#920 `_). + Any object of type ``S`` that has an overloaded ``to_string_view(const S&)`` + returning ``fmt::string_view`` can be used as a format string: + + .. code:: c++ + + namespace my_ns { + inline string_view to_string_view(const my_string& s) { + return {s.data(), s.length()}; + } + } + + std::string message = fmt::format(my_string("The answer is {}."), 42); + + Thanks `@DanielaE (Daniela Engert) `_. + +* Made ``std::string_view`` work as a format string + (`#898 `_): + + .. code:: c++ + + auto message = fmt::format(std::string_view("The answer is {}."), 42); + + Thanks `@DanielaE (Daniela Engert) `_. + +* Added wide string support to compile-time format string checks + (`#924 `_): + + .. code:: c++ + + print(fmt(L"{:f}"), 42); // compile-time error: invalid type specifier + + Thanks `@XZiar `_. + +* Made colored print functions work with wide strings + (`#867 `_): + + .. code:: c++ + + #include + + int main() { + print(fg(fmt::color::red), L"{}\n", 42); + } + + Thanks `@DanielaE (Daniela Engert) `_. + +* Introduced experimental Unicode support + (`#628 `_, + `#891 `_): + + .. code:: c++ + + using namespace fmt::literals; + auto s = fmt::format("{:*^5}"_u, "🤡"_u); // s == "**🤡**"_u + +* Improved locale support: + + .. code:: c++ + + #include + + struct numpunct : std::numpunct { + protected: + char do_thousands_sep() const override { return '~'; } + }; + + std::locale loc; + auto s = fmt::format(std::locale(loc, new numpunct()), "{:n}", 1234567); + // s == "1~234~567" + +* Constrained formatting functions on proper iterator types + (`#921 `_). + Thanks `@DanielaE (Daniela Engert) `_. + +* Added ``make_printf_args`` and ``make_wprintf_args`` functions + (`#934 `_). + Thanks `@tnovotny `_. + +* Deprecated ``fmt::visit``, ``parse_context``, and ``wparse_context``. + Use ``fmt::visit_format_arg``, ``format_parse_context``, and + ``wformat_parse_context`` instead. + +* Removed undocumented ``basic_fixed_buffer`` which has been superseded by the + iterator-based API + (`#873 `_, + `#902 `_). + Thanks `@superfunc (hollywood programmer) `_. + +* Disallowed repeated leading zeros in an argument ID: + + .. code:: c++ + + fmt::print("{000}", 42); // error + +* Reintroduced support for gcc 4.4. + +* Fixed compilation on platforms with exotic ``double`` + (`#878 `_). + +* Improved documentation + (`#164 `_, + `#877 `_, + `#901 `_, + `#906 `_, + `#979 `_). + Thanks `@kookjr (Mathew Cucuzella) `_, + `@DarkDimius (Dmitry Petrashko) `_, + `@HecticSerenity `_. + +* Added pkgconfig support which makes it easier to consume the library from + meson and other build systems + (`#916 `_). + Thanks `@colemickens (Cole Mickens) `_. + +* Various build improvements + (`#909 `_, + `#926 `_, + `#937 `_, + `#953 `_, + `#959 `_). + Thanks `@tchaikov (Kefu Chai) `_, + `@luncliff (Park DongHa) `_, + `@AndreasSchoenle (Andreas Schönle) `_, + `@hotwatermorning `_, + `@Zefz (JohanJansen) `_. + +* Improved ``string_view`` construction performance + (`#914 `_). + Thanks `@gabime (Gabi Melman) `_. + +* Fixed non-matching char types + (`#895 `_). + Thanks `@DanielaE (Daniela Engert) `_. + +* Fixed ``format_to_n`` with ``std::back_insert_iterator`` + (`#913 `_). + Thanks `@DanielaE (Daniela Engert) `_. + +* Fixed locale-dependent formatting + (`#905 `_). + +* Fixed various compiler warnings and errors + (`#882 `_, + `#886 `_, + `#933 `_, + `#941 `_, + `#931 `_, + `#943 `_, + `#954 `_, + `#956 `_, + `#962 `_, + `#965 `_, + `#977 `_, + `#983 `_, + `#989 `_). + Thanks `@Luthaf (Guillaume Fraux) `_, + `@stevenhoving (Steven Hoving) `_, + `@christinaa (Kristina Brooks) `_, + `@lgritz (Larry Gritz) `_, + `@DanielaE (Daniela Engert) `_, + `@0x8000-0000 (Sign Bit) `_, + `@liuping1997 `_. + +5.2.1 - 2018-09-21 +------------------ + +* Fixed ``visit`` lookup issues on gcc 7 & 8 + (`#870 `_). + Thanks `@medithe `_. + +* Fixed linkage errors on older gcc. + +* Prevented ``fmt/range.h`` from specializing ``fmt::basic_string_view`` + (`#865 `_, + `#868 `_). + Thanks `@hhggit (dual) `_. + +* Improved error message when formatting unknown types + (`#872 `_). + Thanks `@foonathan (Jonathan Müller) `_, + +* Disabled templated user-defined literals when compiled under nvcc + (`#875 `_). + Thanks `@CandyGumdrop (Candy Gumdrop) `_, + +* Fixed ``format_to`` formatting to ``wmemory_buffer`` + (`#874 `_). + +5.2.0 - 2018-09-13 +------------------ + +* Optimized format string parsing and argument processing which resulted in up + to 5x speed up on long format strings and significant performance boost on + various benchmarks. For example, version 5.2 is 2.22x faster than 5.1 on + decimal integer formatting with ``format_to`` (macOS, clang-902.0.39.2): + + ================== ======= ======= + Method Time, s Speedup + ================== ======= ======= + fmt::format 5.1 0.58 + fmt::format 5.2 0.35 1.66x + fmt::format_to 5.1 0.51 + fmt::format_to 5.2 0.23 2.22x + sprintf 0.71 + std::to_string 1.01 + std::stringstream 1.73 + ================== ======= ======= + +* Changed the ``fmt`` macro from opt-out to opt-in to prevent name collisions. + To enable it define the ``FMT_STRING_ALIAS`` macro to 1 before including + ``fmt/format.h``: + + .. code:: c++ + + #define FMT_STRING_ALIAS 1 + #include + std::string answer = format(fmt("{}"), 42); + +* Added compile-time format string checks to ``format_to`` overload that takes + ``fmt::memory_buffer`` (`#783 `_): + + .. code:: c++ + + fmt::memory_buffer buf; + // Compile-time error: invalid type specifier. + fmt::format_to(buf, fmt("{:d}"), "foo"); + +* Moved experimental color support to ``fmt/color.h`` and enabled the + new API by default. The old API can be enabled by defining the + ``FMT_DEPRECATED_COLORS`` macro. + +* Added formatting support for types explicitly convertible to + ``fmt::string_view``: + + .. code:: c++ + + struct foo { + explicit operator fmt::string_view() const { return "foo"; } + }; + auto s = format("{}", foo()); + + In particular, this makes formatting function work with + ``folly::StringPiece``. + +* Implemented preliminary support for ``char*_t`` by replacing the ``format`` + function overloads with a single function template parameterized on the string + type. + +* Added support for dynamic argument lists + (`#814 `_, + `#819 `_). + Thanks `@MikePopoloski (Michael Popoloski) + `_. + +* Reduced executable size overhead for embedded targets using newlib nano by + making locale dependency optional + (`#839 `_). + Thanks `@teajay-fr (Thomas Benard) `_. + +* Keep ``noexcept`` specifier when exceptions are disabled + (`#801 `_, + `#810 `_). + Thanks `@qis (Alexej Harm) `_. + +* Fixed formatting of user-defined types providing ``operator<<`` with + ``format_to_n`` + (`#806 `_). + Thanks `@mkurdej (Marek Kurdej) `_. + +* Fixed dynamic linkage of new symbols + (`#808 `_). + +* Fixed global initialization issue + (`#807 `_): + + .. code:: c++ + + // This works on compilers with constexpr support. + static const std::string answer = fmt::format("{}", 42); + +* Fixed various compiler warnings and errors + (`#804 `_, + `#809 `_, + `#811 `_, + `#822 `_, + `#827 `_, + `#830 `_, + `#838 `_, + `#843 `_, + `#844 `_, + `#851 `_, + `#852 `_, + `#854 `_). + Thanks `@henryiii (Henry Schreiner) `_, + `@medithe `_, and + `@eliasdaler (Elias Daler) `_. + +5.1.0 - 2018-07-05 +------------------ + +* Added experimental support for RGB color output enabled with + the ``FMT_EXTENDED_COLORS`` macro: + + .. code:: c++ + + #define FMT_EXTENDED_COLORS + #define FMT_HEADER_ONLY // or compile fmt with FMT_EXTENDED_COLORS defined + #include + + fmt::print(fmt::color::steel_blue, "Some beautiful text"); + + The old API (the ``print_colored`` and ``vprint_colored`` functions and the + ``color`` enum) is now deprecated. + (`#762 `_ + `#767 `_). + thanks `@Remotion (Remo) `_. + +* Added quotes to strings in ranges and tuples + (`#766 `_). + Thanks `@Remotion (Remo) `_. + +* Made ``format_to`` work with ``basic_memory_buffer`` + (`#776 `_). + +* Added ``vformat_to_n`` and ``wchar_t`` overload of ``format_to_n`` + (`#764 `_, + `#769 `_). + +* Made ``is_range`` and ``is_tuple_like`` part of public (experimental) API + to allow specialization for user-defined types + (`#751 `_, + `#759 `_). + Thanks `@drrlvn (Dror Levin) `_. + +* Added more compilers to continuous integration and increased ``FMT_PEDANTIC`` + warning levels + (`#736 `_). + Thanks `@eliaskosunen (Elias Kosunen) `_. + +* Fixed compilation with MSVC 2013. + +* Fixed handling of user-defined types in ``format_to`` + (`#793 `_). + +* Forced linking of inline ``vformat`` functions into the library + (`#795 `_). + +* Fixed incorrect call to on_align in ``'{:}='`` + (`#750 `_). + +* Fixed floating-point formatting to a non-back_insert_iterator with sign & + numeric alignment specified + (`#756 `_). + +* Fixed formatting to an array with ``format_to_n`` + (`#778 `_). + +* Fixed formatting of more than 15 named arguments + (`#754 `_). + +* Fixed handling of compile-time strings when including ``fmt/ostream.h``. + (`#768 `_). + +* Fixed various compiler warnings and errors + (`#742 `_, + `#748 `_, + `#752 `_, + `#770 `_, + `#775 `_, + `#779 `_, + `#780 `_, + `#790 `_, + `#792 `_, + `#800 `_). + Thanks `@Remotion (Remo) `_, + `@gabime (Gabi Melman) `_, + `@foonathan (Jonathan Müller) `_, + `@Dark-Passenger (Dhruv Paranjape) `_, and + `@0x8000-0000 (Sign Bit) `_. + +5.0.0 - 2018-05-21 +------------------ + +* Added a requirement for partial C++11 support, most importantly variadic + templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros. + Variadic templates are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). + For older compilers use {fmt} `version 4.x + `_ which continues to be + maintained and works with C++98 compilers. + +* Renamed symbols to follow standard C++ naming conventions and proposed a subset + of the library for standardization in `P0645R2 Text Formatting + `_. + +* Implemented ``constexpr`` parsing of format strings and `compile-time format + string checks + `_. For + example + + .. code:: c++ + + #include + + std::string s = format(fmt("{:d}"), "foo"); + + gives a compile-time error because ``d`` is an invalid specifier for strings + (`godbolt `__):: + + ... + :4:19: note: in instantiation of function template specialization 'fmt::v5::format' requested here + std::string s = format(fmt("{:d}"), "foo"); + ^ + format.h:1337:13: note: non-constexpr function 'on_error' cannot be used in a constant expression + handler.on_error("invalid type specifier"); + + Compile-time checks require relaxed ``constexpr`` (C++14 feature) support. If + the latter is not available, checks will be performed at runtime. + +* Separated format string parsing and formatting in the extension API to enable + compile-time format string processing. For example + + .. code:: c++ + + struct Answer {}; + + namespace fmt { + template <> + struct formatter { + constexpr auto parse(parse_context& ctx) { + auto it = ctx.begin(); + spec = *it; + if (spec != 'd' && spec != 's') + throw format_error("invalid specifier"); + return ++it; + } + + template + auto format(Answer, FormatContext& ctx) { + return spec == 's' ? + format_to(ctx.begin(), "{}", "fourty-two") : + format_to(ctx.begin(), "{}", 42); + } + + char spec = 0; + }; + } + + std::string s = format(fmt("{:x}"), Answer()); + + gives a compile-time error due to invalid format specifier (`godbolt + `__):: + + ... + :12:45: error: expression '' is not a constant expression + throw format_error("invalid specifier"); + +* Added `iterator support + `_: + + .. code:: c++ + + #include + #include + + std::vector out; + fmt::format_to(std::back_inserter(out), "{}", 42); + +* Added the `format_to_n + `_ + function that restricts the output to the specified number of characters + (`#298 `_): + + .. code:: c++ + + char out[4]; + fmt::format_to_n(out, sizeof(out), "{}", 12345); + // out == "1234" (without terminating '\0') + +* Added the `formatted_size + `_ + function for computing the output size: + + .. code:: c++ + + #include + + auto size = fmt::formatted_size("{}", 12345); // size == 5 + +* Improved compile times by reducing dependencies on standard headers and + providing a lightweight `core API `_: + + .. code:: c++ + + #include + + fmt::print("The answer is {}.", 42); + + See `Compile time and code bloat + `_. + +* Added the `make_format_args + `_ + function for capturing formatting arguments: + + .. code:: c++ + + // Prints formatted error message. + void vreport_error(const char *format, fmt::format_args args) { + fmt::print("Error: "); + fmt::vprint(format, args); + } + template + void report_error(const char *format, const Args & ... args) { + vreport_error(format, fmt::make_format_args(args...)); + } + +* Added the ``make_printf_args`` function for capturing ``printf`` arguments + (`#687 `_, + `#694 `_). + Thanks `@Kronuz (Germán Méndez Bravo) `_. + +* Added prefix ``v`` to non-variadic functions taking ``format_args`` to + distinguish them from variadic ones: + + .. code:: c++ + + std::string vformat(string_view format_str, format_args args); + + template + std::string format(string_view format_str, const Args & ... args); + +* Added experimental support for formatting ranges, containers and tuple-like + types in ``fmt/ranges.h`` (`#735 `_): + + .. code:: c++ + + #include + + std::vector v = {1, 2, 3}; + fmt::print("{}", v); // prints {1, 2, 3} + + Thanks `@Remotion (Remo) `_. + +* Implemented ``wchar_t`` date and time formatting + (`#712 `_): + + .. code:: c++ + + #include + + std::time_t t = std::time(nullptr); + auto s = fmt::format(L"The date is {:%Y-%m-%d}.", *std::localtime(&t)); + + Thanks `@DanielaE (Daniela Engert) `_. + +* Provided more wide string overloads + (`#724 `_). + Thanks `@DanielaE (Daniela Engert) `_. + +* Switched from a custom null-terminated string view class to ``string_view`` + in the format API and provided ``fmt::string_view`` which implements a subset + of ``std::string_view`` API for pre-C++17 systems. + +* Added support for ``std::experimental::string_view`` + (`#607 `_): + + .. code:: c++ + + #include + #include + + fmt::print("{}", std::experimental::string_view("foo")); + + Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin) + `__. + +* Allowed mixing named and automatic arguments: + + .. code:: c++ + + fmt::format("{} {two}", 1, fmt::arg("two", 2)); + +* Removed the write API in favor of the `format API + `_ with compile-time handling of + format strings. + +* Disallowed formatting of multibyte strings into a wide character target + (`#606 `_). + +* Improved documentation + (`#515 `_, + `#614 `_, + `#617 `_, + `#661 `_, + `#680 `_). + Thanks `@ibell (Ian Bell) `_, + `@mihaitodor (Mihai Todor) `_, and + `@johnthagen `_. + +* Implemented more efficient handling of large number of format arguments. + +* Introduced an inline namespace for symbol versioning. + +* Added debug postfix ``d`` to the ``fmt`` library name + (`#636 `_). + +* Removed unnecessary ``fmt/`` prefix in includes + (`#397 `_). + Thanks `@chronoxor (Ivan Shynkarenka) `_. + +* Moved ``fmt/*.h`` to ``include/fmt/*.h`` to prevent irrelevant files and + directories appearing on the include search paths when fmt is used as a + subproject and moved source files to the ``src`` directory. + +* Added qmake project file ``support/fmt.pro`` + (`#641 `_). + Thanks `@cowo78 (Giuseppe Corbelli) `_. + +* Added Gradle build file ``support/build.gradle`` + (`#649 `_). + Thanks `@luncliff (Park DongHa) `_. + +* Removed ``FMT_CPPFORMAT`` CMake option. + +* Fixed a name conflict with the macro ``CHAR_WIDTH`` in glibc + (`#616 `_). + Thanks `@aroig (Abdó Roig-Maranges) `_. + +* Fixed handling of nested braces in ``fmt::join`` + (`#638 `_). + +* Added ``SOURCELINK_SUFFIX`` for compatibility with Sphinx 1.5 + (`#497 `_). + Thanks `@ginggs (Graham Inggs) `_. + +* Added a missing ``inline`` in the header-only mode + (`#626 `_). + Thanks `@aroig (Abdó Roig-Maranges) `_. + +* Fixed various compiler warnings + (`#640 `_, + `#656 `_, + `#679 `_, + `#681 `_, + `#705 `__, + `#715 `_, + `#717 `_, + `#720 `_, + `#723 `_, + `#726 `_, + `#730 `_, + `#739 `_). + Thanks `@peterbell10 `_, + `@LarsGullik `_, + `@foonathan (Jonathan Müller) `_, + `@eliaskosunen (Elias Kosunen) `_, + `@christianparpart (Christian Parpart) `_, + `@DanielaE (Daniela Engert) `_, + and `@mwinterb `_. + +* Worked around an MSVC bug and fixed several warnings + (`#653 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_. + +* Worked around GCC bug 67371 + (`#682 `_). + +* Fixed compilation with ``-fno-exceptions`` + (`#655 `_). + Thanks `@chenxiaolong (Andrew Gunnerson) `_. + +* Made ``constexpr remove_prefix`` gcc version check tighter + (`#648 `_). + +* Renamed internal type enum constants to prevent collision with poorly written + C libraries (`#644 `_). + +* Added detection of ``wostream operator<<`` + (`#650 `_). + +* Fixed compilation on OpenBSD + (`#660 `_). + Thanks `@hubslave `_. + +* Fixed compilation on FreeBSD 12 + (`#732 `_). + Thanks `@dankm `_. + +* Fixed compilation when there is a mismatch between ``-std`` options between + the library and user code + (`#664 `_). + +* Fixed compilation with GCC 7 and ``-std=c++11`` + (`#734 `_). + +* Improved generated binary code on GCC 7 and older + (`#668 `_). + +* Fixed handling of numeric alignment with no width + (`#675 `_). + +* Fixed handling of empty strings in UTF8/16 converters + (`#676 `_). + Thanks `@vgalka-sl (Vasili Galka) `_. + +* Fixed formatting of an empty ``string_view`` + (`#689 `_). + +* Fixed detection of ``string_view`` on libc++ + (`#686 `_). + +* Fixed DLL issues (`#696 `_). + Thanks `@sebkoenig `_. + +* Fixed compile checks for mixing narrow and wide strings + (`#690 `_). + +* Disabled unsafe implicit conversion to ``std::string`` + (`#729 `_). + +* Fixed handling of reused format specs (as in ``fmt::join``) for pointers + (`#725 `_). + Thanks `@mwinterb `_. + +* Fixed installation of ``fmt/ranges.h`` + (`#738 `_). + Thanks `@sv1990 `_. + +4.1.0 - 2017-12-20 +------------------ + +* Added ``fmt::to_wstring()`` in addition to ``fmt::to_string()`` + (`#559 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_. + +* Added support for C++17 ``std::string_view`` + (`#571 `_ and + `#578 `_). + Thanks `@thelostt (Mário Feroldi) `_ and + `@mwinterb `_. + +* Enabled stream exceptions to catch errors + (`#581 `_). + Thanks `@crusader-mike `_. + +* Allowed formatting of class hierarchies with ``fmt::format_arg()`` + (`#547 `_). + Thanks `@rollbear (Björn Fahller) `_. + +* Removed limitations on character types + (`#563 `_). + Thanks `@Yelnats321 (Elnar Dakeshov) `_. + +* Conditionally enabled use of ``std::allocator_traits`` + (`#583 `_). + Thanks `@mwinterb `_. + +* Added support for ``const`` variadic member function emulation with + ``FMT_VARIADIC_CONST`` (`#591 `_). + Thanks `@ludekvodicka (Ludek Vodicka) `_. + +* Various bugfixes: bad overflow check, unsupported implicit type conversion + when determining formatting function, test segfaults + (`#551 `_), ill-formed macros + (`#542 `_) and ambiguous overloads + (`#580 `_). + Thanks `@xylosper (Byoung-young Lee) `_. + +* Prevented warnings on MSVC (`#605 `_, + `#602 `_, and + `#545 `_), + clang (`#582 `_), + GCC (`#573 `_), + various conversion warnings (`#609 `_, + `#567 `_, + `#553 `_ and + `#553 `_), and added ``override`` and + ``[[noreturn]]`` (`#549 `_ and + `#555 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_, + `@virgiliofornazin (Virgilio Alexandre Fornazin) + `_, + `@alexanderbock (Alexander Bock) `_, + `@yumetodo `_, + `@VaderY (Császár Mátyás) `_, + `@jpcima (JP Cimalando) `_, + `@thelostt (Mário Feroldi) `_, and + `@Manu343726 (Manu Sánchez) `_. + +* Improved CMake: Used ``GNUInstallDirs`` to set installation location + (`#610 `_) and fixed warnings + (`#536 `_ and + `#556 `_). + Thanks `@mikecrowe (Mike Crowe) `_, + `@evgen231 `_ and + `@henryiii (Henry Schreiner) `_. 4.0.0 - 2017-06-27 ------------------ -* Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 `_). Thanks `@maddinat0r (Alex Martin) `_. +* Removed old compatibility headers ``cppformat/*.h`` and CMake options + (`#527 `_). + Thanks `@maddinat0r (Alex Martin) `_. -* Added ``string.h`` containing ``fmt::to_string()`` as alternative to ``std::to_string()`` as well as other string writer functionality (`#326 `_ and `#441 `_): +* Added ``string.h`` containing ``fmt::to_string()`` as alternative to + ``std::to_string()`` as well as other string writer functionality + (`#326 `_ and + `#441 `_): .. code:: c++ @@ -14,9 +2549,17 @@ std::string answer = fmt::to_string(42); - Thanks to `@glebov-andrey (Andrey Glebov) `_. + Thanks to `@glebov-andrey (Andrey Glebov) + `_. -* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as generic specifier (`#453 `_), made ``%.f`` more conformant to regular ``printf()`` (`#490 `_), added custom writer support (`#476 `_) and implemented missing custom argument formatting (`#339 `_ and `#340 `_): +* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as + generic specifier (`#453 `_), + made ``%.f`` more conformant to regular ``printf()`` + (`#490 `_), added custom writer + support (`#476 `_) and implemented + missing custom argument formatting + (`#339 `_ and + `#340 `_): .. code:: c++ @@ -25,11 +2568,21 @@ // %s format specifier can be used with any argument type. fmt::printf("%s", 42); - Thanks `@mojoBrendan `_, `@manylegged (Arthur Danskin) `_ and `@spacemoose (Glen Stark) `_. See also `#360 `_, `#335 `_ and `#331 `_. + Thanks `@mojoBrendan `_, + `@manylegged (Arthur Danskin) `_ and + `@spacemoose (Glen Stark) `_. + See also `#360 `_, + `#335 `_ and + `#331 `_. -* Added ``container.h`` containing a ``BasicContainerWriter`` to write to containers like ``std::vector`` (`#450 `_). Thanks `@polyvertex (Jean-Charles Lefebvre) `_. +* Added ``container.h`` containing a ``BasicContainerWriter`` + to write to containers like ``std::vector`` + (`#450 `_). + Thanks `@polyvertex (Jean-Charles Lefebvre) `_. -* Added ``fmt::join()`` function that takes a range and formats its elements separated by a given string (`#466 `_): +* Added ``fmt::join()`` function that takes a range and formats + its elements separated by a given string + (`#466 `_): .. code:: c++ @@ -41,75 +2594,174 @@ Thanks `@olivier80 `_. -* Added support for custom formatting specifications to simplify customization of built-in formatting (`#444 `_). Thanks `@polyvertex (Jean-Charles Lefebvre) `_. See also `#439 `_. +* Added support for custom formatting specifications to simplify customization + of built-in formatting (`#444 `_). + Thanks `@polyvertex (Jean-Charles Lefebvre) `_. + See also `#439 `_. -* Added ``fmt::format_system_error()`` for error code formatting (`#323 `_ and `#526 `_). Thanks `@maddinat0r (Alex Martin) `_. +* Added ``fmt::format_system_error()`` for error code formatting + (`#323 `_ and + `#526 `_). + Thanks `@maddinat0r (Alex Martin) `_. -* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()`` as replacement for the standard version to ``time.h`` (`#396 `_). Thanks `@codicodi `_. +* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()`` + as replacement for the standard version to ``time.h`` + (`#396 `_). + Thanks `@codicodi `_. -* Internal improvements to ``NamedArg`` and ``ArgLists`` (`#389 `_ and `#390 `_). Thanks `@chronoxor `_. +* Internal improvements to ``NamedArg`` and ``ArgLists`` + (`#389 `_ and + `#390 `_). + Thanks `@chronoxor `_. -* Fixed crash due to bug in ``FormatBuf`` (`#493 `_). Thanks `@effzeh `_. See also `#480 `_ and `#491 `_. +* Fixed crash due to bug in ``FormatBuf`` + (`#493 `_). + Thanks `@effzeh `_. See also + `#480 `_ and + `#491 `_. * Fixed handling of wide strings in ``fmt::StringWriter``. -* Improved compiler error messages (`#357 `_). - -* Fixed various warnings and issues with various compilers (`#494 `_, `#499 `_, `#483 `_, `#519 `_, `#485 `_, `#482 `_, `#475 `_, `#473 `_ and `#414 `_). Thanks `@chronoxor `_, `@zhaohuaxishi `_, `@pkestene (Pierre Kestener) `_, `@dschmidt (Dominik Schmidt) `_ and `@0x414c (Alexey Gorishny) `_ . - -* Improved CMake: targets are now namespaced (`#511 `_ and `#513 `_), supported header-only ``printf.h`` (`#354 `_), fixed issue with minimal supported library subset (`#418 `_, `#419 `_ and `#420 `_). Thanks `@bjoernthiel (Bjoern Thiel) `_, - `@niosHD (Mario Werner) `_, `@LogicalKnight (Sean LK) `_ and `@alabuzhev (Alex Alabuzhev) `_. - -* Improved documentation. Thanks to `@pwm1234 (Phil) `_ for `#393 `_. +* Improved compiler error messages + (`#357 `_). + +* Fixed various warnings and issues with various compilers + (`#494 `_, + `#499 `_, + `#483 `_, + `#485 `_, + `#482 `_, + `#475 `_, + `#473 `_ and + `#414 `_). + Thanks `@chronoxor `_, + `@zhaohuaxishi `_, + `@pkestene (Pierre Kestener) `_, + `@dschmidt (Dominik Schmidt) `_ and + `@0x414c (Alexey Gorishny) `_ . + +* Improved CMake: targets are now namespaced + (`#511 `_ and + `#513 `_), supported header-only + ``printf.h`` (`#354 `_), fixed issue + with minimal supported library subset + (`#418 `_, + `#419 `_ and + `#420 `_). + Thanks `@bjoernthiel (Bjoern Thiel) `_, + `@niosHD (Mario Werner) `_, + `@LogicalKnight (Sean LK) `_ and + `@alabuzhev (Alex Alabuzhev) `_. + +* Improved documentation. Thanks to + `@pwm1234 (Phil) `_ for + `#393 `_. 3.0.2 - 2017-06-14 ------------------ -* Added ``FMT_VERSION`` macro (`#411 `_). +* Added ``FMT_VERSION`` macro + (`#411 `_). -* Used ``FMT_NULL`` instead of literal ``0`` (`#409 `_). Thanks `@alabuzhev (Alex Alabuzhev) `_. +* Used ``FMT_NULL`` instead of literal ``0`` + (`#409 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_. -* Added extern templates for ``format_float`` (`#413 `_). +* Added extern templates for ``format_float`` + (`#413 `_). -* Fixed implicit conversion issue (`#507 `_). +* Fixed implicit conversion issue + (`#507 `_). * Fixed signbit detection (`#423 `_). * Fixed naming collision (`#425 `_). -* Fixed missing intrinsic for C++/CLI (`#457 `_). Thanks `@calumr (Calum Robinson) `_ +* Fixed missing intrinsic for C++/CLI + (`#457 `_). + Thanks `@calumr (Calum Robinson) `_ -* Fixed Android detection (`#458 `_). Thanks `@Gachapen (Magnus Bjerke Vik) `_. +* Fixed Android detection (`#458 `_). + Thanks `@Gachapen (Magnus Bjerke Vik) `_. -* Use lean ``windows.h`` if not in header-only mode (`#503 `_). Thanks `@Quentin01 (Quentin Buathier) `_. +* Use lean ``windows.h`` if not in header-only mode + (`#503 `_). + Thanks `@Quentin01 (Quentin Buathier) `_. -* Fixed issue with CMake exporting C++11 flag (`#445 `_). Thanks `@EricWF (Eric) `_. +* Fixed issue with CMake exporting C++11 flag + (`#445 `_). + Thanks `@EricWF (Eric) `_. -* Fixed issue with nvcc and MSVC compiler bug and MinGW (`#505 `_). +* Fixed issue with nvcc and MSVC compiler bug and MinGW + (`#505 `_). -* Fixed DLL issues (`#469 `_ and `#502 `_). Thanks `@richardeakin (Richard Eakin) `_ and `@AndreasSchoenle (Andreas Schönle) `_. +* Fixed DLL issues (`#469 `_ and + `#502 `_). + Thanks `@richardeakin (Richard Eakin) `_ and + `@AndreasSchoenle (Andreas Schönle) `_. -* Fixed test compilation under FreeBSD (`#433 `_). +* Fixed test compilation under FreeBSD + (`#433 `_). -* Fixed various warnings (`#403 `_, `#410 `_ and `#510 `_). Thanks `@Lecetem `_, `@chenhayat (Chen Hayat) `_ and `@trozen `_. +* Fixed various warnings (`#403 `_, + `#410 `_ and + `#510 `_). + Thanks `@Lecetem `_, + `@chenhayat (Chen Hayat) `_ and + `@trozen `_. -* Removed redundant include (`#479 `_). +* Worked around a broken ``__builtin_clz`` in clang with MS codegen + (`#519 `_). + +* Removed redundant include + (`#479 `_). * Fixed documentation issues. 3.0.1 - 2016-11-01 ------------------ -* Fixed handling of thousands seperator (`#353 `_) - -* Fixed handling of ``unsigned char`` strings (`#373 `_) - -* Corrected buffer growth when formatting time (`#367 `_) - -* Removed warnings under MSVC and clang (`#318 `_, `#250 `_, also merged `#385 `_ and `#361 `_). Thanks `@jcelerier (Jean-Michaël Celerier) `_ and `@nmoehrle (Nils Moehrle) `_. - -* Fixed compilation issues under Android (`#327 `_, `#345 `_ and `#381 `_), FreeBSD (`#358 `_), Cygwin (`#388 `_), MinGW (`#355 `_) as well as other issues (`#350 `_, `#366 `_, `#348 `_, `#402 `_, `#405 `_). Thanks to `@dpantele (Dmitry) `_, `@hghwng (Hugh Wang) `_, `@arvedarved (Tilman Keskinöz) `_, `@LogicalKnight (Sean) `_ and `@JanHellwig (Jan Hellwig) `_. - -* Fixed some documentation issues and extended specification (`#320 `_, `#333 `_, `#347 `_, `#362 `_). Thanks to `@smellman (Taro Matsuzawa aka. btm) `_. +* Fixed handling of thousands separator + (`#353 `_). + +* Fixed handling of ``unsigned char`` strings + (`#373 `_). + +* Corrected buffer growth when formatting time + (`#367 `_). + +* Removed warnings under MSVC and clang + (`#318 `_, + `#250 `_, also merged + `#385 `_ and + `#361 `_). + Thanks `@jcelerier (Jean-Michaël Celerier) `_ + and `@nmoehrle (Nils Moehrle) `_. + +* Fixed compilation issues under Android + (`#327 `_, + `#345 `_ and + `#381 `_), + FreeBSD (`#358 `_), + Cygwin (`#388 `_), + MinGW (`#355 `_) as well as other + issues (`#350 `_, + `#366 `_, + `#348 `_, + `#402 `_, + `#405 `_). + Thanks to `@dpantele (Dmitry) `_, + `@hghwng (Hugh Wang) `_, + `@arvedarved (Tilman Keskinöz) `_, + `@LogicalKnight (Sean) `_ and + `@JanHellwig (Jan Hellwig) `_. + +* Fixed some documentation issues and extended specification + (`#320 `_, + `#333 `_, + `#347 `_, + `#362 `_). + Thanks to `@smellman (Taro Matsuzawa aka. btm) + `_. 3.0.0 - 2016-05-07 ------------------ @@ -126,10 +2778,10 @@ Including ``format.h`` from the ``cppformat`` directory is deprecated but works via a proxy header which will be removed in the next major version. - The documentation is now available at http://fmtlib.net. + The documentation is now available at https://fmt.dev. * Added support for `strftime `_-like - `date and time formatting `_ + `date and time formatting `_ (`#283 `_): .. code:: c++ @@ -161,7 +2813,7 @@ // s == "The date is 2012-12-9" * Added support for `custom argument formatters - `_ + `_ (`#235 `_). * Added support for locale-specific integer formatting with the ``n`` specifier @@ -227,8 +2879,8 @@ `@Gachapen (Magnus Bjerke Vik) `_ and `@jwilk (Jakub Wilk) `_. -* Fixed compiler and sanitizer warnings ( - `#244 `_, +* Fixed compiler and sanitizer warnings + (`#244 `_, `#256 `_, `#259 `_, `#263 `_, @@ -541,7 +3193,7 @@ Documentation * Added `Building the documentation - `_ + `_ section to the documentation. * Documentation build script is now compatible with Python 3 and newer pip versions. @@ -648,8 +3300,8 @@ Fixes `@Jopie64 (Johan) `_. * Fixed portability issues (mostly causing test failures) on ARM, ppc64, ppc64le, - s390x and SunOS 5.11 i386 ( - `#138 `_, + s390x and SunOS 5.11 i386 + (`#138 `_, `#179 `_, `#180 `_, `#202 `_, diff --git a/dep/fmt/LICENSE.rst b/dep/fmt/LICENSE.rst index eb6be6503e9..f0ec3db4d2a 100644 --- a/dep/fmt/LICENSE.rst +++ b/dep/fmt/LICENSE.rst @@ -1,23 +1,27 @@ -Copyright (c) 2012 - 2016, Victor Zverovich +Copyright (c) 2012 - present, Victor Zverovich -All rights reserved. +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: -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. -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. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -THIS 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. +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into a machine-executable object form of such +source code, you may redistribute such embedded portions in such object form +without including the above copyright and permission notices. diff --git a/dep/fmt/README.rst b/dep/fmt/README.rst index 32f50257eb8..acddc70ef18 100644 --- a/dep/fmt/README.rst +++ b/dep/fmt/README.rst @@ -6,189 +6,392 @@ .. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v :target: https://ci.appveyor.com/project/vitaut/fmt - -.. image:: https://badges.gitter.im/Join%20Chat.svg - :alt: Join the chat at https://gitter.im/fmtlib/fmt - :target: https://gitter.im/fmtlib/fmt -**fmt** is an open-source formatting library for C++. -It can be used as a safe alternative to printf or as a fast -alternative to IOStreams. +.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg + :alt: fmt is continuously fuzzed at oss-fuzz + :target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\ + colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\ + Summary&q=proj%3Dfmt&can=1 -`Documentation `_ +.. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg + :alt: Ask questions at StackOverflow with the tag fmt + :target: https://stackoverflow.com/questions/tagged/fmt + +**{fmt}** is an open-source formatting library providing a fast and safe +alternative to C stdio and C++ iostreams. + +If you like this project, please consider donating to BYSOL, +an initiative to help victims of political repressions in Belarus: +https://www.facebook.com/donate/759400044849707/108388587646909/. + +`Documentation `__ + +Q&A: ask questions on `StackOverflow with the tag fmt +`_. + +Try {fmt} in `Compiler Explorer `_. Features -------- -* Two APIs: faster concatenation-based `write API - `_ and slower, - but still very fast, replacement-based `format API - `_ with positional arguments - for localization. -* Write API similar to the one used by IOStreams but stateless allowing - faster implementation. -* Format API with `format string syntax - `_ - similar to the one used by `str.format - `_ in Python. +* Simple `format API `_ with positional arguments + for localization +* Implementation of `C++20 std::format + `__ +* `Format string syntax `_ similar to Python's + `format `_ +* Fast IEEE 754 floating-point formatter with correct rounding, shortness and + round-trip guarantees * Safe `printf implementation - `_ - including the POSIX extension for positional arguments. -* Support for user-defined types. -* High speed: performance of the format API is close to that of - glibc's `printf `_ - and better than the performance of IOStreams. See `Speed tests`_ and - `Fast integer to string conversion in C++ - `_. -* Small code size both in terms of source code (the core library consists of a single - header file and a single source file) and compiled code. - See `Compile time and code bloat`_. -* Reliability: the library has an extensive set of `unit tests - `_. -* Safety: the library is fully type safe, errors in format strings are - reported using exceptions, automatic memory management prevents buffer - overflow errors. + `_ including the POSIX + extension for positional arguments +* Extensibility: `support for user-defined types + `_ +* High performance: faster than common standard library implementations of + ``(s)printf``, iostreams, ``to_string`` and ``to_chars``, see `Speed tests`_ + and `Converting a hundred million integers to strings per second + `_ +* Small code size both in terms of source code with the minimum configuration + consisting of just three files, ``core.h``, ``format.h`` and ``format-inl.h``, + and compiled code; see `Compile time and code bloat`_ +* Reliability: the library has an extensive set of `tests + `_ and is `continuously fuzzed + `_ +* Safety: the library is fully type safe, errors in format strings can be + reported at compile time, automatic memory management prevents buffer overflow + errors * Ease of use: small self-contained code base, no external dependencies, - permissive BSD `license + permissive MIT `license `_ -* `Portability `_ with consistent output - across platforms and support for older compilers. -* Clean warning-free codebase even on high warning levels - (-Wall -Wextra -pedantic). -* Support for wide strings. -* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro. +* `Portability `_ with + consistent output across platforms and support for older compilers +* Clean warning-free codebase even on high warning levels such as + ``-Wall -Wextra -pedantic`` +* Locale-independence by default +* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro -See the `documentation `_ for more details. +See the `documentation `_ for more details. Examples -------- -This prints ``Hello, world!`` to stdout: +**Print to stdout** (`run `_) + +.. code:: c++ + + #include + + int main() { + fmt::print("Hello, world!\n"); + } + +**Format a string** (`run `_) .. code:: c++ - fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax - fmt::printf("Hello, %s!", "world"); // uses printf format string syntax + std::string s = fmt::format("The answer is {}.", 42); + // s == "The answer is 42." -Arguments can be accessed by position and arguments' indices can be repeated: +**Format a string using positional arguments** (`run `_) .. code:: c++ - std::string s = fmt::format("{0}{1}{0}", "abra", "cad"); - // s == "abracadabra" + std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy"); + // s == "I'd rather be happy than right." -fmt can be used as a safe portable replacement for ``itoa``: +**Print chrono durations** (`run `_) .. code:: c++ - fmt::MemoryWriter w; - w << 42; // replaces itoa(42, buffer, 10) - w << fmt::hex(42); // replaces itoa(42, buffer, 16) - // access the string using w.str() or w.c_str() + #include + + int main() { + using namespace std::literals::chrono_literals; + fmt::print("Default format: {} {}\n", 42s, 100ms); + fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s); + } + +Output:: + + Default format: 42s 100ms + strftime-like format: 03:15:30 + +**Print a container** (`run `_) + +.. code:: c++ + + #include + #include + + int main() { + std::vector v = {1, 2, 3}; + fmt::print("{}\n", v); + } + +Output:: + + {1, 2, 3} -An object of any user-defined type for which there is an overloaded -:code:`std::ostream` insertion operator (``operator<<``) can be formatted: +**Check a format string at compile time** .. code:: c++ - #include "fmt/ostream.h" + std::string s = fmt::format(FMT_STRING("{:d}"), "don't panic"); + +This gives a compile-time error because ``d`` is an invalid format specifier for +a string. + +**Write a file from a single thread** + +.. code:: c++ - class Date { - int year_, month_, day_; - public: - Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} + #include - friend std::ostream &operator<<(std::ostream &os, const Date &d) { - return os << d.year_ << '-' << d.month_ << '-' << d.day_; - } - }; + int main() { + auto out = fmt::output_file("guide.txt"); + out.print("Don't {}", "Panic"); + } - std::string s = fmt::format("The date is {}", Date(2012, 12, 9)); - // s == "The date is 2012-12-9" +This can be `5 to 9 times faster than fprintf +`_. -You can use the `FMT_VARIADIC -`_ -macro to create your own functions similar to `format -`_ and -`print `_ -which take arbitrary arguments: +**Print with colors and text styles** .. code:: c++ - // Prints formatted error message. - void report_error(const char *format, fmt::ArgList args) { - fmt::print("Error: "); - fmt::print(format, args); + #include + + int main() { + fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, + "Hello, {}!\n", "world"); + fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | + fmt::emphasis::underline, "Hello, {}!\n", "мир"); + fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, + "Hello, {}!\n", "世界"); } - FMT_VARIADIC(void, report_error, const char *) - report_error("file not found: {}", path); +Output on a modern terminal: + +.. image:: https://user-images.githubusercontent.com/ + 576385/88485597-d312f600-cf2b-11ea-9cbe-61f535a86e28.png + +Benchmarks +---------- + +Speed tests +~~~~~~~~~~~ + +================= ============= =========== +Library Method Run Time, s +================= ============= =========== +libc printf 1.04 +libc++ std::ostream 3.05 +{fmt} 6.1.1 fmt::print 0.75 +Boost Format 1.67 boost::format 7.24 +Folly Format folly::format 2.23 +================= ============= =========== + +{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``. + +The above results were generated by building ``tinyformat_test.cpp`` on macOS +10.14.6 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the +best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` +or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for +further details refer to the `source +`_. + +{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on +floating-point formatting (`dtoa-benchmark `_) +and faster than `double-conversion `_ and +`ryu `_: + +.. image:: https://user-images.githubusercontent.com/576385/ + 95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png + :target: https://fmt.dev/unknown_mac64_clang12.0.html + +Compile time and code bloat +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The script `bloat-test.py +`_ +from `format-benchmark `_ +tests compile time and code bloat for nontrivial projects. +It generates 100 translation units and uses ``printf()`` or its alternative +five times in each to simulate a medium sized project. The resulting +executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42), +macOS Sierra, best of three) is shown in the following tables. + +**Optimized build (-O3)** + +============= =============== ==================== ================== +Method Compile Time, s Executable size, KiB Stripped size, KiB +============= =============== ==================== ================== +printf 2.6 29 26 +printf+string 16.4 29 26 +iostreams 31.1 59 55 +{fmt} 19.0 37 34 +Boost Format 91.9 226 203 +Folly Format 115.7 101 88 +============= =============== ==================== ================== + +As you can see, {fmt} has 60% less overhead in terms of resulting binary code +size compared to iostreams and comes pretty close to ``printf``. Boost Format +and Folly Format have the largest overheads. + +``printf+string`` is the same as ``printf`` but with extra ```` +include to measure the overhead of the latter. + +**Non-optimized build** + +============= =============== ==================== ================== +Method Compile Time, s Executable size, KiB Stripped size, KiB +============= =============== ==================== ================== +printf 2.2 33 30 +printf+string 16.0 33 30 +iostreams 28.3 56 52 +{fmt} 18.2 59 50 +Boost Format 54.1 365 303 +Folly Format 79.9 445 430 +============= =============== ==================== ================== + +``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared libraries to +compare formatting function overhead only. Boost Format is a +header-only library so it doesn't provide any linkage options. + +Running the tests +~~~~~~~~~~~~~~~~~ + +Please refer to `Building the library`__ for the instructions on how to build +the library and run the unit tests. + +__ https://fmt.dev/latest/usage.html#building-the-library + +Benchmarks reside in a separate repository, +`format-benchmarks `_, +so to run the benchmarks you first need to clone this repository and +generate Makefiles with CMake:: + + $ git clone --recursive https://github.com/fmtlib/format-benchmark.git + $ cd format-benchmark + $ cmake . + +Then you can run the speed test:: + + $ make speed-test + +or the bloat test:: -Note that you only need to define one function that takes ``fmt::ArgList`` -argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that -accept variable number of arguments. + $ make bloat-test Projects using this library --------------------------- -* `0 A.D. `_: A free, open-source, cross-platform real-time strategy game +* `0 A.D. `_: a free, open-source, cross-platform + real-time strategy game * `AMPL/MP `_: - An open-source library for mathematical programming + an open-source library for mathematical programming + +* `Aseprite `_: + animated sprite editor & pixel art tool + +* `AvioBook `_: a comprehensive aircraft + operations suite + +* `Blizzard Battle.net `_: an online gaming platform + +* `Celestia `_: real-time 3D visualization of space + +* `Ceph `_: a scalable distributed storage system -* `CUAUV `_: Cornell University's autonomous underwater vehicle +* `ccache `_: a compiler cache -* `Drake `_: A planning, control, and analysis toolbox for nonlinear dynamical systems (MIT) +* `ClickHouse `_: analytical database + management system -* `Envoy `_: C++ L7 proxy and communication bus (Lyft) +* `CUAUV `_: Cornell University's autonomous underwater + vehicle + +* `Drake `_: a planning, control, and analysis toolbox + for nonlinear dynamical systems (MIT) + +* `Envoy `_: C++ L7 proxy and communication bus + (Lyft) * `FiveM `_: a modification framework for GTA V +* `Folly `_: Facebook open-source library + * `HarpyWar/pvpgn `_: Player vs Player Gaming Network with tweaks -* `KBEngine `_: An open-source MMOG server engine +* `KBEngine `_: an open-source MMOG server + engine + +* `Keypirinha `_: a semantic launcher for Windows + +* `Kodi `_ (formerly xbmc): home theater software -* `Keypirinha `_: A semantic launcher for Windows +* `Knuth `_: high-performance Bitcoin full-node -* `Kodi `_ (formerly xbmc): Home theater software +* `Microsoft Verona `_: + research programming language for concurrent ownership -* `Lifeline `_: A 2D game +* `MongoDB `_: distributed document database -* `MongoDB Smasher `_: A small tool to generate randomized datasets +* `MongoDB Smasher `_: a small tool to + generate randomized datasets -* `OpenSpace `_: An open-source astrovisualization framework +* `OpenSpace `_: an open-source + astrovisualization framework -* `PenUltima Online (POL) `_: - An MMO server, compatible with most Ultima Online clients +* `PenUltima Online (POL) `_: + an MMO server, compatible with most Ultima Online clients -* `quasardb `_: A distributed, high-performance, associative database +* `PyTorch `_: an open-source machine + learning library -* `readpe `_: Read Portable Executable +* `quasardb `_: a distributed, high-performance, + associative database + +* `Quill `_: asynchronous low-latency logging library -* `redis-cerberus `_: A Redis cluster proxy +* `QKW `_: generalizing aliasing to simplify + navigation, and executing complex multi-line terminal command sequences -* `Saddy `_: - Small crossplatform 2D graphic engine +* `redis-cerberus `_: a Redis cluster + proxy -* `Salesforce Analytics Cloud `_: - Business intelligence software +* `redpanda `_: a 10x faster Kafka® replacement + for mission critical systems written in C++ -* `Scylla `_: A Cassandra-compatible NoSQL data store that can handle - 1 million transactions per second on a single server +* `rpclib `_: a modern C++ msgpack-RPC server and client + library -* `Seastar `_: An advanced, open-source C++ framework for - high-performance server applications on modern hardware +* `Salesforce Analytics Cloud + `_: + business intelligence software -* `spdlog `_: Super fast C++ logging library +* `Scylla `_: a Cassandra-compatible NoSQL data store + that can handle 1 million transactions per second on a single server -* `Stellar `_: Financial platform +* `Seastar `_: an advanced, open-source C++ + framework for high-performance server applications on modern hardware -* `Touch Surgery `_: Surgery simulator +* `spdlog `_: super fast C++ logging library -* `TrinityCore `_: Open-source MMORPG framework +* `Stellar `_: financial platform -`More... `_ +* `Touch Surgery `_: surgery simulator + +* `TrinityCore `_: open-source + MMORPG framework + +* `Windows Terminal `_: the new Windows + terminal + +`More... `_ If you are aware of other projects using this library, please let me know by `email `_ or by submitting an @@ -200,28 +403,28 @@ Motivation So why yet another formatting library? There are plenty of methods for doing this task, from standard ones like -the printf family of function and IOStreams to Boost Format library and -FastFormat. The reason for creating a new library is that every existing +the printf family of function and iostreams to Boost Format and FastFormat +libraries. The reason for creating a new library is that every existing solution that I found either had serious issues or didn't provide all the features I needed. -Printf +printf ~~~~~~ -The good thing about printf is that it is pretty fast and readily available +The good thing about ``printf`` is that it is pretty fast and readily available being a part of the C standard library. The main drawback is that it -doesn't support user-defined types. Printf also has safety issues although -they are mostly solved with `__attribute__ ((format (printf, ...)) -`_ in GCC. +doesn't support user-defined types. ``printf`` also has safety issues although +they are somewhat mitigated with `__attribute__ ((format (printf, ...)) +`_ in GCC. There is a POSIX extension that adds positional arguments required for `i18n `_ -to printf but it is not a part of C99 and may not be available on some +to ``printf`` but it is not a part of C99 and may not be available on some platforms. -IOStreams +iostreams ~~~~~~~~~ -The main issue with IOStreams is best illustrated with an example: +The main issue with iostreams is best illustrated with an example: .. code:: c++ @@ -233,27 +436,26 @@ which is a lot of typing compared to printf: printf("%.2f\n", 1.23456); -Matthew Wilson, the author of FastFormat, referred to this situation with -IOStreams as "chevron hell". IOStreams doesn't support positional arguments -by design. +Matthew Wilson, the author of FastFormat, called this "chevron hell". iostreams +don't support positional arguments by design. -The good part is that IOStreams supports user-defined types and is safe -although error reporting is awkward. +The good part is that iostreams support user-defined types and are safe although +error handling is awkward. -Boost Format library -~~~~~~~~~~~~~~~~~~~~ +Boost Format +~~~~~~~~~~~~ -This is a very powerful library which supports both printf-like format -strings and positional arguments. The main its drawback is performance. -According to various benchmarks it is much slower than other methods -considered here. Boost Format also has excessive build times and severe -code bloat issues (see `Benchmarks`_). +This is a very powerful library which supports both ``printf``-like format +strings and positional arguments. Its main drawback is performance. According to +various, benchmarks it is much slower than other methods considered here. Boost +Format also has excessive build times and severe code bloat issues (see +`Benchmarks`_). FastFormat ~~~~~~~~~~ -This is an interesting library which is fast, safe and has positional -arguments. However it has significant limitations, citing its author: +This is an interesting library which is fast, safe and has positional arguments. +However, it has significant limitations, citing its author: Three features that have no hope of being accommodated within the current design are: @@ -262,177 +464,43 @@ arguments. However it has significant limitations, citing its author: * Octal/hexadecimal encoding * Runtime width/alignment specification -It is also quite big and has a heavy dependency, STLSoft, which might be -too restrictive for using it in some projects. - -Loki SafeFormat -~~~~~~~~~~~~~~~ - -SafeFormat is a formatting library which uses printf-like format strings -and is type safe. It doesn't support user-defined types or positional -arguments. It makes unconventional use of ``operator()`` for passing -format arguments. - -Tinyformat -~~~~~~~~~~ - -This library supports printf-like format strings and is very small and -fast. Unfortunately it doesn't support positional arguments and wrapping -it in C++98 is somewhat difficult. Also its performance and code compactness -are limited by IOStreams. +It is also quite big and has a heavy dependency, STLSoft, which might be too +restrictive for using it in some projects. Boost Spirit.Karma ~~~~~~~~~~~~~~~~~~ -This is not really a formatting library but I decided to include it here -for completeness. As IOStreams it suffers from the problem of mixing -verbatim text with arguments. The library is pretty fast, but slower -on integer formatting than ``fmt::Writer`` on Karma's own benchmark, -see `Fast integer to string conversion in C++ -`_. - -Benchmarks ----------- - -Speed tests -~~~~~~~~~~~ - -The following speed tests results were generated by building -``tinyformat_test.cpp`` on Ubuntu GNU/Linux 14.04.1 with -``g++-4.8.2 -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of three -runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` or -equivalent is filled 2000000 times with output sent to ``/dev/null``; for -further details see the `source -`_. - -================= ============= =========== -Library Method Run Time, s -================= ============= =========== -EGLIBC 2.19 printf 1.30 -libstdc++ 4.8.2 std::ostream 1.85 -fmt 1.0 fmt::print 1.42 -tinyformat 2.0.1 tfm::printf 2.25 -Boost Format 1.54 boost::format 9.94 -================= ============= =========== - -As you can see ``boost::format`` is much slower than the alternative methods; this -is confirmed by `other tests `_. -Tinyformat is quite good coming close to IOStreams. Unfortunately tinyformat -cannot be faster than the IOStreams because it uses them internally. -Performance of fmt is close to that of printf, being `faster than printf on integer -formatting `_, -but slower on floating-point formatting which dominates this benchmark. - -Compile time and code bloat -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The script `bloat-test.py -`_ -from `format-benchmark `_ -tests compile time and code bloat for nontrivial projects. -It generates 100 translation units and uses ``printf()`` or its alternative -five times in each to simulate a medium sized project. The resulting -executable size and compile time (g++-4.8.1, Ubuntu GNU/Linux 13.10, -best of three) is shown in the following tables. - -**Optimized build (-O3)** - -============ =============== ==================== ================== -Method Compile Time, s Executable size, KiB Stripped size, KiB -============ =============== ==================== ================== -printf 2.6 41 30 -IOStreams 19.4 92 70 -fmt 46.8 46 34 -tinyformat 64.6 418 386 -Boost Format 222.8 990 923 -============ =============== ==================== ================== - -As you can see, fmt has two times less overhead in terms of resulting -code size compared to IOStreams and comes pretty close to ``printf``. -Boost Format has by far the largest overheads. - -**Non-optimized build** - -============ =============== ==================== ================== -Method Compile Time, s Executable size, KiB Stripped size, KiB -============ =============== ==================== ================== -printf 2.1 41 30 -IOStreams 19.7 86 62 -fmt 47.9 108 86 -tinyformat 27.7 234 190 -Boost Format 122.6 884 763 -============ =============== ==================== ================== - -``libc``, ``libstdc++`` and ``libfmt`` are all linked as shared -libraries to compare formatting function overhead only. Boost Format -and tinyformat are header-only libraries so they don't provide any -linkage options. - -Running the tests -~~~~~~~~~~~~~~~~~ - -Please refer to `Building the library`__ for the instructions on how to build -the library and run the unit tests. - -__ http://fmtlib.net/latest/usage.html#building-the-library - -Benchmarks reside in a separate repository, -`format-benchmarks `_, -so to run the benchmarks you first need to clone this repository and -generate Makefiles with CMake:: - - $ git clone --recursive https://github.com/fmtlib/format-benchmark.git - $ cd format-benchmark - $ cmake . - -Then you can run the speed test:: - - $ make speed-test - -or the bloat test:: - - $ make bloat-test +This is not really a formatting library but I decided to include it here for +completeness. As iostreams, it suffers from the problem of mixing verbatim text +with arguments. The library is pretty fast, but slower on integer formatting +than ``fmt::format_to`` with format string compilation on Karma's own benchmark, +see `Converting a hundred million integers to strings per second +`_. License ------- -fmt is distributed under the BSD `license +{fmt} is distributed under the MIT `license `_. -The `Format String Syntax -`_ +Documentation License +--------------------- + +The `Format String Syntax `_ section in the documentation is based on the one from Python `string module -documentation `_ -adapted for the current library. For this reason the documentation is -distributed under the Python Software Foundation license available in -`doc/python-license.txt +documentation `_. +For this reason the documentation is distributed under the Python Software +Foundation license available in `doc/python-license.txt `_. -It only applies if you distribute the documentation of fmt. - -Acknowledgments ---------------- - -The fmt library is maintained by Victor Zverovich (`vitaut `_) -and Jonathan Müller (`foonathan `_) with contributions from many -other people. See `Contributors `_ and `Releases `_ for some of the names. Let us know if your contribution -is not listed or mentioned incorrectly and we'll make it right. - -The benchmark section of this readme file and the performance tests are taken -from the excellent `tinyformat `_ library -written by Chris Foster. Boost Format library is acknowledged transitively -since it had some influence on tinyformat. -Some ideas used in the implementation are borrowed from `Loki -`_ SafeFormat and `Diagnostic API -`_ in -`Clang `_. -Format string syntax and the documentation are based on Python's `str.format -`_. -Thanks `Doug Turnbull `_ for his valuable -comments and contribution to the design of the type-safe API and -`Gregory Czajkowski `_ for implementing binary -formatting. Thanks `Ruslan Baratov `_ for comprehensive -`comparison of integer formatting algorithms `_ -and useful comments regarding performance, `Boris Kaul `_ for -`C++ counting digits benchmark `_. -Thanks to `CarterLi `_ for contributing various -improvements to the code. +It only applies if you distribute the documentation of {fmt}. + +Maintainers +----------- + +The {fmt} library is maintained by Victor Zverovich (`vitaut +`_) and Jonathan Müller (`foonathan +`_) with contributions from many other people. +See `Contributors `_ and +`Releases `_ for some of the names. +Let us know if your contribution is not listed or mentioned incorrectly and +we'll make it right. diff --git a/dep/fmt/fmt/container.h b/dep/fmt/fmt/container.h deleted file mode 100644 index cb6303fb7e4..00000000000 --- a/dep/fmt/fmt/container.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - Formatting library for C++ - standard container utilities - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_CONTAINER_H_ -#define FMT_CONTAINER_H_ - -#include "format.h" - -namespace fmt { - -namespace internal { - -/** - \rst - A "buffer" that appends data to a standard container (e.g. typically a - ``std::vector`` or ``std::basic_string``). - \endrst - */ -template -class ContainerBuffer : public Buffer { - private: - Container& container_; - - protected: - virtual void grow(std::size_t size) FMT_OVERRIDE { - container_.resize(size); - this->ptr_ = &container_[0]; - this->capacity_ = size; - } - - public: - explicit ContainerBuffer(Container& container) : container_(container) { - this->size_ = container_.size(); - if (this->size_ > 0) { - this->ptr_ = &container_[0]; - this->capacity_ = this->size_; - } - } -}; -} // namespace internal - -/** - \rst - This class template provides operations for formatting and appending data - to a standard *container* like ``std::vector`` or ``std::basic_string``. - - **Example**:: - - void vecformat(std::vector& dest, fmt::BasicCStringRef format, - fmt::ArgList args) { - fmt::BasicContainerWriter > appender(dest); - appender.write(format, args); - } - FMT_VARIADIC(void, vecformat, std::vector&, - fmt::BasicCStringRef); - \endrst - */ -template -class BasicContainerWriter - : public BasicWriter { - private: - internal::ContainerBuffer buffer_; - - public: - /** - \rst - Constructs a :class:`fmt::BasicContainerWriter` object. - \endrst - */ - explicit BasicContainerWriter(Container& dest) - : BasicWriter(buffer_), buffer_(dest) {} -}; - -} // namespace fmt - -#endif // FMT_CONTAINER_H_ diff --git a/dep/fmt/fmt/format.cc b/dep/fmt/fmt/format.cc deleted file mode 100644 index 2d236bc641d..00000000000 --- a/dep/fmt/fmt/format.cc +++ /dev/null @@ -1,495 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE 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 "format.h" - -#include - -#include -#include -#include -#include -#include -#include // for std::ptrdiff_t - -#if defined(_WIN32) && defined(__MINGW32__) -# include -#endif - -#if FMT_USE_WINDOWS_H -# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) -# define WIN32_LEAN_AND_MEAN -# endif -# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) -# include -# else -# define NOMINMAX -# include -# undef NOMINMAX -# endif -#endif - -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4702) // unreachable code -// Disable deprecation warning for strerror. The latter is not called but -// MSVC fails to detect it. -# pragma warning(disable: 4996) -#endif - -// Dummy implementations of strerror_r and strerror_s called if corresponding -// system functions are not available. -FMT_MAYBE_UNUSED -static inline fmt::internal::Null<> strerror_r(int, char *, ...) { - return fmt::internal::Null<>(); -} -FMT_MAYBE_UNUSED -static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { - return fmt::internal::Null<>(); -} - -namespace fmt { - -FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {} -FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {} -FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {} - -namespace { - -#ifndef _MSC_VER -# define FMT_SNPRINTF snprintf -#else // _MSC_VER -inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { - va_list args; - va_start(args, format); - int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); - va_end(args); - return result; -} -# define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER - -#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) -# define FMT_SWPRINTF snwprintf -#else -# define FMT_SWPRINTF swprintf -#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) - -const char RESET_COLOR[] = "\x1b[0m"; - -typedef void (*FormatFunc)(Writer &, int, StringRef); - -// Portable thread-safe version of strerror. -// Sets buffer to point to a string describing the error code. -// This can be either a pointer to a string stored in buffer, -// or a pointer to some static immutable string. -// Returns one of the following values: -// 0 - success -// ERANGE - buffer is not large enough to store the error message -// other - failure -// Buffer should be at least of size 1. -int safe_strerror( - int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { - FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); - - class StrError { - private: - int error_code_; - char *&buffer_; - std::size_t buffer_size_; - - // A noop assignment operator to avoid bogus warnings. - void operator=(const StrError &) {} - - // Handle the result of XSI-compliant version of strerror_r. - int handle(int result) { - // glibc versions before 2.13 return result in errno. - return result == -1 ? errno : result; - } - - // Handle the result of GNU-specific version of strerror_r. - int handle(char *message) { - // If the buffer is full then the message is probably truncated. - if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) - return ERANGE; - buffer_ = message; - return 0; - } - - // Handle the case when strerror_r is not available. - int handle(internal::Null<>) { - return fallback(strerror_s(buffer_, buffer_size_, error_code_)); - } - - // Fallback to strerror_s when strerror_r is not available. - int fallback(int result) { - // If the buffer is full then the message is probably truncated. - return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? - ERANGE : result; - } - -#ifdef __c2__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - - // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(internal::Null<>) { - errno = 0; - buffer_ = strerror(error_code_); - return errno; - } - -#ifdef __c2__ -# pragma clang diagnostic pop -#endif - - public: - StrError(int err_code, char *&buf, std::size_t buf_size) - : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} - - int run() { - return handle(strerror_r(error_code_, buffer_, buffer_size_)); - } - }; - return StrError(error_code, buffer, buffer_size).run(); -} - -void format_error_code(Writer &out, int error_code, - StringRef message) FMT_NOEXCEPT { - // Report error code making sure that the output fits into - // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential - // bad_alloc. - out.clear(); - static const char SEP[] = ": "; - static const char ERROR_STR[] = "error "; - // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. - std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - typedef internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(error_code); - if (internal::is_negative(error_code)) { - abs_value = 0 - abs_value; - ++error_code_size; - } - error_code_size += internal::count_digits(abs_value); - if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) - out << message << SEP; - out << ERROR_STR << error_code; - assert(out.size() <= internal::INLINE_BUFFER_SIZE); -} - -void report_error(FormatFunc func, int error_code, - StringRef message) FMT_NOEXCEPT { - MemoryWriter full_message; - func(full_message, error_code, message); - // Use Writer::data instead of Writer::c_str to avoid potential memory - // allocation. - std::fwrite(full_message.data(), full_message.size(), 1, stderr); - std::fputc('\n', stderr); -} -} // namespace - -FMT_FUNC void SystemError::init( - int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - format_system_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -template -int internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? - FMT_SNPRINTF(buffer, size, format, value) : - FMT_SNPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? - FMT_SNPRINTF(buffer, size, format, width, value) : - FMT_SNPRINTF(buffer, size, format, width, precision, value); -} - -template -int internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? - FMT_SWPRINTF(buffer, size, format, value) : - FMT_SWPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? - FMT_SWPRINTF(buffer, size, format, width, value) : - FMT_SWPRINTF(buffer, size, format, width, precision, value); -} - -template -const char internal::BasicData::DIGITS[] = - "0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"; - -#define FMT_POWERS_OF_10(factor) \ - factor * 10, \ - factor * 100, \ - factor * 1000, \ - factor * 10000, \ - factor * 100000, \ - factor * 1000000, \ - factor * 10000000, \ - factor * 100000000, \ - factor * 1000000000 - -template -const uint32_t internal::BasicData::POWERS_OF_10_32[] = { - 0, FMT_POWERS_OF_10(1) -}; - -template -const uint64_t internal::BasicData::POWERS_OF_10_64[] = { - 0, - FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(ULongLong(1000000000)), - // Multiply several constants instead of using a single long long constant - // to avoid warnings about C++98 not supporting long long. - ULongLong(1000000000) * ULongLong(1000000000) * 10 -}; - -FMT_FUNC void internal::report_unknown_type(char code, const char *type) { - (void)type; - if (std::isprint(static_cast(code))) { - FMT_THROW(FormatError( - format("unknown format code '{}' for {}", code, type))); - } - FMT_THROW(FormatError( - format("unknown format code '\\x{:02x}' for {}", - static_cast(code), type))); -} - -#if FMT_USE_WINDOWS_H - -FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { - static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; - if (s.size() > INT_MAX) - FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); - int s_size = static_cast(s.size()); - int length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_.resize(length + 1); - length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_[length] = 0; -} - -FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { - if (int error_code = convert(s)) { - FMT_THROW(WindowsError(error_code, - "cannot convert string from UTF-16 to UTF-8")); - } -} - -FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { - if (s.size() > INT_MAX) - return ERROR_INVALID_PARAMETER; - int s_size = static_cast(s.size()); - int length = WideCharToMultiByte( - CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); - if (length == 0) - return GetLastError(); - buffer_.resize(length + 1); - length = WideCharToMultiByte( - CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); - if (length == 0) - return GetLastError(); - buffer_[length] = 0; - return 0; -} - -FMT_FUNC void WindowsError::init( - int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_windows_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -FMT_FUNC void internal::format_windows_error( - Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { - FMT_TRY { - MemoryBuffer buffer; - buffer.resize(INLINE_BUFFER_SIZE); - for (;;) { - wchar_t *system_message = &buffer[0]; - int result = FormatMessageW( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - system_message, static_cast(buffer.size()), FMT_NULL); - if (result != 0) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; - } - break; - } - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -#endif // FMT_USE_WINDOWS_H - -FMT_FUNC void format_system_error( - Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { - FMT_TRY { - internal::MemoryBuffer buffer; - buffer.resize(internal::INLINE_BUFFER_SIZE); - for (;;) { - char *system_message = &buffer[0]; - int result = safe_strerror(error_code, system_message, buffer.size()); - if (result == 0) { - out << message << ": " << system_message; - return; - } - if (result != ERANGE) - break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -template -void internal::FixedBuffer::grow(std::size_t) { - FMT_THROW(std::runtime_error("buffer overflow")); -} - -FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg( - unsigned arg_index, const char *&error) { - internal::Arg arg = args_[arg_index]; - switch (arg.type) { - case internal::Arg::NONE: - error = "argument index out of range"; - break; - case internal::Arg::NAMED_ARG: - arg = *static_cast(arg.pointer); - break; - default: - /*nothing*/; - } - return arg; -} - -FMT_FUNC void report_system_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - report_error(format_system_error, error_code, message); -} - -#if FMT_USE_WINDOWS_H -FMT_FUNC void report_windows_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - report_error(internal::format_windows_error, error_code, message); -} -#endif - -FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - std::fwrite(w.data(), 1, w.size(), f); -} - -FMT_FUNC void print(CStringRef format_str, ArgList args) { - print(stdout, format_str, args); -} - -FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { - char escape[] = "\x1b[30m"; - escape[3] = static_cast('0' + c); - std::fputs(escape, stdout); - print(format, args); - std::fputs(RESET_COLOR, stdout); -} - -#ifndef FMT_HEADER_ONLY - -template struct internal::BasicData; - -// Explicit instantiations for char. - -template void internal::FixedBuffer::grow(std::size_t); - -template FMT_API int internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, double value); - -template FMT_API int internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, long double value); - -// Explicit instantiations for wchar_t. - -template void internal::FixedBuffer::grow(std::size_t); - -template FMT_API int internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, double value); - -template FMT_API int internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, long double value); - -#endif // FMT_HEADER_ONLY - -} // namespace fmt - -#ifdef _MSC_VER -# pragma warning(pop) -#endif diff --git a/dep/fmt/fmt/format.h b/dep/fmt/fmt/format.h deleted file mode 100644 index bd99746a58c..00000000000 --- a/dep/fmt/fmt/format.h +++ /dev/null @@ -1,4173 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE 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 FMT_FORMAT_H_ -#define FMT_FORMAT_H_ - -#define FMT_INCLUDE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for std::pair -#undef FMT_INCLUDE - -// The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 40001 - -#if defined(__has_include) -# define FMT_HAS_INCLUDE(x) __has_include(x) -#else -# define FMT_HAS_INCLUDE(x) 0 -#endif - -#if (FMT_HAS_INCLUDE() && __cplusplus > 201402L) || \ - (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) -# include -# define FMT_HAS_STRING_VIEW 1 -#else -# define FMT_HAS_STRING_VIEW 0 -#endif - -#if defined _SECURE_SCL && _SECURE_SCL -# define FMT_SECURE_SCL _SECURE_SCL -#else -# define FMT_SECURE_SCL 0 -#endif - -#if FMT_SECURE_SCL -# include -#endif - -#ifdef _MSC_VER -# define FMT_MSC_VER _MSC_VER -#else -# define FMT_MSC_VER 0 -#endif - -#if FMT_MSC_VER && FMT_MSC_VER <= 1500 -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -typedef __int64 intmax_t; -#else -#include -#endif - -#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) -# ifdef FMT_EXPORT -# define FMT_API __declspec(dllexport) -# elif defined(FMT_SHARED) -# define FMT_API __declspec(dllimport) -# endif -#endif -#ifndef FMT_API -# define FMT_API -#endif - -#ifdef __GNUC__ -# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FMT_GCC_EXTENSION __extension__ -# if FMT_GCC_VERSION >= 406 -# pragma GCC diagnostic push -// Disable the warning about "long long" which is sometimes reported even -// when using __extension__. -# pragma GCC diagnostic ignored "-Wlong-long" -// Disable the warning about declaration shadowing because it affects too -// many valid cases. -# pragma GCC diagnostic ignored "-Wshadow" -// Disable the warning about implicit conversions that may change the sign of -// an integer; silencing it otherwise would require many explicit casts. -# pragma GCC diagnostic ignored "-Wsign-conversion" -# endif -# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ -# define FMT_HAS_GXX_CXX11 1 -# endif -#else -# define FMT_GCC_VERSION 0 -# define FMT_GCC_EXTENSION -# define FMT_HAS_GXX_CXX11 0 -#endif - -#if defined(__INTEL_COMPILER) -# define FMT_ICC_VERSION __INTEL_COMPILER -#elif defined(__ICL) -# define FMT_ICC_VERSION __ICL -#endif - -#if defined(__clang__) && !defined(FMT_ICC_VERSION) -# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdocumentation-unknown-command" -# pragma clang diagnostic ignored "-Wpadded" -#endif - -#ifdef __GNUC_LIBSTD__ -# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) -#endif - -#ifdef __has_feature -# define FMT_HAS_FEATURE(x) __has_feature(x) -#else -# define FMT_HAS_FEATURE(x) 0 -#endif - -#ifdef __has_builtin -# define FMT_HAS_BUILTIN(x) __has_builtin(x) -#else -# define FMT_HAS_BUILTIN(x) 0 -#endif - -#ifdef __has_cpp_attribute -# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define FMT_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -#if FMT_HAS_CPP_ATTRIBUTE(maybe_unused) -# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -// VC++ 1910 support /std: option and that will set _MSVC_LANG macro -// Clang with Microsoft CodeGen doesn't define _MSVC_LANG macro -#elif defined(_MSVC_LANG) && _MSVC_LANG > 201402 && _MSC_VER >= 1910 -# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -#endif - -#ifdef FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -# define FMT_MAYBE_UNUSED [[maybe_unused]] -// g++/clang++ also support [[gnu::unused]]. However, we don't use it. -#elif defined(__GNUC__) -# define FMT_MAYBE_UNUSED __attribute__((unused)) -#else -# define FMT_MAYBE_UNUSED -#endif - -// Use the compiler's attribute noreturn -#if defined(__MINGW32__) || defined(__MINGW64__) -# define FMT_NORETURN __attribute__((noreturn)) -#elif FMT_HAS_CPP_ATTRIBUTE(noreturn) && __cplusplus >= 201103L -# define FMT_NORETURN [[noreturn]] -#else -# define FMT_NORETURN -#endif - -#ifndef FMT_USE_VARIADIC_TEMPLATES -// Variadic templates are available in GCC since version 4.4 -// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ -// since version 2013. -# define FMT_USE_VARIADIC_TEMPLATES \ - (FMT_HAS_FEATURE(cxx_variadic_templates) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800) -#endif - -#ifndef FMT_USE_RVALUE_REFERENCES -// Don't use rvalue references when compiling with clang and an old libstdc++ -// as the latter doesn't provide std::move. -# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 -# define FMT_USE_RVALUE_REFERENCES 0 -# else -# define FMT_USE_RVALUE_REFERENCES \ - (FMT_HAS_FEATURE(cxx_rvalue_references) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600) -# endif -#endif - -#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700 -# define FMT_USE_ALLOCATOR_TRAITS 1 -#else -# define FMT_USE_ALLOCATOR_TRAITS 0 -#endif - -// Check if exceptions are disabled. -#if defined(__GNUC__) && !defined(__EXCEPTIONS) -# define FMT_EXCEPTIONS 0 -#endif -#if FMT_MSC_VER && !_HAS_EXCEPTIONS -# define FMT_EXCEPTIONS 0 -#endif -#ifndef FMT_EXCEPTIONS -# define FMT_EXCEPTIONS 1 -#endif - -#ifndef FMT_THROW -# if FMT_EXCEPTIONS -# define FMT_THROW(x) throw x -# else -# define FMT_THROW(x) assert(false) -# endif -#endif - -// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). -#ifndef FMT_USE_NOEXCEPT -# define FMT_USE_NOEXCEPT 0 -#endif - -#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1900 -# define FMT_DETECTED_NOEXCEPT noexcept -#else -# define FMT_DETECTED_NOEXCEPT throw() -#endif - -#ifndef FMT_NOEXCEPT -# if FMT_EXCEPTIONS -# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT -# else -# define FMT_NOEXCEPT -# endif -#endif - -// This is needed because GCC still uses throw() in its headers when exceptions -// are disabled. -#if FMT_GCC_VERSION -# define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT -#else -# define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT -#endif - -#ifndef FMT_OVERRIDE -# if (defined(FMT_USE_OVERRIDE) && FMT_USE_OVERRIDE) || FMT_HAS_FEATURE(cxx_override) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1900 -# define FMT_OVERRIDE override -# else -# define FMT_OVERRIDE -# endif -#endif - -#ifndef FMT_NULL -# if FMT_HAS_FEATURE(cxx_nullptr) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1600 -# define FMT_NULL nullptr -# else -# define FMT_NULL NULL -# endif -#endif - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef FMT_USE_DELETED_FUNCTIONS -# define FMT_USE_DELETED_FUNCTIONS 0 -#endif - -#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 -# define FMT_DELETED_OR_UNDEFINED = delete -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - TypeName& operator=(const TypeName&) = delete -#else -# define FMT_DELETED_OR_UNDEFINED -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - TypeName& operator=(const TypeName&) -#endif - -#ifndef FMT_USE_DEFAULTED_FUNCTIONS -# define FMT_USE_DEFAULTED_FUNCTIONS 0 -#endif - -#ifndef FMT_DEFAULTED_COPY_CTOR -# if FMT_USE_DEFAULTED_FUNCTIONS || FMT_HAS_FEATURE(cxx_defaulted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 -# define FMT_DEFAULTED_COPY_CTOR(TypeName) \ - TypeName(const TypeName&) = default; -# else -# define FMT_DEFAULTED_COPY_CTOR(TypeName) -# endif -#endif - -#ifndef FMT_USE_USER_DEFINED_LITERALS -// All compilers which support UDLs also support variadic templates. This -// makes the fmt::literals implementation easier. However, an explicit check -// for variadic templates is added here just in case. -// For Intel's compiler both it and the system gcc/msc must support UDLs. -# if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ - (FMT_HAS_FEATURE(cxx_user_literals) || \ - (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ - (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) -# define FMT_USE_USER_DEFINED_LITERALS 1 -# else -# define FMT_USE_USER_DEFINED_LITERALS 0 -# endif -#endif - -#ifndef FMT_USE_EXTERN_TEMPLATES -# define FMT_USE_EXTERN_TEMPLATES \ - (FMT_CLANG_VERSION >= 209 || (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) -#endif - -#ifdef FMT_HEADER_ONLY -// If header only do not use extern templates. -# undef FMT_USE_EXTERN_TEMPLATES -# define FMT_USE_EXTERN_TEMPLATES 0 -#endif - -#ifndef FMT_ASSERT -# define FMT_ASSERT(condition, message) assert((condition) && message) -#endif - -// __builtin_clz is broken in clang with Microsoft CodeGen: -// https://github.com/fmtlib/fmt/issues/519 -#ifndef _MSC_VER -# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -# endif - -# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -# endif -#endif - -// Some compilers masquerade as both MSVC and GCC-likes or -// otherwise support __builtin_clz and __builtin_clzll, so -// only define FMT_BUILTIN_CLZ using the MSVC intrinsics -// if the clz and clzll builtins are not available. -#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) -# include // _BitScanReverse, _BitScanReverse64 - -namespace fmt { -namespace internal { -// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning -# ifndef __clang__ -# pragma intrinsic(_BitScanReverse) -# endif -inline uint32_t clz(uint32_t x) { - unsigned long r = 0; - _BitScanReverse(&r, x); - - assert(x != 0); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. -# pragma warning(suppress: 6102) - return 31 - r; -} -# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) - -// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning -# if defined(_WIN64) && !defined(__clang__) -# pragma intrinsic(_BitScanReverse64) -# endif - -inline uint32_t clzll(uint64_t x) { - unsigned long r = 0; -# ifdef _WIN64 - _BitScanReverse64(&r, x); -# else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) - return 63 - (r + 32); - - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x)); -# endif - - assert(x != 0); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. -# pragma warning(suppress: 6102) - return 63 - r; -} -# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) -} -} -#endif - -namespace fmt { -namespace internal { -struct DummyInt { - int data[2]; - operator int() const { return 0; } -}; -typedef std::numeric_limits FPUtil; - -// Dummy implementations of system functions such as signbit and ecvt called -// if the latter are not available. -inline DummyInt signbit(...) { return DummyInt(); } -inline DummyInt _ecvt_s(...) { return DummyInt(); } -inline DummyInt isinf(...) { return DummyInt(); } -inline DummyInt _finite(...) { return DummyInt(); } -inline DummyInt isnan(...) { return DummyInt(); } -inline DummyInt _isnan(...) { return DummyInt(); } - -// A helper function to suppress bogus "conditional expression is constant" -// warnings. -template -inline T const_check(T value) { return value; } -} -} // namespace fmt - -namespace std { -// Standard permits specialization of std::numeric_limits. This specialization -// is used to resolve ambiguity between isinf and std::isinf in glibc: -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 -// and the same for isnan and signbit. -template <> -class numeric_limits : - public std::numeric_limits { - public: - // Portable version of isinf. - template - static bool isinfinity(T x) { - using namespace fmt::internal; - // The resolution "priority" is: - // isinf macro > std::isinf > ::isinf > fmt::internal::isinf - if (const_check(sizeof(isinf(x)) == sizeof(bool) || - sizeof(isinf(x)) == sizeof(int))) { - return isinf(x) != 0; - } - return !_finite(static_cast(x)); - } - - // Portable version of isnan. - template - static bool isnotanumber(T x) { - using namespace fmt::internal; - if (const_check(sizeof(isnan(x)) == sizeof(bool) || - sizeof(isnan(x)) == sizeof(int))) { - return isnan(x) != 0; - } - return _isnan(static_cast(x)) != 0; - } - - // Portable version of signbit. - static bool isnegative(double x) { - using namespace fmt::internal; - if (const_check(sizeof(signbit(x)) == sizeof(bool) || - sizeof(signbit(x)) == sizeof(int))) { - return signbit(x) != 0; - } - if (x < 0) return true; - if (!isnotanumber(x)) return false; - int dec = 0, sign = 0; - char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. - _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); - return sign != 0; - } -}; -} // namespace std - -namespace fmt { - -// Fix the warning about long long on older versions of GCC -// that don't support the diagnostic pragma. -FMT_GCC_EXTENSION typedef long long LongLong; -FMT_GCC_EXTENSION typedef unsigned long long ULongLong; - -#if FMT_USE_RVALUE_REFERENCES -using std::move; -#endif - -template -class BasicWriter; - -typedef BasicWriter Writer; -typedef BasicWriter WWriter; - -template -class ArgFormatter; - -struct FormatSpec; - -template -class BasicPrintfArgFormatter; - -template > -class BasicFormatter; - -/** - \rst - A string reference. It can be constructed from a C string or - ``std::basic_string``. - - You can use one of the following typedefs for common character types: - - +------------+-------------------------+ - | Type | Definition | - +============+=========================+ - | StringRef | BasicStringRef | - +------------+-------------------------+ - | WStringRef | BasicStringRef | - +------------+-------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(StringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class BasicStringRef { - private: - const Char *data_; - std::size_t size_; - - public: - /** Constructs a string reference object from a C string and a size. */ - BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} - - /** - \rst - Constructs a string reference object from a C string computing - the size with ``std::char_traits::length``. - \endrst - */ - BasicStringRef(const Char *s) - : data_(s), size_(std::char_traits::length(s)) {} - - /** - \rst - Constructs a string reference from a ``std::basic_string`` object. - \endrst - */ - template - BasicStringRef( - const std::basic_string, Allocator> &s) - : data_(s.c_str()), size_(s.size()) {} - -#if FMT_HAS_STRING_VIEW - /** - \rst - Constructs a string reference from a ``std::basic_string_view`` object. - \endrst - */ - BasicStringRef( - const std::basic_string_view> &s) - : data_(s.data()), size_(s.size()) {} - - /** - \rst - Converts a string reference to an ``std::string_view`` object. - \endrst - */ - explicit operator std::basic_string_view() const FMT_NOEXCEPT { - return std::basic_string_view(data_, size_); - } -#endif - - /** - \rst - Converts a string reference to an ``std::string`` object. - \endrst - */ - std::basic_string to_string() const { - return std::basic_string(data_, size_); - } - - /** Returns a pointer to the string data. */ - const Char *data() const { return data_; } - - /** Returns the string size. */ - std::size_t size() const { return size_; } - - // Lexicographically compare this string reference to other. - int compare(BasicStringRef other) const { - std::size_t size = size_ < other.size_ ? size_ : other.size_; - int result = std::char_traits::compare(data_, other.data_, size); - if (result == 0) - result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); - return result; - } - - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) == 0; - } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) != 0; - } - friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) < 0; - } - friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) <= 0; - } - friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) > 0; - } - friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) >= 0; - } -}; - -typedef BasicStringRef StringRef; -typedef BasicStringRef WStringRef; - -/** - \rst - A reference to a null terminated string. It can be constructed from a C - string or ``std::basic_string``. - - You can use one of the following typedefs for common character types: - - +-------------+--------------------------+ - | Type | Definition | - +=============+==========================+ - | CStringRef | BasicCStringRef | - +-------------+--------------------------+ - | WCStringRef | BasicCStringRef | - +-------------+--------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(CStringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class BasicCStringRef { - private: - const Char *data_; - - public: - /** Constructs a string reference object from a C string. */ - BasicCStringRef(const Char *s) : data_(s) {} - - /** - \rst - Constructs a string reference from a ``std::basic_string`` object. - \endrst - */ - template - BasicCStringRef( - const std::basic_string, Allocator> &s) - : data_(s.c_str()) {} - - /** Returns the pointer to a C string. */ - const Char *c_str() const { return data_; } -}; - -typedef BasicCStringRef CStringRef; -typedef BasicCStringRef WCStringRef; - -/** A formatting error such as invalid format string. */ -class FormatError : public std::runtime_error { - public: - explicit FormatError(CStringRef message) - : std::runtime_error(message.c_str()) {} - FormatError(const FormatError &ferr) : std::runtime_error(ferr) {} - FMT_API ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; -}; - -namespace internal { - -// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. -template -struct MakeUnsigned { typedef T Type; }; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct MakeUnsigned { typedef U Type; } - -FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); -FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); -FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); - -// Casts nonnegative integer to unsigned. -template -inline typename MakeUnsigned::Type to_unsigned(Int value) { - FMT_ASSERT(value >= 0, "negative value"); - return static_cast::Type>(value); -} - -// The number of characters to store in the MemoryBuffer object itself -// to avoid dynamic memory allocation. -enum { INLINE_BUFFER_SIZE = 500 }; - -#if FMT_SECURE_SCL -// Use checked iterator to avoid warnings on MSVC. -template -inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { - return stdext::checked_array_iterator(ptr, size); -} -#else -template -inline T *make_ptr(T *ptr, std::size_t) { return ptr; } -#endif -} // namespace internal - -/** - \rst - A buffer supporting a subset of ``std::vector``'s operations. - \endrst - */ -template -class Buffer { - private: - FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); - - protected: - T *ptr_; - std::size_t size_; - std::size_t capacity_; - - Buffer(T *ptr = FMT_NULL, std::size_t capacity = 0) - : ptr_(ptr), size_(0), capacity_(capacity) {} - - /** - \rst - Increases the buffer capacity to hold at least *size* elements updating - ``ptr_`` and ``capacity_``. - \endrst - */ - virtual void grow(std::size_t size) = 0; - - public: - virtual ~Buffer() {} - - /** Returns the size of this buffer. */ - std::size_t size() const { return size_; } - - /** Returns the capacity of this buffer. */ - std::size_t capacity() const { return capacity_; } - - /** - Resizes the buffer. If T is a POD type new elements may not be initialized. - */ - void resize(std::size_t new_size) { - if (new_size > capacity_) - grow(new_size); - size_ = new_size; - } - - /** - \rst - Reserves space to store at least *capacity* elements. - \endrst - */ - void reserve(std::size_t capacity) { - if (capacity > capacity_) - grow(capacity); - } - - void clear() FMT_NOEXCEPT { size_ = 0; } - - void push_back(const T &value) { - if (size_ == capacity_) - grow(size_ + 1); - ptr_[size_++] = value; - } - - /** Appends data to the end of the buffer. */ - template - void append(const U *begin, const U *end); - - T &operator[](std::size_t index) { return ptr_[index]; } - const T &operator[](std::size_t index) const { return ptr_[index]; } -}; - -template -template -void Buffer::append(const U *begin, const U *end) { - FMT_ASSERT(end >= begin, "negative value"); - std::size_t new_size = size_ + static_cast(end - begin); - if (new_size > capacity_) - grow(new_size); - std::uninitialized_copy(begin, end, - internal::make_ptr(ptr_, capacity_) + size_); - size_ = new_size; -} - -namespace internal { - -// A memory buffer for trivially copyable/constructible types with the first -// SIZE elements stored in the object itself. -template > -class MemoryBuffer : private Allocator, public Buffer { - private: - T data_[SIZE]; - - // Deallocate memory allocated by the buffer. - void deallocate() { - if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_); - } - - protected: - void grow(std::size_t size) FMT_OVERRIDE; - - public: - explicit MemoryBuffer(const Allocator &alloc = Allocator()) - : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() FMT_OVERRIDE { deallocate(); } - -#if FMT_USE_RVALUE_REFERENCES - private: - // Move data from other to this buffer. - void move(MemoryBuffer &other) { - Allocator &this_alloc = *this, &other_alloc = other; - this_alloc = std::move(other_alloc); - this->size_ = other.size_; - this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { - this->ptr_ = data_; - std::uninitialized_copy(other.data_, other.data_ + this->size_, - make_ptr(data_, this->capacity_)); - } else { - this->ptr_ = other.ptr_; - // Set pointer to the inline array so that delete is not called - // when deallocating. - other.ptr_ = other.data_; - } - } - - public: - MemoryBuffer(MemoryBuffer &&other) { - move(other); - } - - MemoryBuffer &operator=(MemoryBuffer &&other) { - assert(this != &other); - deallocate(); - move(other); - return *this; - } -#endif - - // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const { return *this; } -}; - -template -void MemoryBuffer::grow(std::size_t size) { - std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; - if (size > new_capacity) - new_capacity = size; -#if FMT_USE_ALLOCATOR_TRAITS - T *new_ptr = - std::allocator_traits::allocate(*this, new_capacity, FMT_NULL); -#else - T *new_ptr = this->allocate(new_capacity, FMT_NULL); -#endif - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, - make_ptr(new_ptr, new_capacity)); - std::size_t old_capacity = this->capacity_; - T *old_ptr = this->ptr_; - this->capacity_ = new_capacity; - this->ptr_ = new_ptr; - // deallocate may throw (at least in principle), but it doesn't matter since - // the buffer already uses the new storage and will deallocate it in case - // of exception. - if (old_ptr != data_) - Allocator::deallocate(old_ptr, old_capacity); -} - -// A fixed-size buffer. -template -class FixedBuffer : public fmt::Buffer { - public: - FixedBuffer(Char *array, std::size_t size) : fmt::Buffer(array, size) {} - - protected: - FMT_API void grow(std::size_t size) FMT_OVERRIDE; -}; - -template -class BasicCharTraits { - public: -#if FMT_SECURE_SCL - typedef stdext::checked_array_iterator CharPtr; -#else - typedef Char *CharPtr; -#endif - static Char cast(int value) { return static_cast(value); } -}; - -template -class CharTraits; - -template <> -class CharTraits : public BasicCharTraits { - private: - // Conversion from wchar_t to char is not allowed. - static char convert(wchar_t); - - public: - static char convert(char value) { return value; } - - // Formats a floating-point number. - template - FMT_API static int format_float(char *buffer, std::size_t size, - const char *format, unsigned width, int precision, T value); -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template int CharTraits::format_float - (char *buffer, std::size_t size, - const char* format, unsigned width, int precision, double value); -extern template int CharTraits::format_float - (char *buffer, std::size_t size, - const char* format, unsigned width, int precision, long double value); -#endif - -template <> -class CharTraits : public BasicCharTraits { - public: - static wchar_t convert(char value) { return value; } - static wchar_t convert(wchar_t value) { return value; } - - template - FMT_API static int format_float(wchar_t *buffer, std::size_t size, - const wchar_t *format, unsigned width, int precision, T value); -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template int CharTraits::format_float - (wchar_t *buffer, std::size_t size, - const wchar_t* format, unsigned width, int precision, double value); -extern template int CharTraits::format_float - (wchar_t *buffer, std::size_t size, - const wchar_t* format, unsigned width, int precision, long double value); -#endif - -// Checks if a number is negative - used to avoid warnings. -template -struct SignChecker { - template - static bool is_negative(T value) { return value < 0; } -}; - -template <> -struct SignChecker { - template - static bool is_negative(T) { return false; } -}; - -// Returns true if value is negative, false otherwise. -// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. -template -inline bool is_negative(T value) { - return SignChecker::is_signed>::is_negative(value); -} - -// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. -template -struct TypeSelector { typedef uint32_t Type; }; - -template <> -struct TypeSelector { typedef uint64_t Type; }; - -template -struct IntTraits { - // Smallest of uint32_t and uint64_t that is large enough to represent - // all values of T. - typedef typename - TypeSelector::digits <= 32>::Type MainType; -}; - -FMT_API FMT_NORETURN void report_unknown_type(char code, const char *type); - -// Static data is placed in this class template to allow header-only -// configuration. -template -struct FMT_API BasicData { - static const uint32_t POWERS_OF_10_32[]; - static const uint64_t POWERS_OF_10_64[]; - static const char DIGITS[]; -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template struct BasicData; -#endif - -typedef BasicData<> Data; - -#ifdef FMT_BUILTIN_CLZLL -// Returns the number of decimal digits in n. Leading zeros are not counted -// except for n == 0 in which case count_digits returns 1. -inline unsigned count_digits(uint64_t n) { - // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 - // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. - int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; -} -#else -// Fallback version of count_digits used when __builtin_clz is not available. -inline unsigned count_digits(uint64_t n) { - unsigned count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - if (n < 10000) return count + 3; - n /= 10000u; - count += 4; - } -} -#endif - -#ifdef FMT_BUILTIN_CLZ -// Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned count_digits(uint32_t n) { - int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; -} -#endif - -// A functor that doesn't add a thousands separator. -struct NoThousandsSep { - template - void operator()(Char *) {} -}; - -// A functor that adds a thousands separator. -class ThousandsSep { - private: - fmt::StringRef sep_; - - // Index of a decimal digit with the least significant digit having index 0. - unsigned digit_index_; - - public: - explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {} - - template - void operator()(Char *&buffer) { - if (++digit_index_ % 3 != 0) - return; - buffer -= sep_.size(); - std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), - internal::make_ptr(buffer, sep_.size())); - } -}; - -// Formats a decimal unsigned integer value writing into buffer. -// thousands_sep is a functor that is called after writing each char to -// add a thousands separator if necessary. -template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, - ThousandsSep thousands_sep) { - buffer += num_digits; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = static_cast((value % 100) * 2); - value /= 100; - *--buffer = Data::DIGITS[index + 1]; - thousands_sep(buffer); - *--buffer = Data::DIGITS[index]; - thousands_sep(buffer); - } - if (value < 10) { - *--buffer = static_cast('0' + value); - return; - } - unsigned index = static_cast(value * 2); - *--buffer = Data::DIGITS[index + 1]; - thousands_sep(buffer); - *--buffer = Data::DIGITS[index]; -} - -template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { - format_decimal(buffer, value, num_digits, NoThousandsSep()); - return; -} - -#ifndef _WIN32 -# define FMT_USE_WINDOWS_H 0 -#elif !defined(FMT_USE_WINDOWS_H) -# define FMT_USE_WINDOWS_H 1 -#endif - -// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. -// All the functionality that relies on it will be disabled too. -#if FMT_USE_WINDOWS_H -// A converter from UTF-8 to UTF-16. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { - private: - MemoryBuffer buffer_; - - public: - FMT_API explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const { return WStringRef(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const wchar_t *c_str() const { return &buffer_[0]; } - std::wstring str() const { return std::wstring(&buffer_[0], size()); } -}; - -// A converter from UTF-16 to UTF-8. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 { - private: - MemoryBuffer buffer_; - - public: - UTF16ToUTF8() {} - FMT_API explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const { return StringRef(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const char *c_str() const { return &buffer_[0]; } - std::string str() const { return std::string(&buffer_[0], size()); } - - // Performs conversion returning a system error code instead of - // throwing exception on conversion error. This method may still throw - // in case of memory allocation error. - FMT_API int convert(WStringRef s); -}; - -FMT_API void format_windows_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; -#endif - -// A formatting argument value. -struct Value { - template - struct StringValue { - const Char *value; - std::size_t size; - }; - - typedef void (*FormatFunc)( - void *formatter, const void *arg, void *format_str_ptr); - - struct CustomValue { - const void *value; - FormatFunc format; - }; - - union { - int int_value; - unsigned uint_value; - LongLong long_long_value; - ULongLong ulong_long_value; - double double_value; - long double long_double_value; - const void *pointer; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue wstring; - CustomValue custom; - }; - - enum Type { - NONE, NAMED_ARG, - // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, STRING, WSTRING, POINTER, CUSTOM - }; -}; - -// A formatting argument. It is a trivially copyable/constructible type to -// allow storage in internal::MemoryBuffer. -struct Arg : Value { - Type type; -}; - -template -struct NamedArg; -template -struct NamedArgWithType; - -template -struct Null {}; - -// A helper class template to enable or disable overloads taking wide -// characters and strings in MakeValue. -template -struct WCharHelper { - typedef Null Supported; - typedef T Unsupported; -}; - -template -struct WCharHelper { - typedef T Supported; - typedef Null Unsupported; -}; - -typedef char Yes[1]; -typedef char No[2]; - -template -T &get(); - -// These are non-members to workaround an overload resolution bug in bcc32. -Yes &convert(fmt::ULongLong); -No &convert(...); - -template -struct ConvertToIntImpl { - enum { value = ENABLE_CONVERSION }; -}; - -template -struct ConvertToIntImpl2 { - enum { value = false }; -}; - -template -struct ConvertToIntImpl2 { - enum { - // Don't convert numeric types. - value = ConvertToIntImpl::is_specialized>::value - }; -}; - -template -struct ConvertToInt { - enum { - enable_conversion = sizeof(fmt::internal::convert(get())) == sizeof(Yes) - }; - enum { value = ConvertToIntImpl2::value }; -}; - -#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ - template <> \ - struct ConvertToInt { enum { value = 0 }; } - -// Silence warnings about convering float to int. -FMT_DISABLE_CONVERSION_TO_INT(float); -FMT_DISABLE_CONVERSION_TO_INT(double); -FMT_DISABLE_CONVERSION_TO_INT(long double); - -template -struct EnableIf {}; - -template -struct EnableIf { typedef T type; }; - -template -struct Conditional { typedef T type; }; - -template -struct Conditional { typedef F type; }; - -// For bcc32 which doesn't understand ! in template arguments. -template -struct Not { enum { value = 0 }; }; - -template <> -struct Not { enum { value = 1 }; }; - -template -struct FalseType { enum { value = 0 }; }; - -template struct LConvCheck { - LConvCheck(int) {} -}; - -// Returns the thousands separator for the current locale. -// We check if ``lconv`` contains ``thousands_sep`` because on Android -// ``lconv`` is stubbed as an empty struct. -template -inline StringRef thousands_sep( - LConv *lc, LConvCheck = 0) { - return lc->thousands_sep; -} - -inline fmt::StringRef thousands_sep(...) { return ""; } - -#define FMT_CONCAT(a, b) a##b - -#if FMT_GCC_VERSION >= 303 -# define FMT_UNUSED __attribute__((unused)) -#else -# define FMT_UNUSED -#endif - -#ifndef FMT_USE_STATIC_ASSERT -# define FMT_USE_STATIC_ASSERT 0 -#endif - -#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 -# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) -#else -# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) -# define FMT_STATIC_ASSERT(cond, message) \ - typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED -#endif - -template -void format_arg(Formatter&, ...) { - FMT_STATIC_ASSERT(FalseType::value, - "Cannot format argument. To enable the use of ostream " - "operator<< include fmt/ostream.h. Otherwise provide " - "an overload of format_arg."); -} - -// Makes an Arg object from any type. -template -class MakeValue : public Arg { - public: - typedef typename Formatter::Char Char; - - private: - // The following two methods are private to disallow formatting of - // arbitrary pointers. If you want to output a pointer cast it to - // "void *" or "const void *". In particular, this forbids formatting - // of "[const] volatile char *" which is printed as bool by iostreams. - // Do not implement! - template - MakeValue(const T *value); - template - MakeValue(T *value); - - // The following methods are private to disallow formatting of wide - // characters and strings into narrow strings as in - // fmt::format("{}", L"test"); - // To fix this, use a wide format string: fmt::format(L"{}", L"test"). -#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Unsupported); -#endif - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); -#if FMT_HAS_STRING_VIEW - MakeValue(typename WCharHelper::Unsupported); -#endif - MakeValue(typename WCharHelper::Unsupported); - - void set_string(StringRef str) { - string.value = str.data(); - string.size = str.size(); - } - - void set_string(WStringRef str) { - wstring.value = str.data(); - wstring.size = str.size(); - } - - // Formats an argument of a custom type, such as a user-defined class. - template - static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) { - format_arg(*static_cast(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); - } - - public: - MakeValue() {} - -#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - MakeValue(Type value) { field = rhs; } \ - static uint64_t type(Type) { return Arg::TYPE; } - -#define FMT_MAKE_VALUE(Type, field, TYPE) \ - FMT_MAKE_VALUE_(Type, field, TYPE, value) - - FMT_MAKE_VALUE(bool, int_value, BOOL) - FMT_MAKE_VALUE(short, int_value, INT) - FMT_MAKE_VALUE(unsigned short, uint_value, UINT) - FMT_MAKE_VALUE(int, int_value, INT) - FMT_MAKE_VALUE(unsigned, uint_value, UINT) - - MakeValue(long value) { - // To minimize the number of types we need to deal with, long is - // translated either to int or to long long depending on its size. - if (const_check(sizeof(long) == sizeof(int))) - int_value = static_cast(value); - else - long_long_value = value; - } - static uint64_t type(long) { - return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; - } - - MakeValue(unsigned long value) { - if (const_check(sizeof(unsigned long) == sizeof(unsigned))) - uint_value = static_cast(value); - else - ulong_long_value = value; - } - static uint64_t type(unsigned long) { - return sizeof(unsigned long) == sizeof(unsigned) ? - Arg::UINT : Arg::ULONG_LONG; - } - - FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) - FMT_MAKE_VALUE(float, double_value, DOUBLE) - FMT_MAKE_VALUE(double, double_value, DOUBLE) - FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) - FMT_MAKE_VALUE(signed char, int_value, INT) - FMT_MAKE_VALUE(unsigned char, uint_value, UINT) - FMT_MAKE_VALUE(char, int_value, CHAR) - -#if __cplusplus >= 201103L - template < - typename T, - typename = typename std::enable_if< - std::is_enum::value && ConvertToInt::value>::type> - MakeValue(T value) { int_value = value; } - - template < - typename T, - typename = typename std::enable_if< - std::is_enum::value && ConvertToInt::value>::type> - static uint64_t type(T) { return Arg::INT; } -#endif - -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Supported value) { - int_value = value; - } - static uint64_t type(wchar_t) { return Arg::CHAR; } -#endif - -#define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_VALUE(char *, string.value, CSTRING) - FMT_MAKE_VALUE(const char *, string.value, CSTRING) - FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) - FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) - FMT_MAKE_STR_VALUE(const std::string &, STRING) -#if FMT_HAS_STRING_VIEW - FMT_MAKE_STR_VALUE(const std::string_view &, STRING) -#endif - FMT_MAKE_STR_VALUE(StringRef, STRING) - FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) - -#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - MakeValue(typename WCharHelper::Supported value) { \ - set_string(value); \ - } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) -#if FMT_HAS_STRING_VIEW - FMT_MAKE_WSTR_VALUE(const std::wstring_view &, WSTRING) -#endif - FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) - - FMT_MAKE_VALUE(void *, pointer, POINTER) - FMT_MAKE_VALUE(const void *, pointer, POINTER) - - template - MakeValue(const T &value, - typename EnableIf::value>::value, int>::type = 0) { - custom.value = &value; - custom.format = &format_custom_arg; - } - - template - static typename EnableIf::value>::value, uint64_t>::type - type(const T &) { - return Arg::CUSTOM; - } - - // Additional template param `Char_` is needed here because make_type always - // uses char. - template - MakeValue(const NamedArg &value) { pointer = &value; } - template - MakeValue(const NamedArgWithType &value) { pointer = &value; } - - template - static uint64_t type(const NamedArg &) { return Arg::NAMED_ARG; } - template - static uint64_t type(const NamedArgWithType &) { return Arg::NAMED_ARG; } -}; - -template -class MakeArg : public Arg { -public: - MakeArg() { - type = Arg::NONE; - } - - template - MakeArg(const T &value) - : Arg(MakeValue(value)) { - type = static_cast(MakeValue::type(value)); - } -}; - -template -struct NamedArg : Arg { - BasicStringRef name; - - template - NamedArg(BasicStringRef argname, const T &value) - : Arg(MakeArg< BasicFormatter >(value)), name(argname) {} -}; - -template -struct NamedArgWithType : NamedArg { - NamedArgWithType(BasicStringRef argname, const T &value) - : NamedArg(argname, value) {} -}; - -class RuntimeError : public std::runtime_error { - protected: - RuntimeError() : std::runtime_error("") {} - RuntimeError(const RuntimeError &rerr) : std::runtime_error(rerr) {} - FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; -}; - -template -class ArgMap; -} // namespace internal - -/** An argument list. */ -class ArgList { - private: - // To reduce compiled code size per formatting function call, types of first - // MAX_PACKED_ARGS arguments are passed in the types_ field. - uint64_t types_; - union { - // If the number of arguments is less than MAX_PACKED_ARGS, the argument - // values are stored in values_, otherwise they are stored in args_. - // This is done to reduce compiled code size as storing larger objects - // may require more code (at least on x86-64) even if the same amount of - // data is actually copied to stack. It saves ~10% on the bloat test. - const internal::Value *values_; - const internal::Arg *args_; - }; - - internal::Arg::Type type(unsigned index) const { - return type(types_, index); - } - - template - friend class internal::ArgMap; - - public: - // Maximum number of arguments with packed types. - enum { MAX_PACKED_ARGS = 16 }; - - ArgList() : types_(0) {} - - ArgList(ULongLong types, const internal::Value *values) - : types_(types), values_(values) {} - ArgList(ULongLong types, const internal::Arg *args) - : types_(types), args_(args) {} - - uint64_t types() const { return types_; } - - /** Returns the argument at specified index. */ - internal::Arg operator[](unsigned index) const { - using internal::Arg; - Arg arg; - bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; - if (index < MAX_PACKED_ARGS) { - Arg::Type arg_type = type(index); - internal::Value &val = arg; - if (arg_type != Arg::NONE) - val = use_values ? values_[index] : args_[index]; - arg.type = arg_type; - return arg; - } - if (use_values) { - // The index is greater than the number of arguments that can be stored - // in values, so return a "none" argument. - arg.type = Arg::NONE; - return arg; - } - for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type == Arg::NONE) - return args_[i]; - } - return args_[index]; - } - - static internal::Arg::Type type(uint64_t types, unsigned index) { - unsigned shift = index * 4; - uint64_t mask = 0xf; - return static_cast( - (types & (mask << shift)) >> shift); - } -}; - -#define FMT_DISPATCH(call) static_cast(this)->call - -/** - \rst - An argument visitor based on the `curiously recurring template pattern - `_. - - To use `~fmt::ArgVisitor` define a subclass that implements some or all of the - visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, - for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. Then calling - `~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::ArgVisitor` will be called. - - **Example**:: - - class MyArgVisitor : public fmt::ArgVisitor { - public: - void visit_int(int value) { fmt::print("{}", value); } - void visit_double(double value) { fmt::print("{}", value ); } - }; - \endrst - */ -template -class ArgVisitor { - private: - typedef internal::Arg Arg; - - public: - void report_unhandled_arg() {} - - Result visit_unhandled_arg() { - FMT_DISPATCH(report_unhandled_arg()); - return Result(); - } - - /** Visits an ``int`` argument. **/ - Result visit_int(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``long long`` argument. **/ - Result visit_long_long(LongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an ``unsigned`` argument. **/ - Result visit_uint(unsigned value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an ``unsigned long long`` argument. **/ - Result visit_ulong_long(ULongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``bool`` argument. **/ - Result visit_bool(bool value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``char`` or ``wchar_t`` argument. **/ - Result visit_char(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an argument of any integral type. **/ - template - Result visit_any_int(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a ``double`` argument. **/ - Result visit_double(double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - - /** Visits a ``long double`` argument. **/ - Result visit_long_double(long double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - - /** Visits a ``double`` or ``long double`` argument. **/ - template - Result visit_any_double(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a null-terminated C string (``const char *``) argument. **/ - Result visit_cstring(const char *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a string argument. **/ - Result visit_string(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a wide string argument. **/ - Result visit_wstring(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a pointer argument. **/ - Result visit_pointer(const void *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits an argument of a custom (user-defined) type. **/ - Result visit_custom(Arg::CustomValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** - \rst - Visits an argument dispatching to the appropriate visit method based on - the argument type. For example, if the argument type is ``double`` then - the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be - called. - \endrst - */ - Result visit(const Arg &arg) { - switch (arg.type) { - case Arg::NONE: - case Arg::NAMED_ARG: - FMT_ASSERT(false, "invalid argument type"); - break; - case Arg::INT: - return FMT_DISPATCH(visit_int(arg.int_value)); - case Arg::UINT: - return FMT_DISPATCH(visit_uint(arg.uint_value)); - case Arg::LONG_LONG: - return FMT_DISPATCH(visit_long_long(arg.long_long_value)); - case Arg::ULONG_LONG: - return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); - case Arg::BOOL: - return FMT_DISPATCH(visit_bool(arg.int_value != 0)); - case Arg::CHAR: - return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::DOUBLE: - return FMT_DISPATCH(visit_double(arg.double_value)); - case Arg::LONG_DOUBLE: - return FMT_DISPATCH(visit_long_double(arg.long_double_value)); - case Arg::CSTRING: - return FMT_DISPATCH(visit_cstring(arg.string.value)); - case Arg::STRING: - return FMT_DISPATCH(visit_string(arg.string)); - case Arg::WSTRING: - return FMT_DISPATCH(visit_wstring(arg.wstring)); - case Arg::POINTER: - return FMT_DISPATCH(visit_pointer(arg.pointer)); - case Arg::CUSTOM: - return FMT_DISPATCH(visit_custom(arg.custom)); - } - return Result(); - } -}; - -enum Alignment { - ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC -}; - -// Flags. -enum { - SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, - CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. -}; - -// An empty format specifier. -struct EmptySpec {}; - -// A type specifier. -template -struct TypeSpec : EmptySpec { - Alignment align() const { return ALIGN_DEFAULT; } - unsigned width() const { return 0; } - int precision() const { return -1; } - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } - char type_prefix() const { return TYPE; } - char fill() const { return ' '; } -}; - -// A width specifier. -struct WidthSpec { - unsigned width_; - // Fill is always wchar_t and cast to char if necessary to avoid having - // two specialization of WidthSpec and its subclasses. - wchar_t fill_; - - WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} - - unsigned width() const { return width_; } - wchar_t fill() const { return fill_; } -}; - -// An alignment specifier. -struct AlignSpec : WidthSpec { - Alignment align_; - - AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) - : WidthSpec(width, fill), align_(align) {} - - Alignment align() const { return align_; } - - int precision() const { return -1; } -}; - -// An alignment and type specifier. -template -struct AlignTypeSpec : AlignSpec { - AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } - char type_prefix() const { return TYPE; } -}; - -// A full format specifier. -struct FormatSpec : AlignSpec { - unsigned flags_; - int precision_; - char type_; - - FormatSpec( - unsigned width = 0, char type = 0, wchar_t fill = ' ') - : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} - - bool flag(unsigned f) const { return (flags_ & f) != 0; } - int precision() const { return precision_; } - char type() const { return type_; } - char type_prefix() const { return type_; } -}; - -// An integer format specifier. -template , typename Char = char> -class IntFormatSpec : public SpecT { - private: - T value_; - - public: - IntFormatSpec(T val, const SpecT &spec = SpecT()) - : SpecT(spec), value_(val) {} - - T value() const { return value_; } -}; - -// A string format specifier. -template -class StrFormatSpec : public AlignSpec { - private: - const Char *str_; - - public: - template - StrFormatSpec(const Char *str, unsigned width, FillChar fill) - : AlignSpec(width, fill), str_(str) { - internal::CharTraits::convert(FillChar()); - } - - const Char *str() const { return str_; } -}; - -/** - Returns an integer format specifier to format the value in base 2. - */ -IntFormatSpec > bin(int value); - -/** - Returns an integer format specifier to format the value in base 8. - */ -IntFormatSpec > oct(int value); - -/** - Returns an integer format specifier to format the value in base 16 using - lower-case letters for the digits above 9. - */ -IntFormatSpec > hex(int value); - -/** - Returns an integer formatter format specifier to format in base 16 using - upper-case letters for the digits above 9. - */ -IntFormatSpec > hexu(int value); - -/** - \rst - Returns an integer format specifier to pad the formatted argument with the - fill character to the specified width using the default (right) numeric - alignment. - - **Example**:: - - MemoryWriter out; - out << pad(hex(0xcafe), 8, '0'); - // out.str() == "0000cafe" - - \endrst - */ -template -IntFormatSpec, Char> pad( - int value, unsigned width, Char fill = ' '); - -#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ -inline IntFormatSpec > bin(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'b'>()); \ -} \ - \ -inline IntFormatSpec > oct(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'o'>()); \ -} \ - \ -inline IntFormatSpec > hex(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'x'>()); \ -} \ - \ -inline IntFormatSpec > hexu(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'X'>()); \ -} \ - \ -template \ -inline IntFormatSpec > pad( \ - IntFormatSpec > f, unsigned width) { \ - return IntFormatSpec >( \ - f.value(), AlignTypeSpec(width, ' ')); \ -} \ - \ -/* For compatibility with older compilers we provide two overloads for pad, */ \ -/* one that takes a fill character and one that doesn't. In the future this */ \ -/* can be replaced with one overload making the template argument Char */ \ -/* default to char (C++11). */ \ -template \ -inline IntFormatSpec, Char> pad( \ - IntFormatSpec, Char> f, \ - unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - f.value(), AlignTypeSpec(width, fill)); \ -} \ - \ -inline IntFormatSpec > pad( \ - TYPE value, unsigned width) { \ - return IntFormatSpec >( \ - value, AlignTypeSpec<0>(width, ' ')); \ -} \ - \ -template \ -inline IntFormatSpec, Char> pad( \ - TYPE value, unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - value, AlignTypeSpec<0>(width, fill)); \ -} - -FMT_DEFINE_INT_FORMATTERS(int) -FMT_DEFINE_INT_FORMATTERS(long) -FMT_DEFINE_INT_FORMATTERS(unsigned) -FMT_DEFINE_INT_FORMATTERS(unsigned long) -FMT_DEFINE_INT_FORMATTERS(LongLong) -FMT_DEFINE_INT_FORMATTERS(ULongLong) - -/** - \rst - Returns a string formatter that pads the formatted argument with the fill - character to the specified width using the default (left) string alignment. - - **Example**:: - - std::string s = str(MemoryWriter() << pad("abc", 8)); - // s == "abc " - - \endrst - */ -template -inline StrFormatSpec pad( - const Char *str, unsigned width, Char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -inline StrFormatSpec pad( - const wchar_t *str, unsigned width, char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -namespace internal { - -template -class ArgMap { - private: - typedef std::vector< - std::pair, internal::Arg> > MapType; - typedef typename MapType::value_type Pair; - - MapType map_; - - public: - void init(const ArgList &args); - - const internal::Arg *find(const fmt::BasicStringRef &name) const { - // The list is unsorted, so just return the first matching name. - for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); - it != end; ++it) { - if (it->first == name) - return &it->second; - } - return FMT_NULL; - } -}; - -template -void ArgMap::init(const ArgList &args) { - if (!map_.empty()) - return; - typedef internal::NamedArg NamedArg; - const NamedArg *named_arg = FMT_NULL; - bool use_values = - args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; - if (use_values) { - for (unsigned i = 0;/*nothing*/; ++i) { - internal::Arg::Type arg_type = args.type(i); - switch (arg_type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.values_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } - return; - } - for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { - internal::Arg::Type arg_type = args.type(i); - if (arg_type == internal::Arg::NAMED_ARG) { - named_arg = static_cast(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - } - } - for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { - switch (args.args_[i].type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } -} - -template -class ArgFormatterBase : public ArgVisitor { - private: - BasicWriter &writer_; - Spec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); - - void write_pointer(const void *p) { - spec_.flags_ = HASH_FLAG; - spec_.type_ = 'x'; - writer_.write_int(reinterpret_cast(p), spec_); - } - - // workaround MSVC two-phase lookup issue - typedef internal::Arg Arg; - - protected: - BasicWriter &writer() { return writer_; } - Spec &spec() { return spec_; } - - void write(bool value) { - const char *str_value = value ? "true" : "false"; - Arg::StringValue str = { str_value, std::strlen(str_value) }; - writer_.write_str(str, spec_); - } - - void write(const char *value) { - Arg::StringValue str = {value, value ? std::strlen(value) : 0}; - writer_.write_str(str, spec_); - } - - public: - typedef Spec SpecType; - - ArgFormatterBase(BasicWriter &w, Spec &s) - : writer_(w), spec_(s) {} - - template - void visit_any_int(T value) { writer_.write_int(value, spec_); } - - template - void visit_any_double(T value) { writer_.write_double(value, spec_); } - - void visit_bool(bool value) { - if (spec_.type_) { - visit_any_int(value); - return; - } - write(value); - } - - void visit_char(int value) { - if (spec_.type_ && spec_.type_ != 'c') { - spec_.flags_ |= CHAR_FLAG; - writer_.write_int(value, spec_); - return; - } - if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) - FMT_THROW(FormatError("invalid format specifier for char")); - typedef typename BasicWriter::CharPtr CharPtr; - Char fill = internal::CharTraits::cast(spec_.fill()); - CharPtr out = CharPtr(); - const unsigned CHAR_SIZE = 1; - if (spec_.width_ > CHAR_SIZE) { - out = writer_.grow_buffer(spec_.width_); - if (spec_.align_ == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec_.width_ - CHAR_SIZE, fill); - out += spec_.width_ - CHAR_SIZE; - } else if (spec_.align_ == ALIGN_CENTER) { - out = writer_.fill_padding(out, spec_.width_, - internal::const_check(CHAR_SIZE), fill); - } else { - std::uninitialized_fill_n(out + CHAR_SIZE, - spec_.width_ - CHAR_SIZE, fill); - } - } else { - out = writer_.grow_buffer(CHAR_SIZE); - } - *out = internal::CharTraits::cast(value); - } - - void visit_cstring(const char *value) { - if (spec_.type_ == 'p') - return write_pointer(value); - write(value); - } - - // Qualification with "internal" here and below is a workaround for nvcc. - void visit_string(internal::Arg::StringValue value) { - writer_.write_str(value, spec_); - } - - using ArgVisitor::visit_wstring; - - void visit_wstring(internal::Arg::StringValue value) { - writer_.write_str(value, spec_); - } - - void visit_pointer(const void *value) { - if (spec_.type_ && spec_.type_ != 'p') - report_unknown_type(spec_.type_, "pointer"); - write_pointer(value); - } -}; - -class FormatterBase { - private: - ArgList args_; - int next_arg_index_; - - // Returns the argument with specified index. - FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); - - protected: - const ArgList &args() const { return args_; } - - explicit FormatterBase(const ArgList &args) { - args_ = args; - next_arg_index_ = 0; - } - - // Returns the next argument. - Arg next_arg(const char *&error) { - if (next_arg_index_ >= 0) - return do_get_arg(internal::to_unsigned(next_arg_index_++), error); - error = "cannot switch from manual to automatic argument indexing"; - return Arg(); - } - - // Checks if manual indexing is used and returns the argument with - // specified index. - Arg get_arg(unsigned arg_index, const char *&error) { - return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); - } - - bool check_no_auto_index(const char *&error) { - if (next_arg_index_ > 0) { - error = "cannot switch from automatic to manual argument indexing"; - return false; - } - next_arg_index_ = -1; - return true; - } - - template - void write(BasicWriter &w, const Char *start, const Char *end) { - if (start != end) - w << BasicStringRef(start, internal::to_unsigned(end - start)); - } -}; -} // namespace internal - -/** - \rst - An argument formatter based on the `curiously recurring template pattern - `_. - - To use `~fmt::BasicArgFormatter` define a subclass that implements some or - all of the visit methods with the same signatures as the methods in - `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. When a formatting - function processes an argument, it will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::BasicArgFormatter` or its superclass - will be called. - \endrst - */ -template -class BasicArgFormatter : public internal::ArgFormatterBase { - private: - BasicFormatter &formatter_; - const Char *format_; - - public: - /** - \rst - Constructs an argument formatter object. - *formatter* is a reference to the main formatter object, *spec* contains - format specifier information for standard argument types, and *fmt* points - to the part of the format string being parsed for custom argument types. - \endrst - */ - BasicArgFormatter(BasicFormatter &formatter, - Spec &spec, const Char *fmt) - : internal::ArgFormatterBase(formatter.writer(), spec), - formatter_(formatter), format_(fmt) {} - - /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); - } -}; - -/** The default argument formatter. */ -template -class ArgFormatter : - public BasicArgFormatter, Char, FormatSpec> { - public: - /** Constructs an argument formatter object. */ - ArgFormatter(BasicFormatter &formatter, - FormatSpec &spec, const Char *fmt) - : BasicArgFormatter, - Char, FormatSpec>(formatter, spec, fmt) {} -}; - -/** This template formats data and writes the output to a writer. */ -template -class BasicFormatter : private internal::FormatterBase { - public: - /** The character type for the output. */ - typedef CharType Char; - - private: - BasicWriter &writer_; - internal::ArgMap map_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); - - using internal::FormatterBase::get_arg; - - // Checks if manual indexing is used and returns the argument with - // specified name. - internal::Arg get_arg(BasicStringRef arg_name, const char *&error); - - // Parses argument index and returns corresponding argument. - internal::Arg parse_arg_index(const Char *&s); - - // Parses argument name and returns corresponding argument. - internal::Arg parse_arg_name(const Char *&s); - - public: - /** - \rst - Constructs a ``BasicFormatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have - appropriate lifetimes. - \endrst - */ - BasicFormatter(const ArgList &args, BasicWriter &w) - : internal::FormatterBase(args), writer_(w) {} - - /** Returns a reference to the writer associated with this formatter. */ - BasicWriter &writer() { return writer_; } - - /** Formats stored arguments and writes the output to the writer. */ - void format(BasicCStringRef format_str); - - // Formats a single argument and advances format_str, a format string pointer. - const Char *format(const Char *&format_str, const internal::Arg &arg); -}; - -// Generates a comma-separated list with results of applying f to -// numbers 0..n-1. -# define FMT_GEN(n, f) FMT_GEN##n(f) -# define FMT_GEN1(f) f(0) -# define FMT_GEN2(f) FMT_GEN1(f), f(1) -# define FMT_GEN3(f) FMT_GEN2(f), f(2) -# define FMT_GEN4(f) FMT_GEN3(f), f(3) -# define FMT_GEN5(f) FMT_GEN4(f), f(4) -# define FMT_GEN6(f) FMT_GEN5(f), f(5) -# define FMT_GEN7(f) FMT_GEN6(f), f(6) -# define FMT_GEN8(f) FMT_GEN7(f), f(7) -# define FMT_GEN9(f) FMT_GEN8(f), f(8) -# define FMT_GEN10(f) FMT_GEN9(f), f(9) -# define FMT_GEN11(f) FMT_GEN10(f), f(10) -# define FMT_GEN12(f) FMT_GEN11(f), f(11) -# define FMT_GEN13(f) FMT_GEN12(f), f(12) -# define FMT_GEN14(f) FMT_GEN13(f), f(13) -# define FMT_GEN15(f) FMT_GEN14(f), f(14) - -namespace internal { -inline uint64_t make_type() { return 0; } - -template -inline uint64_t make_type(const T &arg) { - return MakeValue< BasicFormatter >::type(arg); -} - -template -struct ArgArray; - -template -struct ArgArray { - // '+' is used to silence GCC -Wduplicated-branches warning. - typedef Value Type[N > 0 ? N : +1]; - - template - static Value make(const T &value) { -#ifdef __clang__ - Value result = MakeValue(value); - // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: - // https://github.com/fmtlib/fmt/issues/276 - (void)result.custom.format; - return result; -#else - return MakeValue(value); -#endif - } -}; - -template -struct ArgArray { - typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE - - template - static Arg make(const T &value) { return MakeArg(value); } -}; - -#if FMT_USE_VARIADIC_TEMPLATES -template -inline uint64_t make_type(const Arg &first, const Args & ... tail) { - return make_type(first) | (make_type(tail...) << 4); -} - -#else - -struct ArgType { - uint64_t type; - - ArgType() : type(0) {} - - template - ArgType(const T &arg) : type(make_type(arg)) {} -}; - -# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() - -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { - return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | - (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | - (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | - (t12.type << 48) | (t13.type << 52) | (t14.type << 56); -} -#endif -} // namespace internal - -# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n -# define FMT_MAKE_ARG_TYPE(n) T##n -# define FMT_MAKE_ARG(n) const T##n &v##n -# define FMT_ASSIGN_char(n) \ - arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -# define FMT_ASSIGN_wchar_t(n) \ - arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) - -#if FMT_USE_VARIADIC_TEMPLATES -// Defines a variadic function returning void. -# define FMT_VARIADIC_VOID(func, arg_type) \ - template \ - void func(arg_type arg0, const Args & ... args) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ - func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } - -// Defines a variadic constructor. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ - func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } - -#else - -# define FMT_MAKE_REF(n) \ - fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -# define FMT_MAKE_REF2(n) v##n - -// Defines a wrapper for a function taking one argument of type arg_type -// and n additional arguments of arbitrary types. -# define FMT_WRAP1(func, arg_type, n) \ - template \ - inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic function returning void on a pre-C++11 compiler. -# define FMT_VARIADIC_VOID(func, arg_type) \ - inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ - FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ - FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ - FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ - FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ - FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) - -# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg0, arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic constructor on a pre-C++11 compiler. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) -#endif - -// Generates a comma-separated list with results of applying f to pairs -// (argument, index). -#define FMT_FOR_EACH1(f, x0) f(x0, 0) -#define FMT_FOR_EACH2(f, x0, x1) \ - FMT_FOR_EACH1(f, x0), f(x1, 1) -#define FMT_FOR_EACH3(f, x0, x1, x2) \ - FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) -#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ - FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) -#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ - FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) -#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ - FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) -#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ - FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) -#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ - FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) -#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ - FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) -#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ - FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) - -/** - An error returned by an operating system or a language runtime, - for example a file opening error. -*/ -class SystemError : public internal::RuntimeError { - private: - FMT_API void init(int err_code, CStringRef format_str, ArgList args); - - protected: - int error_code_; - - typedef char Char; // For FMT_VARIADIC_CTOR. - - SystemError() {} - - public: - /** - \rst - Constructs a :class:`fmt::SystemError` object with a description - formatted with `fmt::format_system_error`. *message* and additional - arguments passed into the constructor are formatted similarly to - `fmt::format`. - - **Example**:: - - // This throws a SystemError with the description - // cannot open file 'madeup': No such file or directory - // or similar (system message may vary). - const char *filename = "madeup"; - std::FILE *file = std::fopen(filename, "r"); - if (!file) - throw fmt::SystemError(errno, "cannot open file '{}'", filename); - \endrst - */ - SystemError(int error_code, CStringRef message) { - init(error_code, message, ArgList()); - } - FMT_DEFAULTED_COPY_CTOR(SystemError) - FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) - - FMT_API ~SystemError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; - - int error_code() const { return error_code_; } -}; - -/** - \rst - Formats an error returned by an operating system or a language runtime, - for example a file opening error, and writes it to *out* in the following - form: - - .. parsed-literal:: - **: ** - - where ** is the passed message and ** is - the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - If *error_code* is not a valid error code such as -1, the system message - may look like "Unknown error -1" and is platform-dependent. - \endrst - */ -FMT_API void format_system_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; - -/** - \rst - This template provides operations for formatting and writing data into - a character stream. The output is stored in a buffer provided by a subclass - such as :class:`fmt::BasicMemoryWriter`. - - You can use one of the following typedefs for common character types: - - +---------+----------------------+ - | Type | Definition | - +=========+======================+ - | Writer | BasicWriter | - +---------+----------------------+ - | WWriter | BasicWriter | - +---------+----------------------+ - - \endrst - */ -template -class BasicWriter { - private: - // Output buffer. - Buffer &buffer_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); - - typedef typename internal::CharTraits::CharPtr CharPtr; - -#if FMT_SECURE_SCL - // Returns pointer value. - static Char *get(CharPtr p) { return p.base(); } -#else - static Char *get(Char *p) { return p; } -#endif - - // Fills the padding around the content and returns the pointer to the - // content area. - static CharPtr fill_padding(CharPtr buffer, - unsigned total_size, std::size_t content_size, wchar_t fill); - - // Grows the buffer by n characters and returns a pointer to the newly - // allocated area. - CharPtr grow_buffer(std::size_t n) { - std::size_t size = buffer_.size(); - buffer_.resize(size + n); - return internal::make_ptr(&buffer_[size], n); - } - - // Writes an unsigned decimal integer. - template - Char *write_unsigned_decimal(UInt value, unsigned prefix_size = 0) { - unsigned num_digits = internal::count_digits(value); - Char *ptr = get(grow_buffer(prefix_size + num_digits)); - internal::format_decimal(ptr + prefix_size, value, num_digits); - return ptr; - } - - // Writes a decimal integer. - template - void write_decimal(Int value) { - typedef typename internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(value); - if (internal::is_negative(value)) { - abs_value = 0 - abs_value; - *write_unsigned_decimal(abs_value, 1) = '-'; - } else { - write_unsigned_decimal(abs_value, 0); - } - } - - // Prepare a buffer for integer formatting. - CharPtr prepare_int_buffer(unsigned num_digits, - const EmptySpec &, const char *prefix, unsigned prefix_size) { - unsigned size = prefix_size + num_digits; - CharPtr p = grow_buffer(size); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - - template - CharPtr prepare_int_buffer(unsigned num_digits, - const Spec &spec, const char *prefix, unsigned prefix_size); - - // Formats an integer. - template - void write_int(T value, Spec spec); - - // Formats a floating-point number (double or long double). - template - void write_double(T value, const Spec &spec); - - // Writes a formatted string. - template - CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); - - template - void write_str(const internal::Arg::StringValue &str, - const Spec &spec); - - // This following methods are private to disallow writing wide characters - // and strings to a char stream. If you want to print a wide string as a - // pointer as std::ostream does, cast it to const void*. - // Do not implement! - void operator<<(typename internal::WCharHelper::Unsupported); - void operator<<( - typename internal::WCharHelper::Unsupported); - - // Appends floating-point length specifier to the format string. - // The second argument is only used for overload resolution. - void append_float_length(Char *&format_ptr, long double) { - *format_ptr++ = 'L'; - } - - template - void append_float_length(Char *&, T) {} - - template - friend class internal::ArgFormatterBase; - - template - friend class BasicPrintfArgFormatter; - - protected: - /** - Constructs a ``BasicWriter`` object. - */ - explicit BasicWriter(Buffer &b) : buffer_(b) {} - - public: - /** - \rst - Destroys a ``BasicWriter`` object. - \endrst - */ - virtual ~BasicWriter() {} - - /** - Returns the total number of characters written. - */ - std::size_t size() const { return buffer_.size(); } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const Char *c_str() const { - std::size_t size = buffer_.size(); - buffer_.reserve(size + 1); - buffer_[size] = '\0'; - return &buffer_[0]; - } - - /** - \rst - Returns the content of the output buffer as an `std::string`. - \endrst - */ - std::basic_string str() const { - return std::basic_string(&buffer_[0], buffer_.size()); - } - - /** - \rst - Writes formatted data. - - *args* is an argument list representing arbitrary arguments. - - **Example**:: - - MemoryWriter out; - out.write("Current point:\n"); - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - Current point: - (-3.140000, +3.140000) - - The output can be accessed using :func:`data()`, :func:`c_str` or - :func:`str` methods. - - See also :ref:`syntax`. - \endrst - */ - void write(BasicCStringRef format, ArgList args) { - BasicFormatter(args, *this).format(format); - } - FMT_VARIADIC_VOID(write, BasicCStringRef) - - BasicWriter &operator<<(int value) { - write_decimal(value); - return *this; - } - BasicWriter &operator<<(unsigned value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(long value) { - write_decimal(value); - return *this; - } - BasicWriter &operator<<(unsigned long value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(LongLong value) { - write_decimal(value); - return *this; - } - - /** - \rst - Formats *value* and writes it to the stream. - \endrst - */ - BasicWriter &operator<<(ULongLong value) { - return *this << IntFormatSpec(value); - } - - BasicWriter &operator<<(double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - \rst - Formats *value* using the general format for floating-point numbers - (``'g'``) and writes it to the stream. - \endrst - */ - BasicWriter &operator<<(long double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - Writes a character to the stream. - */ - BasicWriter &operator<<(char value) { - buffer_.push_back(value); - return *this; - } - - BasicWriter &operator<<( - typename internal::WCharHelper::Supported value) { - buffer_.push_back(value); - return *this; - } - - /** - \rst - Writes *value* to the stream. - \endrst - */ - BasicWriter &operator<<(fmt::BasicStringRef value) { - const Char *str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - BasicWriter &operator<<( - typename internal::WCharHelper::Supported value) { - const char *str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - template - BasicWriter &operator<<(IntFormatSpec spec) { - internal::CharTraits::convert(FillChar()); - write_int(spec.value(), spec); - return *this; - } - - template - BasicWriter &operator<<(const StrFormatSpec &spec) { - const StrChar *s = spec.str(); - write_str(s, std::char_traits::length(s), spec); - return *this; - } - - void clear() FMT_NOEXCEPT { buffer_.clear(); } - - Buffer &buffer() FMT_NOEXCEPT { return buffer_; } -}; - -template -template -typename BasicWriter::CharPtr BasicWriter::write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec) { - CharPtr out = CharPtr(); - if (spec.width() > size) { - out = grow_buffer(spec.width()); - Char fill = internal::CharTraits::cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec.width() - size, fill); - out += spec.width() - size; - } else if (spec.align() == ALIGN_CENTER) { - out = fill_padding(out, spec.width(), size, fill); - } else { - std::uninitialized_fill_n(out + size, spec.width() - size, fill); - } - } else { - out = grow_buffer(size); - } - std::uninitialized_copy(s, s + size, out); - return out; -} - -template -template -void BasicWriter::write_str( - const internal::Arg::StringValue &s, const Spec &spec) { - // Check if StrChar is convertible to Char. - internal::CharTraits::convert(StrChar()); - if (spec.type_ && spec.type_ != 's') - internal::report_unknown_type(spec.type_, "string"); - const StrChar *str_value = s.value; - std::size_t str_size = s.size; - if (str_size == 0) { - if (!str_value) { - FMT_THROW(FormatError("string pointer is null")); - } - } - std::size_t precision = static_cast(spec.precision_); - if (spec.precision_ >= 0 && precision < str_size) - str_size = precision; - write_str(str_value, str_size, spec); -} - -template -typename BasicWriter::CharPtr - BasicWriter::fill_padding( - CharPtr buffer, unsigned total_size, - std::size_t content_size, wchar_t fill) { - std::size_t padding = total_size - content_size; - std::size_t left_padding = padding / 2; - Char fill_char = internal::CharTraits::cast(fill); - std::uninitialized_fill_n(buffer, left_padding, fill_char); - buffer += left_padding; - CharPtr content = buffer; - std::uninitialized_fill_n(buffer + content_size, - padding - left_padding, fill_char); - return content; -} - -template -template -typename BasicWriter::CharPtr - BasicWriter::prepare_int_buffer( - unsigned num_digits, const Spec &spec, - const char *prefix, unsigned prefix_size) { - unsigned width = spec.width(); - Alignment align = spec.align(); - Char fill = internal::CharTraits::cast(spec.fill()); - if (spec.precision() > static_cast(num_digits)) { - // Octal prefix '0' is counted as a digit, so ignore it if precision - // is specified. - if (prefix_size > 0 && prefix[prefix_size - 1] == '0') - --prefix_size; - unsigned number_size = - prefix_size + internal::to_unsigned(spec.precision()); - AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); - if (number_size >= width) - return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); - buffer_.reserve(width); - unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::uninitialized_fill(p, p + fill_size, fill); - } - CharPtr result = prepare_int_buffer( - num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::uninitialized_fill(p, p + fill_size, fill); - } - return result; - } - unsigned size = prefix_size + num_digits; - if (width <= size) { - CharPtr p = grow_buffer(size); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - CharPtr p = grow_buffer(width); - CharPtr end = p + width; - if (align == ALIGN_LEFT) { - std::uninitialized_copy(prefix, prefix + prefix_size, p); - p += size; - std::uninitialized_fill(p, end, fill); - } else if (align == ALIGN_CENTER) { - p = fill_padding(p, width, size, fill); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - p += size; - } else { - if (align == ALIGN_NUMERIC) { - if (prefix_size != 0) { - p = std::uninitialized_copy(prefix, prefix + prefix_size, p); - size -= prefix_size; - } - } else { - std::uninitialized_copy(prefix, prefix + prefix_size, end - size); - } - std::uninitialized_fill(p, end - size, fill); - p = end; - } - return p - 1; -} - -template -template -void BasicWriter::write_int(T value, Spec spec) { - unsigned prefix_size = 0; - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType abs_value = static_cast(value); - char prefix[4] = ""; - if (internal::is_negative(value)) { - prefix[0] = '-'; - ++prefix_size; - abs_value = 0 - abs_value; - } else if (spec.flag(SIGN_FLAG)) { - prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; - ++prefix_size; - } - switch (spec.type()) { - case 0: case 'd': { - unsigned num_digits = internal::count_digits(abs_value); - CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1; - internal::format_decimal(get(p), abs_value, 0); - break; - } - case 'x': case 'X': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type_prefix(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 4) != 0); - Char *p = get(prepare_int_buffer( - num_digits, spec, prefix, prefix_size)); - n = abs_value; - const char *digits = spec.type() == 'x' ? - "0123456789abcdef" : "0123456789ABCDEF"; - do { - *p-- = digits[n & 0xf]; - } while ((n >>= 4) != 0); - break; - } - case 'b': case 'B': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type_prefix(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 1) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = static_cast('0' + (n & 1)); - } while ((n >>= 1) != 0); - break; - } - case 'o': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) - prefix[prefix_size++] = '0'; - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 3) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = static_cast('0' + (n & 7)); - } while ((n >>= 3) != 0); - break; - } - case 'n': { - unsigned num_digits = internal::count_digits(abs_value); - fmt::StringRef sep = ""; -#if !(defined(ANDROID) || defined(__ANDROID__)) - sep = internal::thousands_sep(std::localeconv()); -#endif - unsigned size = static_cast( - num_digits + sep.size() * ((num_digits - 1) / 3)); - CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; - internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep)); - break; - } - default: - internal::report_unknown_type( - spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); - break; - } -} - -template -template -void BasicWriter::write_double(T value, const Spec &spec) { - // Check type. - char type = spec.type(); - bool upper = false; - switch (type) { - case 0: - type = 'g'; - break; - case 'e': case 'f': case 'g': case 'a': - break; - case 'F': -#if FMT_MSC_VER - // MSVC's printf doesn't support 'F'. - type = 'f'; -#endif - // Fall through. - case 'E': case 'G': case 'A': - upper = true; - break; - default: - internal::report_unknown_type(type, "double"); - break; - } - - char sign = 0; - // Use isnegative instead of value < 0 because the latter is always - // false for NaN. - if (internal::FPUtil::isnegative(static_cast(value))) { - sign = '-'; - value = -value; - } else if (spec.flag(SIGN_FLAG)) { - sign = spec.flag(PLUS_FLAG) ? '+' : ' '; - } - - if (internal::FPUtil::isnotanumber(value)) { - // Format NaN ourselves because sprintf's output is not consistent - // across platforms. - std::size_t nan_size = 4; - const char *nan = upper ? " NAN" : " nan"; - if (!sign) { - --nan_size; - ++nan; - } - CharPtr out = write_str(nan, nan_size, spec); - if (sign) - *out = sign; - return; - } - - if (internal::FPUtil::isinfinity(value)) { - // Format infinity ourselves because sprintf's output is not consistent - // across platforms. - std::size_t inf_size = 4; - const char *inf = upper ? " INF" : " inf"; - if (!sign) { - --inf_size; - ++inf; - } - CharPtr out = write_str(inf, inf_size, spec); - if (sign) - *out = sign; - return; - } - - std::size_t offset = buffer_.size(); - unsigned width = spec.width(); - if (sign) { - buffer_.reserve(buffer_.size() + (width > 1u ? width : 1u)); - if (width > 0) - --width; - ++offset; - } - - // Build format string. - enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg - Char format[MAX_FORMAT_SIZE]; - Char *format_ptr = format; - *format_ptr++ = '%'; - unsigned width_for_sprintf = width; - if (spec.flag(HASH_FLAG)) - *format_ptr++ = '#'; - if (spec.align() == ALIGN_CENTER) { - width_for_sprintf = 0; - } else { - if (spec.align() == ALIGN_LEFT) - *format_ptr++ = '-'; - if (width != 0) - *format_ptr++ = '*'; - } - if (spec.precision() >= 0) { - *format_ptr++ = '.'; - *format_ptr++ = '*'; - } - - append_float_length(format_ptr, value); - *format_ptr++ = type; - *format_ptr = '\0'; - - // Format using snprintf. - Char fill = internal::CharTraits::cast(spec.fill()); - unsigned n = 0; - Char *start = FMT_NULL; - for (;;) { - std::size_t buffer_size = buffer_.capacity() - offset; -#if FMT_MSC_VER - // MSVC's vsnprintf_s doesn't work with zero size, so reserve - // space for at least one extra character to make the size non-zero. - // Note that the buffer's capacity will increase by more than 1. - if (buffer_size == 0) { - buffer_.reserve(offset + 1); - buffer_size = buffer_.capacity() - offset; - } -#endif - start = &buffer_[offset]; - int result = internal::CharTraits::format_float( - start, buffer_size, format, width_for_sprintf, spec.precision(), value); - if (result >= 0) { - n = internal::to_unsigned(result); - if (offset + n < buffer_.capacity()) - break; // The buffer is large enough - continue with formatting. - buffer_.reserve(offset + n + 1); - } else { - // If result is negative we ask to increase the capacity by at least 1, - // but as std::vector, the buffer grows exponentially. - buffer_.reserve(buffer_.capacity() + 1); - } - } - if (sign) { - if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') { - *(start - 1) = sign; - sign = 0; - } else { - *(start - 1) = fill; - } - ++n; - } - if (spec.align() == ALIGN_CENTER && spec.width() > n) { - width = spec.width(); - CharPtr p = grow_buffer(width); - std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); - fill_padding(p, spec.width(), n, fill); - return; - } - if (spec.fill() != ' ' || sign) { - while (*start == ' ') - *start++ = fill; - if (sign) - *(start - 1) = sign; - } - grow_buffer(n); -} - -/** - \rst - This class template provides operations for formatting and writing data - into a character stream. The output is stored in a memory buffer that grows - dynamically. - - You can use one of the following typedefs for common character types - and the standard allocator: - - +---------------+-----------------------------------------------------+ - | Type | Definition | - +===============+=====================================================+ - | MemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - | WMemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - - **Example**:: - - MemoryWriter out; - out << "The answer is " << 42 << "\n"; - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42 - (-3.140000, +3.140000) - - The output can be converted to an ``std::string`` with ``out.str()`` or - accessed as a C string with ``out.c_str()``. - \endrst - */ -template > -class BasicMemoryWriter : public BasicWriter { - private: - internal::MemoryBuffer buffer_; - - public: - explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) - : BasicWriter(buffer_), buffer_(alloc) {} - -#if FMT_USE_RVALUE_REFERENCES - /** - \rst - Constructs a :class:`fmt::BasicMemoryWriter` object moving the content - of the other object to it. - \endrst - */ - BasicMemoryWriter(BasicMemoryWriter &&other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { - } - - /** - \rst - Moves the content of the other ``BasicMemoryWriter`` object to this one. - \endrst - */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { - buffer_ = std::move(other.buffer_); - return *this; - } -#endif -}; - -typedef BasicMemoryWriter MemoryWriter; -typedef BasicMemoryWriter WMemoryWriter; - -/** - \rst - This class template provides operations for formatting and writing data - into a fixed-size array. For writing into a dynamically growing buffer - use :class:`fmt::BasicMemoryWriter`. - - Any write method will throw ``std::runtime_error`` if the output doesn't fit - into the array. - - You can use one of the following typedefs for common character types: - - +--------------+---------------------------+ - | Type | Definition | - +==============+===========================+ - | ArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - | WArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - \endrst - */ -template -class BasicArrayWriter : public BasicWriter { - private: - internal::FixedBuffer buffer_; - - public: - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - given size. - \endrst - */ - BasicArrayWriter(Char *array, std::size_t size) - : BasicWriter(buffer_), buffer_(array, size) {} - - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - size known at compile time. - \endrst - */ - template - explicit BasicArrayWriter(Char (&array)[SIZE]) - : BasicWriter(buffer_), buffer_(array, SIZE) {} -}; - -typedef BasicArrayWriter ArrayWriter; -typedef BasicArrayWriter WArrayWriter; - -// Reports a system error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_system_error(int error_code, - StringRef message) FMT_NOEXCEPT; - -#if FMT_USE_WINDOWS_H - -/** A Windows error. */ -class WindowsError : public SystemError { - private: - FMT_API void init(int error_code, CStringRef format_str, ArgList args); - - public: - /** - \rst - Constructs a :class:`fmt::WindowsError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is the - system message corresponding to the error code. - *error_code* is a Windows error code as given by ``GetLastError``. - If *error_code* is not a valid error code such as -1, the system message - will look like "error -1". - - **Example**:: - - // This throws a WindowsError with the description - // cannot open file 'madeup': The system cannot find the file specified. - // or similar (system message may vary). - const char *filename = "madeup"; - LPOFSTRUCT of = LPOFSTRUCT(); - HFILE file = OpenFile(filename, &of, OF_READ); - if (file == HFILE_ERROR) { - throw fmt::WindowsError(GetLastError(), - "cannot open file '{}'", filename); - } - \endrst - */ - WindowsError(int error_code, CStringRef message) { - init(error_code, message, ArgList()); - } - FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) -}; - -// Reports a Windows error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_windows_error(int error_code, - StringRef message) FMT_NOEXCEPT; - -#endif - -enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; - -/** - Formats a string and prints it to stdout using ANSI escape sequences - to specify color (experimental). - Example: - print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); - */ -FMT_API void print_colored(Color c, CStringRef format, ArgList args); - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = format("The answer is {}", 42); - \endrst -*/ -inline std::string format(CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -inline std::wstring format(WCStringRef format_str, ArgList args) { - WMemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - print(stderr, "Don't {}!", "panic"); - \endrst - */ -FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - print("Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ -FMT_API void print(CStringRef format_str, ArgList args); - -/** - Fast integer formatter. - */ -class FormatInt { - private: - // Buffer should be large enough to hold all digits (digits10 + 1), - // a sign and a null character. - enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; - mutable char buffer_[BUFFER_SIZE]; - char *str_; - - // Formats value in reverse and returns the number of digits. - char *format_decimal(ULongLong value) { - char *buffer_end = buffer_ + BUFFER_SIZE - 1; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = static_cast((value % 100) * 2); - value /= 100; - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - } - if (value < 10) { - *--buffer_end = static_cast('0' + value); - return buffer_end; - } - unsigned index = static_cast(value * 2); - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - return buffer_end; - } - - void FormatSigned(LongLong value) { - ULongLong abs_value = static_cast(value); - bool negative = value < 0; - if (negative) - abs_value = 0 - abs_value; - str_ = format_decimal(abs_value); - if (negative) - *--str_ = '-'; - } - - public: - explicit FormatInt(int value) { FormatSigned(value); } - explicit FormatInt(long value) { FormatSigned(value); } - explicit FormatInt(LongLong value) { FormatSigned(value); } - explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} - explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} - explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} - - /** Returns the number of characters written to the output buffer. */ - std::size_t size() const { - return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1); - } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const char *data() const { return str_; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const char *c_str() const { - buffer_[BUFFER_SIZE - 1] = '\0'; - return str_; - } - - /** - \rst - Returns the content of the output buffer as an ``std::string``. - \endrst - */ - std::string str() const { return std::string(str_, size()); } -}; - -// Formats a decimal integer value writing into buffer and returns -// a pointer to the end of the formatted string. This function doesn't -// write a terminating null character. -template -inline void format_decimal(char *&buffer, T value) { - typedef typename internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(value); - if (internal::is_negative(value)) { - *buffer++ = '-'; - abs_value = 0 - abs_value; - } - if (abs_value < 100) { - if (abs_value < 10) { - *buffer++ = static_cast('0' + abs_value); - return; - } - unsigned index = static_cast(abs_value * 2); - *buffer++ = internal::Data::DIGITS[index]; - *buffer++ = internal::Data::DIGITS[index + 1]; - return; - } - unsigned num_digits = internal::count_digits(abs_value); - internal::format_decimal(buffer, abs_value, num_digits); - buffer += num_digits; -} - -/** - \rst - Returns a named argument for formatting functions. - - **Example**:: - - print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); - - \endrst - */ -template -inline internal::NamedArgWithType arg(StringRef name, const T &arg) { - return internal::NamedArgWithType(name, arg); -} - -template -inline internal::NamedArgWithType arg(WStringRef name, const T &arg) { - return internal::NamedArgWithType(name, arg); -} - -// The following two functions are deleted intentionally to disable -// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. -template -void arg(StringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -template -void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -} - -#if FMT_GCC_VERSION -// Use the system_header pragma to suppress warnings about variadic macros -// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't -// work. It is used at the end because we want to suppress as little warnings -// as possible. -# pragma GCC system_header -#endif - -// This is used to work around VC++ bugs in handling variadic macros. -#define FMT_EXPAND(args) args - -// Returns the number of arguments. -// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. -#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) -#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) -#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - -#define FMT_FOR_EACH_(N, f, ...) \ - FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) -#define FMT_FOR_EACH(f, ...) \ - FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) - -#define FMT_ADD_ARG_NAME(type, index) type arg##index -#define FMT_GET_ARG_NAME(type, index) arg##index - -#if FMT_USE_VARIADIC_TEMPLATES -# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \ - template \ - ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const Args & ... args) Const { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } -#else -// Defines a wrapper for a function taking __VA_ARGS__ arguments -// and n additional arguments of arbitrary types. -# define FMT_WRAP(Const, Char, ReturnType, func, call, n, ...) \ - template \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - FMT_GEN(n, FMT_MAKE_ARG)) Const { \ - fmt::internal::ArgArray::Type arr; \ - FMT_GEN(n, FMT_ASSIGN_##Char); \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ - } - -# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) Const { \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ - } \ - FMT_WRAP(Const, Char, ReturnType, func, call, 1, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 2, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 3, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 4, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 5, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 6, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 7, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 8, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 9, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 10, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 11, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 12, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 13, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 14, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 15, __VA_ARGS__) -#endif // FMT_USE_VARIADIC_TEMPLATES - -/** - \rst - Defines a variadic function with the specified return type, function name - and argument types passed as variable arguments to this macro. - - **Example**:: - - void print_error(const char *file, int line, const char *format, - fmt::ArgList args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args); - } - FMT_VARIADIC(void, print_error, const char *, int, const char *) - - ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that - don't implement variadic templates. You don't have to use this macro if - you don't need legacy compiler support and can use variadic templates - directly:: - - template - void print_error(const char *file, int line, const char *format, - const Args & ... args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args...); - } - \endrst - */ -#define FMT_VARIADIC(ReturnType, func, ...) \ - FMT_VARIADIC_(, char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_CONST(ReturnType, func, ...) \ - FMT_VARIADIC_(const, char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_W(ReturnType, func, ...) \ - FMT_VARIADIC_(, wchar_t, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_CONST_W(ReturnType, func, ...) \ - FMT_VARIADIC_(const, wchar_t, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) - -#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id) - -/** - \rst - Convenient macro to capture the arguments' names and values into several - ``fmt::arg(name, value)``. - - **Example**:: - - int x = 1, y = 2; - print("point: ({x}, {y})", FMT_CAPTURE(x, y)); - // same as: - // print("point: ({x}, {y})", arg("x", x), arg("y", y)); - - \endrst - */ -#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) - -#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) - -namespace fmt { -FMT_VARIADIC(std::string, format, CStringRef) -FMT_VARIADIC_W(std::wstring, format, WCStringRef) -FMT_VARIADIC(void, print, CStringRef) -FMT_VARIADIC(void, print, std::FILE *, CStringRef) -FMT_VARIADIC(void, print_colored, Color, CStringRef) - -namespace internal { -template -inline bool is_name_start(Char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; -} - -// Parses an unsigned integer advancing s to the end of the parsed input. -// This function assumes that the first character of s is a digit. -template -unsigned parse_nonnegative_int(const Char *&s) { - assert('0' <= *s && *s <= '9'); - unsigned value = 0; - // Convert to unsigned to prevent a warning. - unsigned max_int = (std::numeric_limits::max)(); - unsigned big = max_int / 10; - do { - // Check for overflow. - if (value > big) { - value = max_int + 1; - break; - } - value = value * 10 + (*s - '0'); - ++s; - } while ('0' <= *s && *s <= '9'); - // Convert to unsigned to prevent a warning. - if (value > max_int) - FMT_THROW(FormatError("number is too big")); - return value; -} - -inline void require_numeric_argument(const Arg &arg, char spec) { - if (arg.type > Arg::LAST_NUMERIC_TYPE) { - std::string message = - fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::FormatError(message)); - } -} - -template -void check_sign(const Char *&s, const Arg &arg) { - char sign = static_cast(*s); - require_numeric_argument(arg, sign); - if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { - FMT_THROW(FormatError(fmt::format( - "format specifier '{}' requires signed argument", sign))); - } - ++s; -} -} // namespace internal - -template -inline internal::Arg BasicFormatter::get_arg( - BasicStringRef arg_name, const char *&error) { - if (check_no_auto_index(error)) { - map_.init(args()); - const internal::Arg *arg = map_.find(arg_name); - if (arg) - return *arg; - error = "argument not found"; - } - return internal::Arg(); -} - -template -inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { - const char *error = FMT_NULL; - internal::Arg arg = *s < '0' || *s > '9' ? - next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); - if (error) { - FMT_THROW(FormatError( - *s != '}' && *s != ':' ? "invalid format string" : error)); - } - return arg; -} - -template -inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { - assert(internal::is_name_start(*s)); - const Char *start = s; - Char c; - do { - c = *++s; - } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); - const char *error = FMT_NULL; - internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); - if (error) - FMT_THROW(FormatError(error)); - return arg; -} - -template -const Char *BasicFormatter::format( - const Char *&format_str, const internal::Arg &arg) { - using internal::Arg; - const Char *s = format_str; - typename ArgFormatter::SpecType spec; - if (*s == ':') { - if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); - return s; - } - ++s; - // Parse fill and alignment. - if (Char c = *s) { - const Char *p = s + 1; - spec.align_ = ALIGN_DEFAULT; - do { - switch (*p) { - case '<': - spec.align_ = ALIGN_LEFT; - break; - case '>': - spec.align_ = ALIGN_RIGHT; - break; - case '=': - spec.align_ = ALIGN_NUMERIC; - break; - case '^': - spec.align_ = ALIGN_CENTER; - break; - } - if (spec.align_ != ALIGN_DEFAULT) { - if (p != s) { - if (c == '}') break; - if (c == '{') - FMT_THROW(FormatError("invalid fill character '{'")); - s += 2; - spec.fill_ = c; - } else ++s; - if (spec.align_ == ALIGN_NUMERIC) - require_numeric_argument(arg, '='); - break; - } - } while (--p >= s); - } - - // Parse sign. - switch (*s) { - case '+': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '-': - check_sign(s, arg); - spec.flags_ |= MINUS_FLAG; - break; - case ' ': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG; - break; - } - - if (*s == '#') { - require_numeric_argument(arg, '#'); - spec.flags_ |= HASH_FLAG; - ++s; - } - - // Parse zero flag. - if (*s == '0') { - require_numeric_argument(arg, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; - ++s; - } - - // Parse width. - if ('0' <= *s && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg width_arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (width_arg.type) { - case Arg::INT: - if (width_arg.int_value < 0) - FMT_THROW(FormatError("negative width")); - value = width_arg.int_value; - break; - case Arg::UINT: - value = width_arg.uint_value; - break; - case Arg::LONG_LONG: - if (width_arg.long_long_value < 0) - FMT_THROW(FormatError("negative width")); - value = width_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = width_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("width is not integer")); - } - unsigned max_int = (std::numeric_limits::max)(); - if (value > max_int) - FMT_THROW(FormatError("number is too big")); - spec.width_ = static_cast(value); - } - - // Parse precision. - if (*s == '.') { - ++s; - spec.precision_ = 0; - if ('0' <= *s && *s <= '9') { - spec.precision_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg precision_arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (precision_arg.type) { - case Arg::INT: - if (precision_arg.int_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.int_value; - break; - case Arg::UINT: - value = precision_arg.uint_value; - break; - case Arg::LONG_LONG: - if (precision_arg.long_long_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = precision_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("precision is not integer")); - } - unsigned max_int = (std::numeric_limits::max)(); - if (value > max_int) - FMT_THROW(FormatError("number is too big")); - spec.precision_ = static_cast(value); - } else { - FMT_THROW(FormatError("missing precision specifier")); - } - if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { - FMT_THROW(FormatError( - fmt::format("precision not allowed in {} format specifier", - arg.type == Arg::POINTER ? "pointer" : "integer"))); - } - } - - // Parse type. - if (*s != '}' && *s) - spec.type_ = static_cast(*s++); - } - - if (*s++ != '}') - FMT_THROW(FormatError("missing '}' in format string")); - - // Format argument. - ArgFormatter(*this, spec, s - 1).visit(arg); - return s; -} - -template -void BasicFormatter::format(BasicCStringRef format_str) { - const Char *s = format_str.c_str(); - const Char *start = s; - while (*s) { - Char c = *s++; - if (c != '{' && c != '}') continue; - if (*s == c) { - write(writer_, start, s); - start = ++s; - continue; - } - if (c == '}') - FMT_THROW(FormatError("unmatched '}' in format string")); - write(writer_, start, s - 1); - internal::Arg arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); - start = s = format(s, arg); - } - write(writer_, start, s); -} - -template -struct ArgJoin { - It first; - It last; - BasicCStringRef sep; - - ArgJoin(It first, It last, const BasicCStringRef& sep) : - first(first), - last(last), - sep(sep) {} -}; - -template -ArgJoin join(It first, It last, const BasicCStringRef& sep) { - return ArgJoin(first, last, sep); -} - -template -ArgJoin join(It first, It last, const BasicCStringRef& sep) { - return ArgJoin(first, last, sep); -} - -#if FMT_HAS_GXX_CXX11 -template -auto join(const Range& range, const BasicCStringRef& sep) - -> ArgJoin { - return join(std::begin(range), std::end(range), sep); -} - -template -auto join(const Range& range, const BasicCStringRef& sep) - -> ArgJoin { - return join(std::begin(range), std::end(range), sep); -} -#endif - -template -void format_arg(fmt::BasicFormatter &f, - const Char *&format_str, const ArgJoin& e) { - const Char* end = format_str; - if (*end == ':') - ++end; - while (*end && *end != '}') - ++end; - if (*end != '}') - FMT_THROW(FormatError("missing '}' in format string")); - - It it = e.first; - if (it != e.last) { - const Char* save = format_str; - f.format(format_str, internal::MakeArg >(*it++)); - while (it != e.last) { - f.writer().write(e.sep); - format_str = save; - f.format(format_str, internal::MakeArg >(*it++)); - } - } - format_str = end + 1; -} -} // namespace fmt - -#if FMT_USE_USER_DEFINED_LITERALS -namespace fmt { -namespace internal { - -template -struct UdlFormat { - const Char *str; - - template - auto operator()(Args && ... args) const - -> decltype(format(str, std::forward(args)...)) { - return format(str, std::forward(args)...); - } -}; - -template -struct UdlArg { - const Char *str; - - template - NamedArgWithType operator=(T &&value) const { - return {str, std::forward(value)}; - } -}; - -} // namespace internal - -inline namespace literals { - -/** - \rst - C++11 literal equivalent of :func:`fmt::format`. - - **Example**:: - - using namespace fmt::literals; - std::string message = "The answer is {}"_format(42); - \endrst - */ -inline internal::UdlFormat -operator"" _format(const char *s, std::size_t) { return {s}; } -inline internal::UdlFormat -operator"" _format(const wchar_t *s, std::size_t) { return {s}; } - -/** - \rst - C++11 literal equivalent of :func:`fmt::arg`. - - **Example**:: - - using namespace fmt::literals; - print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); - \endrst - */ -inline internal::UdlArg -operator"" _a(const char *s, std::size_t) { return {s}; } -inline internal::UdlArg -operator"" _a(const wchar_t *s, std::size_t) { return {s}; } - -} // inline namespace literals -} // namespace fmt -#endif // FMT_USE_USER_DEFINED_LITERALS - -// Restore warnings. -#if FMT_GCC_VERSION >= 406 -# pragma GCC diagnostic pop -#endif - -#if defined(__clang__) && !defined(FMT_ICC_VERSION) -# pragma clang diagnostic pop -#endif - -#ifdef FMT_HEADER_ONLY -# define FMT_FUNC inline -# include "format.cc" -#else -# define FMT_FUNC -#endif - -#endif // FMT_FORMAT_H_ diff --git a/dep/fmt/fmt/ostream.cc b/dep/fmt/fmt/ostream.cc deleted file mode 100644 index 2d443f73054..00000000000 --- a/dep/fmt/fmt/ostream.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - Formatting library for C++ - std::ostream support - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#include "ostream.h" - -namespace fmt { - -namespace internal { -FMT_FUNC void write(std::ostream &os, Writer &w) { - const char *data = w.data(); - typedef internal::MakeUnsigned::Type UnsignedStreamSize; - UnsignedStreamSize size = w.size(); - UnsignedStreamSize max_size = - internal::to_unsigned((std::numeric_limits::max)()); - do { - UnsignedStreamSize n = size <= max_size ? size : max_size; - os.write(data, static_cast(n)); - data += n; - size -= n; - } while (size != 0); -} -} - -FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - internal::write(os, w); -} -} // namespace fmt diff --git a/dep/fmt/fmt/ostream.h b/dep/fmt/fmt/ostream.h deleted file mode 100644 index 6848aac28c2..00000000000 --- a/dep/fmt/fmt/ostream.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - Formatting library for C++ - std::ostream support - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_OSTREAM_H_ -#define FMT_OSTREAM_H_ - -#include "format.h" -#include - -namespace fmt { - -namespace internal { - -template -class FormatBuf : public std::basic_streambuf { - private: - typedef typename std::basic_streambuf::int_type int_type; - typedef typename std::basic_streambuf::traits_type traits_type; - - Buffer &buffer_; - - public: - FormatBuf(Buffer &buffer) : buffer_(buffer) {} - - protected: - // The put-area is actually always empty. This makes the implementation - // simpler and has the advantage that the streambuf and the buffer are always - // in sync and sputc never writes into uninitialized memory. The obvious - // disadvantage is that each call to sputc always results in a (virtual) call - // to overflow. There is no disadvantage here for sputn since this always - // results in a call to xsputn. - - int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { - if (!traits_type::eq_int_type(ch, traits_type::eof())) - buffer_.push_back(static_cast(ch)); - return ch; - } - - std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { - buffer_.append(s, s + count); - return count; - } -}; - -Yes &convert(std::ostream &); - -struct DummyStream : std::ostream { - DummyStream(); // Suppress a bogus warning in MSVC. - - // Hide all operator<< overloads from std::ostream. - template - typename EnableIf::type operator<<(const T &); -}; - -No &operator<<(std::ostream &, int); - -template -struct ConvertToIntImpl { - // Convert to int only if T doesn't have an overloaded operator<<. - enum { - value = sizeof(convert(get() << get())) == sizeof(No) - }; -}; - -// Write the content of w to os. -FMT_API void write(std::ostream &os, Writer &w); -} // namespace internal - -// Formats a value. -template -void format_arg(BasicFormatter &f, - const Char *&format_str, const T &value) { - internal::MemoryBuffer buffer; - - internal::FormatBuf format_buf(buffer); - std::basic_ostream output(&format_buf); - output.exceptions(std::ios_base::failbit | std::ios_base::badbit); - output << value; - - BasicStringRef str(&buffer[0], buffer.size()); - typedef internal::MakeArg< BasicFormatter > MakeArg; - format_str = f.format(format_str, MakeArg(str)); -} - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - print(cerr, "Don't {}!", "panic"); - \endrst - */ -FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); -FMT_VARIADIC(void, print, std::ostream &, CStringRef) -} // namespace fmt - -#ifdef FMT_HEADER_ONLY -# include "ostream.cc" -#endif - -#endif // FMT_OSTREAM_H_ diff --git a/dep/fmt/fmt/posix.cc b/dep/fmt/fmt/posix.cc deleted file mode 100644 index 356668c135a..00000000000 --- a/dep/fmt/fmt/posix.cc +++ /dev/null @@ -1,241 +0,0 @@ -/* - A C++ interface to POSIX functions. - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -// Disable bogus MSVC warnings. -#ifndef _CRT_SECURE_NO_WARNINGS -# define _CRT_SECURE_NO_WARNINGS -#endif - -#include "posix.h" - -#include -#include -#include - -#ifndef _WIN32 -# include -#else -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# include - -# define O_CREAT _O_CREAT -# define O_TRUNC _O_TRUNC - -# ifndef S_IRUSR -# define S_IRUSR _S_IREAD -# endif - -# ifndef S_IWUSR -# define S_IWUSR _S_IWRITE -# endif - -# ifdef __MINGW32__ -# define _SH_DENYNO 0x40 -# endif - -#endif // _WIN32 - -#ifdef fileno -# undef fileno -#endif - -namespace { -#ifdef _WIN32 -// Return type of read and write functions. -typedef int RWResult; - -// On Windows the count argument to read and write is unsigned, so convert -// it from size_t preventing integer overflow. -inline unsigned convert_rwcount(std::size_t count) { - return count <= UINT_MAX ? static_cast(count) : UINT_MAX; -} -#else -// Return type of read and write functions. -typedef ssize_t RWResult; - -inline std::size_t convert_rwcount(std::size_t count) { return count; } -#endif -} - -fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT { - if (file_ && FMT_SYSTEM(fclose(file_)) != 0) - fmt::report_system_error(errno, "cannot close file"); -} - -fmt::BufferedFile::BufferedFile( - fmt::CStringRef filename, fmt::CStringRef mode) { - FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); - if (!file_) - FMT_THROW(SystemError(errno, "cannot open file {}", filename)); -} - -void fmt::BufferedFile::close() { - if (!file_) - return; - int result = FMT_SYSTEM(fclose(file_)); - file_ = FMT_NULL; - if (result != 0) - FMT_THROW(SystemError(errno, "cannot close file")); -} - -// A macro used to prevent expansion of fileno on broken versions of MinGW. -#define FMT_ARGS - -int fmt::BufferedFile::fileno() const { - int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); - if (fd == -1) - FMT_THROW(SystemError(errno, "cannot get file descriptor")); - return fd; -} - -fmt::File::File(fmt::CStringRef path, int oflag) { - int mode = S_IRUSR | S_IWUSR; -#if defined(_WIN32) && !defined(__MINGW32__) - fd_ = -1; - FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); -#else - FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); -#endif - if (fd_ == -1) - FMT_THROW(SystemError(errno, "cannot open file {}", path)); -} - -fmt::File::~File() FMT_NOEXCEPT { - // Don't retry close in case of EINTR! - // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html - if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) - fmt::report_system_error(errno, "cannot close file"); -} - -void fmt::File::close() { - if (fd_ == -1) - return; - // Don't retry close in case of EINTR! - // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html - int result = FMT_POSIX_CALL(close(fd_)); - fd_ = -1; - if (result != 0) - FMT_THROW(SystemError(errno, "cannot close file")); -} - -fmt::LongLong fmt::File::size() const { -#ifdef _WIN32 - // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT - // is less than 0x0500 as is the case with some default MinGW builds. - // Both functions support large file sizes. - DWORD size_upper = 0; - HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); - DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); - if (size_lower == INVALID_FILE_SIZE) { - DWORD error = GetLastError(); - if (error != NO_ERROR) - FMT_THROW(WindowsError(GetLastError(), "cannot get file size")); - } - fmt::ULongLong long_size = size_upper; - return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; -#else - typedef struct stat Stat; - Stat file_stat = Stat(); - if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) - FMT_THROW(SystemError(errno, "cannot get file attributes")); - FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size), - "return type of File::size is not large enough"); - return file_stat.st_size; -#endif -} - -std::size_t fmt::File::read(void *buffer, std::size_t count) { - RWResult result = 0; - FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); - if (result < 0) - FMT_THROW(SystemError(errno, "cannot read from file")); - return internal::to_unsigned(result); -} - -std::size_t fmt::File::write(const void *buffer, std::size_t count) { - RWResult result = 0; - FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); - if (result < 0) - FMT_THROW(SystemError(errno, "cannot write to file")); - return internal::to_unsigned(result); -} - -fmt::File fmt::File::dup(int fd) { - // Don't retry as dup doesn't return EINTR. - // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html - int new_fd = FMT_POSIX_CALL(dup(fd)); - if (new_fd == -1) - FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd)); - return File(new_fd); -} - -void fmt::File::dup2(int fd) { - int result = 0; - FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); - if (result == -1) { - FMT_THROW(SystemError(errno, - "cannot duplicate file descriptor {} to {}", fd_, fd)); - } -} - -void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT { - int result = 0; - FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); - if (result == -1) - ec = ErrorCode(errno); -} - -void fmt::File::pipe(File &read_end, File &write_end) { - // Close the descriptors first to make sure that assignments don't throw - // and there are no leaks. - read_end.close(); - write_end.close(); - int fds[2] = {}; -#ifdef _WIN32 - // Make the default pipe capacity same as on Linux 2.6.11+. - enum { DEFAULT_CAPACITY = 65536 }; - int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); -#else - // Don't retry as the pipe function doesn't return EINTR. - // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html - int result = FMT_POSIX_CALL(pipe(fds)); -#endif - if (result != 0) - FMT_THROW(SystemError(errno, "cannot create pipe")); - // The following assignments don't throw because read_fd and write_fd - // are closed. - read_end = File(fds[0]); - write_end = File(fds[1]); -} - -fmt::BufferedFile fmt::File::fdopen(const char *mode) { - // Don't retry as fdopen doesn't return EINTR. - FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); - if (!f) - FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor")); - BufferedFile file(f); - fd_ = -1; - return file; -} - -long fmt::getpagesize() { -#ifdef _WIN32 - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwPageSize; -#else - long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); - if (size < 0) - FMT_THROW(SystemError(errno, "cannot get memory page size")); - return size; -#endif -} diff --git a/dep/fmt/fmt/posix.h b/dep/fmt/fmt/posix.h deleted file mode 100644 index 88512de5502..00000000000 --- a/dep/fmt/fmt/posix.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - A C++ interface to POSIX functions. - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_POSIX_H_ -#define FMT_POSIX_H_ - -#if defined(__MINGW32__) || defined(__CYGWIN__) -// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. -# undef __STRICT_ANSI__ -#endif - -#include -#include // for O_RDONLY -#include // for locale_t -#include -#include // for strtod_l - -#include - -#if defined __APPLE__ || defined(__FreeBSD__) -# include // for LC_NUMERIC_MASK on OS X -#endif - -#include "format.h" - -#ifndef FMT_POSIX -# if defined(_WIN32) && !defined(__MINGW32__) -// Fix warnings about deprecated symbols. -# define FMT_POSIX(call) _##call -# else -# define FMT_POSIX(call) call -# endif -#endif - -// Calls to system functions are wrapped in FMT_SYSTEM for testability. -#ifdef FMT_SYSTEM -# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) -#else -# define FMT_SYSTEM(call) call -# ifdef _WIN32 -// Fix warnings about deprecated symbols. -# define FMT_POSIX_CALL(call) ::_##call -# else -# define FMT_POSIX_CALL(call) ::call -# endif -#endif - -// Retries the expression while it evaluates to error_result and errno -// equals to EINTR. -#ifndef _WIN32 -# define FMT_RETRY_VAL(result, expression, error_result) \ - do { \ - result = (expression); \ - } while (result == error_result && errno == EINTR) -#else -# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) -#endif - -#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) - -namespace fmt { - -// An error code. -class ErrorCode { - private: - int value_; - - public: - explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {} - - int get() const FMT_NOEXCEPT { return value_; } -}; - -// A buffered file. -class BufferedFile { - private: - FILE *file_; - - friend class File; - - explicit BufferedFile(FILE *f) : file_(f) {} - - public: - // Constructs a BufferedFile object which doesn't represent any file. - BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {} - - // Destroys the object closing the file it represents if any. - FMT_API ~BufferedFile() FMT_NOEXCEPT; - -#if !FMT_USE_RVALUE_REFERENCES - // Emulate a move constructor and a move assignment operator if rvalue - // references are not supported. - - private: - // A proxy object to emulate a move constructor. - // It is private to make it impossible call operator Proxy directly. - struct Proxy { - FILE *file; - }; - -public: - // A "move constructor" for moving from a temporary. - BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {} - - // A "move constructor" for moving from an lvalue. - BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { - f.file_ = FMT_NULL; - } - - // A "move assignment operator" for moving from a temporary. - BufferedFile &operator=(Proxy p) { - close(); - file_ = p.file; - return *this; - } - - // A "move assignment operator" for moving from an lvalue. - BufferedFile &operator=(BufferedFile &other) { - close(); - file_ = other.file_; - other.file_ = FMT_NULL; - return *this; - } - - // Returns a proxy object for moving from a temporary: - // BufferedFile file = BufferedFile(...); - operator Proxy() FMT_NOEXCEPT { - Proxy p = {file_}; - file_ = FMT_NULL; - return p; - } - -#else - private: - FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); - - public: - BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) { - other.file_ = FMT_NULL; - } - - BufferedFile& operator=(BufferedFile &&other) { - close(); - file_ = other.file_; - other.file_ = FMT_NULL; - return *this; - } -#endif - - // Opens a file. - FMT_API BufferedFile(CStringRef filename, CStringRef mode); - - // Closes the file. - FMT_API void close(); - - // Returns the pointer to a FILE object representing this file. - FILE *get() const FMT_NOEXCEPT { return file_; } - - // We place parentheses around fileno to workaround a bug in some versions - // of MinGW that define fileno as a macro. - FMT_API int (fileno)() const; - - void print(CStringRef format_str, const ArgList &args) { - fmt::print(file_, format_str, args); - } - FMT_VARIADIC(void, print, CStringRef) -}; - -// A file. Closed file is represented by a File object with descriptor -1. -// Methods that are not declared with FMT_NOEXCEPT may throw -// fmt::SystemError in case of failure. Note that some errors such as -// closing the file multiple times will cause a crash on Windows rather -// than an exception. You can get standard behavior by overriding the -// invalid parameter handler with _set_invalid_parameter_handler. -class File { - private: - int fd_; // File descriptor. - - // Constructs a File object with a given descriptor. - explicit File(int fd) : fd_(fd) {} - - public: - // Possible values for the oflag argument to the constructor. - enum { - RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. - WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. - RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. - }; - - // Constructs a File object which doesn't represent any file. - File() FMT_NOEXCEPT : fd_(-1) {} - - // Opens a file and constructs a File object representing this file. - FMT_API File(CStringRef path, int oflag); - -#if !FMT_USE_RVALUE_REFERENCES - // Emulate a move constructor and a move assignment operator if rvalue - // references are not supported. - - private: - // A proxy object to emulate a move constructor. - // It is private to make it impossible call operator Proxy directly. - struct Proxy { - int fd; - }; - - public: - // A "move constructor" for moving from a temporary. - File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {} - - // A "move constructor" for moving from an lvalue. - File(File &other) FMT_NOEXCEPT : fd_(other.fd_) { - other.fd_ = -1; - } - - // A "move assignment operator" for moving from a temporary. - File &operator=(Proxy p) { - close(); - fd_ = p.fd; - return *this; - } - - // A "move assignment operator" for moving from an lvalue. - File &operator=(File &other) { - close(); - fd_ = other.fd_; - other.fd_ = -1; - return *this; - } - - // Returns a proxy object for moving from a temporary: - // File file = File(...); - operator Proxy() FMT_NOEXCEPT { - Proxy p = {fd_}; - fd_ = -1; - return p; - } - -#else - private: - FMT_DISALLOW_COPY_AND_ASSIGN(File); - - public: - File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) { - other.fd_ = -1; - } - - File& operator=(File &&other) { - close(); - fd_ = other.fd_; - other.fd_ = -1; - return *this; - } -#endif - - // Destroys the object closing the file it represents if any. - FMT_API ~File() FMT_NOEXCEPT; - - // Returns the file descriptor. - int descriptor() const FMT_NOEXCEPT { return fd_; } - - // Closes the file. - FMT_API void close(); - - // Returns the file size. The size has signed type for consistency with - // stat::st_size. - FMT_API LongLong size() const; - - // Attempts to read count bytes from the file into the specified buffer. - FMT_API std::size_t read(void *buffer, std::size_t count); - - // Attempts to write count bytes from the specified buffer to the file. - FMT_API std::size_t write(const void *buffer, std::size_t count); - - // Duplicates a file descriptor with the dup function and returns - // the duplicate as a file object. - FMT_API static File dup(int fd); - - // Makes fd be the copy of this file descriptor, closing fd first if - // necessary. - FMT_API void dup2(int fd); - - // Makes fd be the copy of this file descriptor, closing fd first if - // necessary. - FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; - - // Creates a pipe setting up read_end and write_end file objects for reading - // and writing respectively. - FMT_API static void pipe(File &read_end, File &write_end); - - // Creates a BufferedFile object associated with this file and detaches - // this File object from the file. - FMT_API BufferedFile fdopen(const char *mode); -}; - -// Returns the memory page size. -long getpagesize(); - -#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \ - !defined(__ANDROID__) && !defined(__CYGWIN__) -# define FMT_LOCALE -#endif - -#ifdef FMT_LOCALE -// A "C" numeric locale. -class Locale { - private: -# ifdef _MSC_VER - typedef _locale_t locale_t; - - enum { LC_NUMERIC_MASK = LC_NUMERIC }; - - static locale_t newlocale(int category_mask, const char *locale, locale_t) { - return _create_locale(category_mask, locale); - } - - static void freelocale(locale_t locale) { - _free_locale(locale); - } - - static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { - return _strtod_l(nptr, endptr, locale); - } -# endif - - locale_t locale_; - - FMT_DISALLOW_COPY_AND_ASSIGN(Locale); - - public: - typedef locale_t Type; - - Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) { - if (!locale_) - FMT_THROW(fmt::SystemError(errno, "cannot create locale")); - } - ~Locale() { freelocale(locale_); } - - Type get() const { return locale_; } - - // Converts string to floating-point number and advances str past the end - // of the parsed input. - double strtod(const char *&str) const { - char *end = FMT_NULL; - double result = strtod_l(str, &end, locale_); - str = end; - return result; - } -}; -#endif // FMT_LOCALE -} // namespace fmt - -#if !FMT_USE_RVALUE_REFERENCES -namespace std { -// For compatibility with C++98. -inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; } -inline fmt::File &move(fmt::File &f) { return f; } -} -#endif - -#endif // FMT_POSIX_H_ diff --git a/dep/fmt/fmt/printf.cc b/dep/fmt/fmt/printf.cc deleted file mode 100644 index 95d7a36ab67..00000000000 --- a/dep/fmt/fmt/printf.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#include "format.h" -#include "printf.h" - -namespace fmt { - -template -void printf(BasicWriter &w, BasicCStringRef format, ArgList args); - -FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - std::size_t size = w.size(); - return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); -} - -#ifndef FMT_HEADER_ONLY - -template void PrintfFormatter::format(CStringRef format); -template void PrintfFormatter::format(WCStringRef format); - -#endif // FMT_HEADER_ONLY - -} // namespace fmt diff --git a/dep/fmt/fmt/printf.h b/dep/fmt/fmt/printf.h deleted file mode 100644 index 46205a78eee..00000000000 --- a/dep/fmt/fmt/printf.h +++ /dev/null @@ -1,603 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_PRINTF_H_ -#define FMT_PRINTF_H_ - -#include // std::fill_n -#include // std::numeric_limits - -#include "ostream.h" - -namespace fmt { -namespace internal { - -// Checks if a value fits in int - used to avoid warnings about comparing -// signed and unsigned integers. -template -struct IntChecker { - template - static bool fits_in_int(T value) { - unsigned max = std::numeric_limits::max(); - return value <= max; - } - static bool fits_in_int(bool) { return true; } -}; - -template <> -struct IntChecker { - template - static bool fits_in_int(T value) { - return value >= std::numeric_limits::min() && - value <= std::numeric_limits::max(); - } - static bool fits_in_int(int) { return true; } -}; - -class PrecisionHandler : public ArgVisitor { - public: - void report_unhandled_arg() { - FMT_THROW(FormatError("precision is not integer")); - } - - template - int visit_any_int(T value) { - if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(FormatError("number is too big")); - return static_cast(value); - } -}; - -// IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public ArgVisitor { - public: - template - bool visit_any_int(T value) { return value == 0; } -}; - -// returns the default type for format specific "%s" -class DefaultType : public ArgVisitor { - public: - char visit_char(int) { return 'c'; } - - char visit_bool(bool) { return 's'; } - - char visit_pointer(const void *) { return 'p'; } - - template - char visit_any_int(T) { return 'd'; } - - template - char visit_any_double(T) { return 'g'; } - - char visit_unhandled_arg() { return 's'; } -}; - -template -struct is_same { - enum { value = 0 }; -}; - -template -struct is_same { - enum { value = 1 }; -}; - -// An argument visitor that converts an integer argument to T for printf, -// if T is an integral type. If T is void, the argument is converted to -// corresponding signed or unsigned type depending on the type specifier: -// 'd' and 'i' - signed, other - unsigned) -template -class ArgConverter : public ArgVisitor, void> { - private: - internal::Arg &arg_; - wchar_t type_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - - public: - ArgConverter(internal::Arg &arg, wchar_t type) - : arg_(arg), type_(type) {} - - void visit_bool(bool value) { - if (type_ != 's') - visit_any_int(value); - } - - void visit_char(int value) { - if (type_ != 's') - visit_any_int(value); - } - - template - void visit_any_int(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - if (type_ == 's') { - is_signed = std::numeric_limits::is_signed; - } - - using internal::Arg; - typedef typename internal::Conditional< - is_same::value, U, T>::type TargetType; - if (const_check(sizeof(TargetType) <= sizeof(int))) { - // Extra casts are used to silence warnings. - if (is_signed) { - arg_.type = Arg::INT; - arg_.int_value = static_cast(static_cast(value)); - } else { - arg_.type = Arg::UINT; - typedef typename internal::MakeUnsigned::Type Unsigned; - arg_.uint_value = static_cast(static_cast(value)); - } - } else { - if (is_signed) { - arg_.type = Arg::LONG_LONG; - // glibc's printf doesn't sign extend arguments of smaller types: - // std::printf("%lld", -42); // prints "4294967254" - // but we don't have to do the same because it's a UB. - arg_.long_long_value = static_cast(value); - } else { - arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast::Type>(value); - } - } - } -}; - -// Converts an integer argument to char for printf. -class CharConverter : public ArgVisitor { - private: - internal::Arg &arg_; - - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - - public: - explicit CharConverter(internal::Arg &arg) : arg_(arg) {} - - template - void visit_any_int(T value) { - arg_.type = internal::Arg::CHAR; - arg_.int_value = static_cast(value); - } -}; - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class WidthHandler : public ArgVisitor { - private: - FormatSpec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - - public: - explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} - - void report_unhandled_arg() { - FMT_THROW(FormatError("width is not integer")); - } - - template - unsigned visit_any_int(T value) { - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType width = static_cast(value); - if (internal::is_negative(value)) { - spec_.align_ = ALIGN_LEFT; - width = 0 - width; - } - unsigned int_max = std::numeric_limits::max(); - if (width > int_max) - FMT_THROW(FormatError("number is too big")); - return static_cast(width); - } -}; -} // namespace internal - -/** - \rst - A ``printf`` argument formatter based on the `curiously recurring template - pattern `_. - - To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some - or all of the visit methods with the same signatures as the methods in - `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. When a formatting - function processes an argument, it will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its - superclass will be called. - \endrst - */ -template -class BasicPrintfArgFormatter : - public internal::ArgFormatterBase { - private: - void write_null_pointer() { - this->spec().type_ = 0; - this->write("(nil)"); - } - - typedef internal::ArgFormatterBase Base; - - public: - /** - \rst - Constructs an argument formatter object. - *writer* is a reference to the output writer and *spec* contains format - specifier information for standard argument types. - \endrst - */ - BasicPrintfArgFormatter(BasicWriter &w, Spec &s) - : internal::ArgFormatterBase(w, s) {} - - /** Formats an argument of type ``bool``. */ - void visit_bool(bool value) { - Spec &fmt_spec = this->spec(); - if (fmt_spec.type_ != 's') - return this->visit_any_int(value); - fmt_spec.type_ = 0; - this->write(value); - } - - /** Formats a character. */ - void visit_char(int value) { - const Spec &fmt_spec = this->spec(); - BasicWriter &w = this->writer(); - if (fmt_spec.type_ && fmt_spec.type_ != 'c') - w.write_int(value, fmt_spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (fmt_spec.width_ > 1) { - Char fill = ' '; - out = w.grow_buffer(fmt_spec.width_); - if (fmt_spec.align_ != ALIGN_LEFT) { - std::fill_n(out, fmt_spec.width_ - 1, fill); - out += fmt_spec.width_ - 1; - } else { - std::fill_n(out + 1, fmt_spec.width_ - 1, fill); - } - } else { - out = w.grow_buffer(1); - } - *out = static_cast(value); - } - - /** Formats a null-terminated C string. */ - void visit_cstring(const char *value) { - if (value) - Base::visit_cstring(value); - else if (this->spec().type_ == 'p') - write_null_pointer(); - else - this->write("(null)"); - } - - /** Formats a pointer. */ - void visit_pointer(const void *value) { - if (value) - return Base::visit_pointer(value); - this->spec().type_ = 0; - write_null_pointer(); - } - - /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) { - BasicFormatter formatter(ArgList(), this->writer()); - const Char format_str[] = {'}', 0}; - const Char *format = format_str; - c.format(&formatter, c.value, &format); - } -}; - -/** The default printf argument formatter. */ -template -class PrintfArgFormatter : - public BasicPrintfArgFormatter, Char, FormatSpec> { - public: - /** Constructs an argument formatter object. */ - PrintfArgFormatter(BasicWriter &w, FormatSpec &s) - : BasicPrintfArgFormatter, Char, FormatSpec>(w, s) {} -}; - -/** This template formats data and writes the output to a writer. */ -template > -class PrintfFormatter : private internal::FormatterBase { - private: - BasicWriter &writer_; - - void parse_flags(FormatSpec &spec, const Char *&s); - - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - internal::Arg get_arg( - const Char *s, - unsigned arg_index = (std::numeric_limits::max)()); - - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); - - public: - /** - \rst - Constructs a ``PrintfFormatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have - appropriate lifetimes. - \endrst - */ - explicit PrintfFormatter(const ArgList &al, BasicWriter &w) - : FormatterBase(al), writer_(w) {} - - /** Formats stored arguments and writes the output to the writer. */ - void format(BasicCStringRef format_str); -}; - -template -void PrintfFormatter::parse_flags(FormatSpec &spec, const Char *&s) { - for (;;) { - switch (*s++) { - case '-': - spec.align_ = ALIGN_LEFT; - break; - case '+': - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '0': - spec.fill_ = '0'; - break; - case ' ': - spec.flags_ |= SIGN_FLAG; - break; - case '#': - spec.flags_ |= HASH_FLAG; - break; - default: - --s; - return; - } - } -} - -template -internal::Arg PrintfFormatter::get_arg(const Char *s, - unsigned arg_index) { - (void)s; - const char *error = FMT_NULL; - internal::Arg arg = arg_index == std::numeric_limits::max() ? - next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); - if (error) - FMT_THROW(FormatError(!*s ? "invalid format string" : error)); - return arg; -} - -template -unsigned PrintfFormatter::parse_header( - const Char *&s, FormatSpec &spec) { - unsigned arg_index = std::numeric_limits::max(); - Char c = *s; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). - unsigned value = internal::parse_nonnegative_int(s); - if (*s == '$') { // value is an argument index - ++s; - arg_index = value; - } else { - if (c == '0') - spec.fill_ = '0'; - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. - spec.width_ = value; - return arg_index; - } - } - } - parse_flags(spec, s); - // Parse width. - if (*s >= '0' && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); - } - return arg_index; -} - -template -void PrintfFormatter::format(BasicCStringRef format_str) { - const Char *start = format_str.c_str(); - const Char *s = start; - while (*s) { - Char c = *s++; - if (c != '%') continue; - if (*s == c) { - write(writer_, start, s); - start = ++s; - continue; - } - write(writer_, start, s - 1); - - FormatSpec spec; - spec.align_ = ALIGN_RIGHT; - - // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); - - // Parse precision. - if (*s == '.') { - ++s; - if ('0' <= *s && *s <= '9') { - spec.precision_ = static_cast(internal::parse_nonnegative_int(s)); - } else if (*s == '*') { - ++s; - spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); - } else { - spec.precision_ = 0; - } - } - - using internal::Arg; - Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) - spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); - if (spec.fill_ == '0') { - if (arg.type <= Arg::LAST_NUMERIC_TYPE) - spec.align_ = ALIGN_NUMERIC; - else - spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. - } - - // Parse length and convert the argument to the required type. - using internal::ArgConverter; - switch (*s++) { - case 'h': - if (*s == 'h') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'l': - if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'j': - ArgConverter(arg, *s).visit(arg); - break; - case 'z': - ArgConverter(arg, *s).visit(arg); - break; - case 't': - ArgConverter(arg, *s).visit(arg); - break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: - --s; - ArgConverter(arg, *s).visit(arg); - } - - // Parse type. - if (!*s) - FMT_THROW(FormatError("invalid format string")); - spec.type_ = static_cast(*s++); - - if (spec.type_ == 's') { - // set the format type to the default if 's' is specified - spec.type_ = internal::DefaultType().visit(arg); - } - - if (arg.type <= Arg::LAST_INTEGER_TYPE) { - // Normalize type. - switch (spec.type_) { - case 'i': case 'u': - spec.type_ = 'd'; - break; - case 'c': - // TODO: handle wchar_t - internal::CharConverter(arg).visit(arg); - break; - } - } - - start = s; - - // Format argument. - AF(writer_, spec).visit(arg); - } - write(writer_, start, s); -} - -inline void printf(Writer &w, CStringRef format, ArgList args) { - PrintfFormatter(args, w).format(format); -} -FMT_VARIADIC(void, printf, Writer &, CStringRef) - -inline void printf(WWriter &w, WCStringRef format, ArgList args) { - PrintfFormatter(args, w).format(format); -} -FMT_VARIADIC(void, printf, WWriter &, WCStringRef) - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = fmt::sprintf("The answer is %d", 42); - \endrst -*/ -inline std::string sprintf(CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); -} -FMT_VARIADIC(std::string, sprintf, CStringRef) - -inline std::wstring sprintf(WCStringRef format, ArgList args) { - WMemoryWriter w; - printf(w, format, args); - return w.str(); -} -FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - fmt::fprintf(stderr, "Don't %s!", "panic"); - \endrst - */ -FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); -FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - fmt::printf("Elapsed time: %.2f seconds", 1.23); - \endrst - */ -inline int printf(CStringRef format, ArgList args) { - return fprintf(stdout, format, args); -} -FMT_VARIADIC(int, printf, CStringRef) - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - fprintf(cerr, "Don't %s!", "panic"); - \endrst - */ -inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) { - MemoryWriter w; - printf(w, format_str, args); - internal::write(os, w); - return static_cast(w.size()); -} -FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) -} // namespace fmt - -#ifdef FMT_HEADER_ONLY -# include "printf.cc" -#endif - -#endif // FMT_PRINTF_H_ diff --git a/dep/fmt/fmt/string.h b/dep/fmt/fmt/string.h deleted file mode 100644 index 05996eb5878..00000000000 --- a/dep/fmt/fmt/string.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - Formatting library for C++ - string utilities - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifdef FMT_INCLUDE -# error "Add the fmt's parent directory and not fmt itself to includes." -#endif - -#ifndef FMT_STRING_H_ -#define FMT_STRING_H_ - -#include "format.h" - -namespace fmt { - -namespace internal { - -// A buffer that stores data in ``std::basic_string``. -template > -class StringBuffer : public Buffer { - public: - typedef std::basic_string, Allocator> StringType; - - private: - StringType data_; - - protected: - virtual void grow(std::size_t size) FMT_OVERRIDE { - data_.resize(size); - this->ptr_ = &data_[0]; - this->capacity_ = size; - } - - public: - explicit StringBuffer(const Allocator &allocator = Allocator()) - : data_(allocator) {} - - // Moves the data to ``str`` clearing the buffer. - void move_to(StringType &str) { - data_.resize(this->size_); - str.swap(data_); - this->capacity_ = this->size_ = 0; - this->ptr_ = FMT_NULL; - } -}; -} // namespace internal - -/** - \rst - This class template provides operations for formatting and writing data - into a character stream. The output is stored in a ``std::basic_string`` - that grows dynamically. - - You can use one of the following typedefs for common character types - and the standard allocator: - - +---------------+----------------------------+ - | Type | Definition | - +===============+============================+ - | StringWriter | BasicStringWriter | - +---------------+----------------------------+ - | WStringWriter | BasicStringWriter | - +---------------+----------------------------+ - - **Example**:: - - StringWriter out; - out << "The answer is " << 42 << "\n"; - - This will write the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42 - - The output can be moved to a ``std::basic_string`` with ``out.move_to()``. - \endrst - */ -template > -class BasicStringWriter : public BasicWriter { - private: - internal::StringBuffer buffer_; - - public: - /** - \rst - Constructs a :class:`fmt::BasicStringWriter` object. - \endrst - */ - explicit BasicStringWriter(const Allocator &allocator = Allocator()) - : BasicWriter(buffer_), buffer_(allocator) {} - - /** - \rst - Moves the buffer content to *str* clearing the buffer. - \endrst - */ - void move_to(std::basic_string, Allocator> &str) { - buffer_.move_to(str); - } -}; - -typedef BasicStringWriter StringWriter; -typedef BasicStringWriter WStringWriter; - -/** - \rst - Converts *value* to ``std::string`` using the default format for type *T*. - - **Example**:: - - #include "fmt/string.h" - - std::string answer = fmt::to_string(42); - \endrst - */ -template -std::string to_string(const T &value) { - fmt::MemoryWriter w; - w << value; - return w.str(); -} - -/** - \rst - Converts *value* to ``std::wstring`` using the default format for type *T*. - - **Example**:: - - #include "fmt/string.h" - - std::wstring answer = fmt::to_wstring(42); - \endrst - */ -template -std::wstring to_wstring(const T &value) { - fmt::WMemoryWriter w; - w << value; - return w.str(); -} -} - -#endif // FMT_STRING_H_ diff --git a/dep/fmt/fmt/time.h b/dep/fmt/fmt/time.h deleted file mode 100644 index c98b0e0116f..00000000000 --- a/dep/fmt/fmt/time.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - Formatting library for C++ - time formatting - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_TIME_H_ -#define FMT_TIME_H_ - -#include "format.h" -#include - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4702) // unreachable code -# pragma warning(disable: 4996) // "deprecated" functions -#endif - -namespace fmt { -template -void format_arg(BasicFormatter &f, - const char *&format_str, const std::tm &tm) { - if (*format_str == ':') - ++format_str; - const char *end = format_str; - while (*end && *end != '}') - ++end; - if (*end != '}') - FMT_THROW(FormatError("missing '}' in format string")); - internal::MemoryBuffer format; - format.append(format_str, end + 1); - format[format.size() - 1] = '\0'; - Buffer &buffer = f.writer().buffer(); - std::size_t start = buffer.size(); - for (;;) { - std::size_t size = buffer.capacity() - start; - std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); - if (count != 0) { - buffer.resize(start + count); - break; - } - if (size >= format.size() * 256) { - // If the buffer is 256 times larger than the format string, assume - // that `strftime` gives an empty result. There doesn't seem to be a - // better way to distinguish the two cases: - // https://github.com/fmtlib/fmt/issues/367 - break; - } - const std::size_t MIN_GROWTH = 10; - buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); - } - format_str = end + 1; -} - -namespace internal{ -inline Null<> localtime_r(...) { return Null<>(); } -inline Null<> localtime_s(...) { return Null<>(); } -inline Null<> gmtime_r(...) { return Null<>(); } -inline Null<> gmtime_s(...) { return Null<>(); } -} - -// Thread-safe replacement for std::localtime -inline std::tm localtime(std::time_t time) { - struct LocalTime { - std::time_t time_; - std::tm tm_; - - LocalTime(std::time_t t): time_(t) {} - - bool run() { - using namespace fmt::internal; - return handle(localtime_r(&time_, &tm_)); - } - - bool handle(std::tm *tm) { return tm != FMT_NULL; } - - bool handle(internal::Null<>) { - using namespace fmt::internal; - return fallback(localtime_s(&tm_, &time_)); - } - - bool fallback(int res) { return res == 0; } - - bool fallback(internal::Null<>) { - using namespace fmt::internal; - std::tm *tm = std::localtime(&time_); - if (tm) tm_ = *tm; - return tm != FMT_NULL; - } - }; - LocalTime lt(time); - if (lt.run()) - return lt.tm_; - // Too big time values may be unsupported. - FMT_THROW(fmt::FormatError("time_t value out of range")); - return std::tm(); -} - -// Thread-safe replacement for std::gmtime -inline std::tm gmtime(std::time_t time) { - struct GMTime { - std::time_t time_; - std::tm tm_; - - GMTime(std::time_t t): time_(t) {} - - bool run() { - using namespace fmt::internal; - return handle(gmtime_r(&time_, &tm_)); - } - - bool handle(std::tm *tm) { return tm != FMT_NULL; } - - bool handle(internal::Null<>) { - using namespace fmt::internal; - return fallback(gmtime_s(&tm_, &time_)); - } - - bool fallback(int res) { return res == 0; } - - bool fallback(internal::Null<>) { - std::tm *tm = std::gmtime(&time_); - if (tm != FMT_NULL) tm_ = *tm; - return tm != FMT_NULL; - } - }; - GMTime gt(time); - if (gt.run()) - return gt.tm_; - // Too big time values may be unsupported. - FMT_THROW(fmt::FormatError("time_t value out of range")); - return std::tm(); -} -} //namespace fmt - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#endif // FMT_TIME_H_ diff --git a/dep/fmt/include/fmt/args.h b/dep/fmt/include/fmt/args.h new file mode 100644 index 00000000000..ad1654bbb60 --- /dev/null +++ b/dep/fmt/include/fmt/args.h @@ -0,0 +1,235 @@ +// Formatting library for C++ - dynamic argument lists +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_ARGS_H_ +#define FMT_ARGS_H_ + +#include // std::reference_wrapper +#include // std::unique_ptr +#include + +#include "core.h" + +FMT_BEGIN_NAMESPACE + +namespace detail { + +template struct is_reference_wrapper : std::false_type {}; +template +struct is_reference_wrapper> : std::true_type {}; + +template auto unwrap(const T& v) -> const T& { return v; } +template +auto unwrap(const std::reference_wrapper& v) -> const T& { + return static_cast(v); +} + +class dynamic_arg_list { + // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for + // templates it doesn't complain about inability to deduce single translation + // unit for placing vtable. So storage_node_base is made a fake template. + template struct node { + virtual ~node() = default; + std::unique_ptr> next; + }; + + template struct typed_node : node<> { + T value; + + template + FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} + + template + FMT_CONSTEXPR typed_node(const basic_string_view& arg) + : value(arg.data(), arg.size()) {} + }; + + std::unique_ptr> head_; + + public: + template auto push(const Arg& arg) -> const T& { + auto new_node = std::unique_ptr>(new typed_node(arg)); + auto& value = new_node->value; + new_node->next = std::move(head_); + head_ = std::move(new_node); + return value; + } +}; +} // namespace detail + +/** + \rst + A dynamic version of `fmt::format_arg_store`. + It's equipped with a storage to potentially temporary objects which lifetimes + could be shorter than the format arguments object. + + It can be implicitly converted into `~fmt::basic_format_args` for passing + into type-erased formatting functions such as `~fmt::vformat`. + \endrst + */ +template +class dynamic_format_arg_store +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif +{ + private: + using char_type = typename Context::char_type; + + template struct need_copy { + static constexpr detail::type mapped_type = + detail::mapped_type_constant::value; + + enum { + value = !(detail::is_reference_wrapper::value || + std::is_same>::value || + std::is_same>::value || + (mapped_type != detail::type::cstring_type && + mapped_type != detail::type::string_type && + mapped_type != detail::type::custom_type)) + }; + }; + + template + using stored_type = conditional_t< + std::is_convertible>::value && + !detail::is_reference_wrapper::value, + std::basic_string, T>; + + // Storage of basic_format_arg must be contiguous. + std::vector> data_; + std::vector> named_info_; + + // Storage of arguments not fitting into basic_format_arg must grow + // without relocation because items in data_ refer to it. + detail::dynamic_arg_list dynamic_args_; + + friend class basic_format_args; + + auto get_types() const -> unsigned long long { + return detail::is_unpacked_bit | data_.size() | + (named_info_.empty() + ? 0ULL + : static_cast(detail::has_named_args_bit)); + } + + auto data() const -> const basic_format_arg* { + return named_info_.empty() ? data_.data() : data_.data() + 1; + } + + template void emplace_arg(const T& arg) { + data_.emplace_back(detail::make_arg(arg)); + } + + template + void emplace_arg(const detail::named_arg& arg) { + if (named_info_.empty()) { + constexpr const detail::named_arg_info* zero_ptr{nullptr}; + data_.insert(data_.begin(), {zero_ptr, 0}); + } + data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); + auto pop_one = [](std::vector>* data) { + data->pop_back(); + }; + std::unique_ptr>, decltype(pop_one)> + guard{&data_, pop_one}; + named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); + data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; + guard.release(); + } + + public: + constexpr dynamic_format_arg_store() = default; + + /** + \rst + Adds an argument into the dynamic store for later passing to a formatting + function. + + Note that custom types and string types (but not string views) are copied + into the store dynamically allocating memory if necessary. + + **Example**:: + + fmt::dynamic_format_arg_store store; + store.push_back(42); + store.push_back("abc"); + store.push_back(1.5f); + std::string result = fmt::vformat("{} and {} and {}", store); + \endrst + */ + template void push_back(const T& arg) { + if (detail::const_check(need_copy::value)) + emplace_arg(dynamic_args_.push>(arg)); + else + emplace_arg(detail::unwrap(arg)); + } + + /** + \rst + Adds a reference to the argument into the dynamic store for later passing to + a formatting function. + + **Example**:: + + fmt::dynamic_format_arg_store store; + char band[] = "Rolling Stones"; + store.push_back(std::cref(band)); + band[9] = 'c'; // Changing str affects the output. + std::string result = fmt::vformat("{}", store); + // result == "Rolling Scones" + \endrst + */ + template void push_back(std::reference_wrapper arg) { + static_assert( + need_copy::value, + "objects of built-in types and string views are always copied"); + emplace_arg(arg.get()); + } + + /** + Adds named argument into the dynamic store for later passing to a formatting + function. ``std::reference_wrapper`` is supported to avoid copying of the + argument. The name is always copied into the store. + */ + template + void push_back(const detail::named_arg& arg) { + const char_type* arg_name = + dynamic_args_.push>(arg.name).c_str(); + if (detail::const_check(need_copy::value)) { + emplace_arg( + fmt::arg(arg_name, dynamic_args_.push>(arg.value))); + } else { + emplace_arg(fmt::arg(arg_name, arg.value)); + } + } + + /** Erase all elements from the store */ + void clear() { + data_.clear(); + named_info_.clear(); + dynamic_args_ = detail::dynamic_arg_list(); + } + + /** + \rst + Reserves space to store at least *new_cap* arguments including + *new_cap_named* named arguments. + \endrst + */ + void reserve(size_t new_cap, size_t new_cap_named) { + FMT_ASSERT(new_cap >= new_cap_named, + "Set of arguments includes set of named arguments"); + data_.reserve(new_cap); + named_info_.reserve(new_cap_named); + } +}; + +FMT_END_NAMESPACE + +#endif // FMT_ARGS_H_ diff --git a/dep/fmt/include/fmt/chrono.h b/dep/fmt/include/fmt/chrono.h new file mode 100644 index 00000000000..9d54574e168 --- /dev/null +++ b/dep/fmt/include/fmt/chrono.h @@ -0,0 +1,2240 @@ +// Formatting library for C++ - chrono support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CHRONO_H_ +#define FMT_CHRONO_H_ + +#include +#include +#include // std::isfinite +#include // std::memcpy +#include +#include +#include +#include +#include + +#include "ostream.h" // formatbuf + +FMT_BEGIN_NAMESPACE + +// Check if std::chrono::local_t is available. +#ifndef FMT_USE_LOCAL_TIME +# ifdef __cpp_lib_chrono +# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L) +# else +# define FMT_USE_LOCAL_TIME 0 +# endif +#endif + +// Check if std::chrono::utc_timestamp is available. +#ifndef FMT_USE_UTC_TIME +# ifdef __cpp_lib_chrono +# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L) +# else +# define FMT_USE_UTC_TIME 0 +# endif +#endif + +// Enable tzset. +#ifndef FMT_USE_TZSET +// UWP doesn't provide _tzset. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# define FMT_USE_TZSET 1 +# else +# define FMT_USE_TZSET 0 +# endif +#endif + +// Enable safe chrono durations, unless explicitly disabled. +#ifndef FMT_SAFE_DURATION_CAST +# define FMT_SAFE_DURATION_CAST 1 +#endif +#if FMT_SAFE_DURATION_CAST + +// For conversion between std::chrono::durations without undefined +// behaviour or erroneous results. +// This is a stripped down version of duration_cast, for inclusion in fmt. +// See https://github.com/pauldreik/safe_duration_cast +// +// Copyright Paul Dreik 2019 +namespace safe_duration_cast { + +template ::value && + std::numeric_limits::is_signed == + std::numeric_limits::is_signed)> +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { + ec = 0; + using F = std::numeric_limits; + using T = std::numeric_limits; + static_assert(F::is_integer, "From must be integral"); + static_assert(T::is_integer, "To must be integral"); + + // A and B are both signed, or both unsigned. + if (detail::const_check(F::digits <= T::digits)) { + // From fits in To without any problem. + } else { + // From does not always fit in To, resort to a dynamic check. + if (from < (T::min)() || from > (T::max)()) { + // outside range. + ec = 1; + return {}; + } + } + return static_cast(from); +} + +/** + * converts From to To, without loss. If the dynamic value of from + * can't be converted to To without loss, ec is set. + */ +template ::value && + std::numeric_limits::is_signed != + std::numeric_limits::is_signed)> +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { + ec = 0; + using F = std::numeric_limits; + using T = std::numeric_limits; + static_assert(F::is_integer, "From must be integral"); + static_assert(T::is_integer, "To must be integral"); + + if (detail::const_check(F::is_signed && !T::is_signed)) { + // From may be negative, not allowed! + if (fmt::detail::is_negative(from)) { + ec = 1; + return {}; + } + // From is positive. Can it always fit in To? + if (detail::const_check(F::digits > T::digits) && + from > static_cast(detail::max_value())) { + ec = 1; + return {}; + } + } + + if (detail::const_check(!F::is_signed && T::is_signed && + F::digits >= T::digits) && + from > static_cast(detail::max_value())) { + ec = 1; + return {}; + } + return static_cast(from); // Lossless conversion. +} + +template ::value)> +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { + ec = 0; + return from; +} // function + +// clang-format off +/** + * converts From to To if possible, otherwise ec is set. + * + * input | output + * ---------------------------------|--------------- + * NaN | NaN + * Inf | Inf + * normal, fits in output | converted (possibly lossy) + * normal, does not fit in output | ec is set + * subnormal | best effort + * -Inf | -Inf + */ +// clang-format on +template ::value)> +FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To { + ec = 0; + using T = std::numeric_limits; + static_assert(std::is_floating_point::value, "From must be floating"); + static_assert(std::is_floating_point::value, "To must be floating"); + + // catch the only happy case + if (std::isfinite(from)) { + if (from >= T::lowest() && from <= (T::max)()) { + return static_cast(from); + } + // not within range. + ec = 1; + return {}; + } + + // nan and inf will be preserved + return static_cast(from); +} // function + +template ::value)> +FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To { + ec = 0; + static_assert(std::is_floating_point::value, "From must be floating"); + return from; +} + +/** + * safe duration cast between integral durations + */ +template ::value), + FMT_ENABLE_IF(std::is_integral::value)> +auto safe_duration_cast(std::chrono::duration from, + int& ec) -> To { + using From = std::chrono::duration; + ec = 0; + // the basic idea is that we need to convert from count() in the from type + // to count() in the To type, by multiplying it with this: + struct Factor + : std::ratio_divide {}; + + static_assert(Factor::num > 0, "num must be positive"); + static_assert(Factor::den > 0, "den must be positive"); + + // the conversion is like this: multiply from.count() with Factor::num + // /Factor::den and convert it to To::rep, all this without + // overflow/underflow. let's start by finding a suitable type that can hold + // both To, From and Factor::num + using IntermediateRep = + typename std::common_type::type; + + // safe conversion to IntermediateRep + IntermediateRep count = + lossless_integral_conversion(from.count(), ec); + if (ec) return {}; + // multiply with Factor::num without overflow or underflow + if (detail::const_check(Factor::num != 1)) { + const auto max1 = detail::max_value() / Factor::num; + if (count > max1) { + ec = 1; + return {}; + } + const auto min1 = + (std::numeric_limits::min)() / Factor::num; + if (detail::const_check(!std::is_unsigned::value) && + count < min1) { + ec = 1; + return {}; + } + count *= Factor::num; + } + + if (detail::const_check(Factor::den != 1)) count /= Factor::den; + auto tocount = lossless_integral_conversion(count, ec); + return ec ? To() : To(tocount); +} + +/** + * safe duration_cast between floating point durations + */ +template ::value), + FMT_ENABLE_IF(std::is_floating_point::value)> +auto safe_duration_cast(std::chrono::duration from, + int& ec) -> To { + using From = std::chrono::duration; + ec = 0; + if (std::isnan(from.count())) { + // nan in, gives nan out. easy. + return To{std::numeric_limits::quiet_NaN()}; + } + // maybe we should also check if from is denormal, and decide what to do about + // it. + + // +-inf should be preserved. + if (std::isinf(from.count())) { + return To{from.count()}; + } + + // the basic idea is that we need to convert from count() in the from type + // to count() in the To type, by multiplying it with this: + struct Factor + : std::ratio_divide {}; + + static_assert(Factor::num > 0, "num must be positive"); + static_assert(Factor::den > 0, "den must be positive"); + + // the conversion is like this: multiply from.count() with Factor::num + // /Factor::den and convert it to To::rep, all this without + // overflow/underflow. let's start by finding a suitable type that can hold + // both To, From and Factor::num + using IntermediateRep = + typename std::common_type::type; + + // force conversion of From::rep -> IntermediateRep to be safe, + // even if it will never happen be narrowing in this context. + IntermediateRep count = + safe_float_conversion(from.count(), ec); + if (ec) { + return {}; + } + + // multiply with Factor::num without overflow or underflow + if (detail::const_check(Factor::num != 1)) { + constexpr auto max1 = detail::max_value() / + static_cast(Factor::num); + if (count > max1) { + ec = 1; + return {}; + } + constexpr auto min1 = std::numeric_limits::lowest() / + static_cast(Factor::num); + if (count < min1) { + ec = 1; + return {}; + } + count *= static_cast(Factor::num); + } + + // this can't go wrong, right? den>0 is checked earlier. + if (detail::const_check(Factor::den != 1)) { + using common_t = typename std::common_type::type; + count /= static_cast(Factor::den); + } + + // convert to the to type, safely + using ToRep = typename To::rep; + + const ToRep tocount = safe_float_conversion(count, ec); + if (ec) { + return {}; + } + return To{tocount}; +} +} // namespace safe_duration_cast +#endif + +// Prevents expansion of a preceding token as a function-style macro. +// Usage: f FMT_NOMACRO() +#define FMT_NOMACRO + +namespace detail { +template struct null {}; +inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); } +inline auto localtime_s(...) -> null<> { return null<>(); } +inline auto gmtime_r(...) -> null<> { return null<>(); } +inline auto gmtime_s(...) -> null<> { return null<>(); } + +inline auto get_classic_locale() -> const std::locale& { + static const auto& locale = std::locale::classic(); + return locale; +} + +template struct codecvt_result { + static constexpr const size_t max_size = 32; + CodeUnit buf[max_size]; + CodeUnit* end; +}; + +template +void write_codecvt(codecvt_result& out, string_view in_buf, + const std::locale& loc) { +#if FMT_CLANG_VERSION +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" + auto& f = std::use_facet>(loc); +# pragma clang diagnostic pop +#else + auto& f = std::use_facet>(loc); +#endif + auto mb = std::mbstate_t(); + const char* from_next = nullptr; + auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, + std::begin(out.buf), std::end(out.buf), out.end); + if (result != std::codecvt_base::ok) + FMT_THROW(format_error("failed to format time")); +} + +template +auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) + -> OutputIt { + if (detail::is_utf8() && loc != get_classic_locale()) { + // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and + // gcc-4. +#if FMT_MSC_VERSION != 0 || \ + (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) + // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 + // and newer. + using code_unit = wchar_t; +#else + using code_unit = char32_t; +#endif + + using unit_t = codecvt_result; + unit_t unit; + write_codecvt(unit, in, loc); + // In UTF-8 is used one to four one-byte code units. + auto u = + to_utf8>(); + if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)})) + FMT_THROW(format_error("failed to format time")); + return copy_str(u.c_str(), u.c_str() + u.size(), out); + } + return copy_str(in.data(), in.data() + in.size(), out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + codecvt_result unit; + write_codecvt(unit, sv, loc); + return copy_str(unit.buf, unit.end, out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + return write_encoded_tm_str(out, sv, loc); +} + +template +inline void do_write(buffer& buf, const std::tm& time, + const std::locale& loc, char format, char modifier) { + auto&& format_buf = formatbuf>(buf); + auto&& os = std::basic_ostream(&format_buf); + os.imbue(loc); + const auto& facet = std::use_facet>(loc); + auto end = facet.put(os, os, Char(' '), &time, format, modifier); + if (end.failed()) FMT_THROW(format_error("failed to format time")); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = get_buffer(out); + do_write(buf, time, loc, format, modifier); + return get_iterator(buf, out); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = basic_memory_buffer(); + do_write(buf, time, loc, format, modifier); + return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); +} + +template +struct is_same_arithmetic_type + : public std::integral_constant::value && + std::is_integral::value) || + (std::is_floating_point::value && + std::is_floating_point::value)> { +}; + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(is_same_arithmetic_type::value)> +auto fmt_duration_cast(std::chrono::duration from) -> To { +#if FMT_SAFE_DURATION_CAST + // Throwing version of safe_duration_cast is only available for + // integer to integer or float to float casts. + int ec; + To to = safe_duration_cast::safe_duration_cast(from, ec); + if (ec) FMT_THROW(format_error("cannot format duration")); + return to; +#else + // Standard duration cast, may overflow. + return std::chrono::duration_cast(from); +#endif +} + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(!is_same_arithmetic_type::value)> +auto fmt_duration_cast(std::chrono::duration from) -> To { + // Mixed integer <-> float cast is not supported by safe_duration_cast. + return std::chrono::duration_cast(from); +} + +template +auto to_time_t( + std::chrono::time_point time_point) + -> std::time_t { + // Cannot use std::chrono::system_clock::to_time_t since this would first + // require a cast to std::chrono::system_clock::time_point, which could + // overflow. + return fmt_duration_cast>( + time_point.time_since_epoch()) + .count(); +} +} // namespace detail + +FMT_BEGIN_EXPORT + +/** + Converts given time since epoch as ``std::time_t`` value into calendar time, + expressed in local time. Unlike ``std::localtime``, this function is + thread-safe on most platforms. + */ +inline auto localtime(std::time_t time) -> std::tm { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + dispatcher(std::time_t t) : time_(t) {} + + auto run() -> bool { + using namespace fmt::detail; + return handle(localtime_r(&time_, &tm_)); + } + + auto handle(std::tm* tm) -> bool { return tm != nullptr; } + + auto handle(detail::null<>) -> bool { + using namespace fmt::detail; + return fallback(localtime_s(&tm_, &time_)); + } + + auto fallback(int res) -> bool { return res == 0; } + +#if !FMT_MSC_VERSION + auto fallback(detail::null<>) -> bool { + using namespace fmt::detail; + std::tm* tm = std::localtime(&time_); + if (tm) tm_ = *tm; + return tm != nullptr; + } +#endif + }; + dispatcher lt(time); + // Too big time values may be unsupported. + if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); + return lt.tm_; +} + +#if FMT_USE_LOCAL_TIME +template +inline auto localtime(std::chrono::local_time time) -> std::tm { + return localtime( + detail::to_time_t(std::chrono::current_zone()->to_sys(time))); +} +#endif + +/** + Converts given time since epoch as ``std::time_t`` value into calendar time, + expressed in Coordinated Universal Time (UTC). Unlike ``std::gmtime``, this + function is thread-safe on most platforms. + */ +inline auto gmtime(std::time_t time) -> std::tm { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + dispatcher(std::time_t t) : time_(t) {} + + auto run() -> bool { + using namespace fmt::detail; + return handle(gmtime_r(&time_, &tm_)); + } + + auto handle(std::tm* tm) -> bool { return tm != nullptr; } + + auto handle(detail::null<>) -> bool { + using namespace fmt::detail; + return fallback(gmtime_s(&tm_, &time_)); + } + + auto fallback(int res) -> bool { return res == 0; } + +#if !FMT_MSC_VERSION + auto fallback(detail::null<>) -> bool { + std::tm* tm = std::gmtime(&time_); + if (tm) tm_ = *tm; + return tm != nullptr; + } +#endif + }; + auto gt = dispatcher(time); + // Too big time values may be unsupported. + if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); + return gt.tm_; +} + +template +inline auto gmtime( + std::chrono::time_point time_point) + -> std::tm { + return gmtime(detail::to_time_t(time_point)); +} + +namespace detail { + +// Writes two-digit numbers a, b and c separated by sep to buf. +// The method by Pavel Novikov based on +// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. +inline void write_digit2_separated(char* buf, unsigned a, unsigned b, + unsigned c, char sep) { + unsigned long long digits = + a | (b << 24) | (static_cast(c) << 48); + // Convert each value to BCD. + // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. + // The difference is + // y - x = a * 6 + // a can be found from x: + // a = floor(x / 10) + // then + // y = x + a * 6 = x + floor(x / 10) * 6 + // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). + digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; + // Put low nibbles to high bytes and high nibbles to low bytes. + digits = ((digits & 0x00f00000f00000f0) >> 4) | + ((digits & 0x000f00000f00000f) << 8); + auto usep = static_cast(sep); + // Add ASCII '0' to each digit byte and insert separators. + digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); + + constexpr const size_t len = 8; + if (const_check(is_big_endian())) { + char tmp[len]; + std::memcpy(tmp, &digits, len); + std::reverse_copy(tmp, tmp + len, buf); + } else { + std::memcpy(buf, &digits, len); + } +} + +template +FMT_CONSTEXPR inline auto get_units() -> const char* { + if (std::is_same::value) return "as"; + if (std::is_same::value) return "fs"; + if (std::is_same::value) return "ps"; + if (std::is_same::value) return "ns"; + if (std::is_same::value) return "µs"; + if (std::is_same::value) return "ms"; + if (std::is_same::value) return "cs"; + if (std::is_same::value) return "ds"; + if (std::is_same>::value) return "s"; + if (std::is_same::value) return "das"; + if (std::is_same::value) return "hs"; + if (std::is_same::value) return "ks"; + if (std::is_same::value) return "Ms"; + if (std::is_same::value) return "Gs"; + if (std::is_same::value) return "Ts"; + if (std::is_same::value) return "Ps"; + if (std::is_same::value) return "Es"; + if (std::is_same>::value) return "min"; + if (std::is_same>::value) return "h"; + if (std::is_same>::value) return "d"; + return nullptr; +} + +enum class numeric_system { + standard, + // Alternative numeric system, e.g. å二 instead of 12 in ja_JP locale. + alternative +}; + +// Glibc extensions for formatting numeric values. +enum class pad_type { + unspecified, + // Do not pad a numeric result string. + none, + // Pad a numeric result string with zeros even if the conversion specifier + // character uses space-padding by default. + zero, + // Pad a numeric result string with spaces. + space, +}; + +template +auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt { + if (pad == pad_type::none) return out; + return std::fill_n(out, width, pad == pad_type::space ? ' ' : '0'); +} + +template +auto write_padding(OutputIt out, pad_type pad) -> OutputIt { + if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0'; + return out; +} + +// Parses a put_time-like format string and invokes handler actions. +template +FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + if (begin == end || *begin == '}') return begin; + if (*begin != '%') FMT_THROW(format_error("invalid format")); + auto ptr = begin; + pad_type pad = pad_type::unspecified; + while (ptr != end) { + auto c = *ptr; + if (c == '}') break; + if (c != '%') { + ++ptr; + continue; + } + if (begin != ptr) handler.on_text(begin, ptr); + ++ptr; // consume '%' + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr; + switch (c) { + case '_': + pad = pad_type::space; + ++ptr; + break; + case '-': + pad = pad_type::none; + ++ptr; + break; + case '0': + pad = pad_type::zero; + ++ptr; + break; + } + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case '%': + handler.on_text(ptr - 1, ptr); + break; + case 'n': { + const Char newline[] = {'\n'}; + handler.on_text(newline, newline + 1); + break; + } + case 't': { + const Char tab[] = {'\t'}; + handler.on_text(tab, tab + 1); + break; + } + // Year: + case 'Y': + handler.on_year(numeric_system::standard); + break; + case 'y': + handler.on_short_year(numeric_system::standard); + break; + case 'C': + handler.on_century(numeric_system::standard); + break; + case 'G': + handler.on_iso_week_based_year(); + break; + case 'g': + handler.on_iso_week_based_short_year(); + break; + // Day of the week: + case 'a': + handler.on_abbr_weekday(); + break; + case 'A': + handler.on_full_weekday(); + break; + case 'w': + handler.on_dec0_weekday(numeric_system::standard); + break; + case 'u': + handler.on_dec1_weekday(numeric_system::standard); + break; + // Month: + case 'b': + case 'h': + handler.on_abbr_month(); + break; + case 'B': + handler.on_full_month(); + break; + case 'm': + handler.on_dec_month(numeric_system::standard); + break; + // Day of the year/month: + case 'U': + handler.on_dec0_week_of_year(numeric_system::standard); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::standard); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::standard); + break; + case 'j': + handler.on_day_of_year(); + break; + case 'd': + handler.on_day_of_month(numeric_system::standard); + break; + case 'e': + handler.on_day_of_month_space(numeric_system::standard); + break; + // Hour, minute, second: + case 'H': + handler.on_24_hour(numeric_system::standard, pad); + break; + case 'I': + handler.on_12_hour(numeric_system::standard, pad); + break; + case 'M': + handler.on_minute(numeric_system::standard, pad); + break; + case 'S': + handler.on_second(numeric_system::standard, pad); + break; + // Other: + case 'c': + handler.on_datetime(numeric_system::standard); + break; + case 'x': + handler.on_loc_date(numeric_system::standard); + break; + case 'X': + handler.on_loc_time(numeric_system::standard); + break; + case 'D': + handler.on_us_date(); + break; + case 'F': + handler.on_iso_date(); + break; + case 'r': + handler.on_12_hour_time(); + break; + case 'R': + handler.on_24_hour_time(); + break; + case 'T': + handler.on_iso_time(); + break; + case 'p': + handler.on_am_pm(); + break; + case 'Q': + handler.on_duration_value(); + break; + case 'q': + handler.on_duration_unit(); + break; + case 'z': + handler.on_utc_offset(numeric_system::standard); + break; + case 'Z': + handler.on_tz_name(); + break; + // Alternative representation: + case 'E': { + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case 'Y': + handler.on_year(numeric_system::alternative); + break; + case 'y': + handler.on_offset_year(); + break; + case 'C': + handler.on_century(numeric_system::alternative); + break; + case 'c': + handler.on_datetime(numeric_system::alternative); + break; + case 'x': + handler.on_loc_date(numeric_system::alternative); + break; + case 'X': + handler.on_loc_time(numeric_system::alternative); + break; + case 'z': + handler.on_utc_offset(numeric_system::alternative); + break; + default: + FMT_THROW(format_error("invalid format")); + } + break; + } + case 'O': + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case 'y': + handler.on_short_year(numeric_system::alternative); + break; + case 'm': + handler.on_dec_month(numeric_system::alternative); + break; + case 'U': + handler.on_dec0_week_of_year(numeric_system::alternative); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::alternative); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::alternative); + break; + case 'd': + handler.on_day_of_month(numeric_system::alternative); + break; + case 'e': + handler.on_day_of_month_space(numeric_system::alternative); + break; + case 'w': + handler.on_dec0_weekday(numeric_system::alternative); + break; + case 'u': + handler.on_dec1_weekday(numeric_system::alternative); + break; + case 'H': + handler.on_24_hour(numeric_system::alternative, pad); + break; + case 'I': + handler.on_12_hour(numeric_system::alternative, pad); + break; + case 'M': + handler.on_minute(numeric_system::alternative, pad); + break; + case 'S': + handler.on_second(numeric_system::alternative, pad); + break; + case 'z': + handler.on_utc_offset(numeric_system::alternative); + break; + default: + FMT_THROW(format_error("invalid format")); + } + break; + default: + FMT_THROW(format_error("invalid format")); + } + begin = ptr; + } + if (begin != ptr) handler.on_text(begin, ptr); + return ptr; +} + +template struct null_chrono_spec_handler { + FMT_CONSTEXPR void unsupported() { + static_cast(this)->unsupported(); + } + FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_offset_year() { unsupported(); } + FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); } + FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } + FMT_CONSTEXPR void on_full_weekday() { unsupported(); } + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_abbr_month() { unsupported(); } + FMT_CONSTEXPR void on_full_month() { unsupported(); } + FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_year() { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_month_space(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_us_date() { unsupported(); } + FMT_CONSTEXPR void on_iso_date() { unsupported(); } + FMT_CONSTEXPR void on_12_hour_time() { unsupported(); } + FMT_CONSTEXPR void on_24_hour_time() { unsupported(); } + FMT_CONSTEXPR void on_iso_time() { unsupported(); } + FMT_CONSTEXPR void on_am_pm() { unsupported(); } + FMT_CONSTEXPR void on_duration_value() { unsupported(); } + FMT_CONSTEXPR void on_duration_unit() { unsupported(); } + FMT_CONSTEXPR void on_utc_offset(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_tz_name() { unsupported(); } +}; + +struct tm_format_checker : null_chrono_spec_handler { + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_year(numeric_system) {} + FMT_CONSTEXPR void on_short_year(numeric_system) {} + FMT_CONSTEXPR void on_offset_year() {} + FMT_CONSTEXPR void on_century(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_based_year() {} + FMT_CONSTEXPR void on_iso_week_based_short_year() {} + FMT_CONSTEXPR void on_abbr_weekday() {} + FMT_CONSTEXPR void on_full_weekday() {} + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} + FMT_CONSTEXPR void on_abbr_month() {} + FMT_CONSTEXPR void on_full_month() {} + FMT_CONSTEXPR void on_dec_month(numeric_system) {} + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_day_of_month(numeric_system) {} + FMT_CONSTEXPR void on_day_of_month_space(numeric_system) {} + FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_datetime(numeric_system) {} + FMT_CONSTEXPR void on_loc_date(numeric_system) {} + FMT_CONSTEXPR void on_loc_time(numeric_system) {} + FMT_CONSTEXPR void on_us_date() {} + FMT_CONSTEXPR void on_iso_date() {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_utc_offset(numeric_system) {} + FMT_CONSTEXPR void on_tz_name() {} +}; + +inline auto tm_wday_full_name(int wday) -> const char* { + static constexpr const char* full_name_list[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; +} +inline auto tm_wday_short_name(int wday) -> const char* { + static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; +} + +inline auto tm_mon_full_name(int mon) -> const char* { + static constexpr const char* full_name_list[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; + return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; +} +inline auto tm_mon_short_name(int mon) -> const char* { + static constexpr const char* short_name_list[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; +} + +template +struct has_member_data_tm_gmtoff : std::false_type {}; +template +struct has_member_data_tm_gmtoff> + : std::true_type {}; + +template +struct has_member_data_tm_zone : std::false_type {}; +template +struct has_member_data_tm_zone> + : std::true_type {}; + +#if FMT_USE_TZSET +inline void tzset_once() { + static bool init = []() -> bool { + _tzset(); + return true; + }(); + ignore_unused(init); +} +#endif + +// Converts value to Int and checks that it's in the range [0, upper). +template ::value)> +inline auto to_nonnegative_int(T value, Int upper) -> Int { + if (!std::is_unsigned::value && + (value < 0 || to_unsigned(value) > to_unsigned(upper))) { + FMT_THROW(fmt::format_error("chrono value is out of range")); + } + return static_cast(value); +} +template ::value)> +inline auto to_nonnegative_int(T value, Int upper) -> Int { + if (value < 0 || value > static_cast(upper)) + FMT_THROW(format_error("invalid value")); + return static_cast(value); +} + +constexpr auto pow10(std::uint32_t n) -> long long { + return n == 0 ? 1 : 10 * pow10(n - 1); +} + +// Counts the number of fractional digits in the range [0, 18] according to the +// C++20 spec. If more than 18 fractional digits are required then returns 6 for +// microseconds precision. +template () / 10)> +struct count_fractional_digits { + static constexpr int value = + Num % Den == 0 ? N : count_fractional_digits::value; +}; + +// Base case that doesn't instantiate any more templates +// in order to avoid overflow. +template +struct count_fractional_digits { + static constexpr int value = (Num % Den == 0) ? N : 6; +}; + +// Format subseconds which are given as an integer type with an appropriate +// number of digits. +template +void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) { + constexpr auto num_fractional_digits = + count_fractional_digits::value; + + using subsecond_precision = std::chrono::duration< + typename std::common_type::type, + std::ratio<1, detail::pow10(num_fractional_digits)>>; + + const auto fractional = d - fmt_duration_cast(d); + const auto subseconds = + std::chrono::treat_as_floating_point< + typename subsecond_precision::rep>::value + ? fractional.count() + : fmt_duration_cast(fractional).count(); + auto n = static_cast>(subseconds); + const int num_digits = detail::count_digits(n); + + int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits); + if (precision < 0) { + FMT_ASSERT(!std::is_floating_point::value, ""); + if (std::ratio_less::value) { + *out++ = '.'; + out = std::fill_n(out, leading_zeroes, '0'); + out = format_decimal(out, n, num_digits).end; + } + } else { + *out++ = '.'; + leading_zeroes = (std::min)(leading_zeroes, precision); + out = std::fill_n(out, leading_zeroes, '0'); + int remaining = precision - leading_zeroes; + if (remaining != 0 && remaining < num_digits) { + n /= to_unsigned(detail::pow10(to_unsigned(num_digits - remaining))); + out = format_decimal(out, n, remaining).end; + return; + } + out = format_decimal(out, n, num_digits).end; + remaining -= num_digits; + out = std::fill_n(out, remaining, '0'); + } +} + +// Format subseconds which are given as a floating point type with an +// appropriate number of digits. We cannot pass the Duration here, as we +// explicitly need to pass the Rep value in the chrono_formatter. +template +void write_floating_seconds(memory_buffer& buf, Duration duration, + int num_fractional_digits = -1) { + using rep = typename Duration::rep; + FMT_ASSERT(std::is_floating_point::value, ""); + + auto val = duration.count(); + + if (num_fractional_digits < 0) { + // For `std::round` with fallback to `round`: + // On some toolchains `std::round` is not available (e.g. GCC 6). + using namespace std; + num_fractional_digits = + count_fractional_digits::value; + if (num_fractional_digits < 6 && static_cast(round(val)) != val) + num_fractional_digits = 6; + } + + fmt::format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"), + std::fmod(val * static_cast(Duration::period::num) / + static_cast(Duration::period::den), + static_cast(60)), + num_fractional_digits); +} + +template +class tm_writer { + private: + static constexpr int days_per_week = 7; + + const std::locale& loc_; + const bool is_classic_; + OutputIt out_; + const Duration* subsecs_; + const std::tm& tm_; + + auto tm_sec() const noexcept -> int { + FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); + return tm_.tm_sec; + } + auto tm_min() const noexcept -> int { + FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); + return tm_.tm_min; + } + auto tm_hour() const noexcept -> int { + FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); + return tm_.tm_hour; + } + auto tm_mday() const noexcept -> int { + FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); + return tm_.tm_mday; + } + auto tm_mon() const noexcept -> int { + FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); + return tm_.tm_mon; + } + auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } + auto tm_wday() const noexcept -> int { + FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); + return tm_.tm_wday; + } + auto tm_yday() const noexcept -> int { + FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); + return tm_.tm_yday; + } + + auto tm_hour12() const noexcept -> int { + const auto h = tm_hour(); + const auto z = h < 12 ? h : h - 12; + return z == 0 ? 12 : z; + } + + // POSIX and the C Standard are unclear or inconsistent about what %C and %y + // do if the year is negative or exceeds 9999. Use the convention that %C + // concatenated with %y yields the same output as %Y, and that %Y contains at + // least 4 characters, with more only if necessary. + auto split_year_lower(long long year) const noexcept -> int { + auto l = year % 100; + if (l < 0) l = -l; // l in [0, 99] + return static_cast(l); + } + + // Algorithm: https://en.wikipedia.org/wiki/ISO_week_date. + auto iso_year_weeks(long long curr_year) const noexcept -> int { + const auto prev_year = curr_year - 1; + const auto curr_p = + (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % + days_per_week; + const auto prev_p = + (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % + days_per_week; + return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); + } + auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { + return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / + days_per_week; + } + auto tm_iso_week_year() const noexcept -> long long { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return year - 1; + if (w > iso_year_weeks(year)) return year + 1; + return year; + } + auto tm_iso_week_of_year() const noexcept -> int { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return iso_year_weeks(year - 1); + if (w > iso_year_weeks(year)) return 1; + return w; + } + + void write1(int value) { + *out_++ = static_cast('0' + to_unsigned(value) % 10); + } + void write2(int value) { + const char* d = digits2(to_unsigned(value) % 100); + *out_++ = *d++; + *out_++ = *d; + } + void write2(int value, pad_type pad) { + unsigned int v = to_unsigned(value) % 100; + if (v >= 10) { + const char* d = digits2(v); + *out_++ = *d++; + *out_++ = *d; + } else { + out_ = detail::write_padding(out_, pad); + *out_++ = static_cast('0' + v); + } + } + + void write_year_extended(long long year) { + // At least 4 characters. + int width = 4; + if (year < 0) { + *out_++ = '-'; + year = 0 - year; + --width; + } + uint32_or_64_or_128_t n = to_unsigned(year); + const int num_digits = count_digits(n); + if (width > num_digits) out_ = std::fill_n(out_, width - num_digits, '0'); + out_ = format_decimal(out_, n, num_digits).end; + } + void write_year(long long year) { + if (year >= 0 && year < 10000) { + write2(static_cast(year / 100)); + write2(static_cast(year % 100)); + } else { + write_year_extended(year); + } + } + + void write_utc_offset(long offset, numeric_system ns) { + if (offset < 0) { + *out_++ = '-'; + offset = -offset; + } else { + *out_++ = '+'; + } + offset /= 60; + write2(static_cast(offset / 60)); + if (ns != numeric_system::standard) *out_++ = ':'; + write2(static_cast(offset % 60)); + } + template ::value)> + void format_utc_offset_impl(const T& tm, numeric_system ns) { + write_utc_offset(tm.tm_gmtoff, ns); + } + template ::value)> + void format_utc_offset_impl(const T& tm, numeric_system ns) { +#if defined(_WIN32) && defined(_UCRT) +# if FMT_USE_TZSET + tzset_once(); +# endif + long offset = 0; + _get_timezone(&offset); + if (tm.tm_isdst) { + long dstbias = 0; + _get_dstbias(&dstbias); + offset += dstbias; + } + write_utc_offset(-offset, ns); +#else + if (ns == numeric_system::standard) return format_localized('z'); + + // Extract timezone offset from timezone conversion functions. + std::tm gtm = tm; + std::time_t gt = std::mktime(>m); + std::tm ltm = gmtime(gt); + std::time_t lt = std::mktime(<m); + long offset = gt - lt; + write_utc_offset(offset, ns); +#endif + } + + template ::value)> + void format_tz_name_impl(const T& tm) { + if (is_classic_) + out_ = write_tm_str(out_, tm.tm_zone, loc_); + else + format_localized('Z'); + } + template ::value)> + void format_tz_name_impl(const T&) { + format_localized('Z'); + } + + void format_localized(char format, char modifier = 0) { + out_ = write(out_, tm_, loc_, format, modifier); + } + + public: + tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm, + const Duration* subsecs = nullptr) + : loc_(loc), + is_classic_(loc_ == get_classic_locale()), + out_(out), + subsecs_(subsecs), + tm_(tm) {} + + auto out() const -> OutputIt { return out_; } + + FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { + out_ = copy_str(begin, end, out_); + } + + void on_abbr_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_short_name(tm_wday())); + else + format_localized('a'); + } + void on_full_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_full_name(tm_wday())); + else + format_localized('A'); + } + void on_dec0_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); + format_localized('w', 'O'); + } + void on_dec1_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write1(wday == 0 ? days_per_week : wday); + } else { + format_localized('u', 'O'); + } + } + + void on_abbr_month() { + if (is_classic_) + out_ = write(out_, tm_mon_short_name(tm_mon())); + else + format_localized('b'); + } + void on_full_month() { + if (is_classic_) + out_ = write(out_, tm_mon_full_name(tm_mon())); + else + format_localized('B'); + } + + void on_datetime(numeric_system ns) { + if (is_classic_) { + on_abbr_weekday(); + *out_++ = ' '; + on_abbr_month(); + *out_++ = ' '; + on_day_of_month_space(numeric_system::standard); + *out_++ = ' '; + on_iso_time(); + *out_++ = ' '; + on_year(numeric_system::standard); + } else { + format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); + } + } + void on_loc_date(numeric_system ns) { + if (is_classic_) + on_us_date(); + else + format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_loc_time(numeric_system ns) { + if (is_classic_) + on_iso_time(); + else + format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_us_date() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_mon() + 1), + to_unsigned(tm_mday()), + to_unsigned(split_year_lower(tm_year())), '/'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + } + void on_iso_date() { + auto year = tm_year(); + char buf[10]; + size_t offset = 0; + if (year >= 0 && year < 10000) { + copy2(buf, digits2(static_cast(year / 100))); + } else { + offset = 4; + write_year_extended(year); + year = 0; + } + write_digit2_separated(buf + 2, static_cast(year % 100), + to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), + '-'); + out_ = copy_str(std::begin(buf) + offset, std::end(buf), out_); + } + + void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); } + void on_tz_name() { format_tz_name_impl(tm_); } + + void on_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write_year(tm_year()); + format_localized('Y', 'E'); + } + void on_short_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(split_year_lower(tm_year())); + format_localized('y', 'O'); + } + void on_offset_year() { + if (is_classic_) return write2(split_year_lower(tm_year())); + format_localized('y', 'E'); + } + + void on_century(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto year = tm_year(); + auto upper = year / 100; + if (year >= -99 && year < 0) { + // Zero upper on negative year. + *out_++ = '-'; + *out_++ = '0'; + } else if (upper >= 0 && upper < 100) { + write2(static_cast(upper)); + } else { + out_ = write(out_, upper); + } + } else { + format_localized('C', 'E'); + } + } + + void on_dec_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mon() + 1); + format_localized('m', 'O'); + } + + void on_dec0_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week); + format_localized('U', 'O'); + } + void on_dec1_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write2((tm_yday() + days_per_week - + (wday == 0 ? (days_per_week - 1) : (wday - 1))) / + days_per_week); + } else { + format_localized('W', 'O'); + } + } + void on_iso_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_iso_week_of_year()); + format_localized('V', 'O'); + } + + void on_iso_week_based_year() { write_year(tm_iso_week_year()); } + void on_iso_week_based_short_year() { + write2(split_year_lower(tm_iso_week_year())); + } + + void on_day_of_year() { + auto yday = tm_yday() + 1; + write1(yday / 100); + write2(yday % 100); + } + void on_day_of_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday()); + format_localized('d', 'O'); + } + void on_day_of_month_space(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto mday = to_unsigned(tm_mday()) % 100; + const char* d2 = digits2(mday); + *out_++ = mday < 10 ? ' ' : d2[0]; + *out_++ = d2[1]; + } else { + format_localized('e', 'O'); + } + } + + void on_24_hour(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour(), pad); + format_localized('H', 'O'); + } + void on_12_hour(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour12(), pad); + format_localized('I', 'O'); + } + void on_minute(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_min(), pad); + format_localized('M', 'O'); + } + + void on_second(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) { + write2(tm_sec(), pad); + if (subsecs_) { + if (std::is_floating_point::value) { + auto buf = memory_buffer(); + write_floating_seconds(buf, *subsecs_); + if (buf.size() > 1) { + // Remove the leading "0", write something like ".123". + out_ = std::copy(buf.begin() + 1, buf.end(), out_); + } + } else { + write_fractional_seconds(out_, *subsecs_); + } + } + } else { + // Currently no formatting of subseconds when a locale is set. + format_localized('S', 'O'); + } + } + + void on_12_hour_time() { + if (is_classic_) { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour12()), + to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + *out_++ = ' '; + on_am_pm(); + } else { + format_localized('r'); + } + } + void on_24_hour_time() { + write2(tm_hour()); + *out_++ = ':'; + write2(tm_min()); + } + void on_iso_time() { + on_24_hour_time(); + *out_++ = ':'; + on_second(numeric_system::standard, pad_type::unspecified); + } + + void on_am_pm() { + if (is_classic_) { + *out_++ = tm_hour() < 12 ? 'A' : 'P'; + *out_++ = 'M'; + } else { + format_localized('p'); + } + } + + // These apply to chrono durations but not tm. + void on_duration_value() {} + void on_duration_unit() {} +}; + +struct chrono_format_checker : null_chrono_spec_handler { + bool has_precision_integral = false; + + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_duration_value() const { + if (has_precision_integral) { + FMT_THROW(format_error("precision not allowed for this argument type")); + } + } + FMT_CONSTEXPR void on_duration_unit() {} +}; + +template ::value&& has_isfinite::value)> +inline auto isfinite(T) -> bool { + return true; +} + +template ::value)> +inline auto mod(T x, int y) -> T { + return x % static_cast(y); +} +template ::value)> +inline auto mod(T x, int y) -> T { + return std::fmod(x, static_cast(y)); +} + +// If T is an integral type, maps T to its unsigned counterpart, otherwise +// leaves it unchanged (unlike std::make_unsigned). +template ::value> +struct make_unsigned_or_unchanged { + using type = T; +}; + +template struct make_unsigned_or_unchanged { + using type = typename std::make_unsigned::type; +}; + +template ::value)> +inline auto get_milliseconds(std::chrono::duration d) + -> std::chrono::duration { + // this may overflow and/or the result may not fit in the + // target type. +#if FMT_SAFE_DURATION_CAST + using CommonSecondsType = + typename std::common_type::type; + const auto d_as_common = fmt_duration_cast(d); + const auto d_as_whole_seconds = + fmt_duration_cast(d_as_common); + // this conversion should be nonproblematic + const auto diff = d_as_common - d_as_whole_seconds; + const auto ms = + fmt_duration_cast>(diff); + return ms; +#else + auto s = fmt_duration_cast(d); + return fmt_duration_cast(d - s); +#endif +} + +template ::value)> +auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt { + return write(out, val); +} + +template ::value)> +auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt { + auto specs = format_specs(); + specs.precision = precision; + specs.type = precision >= 0 ? presentation_type::fixed_lower + : presentation_type::general_lower; + return write(out, val, specs); +} + +template +auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt { + return std::copy(unit.begin(), unit.end(), out); +} + +template +auto copy_unit(string_view unit, OutputIt out, wchar_t) -> OutputIt { + // This works when wchar_t is UTF-32 because units only contain characters + // that have the same representation in UTF-16 and UTF-32. + utf8_to_utf16 u(unit); + return std::copy(u.c_str(), u.c_str() + u.size(), out); +} + +template +auto format_duration_unit(OutputIt out) -> OutputIt { + if (const char* unit = get_units()) + return copy_unit(string_view(unit), out, Char()); + *out++ = '['; + out = write(out, Period::num); + if (const_check(Period::den != 1)) { + *out++ = '/'; + out = write(out, Period::den); + } + *out++ = ']'; + *out++ = 's'; + return out; +} + +class get_locale { + private: + union { + std::locale locale_; + }; + bool has_locale_ = false; + + public: + get_locale(bool localized, locale_ref loc) : has_locale_(localized) { + if (localized) + ::new (&locale_) std::locale(loc.template get()); + } + ~get_locale() { + if (has_locale_) locale_.~locale(); + } + operator const std::locale&() const { + return has_locale_ ? locale_ : get_classic_locale(); + } +}; + +template +struct chrono_formatter { + FormatContext& context; + OutputIt out; + int precision; + bool localized = false; + // rep is unsigned to avoid overflow. + using rep = + conditional_t::value && sizeof(Rep) < sizeof(int), + unsigned, typename make_unsigned_or_unchanged::type>; + rep val; + using seconds = std::chrono::duration; + seconds s; + using milliseconds = std::chrono::duration; + bool negative; + + using char_type = typename FormatContext::char_type; + using tm_writer_type = tm_writer; + + chrono_formatter(FormatContext& ctx, OutputIt o, + std::chrono::duration d) + : context(ctx), + out(o), + val(static_cast(d.count())), + negative(false) { + if (d.count() < 0) { + val = 0 - val; + negative = true; + } + + // this may overflow and/or the result may not fit in the + // target type. + // might need checked conversion (rep!=Rep) + s = fmt_duration_cast(std::chrono::duration(val)); + } + + // returns true if nan or inf, writes to out. + auto handle_nan_inf() -> bool { + if (isfinite(val)) { + return false; + } + if (isnan(val)) { + write_nan(); + return true; + } + // must be +-inf + if (val > 0) { + write_pinf(); + } else { + write_ninf(); + } + return true; + } + + auto days() const -> Rep { return static_cast(s.count() / 86400); } + auto hour() const -> Rep { + return static_cast(mod((s.count() / 3600), 24)); + } + + auto hour12() const -> Rep { + Rep hour = static_cast(mod((s.count() / 3600), 12)); + return hour <= 0 ? 12 : hour; + } + + auto minute() const -> Rep { + return static_cast(mod((s.count() / 60), 60)); + } + auto second() const -> Rep { return static_cast(mod(s.count(), 60)); } + + auto time() const -> std::tm { + auto time = std::tm(); + time.tm_hour = to_nonnegative_int(hour(), 24); + time.tm_min = to_nonnegative_int(minute(), 60); + time.tm_sec = to_nonnegative_int(second(), 60); + return time; + } + + void write_sign() { + if (negative) { + *out++ = '-'; + negative = false; + } + } + + void write(Rep value, int width, pad_type pad = pad_type::unspecified) { + write_sign(); + if (isnan(value)) return write_nan(); + uint32_or_64_or_128_t n = + to_unsigned(to_nonnegative_int(value, max_value())); + int num_digits = detail::count_digits(n); + if (width > num_digits) { + out = detail::write_padding(out, pad, width - num_digits); + } + out = format_decimal(out, n, num_digits).end; + } + + void write_nan() { std::copy_n("nan", 3, out); } + void write_pinf() { std::copy_n("inf", 3, out); } + void write_ninf() { std::copy_n("-inf", 4, out); } + + template + void format_tm(const tm& time, Callback cb, Args... args) { + if (isnan(val)) return write_nan(); + get_locale loc(localized, context.locale()); + auto w = tm_writer_type(loc, out, time); + (w.*cb)(args...); + out = w.out(); + } + + void on_text(const char_type* begin, const char_type* end) { + std::copy(begin, end, out); + } + + // These are not implemented because durations don't have date information. + void on_abbr_weekday() {} + void on_full_weekday() {} + void on_dec0_weekday(numeric_system) {} + void on_dec1_weekday(numeric_system) {} + void on_abbr_month() {} + void on_full_month() {} + void on_datetime(numeric_system) {} + void on_loc_date(numeric_system) {} + void on_loc_time(numeric_system) {} + void on_us_date() {} + void on_iso_date() {} + void on_utc_offset(numeric_system) {} + void on_tz_name() {} + void on_year(numeric_system) {} + void on_short_year(numeric_system) {} + void on_offset_year() {} + void on_century(numeric_system) {} + void on_iso_week_based_year() {} + void on_iso_week_based_short_year() {} + void on_dec_month(numeric_system) {} + void on_dec0_week_of_year(numeric_system) {} + void on_dec1_week_of_year(numeric_system) {} + void on_iso_week_of_year(numeric_system) {} + void on_day_of_month(numeric_system) {} + void on_day_of_month_space(numeric_system) {} + + void on_day_of_year() { + if (handle_nan_inf()) return; + write(days(), 0); + } + + void on_24_hour(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(hour(), 2, pad); + auto time = tm(); + time.tm_hour = to_nonnegative_int(hour(), 24); + format_tm(time, &tm_writer_type::on_24_hour, ns, pad); + } + + void on_12_hour(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(hour12(), 2, pad); + auto time = tm(); + time.tm_hour = to_nonnegative_int(hour12(), 12); + format_tm(time, &tm_writer_type::on_12_hour, ns, pad); + } + + void on_minute(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(minute(), 2, pad); + auto time = tm(); + time.tm_min = to_nonnegative_int(minute(), 60); + format_tm(time, &tm_writer_type::on_minute, ns, pad); + } + + void on_second(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) { + if (std::is_floating_point::value) { + auto buf = memory_buffer(); + write_floating_seconds(buf, std::chrono::duration(val), + precision); + if (negative) *out++ = '-'; + if (buf.size() < 2 || buf[1] == '.') { + out = detail::write_padding(out, pad); + } + out = std::copy(buf.begin(), buf.end(), out); + } else { + write(second(), 2, pad); + write_fractional_seconds( + out, std::chrono::duration(val), precision); + } + return; + } + auto time = tm(); + time.tm_sec = to_nonnegative_int(second(), 60); + format_tm(time, &tm_writer_type::on_second, ns, pad); + } + + void on_12_hour_time() { + if (handle_nan_inf()) return; + format_tm(time(), &tm_writer_type::on_12_hour_time); + } + + void on_24_hour_time() { + if (handle_nan_inf()) { + *out++ = ':'; + handle_nan_inf(); + return; + } + + write(hour(), 2); + *out++ = ':'; + write(minute(), 2); + } + + void on_iso_time() { + on_24_hour_time(); + *out++ = ':'; + if (handle_nan_inf()) return; + on_second(numeric_system::standard, pad_type::unspecified); + } + + void on_am_pm() { + if (handle_nan_inf()) return; + format_tm(time(), &tm_writer_type::on_am_pm); + } + + void on_duration_value() { + if (handle_nan_inf()) return; + write_sign(); + out = format_duration_value(out, val, precision); + } + + void on_duration_unit() { + out = format_duration_unit(out); + } +}; + +} // namespace detail + +#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 +using weekday = std::chrono::weekday; +#else +// A fallback version of weekday. +class weekday { + private: + unsigned char value; + + public: + weekday() = default; + explicit constexpr weekday(unsigned wd) noexcept + : value(static_cast(wd != 7 ? wd : 0)) {} + constexpr auto c_encoding() const noexcept -> unsigned { return value; } +}; + +class year_month_day {}; +#endif + +// A rudimentary weekday formatter. +template struct formatter { + private: + bool localized = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto begin = ctx.begin(), end = ctx.end(); + if (begin != end && *begin == 'L') { + ++begin; + localized = true; + } + return begin; + } + + template + auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_wday = static_cast(wd.c_encoding()); + detail::get_locale loc(localized, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_weekday(); + return w.out(); + } +}; + +template +struct formatter, Char> { + private: + format_specs specs_; + detail::arg_ref width_ref_; + detail::arg_ref precision_ref_; + bool localized_ = false; + basic_string_view format_str_; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it == end) return it; + + auto checker = detail::chrono_format_checker(); + if (*it == '.') { + checker.has_precision_integral = !std::is_floating_point::value; + it = detail::parse_precision(it, end, specs_.precision, precision_ref_, + ctx); + } + if (it != end && *it == 'L') { + localized_ = true; + ++it; + } + end = detail::parse_chrono_format(it, end, checker); + format_str_ = {it, detail::to_unsigned(end - it)}; + return end; + } + + template + auto format(std::chrono::duration d, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs = specs_; + auto precision = specs.precision; + specs.precision = -1; + auto begin = format_str_.begin(), end = format_str_.end(); + // As a possible future optimization, we could avoid extra copying if width + // is not specified. + auto buf = basic_memory_buffer(); + auto out = std::back_inserter(buf); + detail::handle_dynamic_spec(specs.width, width_ref_, + ctx); + detail::handle_dynamic_spec(precision, + precision_ref_, ctx); + if (begin == end || *begin == '}') { + out = detail::format_duration_value(out, d.count(), precision); + detail::format_duration_unit(out); + } else { + using chrono_formatter = + detail::chrono_formatter; + auto f = chrono_formatter(ctx, out, d); + f.precision = precision; + f.localized = localized_; + detail::parse_chrono_format(begin, end, f); + } + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } +}; + +template +struct formatter, + Char> : formatter { + FMT_CONSTEXPR formatter() { + this->format_str_ = detail::string_literal{}; + } + + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + using period = typename Duration::period; + if (detail::const_check( + period::num != 1 || period::den != 1 || + std::is_floating_point::value)) { + const auto epoch = val.time_since_epoch(); + auto subsecs = detail::fmt_duration_cast( + epoch - detail::fmt_duration_cast(epoch)); + + if (subsecs.count() < 0) { + auto second = + detail::fmt_duration_cast(std::chrono::seconds(1)); + if (epoch.count() < ((Duration::min)() + second).count()) + FMT_THROW(format_error("duration is too small")); + subsecs += second; + val -= second; + } + + return formatter::do_format(gmtime(val), ctx, &subsecs); + } + + return formatter::format(gmtime(val), ctx); + } +}; + +#if FMT_USE_LOCAL_TIME +template +struct formatter, Char> + : formatter { + FMT_CONSTEXPR formatter() { + this->format_str_ = detail::string_literal{}; + } + + template + auto format(std::chrono::local_time val, FormatContext& ctx) const + -> decltype(ctx.out()) { + using period = typename Duration::period; + if (period::num != 1 || period::den != 1 || + std::is_floating_point::value) { + const auto epoch = val.time_since_epoch(); + const auto subsecs = detail::fmt_duration_cast( + epoch - detail::fmt_duration_cast(epoch)); + + return formatter::do_format(localtime(val), ctx, &subsecs); + } + + return formatter::format(localtime(val), ctx); + } +}; +#endif + +#if FMT_USE_UTC_TIME +template +struct formatter, + Char> + : formatter, + Char> { + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + return formatter< + std::chrono::time_point, + Char>::format(std::chrono::utc_clock::to_sys(val), ctx); + } +}; +#endif + +template struct formatter { + private: + format_specs specs_; + detail::arg_ref width_ref_; + + protected: + basic_string_view format_str_; + + template + auto do_format(const std::tm& tm, FormatContext& ctx, + const Duration* subsecs) const -> decltype(ctx.out()) { + auto specs = specs_; + auto buf = basic_memory_buffer(); + auto out = std::back_inserter(buf); + detail::handle_dynamic_spec(specs.width, width_ref_, + ctx); + + auto loc_ref = ctx.locale(); + detail::get_locale loc(static_cast(loc_ref), loc_ref); + auto w = + detail::tm_writer(loc, out, tm, subsecs); + detail::parse_chrono_format(format_str_.begin(), format_str_.end(), w); + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it == end) return it; + + end = detail::parse_chrono_format(it, end, detail::tm_format_checker()); + // Replace the default format_str only if the new spec is not empty. + if (end != it) format_str_ = {it, detail::to_unsigned(end - it)}; + return end; + } + + template + auto format(const std::tm& tm, FormatContext& ctx) const + -> decltype(ctx.out()) { + return do_format(tm, ctx, nullptr); + } +}; + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_CHRONO_H_ diff --git a/dep/fmt/include/fmt/color.h b/dep/fmt/include/fmt/color.h new file mode 100644 index 00000000000..367849a86a7 --- /dev/null +++ b/dep/fmt/include/fmt/color.h @@ -0,0 +1,643 @@ +// Formatting library for C++ - color support +// +// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COLOR_H_ +#define FMT_COLOR_H_ + +#include "format.h" + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +enum class color : uint32_t { + alice_blue = 0xF0F8FF, // rgb(240,248,255) + antique_white = 0xFAEBD7, // rgb(250,235,215) + aqua = 0x00FFFF, // rgb(0,255,255) + aquamarine = 0x7FFFD4, // rgb(127,255,212) + azure = 0xF0FFFF, // rgb(240,255,255) + beige = 0xF5F5DC, // rgb(245,245,220) + bisque = 0xFFE4C4, // rgb(255,228,196) + black = 0x000000, // rgb(0,0,0) + blanched_almond = 0xFFEBCD, // rgb(255,235,205) + blue = 0x0000FF, // rgb(0,0,255) + blue_violet = 0x8A2BE2, // rgb(138,43,226) + brown = 0xA52A2A, // rgb(165,42,42) + burly_wood = 0xDEB887, // rgb(222,184,135) + cadet_blue = 0x5F9EA0, // rgb(95,158,160) + chartreuse = 0x7FFF00, // rgb(127,255,0) + chocolate = 0xD2691E, // rgb(210,105,30) + coral = 0xFF7F50, // rgb(255,127,80) + cornflower_blue = 0x6495ED, // rgb(100,149,237) + cornsilk = 0xFFF8DC, // rgb(255,248,220) + crimson = 0xDC143C, // rgb(220,20,60) + cyan = 0x00FFFF, // rgb(0,255,255) + dark_blue = 0x00008B, // rgb(0,0,139) + dark_cyan = 0x008B8B, // rgb(0,139,139) + dark_golden_rod = 0xB8860B, // rgb(184,134,11) + dark_gray = 0xA9A9A9, // rgb(169,169,169) + dark_green = 0x006400, // rgb(0,100,0) + dark_khaki = 0xBDB76B, // rgb(189,183,107) + dark_magenta = 0x8B008B, // rgb(139,0,139) + dark_olive_green = 0x556B2F, // rgb(85,107,47) + dark_orange = 0xFF8C00, // rgb(255,140,0) + dark_orchid = 0x9932CC, // rgb(153,50,204) + dark_red = 0x8B0000, // rgb(139,0,0) + dark_salmon = 0xE9967A, // rgb(233,150,122) + dark_sea_green = 0x8FBC8F, // rgb(143,188,143) + dark_slate_blue = 0x483D8B, // rgb(72,61,139) + dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) + dark_turquoise = 0x00CED1, // rgb(0,206,209) + dark_violet = 0x9400D3, // rgb(148,0,211) + deep_pink = 0xFF1493, // rgb(255,20,147) + deep_sky_blue = 0x00BFFF, // rgb(0,191,255) + dim_gray = 0x696969, // rgb(105,105,105) + dodger_blue = 0x1E90FF, // rgb(30,144,255) + fire_brick = 0xB22222, // rgb(178,34,34) + floral_white = 0xFFFAF0, // rgb(255,250,240) + forest_green = 0x228B22, // rgb(34,139,34) + fuchsia = 0xFF00FF, // rgb(255,0,255) + gainsboro = 0xDCDCDC, // rgb(220,220,220) + ghost_white = 0xF8F8FF, // rgb(248,248,255) + gold = 0xFFD700, // rgb(255,215,0) + golden_rod = 0xDAA520, // rgb(218,165,32) + gray = 0x808080, // rgb(128,128,128) + green = 0x008000, // rgb(0,128,0) + green_yellow = 0xADFF2F, // rgb(173,255,47) + honey_dew = 0xF0FFF0, // rgb(240,255,240) + hot_pink = 0xFF69B4, // rgb(255,105,180) + indian_red = 0xCD5C5C, // rgb(205,92,92) + indigo = 0x4B0082, // rgb(75,0,130) + ivory = 0xFFFFF0, // rgb(255,255,240) + khaki = 0xF0E68C, // rgb(240,230,140) + lavender = 0xE6E6FA, // rgb(230,230,250) + lavender_blush = 0xFFF0F5, // rgb(255,240,245) + lawn_green = 0x7CFC00, // rgb(124,252,0) + lemon_chiffon = 0xFFFACD, // rgb(255,250,205) + light_blue = 0xADD8E6, // rgb(173,216,230) + light_coral = 0xF08080, // rgb(240,128,128) + light_cyan = 0xE0FFFF, // rgb(224,255,255) + light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) + light_gray = 0xD3D3D3, // rgb(211,211,211) + light_green = 0x90EE90, // rgb(144,238,144) + light_pink = 0xFFB6C1, // rgb(255,182,193) + light_salmon = 0xFFA07A, // rgb(255,160,122) + light_sea_green = 0x20B2AA, // rgb(32,178,170) + light_sky_blue = 0x87CEFA, // rgb(135,206,250) + light_slate_gray = 0x778899, // rgb(119,136,153) + light_steel_blue = 0xB0C4DE, // rgb(176,196,222) + light_yellow = 0xFFFFE0, // rgb(255,255,224) + lime = 0x00FF00, // rgb(0,255,0) + lime_green = 0x32CD32, // rgb(50,205,50) + linen = 0xFAF0E6, // rgb(250,240,230) + magenta = 0xFF00FF, // rgb(255,0,255) + maroon = 0x800000, // rgb(128,0,0) + medium_aquamarine = 0x66CDAA, // rgb(102,205,170) + medium_blue = 0x0000CD, // rgb(0,0,205) + medium_orchid = 0xBA55D3, // rgb(186,85,211) + medium_purple = 0x9370DB, // rgb(147,112,219) + medium_sea_green = 0x3CB371, // rgb(60,179,113) + medium_slate_blue = 0x7B68EE, // rgb(123,104,238) + medium_spring_green = 0x00FA9A, // rgb(0,250,154) + medium_turquoise = 0x48D1CC, // rgb(72,209,204) + medium_violet_red = 0xC71585, // rgb(199,21,133) + midnight_blue = 0x191970, // rgb(25,25,112) + mint_cream = 0xF5FFFA, // rgb(245,255,250) + misty_rose = 0xFFE4E1, // rgb(255,228,225) + moccasin = 0xFFE4B5, // rgb(255,228,181) + navajo_white = 0xFFDEAD, // rgb(255,222,173) + navy = 0x000080, // rgb(0,0,128) + old_lace = 0xFDF5E6, // rgb(253,245,230) + olive = 0x808000, // rgb(128,128,0) + olive_drab = 0x6B8E23, // rgb(107,142,35) + orange = 0xFFA500, // rgb(255,165,0) + orange_red = 0xFF4500, // rgb(255,69,0) + orchid = 0xDA70D6, // rgb(218,112,214) + pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) + pale_green = 0x98FB98, // rgb(152,251,152) + pale_turquoise = 0xAFEEEE, // rgb(175,238,238) + pale_violet_red = 0xDB7093, // rgb(219,112,147) + papaya_whip = 0xFFEFD5, // rgb(255,239,213) + peach_puff = 0xFFDAB9, // rgb(255,218,185) + peru = 0xCD853F, // rgb(205,133,63) + pink = 0xFFC0CB, // rgb(255,192,203) + plum = 0xDDA0DD, // rgb(221,160,221) + powder_blue = 0xB0E0E6, // rgb(176,224,230) + purple = 0x800080, // rgb(128,0,128) + rebecca_purple = 0x663399, // rgb(102,51,153) + red = 0xFF0000, // rgb(255,0,0) + rosy_brown = 0xBC8F8F, // rgb(188,143,143) + royal_blue = 0x4169E1, // rgb(65,105,225) + saddle_brown = 0x8B4513, // rgb(139,69,19) + salmon = 0xFA8072, // rgb(250,128,114) + sandy_brown = 0xF4A460, // rgb(244,164,96) + sea_green = 0x2E8B57, // rgb(46,139,87) + sea_shell = 0xFFF5EE, // rgb(255,245,238) + sienna = 0xA0522D, // rgb(160,82,45) + silver = 0xC0C0C0, // rgb(192,192,192) + sky_blue = 0x87CEEB, // rgb(135,206,235) + slate_blue = 0x6A5ACD, // rgb(106,90,205) + slate_gray = 0x708090, // rgb(112,128,144) + snow = 0xFFFAFA, // rgb(255,250,250) + spring_green = 0x00FF7F, // rgb(0,255,127) + steel_blue = 0x4682B4, // rgb(70,130,180) + tan = 0xD2B48C, // rgb(210,180,140) + teal = 0x008080, // rgb(0,128,128) + thistle = 0xD8BFD8, // rgb(216,191,216) + tomato = 0xFF6347, // rgb(255,99,71) + turquoise = 0x40E0D0, // rgb(64,224,208) + violet = 0xEE82EE, // rgb(238,130,238) + wheat = 0xF5DEB3, // rgb(245,222,179) + white = 0xFFFFFF, // rgb(255,255,255) + white_smoke = 0xF5F5F5, // rgb(245,245,245) + yellow = 0xFFFF00, // rgb(255,255,0) + yellow_green = 0x9ACD32 // rgb(154,205,50) +}; // enum class color + +enum class terminal_color : uint8_t { + black = 30, + red, + green, + yellow, + blue, + magenta, + cyan, + white, + bright_black = 90, + bright_red, + bright_green, + bright_yellow, + bright_blue, + bright_magenta, + bright_cyan, + bright_white +}; + +enum class emphasis : uint8_t { + bold = 1, + faint = 1 << 1, + italic = 1 << 2, + underline = 1 << 3, + blink = 1 << 4, + reverse = 1 << 5, + conceal = 1 << 6, + strikethrough = 1 << 7, +}; + +// rgb is a struct for red, green and blue colors. +// Using the name "rgb" makes some editors show the color in a tooltip. +struct rgb { + FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} + FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} + FMT_CONSTEXPR rgb(uint32_t hex) + : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} + FMT_CONSTEXPR rgb(color hex) + : r((uint32_t(hex) >> 16) & 0xFF), + g((uint32_t(hex) >> 8) & 0xFF), + b(uint32_t(hex) & 0xFF) {} + uint8_t r; + uint8_t g; + uint8_t b; +}; + +namespace detail { + +// color is a struct of either a rgb color or a terminal color. +struct color_type { + FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} + FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { + value.rgb_color = static_cast(rgb_color); + } + FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} { + value.rgb_color = (static_cast(rgb_color.r) << 16) | + (static_cast(rgb_color.g) << 8) | rgb_color.b; + } + FMT_CONSTEXPR color_type(terminal_color term_color) noexcept + : is_rgb(), value{} { + value.term_color = static_cast(term_color); + } + bool is_rgb; + union color_union { + uint8_t term_color; + uint32_t rgb_color; + } value; +}; +} // namespace detail + +/** A text style consisting of foreground and background colors and emphasis. */ +class text_style { + public: + FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept + : set_foreground_color(), set_background_color(), ems(em) {} + + FMT_CONSTEXPR auto operator|=(const text_style& rhs) -> text_style& { + if (!set_foreground_color) { + set_foreground_color = rhs.set_foreground_color; + foreground_color = rhs.foreground_color; + } else if (rhs.set_foreground_color) { + if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) + FMT_THROW(format_error("can't OR a terminal color")); + foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; + } + + if (!set_background_color) { + set_background_color = rhs.set_background_color; + background_color = rhs.background_color; + } else if (rhs.set_background_color) { + if (!background_color.is_rgb || !rhs.background_color.is_rgb) + FMT_THROW(format_error("can't OR a terminal color")); + background_color.value.rgb_color |= rhs.background_color.value.rgb_color; + } + + ems = static_cast(static_cast(ems) | + static_cast(rhs.ems)); + return *this; + } + + friend FMT_CONSTEXPR auto operator|(text_style lhs, const text_style& rhs) + -> text_style { + return lhs |= rhs; + } + + FMT_CONSTEXPR auto has_foreground() const noexcept -> bool { + return set_foreground_color; + } + FMT_CONSTEXPR auto has_background() const noexcept -> bool { + return set_background_color; + } + FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool { + return static_cast(ems) != 0; + } + FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type { + FMT_ASSERT(has_foreground(), "no foreground specified for this style"); + return foreground_color; + } + FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type { + FMT_ASSERT(has_background(), "no background specified for this style"); + return background_color; + } + FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis { + FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); + return ems; + } + + private: + FMT_CONSTEXPR text_style(bool is_foreground, + detail::color_type text_color) noexcept + : set_foreground_color(), set_background_color(), ems() { + if (is_foreground) { + foreground_color = text_color; + set_foreground_color = true; + } else { + background_color = text_color; + set_background_color = true; + } + } + + friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept + -> text_style; + + friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept + -> text_style; + + detail::color_type foreground_color; + detail::color_type background_color; + bool set_foreground_color; + bool set_background_color; + emphasis ems; +}; + +/** Creates a text style from the foreground (text) color. */ +FMT_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept + -> text_style { + return text_style(true, foreground); +} + +/** Creates a text style from the background color. */ +FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept + -> text_style { + return text_style(false, background); +} + +FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept + -> text_style { + return text_style(lhs) | rhs; +} + +namespace detail { + +template struct ansi_color_escape { + FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, + const char* esc) noexcept { + // If we have a terminal color, we need to output another escape code + // sequence. + if (!text_color.is_rgb) { + bool is_background = esc == string_view("\x1b[48;2;"); + uint32_t value = text_color.value.term_color; + // Background ASCII codes are the same as the foreground ones but with + // 10 more. + if (is_background) value += 10u; + + size_t index = 0; + buffer[index++] = static_cast('\x1b'); + buffer[index++] = static_cast('['); + + if (value >= 100u) { + buffer[index++] = static_cast('1'); + value %= 100u; + } + buffer[index++] = static_cast('0' + value / 10u); + buffer[index++] = static_cast('0' + value % 10u); + + buffer[index++] = static_cast('m'); + buffer[index++] = static_cast('\0'); + return; + } + + for (int i = 0; i < 7; i++) { + buffer[i] = static_cast(esc[i]); + } + rgb color(text_color.value.rgb_color); + to_esc(color.r, buffer + 7, ';'); + to_esc(color.g, buffer + 11, ';'); + to_esc(color.b, buffer + 15, 'm'); + buffer[19] = static_cast(0); + } + FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept { + uint8_t em_codes[num_emphases] = {}; + if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; + if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; + if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; + if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; + if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; + if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; + if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; + if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; + + size_t index = 0; + for (size_t i = 0; i < num_emphases; ++i) { + if (!em_codes[i]) continue; + buffer[index++] = static_cast('\x1b'); + buffer[index++] = static_cast('['); + buffer[index++] = static_cast('0' + em_codes[i]); + buffer[index++] = static_cast('m'); + } + buffer[index++] = static_cast(0); + } + FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } + + FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; } + FMT_CONSTEXPR_CHAR_TRAITS auto end() const noexcept -> const Char* { + return buffer + std::char_traits::length(buffer); + } + + private: + static constexpr size_t num_emphases = 8; + Char buffer[7u + 3u * num_emphases + 1u]; + + static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, + char delimiter) noexcept { + out[0] = static_cast('0' + c / 100); + out[1] = static_cast('0' + c / 10 % 10); + out[2] = static_cast('0' + c % 10); + out[3] = static_cast(delimiter); + } + static FMT_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept + -> bool { + return static_cast(em) & static_cast(mask); + } +}; + +template +FMT_CONSTEXPR auto make_foreground_color(detail::color_type foreground) noexcept + -> ansi_color_escape { + return ansi_color_escape(foreground, "\x1b[38;2;"); +} + +template +FMT_CONSTEXPR auto make_background_color(detail::color_type background) noexcept + -> ansi_color_escape { + return ansi_color_escape(background, "\x1b[48;2;"); +} + +template +FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept + -> ansi_color_escape { + return ansi_color_escape(em); +} + +template inline void reset_color(buffer& buffer) { + auto reset_color = string_view("\x1b[0m"); + buffer.append(reset_color.begin(), reset_color.end()); +} + +template struct styled_arg : detail::view { + const T& value; + text_style style; + styled_arg(const T& v, text_style s) : value(v), style(s) {} +}; + +template +void vformat_to(buffer& buf, const text_style& ts, + basic_string_view format_str, + basic_format_args>> args) { + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = detail::make_emphasis(ts.get_emphasis()); + buf.append(emphasis.begin(), emphasis.end()); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = detail::make_foreground_color(ts.get_foreground()); + buf.append(foreground.begin(), foreground.end()); + } + if (ts.has_background()) { + has_style = true; + auto background = detail::make_background_color(ts.get_background()); + buf.append(background.begin(), background.end()); + } + detail::vformat_to(buf, format_str, args, {}); + if (has_style) detail::reset_color(buf); +} + +} // namespace detail + +inline void vprint(std::FILE* f, const text_style& ts, string_view fmt, + format_args args) { + // Legacy wide streams are not supported. + auto buf = memory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + if (detail::is_utf8()) { + detail::print(f, string_view(buf.begin(), buf.size())); + return; + } + buf.push_back('\0'); + int result = std::fputs(buf.data(), f); + if (result < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); +} + +/** + \rst + Formats a string and prints it to the specified file stream using ANSI + escape sequences to specify text formatting. + + **Example**:: + + fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + "Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template ::value)> +void print(std::FILE* f, const text_style& ts, const S& format_str, + const Args&... args) { + vprint(f, ts, format_str, + fmt::make_format_args>>(args...)); +} + +/** + \rst + Formats a string and prints it to stdout using ANSI escape sequences to + specify text formatting. + + **Example**:: + + fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + "Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template ::value)> +void print(const text_style& ts, const S& format_str, const Args&... args) { + return print(stdout, ts, format_str, args...); +} + +template > +inline auto vformat( + const text_style& ts, const S& format_str, + basic_format_args>> args) + -> std::basic_string { + basic_memory_buffer buf; + detail::vformat_to(buf, ts, detail::to_string_view(format_str), args); + return fmt::to_string(buf); +} + +/** + \rst + Formats arguments and returns the result as a string using ANSI + escape sequences to specify text formatting. + + **Example**:: + + #include + std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), + "The answer is {}", 42); + \endrst +*/ +template > +inline auto format(const text_style& ts, const S& format_str, + const Args&... args) -> std::basic_string { + return fmt::vformat(ts, detail::to_string_view(format_str), + fmt::make_format_args>(args...)); +} + +/** + Formats a string with the given text_style and writes the output to ``out``. + */ +template ::value)> +auto vformat_to(OutputIt out, const text_style& ts, + basic_string_view format_str, + basic_format_args>> args) + -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, ts, format_str, args); + return detail::get_iterator(buf, out); +} + +/** + \rst + Formats arguments with the given text_style, writes the result to the output + iterator ``out`` and returns the iterator past the end of the output range. + + **Example**:: + + std::vector out; + fmt::format_to(std::back_inserter(out), + fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); + \endrst +*/ +template < + typename OutputIt, typename S, typename... Args, + bool enable = detail::is_output_iterator>::value && + detail::is_string::value> +inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, + Args&&... args) -> + typename std::enable_if::type { + return vformat_to(out, ts, detail::to_string_view(format_str), + fmt::make_format_args>>(args...)); +} + +template +struct formatter, Char> : formatter { + template + auto format(const detail::styled_arg& arg, FormatContext& ctx) const + -> decltype(ctx.out()) { + const auto& ts = arg.style; + const auto& value = arg.value; + auto out = ctx.out(); + + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = detail::make_emphasis(ts.get_emphasis()); + out = std::copy(emphasis.begin(), emphasis.end(), out); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = + detail::make_foreground_color(ts.get_foreground()); + out = std::copy(foreground.begin(), foreground.end(), out); + } + if (ts.has_background()) { + has_style = true; + auto background = + detail::make_background_color(ts.get_background()); + out = std::copy(background.begin(), background.end(), out); + } + out = formatter::format(value, ctx); + if (has_style) { + auto reset_color = string_view("\x1b[0m"); + out = std::copy(reset_color.begin(), reset_color.end(), out); + } + return out; + } +}; + +/** + \rst + Returns an argument that will be formatted using ANSI escape sequences, + to be used in a formatting function. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", + fmt::styled(1.23, fmt::fg(fmt::color::green) | + fmt::bg(fmt::color::blue))); + \endrst + */ +template +FMT_CONSTEXPR auto styled(const T& value, text_style ts) + -> detail::styled_arg> { + return detail::styled_arg>{value, ts}; +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_COLOR_H_ diff --git a/dep/fmt/include/fmt/compile.h b/dep/fmt/include/fmt/compile.h new file mode 100644 index 00000000000..3b3f166e0cd --- /dev/null +++ b/dep/fmt/include/fmt/compile.h @@ -0,0 +1,535 @@ +// Formatting library for C++ - experimental format string compilation +// +// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COMPILE_H_ +#define FMT_COMPILE_H_ + +#include "format.h" + +FMT_BEGIN_NAMESPACE +namespace detail { + +template +FMT_CONSTEXPR inline auto copy_str(InputIt begin, InputIt end, + counting_iterator it) -> counting_iterator { + return it + (end - begin); +} + +// A compile-time string which is compiled into fast formatting code. +class compiled_string {}; + +template +struct is_compiled_string : std::is_base_of {}; + +/** + \rst + Converts a string literal *s* into a format string that will be parsed at + compile time and converted into efficient formatting code. Requires C++17 + ``constexpr if`` compiler support. + + **Example**:: + + // Converts 42 into std::string using the most efficient method and no + // runtime format string processing. + std::string s = fmt::format(FMT_COMPILE("{}"), 42); + \endrst + */ +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +# define FMT_COMPILE(s) \ + FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) +#else +# define FMT_COMPILE(s) FMT_STRING(s) +#endif + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template Str> +struct udl_compiled_string : compiled_string { + using char_type = Char; + explicit constexpr operator basic_string_view() const { + return {Str.data, N - 1}; + } +}; +#endif + +template +auto first(const T& value, const Tail&...) -> const T& { + return value; +} + +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +template struct type_list {}; + +// Returns a reference to the argument at index N from [first, rest...]. +template +constexpr const auto& get([[maybe_unused]] const T& first, + [[maybe_unused]] const Args&... rest) { + static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); + if constexpr (N == 0) + return first; + else + return detail::get(rest...); +} + +template +constexpr int get_arg_index_by_name(basic_string_view name, + type_list) { + return get_arg_index_by_name(name); +} + +template struct get_type_impl; + +template struct get_type_impl> { + using type = + remove_cvref_t(std::declval()...))>; +}; + +template +using get_type = typename get_type_impl::type; + +template struct is_compiled_format : std::false_type {}; + +template struct text { + basic_string_view data; + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&...) const { + return write(out, data); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template +constexpr text make_text(basic_string_view s, size_t pos, + size_t size) { + return {{&s[pos], size}}; +} + +template struct code_unit { + Char value; + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&...) const { + *out++ = value; + return out; + } +}; + +// This ensures that the argument type is convertible to `const T&`. +template +constexpr const T& get_arg_checked(const Args&... args) { + const auto& arg = detail::get(args...); + if constexpr (detail::is_named_arg>()) { + return arg.value; + } else { + return arg; + } +} + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument N. +template struct field { + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + const T& arg = get_arg_checked(args...); + if constexpr (std::is_convertible_v>) { + auto s = basic_string_view(arg); + return copy_str(s.begin(), s.end(), out); + } + return write(out, arg); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument with name. +template struct runtime_named_field { + using char_type = Char; + basic_string_view name; + + template + constexpr static bool try_format_argument( + OutputIt& out, + // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 + [[maybe_unused]] basic_string_view arg_name, const T& arg) { + if constexpr (is_named_arg::type>::value) { + if (arg_name == arg.name) { + out = write(out, arg.value); + return true; + } + } + return false; + } + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + bool found = (try_format_argument(out, name, args) || ...); + if (!found) { + FMT_THROW(format_error("argument with specified name is not found")); + } + return out; + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument N and has format specifiers. +template struct spec_field { + using char_type = Char; + formatter fmt; + + template + constexpr FMT_INLINE OutputIt format(OutputIt out, + const Args&... args) const { + const auto& vargs = + fmt::make_format_args>(args...); + basic_format_context ctx(out, vargs); + return fmt.format(get_arg_checked(args...), ctx); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template struct concat { + L lhs; + R rhs; + using char_type = typename L::char_type; + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + out = lhs.format(out, args...); + return rhs.format(out, args...); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template +constexpr concat make_concat(L lhs, R rhs) { + return {lhs, rhs}; +} + +struct unknown_format {}; + +template +constexpr size_t parse_text(basic_string_view str, size_t pos) { + for (size_t size = str.size(); pos != size; ++pos) { + if (str[pos] == '{' || str[pos] == '}') break; + } + return pos; +} + +template +constexpr auto compile_format_string(S format_str); + +template +constexpr auto parse_tail(T head, S format_str) { + if constexpr (POS != + basic_string_view(format_str).size()) { + constexpr auto tail = compile_format_string(format_str); + if constexpr (std::is_same, + unknown_format>()) + return tail; + else + return make_concat(head, tail); + } else { + return head; + } +} + +template struct parse_specs_result { + formatter fmt; + size_t end; + int next_arg_id; +}; + +enum { manual_indexing_id = -1 }; + +template +constexpr parse_specs_result parse_specs(basic_string_view str, + size_t pos, int next_arg_id) { + str.remove_prefix(pos); + auto ctx = + compile_parse_context(str, max_value(), nullptr, next_arg_id); + auto f = formatter(); + auto end = f.parse(ctx); + return {f, pos + fmt::detail::to_unsigned(end - str.data()), + next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; +} + +template struct arg_id_handler { + arg_ref arg_id; + + constexpr int on_auto() { + FMT_ASSERT(false, "handler cannot be used with automatic indexing"); + return 0; + } + constexpr int on_index(int id) { + arg_id = arg_ref(id); + return 0; + } + constexpr int on_name(basic_string_view id) { + arg_id = arg_ref(id); + return 0; + } +}; + +template struct parse_arg_id_result { + arg_ref arg_id; + const Char* arg_id_end; +}; + +template +constexpr auto parse_arg_id(const Char* begin, const Char* end) { + auto handler = arg_id_handler{arg_ref{}}; + auto arg_id_end = parse_arg_id(begin, end, handler); + return parse_arg_id_result{handler.arg_id, arg_id_end}; +} + +template struct field_type { + using type = remove_cvref_t; +}; + +template +struct field_type::value>> { + using type = remove_cvref_t; +}; + +template +constexpr auto parse_replacement_field_then_tail(S format_str) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(format_str); + constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); + if constexpr (c == '}') { + return parse_tail( + field::type, ARG_INDEX>(), + format_str); + } else if constexpr (c != ':') { + FMT_THROW(format_error("expected ':'")); + } else { + constexpr auto result = parse_specs::type>( + str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); + if constexpr (result.end >= str.size() || str[result.end] != '}') { + FMT_THROW(format_error("expected '}'")); + return 0; + } else { + return parse_tail( + spec_field::type, ARG_INDEX>{ + result.fmt}, + format_str); + } + } +} + +// Compiles a non-empty format string and returns the compiled representation +// or unknown_format() on unrecognized input. +template +constexpr auto compile_format_string(S format_str) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(format_str); + if constexpr (str[POS] == '{') { + if constexpr (POS + 1 == str.size()) + FMT_THROW(format_error("unmatched '{' in format string")); + if constexpr (str[POS + 1] == '{') { + return parse_tail(make_text(str, POS, 1), format_str); + } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { + static_assert(ID != manual_indexing_id, + "cannot switch from manual to automatic argument indexing"); + constexpr auto next_id = + ID != manual_indexing_id ? ID + 1 : manual_indexing_id; + return parse_replacement_field_then_tail, Args, + POS + 1, ID, next_id>( + format_str); + } else { + constexpr auto arg_id_result = + parse_arg_id(str.data() + POS + 1, str.data() + str.size()); + constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); + constexpr char_type c = + arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); + static_assert(c == '}' || c == ':', "missing '}' in format string"); + if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { + static_assert( + ID == manual_indexing_id || ID == 0, + "cannot switch from automatic to manual argument indexing"); + constexpr auto arg_index = arg_id_result.arg_id.val.index; + return parse_replacement_field_then_tail, + Args, arg_id_end_pos, + arg_index, manual_indexing_id>( + format_str); + } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { + constexpr auto arg_index = + get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); + if constexpr (arg_index >= 0) { + constexpr auto next_id = + ID != manual_indexing_id ? ID + 1 : manual_indexing_id; + return parse_replacement_field_then_tail< + decltype(get_type::value), Args, arg_id_end_pos, + arg_index, next_id>(format_str); + } else if constexpr (c == '}') { + return parse_tail( + runtime_named_field{arg_id_result.arg_id.val.name}, + format_str); + } else if constexpr (c == ':') { + return unknown_format(); // no type info for specs parsing + } + } + } + } else if constexpr (str[POS] == '}') { + if constexpr (POS + 1 == str.size()) + FMT_THROW(format_error("unmatched '}' in format string")); + return parse_tail(make_text(str, POS, 1), format_str); + } else { + constexpr auto end = parse_text(str, POS + 1); + if constexpr (end - POS > 1) { + return parse_tail(make_text(str, POS, end - POS), + format_str); + } else { + return parse_tail(code_unit{str[POS]}, + format_str); + } + } +} + +template ::value)> +constexpr auto compile(S format_str) { + constexpr auto str = basic_string_view(format_str); + if constexpr (str.size() == 0) { + return detail::make_text(str, 0, 0); + } else { + constexpr auto result = + detail::compile_format_string, 0, 0>( + format_str); + return result; + } +} +#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +} // namespace detail + +FMT_BEGIN_EXPORT + +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) + +template ::value)> +FMT_INLINE std::basic_string format(const CompiledFormat& cf, + const Args&... args) { + auto s = std::basic_string(); + cf.format(std::back_inserter(s), args...); + return s; +} + +template ::value)> +constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, + const Args&... args) { + return cf.format(out, args...); +} + +template ::value)> +FMT_INLINE std::basic_string format(const S&, + Args&&... args) { + if constexpr (std::is_same::value) { + constexpr auto str = basic_string_view(S()); + if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { + const auto& first = detail::first(args...); + if constexpr (detail::is_named_arg< + remove_cvref_t>::value) { + return fmt::to_string(first.value); + } else { + return fmt::to_string(first); + } + } + } + constexpr auto compiled = detail::compile(S()); + if constexpr (std::is_same, + detail::unknown_format>()) { + return fmt::format( + static_cast>(S()), + std::forward(args)...); + } else { + return fmt::format(compiled, std::forward(args)...); + } +} + +template ::value)> +FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { + constexpr auto compiled = detail::compile(S()); + if constexpr (std::is_same, + detail::unknown_format>()) { + return fmt::format_to( + out, static_cast>(S()), + std::forward(args)...); + } else { + return fmt::format_to(out, compiled, std::forward(args)...); + } +} +#endif + +template ::value)> +auto format_to_n(OutputIt out, size_t n, const S& format_str, Args&&... args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + fmt::format_to(std::back_inserter(buf), format_str, + std::forward(args)...); + return {buf.out(), buf.count()}; +} + +template ::value)> +FMT_CONSTEXPR20 auto formatted_size(const S& format_str, const Args&... args) + -> size_t { + return fmt::format_to(detail::counting_iterator(), format_str, args...) + .count(); +} + +template ::value)> +void print(std::FILE* f, const S& format_str, const Args&... args) { + memory_buffer buffer; + fmt::format_to(std::back_inserter(buffer), format_str, args...); + detail::print(f, {buffer.data(), buffer.size()}); +} + +template ::value)> +void print(const S& format_str, const Args&... args) { + print(stdout, format_str, args...); +} + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +inline namespace literals { +template constexpr auto operator""_cf() { + using char_t = remove_cvref_t; + return detail::udl_compiled_string(); +} +} // namespace literals +#endif + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_COMPILE_H_ diff --git a/dep/fmt/include/fmt/core.h b/dep/fmt/include/fmt/core.h new file mode 100644 index 00000000000..b51c1406a99 --- /dev/null +++ b/dep/fmt/include/fmt/core.h @@ -0,0 +1,2969 @@ +// Formatting library for C++ - the core API for char/UTF-8 +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CORE_H_ +#define FMT_CORE_H_ + +#include // std::byte +#include // std::FILE +#include // std::strlen +#include +#include +#include // std::addressof +#include +#include + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 100201 + +#if defined(__clang__) && !defined(__ibmxl__) +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \ + !defined(__NVCOMPILER) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define FMT_GCC_VERSION 0 +#endif + +#ifndef FMT_GCC_PRAGMA +// Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884. +# if FMT_GCC_VERSION >= 504 +# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +# else +# define FMT_GCC_PRAGMA(arg) +# endif +#endif + +#ifdef __ICL +# define FMT_ICC_VERSION __ICL +#elif defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#else +# define FMT_ICC_VERSION 0 +#endif + +#ifdef _MSC_VER +# define FMT_MSC_VERSION _MSC_VER +# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) +#else +# define FMT_MSC_VERSION 0 +# define FMT_MSC_WARNING(...) +#endif + +#ifdef _MSVC_LANG +# define FMT_CPLUSPLUS _MSVC_LANG +#else +# define FMT_CPLUSPLUS __cplusplus +#endif + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#if defined(__has_include) || FMT_ICC_VERSION >= 1600 || FMT_MSC_VERSION > 1900 +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ + (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ + (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +// Check if relaxed C++14 constexpr is supported. +// GCC doesn't allow throw in constexpr until version 6 (bug 67371). +#ifndef FMT_USE_CONSTEXPR +# if (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 || \ + (FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L)) && \ + !FMT_ICC_VERSION && (!defined(__NVCC__) || FMT_CPLUSPLUS >= 202002L) +# define FMT_USE_CONSTEXPR 1 +# else +# define FMT_USE_CONSTEXPR 0 +# endif +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +#else +# define FMT_CONSTEXPR +#endif + +#if (FMT_CPLUSPLUS >= 202002L || \ + (FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002)) && \ + ((!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 10) && \ + (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 10000) && \ + (!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1928)) && \ + defined(__cpp_lib_is_constant_evaluated) +# define FMT_CONSTEXPR20 constexpr +#else +# define FMT_CONSTEXPR20 +#endif + +// Check if constexpr std::char_traits<>::{compare,length} are supported. +#if defined(__GLIBCXX__) +# if FMT_CPLUSPLUS >= 201703L && defined(_GLIBCXX_RELEASE) && \ + _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +# endif +#elif defined(_LIBCPP_VERSION) && FMT_CPLUSPLUS >= 201703L && \ + _LIBCPP_VERSION >= 4000 +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +#elif FMT_MSC_VERSION >= 1914 && FMT_CPLUSPLUS >= 201703L +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +#endif +#ifndef FMT_CONSTEXPR_CHAR_TRAITS +# define FMT_CONSTEXPR_CHAR_TRAITS +#endif + +// Check if exceptions are disabled. +#ifndef FMT_EXCEPTIONS +# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ + (FMT_MSC_VERSION && !_HAS_EXCEPTIONS) +# define FMT_EXCEPTIONS 0 +# else +# define FMT_EXCEPTIONS 1 +# endif +#endif + +// Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings. +#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \ + !defined(__NVCC__) +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +#ifndef FMT_NODISCARD +# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) +# define FMT_NODISCARD [[nodiscard]] +# else +# define FMT_NODISCARD +# endif +#endif + +#ifndef FMT_INLINE +# if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_INLINE inline __attribute__((always_inline)) +# else +# define FMT_INLINE inline +# endif +#endif + +#ifdef _MSC_VER +# define FMT_UNCHECKED_ITERATOR(It) \ + using _Unchecked_type = It // Mark iterator as checked. +#else +# define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# define FMT_BEGIN_NAMESPACE \ + namespace fmt { \ + inline namespace v10 { +# define FMT_END_NAMESPACE \ + } \ + } +#endif + +#ifndef FMT_EXPORT +# define FMT_EXPORT +# define FMT_BEGIN_EXPORT +# define FMT_END_EXPORT +#endif + +#if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_VISIBILITY(value) __attribute__((visibility(value))) +#else +# define FMT_VISIBILITY(value) +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# if defined(FMT_LIB_EXPORT) +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) +# define FMT_API FMT_VISIBILITY("default") +#endif +#ifndef FMT_API +# define FMT_API +#endif + +// libc++ supports string_view in pre-c++17. +#if FMT_HAS_INCLUDE() && \ + (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) +# include +# define FMT_USE_STRING_VIEW +#elif FMT_HAS_INCLUDE("experimental/string_view") && FMT_CPLUSPLUS >= 201402L +# include +# define FMT_USE_EXPERIMENTAL_STRING_VIEW +#endif + +#ifndef FMT_UNICODE +# define FMT_UNICODE !FMT_MSC_VERSION +#endif + +#ifndef FMT_CONSTEVAL +# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ + (!defined(__apple_build_version__) || \ + __apple_build_version__ >= 14000029L) && \ + FMT_CPLUSPLUS >= 202002L) || \ + (defined(__cpp_consteval) && \ + (!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1929)) +// consteval is broken in MSVC before VS2019 version 16.10 and Apple clang +// before 14. +# define FMT_CONSTEVAL consteval +# define FMT_HAS_CONSTEVAL +# else +# define FMT_CONSTEVAL +# endif +#endif + +#ifndef FMT_USE_NONTYPE_TEMPLATE_ARGS +# if defined(__cpp_nontype_template_args) && \ + ((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \ + __cpp_nontype_template_args >= 201911L) && \ + !defined(__NVCOMPILER) && !defined(__LCC__) +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +# else +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 +# endif +#endif + +// GCC < 5 requires this-> in decltype +#ifndef FMT_DECLTYPE_THIS +# if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +# define FMT_DECLTYPE_THIS this-> +# else +# define FMT_DECLTYPE_THIS +# endif +#endif + +// Enable minimal optimizations for more compact code in debug mode. +FMT_GCC_PRAGMA("GCC push_options") +#if !defined(__OPTIMIZE__) && !defined(__NVCOMPILER) && !defined(__LCC__) && \ + !defined(__CUDACC__) +FMT_GCC_PRAGMA("GCC optimize(\"Og\")") +#endif + +FMT_BEGIN_NAMESPACE + +// Implementations of enable_if_t and other metafunctions for older systems. +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; +template using bool_constant = std::integral_constant; +template +using remove_reference_t = typename std::remove_reference::type; +template +using remove_const_t = typename std::remove_const::type; +template +using remove_cvref_t = typename std::remove_cv>::type; +template struct type_identity { + using type = T; +}; +template using type_identity_t = typename type_identity::type; +template +using underlying_t = typename std::underlying_type::type; + +// Checks whether T is a container with contiguous storage. +template struct is_contiguous : std::false_type {}; +template +struct is_contiguous> : std::true_type {}; + +struct monostate { + constexpr monostate() {} +}; + +// An enable_if helper to be used in template parameters which results in much +// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed +// to workaround a bug in MSVC 2019 (see #1140 and #1186). +#ifdef FMT_DOC +# define FMT_ENABLE_IF(...) +#else +# define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0 +#endif + +// This is defined in core.h instead of format.h to avoid injecting in std. +// It is a template to avoid undesirable implicit conversions to std::byte. +#ifdef __cpp_lib_byte +template ::value)> +inline auto format_as(T b) -> unsigned char { + return static_cast(b); +} +#endif + +namespace detail { +// Suppresses "unused variable" warnings with the method described in +// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. +// (void)var does not work on many Intel compilers. +template FMT_CONSTEXPR void ignore_unused(const T&...) {} + +constexpr FMT_INLINE auto is_constant_evaluated( + bool default_value = false) noexcept -> bool { +// Workaround for incompatibility between libstdc++ consteval-based +// std::is_constant_evaluated() implementation and clang-14. +// https://github.com/fmtlib/fmt/issues/3247 +#if FMT_CPLUSPLUS >= 202002L && defined(_GLIBCXX_RELEASE) && \ + _GLIBCXX_RELEASE >= 12 && \ + (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500) + ignore_unused(default_value); + return __builtin_is_constant_evaluated(); +#elif defined(__cpp_lib_is_constant_evaluated) + ignore_unused(default_value); + return std::is_constant_evaluated(); +#else + return default_value; +#endif +} + +// Suppresses "conditional expression is constant" warnings. +template constexpr FMT_INLINE auto const_check(T value) -> T { + return value; +} + +FMT_NORETURN FMT_API void assert_fail(const char* file, int line, + const char* message); + +#ifndef FMT_ASSERT +# ifdef NDEBUG +// FMT_ASSERT is not empty to avoid -Wempty-body. +# define FMT_ASSERT(condition, message) \ + fmt::detail::ignore_unused((condition), (message)) +# else +# define FMT_ASSERT(condition, message) \ + ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ + ? (void)0 \ + : fmt::detail::assert_fail(__FILE__, __LINE__, (message))) +# endif +#endif + +#if defined(FMT_USE_STRING_VIEW) +template using std_string_view = std::basic_string_view; +#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) +template +using std_string_view = std::experimental::basic_string_view; +#else +template struct std_string_view {}; +#endif + +#ifdef FMT_USE_INT128 +// Do nothing. +#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ + !(FMT_CLANG_VERSION && FMT_MSC_VERSION) +# define FMT_USE_INT128 1 +using int128_opt = __int128_t; // An optional native 128-bit integer. +using uint128_opt = __uint128_t; +template inline auto convert_for_visit(T value) -> T { + return value; +} +#else +# define FMT_USE_INT128 0 +#endif +#if !FMT_USE_INT128 +enum class int128_opt {}; +enum class uint128_opt {}; +// Reduce template instantiations. +template auto convert_for_visit(T) -> monostate { return {}; } +#endif + +// Casts a nonnegative integer to unsigned. +template +FMT_CONSTEXPR auto to_unsigned(Int value) -> + typename std::make_unsigned::type { + FMT_ASSERT(std::is_unsigned::value || value >= 0, "negative value"); + return static_cast::type>(value); +} + +FMT_CONSTEXPR inline auto is_utf8() -> bool { + FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char section[] = "\u00A7"; + + // Avoid buggy sign extensions in MSVC's constant evaluation mode (#2297). + using uchar = unsigned char; + return FMT_UNICODE || (sizeof(section) == 3 && uchar(section[0]) == 0xC2 && + uchar(section[1]) == 0xA7); +} +} // namespace detail + +/** + An implementation of ``std::basic_string_view`` for pre-C++17. It provides a + subset of the API. ``fmt::basic_string_view`` is used for format strings even + if ``std::string_view`` is available to prevent issues when a library is + compiled with a different ``-std`` option than the client code (which is not + recommended). + */ +FMT_EXPORT +template class basic_string_view { + private: + const Char* data_; + size_t size_; + + public: + using value_type = Char; + using iterator = const Char*; + + constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {} + + /** Constructs a string reference object from a C string and a size. */ + constexpr basic_string_view(const Char* s, size_t count) noexcept + : data_(s), size_(count) {} + + /** + \rst + Constructs a string reference object from a C string computing + the size with ``std::char_traits::length``. + \endrst + */ + FMT_CONSTEXPR_CHAR_TRAITS + FMT_INLINE + basic_string_view(const Char* s) + : data_(s), + size_(detail::const_check(std::is_same::value && + !detail::is_constant_evaluated(true)) + ? std::strlen(reinterpret_cast(s)) + : std::char_traits::length(s)) {} + + /** Constructs a string reference from a ``std::basic_string`` object. */ + template + FMT_CONSTEXPR basic_string_view( + const std::basic_string& s) noexcept + : data_(s.data()), size_(s.size()) {} + + template >::value)> + FMT_CONSTEXPR basic_string_view(S s) noexcept + : data_(s.data()), size_(s.size()) {} + + /** Returns a pointer to the string data. */ + constexpr auto data() const noexcept -> const Char* { return data_; } + + /** Returns the string size. */ + constexpr auto size() const noexcept -> size_t { return size_; } + + constexpr auto begin() const noexcept -> iterator { return data_; } + constexpr auto end() const noexcept -> iterator { return data_ + size_; } + + constexpr auto operator[](size_t pos) const noexcept -> const Char& { + return data_[pos]; + } + + FMT_CONSTEXPR void remove_prefix(size_t n) noexcept { + data_ += n; + size_ -= n; + } + + FMT_CONSTEXPR_CHAR_TRAITS auto starts_with( + basic_string_view sv) const noexcept -> bool { + return size_ >= sv.size_ && + std::char_traits::compare(data_, sv.data_, sv.size_) == 0; + } + FMT_CONSTEXPR_CHAR_TRAITS auto starts_with(Char c) const noexcept -> bool { + return size_ >= 1 && std::char_traits::eq(*data_, c); + } + FMT_CONSTEXPR_CHAR_TRAITS auto starts_with(const Char* s) const -> bool { + return starts_with(basic_string_view(s)); + } + + // Lexicographically compare this string reference to other. + FMT_CONSTEXPR_CHAR_TRAITS auto compare(basic_string_view other) const -> int { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = std::char_traits::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + FMT_CONSTEXPR_CHAR_TRAITS friend auto operator==(basic_string_view lhs, + basic_string_view rhs) + -> bool { + return lhs.compare(rhs) == 0; + } + friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) != 0; + } + friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) < 0; + } + friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) <= 0; + } + friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) > 0; + } + friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) >= 0; + } +}; + +FMT_EXPORT +using string_view = basic_string_view; + +/** Specifies if ``T`` is a character type. Can be specialized by users. */ +FMT_EXPORT +template struct is_char : std::false_type {}; +template <> struct is_char : std::true_type {}; + +namespace detail { + +// A base class for compile-time strings. +struct compile_string {}; + +template +struct is_compile_string : std::is_base_of {}; + +template ::value)> +FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view { + return s; +} +template +inline auto to_string_view(const std::basic_string& s) + -> basic_string_view { + return s; +} +template +constexpr auto to_string_view(basic_string_view s) + -> basic_string_view { + return s; +} +template >::value)> +inline auto to_string_view(std_string_view s) -> basic_string_view { + return s; +} +template ::value)> +constexpr auto to_string_view(const S& s) + -> basic_string_view { + return basic_string_view(s); +} +void to_string_view(...); + +// Specifies whether S is a string type convertible to fmt::basic_string_view. +// It should be a constexpr function but MSVC 2017 fails to compile it in +// enable_if and MSVC 2015 fails to compile it as an alias template. +// ADL is intentionally disabled as to_string_view is not an extension point. +template +struct is_string + : std::is_class()))> {}; + +template struct char_t_impl {}; +template struct char_t_impl::value>> { + using result = decltype(to_string_view(std::declval())); + using type = typename result::value_type; +}; + +enum class type { + none_type, + // Integer types should go first, + int_type, + uint_type, + long_long_type, + ulong_long_type, + int128_type, + uint128_type, + bool_type, + char_type, + last_integer_type = char_type, + // followed by floating-point types. + float_type, + double_type, + long_double_type, + last_numeric_type = long_double_type, + cstring_type, + string_type, + pointer_type, + custom_type +}; + +// Maps core type T to the corresponding type enum constant. +template +struct type_constant : std::integral_constant {}; + +#define FMT_TYPE_CONSTANT(Type, constant) \ + template \ + struct type_constant \ + : std::integral_constant {} + +FMT_TYPE_CONSTANT(int, int_type); +FMT_TYPE_CONSTANT(unsigned, uint_type); +FMT_TYPE_CONSTANT(long long, long_long_type); +FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); +FMT_TYPE_CONSTANT(int128_opt, int128_type); +FMT_TYPE_CONSTANT(uint128_opt, uint128_type); +FMT_TYPE_CONSTANT(bool, bool_type); +FMT_TYPE_CONSTANT(Char, char_type); +FMT_TYPE_CONSTANT(float, float_type); +FMT_TYPE_CONSTANT(double, double_type); +FMT_TYPE_CONSTANT(long double, long_double_type); +FMT_TYPE_CONSTANT(const Char*, cstring_type); +FMT_TYPE_CONSTANT(basic_string_view, string_type); +FMT_TYPE_CONSTANT(const void*, pointer_type); + +constexpr auto is_integral_type(type t) -> bool { + return t > type::none_type && t <= type::last_integer_type; +} +constexpr auto is_arithmetic_type(type t) -> bool { + return t > type::none_type && t <= type::last_numeric_type; +} + +constexpr auto set(type rhs) -> int { return 1 << static_cast(rhs); } +constexpr auto in(type t, int set) -> bool { + return ((set >> static_cast(t)) & 1) != 0; +} + +// Bitsets of types. +enum { + sint_set = + set(type::int_type) | set(type::long_long_type) | set(type::int128_type), + uint_set = set(type::uint_type) | set(type::ulong_long_type) | + set(type::uint128_type), + bool_set = set(type::bool_type), + char_set = set(type::char_type), + float_set = set(type::float_type) | set(type::double_type) | + set(type::long_double_type), + string_set = set(type::string_type), + cstring_set = set(type::cstring_type), + pointer_set = set(type::pointer_type) +}; + +// DEPRECATED! +FMT_NORETURN FMT_API void throw_format_error(const char* message); + +struct error_handler { + constexpr error_handler() = default; + + // This function is intentionally not constexpr to give a compile-time error. + FMT_NORETURN void on_error(const char* message) { + throw_format_error(message); + } +}; +} // namespace detail + +/** Throws ``format_error`` with a given message. */ +using detail::throw_format_error; + +/** String's character type. */ +template using char_t = typename detail::char_t_impl::type; + +/** + \rst + Parsing context consisting of a format string range being parsed and an + argument counter for automatic indexing. + You can use the ``format_parse_context`` type alias for ``char`` instead. + \endrst + */ +FMT_EXPORT +template class basic_format_parse_context { + private: + basic_string_view format_str_; + int next_arg_id_; + + FMT_CONSTEXPR void do_check_arg_id(int id); + + public: + using char_type = Char; + using iterator = const Char*; + + explicit constexpr basic_format_parse_context( + basic_string_view format_str, int next_arg_id = 0) + : format_str_(format_str), next_arg_id_(next_arg_id) {} + + /** + Returns an iterator to the beginning of the format string range being + parsed. + */ + constexpr auto begin() const noexcept -> iterator { + return format_str_.begin(); + } + + /** + Returns an iterator past the end of the format string range being parsed. + */ + constexpr auto end() const noexcept -> iterator { return format_str_.end(); } + + /** Advances the begin iterator to ``it``. */ + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(detail::to_unsigned(it - begin())); + } + + /** + Reports an error if using the manual argument indexing; otherwise returns + the next argument index and switches to the automatic indexing. + */ + FMT_CONSTEXPR auto next_arg_id() -> int { + if (next_arg_id_ < 0) { + detail::throw_format_error( + "cannot switch from manual to automatic argument indexing"); + return 0; + } + int id = next_arg_id_++; + do_check_arg_id(id); + return id; + } + + /** + Reports an error if using the automatic argument indexing; otherwise + switches to the manual indexing. + */ + FMT_CONSTEXPR void check_arg_id(int id) { + if (next_arg_id_ > 0) { + detail::throw_format_error( + "cannot switch from automatic to manual argument indexing"); + return; + } + next_arg_id_ = -1; + do_check_arg_id(id); + } + FMT_CONSTEXPR void check_arg_id(basic_string_view) {} + FMT_CONSTEXPR void check_dynamic_spec(int arg_id); +}; + +FMT_EXPORT +using format_parse_context = basic_format_parse_context; + +namespace detail { +// A parse context with extra data used only in compile-time checks. +template +class compile_parse_context : public basic_format_parse_context { + private: + int num_args_; + const type* types_; + using base = basic_format_parse_context; + + public: + explicit FMT_CONSTEXPR compile_parse_context( + basic_string_view format_str, int num_args, const type* types, + int next_arg_id = 0) + : base(format_str, next_arg_id), num_args_(num_args), types_(types) {} + + constexpr auto num_args() const -> int { return num_args_; } + constexpr auto arg_type(int id) const -> type { return types_[id]; } + + FMT_CONSTEXPR auto next_arg_id() -> int { + int id = base::next_arg_id(); + if (id >= num_args_) throw_format_error("argument not found"); + return id; + } + + FMT_CONSTEXPR void check_arg_id(int id) { + base::check_arg_id(id); + if (id >= num_args_) throw_format_error("argument not found"); + } + using base::check_arg_id; + + FMT_CONSTEXPR void check_dynamic_spec(int arg_id) { + detail::ignore_unused(arg_id); +#if !defined(__LCC__) + if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id])) + throw_format_error("width/precision is not integer"); +#endif + } +}; + +// Extracts a reference to the container from back_insert_iterator. +template +inline auto get_container(std::back_insert_iterator it) + -> Container& { + using base = std::back_insert_iterator; + struct accessor : base { + accessor(base b) : base(b) {} + using base::container; + }; + return *accessor(it).container; +} + +template +FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) + -> OutputIt { + while (begin != end) *out++ = static_cast(*begin++); + return out; +} + +template , U>::value&& is_char::value)> +FMT_CONSTEXPR auto copy_str(T* begin, T* end, U* out) -> U* { + if (is_constant_evaluated()) return copy_str(begin, end, out); + auto size = to_unsigned(end - begin); + if (size > 0) memcpy(out, begin, size * sizeof(U)); + return out + size; +} + +/** + \rst + A contiguous memory buffer with an optional growing ability. It is an internal + class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`. + \endrst + */ +template class buffer { + private: + T* ptr_; + size_t size_; + size_t capacity_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + FMT_MSC_WARNING(suppress : 26495) + FMT_CONSTEXPR buffer(size_t sz) noexcept : size_(sz), capacity_(sz) {} + + FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) noexcept + : ptr_(p), size_(sz), capacity_(cap) {} + + FMT_CONSTEXPR20 ~buffer() = default; + buffer(buffer&&) = default; + + /** Sets the buffer data and capacity. */ + FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + /** Increases the buffer capacity to hold at least *capacity* elements. */ + // DEPRECATED! + virtual FMT_CONSTEXPR20 void grow(size_t capacity) = 0; + + public: + using value_type = T; + using const_reference = const T&; + + buffer(const buffer&) = delete; + void operator=(const buffer&) = delete; + + FMT_INLINE auto begin() noexcept -> T* { return ptr_; } + FMT_INLINE auto end() noexcept -> T* { return ptr_ + size_; } + + FMT_INLINE auto begin() const noexcept -> const T* { return ptr_; } + FMT_INLINE auto end() const noexcept -> const T* { return ptr_ + size_; } + + /** Returns the size of this buffer. */ + constexpr auto size() const noexcept -> size_t { return size_; } + + /** Returns the capacity of this buffer. */ + constexpr auto capacity() const noexcept -> size_t { return capacity_; } + + /** Returns a pointer to the buffer data (not null-terminated). */ + FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; } + FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; } + + /** Clears this buffer. */ + void clear() { size_ = 0; } + + // Tries resizing the buffer to contain *count* elements. If T is a POD type + // the new elements may not be initialized. + FMT_CONSTEXPR20 void try_resize(size_t count) { + try_reserve(count); + size_ = count <= capacity_ ? count : capacity_; + } + + // Tries increasing the buffer capacity to *new_capacity*. It can increase the + // capacity by a smaller amount than requested but guarantees there is space + // for at least one additional element either by increasing the capacity or by + // flushing the buffer if it is full. + FMT_CONSTEXPR20 void try_reserve(size_t new_capacity) { + if (new_capacity > capacity_) grow(new_capacity); + } + + FMT_CONSTEXPR20 void push_back(const T& value) { + try_reserve(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template void append(const U* begin, const U* end); + + template FMT_CONSTEXPR auto operator[](Idx index) -> T& { + return ptr_[index]; + } + template + FMT_CONSTEXPR auto operator[](Idx index) const -> const T& { + return ptr_[index]; + } +}; + +struct buffer_traits { + explicit buffer_traits(size_t) {} + auto count() const -> size_t { return 0; } + auto limit(size_t size) -> size_t { return size; } +}; + +class fixed_buffer_traits { + private: + size_t count_ = 0; + size_t limit_; + + public: + explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} + auto count() const -> size_t { return count_; } + auto limit(size_t size) -> size_t { + size_t n = limit_ > count_ ? limit_ - count_ : 0; + count_ += size; + return size < n ? size : n; + } +}; + +// A buffer that writes to an output iterator when flushed. +template +class iterator_buffer final : public Traits, public buffer { + private: + OutputIt out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + protected: + FMT_CONSTEXPR20 void grow(size_t) override { + if (this->size() == buffer_size) flush(); + } + + void flush() { + auto size = this->size(); + this->clear(); + out_ = copy_str(data_, data_ + this->limit(size), out_); + } + + public: + explicit iterator_buffer(OutputIt out, size_t n = buffer_size) + : Traits(n), buffer(data_, 0, buffer_size), out_(out) {} + iterator_buffer(iterator_buffer&& other) + : Traits(other), buffer(data_, 0, buffer_size), out_(other.out_) {} + ~iterator_buffer() { flush(); } + + auto out() -> OutputIt { + flush(); + return out_; + } + auto count() const -> size_t { return Traits::count() + this->size(); } +}; + +template +class iterator_buffer final + : public fixed_buffer_traits, + public buffer { + private: + T* out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + protected: + FMT_CONSTEXPR20 void grow(size_t) override { + if (this->size() == this->capacity()) flush(); + } + + void flush() { + size_t n = this->limit(this->size()); + if (this->data() == out_) { + out_ += n; + this->set(data_, buffer_size); + } + this->clear(); + } + + public: + explicit iterator_buffer(T* out, size_t n = buffer_size) + : fixed_buffer_traits(n), buffer(out, 0, n), out_(out) {} + iterator_buffer(iterator_buffer&& other) + : fixed_buffer_traits(other), + buffer(std::move(other)), + out_(other.out_) { + if (this->data() != out_) { + this->set(data_, buffer_size); + this->clear(); + } + } + ~iterator_buffer() { flush(); } + + auto out() -> T* { + flush(); + return out_; + } + auto count() const -> size_t { + return fixed_buffer_traits::count() + this->size(); + } +}; + +template class iterator_buffer final : public buffer { + protected: + FMT_CONSTEXPR20 void grow(size_t) override {} + + public: + explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} + + auto out() -> T* { return &*this->end(); } +}; + +// A buffer that writes to a container with the contiguous storage. +template +class iterator_buffer, + enable_if_t::value, + typename Container::value_type>> + final : public buffer { + private: + Container& container_; + + protected: + FMT_CONSTEXPR20 void grow(size_t capacity) override { + container_.resize(capacity); + this->set(&container_[0], capacity); + } + + public: + explicit iterator_buffer(Container& c) + : buffer(c.size()), container_(c) {} + explicit iterator_buffer(std::back_insert_iterator out, size_t = 0) + : iterator_buffer(get_container(out)) {} + + auto out() -> std::back_insert_iterator { + return std::back_inserter(container_); + } +}; + +// A buffer that counts the number of code units written discarding the output. +template class counting_buffer final : public buffer { + private: + enum { buffer_size = 256 }; + T data_[buffer_size]; + size_t count_ = 0; + + protected: + FMT_CONSTEXPR20 void grow(size_t) override { + if (this->size() != buffer_size) return; + count_ += this->size(); + this->clear(); + } + + public: + counting_buffer() : buffer(data_, 0, buffer_size) {} + + auto count() -> size_t { return count_ + this->size(); } +}; +} // namespace detail + +template +FMT_CONSTEXPR void basic_format_parse_context::do_check_arg_id(int id) { + // Argument id is only checked at compile-time during parsing because + // formatting has its own validation. + if (detail::is_constant_evaluated() && + (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { + using context = detail::compile_parse_context; + if (id >= static_cast(this)->num_args()) + detail::throw_format_error("argument not found"); + } +} + +template +FMT_CONSTEXPR void basic_format_parse_context::check_dynamic_spec( + int arg_id) { + if (detail::is_constant_evaluated() && + (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { + using context = detail::compile_parse_context; + static_cast(this)->check_dynamic_spec(arg_id); + } +} + +FMT_EXPORT template class basic_format_arg; +FMT_EXPORT template class basic_format_args; +FMT_EXPORT template class dynamic_format_arg_store; + +// A formatter for objects of type T. +FMT_EXPORT +template +struct formatter { + // A deleted default constructor indicates a disabled formatter. + formatter() = delete; +}; + +// Specifies if T has an enabled formatter specialization. A type can be +// formattable even if it doesn't have a formatter e.g. via a conversion. +template +using has_formatter = + std::is_constructible>; + +// An output iterator that appends to a buffer. +// It is used to reduce symbol sizes for the common case. +class appender : public std::back_insert_iterator> { + using base = std::back_insert_iterator>; + + public: + using std::back_insert_iterator>::back_insert_iterator; + appender(base it) noexcept : base(it) {} + FMT_UNCHECKED_ITERATOR(appender); + + auto operator++() noexcept -> appender& { return *this; } + auto operator++(int) noexcept -> appender { return *this; } +}; + +namespace detail { + +template +constexpr auto has_const_formatter_impl(T*) + -> decltype(typename Context::template formatter_type().format( + std::declval(), std::declval()), + true) { + return true; +} +template +constexpr auto has_const_formatter_impl(...) -> bool { + return false; +} +template +constexpr auto has_const_formatter() -> bool { + return has_const_formatter_impl(static_cast(nullptr)); +} + +template +using buffer_appender = conditional_t::value, appender, + std::back_insert_iterator>>; + +// Maps an output iterator to a buffer. +template +auto get_buffer(OutputIt out) -> iterator_buffer { + return iterator_buffer(out); +} +template , Buf>::value)> +auto get_buffer(std::back_insert_iterator out) -> buffer& { + return get_container(out); +} + +template +FMT_INLINE auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) { + return buf.out(); +} +template +auto get_iterator(buffer&, OutputIt out) -> OutputIt { + return out; +} + +struct view {}; + +template struct named_arg : view { + const Char* name; + const T& value; + named_arg(const Char* n, const T& v) : name(n), value(v) {} +}; + +template struct named_arg_info { + const Char* name; + int id; +}; + +template +struct arg_data { + // args_[0].named_args points to named_args_ to avoid bloating format_args. + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; + named_arg_info named_args_[NUM_NAMED_ARGS]; + + template + arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} + arg_data(const arg_data& other) = delete; + auto args() const -> const T* { return args_ + 1; } + auto named_args() -> named_arg_info* { return named_args_; } +}; + +template +struct arg_data { + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; + + template + FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {} + FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; } + FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t { + return nullptr; + } +}; + +template +inline void init_named_args(named_arg_info*, int, int) {} + +template struct is_named_arg : std::false_type {}; +template struct is_statically_named_arg : std::false_type {}; + +template +struct is_named_arg> : std::true_type {}; + +template ::value)> +void init_named_args(named_arg_info* named_args, int arg_count, + int named_arg_count, const T&, const Tail&... args) { + init_named_args(named_args, arg_count + 1, named_arg_count, args...); +} + +template ::value)> +void init_named_args(named_arg_info* named_args, int arg_count, + int named_arg_count, const T& arg, const Tail&... args) { + named_args[named_arg_count++] = {arg.name, arg_count}; + init_named_args(named_args, arg_count + 1, named_arg_count, args...); +} + +template +FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int, + const Args&...) {} + +template constexpr auto count() -> size_t { return B ? 1 : 0; } +template constexpr auto count() -> size_t { + return (B1 ? 1 : 0) + count(); +} + +template constexpr auto count_named_args() -> size_t { + return count::value...>(); +} + +template +constexpr auto count_statically_named_args() -> size_t { + return count::value...>(); +} + +struct unformattable {}; +struct unformattable_char : unformattable {}; +struct unformattable_pointer : unformattable {}; + +template struct string_value { + const Char* data; + size_t size; +}; + +template struct named_arg_value { + const named_arg_info* data; + size_t size; +}; + +template struct custom_value { + using parse_context = typename Context::parse_context_type; + void* value; + void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); +}; + +// A formatting argument value. +template class value { + public: + using char_type = typename Context::char_type; + + union { + monostate no_value; + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + int128_opt int128_value; + uint128_opt uint128_value; + bool bool_value; + char_type char_value; + float float_value; + double double_value; + long double long_double_value; + const void* pointer; + string_value string; + custom_value custom; + named_arg_value named_args; + }; + + constexpr FMT_INLINE value() : no_value() {} + constexpr FMT_INLINE value(int val) : int_value(val) {} + constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} + constexpr FMT_INLINE value(long long val) : long_long_value(val) {} + constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} + FMT_INLINE value(int128_opt val) : int128_value(val) {} + FMT_INLINE value(uint128_opt val) : uint128_value(val) {} + constexpr FMT_INLINE value(float val) : float_value(val) {} + constexpr FMT_INLINE value(double val) : double_value(val) {} + FMT_INLINE value(long double val) : long_double_value(val) {} + constexpr FMT_INLINE value(bool val) : bool_value(val) {} + constexpr FMT_INLINE value(char_type val) : char_value(val) {} + FMT_CONSTEXPR FMT_INLINE value(const char_type* val) { + string.data = val; + if (is_constant_evaluated()) string.size = {}; + } + FMT_CONSTEXPR FMT_INLINE value(basic_string_view val) { + string.data = val.data(); + string.size = val.size(); + } + FMT_INLINE value(const void* val) : pointer(val) {} + FMT_INLINE value(const named_arg_info* args, size_t size) + : named_args{args, size} {} + + template FMT_CONSTEXPR20 FMT_INLINE value(T& val) { + using value_type = remove_const_t; + custom.value = const_cast(std::addressof(val)); + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + custom.format = format_custom_arg< + value_type, typename Context::template formatter_type>; + } + value(unformattable); + value(unformattable_char); + value(unformattable_pointer); + + private: + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg(void* arg, + typename Context::parse_context_type& parse_ctx, + Context& ctx) { + auto f = Formatter(); + parse_ctx.advance_to(f.parse(parse_ctx)); + using qualified_type = + conditional_t(), const T, T>; + // Calling format through a mutable reference is deprecated. + ctx.advance_to(f.format(*static_cast(arg), ctx)); + } +}; + +// To minimize the number of types we need to deal with, long is translated +// either to int or to long long depending on its size. +enum { long_short = sizeof(long) == sizeof(int) }; +using long_type = conditional_t; +using ulong_type = conditional_t; + +template struct format_as_result { + template ::value || std::is_class::value)> + static auto map(U*) -> remove_cvref_t()))>; + static auto map(...) -> void; + + using type = decltype(map(static_cast(nullptr))); +}; +template using format_as_t = typename format_as_result::type; + +template +struct has_format_as + : bool_constant, void>::value> {}; + +// Maps formatting arguments to core types. +// arg_mapper reports errors by returning unformattable instead of using +// static_assert because it's used in the is_formattable trait. +template struct arg_mapper { + using char_type = typename Context::char_type; + + FMT_CONSTEXPR FMT_INLINE auto map(signed char val) -> int { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned char val) -> unsigned { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(short val) -> int { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned short val) -> unsigned { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(int val) -> int { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned val) -> unsigned { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(long val) -> long_type { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned long val) -> ulong_type { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(long long val) -> long long { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned long long val) + -> unsigned long long { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(int128_opt val) -> int128_opt { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(uint128_opt val) -> uint128_opt { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type { + return val; + } + template ::value || +#ifdef __cpp_char8_t + std::is_same::value || +#endif + std::is_same::value || + std::is_same::value) && + !std::is_same::value, + int> = 0> + FMT_CONSTEXPR FMT_INLINE auto map(T) -> unformattable_char { + return {}; + } + + FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(long double val) -> long double { + return val; + } + + FMT_CONSTEXPR FMT_INLINE auto map(char_type* val) -> const char_type* { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* { + return val; + } + template ::value && !std::is_pointer::value && + std::is_same>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> basic_string_view { + return to_string_view(val); + } + template ::value && !std::is_pointer::value && + !std::is_same>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char { + return {}; + } + + FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(std::nullptr_t val) -> const void* { + return val; + } + + // Use SFINAE instead of a const T* parameter to avoid a conflict with the + // array overload. + template < + typename T, + FMT_ENABLE_IF( + std::is_pointer::value || std::is_member_pointer::value || + std::is_function::type>::value || + (std::is_array::value && + !std::is_convertible::value))> + FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer { + return {}; + } + + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { + return values; + } + + // Only map owning types because mapping views can be unsafe. + template , + FMT_ENABLE_IF(std::is_arithmetic::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> decltype(FMT_DECLTYPE_THIS map(U())) { + return map(format_as(val)); + } + + template > + struct formattable : bool_constant() || + (has_formatter::value && + !std::is_const::value)> {}; + + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto do_map(T& val) -> T& { + return val; + } + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto do_map(T&) -> unformattable { + return {}; + } + + template , + FMT_ENABLE_IF((std::is_class::value || std::is_enum::value || + std::is_union::value) && + !is_string::value && !is_char::value && + !is_named_arg::value && + !std::is_arithmetic>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(T& val) + -> decltype(FMT_DECLTYPE_THIS do_map(val)) { + return do_map(val); + } + + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) + -> decltype(FMT_DECLTYPE_THIS map(named_arg.value)) { + return map(named_arg.value); + } + + auto map(...) -> unformattable { return {}; } +}; + +// A type constant after applying arg_mapper. +template +using mapped_type_constant = + type_constant().map(std::declval())), + typename Context::char_type>; + +enum { packed_arg_bits = 4 }; +// Maximum number of arguments with packed types. +enum { max_packed_args = 62 / packed_arg_bits }; +enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; +enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; + +template +auto copy_str(InputIt begin, InputIt end, appender out) -> appender { + get_container(out).append(begin, end); + return out; +} +template +auto copy_str(InputIt begin, InputIt end, + std::back_insert_iterator out) + -> std::back_insert_iterator { + get_container(out).append(begin, end); + return out; +} + +template +FMT_CONSTEXPR auto copy_str(R&& rng, OutputIt out) -> OutputIt { + return detail::copy_str(rng.begin(), rng.end(), out); +} + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +// A workaround for gcc 4.8 to make void_t work in a SFINAE context. +template struct void_t_impl { + using type = void; +}; +template using void_t = typename void_t_impl::type; +#else +template using void_t = void; +#endif + +template +struct is_output_iterator : std::false_type {}; + +template +struct is_output_iterator< + It, T, + void_t::iterator_category, + decltype(*std::declval() = std::declval())>> + : std::true_type {}; + +template struct is_back_insert_iterator : std::false_type {}; +template +struct is_back_insert_iterator> + : std::true_type {}; + +// A type-erased reference to an std::locale to avoid a heavy include. +class locale_ref { + private: + const void* locale_; // A type-erased pointer to std::locale. + + public: + constexpr FMT_INLINE locale_ref() : locale_(nullptr) {} + template explicit locale_ref(const Locale& loc); + + explicit operator bool() const noexcept { return locale_ != nullptr; } + + template auto get() const -> Locale; +}; + +template constexpr auto encode_types() -> unsigned long long { + return 0; +} + +template +constexpr auto encode_types() -> unsigned long long { + return static_cast(mapped_type_constant::value) | + (encode_types() << packed_arg_bits); +} + +#if defined(__cpp_if_constexpr) +// This type is intentionally undefined, only used for errors +template struct type_is_unformattable_for; +#endif + +template +FMT_CONSTEXPR FMT_INLINE auto make_arg(T& val) -> value { + using arg_type = remove_cvref_t().map(val))>; + + constexpr bool formattable_char = + !std::is_same::value; + static_assert(formattable_char, "Mixing character types is disallowed."); + + // Formatting of arbitrary pointers is disallowed. If you want to format a + // pointer cast it to `void*` or `const void*`. In particular, this forbids + // formatting of `[const] volatile char*` printed as bool by iostreams. + constexpr bool formattable_pointer = + !std::is_same::value; + static_assert(formattable_pointer, + "Formatting of non-void pointers is disallowed."); + + constexpr bool formattable = !std::is_same::value; +#if defined(__cpp_if_constexpr) + if constexpr (!formattable) { + type_is_unformattable_for _; + } +#endif + static_assert( + formattable, + "Cannot format an argument. To make type T formattable provide a " + "formatter specialization: https://fmt.dev/latest/api.html#udt"); + return {arg_mapper().map(val)}; +} + +template +FMT_CONSTEXPR auto make_arg(T& val) -> basic_format_arg { + auto arg = basic_format_arg(); + arg.type_ = mapped_type_constant::value; + arg.value_ = make_arg(val); + return arg; +} + +template +FMT_CONSTEXPR inline auto make_arg(T& val) -> basic_format_arg { + return make_arg(val); +} +} // namespace detail +FMT_BEGIN_EXPORT + +// A formatting argument. Context is a template parameter for the compiled API +// where output can be unbuffered. +template class basic_format_arg { + private: + detail::value value_; + detail::type type_; + + template + friend FMT_CONSTEXPR auto detail::make_arg(T& value) + -> basic_format_arg; + + template + friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, + const basic_format_arg& arg) + -> decltype(vis(0)); + + friend class basic_format_args; + friend class dynamic_format_arg_store; + + using char_type = typename Context::char_type; + + template + friend struct detail::arg_data; + + basic_format_arg(const detail::named_arg_info* args, size_t size) + : value_(args, size) {} + + public: + class handle { + public: + explicit handle(detail::custom_value custom) : custom_(custom) {} + + void format(typename Context::parse_context_type& parse_ctx, + Context& ctx) const { + custom_.format(custom_.value, parse_ctx, ctx); + } + + private: + detail::custom_value custom_; + }; + + constexpr basic_format_arg() : type_(detail::type::none_type) {} + + constexpr explicit operator bool() const noexcept { + return type_ != detail::type::none_type; + } + + auto type() const -> detail::type { return type_; } + + auto is_integral() const -> bool { return detail::is_integral_type(type_); } + auto is_arithmetic() const -> bool { + return detail::is_arithmetic_type(type_); + } + + FMT_INLINE auto format_custom(const char_type* parse_begin, + typename Context::parse_context_type& parse_ctx, + Context& ctx) -> bool { + if (type_ != detail::type::custom_type) return false; + parse_ctx.advance_to(parse_begin); + value_.custom.format(value_.custom.value, parse_ctx, ctx); + return true; + } +}; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ +// DEPRECATED! +template +FMT_CONSTEXPR FMT_INLINE auto visit_format_arg( + Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { + switch (arg.type_) { + case detail::type::none_type: + break; + case detail::type::int_type: + return vis(arg.value_.int_value); + case detail::type::uint_type: + return vis(arg.value_.uint_value); + case detail::type::long_long_type: + return vis(arg.value_.long_long_value); + case detail::type::ulong_long_type: + return vis(arg.value_.ulong_long_value); + case detail::type::int128_type: + return vis(detail::convert_for_visit(arg.value_.int128_value)); + case detail::type::uint128_type: + return vis(detail::convert_for_visit(arg.value_.uint128_value)); + case detail::type::bool_type: + return vis(arg.value_.bool_value); + case detail::type::char_type: + return vis(arg.value_.char_value); + case detail::type::float_type: + return vis(arg.value_.float_value); + case detail::type::double_type: + return vis(arg.value_.double_value); + case detail::type::long_double_type: + return vis(arg.value_.long_double_value); + case detail::type::cstring_type: + return vis(arg.value_.string.data); + case detail::type::string_type: + using sv = basic_string_view; + return vis(sv(arg.value_.string.data, arg.value_.string.size)); + case detail::type::pointer_type: + return vis(arg.value_.pointer); + case detail::type::custom_type: + return vis(typename basic_format_arg::handle(arg.value_.custom)); + } + return vis(monostate()); +} + +// Formatting context. +template class basic_format_context { + private: + OutputIt out_; + basic_format_args args_; + detail::locale_ref loc_; + + public: + using iterator = OutputIt; + using format_arg = basic_format_arg; + using format_args = basic_format_args; + using parse_context_type = basic_format_parse_context; + template using formatter_type = formatter; + + /** The character type for the output. */ + using char_type = Char; + + basic_format_context(basic_format_context&&) = default; + basic_format_context(const basic_format_context&) = delete; + void operator=(const basic_format_context&) = delete; + /** + Constructs a ``basic_format_context`` object. References to the arguments + are stored in the object so make sure they have appropriate lifetimes. + */ + constexpr basic_format_context(OutputIt out, format_args ctx_args, + detail::locale_ref loc = {}) + : out_(out), args_(ctx_args), loc_(loc) {} + + constexpr auto arg(int id) const -> format_arg { return args_.get(id); } + FMT_CONSTEXPR auto arg(basic_string_view name) -> format_arg { + return args_.get(name); + } + FMT_CONSTEXPR auto arg_id(basic_string_view name) -> int { + return args_.get_id(name); + } + auto args() const -> const format_args& { return args_; } + + // DEPRECATED! + FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; } + void on_error(const char* message) { error_handler().on_error(message); } + + // Returns an iterator to the beginning of the output range. + FMT_CONSTEXPR auto out() -> iterator { return out_; } + + // Advances the begin iterator to ``it``. + void advance_to(iterator it) { + if (!detail::is_back_insert_iterator()) out_ = it; + } + + FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } +}; + +template +using buffer_context = + basic_format_context, Char>; +using format_context = buffer_context; + +template +using is_formattable = bool_constant>() + .map(std::declval()))>::value>; + +/** + \rst + An array of references to arguments. It can be implicitly converted into + `~fmt::basic_format_args` for passing into type-erased formatting functions + such as `~fmt::vformat`. + \endrst + */ +template +class format_arg_store +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif +{ + private: + static const size_t num_args = sizeof...(Args); + static constexpr size_t num_named_args = detail::count_named_args(); + static const bool is_packed = num_args <= detail::max_packed_args; + + using value_type = conditional_t, + basic_format_arg>; + + detail::arg_data + data_; + + friend class basic_format_args; + + static constexpr unsigned long long desc = + (is_packed ? detail::encode_types() + : detail::is_unpacked_bit | num_args) | + (num_named_args != 0 + ? static_cast(detail::has_named_args_bit) + : 0); + + public: + template + FMT_CONSTEXPR FMT_INLINE format_arg_store(T&... args) + : +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + basic_format_args(*this), +#endif + data_{detail::make_arg(args)...} { + if (detail::const_check(num_named_args != 0)) + detail::init_named_args(data_.named_args(), 0, 0, args...); + } +}; + +/** + \rst + Constructs a `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::format_args`. `Context` + can be omitted in which case it defaults to `~fmt::format_context`. + See `~fmt::arg` for lifetime considerations. + \endrst + */ +// Arguments are taken by lvalue references to avoid some lifetime issues. +template +constexpr auto make_format_args(T&... args) + -> format_arg_store...> { + return {args...}; +} + +/** + \rst + Returns a named argument to be used in a formatting function. + It should only be used in a call to a formatting function or + `dynamic_format_arg_store::push_back`. + + **Example**:: + + fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); + \endrst + */ +template +inline auto arg(const Char* name, const T& arg) -> detail::named_arg { + static_assert(!detail::is_named_arg(), "nested named arguments"); + return {name, arg}; +} +FMT_END_EXPORT + +/** + \rst + A view of a collection of formatting arguments. To avoid lifetime issues it + should only be used as a parameter type in type-erased functions such as + ``vformat``:: + + void vlog(string_view format_str, format_args args); // OK + format_args args = make_format_args(); // Error: dangling reference + \endrst + */ +template class basic_format_args { + public: + using size_type = int; + using format_arg = basic_format_arg; + + private: + // A descriptor that contains information about formatting arguments. + // If the number of arguments is less or equal to max_packed_args then + // argument types are passed in the descriptor. This reduces binary code size + // per formatting function call. + unsigned long long desc_; + union { + // If is_packed() returns true then argument values are stored in values_; + // otherwise they are stored in args_. This is done to improve cache + // locality and reduce compiled code size since storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const detail::value* values_; + const format_arg* args_; + }; + + constexpr auto is_packed() const -> bool { + return (desc_ & detail::is_unpacked_bit) == 0; + } + auto has_named_args() const -> bool { + return (desc_ & detail::has_named_args_bit) != 0; + } + + FMT_CONSTEXPR auto type(int index) const -> detail::type { + int shift = index * detail::packed_arg_bits; + unsigned int mask = (1 << detail::packed_arg_bits) - 1; + return static_cast((desc_ >> shift) & mask); + } + + constexpr FMT_INLINE basic_format_args(unsigned long long desc, + const detail::value* values) + : desc_(desc), values_(values) {} + constexpr basic_format_args(unsigned long long desc, const format_arg* args) + : desc_(desc), args_(args) {} + + public: + constexpr basic_format_args() : desc_(0), args_(nullptr) {} + + /** + \rst + Constructs a `basic_format_args` object from `~fmt::format_arg_store`. + \endrst + */ + template + constexpr FMT_INLINE basic_format_args( + const format_arg_store& store) + : basic_format_args(format_arg_store::desc, + store.data_.args()) {} + + /** + \rst + Constructs a `basic_format_args` object from + `~fmt::dynamic_format_arg_store`. + \endrst + */ + constexpr FMT_INLINE basic_format_args( + const dynamic_format_arg_store& store) + : basic_format_args(store.get_types(), store.data()) {} + + /** + \rst + Constructs a `basic_format_args` object from a dynamic set of arguments. + \endrst + */ + constexpr basic_format_args(const format_arg* args, int count) + : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), + args) {} + + /** Returns the argument with the specified id. */ + FMT_CONSTEXPR auto get(int id) const -> format_arg { + format_arg arg; + if (!is_packed()) { + if (id < max_size()) arg = args_[id]; + return arg; + } + if (id >= detail::max_packed_args) return arg; + arg.type_ = type(id); + if (arg.type_ == detail::type::none_type) return arg; + arg.value_ = values_[id]; + return arg; + } + + template + auto get(basic_string_view name) const -> format_arg { + int id = get_id(name); + return id >= 0 ? get(id) : format_arg(); + } + + template + auto get_id(basic_string_view name) const -> int { + if (!has_named_args()) return -1; + const auto& named_args = + (is_packed() ? values_[-1] : args_[-1].value_).named_args; + for (size_t i = 0; i < named_args.size; ++i) { + if (named_args.data[i].name == name) return named_args.data[i].id; + } + return -1; + } + + auto max_size() const -> int { + unsigned long long max_packed = detail::max_packed_args; + return static_cast(is_packed() ? max_packed + : desc_ & ~detail::is_unpacked_bit); + } +}; + +/** An alias to ``basic_format_args``. */ +// A separate type would result in shorter symbols but break ABI compatibility +// between clang and gcc on ARM (#1919). +FMT_EXPORT using format_args = basic_format_args; + +// We cannot use enum classes as bit fields because of a gcc bug, so we put them +// in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414). +// Additionally, if an underlying type is specified, older gcc incorrectly warns +// that the type is too small. Both bugs are fixed in gcc 9.3. +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 903 +# define FMT_ENUM_UNDERLYING_TYPE(type) +#else +# define FMT_ENUM_UNDERLYING_TYPE(type) : type +#endif +namespace align { +enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, left, right, center, + numeric}; +} +using align_t = align::type; +namespace sign { +enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, minus, plus, space}; +} +using sign_t = sign::type; + +namespace detail { + +// Workaround an array initialization issue in gcc 4.8. +template struct fill_t { + private: + enum { max_size = 4 }; + Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; + unsigned char size_ = 1; + + public: + FMT_CONSTEXPR void operator=(basic_string_view s) { + auto size = s.size(); + FMT_ASSERT(size <= max_size, "invalid fill"); + for (size_t i = 0; i < size; ++i) data_[i] = s[i]; + size_ = static_cast(size); + } + + constexpr auto size() const -> size_t { return size_; } + constexpr auto data() const -> const Char* { return data_; } + + FMT_CONSTEXPR auto operator[](size_t index) -> Char& { return data_[index]; } + FMT_CONSTEXPR auto operator[](size_t index) const -> const Char& { + return data_[index]; + } +}; +} // namespace detail + +enum class presentation_type : unsigned char { + none, + dec, // 'd' + oct, // 'o' + hex_lower, // 'x' + hex_upper, // 'X' + bin_lower, // 'b' + bin_upper, // 'B' + hexfloat_lower, // 'a' + hexfloat_upper, // 'A' + exp_lower, // 'e' + exp_upper, // 'E' + fixed_lower, // 'f' + fixed_upper, // 'F' + general_lower, // 'g' + general_upper, // 'G' + chr, // 'c' + string, // 's' + pointer, // 'p' + debug // '?' +}; + +// Format specifiers for built-in and string types. +template struct format_specs { + int width; + int precision; + presentation_type type; + align_t align : 4; + sign_t sign : 3; + bool alt : 1; // Alternate form ('#'). + bool localized : 1; + detail::fill_t fill; + + constexpr format_specs() + : width(0), + precision(-1), + type(presentation_type::none), + align(align::none), + sign(sign::none), + alt(false), + localized(false) {} +}; + +namespace detail { + +enum class arg_id_kind { none, index, name }; + +// An argument reference. +template struct arg_ref { + FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} + + FMT_CONSTEXPR explicit arg_ref(int index) + : kind(arg_id_kind::index), val(index) {} + FMT_CONSTEXPR explicit arg_ref(basic_string_view name) + : kind(arg_id_kind::name), val(name) {} + + FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& { + kind = arg_id_kind::index; + val.index = idx; + return *this; + } + + arg_id_kind kind; + union value { + FMT_CONSTEXPR value(int idx = 0) : index(idx) {} + FMT_CONSTEXPR value(basic_string_view n) : name(n) {} + + int index; + basic_string_view name; + } val; +}; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow reusing the same parsed specifiers with +// different sets of arguments (precompilation of format strings). +template +struct dynamic_format_specs : format_specs { + arg_ref width_ref; + arg_ref precision_ref; +}; + +// Converts a character to ASCII. Returns '\0' on conversion failure. +template ::value)> +constexpr auto to_ascii(Char c) -> char { + return c <= 0xff ? static_cast(c) : '\0'; +} +template ::value)> +constexpr auto to_ascii(Char c) -> char { + return c <= 0xff ? static_cast(c) : '\0'; +} + +// Returns the number of code units in a code point or 1 on error. +template +FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { + if (const_check(sizeof(Char) != 1)) return 1; + auto c = static_cast(*begin); + return static_cast((0x3a55000000000000ull >> (2 * (c >> 3))) & 0x3) + 1; +} + +// Return the result via the out param to workaround gcc bug 77539. +template +FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool { + for (out = first; out != last; ++out) { + if (*out == value) return true; + } + return false; +} + +template <> +inline auto find(const char* first, const char* last, char value, + const char*& out) -> bool { + out = static_cast( + std::memchr(first, value, to_unsigned(last - first))); + return out != nullptr; +} + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. +template +FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end, + int error_value) noexcept -> int { + FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); + unsigned value = 0, prev = 0; + auto p = begin; + do { + prev = value; + value = value * 10 + unsigned(*p - '0'); + ++p; + } while (p != end && '0' <= *p && *p <= '9'); + auto num_digits = p - begin; + begin = p; + if (num_digits <= std::numeric_limits::digits10) + return static_cast(value); + // Check for overflow. + const unsigned max = to_unsigned((std::numeric_limits::max)()); + return num_digits == std::numeric_limits::digits10 + 1 && + prev * 10ull + unsigned(p[-1] - '0') <= max + ? static_cast(value) + : error_value; +} + +FMT_CONSTEXPR inline auto parse_align(char c) -> align_t { + switch (c) { + case '<': + return align::left; + case '>': + return align::right; + case '^': + return align::center; + } + return align::none; +} + +template constexpr auto is_name_start(Char c) -> bool { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_'; +} + +template +FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + Char c = *begin; + if (c >= '0' && c <= '9') { + int index = 0; + constexpr int max = (std::numeric_limits::max)(); + if (c != '0') + index = parse_nonnegative_int(begin, end, max); + else + ++begin; + if (begin == end || (*begin != '}' && *begin != ':')) + throw_format_error("invalid format string"); + else + handler.on_index(index); + return begin; + } + if (!is_name_start(c)) { + throw_format_error("invalid format string"); + return begin; + } + auto it = begin; + do { + ++it; + } while (it != end && (is_name_start(*it) || ('0' <= *it && *it <= '9'))); + handler.on_name({begin, to_unsigned(it - begin)}); + return it; +} + +template +FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + FMT_ASSERT(begin != end, ""); + Char c = *begin; + if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); + handler.on_auto(); + return begin; +} + +template struct dynamic_spec_id_handler { + basic_format_parse_context& ctx; + arg_ref& ref; + + FMT_CONSTEXPR void on_auto() { + int id = ctx.next_arg_id(); + ref = arg_ref(id); + ctx.check_dynamic_spec(id); + } + FMT_CONSTEXPR void on_index(int id) { + ref = arg_ref(id); + ctx.check_arg_id(id); + ctx.check_dynamic_spec(id); + } + FMT_CONSTEXPR void on_name(basic_string_view id) { + ref = arg_ref(id); + ctx.check_arg_id(id); + } +}; + +// Parses [integer | "{" [arg_id] "}"]. +template +FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end, + int& value, arg_ref& ref, + basic_format_parse_context& ctx) + -> const Char* { + FMT_ASSERT(begin != end, ""); + if ('0' <= *begin && *begin <= '9') { + int val = parse_nonnegative_int(begin, end, -1); + if (val != -1) + value = val; + else + throw_format_error("number is too big"); + } else if (*begin == '{') { + ++begin; + auto handler = dynamic_spec_id_handler{ctx, ref}; + if (begin != end) begin = parse_arg_id(begin, end, handler); + if (begin != end && *begin == '}') return ++begin; + throw_format_error("invalid format string"); + } + return begin; +} + +template +FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, + int& value, arg_ref& ref, + basic_format_parse_context& ctx) + -> const Char* { + ++begin; + if (begin == end || *begin == '}') { + throw_format_error("invalid precision"); + return begin; + } + return parse_dynamic_spec(begin, end, value, ref, ctx); +} + +enum class state { start, align, sign, hash, zero, width, precision, locale }; + +// Parses standard format specifiers. +template +FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( + const Char* begin, const Char* end, dynamic_format_specs& specs, + basic_format_parse_context& ctx, type arg_type) -> const Char* { + auto c = '\0'; + if (end - begin > 1) { + auto next = to_ascii(begin[1]); + c = parse_align(next) == align::none ? to_ascii(*begin) : '\0'; + } else { + if (begin == end) return begin; + c = to_ascii(*begin); + } + + struct { + state current_state = state::start; + FMT_CONSTEXPR void operator()(state s, bool valid = true) { + if (current_state >= s || !valid) + throw_format_error("invalid format specifier"); + current_state = s; + } + } enter_state; + + using pres = presentation_type; + constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; + struct { + const Char*& begin; + dynamic_format_specs& specs; + type arg_type; + + FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* { + if (!in(arg_type, set)) { + if (arg_type == type::none_type) return begin; + throw_format_error("invalid format specifier"); + } + specs.type = pres_type; + return begin + 1; + } + } parse_presentation_type{begin, specs, arg_type}; + + for (;;) { + switch (c) { + case '<': + case '>': + case '^': + enter_state(state::align); + specs.align = parse_align(c); + ++begin; + break; + case '+': + case '-': + case ' ': + if (arg_type == type::none_type) return begin; + enter_state(state::sign, in(arg_type, sint_set | float_set)); + switch (c) { + case '+': + specs.sign = sign::plus; + break; + case '-': + specs.sign = sign::minus; + break; + case ' ': + specs.sign = sign::space; + break; + } + ++begin; + break; + case '#': + if (arg_type == type::none_type) return begin; + enter_state(state::hash, is_arithmetic_type(arg_type)); + specs.alt = true; + ++begin; + break; + case '0': + enter_state(state::zero); + if (!is_arithmetic_type(arg_type)) { + if (arg_type == type::none_type) return begin; + throw_format_error("format specifier requires numeric argument"); + } + if (specs.align == align::none) { + // Ignore 0 if align is specified for compatibility with std::format. + specs.align = align::numeric; + specs.fill[0] = Char('0'); + } + ++begin; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '{': + enter_state(state::width); + begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx); + break; + case '.': + if (arg_type == type::none_type) return begin; + enter_state(state::precision, + in(arg_type, float_set | string_set | cstring_set)); + begin = parse_precision(begin, end, specs.precision, specs.precision_ref, + ctx); + break; + case 'L': + if (arg_type == type::none_type) return begin; + enter_state(state::locale, is_arithmetic_type(arg_type)); + specs.localized = true; + ++begin; + break; + case 'd': + return parse_presentation_type(pres::dec, integral_set); + case 'o': + return parse_presentation_type(pres::oct, integral_set); + case 'x': + return parse_presentation_type(pres::hex_lower, integral_set); + case 'X': + return parse_presentation_type(pres::hex_upper, integral_set); + case 'b': + return parse_presentation_type(pres::bin_lower, integral_set); + case 'B': + return parse_presentation_type(pres::bin_upper, integral_set); + case 'a': + return parse_presentation_type(pres::hexfloat_lower, float_set); + case 'A': + return parse_presentation_type(pres::hexfloat_upper, float_set); + case 'e': + return parse_presentation_type(pres::exp_lower, float_set); + case 'E': + return parse_presentation_type(pres::exp_upper, float_set); + case 'f': + return parse_presentation_type(pres::fixed_lower, float_set); + case 'F': + return parse_presentation_type(pres::fixed_upper, float_set); + case 'g': + return parse_presentation_type(pres::general_lower, float_set); + case 'G': + return parse_presentation_type(pres::general_upper, float_set); + case 'c': + if (arg_type == type::bool_type) + throw_format_error("invalid format specifier"); + return parse_presentation_type(pres::chr, integral_set); + case 's': + return parse_presentation_type(pres::string, + bool_set | string_set | cstring_set); + case 'p': + return parse_presentation_type(pres::pointer, pointer_set | cstring_set); + case '?': + return parse_presentation_type(pres::debug, + char_set | string_set | cstring_set); + case '}': + return begin; + default: { + if (*begin == '}') return begin; + // Parse fill and alignment. + auto fill_end = begin + code_point_length(begin); + if (end - fill_end <= 0) { + throw_format_error("invalid format specifier"); + return begin; + } + if (*begin == '{') { + throw_format_error("invalid fill character '{'"); + return begin; + } + auto align = parse_align(to_ascii(*fill_end)); + enter_state(state::align, align != align::none); + specs.fill = {begin, to_unsigned(fill_end - begin)}; + specs.align = align; + begin = fill_end + 1; + } + } + if (begin == end) return begin; + c = to_ascii(*begin); + } +} + +template +FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + struct id_adapter { + Handler& handler; + int arg_id; + + FMT_CONSTEXPR void on_auto() { arg_id = handler.on_arg_id(); } + FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); } + FMT_CONSTEXPR void on_name(basic_string_view id) { + arg_id = handler.on_arg_id(id); + } + }; + + ++begin; + if (begin == end) return handler.on_error("invalid format string"), end; + if (*begin == '}') { + handler.on_replacement_field(handler.on_arg_id(), begin); + } else if (*begin == '{') { + handler.on_text(begin, begin + 1); + } else { + auto adapter = id_adapter{handler, 0}; + begin = parse_arg_id(begin, end, adapter); + Char c = begin != end ? *begin : Char(); + if (c == '}') { + handler.on_replacement_field(adapter.arg_id, begin); + } else if (c == ':') { + begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); + if (begin == end || *begin != '}') + return handler.on_error("unknown format specifier"), end; + } else { + return handler.on_error("missing '}' in format string"), end; + } + } + return begin + 1; +} + +template +FMT_CONSTEXPR FMT_INLINE void parse_format_string( + basic_string_view format_str, Handler&& handler) { + auto begin = format_str.data(); + auto end = begin + format_str.size(); + if (end - begin < 32) { + // Use a simple loop instead of memchr for small strings. + const Char* p = begin; + while (p != end) { + auto c = *p++; + if (c == '{') { + handler.on_text(begin, p - 1); + begin = p = parse_replacement_field(p - 1, end, handler); + } else if (c == '}') { + if (p == end || *p != '}') + return handler.on_error("unmatched '}' in format string"); + handler.on_text(begin, p); + begin = ++p; + } + } + handler.on_text(begin, end); + return; + } + struct writer { + FMT_CONSTEXPR void operator()(const Char* from, const Char* to) { + if (from == to) return; + for (;;) { + const Char* p = nullptr; + if (!find(from, to, Char('}'), p)) + return handler_.on_text(from, to); + ++p; + if (p == to || *p != '}') + return handler_.on_error("unmatched '}' in format string"); + handler_.on_text(from, p); + from = p + 1; + } + } + Handler& handler_; + } write = {handler}; + while (begin != end) { + // Doing two passes with memchr (one for '{' and another for '}') is up to + // 2.5x faster than the naive one-pass implementation on big format strings. + const Char* p = begin; + if (*begin != '{' && !find(begin + 1, end, Char('{'), p)) + return write(begin, end); + write(begin, p); + begin = parse_replacement_field(p, end, handler); + } +} + +template ::value> struct strip_named_arg { + using type = T; +}; +template struct strip_named_arg { + using type = remove_cvref_t; +}; + +template +FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) + -> decltype(ctx.begin()) { + using char_type = typename ParseContext::char_type; + using context = buffer_context; + using mapped_type = conditional_t< + mapped_type_constant::value != type::custom_type, + decltype(arg_mapper().map(std::declval())), + typename strip_named_arg::type>; +#if defined(__cpp_if_constexpr) + if constexpr (std::is_default_constructible< + formatter>::value) { + return formatter().parse(ctx); + } else { + type_is_unformattable_for _; + return ctx.begin(); + } +#else + return formatter().parse(ctx); +#endif +} + +// Checks char specs and returns true iff the presentation type is char-like. +template +FMT_CONSTEXPR auto check_char_specs(const format_specs& specs) -> bool { + if (specs.type != presentation_type::none && + specs.type != presentation_type::chr && + specs.type != presentation_type::debug) { + return false; + } + if (specs.align == align::numeric || specs.sign != sign::none || specs.alt) + throw_format_error("invalid format specifier for char"); + return true; +} + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template +constexpr auto get_arg_index_by_name(basic_string_view name) -> int { + if constexpr (is_statically_named_arg()) { + if (name == T::name) return N; + } + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name(name); + (void)name; // Workaround an MSVC bug about "unused" parameter. + return -1; +} +#endif + +template +FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name<0, Args...>(name); +#endif + (void)name; + return -1; +} + +template class format_string_checker { + private: + using parse_context_type = compile_parse_context; + static constexpr int num_args = sizeof...(Args); + + // Format specifier parsing function. + // In the future basic_format_parse_context will replace compile_parse_context + // here and will use is_constant_evaluated and downcasting to access the data + // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1. + using parse_func = const Char* (*)(parse_context_type&); + + type types_[num_args > 0 ? static_cast(num_args) : 1]; + parse_context_type context_; + parse_func parse_funcs_[num_args > 0 ? static_cast(num_args) : 1]; + + public: + explicit FMT_CONSTEXPR format_string_checker(basic_string_view fmt) + : types_{mapped_type_constant>::value...}, + context_(fmt, num_args, types_), + parse_funcs_{&parse_format_specs...} {} + + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + + FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + return context_.check_arg_id(id), id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS + auto index = get_arg_index_by_name(id); + if (index < 0) on_error("named argument is not found"); + return index; +#else + (void)id; + on_error("compile-time checks for named arguments require C++20 support"); + return 0; +#endif + } + + FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) { + on_format_specs(id, begin, begin); // Call parse() on empty specs. + } + + FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*) + -> const Char* { + context_.advance_to(begin); + // id >= 0 check is a workaround for gcc 10 bug (#2065). + return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; + } + + FMT_CONSTEXPR void on_error(const char* message) { + throw_format_error(message); + } +}; + +// Reports a compile-time error if S is not a valid format string. +template ::value)> +FMT_INLINE void check_format_string(const S&) { +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert(is_compile_string::value, + "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " + "FMT_STRING."); +#endif +} +template ::value)> +void check_format_string(S format_str) { + using char_t = typename S::char_type; + FMT_CONSTEXPR auto s = basic_string_view(format_str); + using checker = format_string_checker...>; + FMT_CONSTEXPR bool error = (parse_format_string(s, checker(s)), true); + ignore_unused(error); +} + +template struct vformat_args { + using type = basic_format_args< + basic_format_context>, Char>>; +}; +template <> struct vformat_args { + using type = format_args; +}; + +// Use vformat_args and avoid type_identity to keep symbols short. +template +void vformat_to(buffer& buf, basic_string_view fmt, + typename vformat_args::type args, locale_ref loc = {}); + +FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); +#ifndef _WIN32 +inline void vprint_mojibake(std::FILE*, string_view, format_args) {} +#endif +} // namespace detail + +FMT_BEGIN_EXPORT + +// A formatter specialization for natively supported types. +template +struct formatter::value != + detail::type::custom_type>> { + private: + detail::dynamic_format_specs specs_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* { + auto type = detail::type_constant::value; + auto end = + detail::parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, type); + if (type == detail::type::char_type) detail::check_char_specs(specs_); + return end; + } + + template ::value, + FMT_ENABLE_IF(U == detail::type::string_type || + U == detail::type::cstring_type || + U == detail::type::char_type)> + FMT_CONSTEXPR void set_debug_format(bool set = true) { + specs_.type = set ? presentation_type::debug : presentation_type::none; + } + + template + FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const + -> decltype(ctx.out()); +}; + +template struct runtime_format_string { + basic_string_view str; +}; + +/** A compile-time format string. */ +template class basic_format_string { + private: + basic_string_view str_; + + public: + template >::value)> + FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) { + static_assert( + detail::count< + (std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); +#ifdef FMT_HAS_CONSTEVAL + if constexpr (detail::count_named_args() == + detail::count_statically_named_args()) { + using checker = + detail::format_string_checker...>; + detail::parse_format_string(str_, checker(s)); + } +#else + detail::check_format_string(s); +#endif + } + basic_format_string(runtime_format_string fmt) : str_(fmt.str) {} + + FMT_INLINE operator basic_string_view() const { return str_; } + FMT_INLINE auto get() const -> basic_string_view { return str_; } +}; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +// Workaround broken conversion on older gcc. +template using format_string = string_view; +inline auto runtime(string_view s) -> string_view { return s; } +#else +template +using format_string = basic_format_string...>; +/** + \rst + Creates a runtime format string. + + **Example**:: + + // Check format string at runtime instead of compile-time. + fmt::print(fmt::runtime("{:d}"), "I am not a number"); + \endrst + */ +inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; } +#endif + +FMT_API auto vformat(string_view fmt, format_args args) -> std::string; + +/** + \rst + Formats ``args`` according to specifications in ``fmt`` and returns the result + as a string. + + **Example**:: + + #include + std::string message = fmt::format("The answer is {}.", 42); + \endrst +*/ +template +FMT_NODISCARD FMT_INLINE auto format(format_string fmt, T&&... args) + -> std::string { + return vformat(fmt, fmt::make_format_args(args...)); +} + +/** Formats a string and writes the output to ``out``. */ +template ::value)> +auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, fmt, args, {}); + return detail::get_iterator(buf, out); +} + +/** + \rst + Formats ``args`` according to specifications in ``fmt``, writes the result to + the output iterator ``out`` and returns the iterator past the end of the output + range. `format_to` does not append a terminating null character. + + **Example**:: + + auto out = std::vector(); + fmt::format_to(std::back_inserter(out), "{}", 42); + \endrst + */ +template ::value)> +FMT_INLINE auto format_to(OutputIt out, format_string fmt, T&&... args) + -> OutputIt { + return vformat_to(out, fmt, fmt::make_format_args(args...)); +} + +template struct format_to_n_result { + /** Iterator past the end of the output range. */ + OutputIt out; + /** Total (not truncated) output size. */ + size_t size; +}; + +template ::value)> +auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + detail::vformat_to(buf, fmt, args, {}); + return {buf.out(), buf.count()}; +} + +/** + \rst + Formats ``args`` according to specifications in ``fmt``, writes up to ``n`` + characters of the result to the output iterator ``out`` and returns the total + (not truncated) output size and the iterator past the end of the output range. + `format_to_n` does not append a terminating null character. + \endrst + */ +template ::value)> +FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string fmt, + T&&... args) -> format_to_n_result { + return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); +} + +/** Returns the number of chars in the output of ``format(fmt, args...)``. */ +template +FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, + T&&... args) -> size_t { + auto buf = detail::counting_buffer<>(); + detail::vformat_to(buf, fmt, fmt::make_format_args(args...), {}); + return buf.count(); +} + +FMT_API void vprint(string_view fmt, format_args args); +FMT_API void vprint(std::FILE* f, string_view fmt, format_args args); + +/** + \rst + Formats ``args`` according to specifications in ``fmt`` and writes the output + to ``stdout``. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template +FMT_INLINE void print(format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + return detail::is_utf8() ? vprint(fmt, vargs) + : detail::vprint_mojibake(stdout, fmt, vargs); +} + +/** + \rst + Formats ``args`` according to specifications in ``fmt`` and writes the + output to the file ``f``. + + **Example**:: + + fmt::print(stderr, "Don't {}!", "panic"); + \endrst + */ +template +FMT_INLINE void print(std::FILE* f, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + return detail::is_utf8() ? vprint(f, fmt, vargs) + : detail::vprint_mojibake(f, fmt, vargs); +} + +/** + Formats ``args`` according to specifications in ``fmt`` and writes the + output to the file ``f`` followed by a newline. + */ +template +FMT_INLINE void println(std::FILE* f, format_string fmt, T&&... args) { + return fmt::print(f, "{}\n", fmt::format(fmt, std::forward(args)...)); +} + +/** + Formats ``args`` according to specifications in ``fmt`` and writes the output + to ``stdout`` followed by a newline. + */ +template +FMT_INLINE void println(format_string fmt, T&&... args) { + return fmt::println(stdout, fmt, std::forward(args)...); +} + +FMT_END_EXPORT +FMT_GCC_PRAGMA("GCC pop_options") +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# include "format.h" +#endif +#endif // FMT_CORE_H_ diff --git a/dep/fmt/include/fmt/format-inl.h b/dep/fmt/include/fmt/format-inl.h new file mode 100644 index 00000000000..efac5d1f88f --- /dev/null +++ b/dep/fmt/include/fmt/format-inl.h @@ -0,0 +1,1678 @@ +// Formatting library for C++ - implementation +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_FORMAT_INL_H_ +#define FMT_FORMAT_INL_H_ + +#include +#include // errno +#include +#include +#include + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +# include +#endif + +#if defined(_WIN32) && !defined(FMT_WINDOWS_NO_WCHAR) +# include // _isatty +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE +namespace detail { + +FMT_FUNC void assert_fail(const char* file, int line, const char* message) { + // Use unchecked std::fprintf to avoid triggering another assertion when + // writing to stderr fails + std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); + // Chosen instead of std::abort to satisfy Clang in CUDA mode during device + // code pass. + std::terminate(); +} + +FMT_FUNC void throw_format_error(const char* message) { + FMT_THROW(format_error(message)); +} + +FMT_FUNC void format_error_code(detail::buffer& out, int error_code, + string_view message) noexcept { + // Report error code making sure that the output fits into + // inline_buffer_size to avoid dynamic memory allocation and potential + // bad_alloc. + out.try_resize(0); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + auto abs_value = static_cast>(error_code); + if (detail::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += detail::to_unsigned(detail::count_digits(abs_value)); + auto it = buffer_appender(out); + if (message.size() <= inline_buffer_size - error_code_size) + fmt::format_to(it, FMT_STRING("{}{}"), message, SEP); + fmt::format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); + FMT_ASSERT(out.size() <= inline_buffer_size, ""); +} + +FMT_FUNC void report_error(format_func func, int error_code, + const char* message) noexcept { + memory_buffer full_message; + func(full_message, error_code, message); + // Don't use fwrite_fully because the latter may throw. + if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0) + std::fputc('\n', stderr); +} + +// A wrapper around fwrite that throws on error. +inline void fwrite_fully(const void* ptr, size_t count, FILE* stream) { + size_t written = std::fwrite(ptr, 1, count, stream); + if (written < count) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); +} + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template +locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { + static_assert(std::is_same::value, ""); +} + +template auto locale_ref::get() const -> Locale { + static_assert(std::is_same::value, ""); + return locale_ ? *static_cast(locale_) : std::locale(); +} + +template +FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result { + auto& facet = std::use_facet>(loc.get()); + auto grouping = facet.grouping(); + auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); + return {std::move(grouping), thousands_sep}; +} +template +FMT_FUNC auto decimal_point_impl(locale_ref loc) -> Char { + return std::use_facet>(loc.get()) + .decimal_point(); +} +#else +template +FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result { + return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; +} +template FMT_FUNC Char decimal_point_impl(locale_ref) { + return '.'; +} +#endif + +FMT_FUNC auto write_loc(appender out, loc_value value, + const format_specs<>& specs, locale_ref loc) -> bool { +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR + auto locale = loc.get(); + // We cannot use the num_put facet because it may produce output in + // a wrong encoding. + using facet = format_facet; + if (std::has_facet(locale)) + return std::use_facet(locale).put(out, value, specs); + return facet(locale).put(out, value, specs); +#endif + return false; +} +} // namespace detail + +template typename Locale::id format_facet::id; + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template format_facet::format_facet(Locale& loc) { + auto& numpunct = std::use_facet>(loc); + grouping_ = numpunct.grouping(); + if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep()); +} + +template <> +FMT_API FMT_FUNC auto format_facet::do_put( + appender out, loc_value val, const format_specs<>& specs) const -> bool { + return val.visit( + detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_}); +} +#endif + +FMT_FUNC auto vsystem_error(int error_code, string_view fmt, format_args args) + -> std::system_error { + auto ec = std::error_code(error_code, std::generic_category()); + return std::system_error(ec, vformat(fmt, args)); +} + +namespace detail { + +template +inline auto operator==(basic_fp x, basic_fp y) -> bool { + return x.f == y.f && x.e == y.e; +} + +// Compilers should be able to optimize this into the ror instruction. +FMT_CONSTEXPR inline auto rotr(uint32_t n, uint32_t r) noexcept -> uint32_t { + r &= 31; + return (n >> r) | (n << (32 - r)); +} +FMT_CONSTEXPR inline auto rotr(uint64_t n, uint32_t r) noexcept -> uint64_t { + r &= 63; + return (n >> r) | (n << (64 - r)); +} + +// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. +namespace dragonbox { +// Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline auto umul96_upper64(uint32_t x, uint64_t y) noexcept -> uint64_t { + return umul128_upper64(static_cast(x) << 32, y); +} + +// Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline auto umul192_lower128(uint64_t x, uint128_fallback y) noexcept + -> uint128_fallback { + uint64_t high = x * y.high(); + uint128_fallback high_low = umul128(x, y.low()); + return {high + high_low.high(), high_low.low()}; +} + +// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline auto umul96_lower64(uint32_t x, uint64_t y) noexcept -> uint64_t { + return x * y; +} + +// Various fast log computations. +inline auto floor_log10_pow2_minus_log10_4_over_3(int e) noexcept -> int { + FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent"); + return (e * 631305 - 261663) >> 21; +} + +FMT_INLINE_VARIABLE constexpr struct { + uint32_t divisor; + int shift_amount; +} div_small_pow10_infos[] = {{10, 16}, {100, 16}}; + +// Replaces n by floor(n / pow(10, N)) returning true if and only if n is +// divisible by pow(10, N). +// Precondition: n <= pow(10, N + 1). +template +auto check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept -> bool { + // The numbers below are chosen such that: + // 1. floor(n/d) = floor(nm / 2^k) where d=10 or d=100, + // 2. nm mod 2^k < m if and only if n is divisible by d, + // where m is magic_number, k is shift_amount + // and d is divisor. + // + // Item 1 is a common technique of replacing division by a constant with + // multiplication, see e.g. "Division by Invariant Integers Using + // Multiplication" by Granlund and Montgomery (1994). magic_number (m) is set + // to ceil(2^k/d) for large enough k. + // The idea for item 2 originates from Schubfach. + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + n *= magic_number; + const uint32_t comparison_mask = (1u << info.shift_amount) - 1; + bool result = (n & comparison_mask) < magic_number; + n >>= info.shift_amount; + return result; +} + +// Computes floor(n / pow(10, N)) for small n and N. +// Precondition: n <= pow(10, N + 1). +template auto small_division_by_pow10(uint32_t n) noexcept -> uint32_t { + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + return (n * magic_number) >> info.shift_amount; +} + +// Computes floor(n / 10^(kappa + 1)) (float) +inline auto divide_by_10_to_kappa_plus_1(uint32_t n) noexcept -> uint32_t { + // 1374389535 = ceil(2^37/100) + return static_cast((static_cast(n) * 1374389535) >> 37); +} +// Computes floor(n / 10^(kappa + 1)) (double) +inline auto divide_by_10_to_kappa_plus_1(uint64_t n) noexcept -> uint64_t { + // 2361183241434822607 = ceil(2^(64+7)/1000) + return umul128_upper64(n, 2361183241434822607ull) >> 7; +} + +// Various subroutines using pow10 cache +template struct cache_accessor; + +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint64_t; + + static auto get_cached_power(int k) noexcept -> uint64_t { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + static constexpr const uint64_t pow10_significands[] = { + 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, + 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, + 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, + 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, + 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, + 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810, + 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, + 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, + 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, + 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, + 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, + 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, + 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, + 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, + 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, + 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, + 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, + 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, + 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, + 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940985, + 0xa18f07d736b90be6, 0xc9f2c9cd04674edf, 0xfc6f7c4045812297, + 0x9dc5ada82b70b59e, 0xc5371912364ce306, 0xf684df56c3e01bc7, + 0x9a130b963a6c115d, 0xc097ce7bc90715b4, 0xf0bdc21abb48db21, + 0x96769950b50d88f5, 0xbc143fa4e250eb32, 0xeb194f8e1ae525fe, + 0x92efd1b8d0cf37bf, 0xb7abc627050305ae, 0xe596b7b0c643c71a, + 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f}; + return pow10_significands[k - float_info::min_k]; + } + + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static auto compute_mul(carrier_uint u, + const cache_entry_type& cache) noexcept + -> compute_mul_result { + auto r = umul96_upper64(u, cache); + return {static_cast(r >> 32), + static_cast(r) == 0}; + } + + static auto compute_delta(const cache_entry_type& cache, int beta) noexcept + -> uint32_t { + return static_cast(cache >> (64 - 1 - beta)); + } + + static auto compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta) noexcept + -> compute_mul_parity_result { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); + + auto r = umul96_lower64(two_f, cache); + return {((r >> (64 - beta)) & 1) != 0, + static_cast(r >> (32 - beta)) == 0}; + } + + static auto compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return static_cast( + (cache - (cache >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta)); + } + + static auto compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return static_cast( + (cache + (cache >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta)); + } + + static auto compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (static_cast( + cache >> (64 - num_significand_bits() - 2 - beta)) + + 1) / + 2; + } +}; + +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint128_fallback; + + static auto get_cached_power(int k) noexcept -> uint128_fallback { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + + static constexpr const uint128_fallback pow10_significands[] = { +#if FMT_USE_FULL_CACHE_DRAGONBOX + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0x9faacf3df73609b1, 0x77b191618c54e9ad}, + {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, + {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, + {0x9becce62836ac577, 0x4ee367f9430aec33}, + {0xc2e801fb244576d5, 0x229c41f793cda740}, + {0xf3a20279ed56d48a, 0x6b43527578c11110}, + {0x9845418c345644d6, 0x830a13896b78aaaa}, + {0xbe5691ef416bd60c, 0x23cc986bc656d554}, + {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, + {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, + {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, + {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, + {0x91376c36d99995be, 0x23100809b9c21fa2}, + {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, + {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, + {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, + {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, + {0xdd95317f31c7fa1d, 0x40405643d711d584}, + {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, + {0xad1c8eab5ee43b66, 0xda3243650005eed0}, + {0xd863b256369d4a40, 0x90bed43e40076a83}, + {0x873e4f75e2224e68, 0x5a7744a6e804a292}, + {0xa90de3535aaae202, 0x711515d0a205cb37}, + {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, + {0x8412d9991ed58091, 0xe858790afe9486c3}, + {0xa5178fff668ae0b6, 0x626e974dbe39a873}, + {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, + {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, + {0xc987434744ac874e, 0xa327ffb266b56221}, + {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, + {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, + {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, + {0xf6019da07f549b2b, 0x7e2a53a146606a49}, + {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, + {0xc0314325637a1939, 0xfa911155fefb5309}, + {0xf03d93eebc589f88, 0x793555ab7eba27cb}, + {0x96267c7535b763b5, 0x4bc1558b2f3458df}, + {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, + {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, + {0x92a1958a7675175f, 0x0bfacd89ec191eca}, + {0xb749faed14125d36, 0xcef980ec671f667c}, + {0xe51c79a85916f484, 0x82b7e12780e7401b}, + {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, + {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, + {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, + {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, + {0xaecc49914078536d, 0x58fae9f773886e19}, + {0xda7f5bf590966848, 0xaf39a475506a899f}, + {0x888f99797a5e012d, 0x6d8406c952429604}, + {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, + {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, + {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, + {0xd0601d8efc57b08b, 0xf13b94daf124da27}, + {0x823c12795db6ce57, 0x76c53d08d6b70859}, + {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, + {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, + {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, + {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, + {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, + {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, + {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, + {0xc21094364dfb5636, 0x985915fc12f542e5}, + {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, + {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, + {0xbd8430bd08277231, 0x50c6ff782a838354}, + {0xece53cec4a314ebd, 0xa4f8bf5635246429}, + {0x940f4613ae5ed136, 0x871b7795e136be9a}, + {0xb913179899f68584, 0x28e2557b59846e40}, + {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, + {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, + {0xb4bca50b065abe63, 0x0fed077a756b53aa}, + {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, + {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, + {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, + {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, + {0x89e42caaf9491b60, 0xf41686c49db57245}, + {0xac5d37d5b79b6239, 0x311c2875c522ced6}, + {0xd77485cb25823ac7, 0x7d633293366b828c}, + {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, + {0xd267caa862a12d66, 0xd072df63c324fd7c}, + {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, + {0xa46116538d0deb78, 0x52d9be85f074e609}, + {0xcd795be870516656, 0x67902e276c921f8c}, + {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, + {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, + {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, + {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, + {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, + {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, + {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, + {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, + {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, + {0xef340a98172aace4, 0x86fb897116c87c35}, + {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, + {0xbae0a846d2195712, 0x8974836059cca10a}, + {0xe998d258869facd7, 0x2bd1a438703fc94c}, + {0x91ff83775423cc06, 0x7b6306a34627ddd0}, + {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, + {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, + {0x8e938662882af53e, 0x547eb47b7282ee9d}, + {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, + {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, + {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, + {0xae0b158b4738705e, 0x9624ab50b148d446}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, + {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, + {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, + {0xd47487cc8470652b, 0x7647c32000696720}, + {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, + {0xa5fb0a17c777cf09, 0xf468107100525891}, + {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, + {0x81ac1fe293d599bf, 0xc6f14cd848405531}, + {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, + {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, + {0xfd442e4688bd304a, 0x908f4a166d1da664}, + {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, + {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, + {0xf7549530e188c128, 0xd12bee59e68ef47d}, + {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, + {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, + {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, + {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, + {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, + {0xebdf661791d60f56, 0x111b495b3464ad22}, + {0x936b9fcebb25c995, 0xcab10dd900beec35}, + {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, + {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, + {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, + {0xb3f4e093db73a093, 0x59ed216765690f57}, + {0xe0f218b8d25088b8, 0x306869c13ec3532d}, + {0x8c974f7383725573, 0x1e414218c73a13fc}, + {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, + {0x894bc396ce5da772, 0x6b8bba8c328eb784}, + {0xab9eb47c81f5114f, 0x066ea92f3f326565}, + {0xd686619ba27255a2, 0xc80a537b0efefebe}, + {0x8613fd0145877585, 0xbd06742ce95f5f37}, + {0xa798fc4196e952e7, 0x2c48113823b73705}, + {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, + {0x82ef85133de648c4, 0x9a984d73dbe722fc}, + {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, + {0xcc963fee10b7d1b3, 0x318df905079926a9}, + {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, + {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, + {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, + {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, + {0x9c1661a651213e2d, 0x06bea10ca65c084f}, + {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, + {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, + {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, + {0xbe89523386091465, 0xf6bbb397f1135824}, + {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, + {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, + {0xba121a4650e4ddeb, 0x92f34d62616ce414}, + {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, + {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, + {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, + {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, + {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, + {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, + {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, + {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, + {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, + {0x87625f056c7c4a8b, 0x11471cd764ad4973}, + {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, + {0xd389b47879823479, 0x4aff1d108d4ec2c4}, + {0x843610cb4bf160cb, 0xcedf722a585139bb}, + {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, + {0xce947a3da6a9273e, 0x733d226229feea33}, + {0x811ccc668829b887, 0x0806357d5a3f5260}, + {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, + {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, + {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, + {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, + {0xc5029163f384a931, 0x0a9e795e65d4df12}, + {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, + {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, + {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, + {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, + {0x964e858c91ba2655, 0x3a6a07f8d510f870}, + {0xbbe226efb628afea, 0x890489f70a55368c}, + {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, + {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, + {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, + {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, + {0xb32df8e9f3546564, 0x47939822dc96abfa}, + {0xdff9772470297ebd, 0x59787e2b93bc56f8}, + {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, + {0xaefae51477a06b03, 0xede622920b6b23f2}, + {0xdab99e59958885c4, 0xe95fab368e45ecee}, + {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, + {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, + {0xd59944a37c0752a2, 0x4be76d3346f04960}, + {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, + {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, + {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, + {0x825ecc24c873782f, 0x8ed400668c0c28c9}, + {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, + {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, + {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, + {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, + {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, + {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, + {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, + {0xc24452da229b021b, 0xfbe85badce996169}, + {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, + {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, + {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, + {0xed246723473e3813, 0x290123e9aab23b69}, + {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, + {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, + {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, + {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, + {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, + {0x8d590723948a535f, 0x579c487e5a38ad0f}, + {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, + {0xdcdb1b2798182244, 0xf8e431456cf88e66}, + {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, + {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, + {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, + {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, + {0xa87fea27a539e9a5, 0x3f2398d747b36225}, + {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, + {0x83a3eeeef9153e89, 0x1953cf68300424ad}, + {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, + {0xcdb02555653131b6, 0x3792f412cb06794e}, + {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, + {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, + {0xc8de047564d20a8b, 0xf245825a5a445276}, + {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, + {0x9ced737bb6c4183d, 0x55464dd69685606c}, + {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, + {0xf53304714d9265df, 0xd53dd99f4b3066a9}, + {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, + {0xbf8fdb78849a5f96, 0xde98520472bdd034}, + {0xef73d256a5c0f77c, 0x963e66858f6d4441}, + {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xbb127c53b17ec159, 0x5560c018580d5d53}, + {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, + {0x9226712162ab070d, 0xcab3961304ca70e9}, + {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, + {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, + {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, + {0xb267ed1940f1c61c, 0x55f038b237591ed4}, + {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, + {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, + {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, + {0xd9c7dced53c72255, 0x96e7bd358c904a22}, + {0x881cea14545c7575, 0x7e50d64177da2e55}, + {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, + {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, + {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, + {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, + {0xcfb11ead453994ba, 0x67de18eda5814af3}, + {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, + {0xa2425ff75e14fc31, 0xa1258379a94d028e}, + {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, + {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, + {0x9e74d1b791e07e48, 0x775ea264cf55347e}, + {0xc612062576589dda, 0x95364afe032a819e}, + {0xf79687aed3eec551, 0x3a83ddbd83f52205}, + {0x9abe14cd44753b52, 0xc4926a9672793543}, + {0xc16d9a0095928a27, 0x75b7053c0f178294}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, + {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, + {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, + {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, + {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, + {0xb877aa3236a4b449, 0x09befeb9fad487c3}, + {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, + {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, + {0xb424dc35095cd80f, 0x538484c19ef38c95}, + {0xe12e13424bb40e13, 0x2865a5f206b06fba}, + {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, + {0xafebff0bcb24aafe, 0xf78f69a51539d749}, + {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, + {0x89705f4136b4a597, 0x31680a88f8953031}, + {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, + {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, + {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, + {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, + {0xd1b71758e219652b, 0xd3c36113404ea4a9}, + {0x83126e978d4fdf3b, 0x645a1cac083126ea}, + {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, + {0xcccccccccccccccc, 0xcccccccccccccccd}, + {0x8000000000000000, 0x0000000000000000}, + {0xa000000000000000, 0x0000000000000000}, + {0xc800000000000000, 0x0000000000000000}, + {0xfa00000000000000, 0x0000000000000000}, + {0x9c40000000000000, 0x0000000000000000}, + {0xc350000000000000, 0x0000000000000000}, + {0xf424000000000000, 0x0000000000000000}, + {0x9896800000000000, 0x0000000000000000}, + {0xbebc200000000000, 0x0000000000000000}, + {0xee6b280000000000, 0x0000000000000000}, + {0x9502f90000000000, 0x0000000000000000}, + {0xba43b74000000000, 0x0000000000000000}, + {0xe8d4a51000000000, 0x0000000000000000}, + {0x9184e72a00000000, 0x0000000000000000}, + {0xb5e620f480000000, 0x0000000000000000}, + {0xe35fa931a0000000, 0x0000000000000000}, + {0x8e1bc9bf04000000, 0x0000000000000000}, + {0xb1a2bc2ec5000000, 0x0000000000000000}, + {0xde0b6b3a76400000, 0x0000000000000000}, + {0x8ac7230489e80000, 0x0000000000000000}, + {0xad78ebc5ac620000, 0x0000000000000000}, + {0xd8d726b7177a8000, 0x0000000000000000}, + {0x878678326eac9000, 0x0000000000000000}, + {0xa968163f0a57b400, 0x0000000000000000}, + {0xd3c21bcecceda100, 0x0000000000000000}, + {0x84595161401484a0, 0x0000000000000000}, + {0xa56fa5b99019a5c8, 0x0000000000000000}, + {0xcecb8f27f4200f3a, 0x0000000000000000}, + {0x813f3978f8940984, 0x4000000000000000}, + {0xa18f07d736b90be5, 0x5000000000000000}, + {0xc9f2c9cd04674ede, 0xa400000000000000}, + {0xfc6f7c4045812296, 0x4d00000000000000}, + {0x9dc5ada82b70b59d, 0xf020000000000000}, + {0xc5371912364ce305, 0x6c28000000000000}, + {0xf684df56c3e01bc6, 0xc732000000000000}, + {0x9a130b963a6c115c, 0x3c7f400000000000}, + {0xc097ce7bc90715b3, 0x4b9f100000000000}, + {0xf0bdc21abb48db20, 0x1e86d40000000000}, + {0x96769950b50d88f4, 0x1314448000000000}, + {0xbc143fa4e250eb31, 0x17d955a000000000}, + {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, + {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, + {0xb7abc627050305ad, 0xf14a3d9e40000000}, + {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, + {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, + {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, + {0xe0352f62a19e306e, 0xd50b2037ad200000}, + {0x8c213d9da502de45, 0x4526f422cc340000}, + {0xaf298d050e4395d6, 0x9670b12b7f410000}, + {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, + {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, + {0xab0e93b6efee0053, 0x8eea0d047a457a00}, + {0xd5d238a4abe98068, 0x72a4904598d6d880}, + {0x85a36366eb71f041, 0x47a6da2b7f864750}, + {0xa70c3c40a64e6c51, 0x999090b65f67d924}, + {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, + {0x82818f1281ed449f, 0xbff8f10e7a8921a5}, + {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0x9f4f2726179a2245, 0x01d762422c946591}, + {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, + {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, + {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, + {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, + {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, + {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, + {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, + {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, + {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, + {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, + {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, + {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, + {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, + {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, + {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, + {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, + {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, + {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, + {0xacb92ed9397bf996, 0x49c2c37f07965405}, + {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, + {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, + {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, + {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, + {0x83c7088e1aab65db, 0x792667c6da79e0fb}, + {0xa4b8cab1a1563f52, 0x577001b891185939}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0x80b05e5ac60b6178, 0x544f8158315b05b5}, + {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, + {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, + {0xfb5878494ace3a5f, 0x04ab48a04065c724}, + {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, + {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, + {0xf5746577930d6500, 0xca8f44ec7ee3647a}, + {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, + {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, + {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, + {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, + {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, + {0xea1575143cf97226, 0xf52d09d71a3293be}, + {0x924d692ca61be758, 0x593c2626705f9c57}, + {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, + {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, + {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, + {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, + {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, + {0x8b865b215899f46c, 0xbd79e0d20082ee75}, + {0xae67f1e9aec07187, 0xecd8590680a3aa12}, + {0xda01ee641a708de9, 0xe80e6f4820cc9496}, + {0x884134fe908658b2, 0x3109058d147fdcde}, + {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, + {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0xcfe87f7cef46ff16, 0xe612641865679a64}, + {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, + {0xa26da3999aef7749, 0xe3be5e330f38f09e}, + {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, + {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, + {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, + {0xc646d63501a1511d, 0xb281e1fd541501b9}, + {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, + {0x9ae757596946075f, 0x3375788de9b06959}, + {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, + {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, + {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, + {0xbd176620a501fbff, 0xb650e5a93bc3d899}, + {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, + {0x93ba47c980e98cdf, 0xc66f336c36b10138}, + {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, + {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, + {0x9043ea1ac7e41392, 0x87c89837ad68db30}, + {0xb454e4a179dd1877, 0x29babe4598c311fc}, + {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, + {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, + {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, + {0xdc21a1171d42645d, 0x76707543f4fa1f74}, + {0x899504ae72497eba, 0x6a06494a791c53a9}, + {0xabfa45da0edbde69, 0x0487db9d17636893}, + {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xa7f26836f282b732, 0x8e6cac7768d7141f}, + {0xd1ef0244af2364ff, 0x3207d795430cd927}, + {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, + {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, + {0xcd036837130890a1, 0x36dba887c37a8c10}, + {0x802221226be55a64, 0xc2494954da2c978a}, + {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, + {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, + {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, + {0x9c69a97284b578d7, 0xff2a760414536efc}, + {0xc38413cf25e2d70d, 0xfef5138519684abb}, + {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, + {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, + {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, + {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, + {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, + {0xba756174393d88df, 0x94f971119aeef9e5}, + {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, + {0x91abb422ccb812ee, 0xac62e055c10ab33b}, + {0xb616a12b7fe617aa, 0x577b986b314d600a}, + {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, + {0x8e41ade9fbebc27d, 0x14588f13be847308}, + {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, + {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, + {0x8aec23d680043bee, 0x25de7bb9480d5855}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0x87aa9aff79042286, 0x90fb44d2f05d0843}, + {0xa99541bf57452b28, 0x353a1607ac744a54}, + {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, + {0x847c9b5d7c2e09b7, 0x69956135febada12}, + {0xa59bc234db398c25, 0x43fab9837e699096}, + {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, + {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, + {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, + {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, + {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, + {0x9defbf01b061adab, 0x3a0888136afa64a8}, + {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, + {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, + {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, + {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, + {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, + {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, + {0xbc4665b596706114, 0x873d5d9f0dde1fef}, + {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, + {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, + {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, + {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, + {0x8fa475791a569d10, 0xf96e017d694487bd}, + {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, + {0xe070f78d3927556a, 0x85bbe253f47b1418}, + {0x8c469ab843b89562, 0x93956d7478ccec8f}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, + {0x88fcf317f22241e2, 0x441fece3bdf81f04}, + {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, + {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, + {0x85c7056562757456, 0xf6872d5667844e4a}, + {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, + {0xd106f86e69d785c7, 0xe13336d701beba53}, + {0x82a45b450226b39c, 0xecc0024661173474}, + {0xa34d721642b06084, 0x27f002d7f95d0191}, + {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, + {0xff290242c83396ce, 0x7e67047175a15272}, + {0x9f79a169bd203e41, 0x0f0062c6e984d387}, + {0xc75809c42c684dd1, 0x52c07b78a3e60869}, + {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, + {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, + {0xc2abf989935ddbfe, 0x6acff893d00ea436}, + {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, + {0x98165af37b2153de, 0xc3727a337a8b704b}, + {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, + {0xeda2ee1c7064130c, 0x1162def06f79df74}, + {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, + {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, + {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, + {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, + {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xb10d8e1456105dad, 0x7425a83e872c5f48}, + {0xdd50f1996b947518, 0xd12f124e28f7771a}, + {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, + {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, + {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, + {0x8714a775e3e95c78, 0x65acfaec34810a72}, + {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, + {0xd31045a8341ca07c, 0x1ede48111209a051}, + {0x83ea2b892091e44d, 0x934aed0aab460433}, + {0xa4e4b66b68b65d60, 0xf81da84d56178540}, + {0xce1de40642e3f4b9, 0x36251260ab9d668f}, + {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, + {0xa1075a24e4421730, 0xb24cf65b8612f820}, + {0xc94930ae1d529cfc, 0xdee033f26797b628}, + {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, + {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, + {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, + {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, + {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, + {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, + {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, + {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, + {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, + {0xea53df5fd18d5513, 0x84c86189216dc5ee}, + {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, + {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, + {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, + {0xdf78e4b2bd342cf6, 0x914da9246b255417}, + {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, + {0xae9672aba3d0c320, 0xa184ac2473b529b2}, + {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, + {0x8865899617fb1871, 0x7e2fa67c7a658893}, + {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, + {0xd51ea6fa85785631, 0x552a74227f3ea566}, + {0x8533285c936b35de, 0xd53a88958f872760}, + {0xa67ff273b8460356, 0x8a892abaf368f138}, + {0xd01fef10a657842c, 0x2d2b7569b0432d86}, + {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, + {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, + {0xcb3f2f7642717713, 0x241c70a936219a74}, + {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, + {0x9ec95d1463e8a506, 0xf4363804324a40ab}, + {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, + {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, + {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, + {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, + {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, + {0x976e41088617ca01, 0xd5be0503e085d814}, + {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, + {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, + {0x906a617d450187e2, 0x27fb2b80668b24c6}, + {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, + {0xe1a63853bbd26451, 0x5e7873f8a0396974}, + {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, + {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, + {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, + {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, + {0xac2820d9623bf429, 0x546345fa9fbdcd45}, + {0xd732290fbacaf133, 0xa97c177947ad4096}, + {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, + {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, + {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, + {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, + {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, + {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, + {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, + {0xa0555e361951c366, 0xd7e105bcc3326220}, + {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, + {0xfa856334878fc150, 0xb14f98f6f0feb952}, + {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, + {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, + {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, + {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, + {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, + {0xeeea5d5004981478, 0x1858ccfce06cac75}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xbaa718e68396cffd, 0xd30560258f54e6bb}, + {0xe950df20247c83fd, 0x47c6b82ef32a206a}, + {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, + {0xb6472e511c81471d, 0xe0133fe4adf8e953}, + {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, + {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, + {0xb201833b35d63f73, 0x2cd2cc6551e513db}, + {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, + {0x8b112e86420f6191, 0xfb04afaf27faf783}, + {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, + {0xd94ad8b1c7380874, 0x18375281ae7822bd}, + {0x87cec76f1c830548, 0x8f2293910d0b15b6}, + {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, + {0xd433179d9c8cb841, 0x5fa60692a46151ec}, + {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, + {0xa5c7ea73224deff3, 0x12b9b522906c0801}, + {0xcf39e50feae16bef, 0xd768226b34870a01}, + {0x81842f29f2cce375, 0xe6a1158300d46641}, + {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, + {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, + {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, + {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, + {0xc5a05277621be293, 0xc7098b7305241886}, + {0xf70867153aa2db38, 0xb8cbee4fc66d1ea8}, + {0x9a65406d44a5c903, 0x737f74f1dc043329}, + {0xc0fe908895cf3b44, 0x505f522e53053ff3}, + {0xf13e34aabb430a15, 0x647726b9e7c68ff0}, + {0x96c6e0eab509e64d, 0x5eca783430dc19f6}, + {0xbc789925624c5fe0, 0xb67d16413d132073}, + {0xeb96bf6ebadf77d8, 0xe41c5bd18c57e890}, + {0x933e37a534cbaae7, 0x8e91b962f7b6f15a}, + {0xb80dc58e81fe95a1, 0x723627bbb5a4adb1}, + {0xe61136f2227e3b09, 0xcec3b1aaa30dd91d}, + {0x8fcac257558ee4e6, 0x213a4f0aa5e8a7b2}, + {0xb3bd72ed2af29e1f, 0xa988e2cd4f62d19e}, + {0xe0accfa875af45a7, 0x93eb1b80a33b8606}, + {0x8c6c01c9498d8b88, 0xbc72f130660533c4}, + {0xaf87023b9bf0ee6a, 0xeb8fad7c7f8680b5}, + {0xdb68c2ca82ed2a05, 0xa67398db9f6820e2}, +#else + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, + {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, + {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, + {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, + {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, + {0xc350000000000000, 0x0000000000000000}, + {0x9dc5ada82b70b59d, 0xf020000000000000}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xf13e34aabb430a15, 0x647726b9e7c68ff0} +#endif + }; + +#if FMT_USE_FULL_CACHE_DRAGONBOX + return pow10_significands[k - float_info::min_k]; +#else + static constexpr const uint64_t powers_of_5_64[] = { + 0x0000000000000001, 0x0000000000000005, 0x0000000000000019, + 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35, + 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1, + 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd, + 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9, + 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5, + 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631, + 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, + 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; + + static const int compression_ratio = 27; + + // Compute base index. + int cache_index = (k - float_info::min_k) / compression_ratio; + int kb = cache_index * compression_ratio + float_info::min_k; + int offset = k - kb; + + // Get base cache. + uint128_fallback base_cache = pow10_significands[cache_index]; + if (offset == 0) return base_cache; + + // Compute the required amount of bit-shift. + int alpha = floor_log2_pow10(kb + offset) - floor_log2_pow10(kb) - offset; + FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected"); + + // Try to recover the real cache. + uint64_t pow5 = powers_of_5_64[offset]; + uint128_fallback recovered_cache = umul128(base_cache.high(), pow5); + uint128_fallback middle_low = umul128(base_cache.low(), pow5); + + recovered_cache += middle_low.high(); + + uint64_t high_to_middle = recovered_cache.high() << (64 - alpha); + uint64_t middle_to_low = recovered_cache.low() << (64 - alpha); + + recovered_cache = + uint128_fallback{(recovered_cache.low() >> alpha) | high_to_middle, + ((middle_low.low() >> alpha) | middle_to_low)}; + FMT_ASSERT(recovered_cache.low() + 1 != 0, ""); + return {recovered_cache.high(), recovered_cache.low() + 1}; +#endif + } + + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static auto compute_mul(carrier_uint u, + const cache_entry_type& cache) noexcept + -> compute_mul_result { + auto r = umul192_upper128(u, cache); + return {r.high(), r.low() == 0}; + } + + static auto compute_delta(cache_entry_type const& cache, int beta) noexcept + -> uint32_t { + return static_cast(cache.high() >> (64 - 1 - beta)); + } + + static auto compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta) noexcept + -> compute_mul_parity_result { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); + + auto r = umul192_lower128(two_f, cache); + return {((r.high() >> (64 - beta)) & 1) != 0, + ((r.high() << beta) | (r.low() >> (64 - beta))) == 0}; + } + + static auto compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (cache.high() - + (cache.high() >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta); + } + + static auto compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (cache.high() + + (cache.high() >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta); + } + + static auto compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return ((cache.high() >> (64 - num_significand_bits() - 2 - beta)) + + 1) / + 2; + } +}; + +FMT_FUNC auto get_cached_power(int k) noexcept -> uint128_fallback { + return cache_accessor::get_cached_power(k); +} + +// Various integer checks +template +auto is_left_endpoint_integer_shorter_interval(int exponent) noexcept -> bool { + const int case_shorter_interval_left_endpoint_lower_threshold = 2; + const int case_shorter_interval_left_endpoint_upper_threshold = 3; + return exponent >= case_shorter_interval_left_endpoint_lower_threshold && + exponent <= case_shorter_interval_left_endpoint_upper_threshold; +} + +// Remove trailing zeros from n and return the number of zeros removed (float) +FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept { + FMT_ASSERT(n != 0, ""); + // Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1. + constexpr uint32_t mod_inv_5 = 0xcccccccd; + constexpr uint32_t mod_inv_25 = 0xc28f5c29; // = mod_inv_5 * mod_inv_5 + + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; + } + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; + } + return s; +} + +// Removes trailing zeros and returns the number of zeros removed (double) +FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept { + FMT_ASSERT(n != 0, ""); + + // This magic number is ceil(2^90 / 10^8). + constexpr uint64_t magic_number = 12379400392853802749ull; + auto nm = umul128(n, magic_number); + + // Is n is divisible by 10^8? + if ((nm.high() & ((1ull << (90 - 64)) - 1)) == 0 && nm.low() < magic_number) { + // If yes, work with the quotient... + auto n32 = static_cast(nm.high() >> (90 - 64)); + // ... and use the 32 bit variant of the function + int s = remove_trailing_zeros(n32, 8); + n = n32; + return s; + } + + // If n is not divisible by 10^8, work with n itself. + constexpr uint64_t mod_inv_5 = 0xcccccccccccccccd; + constexpr uint64_t mod_inv_25 = 0x8f5c28f5c28f5c29; // mod_inv_5 * mod_inv_5 + + int s = 0; + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; + } + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; + } + + return s; +} + +// The main algorithm for shorter interval case +template +FMT_INLINE decimal_fp shorter_interval_case(int exponent) noexcept { + decimal_fp ret_value; + // Compute k and beta + const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); + const int beta = exponent + floor_log2_pow10(-minus_k); + + // Compute xi and zi + using cache_entry_type = typename cache_accessor::cache_entry_type; + const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); + + auto xi = cache_accessor::compute_left_endpoint_for_shorter_interval_case( + cache, beta); + auto zi = cache_accessor::compute_right_endpoint_for_shorter_interval_case( + cache, beta); + + // If the left endpoint is not an integer, increase it + if (!is_left_endpoint_integer_shorter_interval(exponent)) ++xi; + + // Try bigger divisor + ret_value.significand = zi / 10; + + // If succeed, remove trailing zeros if necessary and return + if (ret_value.significand * 10 >= xi) { + ret_value.exponent = minus_k + 1; + ret_value.exponent += remove_trailing_zeros(ret_value.significand); + return ret_value; + } + + // Otherwise, compute the round-up of y + ret_value.significand = + cache_accessor::compute_round_up_for_shorter_interval_case(cache, + beta); + ret_value.exponent = minus_k; + + // When tie occurs, choose one of them according to the rule + if (exponent >= float_info::shorter_interval_tie_lower_threshold && + exponent <= float_info::shorter_interval_tie_upper_threshold) { + ret_value.significand = ret_value.significand % 2 == 0 + ? ret_value.significand + : ret_value.significand - 1; + } else if (ret_value.significand < xi) { + ++ret_value.significand; + } + return ret_value; +} + +template auto to_decimal(T x) noexcept -> decimal_fp { + // Step 1: integer promotion & Schubfach multiplier calculation. + + using carrier_uint = typename float_info::carrier_uint; + using cache_entry_type = typename cache_accessor::cache_entry_type; + auto br = bit_cast(x); + + // Extract significand bits and exponent bits. + const carrier_uint significand_mask = + (static_cast(1) << num_significand_bits()) - 1; + carrier_uint significand = (br & significand_mask); + int exponent = + static_cast((br & exponent_mask()) >> num_significand_bits()); + + if (exponent != 0) { // Check if normal. + exponent -= exponent_bias() + num_significand_bits(); + + // Shorter interval case; proceed like Schubfach. + // In fact, when exponent == 1 and significand == 0, the interval is + // regular. However, it can be shown that the end-results are anyway same. + if (significand == 0) return shorter_interval_case(exponent); + + significand |= (static_cast(1) << num_significand_bits()); + } else { + // Subnormal case; the interval is always regular. + if (significand == 0) return {0, 0}; + exponent = + std::numeric_limits::min_exponent - num_significand_bits() - 1; + } + + const bool include_left_endpoint = (significand % 2 == 0); + const bool include_right_endpoint = include_left_endpoint; + + // Compute k and beta. + const int minus_k = floor_log10_pow2(exponent) - float_info::kappa; + const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); + const int beta = exponent + floor_log2_pow10(-minus_k); + + // Compute zi and deltai. + // 10^kappa <= deltai < 10^(kappa + 1) + const uint32_t deltai = cache_accessor::compute_delta(cache, beta); + const carrier_uint two_fc = significand << 1; + + // For the case of binary32, the result of integer check is not correct for + // 29711844 * 2^-82 + // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 + // and 29711844 * 2^-81 + // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17, + // and they are the unique counterexamples. However, since 29711844 is even, + // this does not cause any problem for the endpoints calculations; it can only + // cause a problem when we need to perform integer check for the center. + // Fortunately, with these inputs, that branch is never executed, so we are + // fine. + const typename cache_accessor::compute_mul_result z_mul = + cache_accessor::compute_mul((two_fc | 1) << beta, cache); + + // Step 2: Try larger divisor; remove trailing zeros if necessary. + + // Using an upper bound on zi, we might be able to optimize the division + // better than the compiler; we are computing zi / big_divisor here. + decimal_fp ret_value; + ret_value.significand = divide_by_10_to_kappa_plus_1(z_mul.result); + uint32_t r = static_cast(z_mul.result - float_info::big_divisor * + ret_value.significand); + + if (r < deltai) { + // Exclude the right endpoint if necessary. + if (r == 0 && (z_mul.is_integer & !include_right_endpoint)) { + --ret_value.significand; + r = float_info::big_divisor; + goto small_divisor_case_label; + } + } else if (r > deltai) { + goto small_divisor_case_label; + } else { + // r == deltai; compare fractional parts. + const typename cache_accessor::compute_mul_parity_result x_mul = + cache_accessor::compute_mul_parity(two_fc - 1, cache, beta); + + if (!(x_mul.parity | (x_mul.is_integer & include_left_endpoint))) + goto small_divisor_case_label; + } + ret_value.exponent = minus_k + float_info::kappa + 1; + + // We may need to remove trailing zeros. + ret_value.exponent += remove_trailing_zeros(ret_value.significand); + return ret_value; + + // Step 3: Find the significand with the smaller divisor. + +small_divisor_case_label: + ret_value.significand *= 10; + ret_value.exponent = minus_k + float_info::kappa; + + uint32_t dist = r - (deltai / 2) + (float_info::small_divisor / 2); + const bool approx_y_parity = + ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; + + // Is dist divisible by 10^kappa? + const bool divisible_by_small_divisor = + check_divisibility_and_divide_by_pow10::kappa>(dist); + + // Add dist / 10^kappa to the significand. + ret_value.significand += dist; + + if (!divisible_by_small_divisor) return ret_value; + + // Check z^(f) >= epsilon^(f). + // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, + // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f). + // Since there are only 2 possibilities, we only need to care about the + // parity. Also, zi and r should have the same parity since the divisor + // is an even number. + const auto y_mul = cache_accessor::compute_mul_parity(two_fc, cache, beta); + + // If z^(f) >= epsilon^(f), we might have a tie when z^(f) == epsilon^(f), + // or equivalently, when y is an integer. + if (y_mul.parity != approx_y_parity) + --ret_value.significand; + else if (y_mul.is_integer & (ret_value.significand % 2 != 0)) + --ret_value.significand; + return ret_value; +} +} // namespace dragonbox +} // namespace detail + +template <> struct formatter { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { + return ctx.begin(); + } + + auto format(const detail::bigint& n, format_context& ctx) const + -> format_context::iterator { + auto out = ctx.out(); + bool first = true; + for (auto i = n.bigits_.size(); i > 0; --i) { + auto value = n.bigits_[i - 1u]; + if (first) { + out = fmt::format_to(out, FMT_STRING("{:x}"), value); + first = false; + continue; + } + out = fmt::format_to(out, FMT_STRING("{:08x}"), value); + } + if (n.exp_ > 0) + out = fmt::format_to(out, FMT_STRING("p{}"), + n.exp_ * detail::bigint::bigit_bits); + return out; + } +}; + +FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { + for_each_codepoint(s, [this](uint32_t cp, string_view) { + if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8")); + if (cp <= 0xFFFF) { + buffer_.push_back(static_cast(cp)); + } else { + cp -= 0x10000; + buffer_.push_back(static_cast(0xD800 + (cp >> 10))); + buffer_.push_back(static_cast(0xDC00 + (cp & 0x3FF))); + } + return true; + }); + buffer_.push_back(0); +} + +FMT_FUNC void format_system_error(detail::buffer& out, int error_code, + const char* message) noexcept { + FMT_TRY { + auto ec = std::error_code(error_code, std::generic_category()); + write(std::back_inserter(out), std::system_error(ec, message).what()); + return; + } + FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +FMT_FUNC void report_system_error(int error_code, + const char* message) noexcept { + report_error(format_system_error, error_code, message); +} + +FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string { + // Don't optimize the "{}" case to keep the binary size small and because it + // can be better optimized in fmt::format anyway. + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + return to_string(buffer); +} + +namespace detail { +#if !defined(_WIN32) || defined(FMT_WINDOWS_NO_WCHAR) +FMT_FUNC auto write_console(int, string_view) -> bool { return false; } +FMT_FUNC auto write_console(std::FILE*, string_view) -> bool { return false; } +#else +using dword = conditional_t; +extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // + void*, const void*, dword, dword*, void*); + +FMT_FUNC bool write_console(int fd, string_view text) { + auto u16 = utf8_to_utf16(text); + return WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), u16.c_str(), + static_cast(u16.size()), nullptr, nullptr) != 0; +} + +FMT_FUNC auto write_console(std::FILE* f, string_view text) -> bool { + return write_console(_fileno(f), text); +} +#endif + +#ifdef _WIN32 +// Print assuming legacy (non-Unicode) encoding. +FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + fwrite_fully(buffer.data(), buffer.size(), f); +} +#endif + +FMT_FUNC void print(std::FILE* f, string_view text) { +#ifdef _WIN32 + int fd = _fileno(f); + if (_isatty(fd)) { + std::fflush(f); + if (write_console(fd, text)) return; + } +#endif + fwrite_fully(text.data(), text.size(), f); +} +} // namespace detail + +FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + detail::print(f, {buffer.data(), buffer.size()}); +} + +FMT_FUNC void vprint(string_view fmt, format_args args) { + vprint(stdout, fmt, args); +} + +namespace detail { + +struct singleton { + unsigned char upper; + unsigned char lower_count; +}; + +inline auto is_printable(uint16_t x, const singleton* singletons, + size_t singletons_size, + const unsigned char* singleton_lowers, + const unsigned char* normal, size_t normal_size) + -> bool { + auto upper = x >> 8; + auto lower_start = 0; + for (size_t i = 0; i < singletons_size; ++i) { + auto s = singletons[i]; + auto lower_end = lower_start + s.lower_count; + if (upper < s.upper) break; + if (upper == s.upper) { + for (auto j = lower_start; j < lower_end; ++j) { + if (singleton_lowers[j] == (x & 0xff)) return false; + } + } + lower_start = lower_end; + } + + auto xsigned = static_cast(x); + auto current = true; + for (size_t i = 0; i < normal_size; ++i) { + auto v = static_cast(normal[i]); + auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v; + xsigned -= len; + if (xsigned < 0) break; + current = !current; + } + return current; +} + +// This code is generated by support/printable.py. +FMT_FUNC auto is_printable(uint32_t cp) -> bool { + static constexpr singleton singletons0[] = { + {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8}, + {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13}, + {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5}, + {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22}, + {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3}, + {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8}, + {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9}, + }; + static constexpr unsigned char singletons0_lower[] = { + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90, + 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, + 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d, + 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, + 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, + 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d, + 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, + 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, + 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, + 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, + 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, + 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, + 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, + 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, + 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, + 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, + 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, + 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0, + 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, + 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, + 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, + 0xfe, 0xff, + }; + static constexpr singleton singletons1[] = { + {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2}, + {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5}, + {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5}, + {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2}, + {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5}, + {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2}, + {0xfa, 2}, {0xfb, 1}, + }; + static constexpr unsigned char singletons1_lower[] = { + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, + 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, + 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b, + 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, + 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, + 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, + 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, + 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, + 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, + 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, + }; + static constexpr unsigned char normal0[] = { + 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04, + 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0, + 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, + 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03, + 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03, + 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a, + 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15, + 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f, + 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80, + 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, + 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06, + 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04, + 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac, + 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c, + 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, + 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, + 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, + 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6, + 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03, + 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80, + 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06, + 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c, + 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17, + 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80, + 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80, + 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d, + }; + static constexpr unsigned char normal1[] = { + 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f, + 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e, + 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04, + 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09, + 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16, + 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f, + 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36, + 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33, + 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, + 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, + 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, + 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, + 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, + 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04, + 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, + 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, + 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81, + 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, + 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, + 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a, + 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11, + 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09, + 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, + 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6, + 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, + 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, + 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05, + 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, + 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, + 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80, + 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, + 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, + 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e, + 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07, + 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, + }; + auto lower = static_cast(cp); + if (cp < 0x10000) { + return is_printable(lower, singletons0, + sizeof(singletons0) / sizeof(*singletons0), + singletons0_lower, normal0, sizeof(normal0)); + } + if (cp < 0x20000) { + return is_printable(lower, singletons1, + sizeof(singletons1) / sizeof(*singletons1), + singletons1_lower, normal1, sizeof(normal1)); + } + if (0x2a6de <= cp && cp < 0x2a700) return false; + if (0x2b735 <= cp && cp < 0x2b740) return false; + if (0x2b81e <= cp && cp < 0x2b820) return false; + if (0x2cea2 <= cp && cp < 0x2ceb0) return false; + if (0x2ebe1 <= cp && cp < 0x2f800) return false; + if (0x2fa1e <= cp && cp < 0x30000) return false; + if (0x3134b <= cp && cp < 0xe0100) return false; + if (0xe01f0 <= cp && cp < 0x110000) return false; + return cp < 0x110000; +} + +} // namespace detail + +FMT_END_NAMESPACE + +#endif // FMT_FORMAT_INL_H_ diff --git a/dep/fmt/include/fmt/format.h b/dep/fmt/include/fmt/format.h new file mode 100644 index 00000000000..7637c8a0d06 --- /dev/null +++ b/dep/fmt/include/fmt/format.h @@ -0,0 +1,4535 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - present, Victor Zverovich + + 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. + + --- Optional exception to the license --- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into a machine-executable object form of such + source code, you may redistribute such embedded portions in such object form + without including the above copyright and permission notices. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include // std::signbit +#include // uint32_t +#include // std::memcpy +#include // std::initializer_list +#include // std::numeric_limits +#include // std::uninitialized_copy +#include // std::runtime_error +#include // std::system_error + +#ifdef __cpp_lib_bit_cast +# include // std::bit_cast +#endif + +#include "core.h" + +#if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L +# define FMT_INLINE_VARIABLE inline +#else +# define FMT_INLINE_VARIABLE +#endif + +#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough) +# define FMT_FALLTHROUGH [[fallthrough]] +#elif defined(__clang__) +# define FMT_FALLTHROUGH [[clang::fallthrough]] +#elif FMT_GCC_VERSION >= 700 && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) +# define FMT_FALLTHROUGH [[gnu::fallthrough]] +#else +# define FMT_FALLTHROUGH +#endif + +#ifndef FMT_DEPRECATED +# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900 +# define FMT_DEPRECATED [[deprecated]] +# else +# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) +# define FMT_DEPRECATED __attribute__((deprecated)) +# elif FMT_MSC_VERSION +# define FMT_DEPRECATED __declspec(deprecated) +# else +# define FMT_DEPRECATED /* deprecated */ +# endif +# endif +#endif + +#ifndef FMT_NO_UNIQUE_ADDRESS +# if FMT_CPLUSPLUS >= 202002L +# if FMT_HAS_CPP_ATTRIBUTE(no_unique_address) +# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]] +// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485) +# elif (FMT_MSC_VERSION >= 1929) && !FMT_CLANG_VERSION +# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +# endif +# endif +#endif +#ifndef FMT_NO_UNIQUE_ADDRESS +# define FMT_NO_UNIQUE_ADDRESS +#endif + +// Visibility when compiled as a shared library/object. +#if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) +# define FMT_SO_VISIBILITY(value) FMT_VISIBILITY(value) +#else +# define FMT_SO_VISIBILITY(value) +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_NOINLINE __attribute__((noinline)) +#else +# define FMT_NOINLINE +#endif + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# if FMT_MSC_VERSION || defined(__NVCC__) +FMT_BEGIN_NAMESPACE +namespace detail { +template inline void do_throw(const Exception& x) { + // Silence unreachable code warnings in MSVC and NVCC because these + // are nearly impossible to fix in a generic code. + volatile bool b = true; + if (b) throw x; +} +} // namespace detail +FMT_END_NAMESPACE +# define FMT_THROW(x) detail::do_throw(x) +# else +# define FMT_THROW(x) throw x +# endif +# else +# define FMT_THROW(x) \ + ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what()) +# endif +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifndef FMT_MAYBE_UNUSED +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] +# else +# define FMT_MAYBE_UNUSED +# endif +#endif + +#ifndef FMT_USE_USER_DEFINED_LITERALS +// EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. +// +// GCC before 4.9 requires a space in `operator"" _a` which is invalid in later +// compiler versions. +# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 409 || \ + FMT_MSC_VERSION >= 1900) && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif +#endif + +// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of +// integer formatter template instantiations to just one by only using the +// largest integer type. This results in a reduction in binary size but will +// cause a decrease in integer formatting performance. +#if !defined(FMT_REDUCE_INT_INSTANTIATIONS) +# define FMT_REDUCE_INT_INSTANTIATIONS 0 +#endif + +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519. +#if !FMT_MSC_VERSION +# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif +#endif + +// __builtin_ctz is broken in Intel Compiler Classic on Windows: +// https://github.com/fmtlib/fmt/issues/2510. +#ifndef __ICL +# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \ + defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \ + FMT_ICC_VERSION || defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) +# endif +#endif + +#if FMT_MSC_VERSION +# include // _BitScanReverse[64], _BitScanForward[64], _umul128 +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +// MSVC intrinsics if the clz and clzll builtins are not available. +#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \ + !defined(FMT_BUILTIN_CTZLL) +FMT_BEGIN_NAMESPACE +namespace detail { +// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. +# if !defined(__clang__) +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +# if defined(_WIN64) +# pragma intrinsic(_BitScanForward64) +# pragma intrinsic(_BitScanReverse64) +# endif +# endif + +inline auto clz(uint32_t x) -> int { + unsigned long r = 0; + _BitScanReverse(&r, x); + FMT_ASSERT(x != 0, ""); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. + FMT_MSC_WARNING(suppress : 6102) + return 31 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZ(n) detail::clz(n) + +inline auto clzll(uint64_t x) -> int { + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 ^ static_cast(r + 32); + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x)); +# endif + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return 63 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZLL(n) detail::clzll(n) + +inline auto ctz(uint32_t x) -> int { + unsigned long r = 0; + _BitScanForward(&r, x); + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return static_cast(r); +} +# define FMT_BUILTIN_CTZ(n) detail::ctz(n) + +inline auto ctzll(uint64_t x) -> int { + unsigned long r = 0; + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. +# ifdef _WIN64 + _BitScanForward64(&r, x); +# else + // Scan the low 32 bits. + if (_BitScanForward(&r, static_cast(x))) return static_cast(r); + // Scan the high 32 bits. + _BitScanForward(&r, static_cast(x >> 32)); + r += 32; +# endif + return static_cast(r); +} +# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) +} // namespace detail +FMT_END_NAMESPACE +#endif + +FMT_BEGIN_NAMESPACE +namespace detail { + +FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) { + ignore_unused(condition); +#ifdef FMT_FUZZ + if (condition) throw std::runtime_error("fuzzing limit reached"); +#endif +} + +template struct string_literal { + static constexpr CharT value[sizeof...(C)] = {C...}; + constexpr operator basic_string_view() const { + return {value, sizeof...(C)}; + } +}; + +#if FMT_CPLUSPLUS < 201703L +template +constexpr CharT string_literal::value[sizeof...(C)]; +#endif + +// Implementation of std::bit_cast for pre-C++20. +template +FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { +#ifdef __cpp_lib_bit_cast + if (is_constant_evaluated()) return std::bit_cast(from); +#endif + auto to = To(); + // The cast suppresses a bogus -Wclass-memaccess on GCC. + std::memcpy(static_cast(&to), &from, sizeof(to)); + return to; +} + +inline auto is_big_endian() -> bool { +#ifdef _WIN32 + return false; +#elif defined(__BIG_ENDIAN__) + return true; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) + return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; +#else + struct bytes { + char data[sizeof(int)]; + }; + return bit_cast(1).data[0] == 0; +#endif +} + +class uint128_fallback { + private: + uint64_t lo_, hi_; + + public: + constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {} + constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {} + + constexpr auto high() const noexcept -> uint64_t { return hi_; } + constexpr auto low() const noexcept -> uint64_t { return lo_; } + + template ::value)> + constexpr explicit operator T() const { + return static_cast(lo_); + } + + friend constexpr auto operator==(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; + } + friend constexpr auto operator!=(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return !(lhs == rhs); + } + friend constexpr auto operator>(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; + } + friend constexpr auto operator|(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; + } + friend constexpr auto operator&(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; + } + friend constexpr auto operator~(const uint128_fallback& n) + -> uint128_fallback { + return {~n.hi_, ~n.lo_}; + } + friend auto operator+(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> uint128_fallback { + auto result = uint128_fallback(lhs); + result += rhs; + return result; + } + friend auto operator*(const uint128_fallback& lhs, uint32_t rhs) + -> uint128_fallback { + FMT_ASSERT(lhs.hi_ == 0, ""); + uint64_t hi = (lhs.lo_ >> 32) * rhs; + uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; + uint64_t new_lo = (hi << 32) + lo; + return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; + } + friend auto operator-(const uint128_fallback& lhs, uint64_t rhs) + -> uint128_fallback { + return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; + } + FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback { + if (shift == 64) return {0, hi_}; + if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64); + return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; + } + FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback { + if (shift == 64) return {lo_, 0}; + if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64); + return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; + } + FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& { + return *this = *this >> shift; + } + FMT_CONSTEXPR void operator+=(uint128_fallback n) { + uint64_t new_lo = lo_ + n.lo_; + uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0); + FMT_ASSERT(new_hi >= hi_, ""); + lo_ = new_lo; + hi_ = new_hi; + } + FMT_CONSTEXPR void operator&=(uint128_fallback n) { + lo_ &= n.lo_; + hi_ &= n.hi_; + } + + FMT_CONSTEXPR20 auto operator+=(uint64_t n) noexcept -> uint128_fallback& { + if (is_constant_evaluated()) { + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); + return *this; + } +#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) + unsigned long long carry; + lo_ = __builtin_addcll(lo_, n, 0, &carry); + hi_ += carry; +#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) + unsigned long long result; + auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result); + lo_ = result; + hi_ += carry; +#elif defined(_MSC_VER) && defined(_M_X64) + auto carry = _addcarry_u64(0, lo_, n, &lo_); + _addcarry_u64(carry, hi_, 0, &hi_); +#else + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); +#endif + return *this; + } +}; + +using uint128_t = conditional_t; + +#ifdef UINTPTR_MAX +using uintptr_t = ::uintptr_t; +#else +using uintptr_t = uint128_t; +#endif + +// Returns the largest possible value for type T. Same as +// std::numeric_limits::max() but shorter and not affected by the max macro. +template constexpr auto max_value() -> T { + return (std::numeric_limits::max)(); +} +template constexpr auto num_bits() -> int { + return std::numeric_limits::digits; +} +// std::numeric_limits::digits may return 0 for 128-bit ints. +template <> constexpr auto num_bits() -> int { return 128; } +template <> constexpr auto num_bits() -> int { return 128; } + +// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t +// and 128-bit pointers to uint128_fallback. +template sizeof(From))> +inline auto bit_cast(const From& from) -> To { + constexpr auto size = static_cast(sizeof(From) / sizeof(unsigned)); + struct data_t { + unsigned value[static_cast(size)]; + } data = bit_cast(from); + auto result = To(); + if (const_check(is_big_endian())) { + for (int i = 0; i < size; ++i) + result = (result << num_bits()) | data.value[i]; + } else { + for (int i = size - 1; i >= 0; --i) + result = (result << num_bits()) | data.value[i]; + } + return result; +} + +template +FMT_CONSTEXPR20 inline auto countl_zero_fallback(UInt n) -> int { + int lz = 0; + constexpr UInt msb_mask = static_cast(1) << (num_bits() - 1); + for (; (n & msb_mask) == 0; n <<= 1) lz++; + return lz; +} + +FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n); +#endif + return countl_zero_fallback(n); +} + +FMT_CONSTEXPR20 inline auto countl_zero(uint64_t n) -> int { +#ifdef FMT_BUILTIN_CLZLL + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZLL(n); +#endif + return countl_zero_fallback(n); +} + +FMT_INLINE void assume(bool condition) { + (void)condition; +#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION + __builtin_assume(condition); +#elif FMT_GCC_VERSION + if (!condition) __builtin_unreachable(); +#endif +} + +// An approximation of iterator_t for pre-C++20 systems. +template +using iterator_t = decltype(std::begin(std::declval())); +template using sentinel_t = decltype(std::end(std::declval())); + +// A workaround for std::string not having mutable data() until C++17. +template +inline auto get_data(std::basic_string& s) -> Char* { + return &s[0]; +} +template +inline auto get_data(Container& c) -> typename Container::value_type* { + return c.data(); +} + +// Attempts to reserve space for n extra characters in the output range. +// Returns a pointer to the reserved range or a reference to it. +template ::value)> +#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION +__attribute__((no_sanitize("undefined"))) +#endif +inline auto +reserve(std::back_insert_iterator it, size_t n) -> + typename Container::value_type* { + Container& c = get_container(it); + size_t size = c.size(); + c.resize(size + n); + return get_data(c) + size; +} + +template +inline auto reserve(buffer_appender it, size_t n) -> buffer_appender { + buffer& buf = get_container(it); + buf.try_reserve(buf.size() + n); + return it; +} + +template +constexpr auto reserve(Iterator& it, size_t) -> Iterator& { + return it; +} + +template +using reserve_iterator = + remove_reference_t(), 0))>; + +template +constexpr auto to_pointer(OutputIt, size_t) -> T* { + return nullptr; +} +template auto to_pointer(buffer_appender it, size_t n) -> T* { + buffer& buf = get_container(it); + auto size = buf.size(); + if (buf.capacity() < size + n) return nullptr; + buf.try_resize(size + n); + return buf.data() + size; +} + +template ::value)> +inline auto base_iterator(std::back_insert_iterator it, + typename Container::value_type*) + -> std::back_insert_iterator { + return it; +} + +template +constexpr auto base_iterator(Iterator, Iterator it) -> Iterator { + return it; +} + +// is spectacularly slow to compile in C++20 so use a simple fill_n +// instead (#1998). +template +FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value) + -> OutputIt { + for (Size i = 0; i < count; ++i) *out++ = value; + return out; +} +template +FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { + if (is_constant_evaluated()) { + return fill_n(out, count, value); + } + std::memset(out, value, to_unsigned(count)); + return out + count; +} + +#ifdef __cpp_char8_t +using char8_type = char8_t; +#else +enum char8_type : unsigned char {}; +#endif + +template +FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, + OutputIt out) -> OutputIt { + return copy_str(begin, end, out); +} + +// A public domain branchless UTF-8 decoder by Christopher Wellons: +// https://github.com/skeeto/branchless-utf8 +/* Decode the next character, c, from s, reporting errors in e. + * + * Since this is a branchless decoder, four bytes will be read from the + * buffer regardless of the actual length of the next character. This + * means the buffer _must_ have at least three bytes of zero padding + * following the end of the data stream. + * + * Errors are reported in e, which will be non-zero if the parsed + * character was somehow invalid: invalid byte sequence, non-canonical + * encoding, or a surrogate half. + * + * The function returns a pointer to the next character. When an error + * occurs, this pointer will be a guess that depends on the particular + * error, but it will always advance at least one byte. + */ +FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) + -> const char* { + constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; + constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; + constexpr const int shiftc[] = {0, 18, 12, 6, 0}; + constexpr const int shifte[] = {0, 6, 4, 2, 0}; + + int len = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4" + [static_cast(*s) >> 3]; + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + const char* next = s + len + !len; + + using uchar = unsigned char; + + // Assume a four-byte character and load four bytes. Unused bits are + // shifted out. + *c = uint32_t(uchar(s[0]) & masks[len]) << 18; + *c |= uint32_t(uchar(s[1]) & 0x3f) << 12; + *c |= uint32_t(uchar(s[2]) & 0x3f) << 6; + *c |= uint32_t(uchar(s[3]) & 0x3f) << 0; + *c >>= shiftc[len]; + + // Accumulate the various error conditions. + *e = (*c < mins[len]) << 6; // non-canonical encoding + *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? + *e |= (*c > 0x10FFFF) << 8; // out of range? + *e |= (uchar(s[1]) & 0xc0) >> 2; + *e |= (uchar(s[2]) & 0xc0) >> 4; + *e |= uchar(s[3]) >> 6; + *e ^= 0x2a; // top two bits of each tail byte correct? + *e >>= shifte[len]; + + return next; +} + +constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t(); + +// Invokes f(cp, sv) for every code point cp in s with sv being the string view +// corresponding to the code point. cp is invalid_code_point on error. +template +FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { + auto decode = [f](const char* buf_ptr, const char* ptr) { + auto cp = uint32_t(); + auto error = 0; + auto end = utf8_decode(buf_ptr, &cp, &error); + bool result = f(error ? invalid_code_point : cp, + string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr))); + return result ? (error ? buf_ptr + 1 : end) : nullptr; + }; + auto p = s.data(); + const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. + if (s.size() >= block_size) { + for (auto end = p + s.size() - block_size + 1; p < end;) { + p = decode(p, p); + if (!p) return; + } + } + if (auto num_chars_left = s.data() + s.size() - p) { + char buf[2 * block_size - 1] = {}; + copy_str(p, p + num_chars_left, buf); + const char* buf_ptr = buf; + do { + auto end = decode(buf_ptr, p); + if (!end) return; + p += end - buf_ptr; + buf_ptr = end; + } while (buf_ptr - buf < num_chars_left); + } +} + +template +inline auto compute_width(basic_string_view s) -> size_t { + return s.size(); +} + +// Computes approximate display width of a UTF-8 string. +FMT_CONSTEXPR inline auto compute_width(string_view s) -> size_t { + size_t num_code_points = 0; + // It is not a lambda for compatibility with C++14. + struct count_code_points { + size_t* count; + FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { + *count += detail::to_unsigned( + 1 + + (cp >= 0x1100 && + (cp <= 0x115f || // Hangul Jamo init. consonants + cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET + cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET + // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE: + (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || + (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables + (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs + (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms + (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms + (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms + (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms + (cp >= 0x20000 && cp <= 0x2fffd) || // CJK + (cp >= 0x30000 && cp <= 0x3fffd) || + // Miscellaneous Symbols and Pictographs + Emoticons: + (cp >= 0x1f300 && cp <= 0x1f64f) || + // Supplemental Symbols and Pictographs: + (cp >= 0x1f900 && cp <= 0x1f9ff)))); + return true; + } + }; + // We could avoid branches by using utf8_decode directly. + for_each_codepoint(s, count_code_points{&num_code_points}); + return num_code_points; +} + +inline auto compute_width(basic_string_view s) -> size_t { + return compute_width( + string_view(reinterpret_cast(s.data()), s.size())); +} + +template +inline auto code_point_index(basic_string_view s, size_t n) -> size_t { + size_t size = s.size(); + return n < size ? n : size; +} + +// Calculates the index of the nth code point in a UTF-8 string. +inline auto code_point_index(string_view s, size_t n) -> size_t { + size_t result = s.size(); + const char* begin = s.begin(); + for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) { + if (n != 0) { + --n; + return true; + } + result = to_unsigned(sv.begin() - begin); + return false; + }); + return result; +} + +inline auto code_point_index(basic_string_view s, size_t n) + -> size_t { + return code_point_index( + string_view(reinterpret_cast(s.data()), s.size()), n); +} + +template struct is_integral : std::is_integral {}; +template <> struct is_integral : std::true_type {}; +template <> struct is_integral : std::true_type {}; + +template +using is_signed = + std::integral_constant::is_signed || + std::is_same::value>; + +template +using is_integer = + bool_constant::value && !std::is_same::value && + !std::is_same::value && + !std::is_same::value>; + +#ifndef FMT_USE_FLOAT +# define FMT_USE_FLOAT 1 +#endif +#ifndef FMT_USE_DOUBLE +# define FMT_USE_DOUBLE 1 +#endif +#ifndef FMT_USE_LONG_DOUBLE +# define FMT_USE_LONG_DOUBLE 1 +#endif + +#ifndef FMT_USE_FLOAT128 +# ifdef __clang__ +// Clang emulates GCC, so it has to appear early. +# if FMT_HAS_INCLUDE() +# define FMT_USE_FLOAT128 1 +# endif +# elif defined(__GNUC__) +// GNU C++: +# if defined(_GLIBCXX_USE_FLOAT128) && !defined(__STRICT_ANSI__) +# define FMT_USE_FLOAT128 1 +# endif +# endif +# ifndef FMT_USE_FLOAT128 +# define FMT_USE_FLOAT128 0 +# endif +#endif + +#if FMT_USE_FLOAT128 +using float128 = __float128; +#else +using float128 = void; +#endif +template using is_float128 = std::is_same; + +template +using is_floating_point = + bool_constant::value || is_float128::value>; + +template ::value> +struct is_fast_float : bool_constant::is_iec559 && + sizeof(T) <= sizeof(double)> {}; +template struct is_fast_float : std::false_type {}; + +template +using is_double_double = bool_constant::digits == 106>; + +#ifndef FMT_USE_FULL_CACHE_DRAGONBOX +# define FMT_USE_FULL_CACHE_DRAGONBOX 0 +#endif + +template +template +void buffer::append(const U* begin, const U* end) { + while (begin != end) { + auto count = to_unsigned(end - begin); + try_reserve(size_ + count); + auto free_cap = capacity_ - size_; + if (free_cap < count) count = free_cap; + std::uninitialized_copy_n(begin, count, ptr_ + size_); + size_ += count; + begin += count; + } +} + +template +struct is_locale : std::false_type {}; +template +struct is_locale> : std::true_type {}; +} // namespace detail + +FMT_BEGIN_EXPORT + +// The number of characters to store in the basic_memory_buffer object itself +// to avoid dynamic memory allocation. +enum { inline_buffer_size = 500 }; + +/** + \rst + A dynamically growing memory buffer for trivially copyable/constructible types + with the first ``SIZE`` elements stored in the object itself. + + You can use the ``memory_buffer`` type alias for ``char`` instead. + + **Example**:: + + auto out = fmt::memory_buffer(); + fmt::format_to(std::back_inserter(out), "The answer is {}.", 42); + + This will append the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42. + + The output can be converted to an ``std::string`` with ``to_string(out)``. + \endrst + */ +template > +class basic_memory_buffer final : public detail::buffer { + private: + T store_[SIZE]; + + // Don't inherit from Allocator to avoid generating type_info for it. + FMT_NO_UNIQUE_ADDRESS Allocator alloc_; + + // Deallocate memory allocated by the buffer. + FMT_CONSTEXPR20 void deallocate() { + T* data = this->data(); + if (data != store_) alloc_.deallocate(data, this->capacity()); + } + + protected: + FMT_CONSTEXPR20 void grow(size_t size) override { + detail::abort_fuzzing_if(size > 5000); + const size_t max_size = std::allocator_traits::max_size(alloc_); + size_t old_capacity = this->capacity(); + size_t new_capacity = old_capacity + old_capacity / 2; + if (size > new_capacity) + new_capacity = size; + else if (new_capacity > max_size) + new_capacity = size > max_size ? size : max_size; + T* old_data = this->data(); + T* new_data = + std::allocator_traits::allocate(alloc_, new_capacity); + // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481). + detail::assume(this->size() <= new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::uninitialized_copy_n(old_data, this->size(), new_data); + this->set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != store_) alloc_.deallocate(old_data, old_capacity); + } + + public: + using value_type = T; + using const_reference = const T&; + + FMT_CONSTEXPR20 explicit basic_memory_buffer( + const Allocator& alloc = Allocator()) + : alloc_(alloc) { + this->set(store_, SIZE); + if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T()); + } + FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } + + private: + // Move data from other to this buffer. + FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { + alloc_ = std::move(other.alloc_); + T* data = other.data(); + size_t size = other.size(), capacity = other.capacity(); + if (data == other.store_) { + this->set(store_, capacity); + detail::copy_str(other.store_, other.store_ + size, store_); + } else { + this->set(data, capacity); + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.set(other.store_, 0); + other.clear(); + } + this->resize(size); + } + + public: + /** + \rst + Constructs a :class:`fmt::basic_memory_buffer` object moving the content + of the other object to it. + \endrst + */ + FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept { + move(other); + } + + /** + \rst + Moves the content of the other ``basic_memory_buffer`` object to this one. + \endrst + */ + auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& { + FMT_ASSERT(this != &other, ""); + deallocate(); + move(other); + return *this; + } + + // Returns a copy of the allocator associated with this buffer. + auto get_allocator() const -> Allocator { return alloc_; } + + /** + Resizes the buffer to contain *count* elements. If T is a POD type new + elements may not be initialized. + */ + FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } + + /** Increases the buffer capacity to *new_capacity*. */ + void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } + + using detail::buffer::append; + template + void append(const ContiguousRange& range) { + append(range.data(), range.data() + range.size()); + } +}; + +using memory_buffer = basic_memory_buffer; + +template +struct is_contiguous> : std::true_type { +}; + +FMT_END_EXPORT +namespace detail { +FMT_API auto write_console(int fd, string_view text) -> bool; +FMT_API auto write_console(std::FILE* f, string_view text) -> bool; +FMT_API void print(std::FILE*, string_view); +} // namespace detail + +FMT_BEGIN_EXPORT + +// Suppress a misleading warning in older versions of clang. +#if FMT_CLANG_VERSION +# pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +/** An error reported from a formatting function. */ +class FMT_SO_VISIBILITY("default") format_error : public std::runtime_error { + public: + using std::runtime_error::runtime_error; +}; + +namespace detail_exported { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template struct fixed_string { + constexpr fixed_string(const Char (&str)[N]) { + detail::copy_str(static_cast(str), + str + N, data); + } + Char data[N] = {}; +}; +#endif + +// Converts a compile-time string to basic_string_view. +template +constexpr auto compile_string_to_view(const Char (&s)[N]) + -> basic_string_view { + // Remove trailing NUL character if needed. Won't be present if this is used + // with a raw character array (i.e. not defined as a string). + return {s, N - (std::char_traits::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; +} +template +constexpr auto compile_string_to_view(detail::std_string_view s) + -> basic_string_view { + return {s.data(), s.size()}; +} +} // namespace detail_exported + +class loc_value { + private: + basic_format_arg value_; + + public: + template ::value)> + loc_value(T value) : value_(detail::make_arg(value)) {} + + template ::value)> + loc_value(T) {} + + template auto visit(Visitor&& vis) -> decltype(vis(0)) { + return visit_format_arg(vis, value_); + } +}; + +// A locale facet that formats values in UTF-8. +// It is parameterized on the locale to avoid the heavy include. +template class format_facet : public Locale::facet { + private: + std::string separator_; + std::string grouping_; + std::string decimal_point_; + + protected: + virtual auto do_put(appender out, loc_value val, + const format_specs<>& specs) const -> bool; + + public: + static FMT_API typename Locale::id id; + + explicit format_facet(Locale& loc); + explicit format_facet(string_view sep = "", + std::initializer_list g = {3}, + std::string decimal_point = ".") + : separator_(sep.data(), sep.size()), + grouping_(g.begin(), g.end()), + decimal_point_(decimal_point) {} + + auto put(appender out, loc_value val, const format_specs<>& specs) const + -> bool { + return do_put(out, val, specs); + } +}; + +namespace detail { + +// Returns true if value is negative, false otherwise. +// Same as `value < 0` but doesn't produce warnings if T is an unsigned type. +template ::value)> +constexpr auto is_negative(T value) -> bool { + return value < 0; +} +template ::value)> +constexpr auto is_negative(T) -> bool { + return false; +} + +template +FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool { + if (std::is_same()) return FMT_USE_FLOAT; + if (std::is_same()) return FMT_USE_DOUBLE; + if (std::is_same()) return FMT_USE_LONG_DOUBLE; + return true; +} + +// Smallest of uint32_t, uint64_t, uint128_t that is large enough to +// represent all values of an integral type T. +template +using uint32_or_64_or_128_t = + conditional_t() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, + uint32_t, + conditional_t() <= 64, uint64_t, uint128_t>>; +template +using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \ + (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \ + (factor) * 100000000, (factor) * 1000000000 + +// Converts value in the range [0, 100) to a string. +constexpr auto digits2(size_t value) -> const char* { + // GCC generates slightly better code when value is pointer-size. + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; +} + +// Sign is a template parameter to workaround a bug in gcc 4.8. +template constexpr auto sign(Sign s) -> Char { +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 + static_assert(std::is_same::value, ""); +#endif + return static_cast("\0-+ "[s]); +} + +template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { + int count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#if FMT_USE_INT128 +FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int { + return count_digits_fallback(n); +} +#endif + +#ifdef FMT_BUILTIN_CLZLL +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +inline auto do_count_digits(uint64_t n) -> int { + // This has comparable performance to the version by Kendall Willets + // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) + // but uses smaller tables. + // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). + static constexpr uint8_t bsr2log10[] = { + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, + 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; + auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; + static constexpr const uint64_t zero_or_powers_of_10[] = { + 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; + return t - (n < zero_or_powers_of_10[t]); +} +#endif + +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { +#ifdef FMT_BUILTIN_CLZLL + if (!is_constant_evaluated()) { + return do_count_digits(n); + } +#endif + return count_digits_fallback(n); +} + +// Counts the number of digits in n. BITS = log2(radix). +template +FMT_CONSTEXPR auto count_digits(UInt n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated() && num_bits() == 32) + return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; +#endif + // Lambda avoids unreachable code warnings from NVHPC. + return [](UInt m) { + int num_digits = 0; + do { + ++num_digits; + } while ((m >>= BITS) != 0); + return num_digits; + }(n); +} + +#ifdef FMT_BUILTIN_CLZ +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +FMT_INLINE auto do_count_digits(uint32_t n) -> int { +// An optimization by Kendall Willets from https://bit.ly/3uOIQrB. +// This increments the upper 32 bits (log10(T) - 1) when >= T is added. +# define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) + static constexpr uint64_t table[] = { + FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 + FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 + FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 + FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 + FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k + FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k + FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k + FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M + FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M + FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M + FMT_INC(1000000000), FMT_INC(1000000000) // 4B + }; + auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; + return static_cast((n + inc) >> 32); +} +#endif + +// Optional version of count_digits for better performance on 32-bit platforms. +FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) { + return do_count_digits(n); + } +#endif + return count_digits_fallback(n); +} + +template constexpr auto digits10() noexcept -> int { + return std::numeric_limits::digits10; +} +template <> constexpr auto digits10() noexcept -> int { return 38; } +template <> constexpr auto digits10() noexcept -> int { return 38; } + +template struct thousands_sep_result { + std::string grouping; + Char thousands_sep; +}; + +template +FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result; +template +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { + auto result = thousands_sep_impl(loc); + return {result.grouping, Char(result.thousands_sep)}; +} +template <> +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { + return thousands_sep_impl(loc); +} + +template +FMT_API auto decimal_point_impl(locale_ref loc) -> Char; +template inline auto decimal_point(locale_ref loc) -> Char { + return Char(decimal_point_impl(loc)); +} +template <> inline auto decimal_point(locale_ref loc) -> wchar_t { + return decimal_point_impl(loc); +} + +// Compares two characters for equality. +template auto equal2(const Char* lhs, const char* rhs) -> bool { + return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]); +} +inline auto equal2(const char* lhs, const char* rhs) -> bool { + return memcmp(lhs, rhs, 2) == 0; +} + +// Copies two characters from src to dst. +template +FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { + if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { + memcpy(dst, src, 2); + return; + } + *dst++ = static_cast(*src++); + *dst = static_cast(*src); +} + +template struct format_decimal_result { + Iterator begin; + Iterator end; +}; + +// Formats a decimal unsigned integer value writing into out pointing to a +// buffer of specified size. The caller must ensure that the buffer is large +// enough. +template +FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) + -> format_decimal_result { + FMT_ASSERT(size >= count_digits(value), "invalid digit count"); + out += size; + Char* end = out; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + out -= 2; + copy2(out, digits2(static_cast(value % 100))); + value /= 100; + } + if (value < 10) { + *--out = static_cast('0' + value); + return {out, end}; + } + out -= 2; + copy2(out, digits2(static_cast(value))); + return {out, end}; +} + +template >::value)> +FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size) + -> format_decimal_result { + // Buffer is large enough to hold all digits (digits10 + 1). + Char buffer[digits10() + 1] = {}; + auto end = format_decimal(buffer, value, size).end; + return {out, detail::copy_str_noinline(buffer, end, out)}; +} + +template +FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, + bool upper = false) -> Char* { + buffer += num_digits; + Char* end = buffer; + do { + const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = static_cast(value & ((1 << BASE_BITS) - 1)); + *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) + : digits[digit]); + } while ((value >>= BASE_BITS) != 0); + return end; +} + +template +FMT_CONSTEXPR inline auto format_uint(It out, UInt value, int num_digits, + bool upper = false) -> It { + if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { + format_uint(ptr, value, num_digits, upper); + return out; + } + // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). + char buffer[num_bits() / BASE_BITS + 1] = {}; + format_uint(buffer, value, num_digits, upper); + return detail::copy_str_noinline(buffer, buffer + num_digits, out); +} + +// A converter from UTF-8 to UTF-16. +class utf8_to_utf16 { + private: + basic_memory_buffer buffer_; + + public: + FMT_API explicit utf8_to_utf16(string_view s); + operator basic_string_view() const { return {&buffer_[0], size()}; } + auto size() const -> size_t { return buffer_.size() - 1; } + auto c_str() const -> const wchar_t* { return &buffer_[0]; } + auto str() const -> std::wstring { return {&buffer_[0], size()}; } +}; + +enum class to_utf8_error_policy { abort, replace }; + +// A converter from UTF-16/UTF-32 (host endian) to UTF-8. +template class to_utf8 { + private: + Buffer buffer_; + + public: + to_utf8() {} + explicit to_utf8(basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) { + static_assert(sizeof(WChar) == 2 || sizeof(WChar) == 4, + "Expect utf16 or utf32"); + if (!convert(s, policy)) + FMT_THROW(std::runtime_error(sizeof(WChar) == 2 ? "invalid utf16" + : "invalid utf32")); + } + operator string_view() const { return string_view(&buffer_[0], size()); } + auto size() const -> size_t { return buffer_.size() - 1; } + auto c_str() const -> const char* { return &buffer_[0]; } + auto str() const -> std::string { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a bool instead of throwing exception on + // conversion error. This method may still throw in case of memory allocation + // error. + auto convert(basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) + -> bool { + if (!convert(buffer_, s, policy)) return false; + buffer_.push_back(0); + return true; + } + static auto convert(Buffer& buf, basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) + -> bool { + for (auto p = s.begin(); p != s.end(); ++p) { + uint32_t c = static_cast(*p); + if (sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) { + // Handle a surrogate pair. + ++p; + if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { + if (policy == to_utf8_error_policy::abort) return false; + buf.append(string_view("\xEF\xBF\xBD")); + --p; + } else { + c = (c << 10) + static_cast(*p) - 0x35fdc00; + } + } else if (c < 0x80) { + buf.push_back(static_cast(c)); + } else if (c < 0x800) { + buf.push_back(static_cast(0xc0 | (c >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { + buf.push_back(static_cast(0xe0 | (c >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if (c >= 0x10000 && c <= 0x10ffff) { + buf.push_back(static_cast(0xf0 | (c >> 18))); + buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else { + return false; + } + } + return true; + } +}; + +// Computes 128-bit result of multiplication of two 64-bit unsigned integers. +inline auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fallback { +#if FMT_USE_INT128 + auto p = static_cast(x) * static_cast(y); + return {static_cast(p >> 64), static_cast(p)}; +#elif defined(_MSC_VER) && defined(_M_X64) + auto hi = uint64_t(); + auto lo = _umul128(x, y, &hi); + return {hi, lo}; +#else + const uint64_t mask = static_cast(max_value()); + + uint64_t a = x >> 32; + uint64_t b = x & mask; + uint64_t c = y >> 32; + uint64_t d = y & mask; + + uint64_t ac = a * c; + uint64_t bc = b * c; + uint64_t ad = a * d; + uint64_t bd = b * d; + + uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask); + + return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32), + (intermediate << 32) + (bd & mask)}; +#endif +} + +namespace dragonbox { +// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from +// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1. +inline auto floor_log10_pow2(int e) noexcept -> int { + FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent"); + static_assert((-1 >> 1) == -1, "right shift is not arithmetic"); + return (e * 315653) >> 20; +} + +inline auto floor_log2_pow10(int e) noexcept -> int { + FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); + return (e * 1741647) >> 19; +} + +// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. +inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t { +#if FMT_USE_INT128 + auto p = static_cast(x) * static_cast(y); + return static_cast(p >> 64); +#elif defined(_MSC_VER) && defined(_M_X64) + return __umulh(x, y); +#else + return umul128(x, y).high(); +#endif +} + +// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline auto umul192_upper128(uint64_t x, uint128_fallback y) noexcept + -> uint128_fallback { + uint128_fallback r = umul128(x, y.high()); + r += umul128_upper64(x, y.low()); + return r; +} + +FMT_API auto get_cached_power(int k) noexcept -> uint128_fallback; + +// Type-specific information that Dragonbox uses. +template struct float_info; + +template <> struct float_info { + using carrier_uint = uint32_t; + static const int exponent_bits = 8; + static const int kappa = 1; + static const int big_divisor = 100; + static const int small_divisor = 10; + static const int min_k = -31; + static const int max_k = 46; + static const int shorter_interval_tie_lower_threshold = -35; + static const int shorter_interval_tie_upper_threshold = -35; +}; + +template <> struct float_info { + using carrier_uint = uint64_t; + static const int exponent_bits = 11; + static const int kappa = 2; + static const int big_divisor = 1000; + static const int small_divisor = 100; + static const int min_k = -292; + static const int max_k = 341; + static const int shorter_interval_tie_lower_threshold = -77; + static const int shorter_interval_tie_upper_threshold = -77; +}; + +// An 80- or 128-bit floating point number. +template +struct float_info::digits == 64 || + std::numeric_limits::digits == 113 || + is_float128::value>> { + using carrier_uint = detail::uint128_t; + static const int exponent_bits = 15; +}; + +// A double-double floating point number. +template +struct float_info::value>> { + using carrier_uint = detail::uint128_t; +}; + +template struct decimal_fp { + using significand_type = typename float_info::carrier_uint; + significand_type significand; + int exponent; +}; + +template FMT_API auto to_decimal(T x) noexcept -> decimal_fp; +} // namespace dragonbox + +// Returns true iff Float has the implicit bit which is not stored. +template constexpr auto has_implicit_bit() -> bool { + // An 80-bit FP number has a 64-bit significand an no implicit bit. + return std::numeric_limits::digits != 64; +} + +// Returns the number of significand bits stored in Float. The implicit bit is +// not counted since it is not stored. +template constexpr auto num_significand_bits() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 112 + : (std::numeric_limits::digits - + (has_implicit_bit() ? 1 : 0)); +} + +template +constexpr auto exponent_mask() -> + typename dragonbox::float_info::carrier_uint { + using float_uint = typename dragonbox::float_info::carrier_uint; + return ((float_uint(1) << dragonbox::float_info::exponent_bits) - 1) + << num_significand_bits(); +} +template constexpr auto exponent_bias() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 16383 + : std::numeric_limits::max_exponent - 1; +} + +// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. +template +FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { + FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); + if (exp < 0) { + *it++ = static_cast('-'); + exp = -exp; + } else { + *it++ = static_cast('+'); + } + if (exp >= 100) { + const char* top = digits2(to_unsigned(exp / 100)); + if (exp >= 1000) *it++ = static_cast(top[0]); + *it++ = static_cast(top[1]); + exp %= 100; + } + const char* d = digits2(to_unsigned(exp)); + *it++ = static_cast(d[0]); + *it++ = static_cast(d[1]); + return it; +} + +// A floating-point number f * pow(2, e) where F is an unsigned type. +template struct basic_fp { + F f; + int e; + + static constexpr const int num_significand_bits = + static_cast(sizeof(F) * num_bits()); + + constexpr basic_fp() : f(0), e(0) {} + constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 floating-point number. + template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } + + // Assigns n to this and return true iff predecessor is closer than successor. + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename dragonbox::float_info::carrier_uint; + const auto num_float_significand_bits = + detail::num_significand_bits(); + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + const auto significand_mask = implicit_bit - 1; + auto u = bit_cast(n); + f = static_cast(u & significand_mask); + auto biased_e = static_cast((u & exponent_mask()) >> + num_float_significand_bits); + // The predecessor is closer if n is a normalized power of 2 (f == 0) + // other than the smallest normalized number (biased_e > 1). + auto is_predecessor_closer = f == 0 && biased_e > 1; + if (biased_e == 0) + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + else if (has_implicit_bit()) + f += static_cast(implicit_bit); + e = biased_e - exponent_bias() - num_float_significand_bits; + if (!has_implicit_bit()) ++e; + return is_predecessor_closer; + } + + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::is_iec559, "unsupported FP"); + return assign(static_cast(n)); + } +}; + +using fp = basic_fp; + +// Normalizes the value converted from double and multiplied by (1 << SHIFT). +template +FMT_CONSTEXPR auto normalize(basic_fp value) -> basic_fp { + // Handle subnormals. + const auto implicit_bit = F(1) << num_significand_bits(); + const auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((value.f & shifted_implicit_bit) == 0) { + value.f <<= 1; + --value.e; + } + // Subtract 1 to account for hidden bit. + const auto offset = basic_fp::num_significand_bits - + num_significand_bits() - SHIFT - 1; + value.f <<= offset; + value.e -= offset; + return value; +} + +// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. +FMT_CONSTEXPR inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t { +#if FMT_USE_INT128 + auto product = static_cast<__uint128_t>(lhs) * rhs; + auto f = static_cast(product >> 64); + return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; +#else + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = lhs >> 32, b = lhs & mask; + uint64_t c = rhs >> 32, d = rhs & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); +#endif +} + +FMT_CONSTEXPR inline auto operator*(fp x, fp y) -> fp { + return {multiply(x.f, y.f), x.e + y.e + 64}; +} + +template () == num_bits()> +using convert_float_result = + conditional_t::value || doublish, double, T>; + +template +constexpr auto convert_float(T value) -> convert_float_result { + return static_cast>(value); +} + +template +FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, + const fill_t& fill) -> OutputIt { + auto fill_size = fill.size(); + if (fill_size == 1) return detail::fill_n(it, n, fill[0]); + auto data = fill.data(); + for (size_t i = 0; i < n; ++i) + it = copy_str(data, data + fill_size, it); + return it; +} + +// Writes the output of f, padded according to format specifications in specs. +// size: output size in code units. +// width: output display width in (terminal) column positions. +template +FMT_CONSTEXPR auto write_padded(OutputIt out, const format_specs& specs, + size_t size, size_t width, F&& f) -> OutputIt { + static_assert(align == align::left || align == align::right, ""); + unsigned spec_width = to_unsigned(specs.width); + size_t padding = spec_width > width ? spec_width - width : 0; + // Shifts are encoded as string literals because static constexpr is not + // supported in constexpr functions. + auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; + size_t left_padding = padding >> shifts[specs.align]; + size_t right_padding = padding - left_padding; + auto it = reserve(out, size + padding * specs.fill.size()); + if (left_padding != 0) it = fill(it, left_padding, specs.fill); + it = f(it); + if (right_padding != 0) it = fill(it, right_padding, specs.fill); + return base_iterator(out, it); +} + +template +constexpr auto write_padded(OutputIt out, const format_specs& specs, + size_t size, F&& f) -> OutputIt { + return write_padded(out, specs, size, size, f); +} + +template +FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, + const format_specs& specs) -> OutputIt { + return write_padded( + out, specs, bytes.size(), [bytes](reserve_iterator it) { + const char* data = bytes.data(); + return copy_str(data, data + bytes.size(), it); + }); +} + +template +auto write_ptr(OutputIt out, UIntPtr value, const format_specs* specs) + -> OutputIt { + int num_digits = count_digits<4>(value); + auto size = to_unsigned(num_digits) + size_t(2); + auto write = [=](reserve_iterator it) { + *it++ = static_cast('0'); + *it++ = static_cast('x'); + return format_uint<4, Char>(it, value, num_digits); + }; + return specs ? write_padded(out, *specs, size, write) + : base_iterator(out, write(reserve(out, size))); +} + +// Returns true iff the code point cp is printable. +FMT_API auto is_printable(uint32_t cp) -> bool; + +inline auto needs_escape(uint32_t cp) -> bool { + return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || + !is_printable(cp); +} + +template struct find_escape_result { + const Char* begin; + const Char* end; + uint32_t cp; +}; + +template +using make_unsigned_char = + typename conditional_t::value, + std::make_unsigned, + type_identity>::type; + +template +auto find_escape(const Char* begin, const Char* end) + -> find_escape_result { + for (; begin != end; ++begin) { + uint32_t cp = static_cast>(*begin); + if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue; + if (needs_escape(cp)) return {begin, begin + 1, cp}; + } + return {begin, nullptr, 0}; +} + +inline auto find_escape(const char* begin, const char* end) + -> find_escape_result { + if (!is_utf8()) return find_escape(begin, end); + auto result = find_escape_result{end, nullptr, 0}; + for_each_codepoint(string_view(begin, to_unsigned(end - begin)), + [&](uint32_t cp, string_view sv) { + if (needs_escape(cp)) { + result = {sv.begin(), sv.end(), cp}; + return false; + } + return true; + }); + return result; +} + +#define FMT_STRING_IMPL(s, base, explicit) \ + [] { \ + /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ + /* Use a macro-like name to avoid shadowing warnings. */ \ + struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \ + using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t; \ + FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ + operator fmt::basic_string_view() const { \ + return fmt::detail_exported::compile_string_to_view(s); \ + } \ + }; \ + return FMT_COMPILE_STRING(); \ + }() + +/** + \rst + Constructs a compile-time format string from a string literal *s*. + + **Example**:: + + // A compile-time error because 'd' is an invalid specifier for strings. + std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); + \endrst + */ +#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, ) + +template +auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt { + *out++ = static_cast('\\'); + *out++ = static_cast(prefix); + Char buf[width]; + fill_n(buf, width, static_cast('0')); + format_uint<4>(buf, cp, width); + return copy_str(buf, buf + width, out); +} + +template +auto write_escaped_cp(OutputIt out, const find_escape_result& escape) + -> OutputIt { + auto c = static_cast(escape.cp); + switch (escape.cp) { + case '\n': + *out++ = static_cast('\\'); + c = static_cast('n'); + break; + case '\r': + *out++ = static_cast('\\'); + c = static_cast('r'); + break; + case '\t': + *out++ = static_cast('\\'); + c = static_cast('t'); + break; + case '"': + FMT_FALLTHROUGH; + case '\'': + FMT_FALLTHROUGH; + case '\\': + *out++ = static_cast('\\'); + break; + default: + if (escape.cp < 0x100) { + return write_codepoint<2, Char>(out, 'x', escape.cp); + } + if (escape.cp < 0x10000) { + return write_codepoint<4, Char>(out, 'u', escape.cp); + } + if (escape.cp < 0x110000) { + return write_codepoint<8, Char>(out, 'U', escape.cp); + } + for (Char escape_char : basic_string_view( + escape.begin, to_unsigned(escape.end - escape.begin))) { + out = write_codepoint<2, Char>(out, 'x', + static_cast(escape_char) & 0xFF); + } + return out; + } + *out++ = c; + return out; +} + +template +auto write_escaped_string(OutputIt out, basic_string_view str) + -> OutputIt { + *out++ = static_cast('"'); + auto begin = str.begin(), end = str.end(); + do { + auto escape = find_escape(begin, end); + out = copy_str(begin, escape.begin, out); + begin = escape.end; + if (!begin) break; + out = write_escaped_cp(out, escape); + } while (begin != end); + *out++ = static_cast('"'); + return out; +} + +template +auto write_escaped_char(OutputIt out, Char v) -> OutputIt { + Char v_array[1] = {v}; + *out++ = static_cast('\''); + if ((needs_escape(static_cast(v)) && v != static_cast('"')) || + v == static_cast('\'')) { + out = write_escaped_cp(out, + find_escape_result{v_array, v_array + 1, + static_cast(v)}); + } else { + *out++ = v; + } + *out++ = static_cast('\''); + return out; +} + +template +FMT_CONSTEXPR auto write_char(OutputIt out, Char value, + const format_specs& specs) -> OutputIt { + bool is_debug = specs.type == presentation_type::debug; + return write_padded(out, specs, 1, [=](reserve_iterator it) { + if (is_debug) return write_escaped_char(it, value); + *it++ = value; + return it; + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, Char value, + const format_specs& specs, locale_ref loc = {}) + -> OutputIt { + // char is formatted as unsigned char for consistency across platforms. + using unsigned_type = + conditional_t::value, unsigned char, unsigned>; + return check_char_specs(specs) + ? write_char(out, value, specs) + : write(out, static_cast(value), specs, loc); +} + +// Data for write_int that doesn't depend on output iterator type. It is used to +// avoid template code bloat. +template struct write_int_data { + size_t size; + size_t padding; + + FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, + const format_specs& specs) + : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) { + if (specs.align == align::numeric) { + auto width = to_unsigned(specs.width); + if (width > size) { + padding = width - size; + size = width; + } + } else if (specs.precision > num_digits) { + size = (prefix >> 24) + to_unsigned(specs.precision); + padding = to_unsigned(specs.precision - num_digits); + } + } +}; + +// Writes an integer in the format +// +// where are written by write_digits(it). +// prefix contains chars in three lower bytes and the size in the fourth byte. +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, + unsigned prefix, + const format_specs& specs, + W write_digits) -> OutputIt { + // Slightly faster check for specs.width == 0 && specs.precision == -1. + if ((specs.width | (specs.precision + 1)) == 0) { + auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); + if (prefix != 0) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + } + return base_iterator(out, write_digits(it)); + } + auto data = write_int_data(num_digits, prefix, specs); + return write_padded( + out, specs, data.size, [=](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + it = detail::fill_n(it, data.padding, static_cast('0')); + return write_digits(it); + }); +} + +template class digit_grouping { + private: + std::string grouping_; + std::basic_string thousands_sep_; + + struct next_state { + std::string::const_iterator group; + int pos; + }; + auto initial_state() const -> next_state { return {grouping_.begin(), 0}; } + + // Returns the next digit group separator position. + auto next(next_state& state) const -> int { + if (thousands_sep_.empty()) return max_value(); + if (state.group == grouping_.end()) return state.pos += grouping_.back(); + if (*state.group <= 0 || *state.group == max_value()) + return max_value(); + state.pos += *state.group++; + return state.pos; + } + + public: + explicit digit_grouping(locale_ref loc, bool localized = true) { + if (!localized) return; + auto sep = thousands_sep(loc); + grouping_ = sep.grouping; + if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep); + } + digit_grouping(std::string grouping, std::basic_string sep) + : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {} + + auto has_separator() const -> bool { return !thousands_sep_.empty(); } + + auto count_separators(int num_digits) const -> int { + int count = 0; + auto state = initial_state(); + while (num_digits > next(state)) ++count; + return count; + } + + // Applies grouping to digits and write the output to out. + template + auto apply(Out out, basic_string_view digits) const -> Out { + auto num_digits = static_cast(digits.size()); + auto separators = basic_memory_buffer(); + separators.push_back(0); + auto state = initial_state(); + while (int i = next(state)) { + if (i >= num_digits) break; + separators.push_back(i); + } + for (int i = 0, sep_index = static_cast(separators.size() - 1); + i < num_digits; ++i) { + if (num_digits - i == separators[sep_index]) { + out = + copy_str(thousands_sep_.data(), + thousands_sep_.data() + thousands_sep_.size(), out); + --sep_index; + } + *out++ = static_cast(digits[to_unsigned(i)]); + } + return out; + } +}; + +FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { + prefix |= prefix != 0 ? value << 8 : value; + prefix += (1u + (value > 0xff ? 1 : 0)) << 24; +} + +// Writes a decimal integer with digit grouping. +template +auto write_int(OutputIt out, UInt value, unsigned prefix, + const format_specs& specs, + const digit_grouping& grouping) -> OutputIt { + static_assert(std::is_same, UInt>::value, ""); + int num_digits = 0; + auto buffer = memory_buffer(); + switch (specs.type) { + case presentation_type::none: + case presentation_type::dec: { + num_digits = count_digits(value); + format_decimal(appender(buffer), value, num_digits); + break; + } + case presentation_type::hex_lower: + case presentation_type::hex_upper: { + bool upper = specs.type == presentation_type::hex_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); + num_digits = count_digits<4>(value); + format_uint<4, char>(appender(buffer), value, num_digits, upper); + break; + } + case presentation_type::bin_lower: + case presentation_type::bin_upper: { + bool upper = specs.type == presentation_type::bin_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); + num_digits = count_digits<1>(value); + format_uint<1, char>(appender(buffer), value, num_digits); + break; + } + case presentation_type::oct: { + num_digits = count_digits<3>(value); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && value != 0) + prefix_append(prefix, '0'); + format_uint<3, char>(appender(buffer), value, num_digits); + break; + } + case presentation_type::chr: + return write_char(out, static_cast(value), specs); + default: + throw_format_error("invalid format specifier"); + } + + unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) + + to_unsigned(grouping.count_separators(num_digits)); + return write_padded( + out, specs, size, size, [&](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + return grouping.apply(it, string_view(buffer.data(), buffer.size())); + }); +} + +// Writes a localized value. +FMT_API auto write_loc(appender out, loc_value value, + const format_specs<>& specs, locale_ref loc) -> bool; +template +inline auto write_loc(OutputIt, loc_value, const format_specs&, + locale_ref) -> bool { + return false; +} + +template struct write_int_arg { + UInt abs_value; + unsigned prefix; +}; + +template +FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) + -> write_int_arg> { + auto prefix = 0u; + auto abs_value = static_cast>(value); + if (is_negative(value)) { + prefix = 0x01000000 | '-'; + abs_value = 0 - abs_value; + } else { + constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', + 0x1000000u | ' '}; + prefix = prefixes[sign]; + } + return {abs_value, prefix}; +} + +template struct loc_writer { + buffer_appender out; + const format_specs& specs; + std::basic_string sep; + std::string grouping; + std::basic_string decimal_point; + + template ::value)> + auto operator()(T value) -> bool { + auto arg = make_write_int_arg(value, specs.sign); + write_int(out, static_cast>(arg.abs_value), arg.prefix, + specs, digit_grouping(grouping, sep)); + return true; + } + + template ::value)> + auto operator()(T) -> bool { + return false; + } +}; + +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, + const format_specs& specs, + locale_ref) -> OutputIt { + static_assert(std::is_same>::value, ""); + auto abs_value = arg.abs_value; + auto prefix = arg.prefix; + switch (specs.type) { + case presentation_type::none: + case presentation_type::dec: { + auto num_digits = count_digits(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_decimal(it, abs_value, num_digits).end; + }); + } + case presentation_type::hex_lower: + case presentation_type::hex_upper: { + bool upper = specs.type == presentation_type::hex_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); + int num_digits = count_digits<4>(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_uint<4, Char>(it, abs_value, num_digits, upper); + }); + } + case presentation_type::bin_lower: + case presentation_type::bin_upper: { + bool upper = specs.type == presentation_type::bin_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); + int num_digits = count_digits<1>(abs_value); + return write_int(out, num_digits, prefix, specs, + [=](reserve_iterator it) { + return format_uint<1, Char>(it, abs_value, num_digits); + }); + } + case presentation_type::oct: { + int num_digits = count_digits<3>(abs_value); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && abs_value != 0) + prefix_append(prefix, '0'); + return write_int(out, num_digits, prefix, specs, + [=](reserve_iterator it) { + return format_uint<3, Char>(it, abs_value, num_digits); + }); + } + case presentation_type::chr: + return write_char(out, static_cast(abs_value), specs); + default: + throw_format_error("invalid format specifier"); + } + return out; +} +template +FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline( + OutputIt out, write_int_arg arg, const format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int(out, arg, specs, loc); +} +template ::value && + !std::is_same::value && + std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const format_specs& specs, + locale_ref loc) -> OutputIt { + if (specs.localized && write_loc(out, value, specs, loc)) return out; + return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs, + loc); +} +// An inlined version of write used in format string compilation. +template ::value && + !std::is_same::value && + !std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const format_specs& specs, + locale_ref loc) -> OutputIt { + if (specs.localized && write_loc(out, value, specs, loc)) return out; + return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); +} + +// An output iterator that counts the number of objects written to it and +// discards them. +class counting_iterator { + private: + size_t count_; + + public: + using iterator_category = std::output_iterator_tag; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = void; + FMT_UNCHECKED_ITERATOR(counting_iterator); + + struct value_type { + template FMT_CONSTEXPR void operator=(const T&) {} + }; + + FMT_CONSTEXPR counting_iterator() : count_(0) {} + + FMT_CONSTEXPR auto count() const -> size_t { return count_; } + + FMT_CONSTEXPR auto operator++() -> counting_iterator& { + ++count_; + return *this; + } + FMT_CONSTEXPR auto operator++(int) -> counting_iterator { + auto it = *this; + ++*this; + return it; + } + + FMT_CONSTEXPR friend auto operator+(counting_iterator it, difference_type n) + -> counting_iterator { + it.count_ += static_cast(n); + return it; + } + + FMT_CONSTEXPR auto operator*() const -> value_type { return {}; } +}; + +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, + const format_specs& specs) -> OutputIt { + auto data = s.data(); + auto size = s.size(); + if (specs.precision >= 0 && to_unsigned(specs.precision) < size) + size = code_point_index(s, to_unsigned(specs.precision)); + bool is_debug = specs.type == presentation_type::debug; + size_t width = 0; + if (specs.width != 0) { + if (is_debug) + width = write_escaped_string(counting_iterator{}, s).count(); + else + width = compute_width(basic_string_view(data, size)); + } + return write_padded(out, specs, size, width, + [=](reserve_iterator it) { + if (is_debug) return write_escaped_string(it, s); + return copy_str(data, data + size, it); + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, + basic_string_view> s, + const format_specs& specs, locale_ref) + -> OutputIt { + return write(out, s, specs); +} +template +FMT_CONSTEXPR auto write(OutputIt out, const Char* s, + const format_specs& specs, locale_ref) + -> OutputIt { + if (specs.type == presentation_type::pointer) + return write_ptr(out, bit_cast(s), &specs); + if (!s) throw_format_error("string pointer is null"); + return write(out, basic_string_view(s), specs, {}); +} + +template ::value && + !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { + auto abs_value = static_cast>(value); + bool negative = is_negative(value); + // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. + if (negative) abs_value = ~abs_value + 1; + int num_digits = count_digits(abs_value); + auto size = (negative ? 1 : 0) + static_cast(num_digits); + auto it = reserve(out, size); + if (auto ptr = to_pointer(it, size)) { + if (negative) *ptr++ = static_cast('-'); + format_decimal(ptr, abs_value, num_digits); + return out; + } + if (negative) *it++ = static_cast('-'); + it = format_decimal(it, abs_value, num_digits).end; + return base_iterator(out, it); +} + +// DEPRECATED! +template +FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, + format_specs& specs) -> const Char* { + FMT_ASSERT(begin != end, ""); + auto align = align::none; + auto p = begin + code_point_length(begin); + if (end - p <= 0) p = begin; + for (;;) { + switch (to_ascii(*p)) { + case '<': + align = align::left; + break; + case '>': + align = align::right; + break; + case '^': + align = align::center; + break; + } + if (align != align::none) { + if (p != begin) { + auto c = *begin; + if (c == '}') return begin; + if (c == '{') { + throw_format_error("invalid fill character '{'"); + return begin; + } + specs.fill = {begin, to_unsigned(p - begin)}; + begin = p + 1; + } else { + ++begin; + } + break; + } else if (p == begin) { + break; + } + p = begin; + } + specs.align = align; + return begin; +} + +// A floating-point presentation format. +enum class float_format : unsigned char { + general, // General: exponent notation or fixed point based on magnitude. + exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. + fixed, // Fixed point with the default precision of 6, e.g. 0.0012. + hex +}; + +struct float_specs { + int precision; + float_format format : 8; + sign_t sign : 8; + bool upper : 1; + bool locale : 1; + bool binary32 : 1; + bool showpoint : 1; +}; + +template +FMT_CONSTEXPR auto parse_float_type_spec(const format_specs& specs) + -> float_specs { + auto result = float_specs(); + result.showpoint = specs.alt; + result.locale = specs.localized; + switch (specs.type) { + case presentation_type::none: + result.format = float_format::general; + break; + case presentation_type::general_upper: + result.upper = true; + FMT_FALLTHROUGH; + case presentation_type::general_lower: + result.format = float_format::general; + break; + case presentation_type::exp_upper: + result.upper = true; + FMT_FALLTHROUGH; + case presentation_type::exp_lower: + result.format = float_format::exp; + result.showpoint |= specs.precision != 0; + break; + case presentation_type::fixed_upper: + result.upper = true; + FMT_FALLTHROUGH; + case presentation_type::fixed_lower: + result.format = float_format::fixed; + result.showpoint |= specs.precision != 0; + break; + case presentation_type::hexfloat_upper: + result.upper = true; + FMT_FALLTHROUGH; + case presentation_type::hexfloat_lower: + result.format = float_format::hex; + break; + default: + throw_format_error("invalid format specifier"); + break; + } + return result; +} + +template +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, + format_specs specs, + const float_specs& fspecs) -> OutputIt { + auto str = + isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf"); + constexpr size_t str_size = 3; + auto sign = fspecs.sign; + auto size = str_size + (sign ? 1 : 0); + // Replace '0'-padding with space for non-finite values. + const bool is_zero_fill = + specs.fill.size() == 1 && *specs.fill.data() == static_cast('0'); + if (is_zero_fill) specs.fill[0] = static_cast(' '); + return write_padded(out, specs, size, [=](reserve_iterator it) { + if (sign) *it++ = detail::sign(sign); + return copy_str(str, str + str_size, it); + }); +} + +// A decimal floating-point number significand * pow(10, exp). +struct big_decimal_fp { + const char* significand; + int significand_size; + int exponent; +}; + +constexpr auto get_significand_size(const big_decimal_fp& f) -> int { + return f.significand_size; +} +template +inline auto get_significand_size(const dragonbox::decimal_fp& f) -> int { + return count_digits(f.significand); +} + +template +constexpr auto write_significand(OutputIt out, const char* significand, + int significand_size) -> OutputIt { + return copy_str(significand, significand + significand_size, out); +} +template +inline auto write_significand(OutputIt out, UInt significand, + int significand_size) -> OutputIt { + return format_decimal(out, significand, significand_size).end; +} +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int exponent, + const Grouping& grouping) -> OutputIt { + if (!grouping.has_separator()) { + out = write_significand(out, significand, significand_size); + return detail::fill_n(out, exponent, static_cast('0')); + } + auto buffer = memory_buffer(); + write_significand(appender(buffer), significand, significand_size); + detail::fill_n(appender(buffer), exponent, '0'); + return grouping.apply(out, string_view(buffer.data(), buffer.size())); +} + +template ::value)> +inline auto write_significand(Char* out, UInt significand, int significand_size, + int integral_size, Char decimal_point) -> Char* { + if (!decimal_point) + return format_decimal(out, significand, significand_size).end; + out += significand_size + 1; + Char* end = out; + int floating_size = significand_size - integral_size; + for (int i = floating_size / 2; i > 0; --i) { + out -= 2; + copy2(out, digits2(static_cast(significand % 100))); + significand /= 100; + } + if (floating_size % 2 != 0) { + *--out = static_cast('0' + significand % 10); + significand /= 10; + } + *--out = decimal_point; + format_decimal(out - integral_size, significand, integral_size); + return end; +} + +template >::value)> +inline auto write_significand(OutputIt out, UInt significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { + // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. + Char buffer[digits10() + 2]; + auto end = write_significand(buffer, significand, significand_size, + integral_size, decimal_point); + return detail::copy_str_noinline(buffer, end, out); +} + +template +FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { + out = detail::copy_str_noinline(significand, + significand + integral_size, out); + if (!decimal_point) return out; + *out++ = decimal_point; + return detail::copy_str_noinline(significand + integral_size, + significand + significand_size, out); +} + +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int integral_size, + Char decimal_point, + const Grouping& grouping) -> OutputIt { + if (!grouping.has_separator()) { + return write_significand(out, significand, significand_size, integral_size, + decimal_point); + } + auto buffer = basic_memory_buffer(); + write_significand(buffer_appender(buffer), significand, + significand_size, integral_size, decimal_point); + grouping.apply( + out, basic_string_view(buffer.data(), to_unsigned(integral_size))); + return detail::copy_str_noinline(buffer.data() + integral_size, + buffer.end(), out); +} + +template > +FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, + const format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + auto significand = f.significand; + int significand_size = get_significand_size(f); + const Char zero = static_cast('0'); + auto sign = fspecs.sign; + size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); + using iterator = reserve_iterator; + + Char decimal_point = + fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); + + int output_exp = f.exponent + significand_size - 1; + auto use_exp_format = [=]() { + if (fspecs.format == float_format::exp) return true; + if (fspecs.format != float_format::general) return false; + // Use the fixed notation if the exponent is in [exp_lower, exp_upper), + // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation. + const int exp_lower = -4, exp_upper = 16; + return output_exp < exp_lower || + output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper); + }; + if (use_exp_format()) { + int num_zeros = 0; + if (fspecs.showpoint) { + num_zeros = fspecs.precision - significand_size; + if (num_zeros < 0) num_zeros = 0; + size += to_unsigned(num_zeros); + } else if (significand_size == 1) { + decimal_point = Char(); + } + auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; + int exp_digits = 2; + if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3; + + size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); + char exp_char = fspecs.upper ? 'E' : 'e'; + auto write = [=](iterator it) { + if (sign) *it++ = detail::sign(sign); + // Insert a decimal point after the first digit and add an exponent. + it = write_significand(it, significand, significand_size, 1, + decimal_point); + if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero); + *it++ = static_cast(exp_char); + return write_exponent(output_exp, it); + }; + return specs.width > 0 ? write_padded(out, specs, size, write) + : base_iterator(out, write(reserve(out, size))); + } + + int exp = f.exponent + significand_size; + if (f.exponent >= 0) { + // 1234e5 -> 123400000[.0+] + size += to_unsigned(f.exponent); + int num_zeros = fspecs.precision - exp; + abort_fuzzing_if(num_zeros > 5000); + if (fspecs.showpoint) { + ++size; + if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 0; + if (num_zeros > 0) size += to_unsigned(num_zeros); + } + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, + f.exponent, grouping); + if (!fspecs.showpoint) return it; + *it++ = decimal_point; + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } else if (exp > 0) { + // 1234e-2 -> 12.34[0+] + int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; + size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, exp, + decimal_point, grouping); + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } + // 1234e-6 -> 0.001234 + int num_zeros = -exp; + if (significand_size == 0 && fspecs.precision >= 0 && + fspecs.precision < num_zeros) { + num_zeros = fspecs.precision; + } + bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; + size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + *it++ = zero; + if (!pointy) return it; + *it++ = decimal_point; + it = detail::fill_n(it, num_zeros, zero); + return write_significand(it, significand, significand_size); + }); +} + +template class fallback_digit_grouping { + public: + constexpr fallback_digit_grouping(locale_ref, bool) {} + + constexpr auto has_separator() const -> bool { return false; } + + constexpr auto count_separators(int) const -> int { return 0; } + + template + constexpr auto apply(Out out, basic_string_view) const -> Out { + return out; + } +}; + +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f, + const format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + if (is_constant_evaluated()) { + return do_write_float>(out, f, specs, fspecs, + loc); + } else { + return do_write_float(out, f, specs, fspecs, loc); + } +} + +template constexpr auto isnan(T value) -> bool { + return !(value >= value); // std::isnan doesn't support __float128. +} + +template +struct has_isfinite : std::false_type {}; + +template +struct has_isfinite> + : std::true_type {}; + +template ::value&& + has_isfinite::value)> +FMT_CONSTEXPR20 auto isfinite(T value) -> bool { + constexpr T inf = T(std::numeric_limits::infinity()); + if (is_constant_evaluated()) + return !detail::isnan(value) && value < inf && value > -inf; + return std::isfinite(value); +} +template ::value)> +FMT_CONSTEXPR auto isfinite(T value) -> bool { + T inf = T(std::numeric_limits::infinity()); + // std::isfinite doesn't support __float128. + return !detail::isnan(value) && value < inf && value > -inf; +} + +template ::value)> +FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { + if (is_constant_evaluated()) { +#ifdef __cpp_if_constexpr + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + return (bits >> (num_bits() - 1)) != 0; + } +#endif + } + return std::signbit(static_cast(value)); +} + +inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) { + // Adjust fixed precision by exponent because it is relative to decimal + // point. + if (exp10 > 0 && precision > max_value() - exp10) + FMT_THROW(format_error("number is too big")); + precision += exp10; +} + +class bigint { + private: + // A bigint is stored as an array of bigits (big digits), with bigit at index + // 0 being the least significant one. + using bigit = uint32_t; + using double_bigit = uint64_t; + enum { bigits_capacity = 32 }; + basic_memory_buffer bigits_; + int exp_; + + FMT_CONSTEXPR20 auto operator[](int index) const -> bigit { + return bigits_[to_unsigned(index)]; + } + FMT_CONSTEXPR20 auto operator[](int index) -> bigit& { + return bigits_[to_unsigned(index)]; + } + + static constexpr const int bigit_bits = num_bits(); + + friend struct formatter; + + FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) { + auto result = static_cast((*this)[index]) - other - borrow; + (*this)[index] = static_cast(result); + borrow = static_cast(result >> (bigit_bits * 2 - 1)); + } + + FMT_CONSTEXPR20 void remove_leading_zeros() { + int num_bigits = static_cast(bigits_.size()) - 1; + while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; + bigits_.resize(to_unsigned(num_bigits + 1)); + } + + // Computes *this -= other assuming aligned bigints and *this >= other. + FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) { + FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); + FMT_ASSERT(compare(*this, other) >= 0, ""); + bigit borrow = 0; + int i = other.exp_ - exp_; + for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) + subtract_bigits(i, other.bigits_[j], borrow); + while (borrow > 0) subtract_bigits(i, 0, borrow); + remove_leading_zeros(); + } + + FMT_CONSTEXPR20 void multiply(uint32_t value) { + const double_bigit wide_value = value; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + double_bigit result = bigits_[i] * wide_value + carry; + bigits_[i] = static_cast(result); + carry = static_cast(result >> bigit_bits); + } + if (carry != 0) bigits_.push_back(carry); + } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR20 void multiply(UInt value) { + using half_uint = + conditional_t::value, uint64_t, uint32_t>; + const int shift = num_bits() - bigit_bits; + const UInt lower = static_cast(value); + const UInt upper = value >> num_bits(); + UInt carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + UInt result = lower * bigits_[i] + static_cast(carry); + carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) + + (carry >> bigit_bits); + bigits_[i] = static_cast(result); + } + while (carry != 0) { + bigits_.push_back(static_cast(carry)); + carry >>= bigit_bits; + } + } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR20 void assign(UInt n) { + size_t num_bigits = 0; + do { + bigits_[num_bigits++] = static_cast(n); + n >>= bigit_bits; + } while (n != 0); + bigits_.resize(num_bigits); + exp_ = 0; + } + + public: + FMT_CONSTEXPR20 bigint() : exp_(0) {} + explicit bigint(uint64_t n) { assign(n); } + + bigint(const bigint&) = delete; + void operator=(const bigint&) = delete; + + FMT_CONSTEXPR20 void assign(const bigint& other) { + auto size = other.bigits_.size(); + bigits_.resize(size); + auto data = other.bigits_.data(); + copy_str(data, data + size, bigits_.data()); + exp_ = other.exp_; + } + + template FMT_CONSTEXPR20 void operator=(Int n) { + FMT_ASSERT(n > 0, ""); + assign(uint64_or_128_t(n)); + } + + FMT_CONSTEXPR20 auto num_bigits() const -> int { + return static_cast(bigits_.size()) + exp_; + } + + FMT_NOINLINE FMT_CONSTEXPR20 auto operator<<=(int shift) -> bigint& { + FMT_ASSERT(shift >= 0, ""); + exp_ += shift / bigit_bits; + shift %= bigit_bits; + if (shift == 0) return *this; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + bigit c = bigits_[i] >> (bigit_bits - shift); + bigits_[i] = (bigits_[i] << shift) + carry; + carry = c; + } + if (carry != 0) bigits_.push_back(carry); + return *this; + } + + template + FMT_CONSTEXPR20 auto operator*=(Int value) -> bigint& { + FMT_ASSERT(value > 0, ""); + multiply(uint32_or_64_or_128_t(value)); + return *this; + } + + friend FMT_CONSTEXPR20 auto compare(const bigint& lhs, const bigint& rhs) + -> int { + int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); + if (num_lhs_bigits != num_rhs_bigits) + return num_lhs_bigits > num_rhs_bigits ? 1 : -1; + int i = static_cast(lhs.bigits_.size()) - 1; + int j = static_cast(rhs.bigits_.size()) - 1; + int end = i - j; + if (end < 0) end = 0; + for (; i >= end; --i, --j) { + bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; + if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; + } + if (i != j) return i > j ? 1 : -1; + return 0; + } + + // Returns compare(lhs1 + lhs2, rhs). + friend FMT_CONSTEXPR20 auto add_compare(const bigint& lhs1, + const bigint& lhs2, const bigint& rhs) + -> int { + auto minimum = [](int a, int b) { return a < b ? a : b; }; + auto maximum = [](int a, int b) { return a > b ? a : b; }; + int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits()); + int num_rhs_bigits = rhs.num_bigits(); + if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; + if (max_lhs_bigits > num_rhs_bigits) return 1; + auto get_bigit = [](const bigint& n, int i) -> bigit { + return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; + }; + double_bigit borrow = 0; + int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_); + for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { + double_bigit sum = + static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); + bigit rhs_bigit = get_bigit(rhs, i); + if (sum > rhs_bigit + borrow) return 1; + borrow = rhs_bigit + borrow - sum; + if (borrow > 1) return -1; + borrow <<= bigit_bits; + } + return borrow != 0 ? -1 : 0; + } + + // Assigns pow(10, exp) to this bigint. + FMT_CONSTEXPR20 void assign_pow10(int exp) { + FMT_ASSERT(exp >= 0, ""); + if (exp == 0) return *this = 1; + // Find the top bit. + int bitmask = 1; + while (exp >= bitmask) bitmask <<= 1; + bitmask >>= 1; + // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by + // repeated squaring and multiplication. + *this = 5; + bitmask >>= 1; + while (bitmask != 0) { + square(); + if ((exp & bitmask) != 0) *this *= 5; + bitmask >>= 1; + } + *this <<= exp; // Multiply by pow(2, exp) by shifting. + } + + FMT_CONSTEXPR20 void square() { + int num_bigits = static_cast(bigits_.size()); + int num_result_bigits = 2 * num_bigits; + basic_memory_buffer n(std::move(bigits_)); + bigits_.resize(to_unsigned(num_result_bigits)); + auto sum = uint128_t(); + for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { + // Compute bigit at position bigit_index of the result by adding + // cross-product terms n[i] * n[j] such that i + j == bigit_index. + for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { + // Most terms are multiplied twice which can be optimized in the future. + sum += static_cast(n[i]) * n[j]; + } + (*this)[bigit_index] = static_cast(sum); + sum >>= num_bits(); // Compute the carry. + } + // Do the same for the top half. + for (int bigit_index = num_bigits; bigit_index < num_result_bigits; + ++bigit_index) { + for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) + sum += static_cast(n[i++]) * n[j--]; + (*this)[bigit_index] = static_cast(sum); + sum >>= num_bits(); + } + remove_leading_zeros(); + exp_ *= 2; + } + + // If this bigint has a bigger exponent than other, adds trailing zero to make + // exponents equal. This simplifies some operations such as subtraction. + FMT_CONSTEXPR20 void align(const bigint& other) { + int exp_difference = exp_ - other.exp_; + if (exp_difference <= 0) return; + int num_bigits = static_cast(bigits_.size()); + bigits_.resize(to_unsigned(num_bigits + exp_difference)); + for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) + bigits_[j] = bigits_[i]; + std::uninitialized_fill_n(bigits_.data(), exp_difference, 0u); + exp_ -= exp_difference; + } + + // Divides this bignum by divisor, assigning the remainder to this and + // returning the quotient. + FMT_CONSTEXPR20 auto divmod_assign(const bigint& divisor) -> int { + FMT_ASSERT(this != &divisor, ""); + if (compare(*this, divisor) < 0) return 0; + FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); + align(divisor); + int quotient = 0; + do { + subtract_aligned(divisor); + ++quotient; + } while (compare(*this, divisor) >= 0); + return quotient; + } +}; + +// format_dragon flags. +enum dragon { + predecessor_closer = 1, + fixup = 2, // Run fixup to correct exp10 which can be off by one. + fixed = 4, +}; + +// Formats a floating-point number using a variation of the Fixed-Precision +// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: +// https://fmt.dev/papers/p372-steele.pdf. +FMT_CONSTEXPR20 inline void format_dragon(basic_fp value, + unsigned flags, int num_digits, + buffer& buf, int& exp10) { + bigint numerator; // 2 * R in (FPP)^2. + bigint denominator; // 2 * S in (FPP)^2. + // lower and upper are differences between value and corresponding boundaries. + bigint lower; // (M^- in (FPP)^2). + bigint upper_store; // upper's value if different from lower. + bigint* upper = nullptr; // (M^+ in (FPP)^2). + // Shift numerator and denominator by an extra bit or two (if lower boundary + // is closer) to make lower and upper integers. This eliminates multiplication + // by 2 during later computations. + bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0; + int shift = is_predecessor_closer ? 2 : 1; + if (value.e >= 0) { + numerator = value.f; + numerator <<= value.e + shift; + lower = 1; + lower <<= value.e; + if (is_predecessor_closer) { + upper_store = 1; + upper_store <<= value.e + 1; + upper = &upper_store; + } + denominator.assign_pow10(exp10); + denominator <<= shift; + } else if (exp10 < 0) { + numerator.assign_pow10(-exp10); + lower.assign(numerator); + if (is_predecessor_closer) { + upper_store.assign(numerator); + upper_store <<= 1; + upper = &upper_store; + } + numerator *= value.f; + numerator <<= shift; + denominator = 1; + denominator <<= shift - value.e; + } else { + numerator = value.f; + numerator <<= shift; + denominator.assign_pow10(exp10); + denominator <<= shift - value.e; + lower = 1; + if (is_predecessor_closer) { + upper_store = 1ULL << 1; + upper = &upper_store; + } + } + int even = static_cast((value.f & 1) == 0); + if (!upper) upper = &lower; + bool shortest = num_digits < 0; + if ((flags & dragon::fixup) != 0) { + if (add_compare(numerator, *upper, denominator) + even <= 0) { + --exp10; + numerator *= 10; + if (num_digits < 0) { + lower *= 10; + if (upper != &lower) *upper *= 10; + } + } + if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1); + } + // Invariant: value == (numerator / denominator) * pow(10, exp10). + if (shortest) { + // Generate the shortest representation. + num_digits = 0; + char* data = buf.data(); + for (;;) { + int digit = numerator.divmod_assign(denominator); + bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. + // numerator + upper >[=] pow10: + bool high = add_compare(numerator, *upper, denominator) + even > 0; + data[num_digits++] = static_cast('0' + digit); + if (low || high) { + if (!low) { + ++data[num_digits - 1]; + } else if (high) { + int result = add_compare(numerator, numerator, denominator); + // Round half to even. + if (result > 0 || (result == 0 && (digit % 2) != 0)) + ++data[num_digits - 1]; + } + buf.try_resize(to_unsigned(num_digits)); + exp10 -= num_digits - 1; + return; + } + numerator *= 10; + lower *= 10; + if (upper != &lower) *upper *= 10; + } + } + // Generate the given number of digits. + exp10 -= num_digits - 1; + if (num_digits <= 0) { + denominator *= 10; + auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; + buf.push_back(digit); + return; + } + buf.try_resize(to_unsigned(num_digits)); + for (int i = 0; i < num_digits - 1; ++i) { + int digit = numerator.divmod_assign(denominator); + buf[i] = static_cast('0' + digit); + numerator *= 10; + } + int digit = numerator.divmod_assign(denominator); + auto result = add_compare(numerator, numerator, denominator); + if (result > 0 || (result == 0 && (digit % 2) != 0)) { + if (digit == 9) { + const auto overflow = '0' + 10; + buf[num_digits - 1] = overflow; + // Propagate the carry. + for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] == overflow) { + buf[0] = '1'; + if ((flags & dragon::fixed) != 0) + buf.push_back('0'); + else + ++exp10; + } + return; + } + ++digit; + } + buf[num_digits - 1] = static_cast('0' + digit); +} + +// Formats a floating-point number using the hexfloat format. +template ::value)> +FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision, + float_specs specs, buffer& buf) { + // float is passed as double to reduce the number of instantiations and to + // simplify implementation. + static_assert(!std::is_same::value, ""); + + using info = dragonbox::float_info; + + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename info::carrier_uint; + + constexpr auto num_float_significand_bits = + detail::num_significand_bits(); + + basic_fp f(value); + f.e += num_float_significand_bits; + if (!has_implicit_bit()) --f.e; + + constexpr auto num_fraction_bits = + num_float_significand_bits + (has_implicit_bit() ? 1 : 0); + constexpr auto num_xdigits = (num_fraction_bits + 3) / 4; + + constexpr auto leading_shift = ((num_xdigits - 1) * 4); + const auto leading_mask = carrier_uint(0xF) << leading_shift; + const auto leading_xdigit = + static_cast((f.f & leading_mask) >> leading_shift); + if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1); + + int print_xdigits = num_xdigits - 1; + if (precision >= 0 && print_xdigits > precision) { + const int shift = ((print_xdigits - precision - 1) * 4); + const auto mask = carrier_uint(0xF) << shift; + const auto v = static_cast((f.f & mask) >> shift); + + if (v >= 8) { + const auto inc = carrier_uint(1) << (shift + 4); + f.f += inc; + f.f &= ~(inc - 1); + } + + // Check long double overflow + if (!has_implicit_bit()) { + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + if ((f.f & implicit_bit) == implicit_bit) { + f.f >>= 4; + f.e += 4; + } + } + + print_xdigits = precision; + } + + char xdigits[num_bits() / 4]; + detail::fill_n(xdigits, sizeof(xdigits), '0'); + format_uint<4>(xdigits, f.f, num_xdigits, specs.upper); + + // Remove zero tail + while (print_xdigits > 0 && xdigits[print_xdigits] == '0') --print_xdigits; + + buf.push_back('0'); + buf.push_back(specs.upper ? 'X' : 'x'); + buf.push_back(xdigits[0]); + if (specs.showpoint || print_xdigits > 0 || print_xdigits < precision) + buf.push_back('.'); + buf.append(xdigits + 1, xdigits + 1 + print_xdigits); + for (; print_xdigits < precision; ++print_xdigits) buf.push_back('0'); + + buf.push_back(specs.upper ? 'P' : 'p'); + + uint32_t abs_e; + if (f.e < 0) { + buf.push_back('-'); + abs_e = static_cast(-f.e); + } else { + buf.push_back('+'); + abs_e = static_cast(f.e); + } + format_decimal(appender(buf), abs_e, detail::count_digits(abs_e)); +} + +template ::value)> +FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision, + float_specs specs, buffer& buf) { + format_hexfloat(static_cast(value), precision, specs, buf); +} + +constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { + // For checking rounding thresholds. + // The kth entry is chosen to be the smallest integer such that the + // upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k. + // It is equal to ceil(2^31 + 2^32/10^(k + 1)). + // These are stored in a string literal because we cannot have static arrays + // in constexpr functions and non-static ones are poorly optimized. + return U"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7" + U"\x800001ae\x8000002b"[index]; +} + +template +FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, + buffer& buf) -> int { + // float is passed as double to reduce the number of instantiations. + static_assert(!std::is_same::value, ""); + FMT_ASSERT(value >= 0, "value is negative"); + auto converted_value = convert_float(value); + + const bool fixed = specs.format == float_format::fixed; + if (value <= 0) { // <= instead of == to silence a warning. + if (precision <= 0 || !fixed) { + buf.push_back('0'); + return 0; + } + buf.try_resize(to_unsigned(precision)); + fill_n(buf.data(), precision, '0'); + return -precision; + } + + int exp = 0; + bool use_dragon = true; + unsigned dragon_flags = 0; + if (!is_fast_float() || is_constant_evaluated()) { + const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) + using info = dragonbox::float_info; + const auto f = basic_fp(converted_value); + // Compute exp, an approximate power of 10, such that + // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). + // This is based on log10(value) == log2(value) / log2(10) and approximation + // of log2(value) by e + num_fraction_bits idea from double-conversion. + auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10; + exp = static_cast(e); + if (e > exp) ++exp; // Compute ceil. + dragon_flags = dragon::fixup; + } else if (precision < 0) { + // Use Dragonbox for the shortest format. + if (specs.binary32) { + auto dec = dragonbox::to_decimal(static_cast(value)); + write(buffer_appender(buf), dec.significand); + return dec.exponent; + } + auto dec = dragonbox::to_decimal(static_cast(value)); + write(buffer_appender(buf), dec.significand); + return dec.exponent; + } else { + // Extract significand bits and exponent bits. + using info = dragonbox::float_info; + auto br = bit_cast(static_cast(value)); + + const uint64_t significand_mask = + (static_cast(1) << num_significand_bits()) - 1; + uint64_t significand = (br & significand_mask); + int exponent = static_cast((br & exponent_mask()) >> + num_significand_bits()); + + if (exponent != 0) { // Check if normal. + exponent -= exponent_bias() + num_significand_bits(); + significand |= + (static_cast(1) << num_significand_bits()); + significand <<= 1; + } else { + // Normalize subnormal inputs. + FMT_ASSERT(significand != 0, "zeros should not appear here"); + int shift = countl_zero(significand); + FMT_ASSERT(shift >= num_bits() - num_significand_bits(), + ""); + shift -= (num_bits() - num_significand_bits() - 2); + exponent = (std::numeric_limits::min_exponent - + num_significand_bits()) - + shift; + significand <<= shift; + } + + // Compute the first several nonzero decimal significand digits. + // We call the number we get the first segment. + const int k = info::kappa - dragonbox::floor_log10_pow2(exponent); + exp = -k; + const int beta = exponent + dragonbox::floor_log2_pow10(k); + uint64_t first_segment; + bool has_more_segments; + int digits_in_the_first_segment; + { + const auto r = dragonbox::umul192_upper128( + significand << beta, dragonbox::get_cached_power(k)); + first_segment = r.high(); + has_more_segments = r.low() != 0; + + // The first segment can have 18 ~ 19 digits. + if (first_segment >= 1000000000000000000ULL) { + digits_in_the_first_segment = 19; + } else { + // When it is of 18-digits, we align it to 19-digits by adding a bogus + // zero at the end. + digits_in_the_first_segment = 18; + first_segment *= 10; + } + } + + // Compute the actual number of decimal digits to print. + if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment); + + // Use Dragon4 only when there might be not enough digits in the first + // segment. + if (digits_in_the_first_segment > precision) { + use_dragon = false; + + if (precision <= 0) { + exp += digits_in_the_first_segment; + + if (precision < 0) { + // Nothing to do, since all we have are just leading zeros. + buf.try_resize(0); + } else { + // We may need to round-up. + buf.try_resize(1); + if ((first_segment | static_cast(has_more_segments)) > + 5000000000000000000ULL) { + buf[0] = '1'; + } else { + buf[0] = '0'; + } + } + } // precision <= 0 + else { + exp += digits_in_the_first_segment - precision; + + // When precision > 0, we divide the first segment into three + // subsegments, each with 9, 9, and 0 ~ 1 digits so that each fits + // in 32-bits which usually allows faster calculation than in + // 64-bits. Since some compiler (e.g. MSVC) doesn't know how to optimize + // division-by-constant for large 64-bit divisors, we do it here + // manually. The magic number 7922816251426433760 below is equal to + // ceil(2^(64+32) / 10^10). + const uint32_t first_subsegment = static_cast( + dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >> + 32); + const uint64_t second_third_subsegments = + first_segment - first_subsegment * 10000000000ULL; + + uint64_t prod; + uint32_t digits; + bool should_round_up; + int number_of_digits_to_print = precision > 9 ? 9 : precision; + + // Print a 9-digits subsegment, either the first or the second. + auto print_subsegment = [&](uint32_t subsegment, char* buffer) { + int number_of_digits_printed = 0; + + // If we want to print an odd number of digits from the subsegment, + if ((number_of_digits_to_print & 1) != 0) { + // Convert to 64-bit fixed-point fractional form with 1-digit + // integer part. The magic number 720575941 is a good enough + // approximation of 2^(32 + 24) / 10^8; see + // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case + // for details. + prod = ((subsegment * static_cast(720575941)) >> 24) + 1; + digits = static_cast(prod >> 32); + *buffer = static_cast('0' + digits); + number_of_digits_printed++; + } + // If we want to print an even number of digits from the + // first_subsegment, + else { + // Convert to 64-bit fixed-point fractional form with 2-digits + // integer part. The magic number 450359963 is a good enough + // approximation of 2^(32 + 20) / 10^7; see + // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case + // for details. + prod = ((subsegment * static_cast(450359963)) >> 20) + 1; + digits = static_cast(prod >> 32); + copy2(buffer, digits2(digits)); + number_of_digits_printed += 2; + } + + // Print all digit pairs. + while (number_of_digits_printed < number_of_digits_to_print) { + prod = static_cast(prod) * static_cast(100); + digits = static_cast(prod >> 32); + copy2(buffer + number_of_digits_printed, digits2(digits)); + number_of_digits_printed += 2; + } + }; + + // Print first subsegment. + print_subsegment(first_subsegment, buf.data()); + + // Perform rounding if the first subsegment is the last subsegment to + // print. + if (precision <= 9) { + // Rounding inside the subsegment. + // We round-up if: + // - either the fractional part is strictly larger than 1/2, or + // - the fractional part is exactly 1/2 and the last digit is odd. + // We rely on the following observations: + // - If fractional_part >= threshold, then the fractional part is + // strictly larger than 1/2. + // - If the MSB of fractional_part is set, then the fractional part + // must be at least 1/2. + // - When the MSB of fractional_part is set, either + // second_third_subsegments being nonzero or has_more_segments + // being true means there are further digits not printed, so the + // fractional part is strictly larger than 1/2. + if (precision < 9) { + uint32_t fractional_part = static_cast(prod); + should_round_up = + fractional_part >= fractional_part_rounding_thresholds( + 8 - number_of_digits_to_print) || + ((fractional_part >> 31) & + ((digits & 1) | (second_third_subsegments != 0) | + has_more_segments)) != 0; + } + // Rounding at the subsegment boundary. + // In this case, the fractional part is at least 1/2 if and only if + // second_third_subsegments >= 5000000000ULL, and is strictly larger + // than 1/2 if we further have either second_third_subsegments > + // 5000000000ULL or has_more_segments == true. + else { + should_round_up = second_third_subsegments > 5000000000ULL || + (second_third_subsegments == 5000000000ULL && + ((digits & 1) != 0 || has_more_segments)); + } + } + // Otherwise, print the second subsegment. + else { + // Compilers are not aware of how to leverage the maximum value of + // second_third_subsegments to find out a better magic number which + // allows us to eliminate an additional shift. 1844674407370955162 = + // ceil(2^64/10) < ceil(2^64*(10^9/(10^10 - 1))). + const uint32_t second_subsegment = + static_cast(dragonbox::umul128_upper64( + second_third_subsegments, 1844674407370955162ULL)); + const uint32_t third_subsegment = + static_cast(second_third_subsegments) - + second_subsegment * 10; + + number_of_digits_to_print = precision - 9; + print_subsegment(second_subsegment, buf.data() + 9); + + // Rounding inside the subsegment. + if (precision < 18) { + // The condition third_subsegment != 0 implies that the segment was + // of 19 digits, so in this case the third segment should be + // consisting of a genuine digit from the input. + uint32_t fractional_part = static_cast(prod); + should_round_up = + fractional_part >= fractional_part_rounding_thresholds( + 8 - number_of_digits_to_print) || + ((fractional_part >> 31) & + ((digits & 1) | (third_subsegment != 0) | + has_more_segments)) != 0; + } + // Rounding at the subsegment boundary. + else { + // In this case, the segment must be of 19 digits, thus + // the third subsegment should be consisting of a genuine digit from + // the input. + should_round_up = third_subsegment > 5 || + (third_subsegment == 5 && + ((digits & 1) != 0 || has_more_segments)); + } + } + + // Round-up if necessary. + if (should_round_up) { + ++buf[precision - 1]; + for (int i = precision - 1; i > 0 && buf[i] > '9'; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] > '9') { + buf[0] = '1'; + if (fixed) + buf[precision++] = '0'; + else + ++exp; + } + } + buf.try_resize(to_unsigned(precision)); + } + } // if (digits_in_the_first_segment > precision) + else { + // Adjust the exponent for its use in Dragon4. + exp += digits_in_the_first_segment - 1; + } + } + if (use_dragon) { + auto f = basic_fp(); + bool is_predecessor_closer = specs.binary32 + ? f.assign(static_cast(value)) + : f.assign(converted_value); + if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer; + if (fixed) dragon_flags |= dragon::fixed; + // Limit precision to the maximum possible number of significant digits in + // an IEEE754 double because we don't need to generate zeros. + const int max_double_digits = 767; + if (precision > max_double_digits) precision = max_double_digits; + format_dragon(f, dragon_flags, precision, buf, exp); + } + if (!fixed && !specs.showpoint) { + // Remove trailing zeros. + auto num_digits = buf.size(); + while (num_digits > 0 && buf[num_digits - 1] == '0') { + --num_digits; + ++exp; + } + buf.try_resize(num_digits); + } + return exp; +} +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, + format_specs specs, locale_ref loc) + -> OutputIt { + float_specs fspecs = parse_float_type_spec(specs); + fspecs.sign = specs.sign; + if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. + fspecs.sign = sign::minus; + value = -value; + } else if (fspecs.sign == sign::minus) { + fspecs.sign = sign::none; + } + + if (!detail::isfinite(value)) + return write_nonfinite(out, detail::isnan(value), specs, fspecs); + + if (specs.align == align::numeric && fspecs.sign) { + auto it = reserve(out, 1); + *it++ = detail::sign(fspecs.sign); + out = base_iterator(out, it); + fspecs.sign = sign::none; + if (specs.width != 0) --specs.width; + } + + memory_buffer buffer; + if (fspecs.format == float_format::hex) { + if (fspecs.sign) buffer.push_back(detail::sign(fspecs.sign)); + format_hexfloat(convert_float(value), specs.precision, fspecs, buffer); + return write_bytes(out, {buffer.data(), buffer.size()}, + specs); + } + int precision = specs.precision >= 0 || specs.type == presentation_type::none + ? specs.precision + : 6; + if (fspecs.format == float_format::exp) { + if (precision == max_value()) + throw_format_error("number is too big"); + else + ++precision; + } else if (fspecs.format != float_format::fixed && precision == 0) { + precision = 1; + } + if (const_check(std::is_same())) fspecs.binary32 = true; + int exp = format_float(convert_float(value), precision, fspecs, buffer); + fspecs.precision = precision; + auto f = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; + return write_float(out, f, specs, fspecs, loc); +} + +template ::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs, + locale_ref loc = {}) -> OutputIt { + if (const_check(!is_supported_floating_point(value))) return out; + return specs.localized && write_loc(out, value, specs, loc) + ? out + : write_float(out, value, specs, loc); +} + +template ::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { + if (is_constant_evaluated()) return write(out, value, format_specs()); + if (const_check(!is_supported_floating_point(value))) return out; + + auto fspecs = float_specs(); + if (detail::signbit(value)) { + fspecs.sign = sign::minus; + value = -value; + } + + constexpr auto specs = format_specs(); + using floaty = conditional_t::value, double, T>; + using floaty_uint = typename dragonbox::float_info::carrier_uint; + floaty_uint mask = exponent_mask(); + if ((bit_cast(value) & mask) == mask) + return write_nonfinite(out, std::isnan(value), specs, fspecs); + + auto dec = dragonbox::to_decimal(static_cast(value)); + return write_float(out, dec, specs, fspecs, {}); +} + +template ::value && + !is_fast_float::value)> +inline auto write(OutputIt out, T value) -> OutputIt { + return write(out, value, format_specs()); +} + +template +auto write(OutputIt out, monostate, format_specs = {}, locale_ref = {}) + -> OutputIt { + FMT_ASSERT(false, ""); + return out; +} + +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view value) + -> OutputIt { + auto it = reserve(out, value.size()); + it = copy_str_noinline(value.begin(), value.end(), it); + return base_iterator(out, it); +} + +template ::value)> +constexpr auto write(OutputIt out, const T& value) -> OutputIt { + return write(out, to_string_view(value)); +} + +// FMT_ENABLE_IF() condition separated to workaround an MSVC bug. +template < + typename Char, typename OutputIt, typename T, + bool check = + std::is_enum::value && !std::is_same::value && + mapped_type_constant>::value != + type::custom_type, + FMT_ENABLE_IF(check)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { + return write(out, static_cast>(value)); +} + +template ::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value, + const format_specs& specs = {}, locale_ref = {}) + -> OutputIt { + return specs.type != presentation_type::none && + specs.type != presentation_type::string + ? write(out, value ? 1 : 0, specs, {}) + : write_bytes(out, value ? "true" : "false", specs); +} + +template +FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt { + auto it = reserve(out, 1); + *it++ = value; + return base_iterator(out, it); +} + +template +FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value) + -> OutputIt { + if (value) return write(out, basic_string_view(value)); + throw_format_error("string pointer is null"); + return out; +} + +template ::value)> +auto write(OutputIt out, const T* value, const format_specs& specs = {}, + locale_ref = {}) -> OutputIt { + return write_ptr(out, bit_cast(value), &specs); +} + +// A write overload that handles implicit conversions. +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t< + std::is_class::value && !is_string::value && + !is_floating_point::value && !std::is_same::value && + !std::is_same().map( + value))>>::value, + OutputIt> { + return write(out, arg_mapper().map(value)); +} + +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) + -> enable_if_t::value == type::custom_type, + OutputIt> { + auto formatter = typename Context::template formatter_type(); + auto parse_ctx = typename Context::parse_context_type({}); + formatter.parse(parse_ctx); + auto ctx = Context(out, {}, {}); + return formatter.format(value, ctx); +} + +// An argument visitor that formats the argument and writes it via the output +// iterator. It's a class and not a generic lambda for compatibility with C++11. +template struct default_arg_formatter { + using iterator = buffer_appender; + using context = buffer_context; + + iterator out; + basic_format_args args; + locale_ref loc; + + template auto operator()(T value) -> iterator { + return write(out, value); + } + auto operator()(typename basic_format_arg::handle h) -> iterator { + basic_format_parse_context parse_ctx({}); + context format_ctx(out, args, loc); + h.format(parse_ctx, format_ctx); + return format_ctx.out(); + } +}; + +template struct arg_formatter { + using iterator = buffer_appender; + using context = buffer_context; + + iterator out; + const format_specs& specs; + locale_ref locale; + + template + FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { + return detail::write(out, value, specs, locale); + } + auto operator()(typename basic_format_arg::handle) -> iterator { + // User-defined types are handled separately because they require access + // to the parse context. + return out; + } +}; + +struct width_checker { + template ::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { + if (is_negative(value)) throw_format_error("negative width"); + return static_cast(value); + } + + template ::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long { + throw_format_error("width is not integer"); + return 0; + } +}; + +struct precision_checker { + template ::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { + if (is_negative(value)) throw_format_error("negative precision"); + return static_cast(value); + } + + template ::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long { + throw_format_error("precision is not integer"); + return 0; + } +}; + +template +FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg) -> int { + unsigned long long value = visit_format_arg(Handler(), arg); + if (value > to_unsigned(max_value())) + throw_format_error("number is too big"); + return static_cast(value); +} + +template +FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id)) { + auto arg = ctx.arg(id); + if (!arg) ctx.on_error("argument not found"); + return arg; +} + +template +FMT_CONSTEXPR void handle_dynamic_spec(int& value, + arg_ref ref, + Context& ctx) { + switch (ref.kind) { + case arg_id_kind::none: + break; + case arg_id_kind::index: + value = detail::get_dynamic_spec(get_arg(ctx, ref.val.index)); + break; + case arg_id_kind::name: + value = detail::get_dynamic_spec(get_arg(ctx, ref.val.name)); + break; + } +} + +#if FMT_USE_USER_DEFINED_LITERALS +# if FMT_USE_NONTYPE_TEMPLATE_ARGS +template Str> +struct statically_named_arg : view { + static constexpr auto name = Str.data; + + const T& value; + statically_named_arg(const T& v) : value(v) {} +}; + +template Str> +struct is_named_arg> : std::true_type {}; + +template Str> +struct is_statically_named_arg> + : std::true_type {}; + +template Str> +struct udl_arg { + template auto operator=(T&& value) const { + return statically_named_arg(std::forward(value)); + } +}; +# else +template struct udl_arg { + const Char* str; + + template auto operator=(T&& value) const -> named_arg { + return {str, std::forward(value)}; + } +}; +# endif +#endif // FMT_USE_USER_DEFINED_LITERALS + +template +auto vformat(const Locale& loc, basic_string_view fmt, + basic_format_args>> args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); + return {buf.data(), buf.size()}; +} + +using format_func = void (*)(detail::buffer&, int, const char*); + +FMT_API void format_error_code(buffer& out, int error_code, + string_view message) noexcept; + +FMT_API void report_error(format_func func, int error_code, + const char* message) noexcept; +} // namespace detail + +FMT_API auto vsystem_error(int error_code, string_view format_str, + format_args args) -> std::system_error; + +/** + \rst + Constructs :class:`std::system_error` with a message formatted with + ``fmt::format(fmt, args...)``. + *error_code* is a system error code as given by ``errno``. + + **Example**:: + + // This throws std::system_error with the description + // cannot open file 'madeup': No such file or directory + // or similar (system message may vary). + const char* filename = "madeup"; + std::FILE* file = std::fopen(filename, "r"); + if (!file) + throw fmt::system_error(errno, "cannot open file '{}'", filename); + \endrst + */ +template +auto system_error(int error_code, format_string fmt, T&&... args) + -> std::system_error { + return vsystem_error(error_code, fmt, fmt::make_format_args(args...)); +} + +/** + \rst + Formats an error message for an error returned by an operating system or a + language runtime, for example a file opening error, and writes it to *out*. + The format is the same as the one used by ``std::system_error(ec, message)`` + where ``ec`` is ``std::error_code(error_code, std::generic_category()})``. + It is implementation-defined but normally looks like: + + .. parsed-literal:: + **: ** + + where ** is the passed message and ** is the system + message corresponding to the error code. + *error_code* is a system error code as given by ``errno``. + \endrst + */ +FMT_API void format_system_error(detail::buffer& out, int error_code, + const char* message) noexcept; + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_system_error(int error_code, const char* message) noexcept; + +/** Fast integer formatter. */ +class format_int { + private: + // Buffer should be large enough to hold all digits (digits10 + 1), + // a sign and a null character. + enum { buffer_size = std::numeric_limits::digits10 + 3 }; + mutable char buffer_[buffer_size]; + char* str_; + + template auto format_unsigned(UInt value) -> char* { + auto n = static_cast>(value); + return detail::format_decimal(buffer_, n, buffer_size - 1).begin; + } + + template auto format_signed(Int value) -> char* { + auto abs_value = static_cast>(value); + bool negative = value < 0; + if (negative) abs_value = 0 - abs_value; + auto begin = format_unsigned(abs_value); + if (negative) *--begin = '-'; + return begin; + } + + public: + explicit format_int(int value) : str_(format_signed(value)) {} + explicit format_int(long value) : str_(format_signed(value)) {} + explicit format_int(long long value) : str_(format_signed(value)) {} + explicit format_int(unsigned value) : str_(format_unsigned(value)) {} + explicit format_int(unsigned long value) : str_(format_unsigned(value)) {} + explicit format_int(unsigned long long value) + : str_(format_unsigned(value)) {} + + /** Returns the number of characters written to the output buffer. */ + auto size() const -> size_t { + return detail::to_unsigned(buffer_ - str_ + buffer_size - 1); + } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + auto data() const -> const char* { return str_; } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + auto c_str() const -> const char* { + buffer_[buffer_size - 1] = '\0'; + return str_; + } + + /** + \rst + Returns the content of the output buffer as an ``std::string``. + \endrst + */ + auto str() const -> std::string { return std::string(str_, size()); } +}; + +template +struct formatter::value>> + : formatter, Char> { + template + auto format(const T& value, FormatContext& ctx) const -> decltype(ctx.out()) { + using base = formatter, Char>; + return base::format(format_as(value), ctx); + } +}; + +#define FMT_FORMAT_AS(Type, Base) \ + template \ + struct formatter : formatter {} + +FMT_FORMAT_AS(signed char, int); +FMT_FORMAT_AS(unsigned char, unsigned); +FMT_FORMAT_AS(short, int); +FMT_FORMAT_AS(unsigned short, unsigned); +FMT_FORMAT_AS(long, detail::long_type); +FMT_FORMAT_AS(unsigned long, detail::ulong_type); +FMT_FORMAT_AS(Char*, const Char*); +FMT_FORMAT_AS(std::basic_string, basic_string_view); +FMT_FORMAT_AS(std::nullptr_t, const void*); +FMT_FORMAT_AS(detail::std_string_view, basic_string_view); +FMT_FORMAT_AS(void*, const void*); + +template +struct formatter : formatter, Char> {}; + +/** + \rst + Converts ``p`` to ``const void*`` for pointer formatting. + + **Example**:: + + auto s = fmt::format("{}", fmt::ptr(p)); + \endrst + */ +template auto ptr(T p) -> const void* { + static_assert(std::is_pointer::value, ""); + return detail::bit_cast(p); +} +template +auto ptr(const std::unique_ptr& p) -> const void* { + return p.get(); +} +template auto ptr(const std::shared_ptr& p) -> const void* { + return p.get(); +} + +/** + \rst + Converts ``e`` to the underlying type. + + **Example**:: + + enum class color { red, green, blue }; + auto s = fmt::format("{}", fmt::underlying(color::red)); + \endrst + */ +template +constexpr auto underlying(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} + +namespace enums { +template ::value)> +constexpr auto format_as(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} +} // namespace enums + +class bytes { + private: + string_view data_; + friend struct formatter; + + public: + explicit bytes(string_view data) : data_(data) {} +}; + +template <> struct formatter { + private: + detail::dynamic_format_specs<> specs_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const char* { + return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::string_type); + } + + template + auto format(bytes b, FormatContext& ctx) -> decltype(ctx.out()) { + detail::handle_dynamic_spec(specs_.width, + specs_.width_ref, ctx); + detail::handle_dynamic_spec( + specs_.precision, specs_.precision_ref, ctx); + return detail::write_bytes(ctx.out(), b.data_, specs_); + } +}; + +// group_digits_view is not derived from view because it copies the argument. +template struct group_digits_view { + T value; +}; + +/** + \rst + Returns a view that formats an integer value using ',' as a locale-independent + thousands separator. + + **Example**:: + + fmt::print("{}", fmt::group_digits(12345)); + // Output: "12,345" + \endrst + */ +template auto group_digits(T value) -> group_digits_view { + return {value}; +} + +template struct formatter> : formatter { + private: + detail::dynamic_format_specs<> specs_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const char* { + return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::int_type); + } + + template + auto format(group_digits_view t, FormatContext& ctx) + -> decltype(ctx.out()) { + detail::handle_dynamic_spec(specs_.width, + specs_.width_ref, ctx); + detail::handle_dynamic_spec( + specs_.precision, specs_.precision_ref, ctx); + return detail::write_int( + ctx.out(), static_cast>(t.value), 0, specs_, + detail::digit_grouping("\3", ",")); + } +}; + +template struct nested_view { + const formatter* fmt; + const T* value; +}; + +template struct formatter> { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> const char* { + return ctx.begin(); + } + auto format(nested_view view, format_context& ctx) const + -> decltype(ctx.out()) { + return view.fmt->format(*view.value, ctx); + } +}; + +template struct nested_formatter { + private: + int width_; + detail::fill_t fill_; + align_t align_ : 4; + formatter formatter_; + + public: + constexpr nested_formatter() : width_(0), align_(align_t::none) {} + + FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> const char* { + auto specs = detail::dynamic_format_specs(); + auto it = parse_format_specs(ctx.begin(), ctx.end(), specs, ctx, + detail::type::none_type); + width_ = specs.width; + fill_ = specs.fill; + align_ = specs.align; + ctx.advance_to(it); + return formatter_.parse(ctx); + } + + template + auto write_padded(format_context& ctx, F write) const -> decltype(ctx.out()) { + if (width_ == 0) return write(ctx.out()); + auto buf = memory_buffer(); + write(std::back_inserter(buf)); + auto specs = format_specs<>(); + specs.width = width_; + specs.fill = fill_; + specs.align = align_; + return detail::write(ctx.out(), string_view(buf.data(), buf.size()), specs); + } + + auto nested(const T& value) const -> nested_view { + return nested_view{&formatter_, &value}; + } +}; + +// DEPRECATED! join_view will be moved to ranges.h. +template +struct join_view : detail::view { + It begin; + Sentinel end; + basic_string_view sep; + + join_view(It b, Sentinel e, basic_string_view s) + : begin(b), end(e), sep(s) {} +}; + +template +struct formatter, Char> { + private: + using value_type = +#ifdef __cpp_lib_ranges + std::iter_value_t; +#else + typename std::iterator_traits::value_type; +#endif + formatter, Char> value_formatter_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* { + return value_formatter_.parse(ctx); + } + + template + auto format(const join_view& value, + FormatContext& ctx) const -> decltype(ctx.out()) { + auto it = value.begin; + auto out = ctx.out(); + if (it != value.end) { + out = value_formatter_.format(*it, ctx); + ++it; + while (it != value.end) { + out = detail::copy_str(value.sep.begin(), value.sep.end(), out); + ctx.advance_to(out); + out = value_formatter_.format(*it, ctx); + ++it; + } + } + return out; + } +}; + +/** + Returns a view that formats the iterator range `[begin, end)` with elements + separated by `sep`. + */ +template +auto join(It begin, Sentinel end, string_view sep) -> join_view { + return {begin, end, sep}; +} + +/** + \rst + Returns a view that formats `range` with elements separated by `sep`. + + **Example**:: + + std::vector v = {1, 2, 3}; + fmt::print("{}", fmt::join(v, ", ")); + // Output: "1, 2, 3" + + ``fmt::join`` applies passed format specifiers to the range elements:: + + fmt::print("{:02}", fmt::join(v, ", ")); + // Output: "01, 02, 03" + \endrst + */ +template +auto join(Range&& range, string_view sep) + -> join_view, detail::sentinel_t> { + return join(std::begin(range), std::end(range), sep); +} + +/** + \rst + Converts *value* to ``std::string`` using the default format for type *T*. + + **Example**:: + + #include + + std::string answer = fmt::to_string(42); + \endrst + */ +template ::value && + !detail::has_format_as::value)> +inline auto to_string(const T& value) -> std::string { + auto buffer = memory_buffer(); + detail::write(appender(buffer), value); + return {buffer.data(), buffer.size()}; +} + +template ::value)> +FMT_NODISCARD inline auto to_string(T value) -> std::string { + // The buffer should be large enough to store the number including the sign + // or "false" for bool. + constexpr int max_size = detail::digits10() + 2; + char buffer[max_size > 5 ? static_cast(max_size) : 5]; + char* begin = buffer; + return std::string(begin, detail::write(begin, value)); +} + +template +FMT_NODISCARD auto to_string(const basic_memory_buffer& buf) + -> std::basic_string { + auto size = buf.size(); + detail::assume(size < std::basic_string().max_size()); + return std::basic_string(buf.data(), size); +} + +template ::value && + detail::has_format_as::value)> +inline auto to_string(const T& value) -> std::string { + return to_string(format_as(value)); +} + +FMT_END_EXPORT + +namespace detail { + +template +void vformat_to(buffer& buf, basic_string_view fmt, + typename vformat_args::type args, locale_ref loc) { + auto out = buffer_appender(buf); + if (fmt.size() == 2 && equal2(fmt.data(), "{}")) { + auto arg = args.get(0); + if (!arg) throw_format_error("argument not found"); + visit_format_arg(default_arg_formatter{out, args, loc}, arg); + return; + } + + struct format_handler : error_handler { + basic_format_parse_context parse_context; + buffer_context context; + + format_handler(buffer_appender p_out, basic_string_view str, + basic_format_args> p_args, + locale_ref p_loc) + : parse_context(str), context(p_out, p_args, p_loc) {} + + void on_text(const Char* begin, const Char* end) { + auto text = basic_string_view(begin, to_unsigned(end - begin)); + context.advance_to(write(context.out(), text)); + } + + FMT_CONSTEXPR auto on_arg_id() -> int { + return parse_context.next_arg_id(); + } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + return parse_context.check_arg_id(id), id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { + int arg_id = context.arg_id(id); + if (arg_id < 0) throw_format_error("argument not found"); + return arg_id; + } + + FMT_INLINE void on_replacement_field(int id, const Char*) { + auto arg = get_arg(context, id); + context.advance_to(visit_format_arg( + default_arg_formatter{context.out(), context.args(), + context.locale()}, + arg)); + } + + auto on_format_specs(int id, const Char* begin, const Char* end) + -> const Char* { + auto arg = get_arg(context, id); + // Not using a visitor for custom types gives better codegen. + if (arg.format_custom(begin, parse_context, context)) + return parse_context.begin(); + auto specs = detail::dynamic_format_specs(); + begin = parse_format_specs(begin, end, specs, parse_context, arg.type()); + detail::handle_dynamic_spec( + specs.width, specs.width_ref, context); + detail::handle_dynamic_spec( + specs.precision, specs.precision_ref, context); + if (begin == end || *begin != '}') + throw_format_error("missing '}' in format string"); + auto f = arg_formatter{context.out(), specs, context.locale()}; + context.advance_to(visit_format_arg(f, arg)); + return begin; + } + }; + detail::parse_format_string(fmt, format_handler(out, fmt, args, loc)); +} + +FMT_BEGIN_EXPORT + +#ifndef FMT_HEADER_ONLY +extern template FMT_API void vformat_to(buffer&, string_view, + typename vformat_args<>::type, + locale_ref); +extern template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +extern template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +extern template FMT_API auto decimal_point_impl(locale_ref) -> char; +extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; +#endif // FMT_HEADER_ONLY + +} // namespace detail + +#if FMT_USE_USER_DEFINED_LITERALS +inline namespace literals { +/** + \rst + User-defined literal equivalent of :func:`fmt::arg`. + + **Example**:: + + using namespace fmt::literals; + fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); + \endrst + */ +# if FMT_USE_NONTYPE_TEMPLATE_ARGS +template constexpr auto operator""_a() { + using char_t = remove_cvref_t; + return detail::udl_arg(); +} +# else +constexpr auto operator""_a(const char* s, size_t) -> detail::udl_arg { + return {s}; +} +# endif +} // namespace literals +#endif // FMT_USE_USER_DEFINED_LITERALS + +template ::value)> +inline auto vformat(const Locale& loc, string_view fmt, format_args args) + -> std::string { + return detail::vformat(loc, fmt, args); +} + +template ::value)> +inline auto format(const Locale& loc, format_string fmt, T&&... args) + -> std::string { + return fmt::vformat(loc, string_view(fmt), fmt::make_format_args(args...)); +} + +template ::value&& + detail::is_locale::value)> +auto vformat_to(OutputIt out, const Locale& loc, string_view fmt, + format_args args) -> OutputIt { + using detail::get_buffer; + auto&& buf = get_buffer(out); + detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); + return detail::get_iterator(buf, out); +} + +template ::value&& + detail::is_locale::value)> +FMT_INLINE auto format_to(OutputIt out, const Locale& loc, + format_string fmt, T&&... args) -> OutputIt { + return vformat_to(out, loc, fmt, fmt::make_format_args(args...)); +} + +template ::value)> +FMT_NODISCARD FMT_INLINE auto formatted_size(const Locale& loc, + format_string fmt, + T&&... args) -> size_t { + auto buf = detail::counting_buffer<>(); + detail::vformat_to(buf, fmt, fmt::make_format_args(args...), + detail::locale_ref(loc)); + return buf.count(); +} + +FMT_END_EXPORT + +template +template +FMT_CONSTEXPR FMT_INLINE auto +formatter::value != + detail::type::custom_type>>::format(const T& val, + FormatContext& ctx) + const -> decltype(ctx.out()) { + if (specs_.width_ref.kind == detail::arg_id_kind::none && + specs_.precision_ref.kind == detail::arg_id_kind::none) { + return detail::write(ctx.out(), val, specs_, ctx.locale()); + } + auto specs = specs_; + detail::handle_dynamic_spec(specs.width, + specs.width_ref, ctx); + detail::handle_dynamic_spec( + specs.precision, specs.precision_ref, ctx); + return detail::write(ctx.out(), val, specs, ctx.locale()); +} + +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline +# include "format-inl.h" +#else +# define FMT_FUNC +#endif + +#endif // FMT_FORMAT_H_ diff --git a/dep/fmt/include/fmt/os.h b/dep/fmt/include/fmt/os.h new file mode 100644 index 00000000000..3c7b3ccb481 --- /dev/null +++ b/dep/fmt/include/fmt/os.h @@ -0,0 +1,455 @@ +// Formatting library for C++ - optional OS-specific functionality +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_OS_H_ +#define FMT_OS_H_ + +#include +#include +#include +#include // std::system_error + +#include "format.h" + +#if defined __APPLE__ || defined(__FreeBSD__) +# if FMT_HAS_INCLUDE() +# include // for LC_NUMERIC_MASK on OS X +# endif +#endif + +#ifndef FMT_USE_FCNTL +// UWP doesn't provide _pipe. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ + defined(__linux__)) && \ + (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# include // for O_RDONLY +# define FMT_USE_FCNTL 1 +# else +# define FMT_USE_FCNTL 0 +# endif +#endif + +#ifndef FMT_POSIX +# if defined(_WIN32) && !defined(__MINGW32__) +// Fix warnings about deprecated symbols. +# define FMT_POSIX(call) _##call +# else +# define FMT_POSIX(call) call +# endif +#endif + +// Calls to system functions are wrapped in FMT_SYSTEM for testability. +#ifdef FMT_SYSTEM +# define FMT_HAS_SYSTEM +# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) +#else +# define FMT_SYSTEM(call) ::call +# ifdef _WIN32 +// Fix warnings about deprecated symbols. +# define FMT_POSIX_CALL(call) ::_##call +# else +# define FMT_POSIX_CALL(call) ::call +# endif +#endif + +// Retries the expression while it evaluates to error_result and errno +// equals to EINTR. +#ifndef _WIN32 +# define FMT_RETRY_VAL(result, expression, error_result) \ + do { \ + (result) = (expression); \ + } while ((result) == (error_result) && errno == EINTR) +#else +# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) +#endif + +#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +/** + \rst + A reference to a null-terminated string. It can be constructed from a C + string or ``std::string``. + + You can use one of the following type aliases for common character types: + + +---------------+-----------------------------+ + | Type | Definition | + +===============+=============================+ + | cstring_view | basic_cstring_view | + +---------------+-----------------------------+ + | wcstring_view | basic_cstring_view | + +---------------+-----------------------------+ + + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template + std::string format(cstring_view format_str, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); + \endrst + */ +template class basic_cstring_view { + private: + const Char* data_; + + public: + /** Constructs a string reference object from a C string. */ + basic_cstring_view(const Char* s) : data_(s) {} + + /** + \rst + Constructs a string reference from an ``std::string`` object. + \endrst + */ + basic_cstring_view(const std::basic_string& s) : data_(s.c_str()) {} + + /** Returns the pointer to a C string. */ + auto c_str() const -> const Char* { return data_; } +}; + +using cstring_view = basic_cstring_view; +using wcstring_view = basic_cstring_view; + +#ifdef _WIN32 +FMT_API const std::error_category& system_category() noexcept; + +namespace detail { +FMT_API void format_windows_error(buffer& out, int error_code, + const char* message) noexcept; +} + +FMT_API std::system_error vwindows_error(int error_code, string_view format_str, + format_args args); + +/** + \rst + Constructs a :class:`std::system_error` object with the description + of the form + + .. parsed-literal:: + **: ** + + where ** is the formatted message and ** is the + system message corresponding to the error code. + *error_code* is a Windows error code as given by ``GetLastError``. + If *error_code* is not a valid error code such as -1, the system message + will look like "error -1". + + **Example**:: + + // This throws a system_error with the description + // cannot open file 'madeup': The system cannot find the file specified. + // or similar (system message may vary). + const char *filename = "madeup"; + LPOFSTRUCT of = LPOFSTRUCT(); + HFILE file = OpenFile(filename, &of, OF_READ); + if (file == HFILE_ERROR) { + throw fmt::windows_error(GetLastError(), + "cannot open file '{}'", filename); + } + \endrst +*/ +template +std::system_error windows_error(int error_code, string_view message, + const Args&... args) { + return vwindows_error(error_code, message, fmt::make_format_args(args...)); +} + +// Reports a Windows error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_windows_error(int error_code, const char* message) noexcept; +#else +inline auto system_category() noexcept -> const std::error_category& { + return std::system_category(); +} +#endif // _WIN32 + +// std::system is not available on some platforms such as iOS (#2248). +#ifdef __OSX__ +template > +void say(const S& format_str, Args&&... args) { + std::system(format("say \"{}\"", format(format_str, args...)).c_str()); +} +#endif + +// A buffered file. +class buffered_file { + private: + FILE* file_; + + friend class file; + + explicit buffered_file(FILE* f) : file_(f) {} + + public: + buffered_file(const buffered_file&) = delete; + void operator=(const buffered_file&) = delete; + + // Constructs a buffered_file object which doesn't represent any file. + buffered_file() noexcept : file_(nullptr) {} + + // Destroys the object closing the file it represents if any. + FMT_API ~buffered_file() noexcept; + + public: + buffered_file(buffered_file&& other) noexcept : file_(other.file_) { + other.file_ = nullptr; + } + + auto operator=(buffered_file&& other) -> buffered_file& { + close(); + file_ = other.file_; + other.file_ = nullptr; + return *this; + } + + // Opens a file. + FMT_API buffered_file(cstring_view filename, cstring_view mode); + + // Closes the file. + FMT_API void close(); + + // Returns the pointer to a FILE object representing this file. + auto get() const noexcept -> FILE* { return file_; } + + FMT_API auto descriptor() const -> int; + + void vprint(string_view format_str, format_args args) { + fmt::vprint(file_, format_str, args); + } + + template + inline void print(string_view format_str, const Args&... args) { + vprint(format_str, fmt::make_format_args(args...)); + } +}; + +#if FMT_USE_FCNTL +// A file. Closed file is represented by a file object with descriptor -1. +// Methods that are not declared with noexcept may throw +// fmt::system_error in case of failure. Note that some errors such as +// closing the file multiple times will cause a crash on Windows rather +// than an exception. You can get standard behavior by overriding the +// invalid parameter handler with _set_invalid_parameter_handler. +class FMT_API file { + private: + int fd_; // File descriptor. + + // Constructs a file object with a given descriptor. + explicit file(int fd) : fd_(fd) {} + + public: + // Possible values for the oflag argument to the constructor. + enum { + RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. + WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. + RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. + CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. + APPEND = FMT_POSIX(O_APPEND), // Open in append mode. + TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. + }; + + // Constructs a file object which doesn't represent any file. + file() noexcept : fd_(-1) {} + + // Opens a file and constructs a file object representing this file. + file(cstring_view path, int oflag); + + public: + file(const file&) = delete; + void operator=(const file&) = delete; + + file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } + + // Move assignment is not noexcept because close may throw. + auto operator=(file&& other) -> file& { + close(); + fd_ = other.fd_; + other.fd_ = -1; + return *this; + } + + // Destroys the object closing the file it represents if any. + ~file() noexcept; + + // Returns the file descriptor. + auto descriptor() const noexcept -> int { return fd_; } + + // Closes the file. + void close(); + + // Returns the file size. The size has signed type for consistency with + // stat::st_size. + auto size() const -> long long; + + // Attempts to read count bytes from the file into the specified buffer. + auto read(void* buffer, size_t count) -> size_t; + + // Attempts to write count bytes from the specified buffer to the file. + auto write(const void* buffer, size_t count) -> size_t; + + // Duplicates a file descriptor with the dup function and returns + // the duplicate as a file object. + static auto dup(int fd) -> file; + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + void dup2(int fd); + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + void dup2(int fd, std::error_code& ec) noexcept; + + // Creates a pipe setting up read_end and write_end file objects for reading + // and writing respectively. + // DEPRECATED! Taking files as out parameters is deprecated. + static void pipe(file& read_end, file& write_end); + + // Creates a buffered_file object associated with this file and detaches + // this file object from the file. + auto fdopen(const char* mode) -> buffered_file; + +# if defined(_WIN32) && !defined(__MINGW32__) + // Opens a file and constructs a file object representing this file by + // wcstring_view filename. Windows only. + static file open_windows_file(wcstring_view path, int oflag); +# endif +}; + +// Returns the memory page size. +auto getpagesize() -> long; + +namespace detail { + +struct buffer_size { + buffer_size() = default; + size_t value = 0; + auto operator=(size_t val) const -> buffer_size { + auto bs = buffer_size(); + bs.value = val; + return bs; + } +}; + +struct ostream_params { + int oflag = file::WRONLY | file::CREATE | file::TRUNC; + size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; + + ostream_params() {} + + template + ostream_params(T... params, int new_oflag) : ostream_params(params...) { + oflag = new_oflag; + } + + template + ostream_params(T... params, detail::buffer_size bs) + : ostream_params(params...) { + this->buffer_size = bs.value; + } + +// Intel has a bug that results in failure to deduce a constructor +// for empty parameter packs. +# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 + ostream_params(int new_oflag) : oflag(new_oflag) {} + ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} +# endif +}; + +class file_buffer final : public buffer { + file file_; + + FMT_API void grow(size_t) override; + + public: + FMT_API file_buffer(cstring_view path, const ostream_params& params); + FMT_API file_buffer(file_buffer&& other); + FMT_API ~file_buffer(); + + void flush() { + if (size() == 0) return; + file_.write(data(), size() * sizeof(data()[0])); + clear(); + } + + void close() { + flush(); + file_.close(); + } +}; + +} // namespace detail + +// Added {} below to work around default constructor error known to +// occur in Xcode versions 7.2.1 and 8.2.1. +constexpr detail::buffer_size buffer_size{}; + +/** A fast output stream which is not thread-safe. */ +class FMT_API ostream { + private: + FMT_MSC_WARNING(suppress : 4251) + detail::file_buffer buffer_; + + ostream(cstring_view path, const detail::ostream_params& params) + : buffer_(path, params) {} + + public: + ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {} + + ~ostream(); + + void flush() { buffer_.flush(); } + + template + friend auto output_file(cstring_view path, T... params) -> ostream; + + void close() { buffer_.close(); } + + /** + Formats ``args`` according to specifications in ``fmt`` and writes the + output to the file. + */ + template void print(format_string fmt, T&&... args) { + vformat_to(std::back_inserter(buffer_), fmt, + fmt::make_format_args(args...)); + } +}; + +/** + \rst + Opens a file for writing. Supported parameters passed in *params*: + + * ````: Flags passed to `open + `_ + (``file::WRONLY | file::CREATE | file::TRUNC`` by default) + * ``buffer_size=``: Output buffer size + + **Example**:: + + auto out = fmt::output_file("guide.txt"); + out.print("Don't {}", "Panic"); + \endrst + */ +template +inline auto output_file(cstring_view path, T... params) -> ostream { + return {path, detail::ostream_params(params...)}; +} +#endif // FMT_USE_FCNTL + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_OS_H_ diff --git a/dep/fmt/include/fmt/ostream.h b/dep/fmt/include/fmt/ostream.h new file mode 100644 index 00000000000..26fb3b5ac07 --- /dev/null +++ b/dep/fmt/include/fmt/ostream.h @@ -0,0 +1,245 @@ +// Formatting library for C++ - std::ostream support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_OSTREAM_H_ +#define FMT_OSTREAM_H_ + +#include // std::filebuf + +#ifdef _WIN32 +# ifdef __GLIBCXX__ +# include +# include +# endif +# include +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE +namespace detail { + +template class formatbuf : public Streambuf { + private: + using char_type = typename Streambuf::char_type; + using streamsize = decltype(std::declval().sputn(nullptr, 0)); + using int_type = typename Streambuf::int_type; + using traits_type = typename Streambuf::traits_type; + + buffer& buffer_; + + public: + explicit formatbuf(buffer& buf) : buffer_(buf) {} + + protected: + // The put area is always empty. This makes the implementation simpler and has + // the advantage that the streambuf and the buffer are always in sync and + // sputc never writes into uninitialized memory. A disadvantage is that each + // call to sputc always results in a (virtual) call to overflow. There is no + // disadvantage here for sputn since this always results in a call to xsputn. + + auto overflow(int_type ch) -> int_type override { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast(ch)); + return ch; + } + + auto xsputn(const char_type* s, streamsize count) -> streamsize override { + buffer_.append(s, s + count); + return count; + } +}; + +// Generate a unique explicit instantion in every translation unit using a tag +// type in an anonymous namespace. +namespace { +struct file_access_tag {}; +} // namespace +template +class file_access { + friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } +}; + +#if FMT_MSC_VERSION +template class file_access; +auto get_file(std::filebuf&) -> FILE*; +#endif + +inline auto write_ostream_unicode(std::ostream& os, fmt::string_view data) + -> bool { + FILE* f = nullptr; +#if FMT_MSC_VERSION + if (auto* buf = dynamic_cast(os.rdbuf())) + f = get_file(*buf); + else + return false; +#elif defined(_WIN32) && defined(__GLIBCXX__) + auto* rdbuf = os.rdbuf(); + if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) + f = sfbuf->file(); + else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) + f = fbuf->file(); + else + return false; +#else + ignore_unused(os, data, f); +#endif +#ifdef _WIN32 + if (f) { + int fd = _fileno(f); + if (_isatty(fd)) { + os.flush(); + return write_console(fd, data); + } + } +#endif + return false; +} +inline auto write_ostream_unicode(std::wostream&, + fmt::basic_string_view) -> bool { + return false; +} + +// Write the content of buf to os. +// It is a separate function rather than a part of vprint to simplify testing. +template +void write_buffer(std::basic_ostream& os, buffer& buf) { + const Char* buf_data = buf.data(); + using unsigned_streamsize = std::make_unsigned::type; + unsigned_streamsize size = buf.size(); + unsigned_streamsize max_size = to_unsigned(max_value()); + do { + unsigned_streamsize n = size <= max_size ? size : max_size; + os.write(buf_data, static_cast(n)); + buf_data += n; + size -= n; + } while (size != 0); +} + +template +void format_value(buffer& buf, const T& value) { + auto&& format_buf = formatbuf>(buf); + auto&& output = std::basic_ostream(&format_buf); +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) + output.imbue(std::locale::classic()); // The default is always unlocalized. +#endif + output << value; + output.exceptions(std::ios_base::failbit | std::ios_base::badbit); +} + +template struct streamed_view { + const T& value; +}; + +} // namespace detail + +// Formats an object of type T that has an overloaded ostream operator<<. +template +struct basic_ostream_formatter : formatter, Char> { + void set_debug_format() = delete; + + template + auto format(const T& value, basic_format_context& ctx) const + -> OutputIt { + auto buffer = basic_memory_buffer(); + detail::format_value(buffer, value); + return formatter, Char>::format( + {buffer.data(), buffer.size()}, ctx); + } +}; + +using ostream_formatter = basic_ostream_formatter; + +template +struct formatter, Char> + : basic_ostream_formatter { + template + auto format(detail::streamed_view view, + basic_format_context& ctx) const -> OutputIt { + return basic_ostream_formatter::format(view.value, ctx); + } +}; + +/** + \rst + Returns a view that formats `value` via an ostream ``operator<<``. + + **Example**:: + + fmt::print("Current thread id: {}\n", + fmt::streamed(std::this_thread::get_id())); + \endrst + */ +template +constexpr auto streamed(const T& value) -> detail::streamed_view { + return {value}; +} + +namespace detail { + +inline void vprint_directly(std::ostream& os, string_view format_str, + format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, format_str, args); + detail::write_buffer(os, buffer); +} + +} // namespace detail + +FMT_EXPORT template +void vprint(std::basic_ostream& os, + basic_string_view> format_str, + basic_format_args>> args) { + auto buffer = basic_memory_buffer(); + detail::vformat_to(buffer, format_str, args); + if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; + detail::write_buffer(os, buffer); +} + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + fmt::print(cerr, "Don't {}!", "panic"); + \endrst + */ +FMT_EXPORT template +void print(std::ostream& os, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + if (detail::is_utf8()) + vprint(os, fmt, vargs); + else + detail::vprint_directly(os, fmt, vargs); +} + +FMT_EXPORT +template +void print(std::wostream& os, + basic_format_string...> fmt, + Args&&... args) { + vprint(os, fmt, fmt::make_format_args>(args...)); +} + +FMT_EXPORT template +void println(std::ostream& os, format_string fmt, T&&... args) { + fmt::print(os, "{}\n", fmt::format(fmt, std::forward(args)...)); +} + +FMT_EXPORT +template +void println(std::wostream& os, + basic_format_string...> fmt, + Args&&... args) { + print(os, L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +FMT_END_NAMESPACE + +#endif // FMT_OSTREAM_H_ diff --git a/dep/fmt/include/fmt/printf.h b/dep/fmt/include/fmt/printf.h new file mode 100644 index 00000000000..07e81577cf3 --- /dev/null +++ b/dep/fmt/include/fmt/printf.h @@ -0,0 +1,675 @@ +// Formatting library for C++ - legacy printf implementation +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_PRINTF_H_ +#define FMT_PRINTF_H_ + +#include // std::max +#include // std::numeric_limits + +#include "format.h" + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +template struct printf_formatter { + printf_formatter() = delete; +}; + +template class basic_printf_context { + private: + detail::buffer_appender out_; + basic_format_args args_; + + static_assert(std::is_same::value || + std::is_same::value, + "Unsupported code unit type."); + + public: + using char_type = Char; + using parse_context_type = basic_format_parse_context; + template using formatter_type = printf_formatter; + + /** + \rst + Constructs a ``printf_context`` object. References to the arguments are + stored in the context object so make sure they have appropriate lifetimes. + \endrst + */ + basic_printf_context(detail::buffer_appender out, + basic_format_args args) + : out_(out), args_(args) {} + + auto out() -> detail::buffer_appender { return out_; } + void advance_to(detail::buffer_appender) {} + + auto locale() -> detail::locale_ref { return {}; } + + auto arg(int id) const -> basic_format_arg { + return args_.get(id); + } + + FMT_CONSTEXPR void on_error(const char* message) { + detail::error_handler().on_error(message); + } +}; + +namespace detail { + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template struct int_checker { + template static auto fits_in_int(T value) -> bool { + unsigned max = max_value(); + return value <= max; + } + static auto fits_in_int(bool) -> bool { return true; } +}; + +template <> struct int_checker { + template static auto fits_in_int(T value) -> bool { + return value >= (std::numeric_limits::min)() && + value <= max_value(); + } + static auto fits_in_int(int) -> bool { return true; } +}; + +struct printf_precision_handler { + template ::value)> + auto operator()(T value) -> int { + if (!int_checker::is_signed>::fits_in_int(value)) + throw_format_error("number is too big"); + return (std::max)(static_cast(value), 0); + } + + template ::value)> + auto operator()(T) -> int { + throw_format_error("precision is not integer"); + return 0; + } +}; + +// An argument visitor that returns true iff arg is a zero integer. +struct is_zero_int { + template ::value)> + auto operator()(T value) -> bool { + return value == 0; + } + + template ::value)> + auto operator()(T) -> bool { + return false; + } +}; + +template struct make_unsigned_or_bool : std::make_unsigned {}; + +template <> struct make_unsigned_or_bool { + using type = bool; +}; + +template class arg_converter { + private: + using char_type = typename Context::char_type; + + basic_format_arg& arg_; + char_type type_; + + public: + arg_converter(basic_format_arg& arg, char_type type) + : arg_(arg), type_(type) {} + + void operator()(bool value) { + if (type_ != 's') operator()(value); + } + + template ::value)> + void operator()(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + using target_type = conditional_t::value, U, T>; + if (const_check(sizeof(target_type) <= sizeof(int))) { + // Extra casts are used to silence warnings. + if (is_signed) { + auto n = static_cast(static_cast(value)); + arg_ = detail::make_arg(n); + } else { + using unsigned_type = typename make_unsigned_or_bool::type; + auto n = static_cast(static_cast(value)); + arg_ = detail::make_arg(n); + } + } else { + if (is_signed) { + // glibc's printf doesn't sign extend arguments of smaller types: + // std::printf("%lld", -42); // prints "4294967254" + // but we don't have to do the same because it's a UB. + auto n = static_cast(value); + arg_ = detail::make_arg(n); + } else { + auto n = static_cast::type>(value); + arg_ = detail::make_arg(n); + } + } + } + + template ::value)> + void operator()(U) {} // No conversion needed for non-integral types. +}; + +// Converts an integer argument to T for printf, if T is an integral type. +// If T is void, the argument is converted to corresponding signed or unsigned +// type depending on the type specifier: 'd' and 'i' - signed, other - +// unsigned). +template +void convert_arg(basic_format_arg& arg, Char type) { + visit_format_arg(arg_converter(arg, type), arg); +} + +// Converts an integer argument to char for printf. +template class char_converter { + private: + basic_format_arg& arg_; + + public: + explicit char_converter(basic_format_arg& arg) : arg_(arg) {} + + template ::value)> + void operator()(T value) { + auto c = static_cast(value); + arg_ = detail::make_arg(c); + } + + template ::value)> + void operator()(T) {} // No conversion needed for non-integral types. +}; + +// An argument visitor that return a pointer to a C string if argument is a +// string or null otherwise. +template struct get_cstring { + template auto operator()(T) -> const Char* { return nullptr; } + auto operator()(const Char* s) -> const Char* { return s; } +}; + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +template class printf_width_handler { + private: + format_specs& specs_; + + public: + explicit printf_width_handler(format_specs& specs) : specs_(specs) {} + + template ::value)> + auto operator()(T value) -> unsigned { + auto width = static_cast>(value); + if (detail::is_negative(value)) { + specs_.align = align::left; + width = 0 - width; + } + unsigned int_max = max_value(); + if (width > int_max) throw_format_error("number is too big"); + return static_cast(width); + } + + template ::value)> + auto operator()(T) -> unsigned { + throw_format_error("width is not integer"); + return 0; + } +}; + +// Workaround for a bug with the XL compiler when initializing +// printf_arg_formatter's base class. +template +auto make_arg_formatter(buffer_appender iter, format_specs& s) + -> arg_formatter { + return {iter, s, locale_ref()}; +} + +// The ``printf`` argument formatter. +template +class printf_arg_formatter : public arg_formatter { + private: + using base = arg_formatter; + using context_type = basic_printf_context; + + context_type& context_; + + void write_null_pointer(bool is_string = false) { + auto s = this->specs; + s.type = presentation_type::none; + write_bytes(this->out, is_string ? "(null)" : "(nil)", s); + } + + public: + printf_arg_formatter(buffer_appender iter, format_specs& s, + context_type& ctx) + : base(make_arg_formatter(iter, s)), context_(ctx) {} + + void operator()(monostate value) { base::operator()(value); } + + template ::value)> + void operator()(T value) { + // MSVC2013 fails to compile separate overloads for bool and Char so use + // std::is_same instead. + if (!std::is_same::value) { + base::operator()(value); + return; + } + format_specs fmt_specs = this->specs; + if (fmt_specs.type != presentation_type::none && + fmt_specs.type != presentation_type::chr) { + return (*this)(static_cast(value)); + } + fmt_specs.sign = sign::none; + fmt_specs.alt = false; + fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types. + // align::numeric needs to be overwritten here since the '0' flag is + // ignored for non-numeric types + if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) + fmt_specs.align = align::right; + write(this->out, static_cast(value), fmt_specs); + } + + template ::value)> + void operator()(T value) { + base::operator()(value); + } + + /** Formats a null-terminated C string. */ + void operator()(const char* value) { + if (value) + base::operator()(value); + else + write_null_pointer(this->specs.type != presentation_type::pointer); + } + + /** Formats a null-terminated wide C string. */ + void operator()(const wchar_t* value) { + if (value) + base::operator()(value); + else + write_null_pointer(this->specs.type != presentation_type::pointer); + } + + void operator()(basic_string_view value) { base::operator()(value); } + + /** Formats a pointer. */ + void operator()(const void* value) { + if (value) + base::operator()(value); + else + write_null_pointer(); + } + + /** Formats an argument of a custom (user-defined) type. */ + void operator()(typename basic_format_arg::handle handle) { + auto parse_ctx = basic_format_parse_context({}); + handle.format(parse_ctx, context_); + } +}; + +template +void parse_flags(format_specs& specs, const Char*& it, const Char* end) { + for (; it != end; ++it) { + switch (*it) { + case '-': + specs.align = align::left; + break; + case '+': + specs.sign = sign::plus; + break; + case '0': + specs.fill[0] = '0'; + break; + case ' ': + if (specs.sign != sign::plus) specs.sign = sign::space; + break; + case '#': + specs.alt = true; + break; + default: + return; + } + } +} + +template +auto parse_header(const Char*& it, const Char* end, format_specs& specs, + GetArg get_arg) -> int { + int arg_index = -1; + Char c = *it; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + int value = parse_nonnegative_int(it, end, -1); + if (it != end && *it == '$') { // value is an argument index + ++it; + arg_index = value != -1 ? value : max_value(); + } else { + if (c == '0') specs.fill[0] = '0'; + if (value != 0) { + // Nonzero value means that we parsed width and don't need to + // parse it or flags again, so return now. + if (value == -1) throw_format_error("number is too big"); + specs.width = value; + return arg_index; + } + } + } + parse_flags(specs, it, end); + // Parse width. + if (it != end) { + if (*it >= '0' && *it <= '9') { + specs.width = parse_nonnegative_int(it, end, -1); + if (specs.width == -1) throw_format_error("number is too big"); + } else if (*it == '*') { + ++it; + specs.width = static_cast(visit_format_arg( + detail::printf_width_handler(specs), get_arg(-1))); + } + } + return arg_index; +} + +inline auto parse_printf_presentation_type(char c, type t) + -> presentation_type { + using pt = presentation_type; + constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; + switch (c) { + case 'd': + return in(t, integral_set) ? pt::dec : pt::none; + case 'o': + return in(t, integral_set) ? pt::oct : pt::none; + case 'x': + return in(t, integral_set) ? pt::hex_lower : pt::none; + case 'X': + return in(t, integral_set) ? pt::hex_upper : pt::none; + case 'a': + return in(t, float_set) ? pt::hexfloat_lower : pt::none; + case 'A': + return in(t, float_set) ? pt::hexfloat_upper : pt::none; + case 'e': + return in(t, float_set) ? pt::exp_lower : pt::none; + case 'E': + return in(t, float_set) ? pt::exp_upper : pt::none; + case 'f': + return in(t, float_set) ? pt::fixed_lower : pt::none; + case 'F': + return in(t, float_set) ? pt::fixed_upper : pt::none; + case 'g': + return in(t, float_set) ? pt::general_lower : pt::none; + case 'G': + return in(t, float_set) ? pt::general_upper : pt::none; + case 'c': + return in(t, integral_set) ? pt::chr : pt::none; + case 's': + return in(t, string_set | cstring_set) ? pt::string : pt::none; + case 'p': + return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; + default: + return pt::none; + } +} + +template +void vprintf(buffer& buf, basic_string_view format, + basic_format_args args) { + using iterator = buffer_appender; + auto out = iterator(buf); + auto context = basic_printf_context(out, args); + auto parse_ctx = basic_format_parse_context(format); + + // Returns the argument with specified index or, if arg_index is -1, the next + // argument. + auto get_arg = [&](int arg_index) { + if (arg_index < 0) + arg_index = parse_ctx.next_arg_id(); + else + parse_ctx.check_arg_id(--arg_index); + return detail::get_arg(context, arg_index); + }; + + const Char* start = parse_ctx.begin(); + const Char* end = parse_ctx.end(); + auto it = start; + while (it != end) { + if (!find(it, end, '%', it)) { + it = end; // find leaves it == nullptr if it doesn't find '%'. + break; + } + Char c = *it++; + if (it != end && *it == c) { + write(out, basic_string_view(start, to_unsigned(it - start))); + start = ++it; + continue; + } + write(out, basic_string_view(start, to_unsigned(it - 1 - start))); + + auto specs = format_specs(); + specs.align = align::right; + + // Parse argument index, flags and width. + int arg_index = parse_header(it, end, specs, get_arg); + if (arg_index == 0) throw_format_error("argument not found"); + + // Parse precision. + if (it != end && *it == '.') { + ++it; + c = it != end ? *it : 0; + if ('0' <= c && c <= '9') { + specs.precision = parse_nonnegative_int(it, end, 0); + } else if (c == '*') { + ++it; + specs.precision = static_cast( + visit_format_arg(printf_precision_handler(), get_arg(-1))); + } else { + specs.precision = 0; + } + } + + auto arg = get_arg(arg_index); + // For d, i, o, u, x, and X conversion specifiers, if a precision is + // specified, the '0' flag is ignored + if (specs.precision >= 0 && arg.is_integral()) { + // Ignore '0' for non-numeric types or if '-' present. + specs.fill[0] = ' '; + } + if (specs.precision >= 0 && arg.type() == type::cstring_type) { + auto str = visit_format_arg(get_cstring(), arg); + auto str_end = str + specs.precision; + auto nul = std::find(str, str_end, Char()); + auto sv = basic_string_view( + str, to_unsigned(nul != str_end ? nul - str : specs.precision)); + arg = make_arg>(sv); + } + if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false; + if (specs.fill[0] == '0') { + if (arg.is_arithmetic() && specs.align != align::left) + specs.align = align::numeric; + else + specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-' + // flag is also present. + } + + // Parse length and convert the argument to the required type. + c = it != end ? *it++ : 0; + Char t = it != end ? *it : 0; + switch (c) { + case 'h': + if (t == 'h') { + ++it; + t = it != end ? *it : 0; + convert_arg(arg, t); + } else { + convert_arg(arg, t); + } + break; + case 'l': + if (t == 'l') { + ++it; + t = it != end ? *it : 0; + convert_arg(arg, t); + } else { + convert_arg(arg, t); + } + break; + case 'j': + convert_arg(arg, t); + break; + case 'z': + convert_arg(arg, t); + break; + case 't': + convert_arg(arg, t); + break; + case 'L': + // printf produces garbage when 'L' is omitted for long double, no + // need to do the same. + break; + default: + --it; + convert_arg(arg, c); + } + + // Parse type. + if (it == end) throw_format_error("invalid format string"); + char type = static_cast(*it++); + if (arg.is_integral()) { + // Normalize type. + switch (type) { + case 'i': + case 'u': + type = 'd'; + break; + case 'c': + visit_format_arg(char_converter>(arg), arg); + break; + } + } + specs.type = parse_printf_presentation_type(type, arg.type()); + if (specs.type == presentation_type::none) + throw_format_error("invalid format specifier"); + + start = it; + + // Format argument. + visit_format_arg(printf_arg_formatter(out, specs, context), arg); + } + write(out, basic_string_view(start, to_unsigned(it - start))); +} +} // namespace detail + +using printf_context = basic_printf_context; +using wprintf_context = basic_printf_context; + +using printf_args = basic_format_args; +using wprintf_args = basic_format_args; + +/** + \rst + Constructs an `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::printf_args`. + \endrst + */ +template +inline auto make_printf_args(const T&... args) + -> format_arg_store { + return {args...}; +} + +// DEPRECATED! +template +inline auto make_wprintf_args(const T&... args) + -> format_arg_store { + return {args...}; +} + +template +inline auto vsprintf( + basic_string_view fmt, + basic_format_args>> args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vprintf(buf, fmt, args); + return to_string(buf); +} + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + std::string message = fmt::sprintf("The answer is %d", 42); + \endrst +*/ +template ::value, char_t>> +inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string { + return vsprintf(detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template +inline auto vfprintf( + std::FILE* f, basic_string_view fmt, + basic_format_args>> args) + -> int { + auto buf = basic_memory_buffer(); + detail::vprintf(buf, fmt, args); + size_t size = buf.size(); + return std::fwrite(buf.data(), sizeof(Char), size, f) < size + ? -1 + : static_cast(size); +} + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + fmt::fprintf(stderr, "Don't %s!", "panic"); + \endrst + */ +template > +inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { + return vfprintf(f, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template +FMT_DEPRECATED inline auto vprintf( + basic_string_view fmt, + basic_format_args>> args) + -> int { + return vfprintf(stdout, fmt, args); +} + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + fmt::printf("Elapsed time: %.2f seconds", 1.23); + \endrst + */ +template +inline auto printf(string_view fmt, const T&... args) -> int { + return vfprintf(stdout, fmt, make_printf_args(args...)); +} +template +FMT_DEPRECATED inline auto printf(basic_string_view fmt, + const T&... args) -> int { + return vfprintf(stdout, fmt, make_wprintf_args(args...)); +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_PRINTF_H_ diff --git a/dep/fmt/include/fmt/ranges.h b/dep/fmt/include/fmt/ranges.h new file mode 100644 index 00000000000..3638fffb83b --- /dev/null +++ b/dep/fmt/include/fmt/ranges.h @@ -0,0 +1,738 @@ +// Formatting library for C++ - range and tuple support +// +// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_RANGES_H_ +#define FMT_RANGES_H_ + +#include +#include +#include + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +namespace detail { + +template +auto copy(const Range& range, OutputIt out) -> OutputIt { + for (auto it = range.begin(), end = range.end(); it != end; ++it) + *out++ = *it; + return out; +} + +template +auto copy(const char* str, OutputIt out) -> OutputIt { + while (*str) *out++ = *str++; + return out; +} + +template auto copy(char ch, OutputIt out) -> OutputIt { + *out++ = ch; + return out; +} + +template auto copy(wchar_t ch, OutputIt out) -> OutputIt { + *out++ = ch; + return out; +} + +// Returns true if T has a std::string-like interface, like std::string_view. +template class is_std_string_like { + template + static auto check(U* p) + -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); + template static void check(...); + + public: + static constexpr const bool value = + is_string::value || + std::is_convertible>::value || + !std::is_void(nullptr))>::value; +}; + +template +struct is_std_string_like> : std::true_type {}; + +template class is_map { + template static auto check(U*) -> typename U::mapped_type; + template static void check(...); + + public: +#ifdef FMT_FORMAT_MAP_AS_LIST // DEPRECATED! + static constexpr const bool value = false; +#else + static constexpr const bool value = + !std::is_void(nullptr))>::value; +#endif +}; + +template class is_set { + template static auto check(U*) -> typename U::key_type; + template static void check(...); + + public: +#ifdef FMT_FORMAT_SET_AS_LIST // DEPRECATED! + static constexpr const bool value = false; +#else + static constexpr const bool value = + !std::is_void(nullptr))>::value && !is_map::value; +#endif +}; + +template struct conditional_helper {}; + +template struct is_range_ : std::false_type {}; + +#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800 + +# define FMT_DECLTYPE_RETURN(val) \ + ->decltype(val) { return val; } \ + static_assert( \ + true, "") // This makes it so that a semicolon is required after the + // macro, which helps clang-format handle the formatting. + +// C array overload +template +auto range_begin(const T (&arr)[N]) -> const T* { + return arr; +} +template +auto range_end(const T (&arr)[N]) -> const T* { + return arr + N; +} + +template +struct has_member_fn_begin_end_t : std::false_type {}; + +template +struct has_member_fn_begin_end_t().begin()), + decltype(std::declval().end())>> + : std::true_type {}; + +// Member function overload +template +auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast(rng).begin()); +template +auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast(rng).end()); + +// ADL overload. Only participates in overload resolution if member functions +// are not found. +template +auto range_begin(T&& rng) + -> enable_if_t::value, + decltype(begin(static_cast(rng)))> { + return begin(static_cast(rng)); +} +template +auto range_end(T&& rng) -> enable_if_t::value, + decltype(end(static_cast(rng)))> { + return end(static_cast(rng)); +} + +template +struct has_const_begin_end : std::false_type {}; +template +struct has_mutable_begin_end : std::false_type {}; + +template +struct has_const_begin_end< + T, + void_t< + decltype(detail::range_begin(std::declval&>())), + decltype(detail::range_end(std::declval&>()))>> + : std::true_type {}; + +template +struct has_mutable_begin_end< + T, void_t())), + decltype(detail::range_end(std::declval())), + // the extra int here is because older versions of MSVC don't + // SFINAE properly unless there are distinct types + int>> : std::true_type {}; + +template +struct is_range_ + : std::integral_constant::value || + has_mutable_begin_end::value)> {}; +# undef FMT_DECLTYPE_RETURN +#endif + +// tuple_size and tuple_element check. +template class is_tuple_like_ { + template + static auto check(U* p) -> decltype(std::tuple_size::value, int()); + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value; +}; + +// Check for integer_sequence +#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 +template +using integer_sequence = std::integer_sequence; +template using index_sequence = std::index_sequence; +template using make_index_sequence = std::make_index_sequence; +#else +template struct integer_sequence { + using value_type = T; + + static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); } +}; + +template using index_sequence = integer_sequence; + +template +struct make_integer_sequence : make_integer_sequence {}; +template +struct make_integer_sequence : integer_sequence {}; + +template +using make_index_sequence = make_integer_sequence; +#endif + +template +using tuple_index_sequence = make_index_sequence::value>; + +template ::value> +class is_tuple_formattable_ { + public: + static constexpr const bool value = false; +}; +template class is_tuple_formattable_ { + template + static auto check2(index_sequence, + integer_sequence) -> std::true_type; + static auto check2(...) -> std::false_type; + template + static auto check(index_sequence) -> decltype(check2( + index_sequence{}, + integer_sequence::type, + C>::value)...>{})); + + public: + static constexpr const bool value = + decltype(check(tuple_index_sequence{}))::value; +}; + +template +FMT_CONSTEXPR void for_each(index_sequence, Tuple&& t, F&& f) { + using std::get; + // Using a free function get(Tuple) now. + const int unused[] = {0, ((void)f(get(t)), 0)...}; + ignore_unused(unused); +} + +template +FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) { + for_each(tuple_index_sequence>(), + std::forward(t), std::forward(f)); +} + +template +void for_each2(index_sequence, Tuple1&& t1, Tuple2&& t2, F&& f) { + using std::get; + const int unused[] = {0, ((void)f(get(t1), get(t2)), 0)...}; + ignore_unused(unused); +} + +template +void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) { + for_each2(tuple_index_sequence>(), + std::forward(t1), std::forward(t2), + std::forward(f)); +} + +namespace tuple { +// Workaround a bug in MSVC 2019 (v140). +template +using result_t = std::tuple, Char>...>; + +using std::get; +template +auto get_formatters(index_sequence) + -> result_t(std::declval()))...>; +} // namespace tuple + +#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920 +// Older MSVC doesn't get the reference type correctly for arrays. +template struct range_reference_type_impl { + using type = decltype(*detail::range_begin(std::declval())); +}; + +template struct range_reference_type_impl { + using type = T&; +}; + +template +using range_reference_type = typename range_reference_type_impl::type; +#else +template +using range_reference_type = + decltype(*detail::range_begin(std::declval())); +#endif + +// We don't use the Range's value_type for anything, but we do need the Range's +// reference type, with cv-ref stripped. +template +using uncvref_type = remove_cvref_t>; + +template +FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) + -> decltype(f.set_debug_format(set)) { + f.set_debug_format(set); +} +template +FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} + +// These are not generic lambdas for compatibility with C++11. +template struct parse_empty_specs { + template FMT_CONSTEXPR void operator()(Formatter& f) { + f.parse(ctx); + detail::maybe_set_debug_format(f, true); + } + ParseContext& ctx; +}; +template struct format_tuple_element { + using char_type = typename FormatContext::char_type; + + template + void operator()(const formatter& f, const T& v) { + if (i > 0) + ctx.advance_to(detail::copy_str(separator, ctx.out())); + ctx.advance_to(f.format(v, ctx)); + ++i; + } + + int i; + FormatContext& ctx; + basic_string_view separator; +}; + +} // namespace detail + +template struct is_tuple_like { + static constexpr const bool value = + detail::is_tuple_like_::value && !detail::is_range_::value; +}; + +template struct is_tuple_formattable { + static constexpr const bool value = + detail::is_tuple_formattable_::value; +}; + +template +struct formatter::value && + fmt::is_tuple_formattable::value>> { + private: + decltype(detail::tuple::get_formatters( + detail::tuple_index_sequence())) formatters_; + + basic_string_view separator_ = detail::string_literal{}; + basic_string_view opening_bracket_ = + detail::string_literal{}; + basic_string_view closing_bracket_ = + detail::string_literal{}; + + public: + FMT_CONSTEXPR formatter() {} + + FMT_CONSTEXPR void set_separator(basic_string_view sep) { + separator_ = sep; + } + + FMT_CONSTEXPR void set_brackets(basic_string_view open, + basic_string_view close) { + opening_bracket_ = open; + closing_bracket_ = close; + } + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + if (it != ctx.end() && *it != '}') + FMT_THROW(format_error("invalid format specifier")); + detail::for_each(formatters_, detail::parse_empty_specs{ctx}); + return it; + } + + template + auto format(const Tuple& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + ctx.advance_to(detail::copy_str(opening_bracket_, ctx.out())); + detail::for_each2( + formatters_, value, + detail::format_tuple_element{0, ctx, separator_}); + return detail::copy_str(closing_bracket_, ctx.out()); + } +}; + +template struct is_range { + static constexpr const bool value = + detail::is_range_::value && !detail::is_std_string_like::value && + !std::is_convertible>::value && + !std::is_convertible>::value; +}; + +namespace detail { +template struct range_mapper { + using mapper = arg_mapper; + + template , Context>::value)> + static auto map(T&& value) -> T&& { + return static_cast(value); + } + template , Context>::value)> + static auto map(T&& value) + -> decltype(mapper().map(static_cast(value))) { + return mapper().map(static_cast(value)); + } +}; + +template +using range_formatter_type = + formatter>{}.map( + std::declval()))>, + Char>; + +template +using maybe_const_range = + conditional_t::value, const R, R>; + +// Workaround a bug in MSVC 2015 and earlier. +#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 +template +struct is_formattable_delayed + : is_formattable>, Char> {}; +#endif +} // namespace detail + +template struct conjunction : std::true_type {}; +template struct conjunction

: P {}; +template +struct conjunction + : conditional_t, P1> {}; + +template +struct range_formatter; + +template +struct range_formatter< + T, Char, + enable_if_t>, + is_formattable>::value>> { + private: + detail::range_formatter_type underlying_; + basic_string_view separator_ = detail::string_literal{}; + basic_string_view opening_bracket_ = + detail::string_literal{}; + basic_string_view closing_bracket_ = + detail::string_literal{}; + + public: + FMT_CONSTEXPR range_formatter() {} + + FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type& { + return underlying_; + } + + FMT_CONSTEXPR void set_separator(basic_string_view sep) { + separator_ = sep; + } + + FMT_CONSTEXPR void set_brackets(basic_string_view open, + basic_string_view close) { + opening_bracket_ = open; + closing_bracket_ = close; + } + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + auto end = ctx.end(); + + if (it != end && *it == 'n') { + set_brackets({}, {}); + ++it; + } + + if (it != end && *it != '}') { + if (*it != ':') FMT_THROW(format_error("invalid format specifier")); + ++it; + } else { + detail::maybe_set_debug_format(underlying_, true); + } + + ctx.advance_to(it); + return underlying_.parse(ctx); + } + + template + auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { + detail::range_mapper> mapper; + auto out = ctx.out(); + out = detail::copy_str(opening_bracket_, out); + int i = 0; + auto it = detail::range_begin(range); + auto end = detail::range_end(range); + for (; it != end; ++it) { + if (i > 0) out = detail::copy_str(separator_, out); + ctx.advance_to(out); + auto&& item = *it; + out = underlying_.format(mapper.map(item), ctx); + ++i; + } + out = detail::copy_str(closing_bracket_, out); + return out; + } +}; + +enum class range_format { disabled, map, set, sequence, string, debug_string }; + +namespace detail { +template +struct range_format_kind_ + : std::integral_constant, T>::value + ? range_format::disabled + : is_map::value ? range_format::map + : is_set::value ? range_format::set + : range_format::sequence> {}; + +template +struct range_default_formatter; + +template +using range_format_constant = std::integral_constant; + +template +struct range_default_formatter< + K, R, Char, + enable_if_t<(K == range_format::sequence || K == range_format::map || + K == range_format::set)>> { + using range_type = detail::maybe_const_range; + range_formatter, Char> underlying_; + + FMT_CONSTEXPR range_default_formatter() { init(range_format_constant()); } + + FMT_CONSTEXPR void init(range_format_constant) { + underlying_.set_brackets(detail::string_literal{}, + detail::string_literal{}); + } + + FMT_CONSTEXPR void init(range_format_constant) { + underlying_.set_brackets(detail::string_literal{}, + detail::string_literal{}); + underlying_.underlying().set_brackets({}, {}); + underlying_.underlying().set_separator( + detail::string_literal{}); + } + + FMT_CONSTEXPR void init(range_format_constant) {} + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return underlying_.parse(ctx); + } + + template + auto format(range_type& range, FormatContext& ctx) const + -> decltype(ctx.out()) { + return underlying_.format(range, ctx); + } +}; +} // namespace detail + +template +struct range_format_kind + : conditional_t< + is_range::value, detail::range_format_kind_, + std::integral_constant> {}; + +template +struct formatter< + R, Char, + enable_if_t::value != + range_format::disabled> +// Workaround a bug in MSVC 2015 and earlier. +#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 + , + detail::is_formattable_delayed +#endif + >::value>> + : detail::range_default_formatter::value, R, + Char> { +}; + +template struct tuple_join_view : detail::view { + const std::tuple& tuple; + basic_string_view sep; + + tuple_join_view(const std::tuple& t, basic_string_view s) + : tuple(t), sep{s} {} +}; + +// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers +// support in tuple_join. It is disabled by default because of issues with +// the dynamic width and precision. +#ifndef FMT_TUPLE_JOIN_SPECIFIERS +# define FMT_TUPLE_JOIN_SPECIFIERS 0 +#endif + +template +struct formatter, Char> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return do_parse(ctx, std::integral_constant()); + } + + template + auto format(const tuple_join_view& value, + FormatContext& ctx) const -> typename FormatContext::iterator { + return do_format(value, ctx, + std::integral_constant()); + } + + private: + std::tuple::type, Char>...> formatters_; + + template + FMT_CONSTEXPR auto do_parse(ParseContext& ctx, + std::integral_constant) + -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + FMT_CONSTEXPR auto do_parse(ParseContext& ctx, + std::integral_constant) + -> decltype(ctx.begin()) { + auto end = ctx.begin(); +#if FMT_TUPLE_JOIN_SPECIFIERS + end = std::get(formatters_).parse(ctx); + if (N > 1) { + auto end1 = do_parse(ctx, std::integral_constant()); + if (end != end1) + FMT_THROW(format_error("incompatible format specs for tuple elements")); + } +#endif + return end; + } + + template + auto do_format(const tuple_join_view&, FormatContext& ctx, + std::integral_constant) const -> + typename FormatContext::iterator { + return ctx.out(); + } + + template + auto do_format(const tuple_join_view& value, FormatContext& ctx, + std::integral_constant) const -> + typename FormatContext::iterator { + auto out = std::get(formatters_) + .format(std::get(value.tuple), ctx); + if (N > 1) { + out = std::copy(value.sep.begin(), value.sep.end(), out); + ctx.advance_to(out); + return do_format(value, ctx, std::integral_constant()); + } + return out; + } +}; + +namespace detail { +// Check if T has an interface like a container adaptor (e.g. std::stack, +// std::queue, std::priority_queue). +template class is_container_adaptor_like { + template static auto check(U* p) -> typename U::container_type; + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value; +}; + +template struct all { + const Container& c; + auto begin() const -> typename Container::const_iterator { return c.begin(); } + auto end() const -> typename Container::const_iterator { return c.end(); } +}; +} // namespace detail + +template +struct formatter< + T, Char, + enable_if_t, + bool_constant::value == + range_format::disabled>>::value>> + : formatter, Char> { + using all = detail::all; + template + auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) { + struct getter : T { + static auto get(const T& t) -> all { + return {t.*(&getter::c)}; // Access c through the derived class. + } + }; + return formatter::format(getter::get(t), ctx); + } +}; + +FMT_BEGIN_EXPORT + +/** + \rst + Returns an object that formats `tuple` with elements separated by `sep`. + + **Example**:: + + std::tuple t = {1, 'a'}; + fmt::print("{}", fmt::join(t, ", ")); + // Output: "1, a" + \endrst + */ +template +FMT_CONSTEXPR auto join(const std::tuple& tuple, string_view sep) + -> tuple_join_view { + return {tuple, sep}; +} + +template +FMT_CONSTEXPR auto join(const std::tuple& tuple, + basic_string_view sep) + -> tuple_join_view { + return {tuple, sep}; +} + +/** + \rst + Returns an object that formats `initializer_list` with elements separated by + `sep`. + + **Example**:: + + fmt::print("{}", fmt::join({1, 2, 3}, ", ")); + // Output: "1, 2, 3" + \endrst + */ +template +auto join(std::initializer_list list, string_view sep) + -> join_view { + return join(std::begin(list), std::end(list), sep); +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_RANGES_H_ diff --git a/dep/fmt/include/fmt/std.h b/dep/fmt/include/fmt/std.h new file mode 100644 index 00000000000..7cff1159201 --- /dev/null +++ b/dep/fmt/include/fmt/std.h @@ -0,0 +1,537 @@ +// Formatting library for C++ - formatters for standard library types +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_STD_H_ +#define FMT_STD_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "format.h" +#include "ostream.h" + +#if FMT_HAS_INCLUDE() +# include +#endif +// Checking FMT_CPLUSPLUS for warning suppression in MSVC. +#if FMT_CPLUSPLUS >= 201703L +# if FMT_HAS_INCLUDE() +# include +# endif +# if FMT_HAS_INCLUDE() +# include +# endif +# if FMT_HAS_INCLUDE() +# include +# endif +#endif + +#if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE() +# include +#endif + +// GCC 4 does not support FMT_HAS_INCLUDE. +#if FMT_HAS_INCLUDE() || defined(__GLIBCXX__) +# include +// Android NDK with gabi++ library on some architectures does not implement +// abi::__cxa_demangle(). +# ifndef __GABIXX_CXXABI_H__ +# define FMT_HAS_ABI_CXA_DEMANGLE +# endif +#endif + +// Check if typeid is available. +#ifndef FMT_USE_TYPEID +// __RTTI is for EDG compilers. In MSVC typeid is available without RTTI. +# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \ + defined(__INTEL_RTTI__) || defined(__RTTI) +# define FMT_USE_TYPEID 1 +# else +# define FMT_USE_TYPEID 0 +# endif +#endif + +// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined. +#ifndef FMT_CPP_LIB_FILESYSTEM +# ifdef __cpp_lib_filesystem +# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem +# else +# define FMT_CPP_LIB_FILESYSTEM 0 +# endif +#endif + +#ifndef FMT_CPP_LIB_VARIANT +# ifdef __cpp_lib_variant +# define FMT_CPP_LIB_VARIANT __cpp_lib_variant +# else +# define FMT_CPP_LIB_VARIANT 0 +# endif +#endif + +#if FMT_CPP_LIB_FILESYSTEM +FMT_BEGIN_NAMESPACE + +namespace detail { + +template +auto get_path_string(const std::filesystem::path& p, + const std::basic_string& native) { + if constexpr (std::is_same_v && std::is_same_v) + return to_utf8(native, to_utf8_error_policy::replace); + else + return p.string(); +} + +template +void write_escaped_path(basic_memory_buffer& quoted, + const std::filesystem::path& p, + const std::basic_string& native) { + if constexpr (std::is_same_v && + std::is_same_v) { + auto buf = basic_memory_buffer(); + write_escaped_string(std::back_inserter(buf), native); + bool valid = to_utf8::convert(quoted, {buf.data(), buf.size()}); + FMT_ASSERT(valid, "invalid utf16"); + } else if constexpr (std::is_same_v) { + write_escaped_string( + std::back_inserter(quoted), native); + } else { + write_escaped_string(std::back_inserter(quoted), p.string()); + } +} + +} // namespace detail + +FMT_EXPORT +template struct formatter { + private: + format_specs specs_; + detail::arg_ref width_ref_; + bool debug_ = false; + char path_type_ = 0; + + public: + FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } + + template FMT_CONSTEXPR auto parse(ParseContext& ctx) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end) return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it != end && *it == '?') { + debug_ = true; + ++it; + } + if (it != end && (*it == 'g')) path_type_ = *it++; + return it; + } + + template + auto format(const std::filesystem::path& p, FormatContext& ctx) const { + auto specs = specs_; +# ifdef _WIN32 + auto path_string = !path_type_ ? p.native() : p.generic_wstring(); +# else + auto path_string = !path_type_ ? p.native() : p.generic_string(); +# endif + + detail::handle_dynamic_spec(specs.width, width_ref_, + ctx); + if (!debug_) { + auto s = detail::get_path_string(p, path_string); + return detail::write(ctx.out(), basic_string_view(s), specs); + } + auto quoted = basic_memory_buffer(); + detail::write_escaped_path(quoted, p, path_string); + return detail::write(ctx.out(), + basic_string_view(quoted.data(), quoted.size()), + specs); + } +}; +FMT_END_NAMESPACE +#endif // FMT_CPP_LIB_FILESYSTEM + +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template +struct formatter, Char> : nested_formatter { + private: + // Functor because C++11 doesn't support generic lambdas. + struct writer { + const std::bitset& bs; + + template + FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { + for (auto pos = N; pos > 0; --pos) { + out = detail::write(out, bs[pos - 1] ? Char('1') : Char('0')); + } + + return out; + } + }; + + public: + template + auto format(const std::bitset& bs, FormatContext& ctx) const + -> decltype(ctx.out()) { + return write_padded(ctx, writer{bs}); + } +}; + +FMT_EXPORT +template +struct formatter : basic_ostream_formatter {}; +FMT_END_NAMESPACE + +#ifdef __cpp_lib_optional +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template +struct formatter, Char, + std::enable_if_t::value>> { + private: + formatter underlying_; + static constexpr basic_string_view optional = + detail::string_literal{}; + static constexpr basic_string_view none = + detail::string_literal{}; + + template + FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) + -> decltype(u.set_debug_format(set)) { + u.set_debug_format(set); + } + + template + FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} + + public: + template FMT_CONSTEXPR auto parse(ParseContext& ctx) { + maybe_set_debug_format(underlying_, true); + return underlying_.parse(ctx); + } + + template + auto format(const std::optional& opt, FormatContext& ctx) const + -> decltype(ctx.out()) { + if (!opt) return detail::write(ctx.out(), none); + + auto out = ctx.out(); + out = detail::write(out, optional); + ctx.advance_to(out); + out = underlying_.format(*opt, ctx); + return detail::write(out, ')'); + } +}; +FMT_END_NAMESPACE +#endif // __cpp_lib_optional + +#ifdef __cpp_lib_source_location +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template <> struct formatter { + template FMT_CONSTEXPR auto parse(ParseContext& ctx) { + return ctx.begin(); + } + + template + auto format(const std::source_location& loc, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + out = detail::write(out, loc.file_name()); + out = detail::write(out, ':'); + out = detail::write(out, loc.line()); + out = detail::write(out, ':'); + out = detail::write(out, loc.column()); + out = detail::write(out, ": "); + out = detail::write(out, loc.function_name()); + return out; + } +}; +FMT_END_NAMESPACE +#endif + +#if FMT_CPP_LIB_VARIANT +FMT_BEGIN_NAMESPACE +namespace detail { + +template +using variant_index_sequence = + std::make_index_sequence::value>; + +template struct is_variant_like_ : std::false_type {}; +template +struct is_variant_like_> : std::true_type {}; + +// formattable element check. +template class is_variant_formattable_ { + template + static std::conjunction< + is_formattable, C>...> + check(std::index_sequence); + + public: + static constexpr const bool value = + decltype(check(variant_index_sequence{}))::value; +}; + +template +auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { + if constexpr (is_string::value) + return write_escaped_string(out, detail::to_string_view(v)); + else if constexpr (std::is_same_v) + return write_escaped_char(out, v); + else + return write(out, v); +} + +} // namespace detail + +template struct is_variant_like { + static constexpr const bool value = detail::is_variant_like_::value; +}; + +template struct is_variant_formattable { + static constexpr const bool value = + detail::is_variant_formattable_::value; +}; + +FMT_EXPORT +template struct formatter { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const std::monostate&, FormatContext& ctx) const + -> decltype(ctx.out()) { + return detail::write(ctx.out(), "monostate"); + } +}; + +FMT_EXPORT +template +struct formatter< + Variant, Char, + std::enable_if_t, is_variant_formattable>>> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const Variant& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + + out = detail::write(out, "variant("); + FMT_TRY { + std::visit( + [&](const auto& v) { + out = detail::write_variant_alternative(out, v); + }, + value); + } + FMT_CATCH(const std::bad_variant_access&) { + detail::write(out, "valueless by exception"); + } + *out++ = ')'; + return out; + } +}; +FMT_END_NAMESPACE +#endif // FMT_CPP_LIB_VARIANT + +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template struct formatter { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + out = detail::write_bytes(out, ec.category().name(), format_specs()); + out = detail::write(out, Char(':')); + out = detail::write(out, ec.value()); + return out; + } +}; + +FMT_EXPORT +template +struct formatter< + T, Char, // DEPRECATED! Mixing code unit types. + typename std::enable_if::value>::type> { + private: + bool with_typename_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(); + auto end = ctx.end(); + if (it == end || *it == '}') return it; + if (*it == 't') { + ++it; + with_typename_ = FMT_USE_TYPEID != 0; + } + return it; + } + + template + auto format(const std::exception& ex, + basic_format_context& ctx) const -> OutputIt { + format_specs spec; + auto out = ctx.out(); + if (!with_typename_) + return detail::write_bytes(out, string_view(ex.what()), spec); + +#if FMT_USE_TYPEID + const std::type_info& ti = typeid(ex); +# ifdef FMT_HAS_ABI_CXA_DEMANGLE + int status = 0; + std::size_t size = 0; + std::unique_ptr demangled_name_ptr( + abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); + + string_view demangled_name_view; + if (demangled_name_ptr) { + demangled_name_view = demangled_name_ptr.get(); + + // Normalization of stdlib inline namespace names. + // libc++ inline namespaces. + // std::__1::* -> std::* + // std::__1::__fs::* -> std::* + // libstdc++ inline namespaces. + // std::__cxx11::* -> std::* + // std::filesystem::__cxx11::* -> std::filesystem::* + if (demangled_name_view.starts_with("std::")) { + char* begin = demangled_name_ptr.get(); + char* to = begin + 5; // std:: + for (char *from = to, *end = begin + demangled_name_view.size(); + from < end;) { + // This is safe, because demangled_name is NUL-terminated. + if (from[0] == '_' && from[1] == '_') { + char* next = from + 1; + while (next < end && *next != ':') next++; + if (next[0] == ':' && next[1] == ':') { + from = next + 2; + continue; + } + } + *to++ = *from++; + } + demangled_name_view = {begin, detail::to_unsigned(to - begin)}; + } + } else { + demangled_name_view = string_view(ti.name()); + } + out = detail::write_bytes(out, demangled_name_view, spec); +# elif FMT_MSC_VERSION + string_view demangled_name_view(ti.name()); + if (demangled_name_view.starts_with("class ")) + demangled_name_view.remove_prefix(6); + else if (demangled_name_view.starts_with("struct ")) + demangled_name_view.remove_prefix(7); + out = detail::write_bytes(out, demangled_name_view, spec); +# else + out = detail::write_bytes(out, string_view(ti.name()), spec); +# endif + *out++ = ':'; + *out++ = ' '; + return detail::write_bytes(out, string_view(ex.what()), spec); +#endif + } +}; + +namespace detail { + +template +struct has_flip : std::false_type {}; + +template +struct has_flip().flip())>> + : std::true_type {}; + +template struct is_bit_reference_like { + static constexpr const bool value = + std::is_convertible::value && + std::is_nothrow_assignable::value && has_flip::value; +}; + +#ifdef _LIBCPP_VERSION + +// Workaround for libc++ incompatibility with C++ standard. +// According to the Standard, `bitset::operator[] const` returns bool. +template +struct is_bit_reference_like> { + static constexpr const bool value = true; +}; + +#endif + +} // namespace detail + +// We can't use std::vector::reference and +// std::bitset::reference because the compiler can't deduce Allocator and N +// in partial specialization. +FMT_EXPORT +template +struct formatter::value>> + : formatter { + template + FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v, ctx); + } +}; + +FMT_EXPORT +template +struct formatter, Char, + enable_if_t::value>> + : formatter { + template + auto format(const std::atomic& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v.load(), ctx); + } +}; + +#ifdef __cpp_lib_atomic_flag_test +FMT_EXPORT +template +struct formatter : formatter { + template + auto format(const std::atomic_flag& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v.test(), ctx); + } +}; +#endif // __cpp_lib_atomic_flag_test + +FMT_END_NAMESPACE +#endif // FMT_STD_H_ diff --git a/dep/fmt/include/fmt/xchar.h b/dep/fmt/include/fmt/xchar.h new file mode 100644 index 00000000000..f609c5c41a2 --- /dev/null +++ b/dep/fmt/include/fmt/xchar.h @@ -0,0 +1,259 @@ +// Formatting library for C++ - optional wchar_t and exotic character support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_XCHAR_H_ +#define FMT_XCHAR_H_ + +#include + +#include "format.h" + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +# include +#endif + +FMT_BEGIN_NAMESPACE +namespace detail { + +template +using is_exotic_char = bool_constant::value>; + +inline auto write_loc(std::back_insert_iterator> out, + loc_value value, const format_specs& specs, + locale_ref loc) -> bool { +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR + auto& numpunct = + std::use_facet>(loc.get()); + auto separator = std::wstring(); + auto grouping = numpunct.grouping(); + if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); + return value.visit(loc_writer{out, specs, separator, grouping, {}}); +#endif + return false; +} +} // namespace detail + +FMT_BEGIN_EXPORT + +using wstring_view = basic_string_view; +using wformat_parse_context = basic_format_parse_context; +using wformat_context = buffer_context; +using wformat_args = basic_format_args; +using wmemory_buffer = basic_memory_buffer; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +// Workaround broken conversion on older gcc. +template using wformat_string = wstring_view; +inline auto runtime(wstring_view s) -> wstring_view { return s; } +#else +template +using wformat_string = basic_format_string...>; +inline auto runtime(wstring_view s) -> runtime_format_string { + return {{s}}; +} +#endif + +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; + +template +constexpr auto make_wformat_args(const T&... args) + -> format_arg_store { + return {args...}; +} + +inline namespace literals { +#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS +constexpr auto operator""_a(const wchar_t* s, size_t) + -> detail::udl_arg { + return {s}; +} +#endif +} // namespace literals + +template +auto join(It begin, Sentinel end, wstring_view sep) + -> join_view { + return {begin, end, sep}; +} + +template +auto join(Range&& range, wstring_view sep) + -> join_view, detail::sentinel_t, + wchar_t> { + return join(std::begin(range), std::end(range), sep); +} + +template +auto join(std::initializer_list list, wstring_view sep) + -> join_view { + return join(std::begin(list), std::end(list), sep); +} + +template ::value)> +auto vformat(basic_string_view format_str, + basic_format_args>> args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vformat_to(buf, format_str, args); + return to_string(buf); +} + +template +auto format(wformat_string fmt, T&&... args) -> std::wstring { + return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +// Pass char_t as a default template parameter instead of using +// std::basic_string> to reduce the symbol size. +template , + FMT_ENABLE_IF(!std::is_same::value && + !std::is_same::value)> +auto format(const S& format_str, T&&... args) -> std::basic_string { + return vformat(detail::to_string_view(format_str), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto vformat( + const Locale& loc, const S& format_str, + basic_format_args>> args) + -> std::basic_string { + return detail::vformat(loc, detail::to_string_view(format_str), args); +} + +template , + FMT_ENABLE_IF(detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto format(const Locale& loc, const S& format_str, T&&... args) + -> std::basic_string { + return detail::vformat(loc, detail::to_string_view(format_str), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_exotic_char::value)> +auto vformat_to(OutputIt out, const S& format_str, + basic_format_args>> args) + -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, detail::to_string_view(format_str), args); + return detail::get_iterator(buf, out); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_exotic_char::value)> +inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { + return vformat_to(out, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto vformat_to( + OutputIt out, const Locale& loc, const S& format_str, + basic_format_args>> args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + vformat_to(buf, detail::to_string_view(format_str), args, + detail::locale_ref(loc)); + return detail::get_iterator(buf, out); +} + +template , + bool enable = detail::is_output_iterator::value && + detail::is_locale::value && + detail::is_exotic_char::value> +inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, + T&&... args) -> + typename std::enable_if::type { + return vformat_to(out, loc, detail::to_string_view(format_str), + fmt::make_format_args>(args...)); +} + +template ::value&& + detail::is_exotic_char::value)> +inline auto vformat_to_n( + OutputIt out, size_t n, basic_string_view format_str, + basic_format_args>> args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + detail::vformat_to(buf, format_str, args); + return {buf.out(), buf.count()}; +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_exotic_char::value)> +inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) + -> format_to_n_result { + return vformat_to_n(out, n, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_exotic_char::value)> +inline auto formatted_size(const S& fmt, T&&... args) -> size_t { + auto buf = detail::counting_buffer(); + detail::vformat_to(buf, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); + return buf.count(); +} + +inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { + auto buf = wmemory_buffer(); + detail::vformat_to(buf, fmt, args); + buf.push_back(L'\0'); + if (std::fputws(buf.data(), f) == -1) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); +} + +inline void vprint(wstring_view fmt, wformat_args args) { + vprint(stdout, fmt, args); +} + +template +void print(std::FILE* f, wformat_string fmt, T&&... args) { + return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +template void print(wformat_string fmt, T&&... args) { + return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +template +void println(std::FILE* f, wformat_string fmt, T&&... args) { + return print(f, L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +template void println(wformat_string fmt, T&&... args) { + return print(L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +/** + Converts *value* to ``std::wstring`` using the default format for type *T*. + */ +template inline auto to_wstring(const T& value) -> std::wstring { + return format(FMT_STRING(L"{}"), value); +} +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_XCHAR_H_ diff --git a/dep/fmt/src/fmt.cc b/dep/fmt/src/fmt.cc new file mode 100644 index 00000000000..5330463a932 --- /dev/null +++ b/dep/fmt/src/fmt.cc @@ -0,0 +1,108 @@ +module; + +// Put all implementation-provided headers into the global module fragment +// to prevent attachment to this module. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __has_include() +# include +#endif +#if defined(_MSC_VER) || defined(__MINGW32__) +# include +#endif +#if defined __APPLE__ || defined(__FreeBSD__) +# include +#endif +#if __has_include() +# include +#endif +#if (__has_include() || defined(__APPLE__) || \ + defined(__linux__)) && \ + (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# include +# include +# include +# ifndef _WIN32 +# include +# else +# include +# endif +#endif +#ifdef _WIN32 +# if defined(__GLIBCXX__) +# include +# include +# endif +# define WIN32_LEAN_AND_MEAN +# include +#endif + +export module fmt; + +#define FMT_EXPORT export +#define FMT_BEGIN_EXPORT export { +#define FMT_END_EXPORT } + +// If you define FMT_ATTACH_TO_GLOBAL_MODULE +// - all declarations are detached from module 'fmt' +// - the module behaves like a traditional static library, too +// - all library symbols are mangled traditionally +// - you can mix TUs with either importing or #including the {fmt} API +#ifdef FMT_ATTACH_TO_GLOBAL_MODULE +extern "C++" { +#endif + +// All library-provided declarations and definitions must be in the module +// purview to be exported. +#include "fmt/args.h" +#include "fmt/chrono.h" +#include "fmt/color.h" +#include "fmt/compile.h" +#include "fmt/format.h" +#include "fmt/os.h" +#include "fmt/printf.h" +#include "fmt/std.h" +#include "fmt/xchar.h" + +#ifdef FMT_ATTACH_TO_GLOBAL_MODULE +} +#endif + +// gcc doesn't yet implement private module fragments +#if !FMT_GCC_VERSION +module :private; +#endif + +#include "format.cc" +#include "os.cc" diff --git a/dep/fmt/src/format.cc b/dep/fmt/src/format.cc new file mode 100644 index 00000000000..391d3a248c2 --- /dev/null +++ b/dep/fmt/src/format.cc @@ -0,0 +1,43 @@ +// Formatting library for C++ +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include "fmt/format-inl.h" + +FMT_BEGIN_NAMESPACE +namespace detail { + +template FMT_API auto dragonbox::to_decimal(float x) noexcept + -> dragonbox::decimal_fp; +template FMT_API auto dragonbox::to_decimal(double x) noexcept + -> dragonbox::decimal_fp; + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template FMT_API locale_ref::locale_ref(const std::locale& loc); +template FMT_API auto locale_ref::get() const -> std::locale; +#endif + +// Explicit instantiations for char. + +template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +template FMT_API auto decimal_point_impl(locale_ref) -> char; + +template FMT_API void buffer::append(const char*, const char*); + +template FMT_API void vformat_to(buffer&, string_view, + typename vformat_args<>::type, locale_ref); + +// Explicit instantiations for wchar_t. + +template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; + +template FMT_API void buffer::append(const wchar_t*, const wchar_t*); + +} // namespace detail +FMT_END_NAMESPACE diff --git a/dep/fmt/src/os.cc b/dep/fmt/src/os.cc new file mode 100644 index 00000000000..a639e78c602 --- /dev/null +++ b/dep/fmt/src/os.cc @@ -0,0 +1,402 @@ +// Formatting library for C++ - optional OS-specific functionality +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +// Disable bogus MSVC warnings. +#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) +# define _CRT_SECURE_NO_WARNINGS +#endif + +#include "fmt/os.h" + +#include + +#if FMT_USE_FCNTL +# include +# include + +# ifdef _WRS_KERNEL // VxWorks7 kernel +# include // getpagesize +# endif + +# ifndef _WIN32 +# include +# else +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + +# ifndef S_IRUSR +# define S_IRUSR _S_IREAD +# endif +# ifndef S_IWUSR +# define S_IWUSR _S_IWRITE +# endif +# ifndef S_IRGRP +# define S_IRGRP 0 +# endif +# ifndef S_IWGRP +# define S_IWGRP 0 +# endif +# ifndef S_IROTH +# define S_IROTH 0 +# endif +# ifndef S_IWOTH +# define S_IWOTH 0 +# endif +# endif // _WIN32 +#endif // FMT_USE_FCNTL + +#ifdef _WIN32 +# include +#endif + +namespace { +#ifdef _WIN32 +// Return type of read and write functions. +using rwresult = int; + +// On Windows the count argument to read and write is unsigned, so convert +// it from size_t preventing integer overflow. +inline unsigned convert_rwcount(std::size_t count) { + return count <= UINT_MAX ? static_cast(count) : UINT_MAX; +} +#elif FMT_USE_FCNTL +// Return type of read and write functions. +using rwresult = ssize_t; + +inline std::size_t convert_rwcount(std::size_t count) { return count; } +#endif +} // namespace + +FMT_BEGIN_NAMESPACE + +#ifdef _WIN32 +namespace detail { + +class system_message { + system_message(const system_message&) = delete; + void operator=(const system_message&) = delete; + + unsigned long result_; + wchar_t* message_; + + static bool is_whitespace(wchar_t c) noexcept { + return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0'; + } + + public: + explicit system_message(unsigned long error_code) + : result_(0), message_(nullptr) { + result_ = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&message_), 0, nullptr); + if (result_ != 0) { + while (result_ != 0 && is_whitespace(message_[result_ - 1])) { + --result_; + } + } + } + ~system_message() { LocalFree(message_); } + explicit operator bool() const noexcept { return result_ != 0; } + operator basic_string_view() const noexcept { + return basic_string_view(message_, result_); + } +}; + +class utf8_system_category final : public std::error_category { + public: + const char* name() const noexcept override { return "system"; } + std::string message(int error_code) const override { + auto&& msg = system_message(error_code); + if (msg) { + auto utf8_message = to_utf8(); + if (utf8_message.convert(msg)) { + return utf8_message.str(); + } + } + return "unknown error"; + } +}; + +} // namespace detail + +FMT_API const std::error_category& system_category() noexcept { + static const detail::utf8_system_category category; + return category; +} + +std::system_error vwindows_error(int err_code, string_view format_str, + format_args args) { + auto ec = std::error_code(err_code, system_category()); + return std::system_error(ec, vformat(format_str, args)); +} + +void detail::format_windows_error(detail::buffer& out, int error_code, + const char* message) noexcept { + FMT_TRY { + auto&& msg = system_message(error_code); + if (msg) { + auto utf8_message = to_utf8(); + if (utf8_message.convert(msg)) { + fmt::format_to(appender(out), FMT_STRING("{}: {}"), message, + string_view(utf8_message)); + return; + } + } + } + FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +void report_windows_error(int error_code, const char* message) noexcept { + report_error(detail::format_windows_error, error_code, message); +} +#endif // _WIN32 + +buffered_file::~buffered_file() noexcept { + if (file_ && FMT_SYSTEM(fclose(file_)) != 0) + report_system_error(errno, "cannot close file"); +} + +buffered_file::buffered_file(cstring_view filename, cstring_view mode) { + FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), + nullptr); + if (!file_) + FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"), + filename.c_str())); +} + +void buffered_file::close() { + if (!file_) return; + int result = FMT_SYSTEM(fclose(file_)); + file_ = nullptr; + if (result != 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); +} + +int buffered_file::descriptor() const { +#if !defined(fileno) + int fd = FMT_POSIX_CALL(fileno(file_)); +#elif defined(FMT_HAS_SYSTEM) + // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL. +# define FMT_DISABLE_MACRO + int fd = FMT_SYSTEM(fileno FMT_DISABLE_MACRO(file_)); +#else + int fd = fileno(file_); +#endif + if (fd == -1) + FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor"))); + return fd; +} + +#if FMT_USE_FCNTL +# ifdef _WIN32 +using mode_t = int; +# endif +constexpr mode_t default_open_mode = + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + +file::file(cstring_view path, int oflag) { +# if defined(_WIN32) && !defined(__MINGW32__) + fd_ = -1; + auto converted = detail::utf8_to_utf16(string_view(path.c_str())); + *this = file::open_windows_file(converted.c_str(), oflag); +# else + FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode))); + if (fd_ == -1) + FMT_THROW( + system_error(errno, FMT_STRING("cannot open file {}"), path.c_str())); +# endif +} + +file::~file() noexcept { + // Don't retry close in case of EINTR! + // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) + report_system_error(errno, "cannot close file"); +} + +void file::close() { + if (fd_ == -1) return; + // Don't retry close in case of EINTR! + // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + int result = FMT_POSIX_CALL(close(fd_)); + fd_ = -1; + if (result != 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); +} + +long long file::size() const { +# ifdef _WIN32 + // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT + // is less than 0x0500 as is the case with some default MinGW builds. + // Both functions support large file sizes. + DWORD size_upper = 0; + HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); + DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); + if (size_lower == INVALID_FILE_SIZE) { + DWORD error = GetLastError(); + if (error != NO_ERROR) + FMT_THROW(windows_error(GetLastError(), "cannot get file size")); + } + unsigned long long long_size = size_upper; + return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; +# else + using Stat = struct stat; + Stat file_stat = Stat(); + if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) + FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes"))); + static_assert(sizeof(long long) >= sizeof(file_stat.st_size), + "return type of file::size is not large enough"); + return file_stat.st_size; +# endif +} + +std::size_t file::read(void* buffer, std::size_t count) { + rwresult result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); + if (result < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot read from file"))); + return detail::to_unsigned(result); +} + +std::size_t file::write(const void* buffer, std::size_t count) { + rwresult result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); + if (result < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); + return detail::to_unsigned(result); +} + +file file::dup(int fd) { + // Don't retry as dup doesn't return EINTR. + // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html + int new_fd = FMT_POSIX_CALL(dup(fd)); + if (new_fd == -1) + FMT_THROW(system_error( + errno, FMT_STRING("cannot duplicate file descriptor {}"), fd)); + return file(new_fd); +} + +void file::dup2(int fd) { + int result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); + if (result == -1) { + FMT_THROW(system_error( + errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_, + fd)); + } +} + +void file::dup2(int fd, std::error_code& ec) noexcept { + int result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); + if (result == -1) ec = std::error_code(errno, std::generic_category()); +} + +void file::pipe(file& read_end, file& write_end) { + // Close the descriptors first to make sure that assignments don't throw + // and there are no leaks. + read_end.close(); + write_end.close(); + int fds[2] = {}; +# ifdef _WIN32 + // Make the default pipe capacity same as on Linux 2.6.11+. + enum { DEFAULT_CAPACITY = 65536 }; + int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); +# else + // Don't retry as the pipe function doesn't return EINTR. + // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html + int result = FMT_POSIX_CALL(pipe(fds)); +# endif + if (result != 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe"))); + // The following assignments don't throw because read_fd and write_fd + // are closed. + read_end = file(fds[0]); + write_end = file(fds[1]); +} + +buffered_file file::fdopen(const char* mode) { +// Don't retry as fdopen doesn't return EINTR. +# if defined(__MINGW32__) && defined(_POSIX_) + FILE* f = ::fdopen(fd_, mode); +# else + FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); +# endif + if (!f) { + FMT_THROW(system_error( + errno, FMT_STRING("cannot associate stream with file descriptor"))); + } + buffered_file bf(f); + fd_ = -1; + return bf; +} + +# if defined(_WIN32) && !defined(__MINGW32__) +file file::open_windows_file(wcstring_view path, int oflag) { + int fd = -1; + auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode); + if (fd == -1) { + FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"), + detail::to_utf8(path.c_str()).c_str())); + } + return file(fd); +} +# endif + +# if !defined(__MSDOS__) +long getpagesize() { +# ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +# else +# ifdef _WRS_KERNEL + long size = FMT_POSIX_CALL(getpagesize()); +# else + long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); +# endif + + if (size < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size"))); + return size; +# endif +} +# endif + +namespace detail { + +void file_buffer::grow(size_t) { + if (this->size() == this->capacity()) flush(); +} + +file_buffer::file_buffer(cstring_view path, + const detail::ostream_params& params) + : file_(path, params.oflag) { + set(new char[params.buffer_size], params.buffer_size); +} + +file_buffer::file_buffer(file_buffer&& other) + : detail::buffer(other.data(), other.size(), other.capacity()), + file_(std::move(other.file_)) { + other.clear(); + other.set(nullptr, 0); +} + +file_buffer::~file_buffer() { + flush(); + delete[] data(); +} +} // namespace detail + +ostream::~ostream() = default; +#endif // FMT_USE_FCNTL +FMT_END_NAMESPACE diff --git a/dep/gsoap/httpget.cpp b/dep/gsoap/httpget.cpp index b1b42dc710e..a34cfb6c706 100644 --- a/dep/gsoap/httpget.cpp +++ b/dep/gsoap/httpget.cpp @@ -264,8 +264,8 @@ char *query_val(struct soap *soap, char **s) } int soap_encode_string(const char *s, char *t, size_t len) -{ register int c; - register size_t n = len; +{ /*register*/ int c; + /*register*/ size_t n = len; while ((c = *s++) && n-- > 1) { if (c == ' ') *t++ = '+'; diff --git a/dep/gsoap/httppost.cpp b/dep/gsoap/httppost.cpp index 4d48109c4f7..bb9bde56259 100644 --- a/dep/gsoap/httppost.cpp +++ b/dep/gsoap/httppost.cpp @@ -264,7 +264,7 @@ int soap_http_body(struct soap *soap, char **buf, size_t *len) || soap->zlib_in != SOAP_ZLIB_NONE #endif ) - { register size_t k; + { /*register*/ size_t k; soap_wchar c = EOF; soap->labidx = 0; do diff --git a/dep/mysql/CMakeLists.txt b/dep/mysql/CMakeLists.txt index a54b6e44b9d..a30b0f738f4 100644 --- a/dep/mysql/CMakeLists.txt +++ b/dep/mysql/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2018 TrinityCore +# This file is part of the TrinityCore Project. See AUTHORS file for Copyright information # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -8,15 +8,10 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -if (NOT MYSQL_FOUND) - message(FATAL_ERROR "MySQL wasn't found on your system but it's required to build the servers!") -endif() +find_package(MySQL REQUIRED COMPONENTS lib) -add_library(mysql STATIC IMPORTED GLOBAL) +add_library(mysql INTERFACE) -set_target_properties(mysql - PROPERTIES - IMPORTED_LOCATION - "${MYSQL_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES - "${MYSQL_INCLUDE_DIR}") +target_link_libraries(mysql + INTERFACE + MySQL::MySQL) diff --git a/sql/ashamane/hotfixes/2020_03_03_00_hotfixes.sql b/sql/ashamane/hotfixes/2020_03_03_00_hotfixes.sql index dc83b357501..8b041209da4 100644 --- a/sql/ashamane/hotfixes/2020_03_03_00_hotfixes.sql +++ b/sql/ashamane/hotfixes/2020_03_03_00_hotfixes.sql @@ -1,6 +1,6 @@ /*Table structure for table `questv2clitask` */ -DROP TABLE IF EXISTS `questv2clitask`; +DROP TABLE IF EXISTS `QuestV2CliTask`; CREATE TABLE `QuestV2CliTask` ( `Unk1` INT(10) NOT NULL, diff --git a/sql/ashamane/old/world/2018_05_05_03_wordl_smart_scripts(part3).sql b/sql/ashamane/old/world/2018_05_05_03_wordl_smart_scripts(part3).sql index 87cd37bfdad..544e6d86141 100644 --- a/sql/ashamane/old/world/2018_05_05_03_wordl_smart_scripts(part3).sql +++ b/sql/ashamane/old/world/2018_05_05_03_wordl_smart_scripts(part3).sql @@ -1326,7 +1326,7 @@ DELETE FROM `smart_scripts` WHERE `entryorguid`=2448401 AND `id`=0 AND `action_ UPDATE `smart_scripts` SET `link`='0' WHERE `entryorguid`=6221 AND `source_type`=0 AND `id`=18 AND `link`=19; DELETE FROM `smart_scripts` WHERE `entryorguid`=86697 AND `source_type`=0 AND `id`=11 AND `link`=0; -DELETE FROM .`smart_scripts` WHERE `entryorguid`=86697 AND `source_type`=0 AND `id`=11 AND `link`=12; +DELETE FROM `smart_scripts` WHERE `entryorguid`=86697 AND `source_type`=0 AND `id`=11 AND `link`=12; UPDATE `smart_scripts` SET `action_param2`='2', `action_param3`='18', `action_param4`='35', `target_type`='1', `target_param1`='0' WHERE `entryorguid`=-204361 AND `source_type`=0 AND `id`=0 AND `action_type`=11; UPDATE `smart_scripts` SET `action_param2`='2', `action_param3`='18', `action_param4`='35', `target_type`='1', `target_param1`='0' WHERE `entryorguid`=24170 AND `source_type`=0 AND `id`=1 AND `action_type`=11; diff --git a/src/common/Asio/IoContext.h b/src/common/Asio/IoContext.h index 877c6017322..4b469d3baa2 100644 --- a/src/common/Asio/IoContext.h +++ b/src/common/Asio/IoContext.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,18 +18,9 @@ #ifndef IoContext_h__ #define IoContext_h__ -#include - -#if BOOST_VERSION >= 106600 +#include #include #include -#define IoContextBaseNamespace boost::asio -#define IoContextBase io_context -#else -#include -#define IoContextBaseNamespace boost::asio -#define IoContextBase io_service -#endif namespace Trinity { @@ -38,41 +29,45 @@ namespace Trinity class IoContext { public: + using Executor = boost::asio::io_context::executor_type; + IoContext() : _impl() { } explicit IoContext(int concurrency_hint) : _impl(concurrency_hint) { } - operator IoContextBaseNamespace::IoContextBase&() { return _impl; } - operator IoContextBaseNamespace::IoContextBase const&() const { return _impl; } + operator boost::asio::io_context&() { return _impl; } + operator boost::asio::io_context const&() const { return _impl; } std::size_t run() { return _impl.run(); } + std::size_t poll() { return _impl.poll(); } void stop() { _impl.stop(); } -#if BOOST_VERSION >= 106600 - boost::asio::io_context::executor_type get_executor() noexcept { return _impl.get_executor(); } -#endif + bool stopped() const { return _impl.stopped(); } + void restart() { return _impl.restart(); } + + Executor get_executor() noexcept { return _impl.get_executor(); } private: - IoContextBaseNamespace::IoContextBase _impl; + boost::asio::io_context _impl; }; template - inline decltype(auto) post(IoContextBaseNamespace::IoContextBase& ioContext, T&& t) + inline decltype(auto) post(boost::asio::io_context& ioContext, T&& t) { -#if BOOST_VERSION >= 106600 return boost::asio::post(ioContext, std::forward(t)); -#else - return ioContext.post(std::forward(t)); -#endif } + template + inline decltype(auto) post(boost::asio::io_context::executor_type& executor, T&& t) + { + return boost::asio::post(executor, std::forward(t)); + } + + using boost::asio::bind_executor; + template inline decltype(auto) get_io_context(T&& ioObject) { -#if BOOST_VERSION >= 106600 return ioObject.get_executor().context(); -#else - return ioObject.get_io_service(); -#endif } } } diff --git a/src/common/Asio/Resolver.h b/src/common/Asio/Resolver.h index 5106421ee5e..01399e435e5 100644 --- a/src/common/Asio/Resolver.h +++ b/src/common/Asio/Resolver.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,34 +18,37 @@ #ifndef Resolver_h__ #define Resolver_h__ +#include "IoContext.h" #include "Optional.h" #include #include namespace Trinity { - namespace Net + namespace Asio { - inline Optional Resolve(boost::asio::ip::tcp::resolver& resolver, boost::asio::ip::tcp const& protocol, - std::string const& host, std::string const& service) + /** + Hack to make it possible to forward declare resolver (one of its template arguments is a typedef to something super long and using nested classes) + */ + class Resolver { - boost::system::error_code ec; -#if BOOST_VERSION >= 106600 - boost::asio::ip::tcp::resolver::results_type results = resolver.resolve(protocol, host, service, ec); - if (results.empty() || ec) - return {}; + public: + explicit Resolver(IoContext& ioContext) : _impl(ioContext) { } - return results.begin()->endpoint(); -#else - boost::asio::ip::tcp::resolver::query query(std::move(protocol), std::move(host), std::move(service)); - boost::asio::ip::tcp::resolver::iterator itr = resolver.resolve(query, ec); - boost::asio::ip::tcp::resolver::iterator end; - if (itr == end || ec) - return {}; + Optional Resolve(boost::asio::ip::tcp const& protocol, std::string const& host, std::string const& service) + { + boost::system::error_code ec; + boost::asio::ip::resolver_base::flags flagsResolver = boost::asio::ip::resolver_base::all_matching; + boost::asio::ip::tcp::resolver::results_type results = _impl.resolve(protocol, host, service, flagsResolver, ec); + if (results.begin() == results.end() || ec) + return {}; - return itr->endpoint(); -#endif - } + return results.begin()->endpoint(); + } + + private: + boost::asio::ip::tcp::resolver _impl; + }; } } diff --git a/src/common/Asio/Strand.h b/src/common/Asio/Strand.h index 2b69c02f7bd..5228a30103b 100644 --- a/src/common/Asio/Strand.h +++ b/src/common/Asio/Strand.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -21,10 +21,6 @@ #include "IoContext.h" #include -#if BOOST_VERSION >= 106600 -#include -#endif - namespace Trinity { namespace Asio @@ -32,21 +28,17 @@ namespace Trinity /** Hack to make it possible to forward declare strand (which is a inner class) */ - class Strand : public IoContextBaseNamespace::IoContextBase::strand + class Strand : public boost::asio::io_context::strand { public: - Strand(IoContext& ioContext) : IoContextBaseNamespace::IoContextBase::strand(ioContext) { } + Strand(IoContext& ioContext) : boost::asio::io_context::strand(ioContext) { } }; -#if BOOST_VERSION >= 106600 - using boost::asio::bind_executor; -#else template - inline decltype(auto) bind_executor(Strand& strand, T&& t) + inline decltype(auto) post(boost::asio::io_context::strand& strand, T&& t) { - return strand.wrap(std::forward(t)); + return boost::asio::post(strand, std::forward(t)); } -#endif } } diff --git a/src/common/Cryptography/OpenSSLCrypto.cpp b/src/common/Cryptography/OpenSSLCrypto.cpp index 0ffcb17d61a..db5e2e01533 100644 --- a/src/common/Cryptography/OpenSSLCrypto.cpp +++ b/src/common/Cryptography/OpenSSLCrypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -15,50 +15,89 @@ * with this program. If not, see . */ -#include +#include "OpenSSLCrypto.h" #include -#include -#include -#include +#include -std::vector cryptoLocks; +OSSL_PROVIDER* LegacyProvider; -static void lockingCallback(int mode, int type, const char* /*file*/, int /*line*/) +void OpenSSLCrypto::threadsSetup([[maybe_unused]] boost::filesystem::path const& providerModulePath) { - if (mode & CRYPTO_LOCK) - cryptoLocks[type]->lock(); - else - cryptoLocks[type]->unlock(); +#ifdef VALGRIND + ValgrindRandomSetup(); +#endif + +#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS + OSSL_PROVIDER_set_default_search_path(nullptr, providerModulePath.string().c_str()); +#endif + LegacyProvider = OSSL_PROVIDER_try_load(nullptr, "legacy", 1); } -static void threadIdCallback(CRYPTO_THREADID * id) +void OpenSSLCrypto::threadsCleanup() { - (void)id; - CRYPTO_THREADID_set_numeric(id, std::hash()(std::this_thread::get_id())); + OSSL_PROVIDER_unload(LegacyProvider); + OSSL_PROVIDER_set_default_search_path(nullptr, nullptr); } -void OpenSSLCrypto::threadsSetup() +#ifdef VALGRIND +#include + +RAND_METHOD const* default_rand; + +static int Valgrind_RAND_seed(const void* buf, int num) { - cryptoLocks.resize(CRYPTO_num_locks()); - for(int i = 0 ; i < CRYPTO_num_locks(); ++i) - { - cryptoLocks[i] = new std::mutex(); - } + VALGRIND_DISCARD(VALGRIND_MAKE_MEM_DEFINED(buf, num)); + return default_rand->seed(buf, num); +} - (void)&threadIdCallback; - CRYPTO_THREADID_set_callback(threadIdCallback); +static int Valgrind_RAND_bytes(unsigned char* buf, int num) +{ + int ret = default_rand->bytes(buf, num); + VALGRIND_DISCARD(VALGRIND_MAKE_MEM_DEFINED(buf, num)); + return ret; +} - (void)&lockingCallback; - CRYPTO_set_locking_callback(lockingCallback); +static void Valgrind_RAND_cleanup(void) +{ + default_rand->cleanup(); } -void OpenSSLCrypto::threadsCleanup() +static int Valgrind_RAND_add(const void* buf, int num, double randomness) +{ + VALGRIND_DISCARD(VALGRIND_MAKE_MEM_DEFINED(buf, num)); + return default_rand->add(buf, num, randomness); +} + +static int Valgrind_RAND_pseudorand(unsigned char* buf, int num) +{ + int ret = default_rand->pseudorand(buf, num); + VALGRIND_DISCARD(VALGRIND_MAKE_MEM_DEFINED(buf, num)); + return ret; +} + +static int Valgrind_RAND_status(void) +{ + return default_rand->status(); +} + +static RAND_METHOD valgrind_rand; + +void ValgrindRandomSetup() { - CRYPTO_set_locking_callback(NULL); - CRYPTO_THREADID_set_callback(NULL); - for(int i = 0 ; i < CRYPTO_num_locks(); ++i) - { - delete cryptoLocks[i]; - } - cryptoLocks.resize(0); + memset(&valgrind_rand, 0, sizeof(RAND_METHOD)); + default_rand = RAND_get_rand_method(); + if (default_rand->seed) + valgrind_rand.seed = &Valgrind_RAND_seed; + if (default_rand->bytes) + valgrind_rand.bytes = &Valgrind_RAND_bytes; + if (default_rand->cleanup) + valgrind_rand.cleanup = &Valgrind_RAND_cleanup; + if (default_rand->add) + valgrind_rand.add = &Valgrind_RAND_add; + if (default_rand->pseudorand) + valgrind_rand.pseudorand = &Valgrind_RAND_pseudorand; + if (default_rand->status) + valgrind_rand.status = &Valgrind_RAND_status; + RAND_set_rand_method(&valgrind_rand); } +#endif diff --git a/src/common/Cryptography/OpenSSLCrypto.h b/src/common/Cryptography/OpenSSLCrypto.h index 100a1c4eb3a..1e6ca9562dd 100644 --- a/src/common/Cryptography/OpenSSLCrypto.h +++ b/src/common/Cryptography/OpenSSLCrypto.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -15,10 +15,11 @@ * with this program. If not, see . */ -#ifndef OPENSSL_CRYPTO_H -#define OPENSSL_CRYPTO_H +#ifndef TRINITY_OPENSSL_CRYPTO_H +#define TRINITY_OPENSSL_CRYPTO_H #include "Define.h" +#include /** * A group of functions which setup openssl crypto module to work properly in multithreaded enviroment @@ -27,7 +28,7 @@ namespace OpenSSLCrypto { /// Needs to be called before threads using openssl are spawned - TC_COMMON_API void threadsSetup(); + TC_COMMON_API void threadsSetup(boost::filesystem::path const& providerModulePath); /// Needs to be called after threads using openssl are despawned TC_COMMON_API void threadsCleanup(); } diff --git a/src/common/Utilities/AsyncCallbackProcessor.h b/src/common/Utilities/AsyncCallbackProcessor.h new file mode 100644 index 00000000000..8a0b123b1b7 --- /dev/null +++ b/src/common/Utilities/AsyncCallbackProcessor.h @@ -0,0 +1,62 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef AsyncCallbackProcessor_h__ +#define AsyncCallbackProcessor_h__ + +#include +#include + +//template +//concept AsyncCallback = requires(T t) { { t.InvokeIfReady() } -> std::convertible_to }; + +template // requires AsyncCallback +class AsyncCallbackProcessor +{ +public: + AsyncCallbackProcessor() = default; + ~AsyncCallbackProcessor() = default; + + T& AddCallback(T&& query) + { + _callbacks.emplace_back(std::move(query)); + return _callbacks.back(); + } + + void ProcessReadyCallbacks() + { + if (_callbacks.empty()) + return; + + std::vector updateCallbacks{ std::move(_callbacks) }; + + updateCallbacks.erase(std::remove_if(updateCallbacks.begin(), updateCallbacks.end(), [](T& callback) + { + return callback.InvokeIfReady(); + }), updateCallbacks.end()); + + _callbacks.insert(_callbacks.end(), std::make_move_iterator(updateCallbacks.begin()), std::make_move_iterator(updateCallbacks.end())); + } + +private: + AsyncCallbackProcessor(AsyncCallbackProcessor const&) = delete; + AsyncCallbackProcessor& operator=(AsyncCallbackProcessor const&) = delete; + + std::vector _callbacks; +}; + +#endif // AsyncCallbackProcessor_h__ diff --git a/src/common/Utilities/Duration.h b/src/common/Utilities/Duration.h index 8d1fc9afb49..b4c3f17cb3e 100644 --- a/src/common/Utilities/Duration.h +++ b/src/common/Utilities/Duration.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,7 +18,12 @@ #ifndef _DURATION_H_ #define _DURATION_H_ +// HACKS TERRITORY +#if __has_include(<__msvc_chrono.hpp>) +#include <__msvc_chrono.hpp> // skip all the formatting/istream/locale/mutex bloat +#else #include +#endif /// Milliseconds shorthand typedef. typedef std::chrono::milliseconds Milliseconds; @@ -32,7 +37,16 @@ typedef std::chrono::minutes Minutes; /// Hours shorthand typedef. typedef std::chrono::hours Hours; +/// time_point shorthand typedefs +typedef std::chrono::steady_clock::time_point TimePoint; +typedef std::chrono::system_clock::time_point SystemTimePoint; + /// Makes std::chrono_literals globally available. using namespace std::chrono_literals; +constexpr std::chrono::hours operator""_days(unsigned long long days) +{ + return std::chrono::hours(days * 24h); +} + #endif // _DURATION_H_ diff --git a/src/common/Utilities/Optional.h b/src/common/Utilities/Optional.h index da30779fa74..7293a4134ba 100644 --- a/src/common/Utilities/Optional.h +++ b/src/common/Utilities/Optional.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,11 +18,10 @@ #ifndef TrinityCore_Optional_h__ #define TrinityCore_Optional_h__ -#include -#include +#include - //! Optional helper class to wrap optional values within. -template -using Optional = boost::optional; +//! Optional helper class to wrap optional values within. +template +using Optional = std::optional; -#endif // TrinityCore_Optional_h__ +#endif // TrinityCore_Optional_h__ \ No newline at end of file diff --git a/src/common/Utilities/StringConvert.h b/src/common/Utilities/StringConvert.h new file mode 100644 index 00000000000..0d11dbb6667 --- /dev/null +++ b/src/common/Utilities/StringConvert.h @@ -0,0 +1,277 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef TRINITY_STRINGCONVERT_H +#define TRINITY_STRINGCONVERT_H + +#include "Define.h" +#include "Errors.h" +#include "Optional.h" +#include "Types.h" +#include "Util.h" +#include +#include +#include +#include + +namespace Trinity::Impl::StringConvertImpl +{ + template struct For + { + static_assert(Trinity::dependant_false_v, "Unsupported type used for ToString or StringTo"); + /* + static Optional FromString(std::string_view str, ...); + static std::string ToString(T&& val, ...); + */ + }; + + template + struct For && !std::is_same_v>> + { + static Optional FromString(std::string_view str, int base = 10) + { + if (base == 0) + { + if (StringEqualI(str.substr(0, 2), "0x")) + { + base = 16; + str.remove_prefix(2); + } + else if (StringEqualI(str.substr(0, 2), "0b")) + { + base = 2; + str.remove_prefix(2); + } + else + base = 10; + + if (str.empty()) + return std::nullopt; + } + + char const* const start = str.data(); + char const* const end = (start + str.length()); + + T val; + std::from_chars_result const res = std::from_chars(start, end, val, base); + if ((res.ptr == end) && (res.ec == std::errc())) + return val; + else + return std::nullopt; + } + + static std::string ToString(T val) + { + using buffer_size = std::integral_constant; + + std::string buf(buffer_size::value,'\0'); /* 2^64 is 20 decimal characters, -(2^63) is 20 including the sign */ + char* const start = buf.data(); + char* const end = (start + buf.length()); + std::to_chars_result const res = std::to_chars(start, end, val); + ASSERT(res.ec == std::errc()); + buf.resize(res.ptr - start); + return buf; + } + }; + +#ifdef TRINITY_NEED_CHARCONV_WORKAROUND + /* + If this is defined, std::from_chars will cause linkage errors for 64-bit types. + (This is a bug in clang-7.) + + If the clang requirement is bumped to >= clang-8, remove this ifdef block and its + associated check in cmake/compiler/clang/settings.cmake + */ + template <> + struct For + { + static Optional FromString(std::string_view str, int base = 10) + { + if (str.empty()) + return std::nullopt; + try + { + size_t n; + uint64 val = std::stoull(std::string(str), &n, base); + if (n != str.length()) + return std::nullopt; + return val; + } + catch (...) { return std::nullopt; } + } + + static std::string ToString(uint64 val) + { + return std::to_string(val); + } + }; + + template <> + struct For + { + static Optional FromString(std::string_view str, int base = 10) + { + try { + if (str.empty()) + return std::nullopt; + size_t n; + int64 val = std::stoll(std::string(str), &n, base); + if (n != str.length()) + return std::nullopt; + return val; + } + catch (...) { return std::nullopt; } + } + + static std::string ToString(int64 val) + { + return std::to_string(val); + } + }; +#endif + + template <> + struct For + { + static Optional FromString(std::string_view str, int strict = 0) /* this is int to match the signature for "proper" integral types */ + { + if (strict) + { + if (str == "1") + return true; + if (str == "0") + return false; + return std::nullopt; + } + else + { + if ((str == "1") || StringEqualI(str, "y") || StringEqualI(str, "on") || StringEqualI(str, "yes") || StringEqualI(str, "true")) + return true; + if ((str == "0") || StringEqualI(str, "n") || StringEqualI(str, "off") || StringEqualI(str, "no") || StringEqualI(str, "false")) + return false; + return std::nullopt; + } + } + + static std::string ToString(bool val) + { + return (val ? "1" : "0"); + } + }; + +#if TRINITY_COMPILER == TRINITY_COMPILER_MICROSOFT + template + struct For>> + { + static Optional FromString(std::string_view str, std::chars_format fmt = std::chars_format()) + { + if (str.empty()) + return std::nullopt; + + if (fmt == std::chars_format()) + { + if (StringEqualI(str.substr(0, 2), "0x")) + { + fmt = std::chars_format::hex; + str.remove_prefix(2); + } + else + fmt = std::chars_format::general; + + if (str.empty()) + return std::nullopt; + } + + char const* const start = str.data(); + char const* const end = (start + str.length()); + + T val; + std::from_chars_result const res = std::from_chars(start, end, val, fmt); + if ((res.ptr == end) && (res.ec == std::errc())) + return val; + else + return std::nullopt; + } + + // this allows generic converters for all numeric types (easier templating!) + static Optional FromString(std::string_view str, int base) + { + if (base == 16) + return FromString(str, std::chars_format::hex); + else if (base == 10) + return FromString(str, std::chars_format::general); + else + return FromString(str, std::chars_format()); + } + + static std::string ToString(T val) + { + return std::to_string(val); + } + }; +#else + // @todo replace this once libc++ supports double args to from_chars + template + struct For>> + { + static Optional FromString(std::string_view str, int base = 0) + { + try { + if (str.empty()) + return std::nullopt; + + if ((base == 10) && StringEqualI(str.substr(0, 2), "0x")) + return std::nullopt; + + std::string tmp; + if (base == 16) + tmp.append("0x"); + tmp.append(str); + + size_t n; + T val = static_cast(std::stold(tmp, &n)); + if (n != tmp.length()) + return std::nullopt; + return val; + } + catch (...) { return std::nullopt; } + } + + static std::string ToString(T val) + { + return std::to_string(val); + } + }; +#endif +} + +namespace Trinity +{ + template + Optional StringTo(std::string_view str, Params&&... params) + { + return Trinity::Impl::StringConvertImpl::For::FromString(str, std::forward(params)...); + } + + template + std::string ToString(Type&& val, Params&&... params) + { + return Trinity::Impl::StringConvertImpl::For>::ToString(std::forward(val), std::forward(params)...); + } +} + +#endif diff --git a/src/common/Utilities/StringFormat.h b/src/common/Utilities/StringFormat.h index 494597f5e76..6b85dc4ab72 100644 --- a/src/common/Utilities/StringFormat.h +++ b/src/common/Utilities/StringFormat.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * Copyright (C) 2008-2016 TrinityCore * Copyright (C) 2005-2009 MaNGOS * * This program is free software; you can redistribute it and/or modify it @@ -20,18 +20,27 @@ #define TRINITYCORE_STRING_FORMAT_H #include "fmt/printf.h" +#include namespace Trinity { /// Default TC string format function. - template - inline std::string StringFormat(Format&& fmt, Args&&... args) + template + std::string StringFormat(std::string_view fmt, Args&&... args) { - return fmt::sprintf(std::forward(fmt), std::forward(args)...); + try + { + return fmt::sprintf(fmt, std::forward(args)...); + } + catch (fmt::format_error const& formatError) + { + std::string error = "An error occurred formatting string \"" + std::string(fmt) + "\" : " + formatError.what(); + return error; + } } /// Returns true if the given char pointer is null. - inline bool IsFormatEmptyOrNull(const char* fmt) + inline bool IsFormatEmptyOrNull(char const* fmt) { return fmt == nullptr; } @@ -41,6 +50,16 @@ namespace Trinity { return fmt.empty(); } + + /// Returns true if the given std::string_view is empty. + inline bool IsFormatEmptyOrNull(std::string_view const& fmt) + { + return fmt.empty(); + } } +// allow implicit enum to int conversions for formatting +template , std::nullptr_t> = nullptr> +auto format_as(E e) { return std::underlying_type_t(e); } + #endif diff --git a/src/common/Utilities/TaskScheduler.cpp b/src/common/Utilities/TaskScheduler.cpp index 2985358f7af..6ae5b0f9e49 100644 --- a/src/common/Utilities/TaskScheduler.cpp +++ b/src/common/Utilities/TaskScheduler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * Copyright (C) 2008-2017 TrinityCore * * 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 @@ -16,6 +16,7 @@ */ #include "TaskScheduler.h" +#include #include "Errors.h" TaskScheduler& TaskScheduler::ClearValidator() @@ -44,13 +45,12 @@ TaskScheduler& TaskScheduler::Async(std::function const& callable) TaskScheduler& TaskScheduler::CancelAll() { - /// Clear the task holder _task_holder.Clear(); _asyncHolder = AsyncHolder(); return *this; } -TaskScheduler& TaskScheduler::CancelGroup(group_t const group) +TaskScheduler& TaskScheduler::CancelGroup(uint32 const group) { _task_holder.RemoveIf([group](TaskContainer const& task) -> bool { @@ -59,11 +59,9 @@ TaskScheduler& TaskScheduler::CancelGroup(group_t const group) return *this; } -TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector const& groups) +TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector const& groups) { - std::for_each(groups.begin(), groups.end(), - std::bind(&TaskScheduler::CancelGroup, this, std::placeholders::_1)); - + std::for_each(groups.begin(), groups.end(), std::bind(&TaskScheduler::CancelGroup, this, std::placeholders::_1)); return *this; } @@ -75,17 +73,13 @@ TaskScheduler& TaskScheduler::InsertTask(TaskContainer task) void TaskScheduler::Dispatch(success_t const& callback) { - // If the validation failed abort the dispatching here. if (!_predicate()) return; - // Process all asyncs while (!_asyncHolder.empty()) { _asyncHolder.front()(); _asyncHolder.pop(); - - // If the validation failed abort the dispatching here. if (!_predicate()) return; } @@ -95,22 +89,45 @@ void TaskScheduler::Dispatch(success_t const& callback) if (_task_holder.First()->_end > _now) break; - // Perfect forward the context to the handler - // Use weak references to catch destruction before callbacks. TaskContext context(_task_holder.Pop(), std::weak_ptr(self_reference), GetSchedulerUnit(), GetSchedulerGameObject()); - - // Invoke the context context.Invoke(); - - // If the validation failed abort the dispatching here. if (!_predicate()) return; } - // On finish call the final callback callback(); } +TaskScheduler::Task::Task(timepoint_t const& end, duration_t const& duration, Optional group, uint32 const repeated, task_handler_t task) : + _end(end), _duration(duration), _group(std::move(group)), _repeated(repeated), _task(std::move(task)) { } + +TaskScheduler::Task::Task(timepoint_t const& end, duration_t const& duration, task_handler_t task) : _end(end), _duration(duration), _group(std::nullopt), _repeated(0), _task(std::move(task)) { } + +bool TaskScheduler::Task::operator<(Task const& other) const +{ + return _end < other._end; +} + +bool TaskScheduler::Task::operator>(Task const& other) const +{ + return _end > other._end; +} + +bool TaskScheduler::Task::operator==(Task const& other) +{ + return _end == other._end; +} + +bool TaskScheduler::Task::IsInGroup(uint32 const group) const +{ + return _group == group; +} + +bool TaskScheduler::Compare::operator()(TaskContainer const& left, TaskContainer const& right) const +{ + return *left.get() < *right.get(); +} + void TaskScheduler::TaskQueue::Push(TaskContainer&& task) { container.insert(task); @@ -118,7 +135,7 @@ void TaskScheduler::TaskQueue::Push(TaskContainer&& task) auto TaskScheduler::TaskQueue::Pop() -> TaskContainer { - TaskContainer result = *container.begin(); + auto result = *container.begin(); container.erase(container.begin()); return result; } @@ -175,12 +192,12 @@ bool TaskContext::IsExpired() const return _owner.expired(); } -bool TaskContext::IsInGroup(TaskScheduler::group_t const group) const +bool TaskContext::IsInGroup(uint32 const group) const { return _task->IsInGroup(group); } -TaskContext& TaskContext::SetGroup(TaskScheduler::group_t const group) +TaskContext& TaskContext::SetGroup(uint32 const group) { _task->_group = group; return *this; @@ -188,15 +205,20 @@ TaskContext& TaskContext::SetGroup(TaskScheduler::group_t const group) TaskContext& TaskContext::ClearGroup() { - _task->_group = boost::none; + _task->_group = std::nullopt; return *this; } -TaskScheduler::repeated_t TaskContext::GetRepeatCounter() const +uint32 TaskContext::GetRepeatCounter() const { return _task->_repeated; } +TaskContext& TaskContext::Repeat() +{ + return Repeat(_task->_duration); +} + TaskContext& TaskContext::Async(std::function const& callable) { return Dispatch(std::bind(&TaskScheduler::Async, std::placeholders::_1, callable)); @@ -207,12 +229,12 @@ TaskContext& TaskContext::CancelAll() return Dispatch(std::mem_fn(&TaskScheduler::CancelAll)); } -TaskContext& TaskContext::CancelGroup(TaskScheduler::group_t const group) +TaskContext& TaskContext::CancelGroup(uint32 const group) { return Dispatch(std::bind(&TaskScheduler::CancelGroup, std::placeholders::_1, group)); } -TaskContext& TaskContext::CancelGroupsOf(std::vector const& groups) +TaskContext& TaskContext::CancelGroupsOf(std::vector const& groups) { return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, std::cref(groups))); } diff --git a/src/common/Utilities/TaskScheduler.h b/src/common/Utilities/TaskScheduler.h index 8184af1c86e..8cca48c8676 100644 --- a/src/common/Utilities/TaskScheduler.h +++ b/src/common/Utilities/TaskScheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * Copyright (C) 2008-2017 TrinityCore * * 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 @@ -18,15 +18,13 @@ #ifndef _TASK_SCHEDULER_H_ #define _TASK_SCHEDULER_H_ -#include "Duration.h" -#include "Optional.h" #include "Random.h" -#include +#include "Optional.h" +#include #include #include #include #include -#include #include class TaskContext; @@ -51,24 +49,15 @@ class GameObject; /// with the same duration or a new one. /// It also provides access to the repeat counter which is useful for task that repeat itself often /// but behave different every time (spoken event dialogs for example). -class TC_COMMON_API TaskScheduler +class TaskScheduler { friend class TaskContext; - // Time definitions (use steady clock) typedef std::chrono::steady_clock clock_t; typedef clock_t::time_point timepoint_t; typedef clock_t::duration duration_t; - - // Task group type - typedef uint32 group_t; - // Task repeated type - typedef uint32 repeated_t; - // Task handle type typedef std::function task_handler_t; - // Predicate type typedef std::function predicate_t; - // Success handle type typedef std::function success_t; class Task @@ -78,101 +67,53 @@ class TC_COMMON_API TaskScheduler timepoint_t _end; duration_t _duration; - Optional _group; - repeated_t _repeated; + Optional _group; + uint32 _repeated; task_handler_t _task; public: - // All Argument construct - Task(timepoint_t const& end, duration_t const& duration, Optional const& group, - repeated_t const repeated, task_handler_t const& task) - : _end(end), _duration(duration), _group(group), _repeated(repeated), _task(task) { } + Task(timepoint_t const& end, duration_t const& duration, Optional group, uint32 repeated, task_handler_t task); + Task(timepoint_t const& end, duration_t const& duration, task_handler_t task); - // Minimal Argument construct - Task(timepoint_t const& end, duration_t const& duration, task_handler_t const& task) - : _end(end), _duration(duration), _group(boost::none), _repeated(0), _task(task) { } - - // Copy construct Task(Task const&) = delete; - // Move construct Task(Task&&) = delete; - // Copy Assign Task& operator= (Task const&) = default; - // Move Assign Task& operator= (Task&& right) = delete; - - // Order tasks by its end - inline bool operator< (Task const& other) const - { - return _end < other._end; - } - - inline bool operator> (Task const& other) const - { - return _end > other._end; - } - - // Compare tasks with its end - inline bool operator== (Task const& other) - { - return _end == other._end; - } - - // Returns true if the task is in the given group - inline bool IsInGroup(group_t const group) const - { - return _group == group; - } + bool operator<(Task const& other) const; + bool operator>(Task const& other) const; + bool operator==(Task const& other); + bool IsInGroup(uint32 group) const; }; typedef std::shared_ptr TaskContainer; - /// Container which provides Task order, insert and reschedule operations. struct Compare { - bool operator() (TaskContainer const& left, TaskContainer const& right) const - { - return (*left.get()) < (*right.get()); - }; + bool operator()(TaskContainer const& left, TaskContainer const& right) const; }; - class TC_COMMON_API TaskQueue + class TaskQueue { std::multiset container; public: - // Pushes the task in the container void Push(TaskContainer&& task); - - /// Pops the task out of the container TaskContainer Pop(); - TaskContainer const& First() const; void Clear(); - void RemoveIf(std::function const& filter); - void ModifyIf(std::function const& filter); - bool IsEmpty() const; }; - /// Contains a self reference to track if this object was deleted or not. std::shared_ptr self_reference; - - /// The current time point (now) timepoint_t _now; - - /// The Task Queue which contains all task objects. TaskQueue _task_holder; typedef std::queue> AsyncHolder; - /// Contains all asynchronous tasks which will be invoked at - /// the next update tick. AsyncHolder _asyncHolder; - predicate_t _predicate; static bool EmptyValidator() @@ -211,7 +152,6 @@ class TC_COMMON_API TaskScheduler TaskScheduler& operator= (TaskScheduler const&) = delete; TaskScheduler& operator= (TaskScheduler&&) = delete; - /// Sets a validator which is asked if tasks are allowed to be executed. template TaskScheduler& SetValidator(P&& predicate) { @@ -219,100 +159,62 @@ class TC_COMMON_API TaskScheduler return *this; } - /// Clears the validator which is asked if tasks are allowed to be executed. TaskScheduler& ClearValidator(); - /// Update the scheduler to the current time. - /// Calls the optional callback on successfully finish. TaskScheduler& Update(success_t const& callback = EmptyCallback); + TaskScheduler& Update(size_t milliseconds, success_t const& callback = EmptyCallback); - /// Update the scheduler with a difftime in ms. - /// Calls the optional callback on successfully finish. - TaskScheduler& Update(size_t const milliseconds, success_t const& callback = EmptyCallback); - - /// Update the scheduler with a difftime. - /// Calls the optional callback on successfully finish. template - TaskScheduler& Update(std::chrono::duration<_Rep, _Period> const& difftime, - success_t const& callback = EmptyCallback) + TaskScheduler& Update(std::chrono::duration<_Rep, _Period> const& difftime, success_t const& callback = EmptyCallback) { _now += difftime; Dispatch(callback); return *this; } - /// Schedule an callable function that is executed at the next update tick. - /// Its safe to modify the TaskScheduler from within the callable. TaskScheduler& Async(std::function const& callable); - /// Schedule an event with a fixed rate. - /// Never call this from within a task context! Use TaskContext::Schedule instead! template - TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time, - task_handler_t const& task) + TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task) { return ScheduleAt(_now, time, task); } - /// Schedule an event with a fixed rate. - /// Never call this from within a task context! Use TaskContext::Schedule instead! template - TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time, - group_t const group, task_handler_t const& task) + TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time, uint32 const group, task_handler_t const& task) { return ScheduleAt(_now, time, group, task); } - /// Schedule an event with a randomized rate between min and max rate. - /// Never call this from within a task context! Use TaskContext::Schedule instead! template - TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task) + TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task) { return Schedule(RandomDurationBetween(min, max), task); } - /// Schedule an event with a fixed rate. - /// Never call this from within a task context! Use TaskContext::Schedule instead! template - TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max, group_t const group, - task_handler_t const& task) + TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max, uint32 const group, task_handler_t const& task) { return Schedule(RandomDurationBetween(min, max), group, task); } - /// Schedule an event with a fixed rate. - /// Never call this from within a task context! Use TaskContext::Schedule instead! template - void Schedule(std::initializer_list> const& times, - task_handler_t const& task) + void Schedule(std::initializer_list> const& times, task_handler_t const& task) { for (auto time : times) ScheduleAt(_now, time, task); } - /// Schedule an event with a fixed rate. - /// Never call this from within a task context! Use TaskContext::Schedule instead! template - void Schedule(std::initializer_list> const& times, - group_t const group, task_handler_t const& task) + void Schedule(std::initializer_list> const& times, uint32 const group, task_handler_t const& task) { - for (auto time: times) + for (auto time : times) ScheduleAt(_now, time, group, task); } - /// Cancels all tasks. - /// Never call this from within a task context! Use TaskContext::CancelAll instead! TaskScheduler& CancelAll(); - - /// Cancel all tasks of a single group. - /// Never call this from within a task context! Use TaskContext::CancelGroup instead! - TaskScheduler& CancelGroup(group_t const group); - - /// Cancels all groups in the given std::vector. - /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}" - TaskScheduler& CancelGroupsOf(std::vector const& groups); + TaskScheduler& CancelGroup(uint32 group); + TaskScheduler& CancelGroupsOf(std::vector const& groups); /// Delays all tasks with the given duration. template @@ -326,17 +228,14 @@ class TC_COMMON_API TaskScheduler return *this; } - /// Delays all tasks with a random duration between min and max. template - TaskScheduler& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskScheduler& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return DelayAll(RandomDurationBetween(min, max)); } - /// Delays all tasks of a group with the given duration. template - TaskScheduler& DelayGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + TaskScheduler& DelayGroup(uint32 const group, std::chrono::duration<_Rep, _Period> const& duration) { _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool { @@ -351,16 +250,12 @@ class TC_COMMON_API TaskScheduler return *this; } - /// Delays all tasks of a group with a random duration between min and max. template - TaskScheduler& DelayGroup(group_t const group, - std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskScheduler& DelayGroup(uint32 const group, std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return DelayGroup(group, RandomDurationBetween(min, max)); } - /// Reschedule all tasks with a given duration. template TaskScheduler& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration) { @@ -373,17 +268,14 @@ class TC_COMMON_API TaskScheduler return *this; } - /// Reschedule all tasks with a random duration between min and max. template - TaskScheduler& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskScheduler& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return RescheduleAll(RandomDurationBetween(min, max)); } - /// Reschedule all tasks of a group with the given duration. template - TaskScheduler& RescheduleGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + TaskScheduler& RescheduleGroup(uint32 const group, std::chrono::duration<_Rep, _Period> const& duration) { auto const end = _now + duration; _task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool @@ -399,11 +291,8 @@ class TC_COMMON_API TaskScheduler return *this; } - /// Reschedule all tasks of a group with a random duration between min and max. template - TaskScheduler& RescheduleGroup(group_t const group, - std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskScheduler& RescheduleGroup(uint32 const group, std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return RescheduleGroup(group, RandomDurationBetween(min, max)); } @@ -415,63 +304,45 @@ class TC_COMMON_API TaskScheduler GameObject* GetSchedulerGameObject() const { return _schedulerGob; } private: - /// Insert a new task to the enqueued tasks. TaskScheduler& InsertTask(TaskContainer task); template - TaskScheduler& ScheduleAt(timepoint_t const& end, - std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task) + TaskScheduler& ScheduleAt(timepoint_t const& end, std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task) { - return InsertTask(TaskContainer(new Task(end + time, time, task))); + return InsertTask(std::make_shared(end + time, time, task)); } - /// Schedule an event with a fixed rate. - /// Never call this from within a task context! Use TaskContext::schedule instead! template - TaskScheduler& ScheduleAt(timepoint_t const& end, - std::chrono::duration<_Rep, _Period> const& time, - group_t const group, task_handler_t const& task) + TaskScheduler& ScheduleAt(timepoint_t const& end, std::chrono::duration<_Rep, _Period> const& time, uint32 const group, task_handler_t const& task) { - static repeated_t const DEFAULT_REPEATED = 0; - return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, task))); + static uint32 const DEFAULT_REPEATED = 0; + return InsertTask(std::make_shared(end + time, time, group, DEFAULT_REPEATED, task)); } - // Returns a random duration between min and max template static std::chrono::milliseconds - RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { auto const milli_min = std::chrono::duration_cast(min); auto const milli_max = std::chrono::duration_cast(max); - - // TC specific: use SFMT URandom return std::chrono::milliseconds(urand(uint32(milli_min.count()), uint32(milli_max.count()))); } - /// Dispatch remaining tasks void Dispatch(success_t const& callback); Unit* _schedulerUnit; GameObject* _schedulerGob; }; -class TC_COMMON_API TaskContext +class TaskContext { friend class TaskScheduler; - /// Associated task TaskScheduler::TaskContainer _task; - - /// Owner std::weak_ptr _owner; - - /// Marks the task as consumed std::shared_ptr _consumed; - /// Dispatches an action safe on the TaskScheduler TaskContext& Dispatch(std::function const& apply); - public: // Empty constructor TaskContext() @@ -492,8 +363,9 @@ class TC_COMMON_API TaskContext : _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)), _contextUnit(std::move(right._contextUnit)), _contextGob(std::move(right._contextGob)) { } + // Copy assign - TaskContext& operator= (TaskContext const& right) + TaskContext& operator=(TaskContext const& right) { _task = right._task; _owner = right._owner; @@ -504,7 +376,7 @@ class TC_COMMON_API TaskContext } // Move assign - TaskContext& operator= (TaskContext&& right) + TaskContext& operator=(TaskContext&& right) { _task = std::move(right._task); _owner = std::move(right._owner); @@ -514,25 +386,14 @@ class TC_COMMON_API TaskContext return *this; } - /// Returns true if the owner was deallocated and this context has expired. bool IsExpired() const; - /// Returns true if the event is in the given group - bool IsInGroup(TaskScheduler::group_t const group) const; - - /// Sets the event in the given group - TaskContext& SetGroup(TaskScheduler::group_t const group); - - /// Removes the group from the event + bool IsInGroup(uint32 group) const; + TaskContext& SetGroup(uint32 group); TaskContext& ClearGroup(); - /// Returns the repeat counter which increases every time the task is repeated. - TaskScheduler::repeated_t GetRepeatCounter() const; + uint32 GetRepeatCounter() const; - /// Repeats the event and sets a new duration. - /// std::chrono::seconds(5) for example. - /// This will consume the task context, its not possible to repeat the task again - /// from the same task context! template TaskContext& Repeat(std::chrono::duration<_Rep, _Period> const& duration) { @@ -542,40 +403,22 @@ class TC_COMMON_API TaskContext _task->_duration = duration; _task->_end += duration; _task->_repeated += 1; - (*_consumed) = true; + *_consumed = true; return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task)); } - /// Repeats the event with the same duration. - /// This will consume the task context, its not possible to repeat the task again - /// from the same task context! - TaskContext& Repeat() - { - return Repeat(_task->_duration); - } + TaskContext& Repeat(); - /// Repeats the event and set a new duration that is randomized between min and max. - /// std::chrono::seconds(5) for example. - /// This will consume the task context, its not possible to repeat the task again - /// from the same task context! template - TaskContext& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskContext& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return Repeat(TaskScheduler::RandomDurationBetween(min, max)); } - /// Schedule a callable function that is executed at the next update tick from within the context. - /// Its safe to modify the TaskScheduler from within the callable. TaskContext& Async(std::function const& callable); - /// Schedule an event with a fixed rate from within the context. - /// Its possible that the new event is executed immediately! - /// Use TaskScheduler::Async to create a task - /// which will be called at the next update tick. template - TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time, - TaskScheduler::task_handler_t const& task) + TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time, TaskScheduler::task_handler_t const& task) { auto const end = _task->_end; return Dispatch([end, time, task](TaskScheduler& scheduler) -> TaskScheduler& @@ -584,13 +427,8 @@ class TC_COMMON_API TaskContext }); } - /// Schedule an event with a fixed rate from within the context. - /// Its possible that the new event is executed immediately! - /// Use TaskScheduler::Async to create a task - /// which will be called at the next update tick. template - TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time, - TaskScheduler::group_t const group, TaskScheduler::task_handler_t const& task) + TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time, uint32 const group, TaskScheduler::task_handler_t const& task) { auto const end = _task->_end; return Dispatch([end, time, group, task](TaskScheduler& scheduler) -> TaskScheduler& @@ -599,97 +437,66 @@ class TC_COMMON_API TaskContext }); } - /// Schedule an event with a randomized rate between min and max rate from within the context. - /// Its possible that the new event is executed immediately! - /// Use TaskScheduler::Async to create a task - /// which will be called at the next update tick. template - TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task) + TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task) { return Schedule(TaskScheduler::RandomDurationBetween(min, max), task); } - /// Schedule an event with a randomized rate between min and max rate from within the context. - /// Its possible that the new event is executed immediately! - /// Use TaskScheduler::Async to create a task - /// which will be called at the next update tick. template - TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group, - TaskScheduler::task_handler_t const& task) + TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max, uint32 const group, TaskScheduler::task_handler_t const& task) { return Schedule(TaskScheduler::RandomDurationBetween(min, max), group, task); } - /// Cancels all tasks from within the context. TaskContext& CancelAll(); + TaskContext& CancelGroup(uint32 group); + TaskContext& CancelGroupsOf(std::vector const& groups); - /// Cancel all tasks of a single group from within the context. - TaskContext& CancelGroup(TaskScheduler::group_t const group); - - /// Cancels all groups in the given std::vector from within the context. - /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}" - TaskContext& CancelGroupsOf(std::vector const& groups); - - /// Delays all tasks with the given duration from within the context. template TaskContext& DelayAll(std::chrono::duration<_Rep, _Period> const& duration) { return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, duration)); } - /// Delays all tasks with a random duration between min and max from within the context. template - TaskContext& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskContext& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return DelayAll(TaskScheduler::RandomDurationBetween(min, max)); } - /// Delays all tasks of a group with the given duration from within the context. template - TaskContext& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + TaskContext& DelayGroup(uint32 const group, std::chrono::duration<_Rep, _Period> const& duration) { return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, duration)); } - /// Delays all tasks of a group with a random duration between min and max from within the context. template - TaskContext& DelayGroup(TaskScheduler::group_t const group, - std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskContext& DelayGroup(uint32 const group, std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return DelayGroup(group, TaskScheduler::RandomDurationBetween(min, max)); } - /// Reschedule all tasks with the given duration. template TaskContext& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration) { return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, duration)); } - /// Reschedule all tasks with a random duration between min and max. template - TaskContext& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskContext& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return RescheduleAll(TaskScheduler::RandomDurationBetween(min, max)); } - /// Reschedule all tasks of a group with the given duration. template - TaskContext& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + TaskContext& RescheduleGroup(uint32 const group, std::chrono::duration<_Rep, _Period> const& duration) { return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, duration)); } - /// Reschedule all tasks of a group with a random duration between min and max. template - TaskContext& RescheduleGroup(TaskScheduler::group_t const group, - std::chrono::duration<_RepLeft, _PeriodLeft> const& min, - std::chrono::duration<_RepRight, _PeriodRight> const& max) + TaskContext& RescheduleGroup(uint32 const group, std::chrono::duration<_RepLeft, _PeriodLeft> const& min, std::chrono::duration<_RepRight, _PeriodRight> const& max) { return RescheduleGroup(group, TaskScheduler::RandomDurationBetween(min, max)); } @@ -701,10 +508,7 @@ class TC_COMMON_API TaskContext GameObject* GetGameObject() const { return _contextGob; } private: - /// Asserts if the task was consumed already. void AssertOnConsumed() const; - - /// Invokes the associated hook of the task. void Invoke(); Unit* _contextUnit; diff --git a/src/common/Utilities/Types.h b/src/common/Utilities/Types.h new file mode 100644 index 00000000000..922be079de0 --- /dev/null +++ b/src/common/Utilities/Types.h @@ -0,0 +1,74 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef Types_h__ +#define Types_h__ + +#include + +namespace Trinity +{ + // end "iterator" tag for find_type_if + struct find_type_end; + + template typename Check, typename... Ts> + struct find_type_if; + + template typename Check> + struct find_type_if + { + using type = find_type_end; + }; + + template typename Check, typename T1, typename... Ts> + struct find_type_if : std::conditional_t::value, std::type_identity, find_type_if> + { + }; + + /* + Utility to find a type matching predicate (Check) in a given type list (Ts) + Evaluates to first type matching predicate or find_type_end + Check must be a type that contains static bool ::value, _v aliases don't work + + template + struct Example + { + using TupleArg = Trinity::find_type_if_t; + + bool HasTuple() + { + return !std::is_same_v; + } + }; + + Example, char> example; + example.HasTuple() == true; // TupleArg is std::tuple + + Example example2; + example2.HasTuple() == false; // TupleArg is Trinity::find_type_end + */ + template typename Check, typename... Ts> + using find_type_if_t = typename find_type_if::type; + + template + struct dependant_false { static constexpr bool value = false; }; + + template + constexpr bool dependant_false_v = dependant_false::value; +} + +#endif // Types_h__ diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index f34989c8546..34e38f314f7 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -31,6 +31,24 @@ #include #endif +std::vector Trinity::Tokenize(std::string_view str, char sep, bool keepEmpty) +{ + std::vector tokens; + + size_t start = 0; + for (size_t end = str.find(sep); end != std::string_view::npos; end = str.find(sep, start)) + { + if (keepEmpty || (start < end)) + tokens.push_back(str.substr(start, end - start)); + start = end+1; + } + + if (keepEmpty || (start < str.length())) + tokens.push_back(str.substr(start)); + + return tokens; +} + Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserve /*= 0*/, bool keepEmptyStrings /*= true*/) { m_str = new char[src.length() + 1]; @@ -66,6 +84,11 @@ Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserv } } +bool StringEqualI(std::string_view a, std::string_view b) +{ + return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); }); +} + void stripLineInvisibleChars(std::string &str) { static std::string const invChars = " \t\7\n"; diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index f6cd0f0646e..486829852c8 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -25,30 +25,42 @@ #include #include -class TC_COMMON_API Tokenizer +namespace Trinity +{ + TC_COMMON_API std::vector Tokenize(std::string_view str, char sep, bool keepEmpty); + + /* this would return string_view into temporary otherwise */ + std::vector Tokenize(std::string&&, char, bool) = delete; + std::vector Tokenize(std::string const&&, char, bool) = delete; + + /* the delete overload means we need to make this explicit */ + inline std::vector Tokenize(char const* str, char sep, bool keepEmpty) { return Tokenize(std::string_view(str ? str : ""), sep, keepEmpty); } +} + +TC_COMMON_API bool StringEqualI(std::string_view str1, std::string_view str2); + +class Tokenizer { public: typedef std::vector StorageType; - typedef StorageType::size_type size_type; - typedef StorageType::const_iterator const_iterator; typedef StorageType::reference reference; typedef StorageType::const_reference const_reference; -public: - Tokenizer(const std::string &src, char const sep, uint32 vectorReserve = 0, bool keepEmptyStrings = true); + Tokenizer(const std::string &src, char sep, uint32 vectorReserve = 0, bool keepEmptyStrings = true); ~Tokenizer() { delete[] m_str; } const_iterator begin() const { return m_storage.begin(); } const_iterator end() const { return m_storage.end(); } size_type size() const { return m_storage.size(); } + bool empty() const { return m_storage.empty(); } reference operator [] (size_type i) { return m_storage[i]; } const_reference operator [] (size_type i) const { return m_storage[i]; } -private: + private: char* m_str; StorageType m_storage; }; diff --git a/src/server/bnetserver/REST/LoginRESTService.cpp b/src/server/bnetserver/REST/LoginRESTService.cpp index d789ce6acac..f45edc59840 100644 --- a/src/server/bnetserver/REST/LoginRESTService.cpp +++ b/src/server/bnetserver/REST/LoginRESTService.cpp @@ -47,7 +47,7 @@ class AsyncRequest bool InvokeIfReady() { ASSERT(_callback); - return _callback->InvokeIfReady() == QueryCallback::Completed; + return _callback->InvokeIfReady(); } soap* GetClient() { return &_client; } @@ -83,10 +83,10 @@ bool LoginRESTService::Start(Trinity::Asio::IoContext* ioContext) } boost::system::error_code ec; - boost::asio::ip::tcp::resolver resolver(*ioContext); + Trinity::Asio::Resolver resolver(*ioContext); std::string configuredAddress = sConfigMgr->GetStringDefault("LoginREST.ExternalAddress", "127.0.0.1"); - Optional externalAddress = Trinity::Net::Resolve(resolver, boost::asio::ip::tcp::v4(), configuredAddress, std::to_string(_port)); + Optional externalAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), configuredAddress, std::to_string(_port)); if (!externalAddress) { TC_LOG_ERROR("server.rest", "Could not resolve LoginREST.ExternalAddress %s", configuredAddress.c_str()); @@ -96,7 +96,7 @@ bool LoginRESTService::Start(Trinity::Asio::IoContext* ioContext) _externalAddress = *externalAddress; configuredAddress = sConfigMgr->GetStringDefault("LoginREST.LocalAddress", "127.0.0.1"); - Optional localAddress = Trinity::Net::Resolve(resolver, boost::asio::ip::tcp::v4(), configuredAddress, std::to_string(_port)); + Optional localAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), configuredAddress, std::to_string(_port)); if (!localAddress) { TC_LOG_ERROR("server.rest", "Could not resolve LoginREST.LocalAddress %s", configuredAddress.c_str()); @@ -255,7 +255,7 @@ int32 LoginRESTService::HandleGetGameAccounts(std::shared_ptr requ return 401; request->SetCallback(Trinity::make_unique(LoginDatabase.AsyncQuery([&] { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_LIST); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_LIST); stmt->setString(0, request->GetClient()->userid); return stmt; }()) @@ -341,7 +341,7 @@ int32 LoginRESTService::HandlePostLogin(std::shared_ptr request) Utf8ToUpperOnlyLatin(login); Utf8ToUpperOnlyLatin(password); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_AUTHENTICATION); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_AUTHENTICATION); stmt->setString(0, login); std::string sentPasswordHash = CalculateShaPassHash(login, password); @@ -369,7 +369,7 @@ int32 LoginRESTService::HandlePostLogin(std::shared_ptr request) loginTicket = "TC-" + ByteArrayToHexStr(ticket.AsByteArray(20).get(), 20); } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_AUTHENTICATION); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_AUTHENTICATION); stmt->setString(0, loginTicket); stmt->setUInt32(1, time(nullptr) + _loginTicketDuration); stmt->setUInt32(2, accountId); @@ -392,8 +392,8 @@ int32 LoginRESTService::HandlePostLogin(std::shared_ptr request) if (maxWrongPassword) { - SQLTransaction trans = LoginDatabase.BeginTransaction(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); + LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); stmt->setUInt32(0, accountId); trans->Append(stmt); @@ -446,7 +446,7 @@ int32 LoginRESTService::HandlePostRefreshLoginTicket(std::shared_ptrSetCallback(Trinity::make_unique(LoginDatabase.AsyncQuery([&] { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_EXISTING_AUTHENTICATION); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_EXISTING_AUTHENTICATION); stmt->setString(0, request->GetClient()->userid); return stmt; }()) @@ -461,7 +461,7 @@ int32 LoginRESTService::HandlePostRefreshLoginTicket(std::shared_ptrsetUInt32(0, uint32(now + _loginTicketDuration)); stmt->setString(1, request->GetClient()->userid); LoginDatabase.Execute(stmt); diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 27e0be864bd..5586a6859fa 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -91,10 +91,10 @@ void Battlenet::Session::Start() // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); stmt->setString(0, ip_address); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1))); } void Battlenet::Session::CheckIpCallback(PreparedQueryResult result) @@ -126,7 +126,7 @@ bool Battlenet::Session::Update() if (!BattlenetSocket::Update()) return false; - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); return true; } @@ -253,12 +253,12 @@ uint32 Battlenet::Session::VerifyWebCredentials(std::string const& webCredential if (webCredentials.empty()) return ERROR_DENIED; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); stmt->setString(0, webCredentials); std::function asyncContinuation = std::move(continuation); std::shared_ptr accountInfo = std::make_shared(); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithChainingPreparedCallback([this, accountInfo, asyncContinuation](QueryCallback& callback, PreparedQueryResult result) + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithChainingPreparedCallback([this, accountInfo, asyncContinuation](QueryCallback& callback, PreparedQueryResult result) { Battlenet::Services::Authentication asyncContinuationService(this); NoData response; @@ -276,7 +276,7 @@ uint32 Battlenet::Session::VerifyWebCredentials(std::string const& webCredential return; } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_BNET_ID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_BNET_ID); stmt->setUInt32(0, accountInfo->Id); callback.SetNextQuery(LoginDatabase.AsyncQuery(stmt)); }) @@ -293,7 +293,7 @@ uint32 Battlenet::Session::VerifyWebCredentials(std::string const& webCredential } while (characterCountsResult->NextRow()); } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_LAST_PLAYER_CHARACTERS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_LAST_PLAYER_CHARACTERS); stmt->setUInt32(0, accountInfo->Id); callback.SetNextQuery(LoginDatabase.AsyncQuery(stmt)); }) @@ -536,7 +536,7 @@ uint32 Battlenet::Session::GetRealmListTicket(std::unordered_mapsetString(0, GetRemoteIpAddress().to_string()); stmt->setUInt8(1, GetLocaleByName(_locale)); stmt->setString(2, _os); diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 22b9e0a7b44..51c35180d78 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -18,13 +18,13 @@ #ifndef Session_h__ #define Session_h__ +#include "AsyncCallbackProcessor.h" #include "Realm.h" #include "SslContext.h" #include "SslSocket.h" #include "Socket.h" #include "BigNumber.h" #include "QueryResult.h" -#include "QueryCallbackProcessor.h" #include #include #include diff --git a/src/server/database/CMakeLists.txt b/src/server/database/CMakeLists.txt index 3605b498b50..6b510ef3bd3 100644 --- a/src/server/database/CMakeLists.txt +++ b/src/server/database/CMakeLists.txt @@ -50,9 +50,9 @@ add_definitions(-DTRINITY_API_EXPORT_DATABASE) target_link_libraries(database PRIVATE trinity-core-interface + mysql PUBLIC - common - mysql) + common) set_target_properties(database PROPERTIES diff --git a/src/server/database/Database/AdhocStatement.cpp b/src/server/database/Database/AdhocStatement.cpp index 3398255d21b..68c5e835b2c 100644 --- a/src/server/database/Database/AdhocStatement.cpp +++ b/src/server/database/Database/AdhocStatement.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -16,44 +16,23 @@ */ #include "AdhocStatement.h" -#include "Errors.h" #include "MySQLConnection.h" #include "QueryResult.h" -#include -#include /*! Basic, ad-hoc queries. */ -BasicStatementTask::BasicStatementTask(const char* sql, bool async) : -m_result(nullptr) +QueryResult BasicStatementTask::Query(MySQLConnection* conn, char const* sql) { - m_sql = strdup(sql); - m_has_result = async; // If the operation is async, then there's a result - if (async) - m_result = new QueryResultPromise(); -} + ResultSet* result = conn->Query(sql); + if (!result || !result->GetRowCount() || !result->NextRow()) + { + delete result; + result = nullptr; + } -BasicStatementTask::~BasicStatementTask() -{ - free((void*)m_sql); - if (m_has_result && m_result != nullptr) - delete m_result; + return QueryResult(result); } -bool BasicStatementTask::Execute() +bool BasicStatementTask::Execute(MySQLConnection* conn, char const* sql) { - if (m_has_result) - { - ResultSet* result = m_conn->Query(m_sql); - if (!result || !result->GetRowCount() || !result->NextRow()) - { - delete result; - m_result->set_value(QueryResult(NULL)); - return false; - } - - m_result->set_value(QueryResult(result)); - return true; - } - - return m_conn->Execute(m_sql); + return conn->Execute(sql); } diff --git a/src/server/database/Database/AdhocStatement.h b/src/server/database/Database/AdhocStatement.h index 010af3690d7..c74b15ccd97 100644 --- a/src/server/database/Database/AdhocStatement.h +++ b/src/server/database/Database/AdhocStatement.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,24 +18,17 @@ #ifndef _ADHOCSTATEMENT_H #define _ADHOCSTATEMENT_H -#include "Define.h" #include "DatabaseEnvFwd.h" -#include "SQLOperation.h" +#include "Define.h" + +class MySQLConnection; /*! Raw, ad-hoc query. */ -class TC_DATABASE_API BasicStatementTask : public SQLOperation +class TC_DATABASE_API BasicStatementTask { - public: - BasicStatementTask(const char* sql, bool async = false); - ~BasicStatementTask(); - - bool Execute() override; - QueryResultFuture GetFuture() const { return m_result->get_future(); } - - private: - const char* m_sql; //- Raw query to be executed - bool m_has_result; - QueryResultPromise* m_result; +public: + static QueryResult Query(MySQLConnection* conn, char const* sql); + static bool Execute(MySQLConnection* conn, char const* sql); }; #endif diff --git a/src/server/database/Database/DatabaseEnv.cpp b/src/server/database/Database/DatabaseEnv.cpp index 6b3a77c5138..0b2a83ae77f 100644 --- a/src/server/database/Database/DatabaseEnv.cpp +++ b/src/server/database/Database/DatabaseEnv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 diff --git a/src/server/database/Database/DatabaseEnv.h b/src/server/database/Database/DatabaseEnv.h index 54d19af0dcf..b481368b842 100644 --- a/src/server/database/Database/DatabaseEnv.h +++ b/src/server/database/Database/DatabaseEnv.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore - * Copyright (C) 2005-2009 MaNGOS + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -22,9 +21,9 @@ #include "Define.h" #include "DatabaseWorkerPool.h" -#include "Implementation/WorldDatabase.h" -#include "Implementation/CharacterDatabase.h" #include "Implementation/LoginDatabase.h" +#include "Implementation/CharacterDatabase.h" +#include "Implementation/WorldDatabase.h" #include "Implementation/HotfixDatabase.h" #include "Field.h" diff --git a/src/server/database/Database/DatabaseEnvFwd.h b/src/server/database/Database/DatabaseEnvFwd.h index 0e3482b638f..18c4216a193 100644 --- a/src/server/database/Database/DatabaseEnvFwd.h +++ b/src/server/database/Database/DatabaseEnvFwd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,37 +18,71 @@ #ifndef DatabaseEnvFwd_h__ #define DatabaseEnvFwd_h__ -#include #include +struct QueryResultFieldMetadata; class Field; class ResultSet; -typedef std::shared_ptr QueryResult; -typedef std::future QueryResultFuture; -typedef std::promise QueryResultPromise; +using QueryResult = std::shared_ptr; +class CharacterDatabaseConnection; +class HotfixDatabaseConnection; +class LoginDatabaseConnection; +class WorldDatabaseConnection; + +class PreparedStatementBase; + +template class PreparedStatement; +using CharacterDatabasePreparedStatement = PreparedStatement; +using HotfixDatabasePreparedStatement = PreparedStatement; +using LoginDatabasePreparedStatement = PreparedStatement; +using WorldDatabasePreparedStatement = PreparedStatement; + class PreparedResultSet; -typedef std::shared_ptr PreparedQueryResult; -typedef std::future PreparedQueryResultFuture; -typedef std::promise PreparedQueryResultPromise; +using PreparedQueryResult = std::shared_ptr; class QueryCallback; +template +class AsyncCallbackProcessor; + +using QueryCallbackProcessor = AsyncCallbackProcessor; + +class TransactionBase; + +template class Transaction; -typedef std::shared_ptr SQLTransaction; +class TransactionCallback; + +template +using SQLTransaction = std::shared_ptr>; + +using CharacterDatabaseTransaction = SQLTransaction; +using HotfixDatabaseTransaction = SQLTransaction; +using LoginDatabaseTransaction = SQLTransaction; +using WorldDatabaseTransaction = SQLTransaction; + +class SQLQueryHolderBase; + +template class SQLQueryHolder; -typedef std::future QueryResultHolderFuture; -typedef std::promise QueryResultHolderPromise; + +using CharacterDatabaseQueryHolder = SQLQueryHolder; +using HotfixDatabaseQueryHolder = SQLQueryHolder; +using LoginDatabaseQueryHolder = SQLQueryHolder; +using WorldDatabaseQueryHolder = SQLQueryHolder; + +class SQLQueryHolderCallback; // mysql -typedef struct st_mysql MYSQL; -typedef struct st_mysql_res MYSQL_RES; -typedef struct st_mysql_field MYSQL_FIELD; -typedef struct st_mysql_bind MYSQL_BIND; -typedef struct st_mysql_stmt MYSQL_STMT; +struct MySQLHandle; +struct MySQLResult; +struct MySQLField; +struct MySQLBind; +struct MySQLStmt; #endif // DatabaseEnvFwd_h__ diff --git a/src/server/database/Database/DatabaseLoader.cpp b/src/server/database/Database/DatabaseLoader.cpp index 2873199846a..eac5fe58a39 100644 --- a/src/server/database/Database/DatabaseLoader.cpp +++ b/src/server/database/Database/DatabaseLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -184,6 +184,6 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWor template TC_DATABASE_API DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); template TC_DATABASE_API -DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); -template TC_DATABASE_API DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); +template TC_DATABASE_API +DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); diff --git a/src/server/database/Database/DatabaseLoader.h b/src/server/database/Database/DatabaseLoader.h index 07490286cd6..2d527c5bb01 100644 --- a/src/server/database/Database/DatabaseLoader.h +++ b/src/server/database/Database/DatabaseLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -25,7 +25,7 @@ #include #include -template +template class DatabaseWorkerPool; // A helper class to initiate all database worker pools, diff --git a/src/server/database/Database/DatabaseWorker.cpp b/src/server/database/Database/DatabaseWorker.cpp deleted file mode 100644 index 781bd6450c6..00000000000 --- a/src/server/database/Database/DatabaseWorker.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * 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 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "DatabaseWorker.h" -#include "SQLOperation.h" -#include "ProducerConsumerQueue.h" - -DatabaseWorker::DatabaseWorker(ProducerConsumerQueue* newQueue, MySQLConnection* connection) -{ - _connection = connection; - _queue = newQueue; - _cancelationToken = false; - _workerThread = std::thread(&DatabaseWorker::WorkerThread, this); -} - -DatabaseWorker::~DatabaseWorker() -{ - _cancelationToken = true; - - _queue->Cancel(); - - _workerThread.join(); -} - -void DatabaseWorker::WorkerThread() -{ - if (!_queue) - return; - - for (;;) - { - SQLOperation* operation = nullptr; - - _queue->WaitAndPop(operation); - - if (_cancelationToken || !operation) - return; - - operation->SetConnection(_connection); - operation->call(); - - delete operation; - } -} diff --git a/src/server/database/Database/DatabaseWorker.h b/src/server/database/Database/DatabaseWorker.h deleted file mode 100644 index 4cfdd9630db..00000000000 --- a/src/server/database/Database/DatabaseWorker.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * 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 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef _WORKERTHREAD_H -#define _WORKERTHREAD_H - -#include "Define.h" -#include -#include - -template -class ProducerConsumerQueue; - -class MySQLConnection; -class SQLOperation; - -class TC_DATABASE_API DatabaseWorker -{ - public: - DatabaseWorker(ProducerConsumerQueue* newQueue, MySQLConnection* connection); - ~DatabaseWorker(); - - private: - ProducerConsumerQueue* _queue; - MySQLConnection* _connection; - - void WorkerThread(); - std::thread _workerThread; - - std::atomic _cancelationToken; - - DatabaseWorker(DatabaseWorker const& right) = delete; - DatabaseWorker& operator=(DatabaseWorker const& right) = delete; -}; - -#endif diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index 942954aca8b..ddd31b39d61 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -19,59 +19,121 @@ #include "AdhocStatement.h" #include "Common.h" #include "Errors.h" +#include "IoContext.h" #include "Implementation/LoginDatabase.h" #include "Implementation/WorldDatabase.h" #include "Implementation/CharacterDatabase.h" #include "Implementation/HotfixDatabase.h" #include "Log.h" +#include "MySQLPreparedStatement.h" #include "PreparedStatement.h" #include "ProducerConsumerQueue.h" #include "QueryCallback.h" #include "QueryHolder.h" #include "QueryResult.h" -#include "SQLOperation.h" #include "Transaction.h" -#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7 -#include -#endif -#include +#include "MySQLWorkaround.h" +#include #include +#include +#ifdef TRINITY_DEBUG +#include +#include +#endif + +#define MIN_MYSQL_SERVER_VERSION 50700u +#define MIN_MYSQL_SERVER_VERSION_STRING "5.7" +#define MIN_MYSQL_CLIENT_VERSION 50700u +#define MIN_MYSQL_CLIENT_VERSION_STRING "5.7" -#define MIN_MYSQL_SERVER_VERSION 50100u -#define MIN_MYSQL_CLIENT_VERSION 50100u +#define MIN_MARIADB_SERVER_VERSION 100209u +#define MIN_MARIADB_SERVER_VERSION_STRING "10.2.9" +#define MIN_MARIADB_CLIENT_VERSION 30003u +#define MIN_MARIADB_CLIENT_VERSION_STRING "3.0.3" -class PingOperation : public SQLOperation +namespace { - //! Operation for idle delaythreads - bool Execute() override +#ifdef TRINITY_DEBUG +template +thread_local bool WarnSyncQueries = false; +#endif +} + +template +struct DatabaseWorkerPool::QueueSizeTracker +{ + explicit QueueSizeTracker(DatabaseWorkerPool* pool) : _pool(pool) + { + ++_pool->_queueSize; + } + + QueueSizeTracker(QueueSizeTracker const& other) : _pool(other._pool) { ++_pool->_queueSize; } + QueueSizeTracker(QueueSizeTracker&& other) noexcept : _pool(std::exchange(other._pool, nullptr)) { } + + QueueSizeTracker& operator=(QueueSizeTracker const& other) + { + if (this != &other) + { + if (_pool != other._pool) + { + if (_pool) + --_pool->_queueSize; + if (other._pool) + ++other._pool->_queueSize; + } + _pool = other._pool; + } + return *this; + } + QueueSizeTracker& operator=(QueueSizeTracker&& other) noexcept + { + if (this != &other) + { + if (_pool != other._pool) + { + if (_pool) + --_pool->_queueSize; + } + _pool = std::exchange(other._pool, nullptr); + } + return *this; + } + + ~QueueSizeTracker() { - m_conn->Ping(); - return true; + if (_pool) + --_pool->_queueSize; } + +private: + DatabaseWorkerPool* _pool; }; template DatabaseWorkerPool::DatabaseWorkerPool() - : _queue(new ProducerConsumerQueue()), - _async_threads(0), _synch_threads(0) + : _async_threads(0), _synch_threads(0) { WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe."); - WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below 5.1"); - WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s) does not match the version used to compile TrinityCore (%s). Search on forum for TCE00011.", - mysql_get_client_info(), MYSQL_SERVER_VERSION); + +#if defined(LIBMARIADB) && MARIADB_PACKAGE_VERSION_ID >= 30200 + WPFatal(mysql_get_client_version() >= MIN_MARIADB_CLIENT_VERSION, "TrinityCore does not support MariaDB versions below " MIN_MARIADB_CLIENT_VERSION_STRING " (found %s id %lu, need id >= %u), please update your MariaDB client library", mysql_get_client_info(), mysql_get_client_version(), MIN_MARIADB_CLIENT_VERSION); + WPFatal(mysql_get_client_version() == MARIADB_PACKAGE_VERSION_ID, "Used MariaDB library version (%s id %lu) does not match the version id used to compile TrinityCore (id %u). Search on forum for TCE00011.", mysql_get_client_info(), mysql_get_client_version(), MARIADB_PACKAGE_VERSION_ID); +#else + WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below " MIN_MYSQL_CLIENT_VERSION_STRING " (found %s id %lu, need id >= %u), please update your MySQL client library", mysql_get_client_info(), mysql_get_client_version(), MIN_MYSQL_CLIENT_VERSION); + WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s id %lu) does not match the version id used to compile TrinityCore (id %u). Search on forum for TCE00011.", mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID); +#endif } template DatabaseWorkerPool::~DatabaseWorkerPool() { - _queue->Cancel(); } template void DatabaseWorkerPool::SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads) { - _connectionInfo = Trinity::make_unique(infoString); + _connectionInfo = std::make_unique(infoString); _async_threads = asyncThreads; _synch_threads = synchThreads; @@ -86,6 +148,8 @@ uint32 DatabaseWorkerPool::Open() "Asynchronous connections: %u, synchronous connections: %u.", GetDatabaseName(), _async_threads, _synch_threads); + _ioContext = std::make_unique(_async_threads); + uint32 error = OpenConnections(IDX_ASYNC, _async_threads); if (error) @@ -93,14 +157,17 @@ uint32 DatabaseWorkerPool::Open() error = OpenConnections(IDX_SYNCH, _synch_threads); - if (!error) - { - TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. " SZFMTD - " total connections running.", GetDatabaseName(), - (_connections[IDX_SYNCH].size() + _connections[IDX_ASYNC].size())); - } + if (error) + return error; + + for (std::unique_ptr const& connection : _connections[IDX_ASYNC]) + connection->StartWorkerThread(_ioContext.get()); + + TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. " + "%zu total connections running.", GetDatabaseName(), + (_connections[IDX_SYNCH].size() + _connections[IDX_ASYNC].size())); - return error; + return 0; } template @@ -108,9 +175,14 @@ void DatabaseWorkerPool::Close() { TC_LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName()); + if (_ioContext) + _ioContext->stop(); + //! Closes the actualy MySQL connection. _connections[IDX_ASYNC].clear(); + _ioContext.reset(); + TC_LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. " "Proceeding with synchronous connections.", GetDatabaseName()); @@ -128,6 +200,7 @@ template bool DatabaseWorkerPool::PrepareStatements() { for (auto& connections : _connections) + { for (auto& connection : connections) { connection->LockIfReady(); @@ -139,85 +212,100 @@ bool DatabaseWorkerPool::PrepareStatements() } else connection->Unlock(); + + size_t const preparedSize = connection->m_stmts.size(); + if (_preparedStatementSize.size() < preparedSize) + _preparedStatementSize.resize(preparedSize); + + for (size_t i = 0; i < preparedSize; ++i) + { + // already set by another connection + // (each connection only has prepared statements of it's own type sync/async) + if (_preparedStatementSize[i] > 0) + continue; + + if (MySQLPreparedStatement * stmt = connection->m_stmts[i].get()) + { + uint32 const paramCount = stmt->GetParameterCount(); + + // TC only supports uint8 indices. + ASSERT(paramCount < std::numeric_limits::max()); + + _preparedStatementSize[i] = static_cast(paramCount); + } + } } + } return true; } template -QueryResult DatabaseWorkerPool::Query(const char* sql, T* connection /*= nullptr*/) +QueryResult DatabaseWorkerPool::Query(char const* sql, T* connection /*= nullptr*/) { if (!connection) connection = GetFreeConnection(); - ResultSet* result = connection->Query(sql); + QueryResult result = BasicStatementTask::Query(connection, sql); connection->Unlock(); - if (!result || !result->GetRowCount() || !result->NextRow()) - { - delete result; - return QueryResult(NULL); - } - return QueryResult(result); + return result; } template -PreparedQueryResult DatabaseWorkerPool::Query(PreparedStatement* stmt) +PreparedQueryResult DatabaseWorkerPool::Query(PreparedStatement* stmt) { - auto connection = GetFreeConnection(); - PreparedResultSet* ret = connection->Query(stmt); + T* connection = GetFreeConnection(); + PreparedQueryResult ret = PreparedStatementTask::Query(connection, stmt); connection->Unlock(); //! Delete proxy-class. Not needed anymore delete stmt; - if (!ret || !ret->GetRowCount()) - { - delete ret; - return PreparedQueryResult(NULL); - } - - return PreparedQueryResult(ret); + return ret; } template -QueryCallback DatabaseWorkerPool::AsyncQuery(const char* sql) +QueryCallback DatabaseWorkerPool::AsyncQuery(char const* sql) { - BasicStatementTask* task = new BasicStatementTask(sql, true); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - QueryResultFuture result = task->GetFuture(); - Enqueue(task); + std::future result = boost::asio::post(_ioContext->get_executor(), boost::asio::use_future([this, sql = std::string(sql), tracker = QueueSizeTracker(this)] + { + T* conn = GetAsyncConnectionForCurrentThread(); + return BasicStatementTask::Query(conn, sql.c_str()); + })); return QueryCallback(std::move(result)); } template -QueryCallback DatabaseWorkerPool::AsyncQuery(PreparedStatement* stmt) +QueryCallback DatabaseWorkerPool::AsyncQuery(PreparedStatement* stmt) { - PreparedStatementTask* task = new PreparedStatementTask(stmt, true); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - PreparedQueryResultFuture result = task->GetFuture(); - Enqueue(task); + std::future result = boost::asio::post(_ioContext->get_executor(), boost::asio::use_future([this, stmt = std::unique_ptr>(stmt), tracker = QueueSizeTracker(this)] + { + T* conn = GetAsyncConnectionForCurrentThread(); + return PreparedStatementTask::Query(conn, stmt.get()); + })); return QueryCallback(std::move(result)); } template -QueryResultHolderFuture DatabaseWorkerPool::DelayQueryHolder(SQLQueryHolder* holder) +SQLQueryHolderCallback DatabaseWorkerPool::DelayQueryHolder(std::shared_ptr> holder) { - SQLQueryHolderTask* task = new SQLQueryHolderTask(holder); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - QueryResultHolderFuture result = task->GetFuture(); - Enqueue(task); - return result; + std::future result = boost::asio::post(_ioContext->get_executor(), boost::asio::use_future([this, holder, tracker = QueueSizeTracker(this)] + { + T* conn = GetAsyncConnectionForCurrentThread(); + SQLQueryHolderTask::Execute(conn, holder.get()); + })); + return { std::move(holder), std::move(result) }; } template -SQLTransaction DatabaseWorkerPool::BeginTransaction() +SQLTransaction DatabaseWorkerPool::BeginTransaction() { - return std::make_shared(); + return std::make_shared>(); } template -void DatabaseWorkerPool::CommitTransaction(SQLTransaction transaction) +void DatabaseWorkerPool::CommitTransaction(SQLTransaction transaction) { #ifdef TRINITY_DEBUG //! Only analyze transaction weaknesses in Debug mode. @@ -236,11 +324,43 @@ void DatabaseWorkerPool::CommitTransaction(SQLTransaction transaction) } #endif // TRINITY_DEBUG - Enqueue(new TransactionTask(transaction)); + boost::asio::post(_ioContext->get_executor(), [this, transaction, tracker = QueueSizeTracker(this)] + { + T* conn = GetAsyncConnectionForCurrentThread(); + TransactionTask::Execute(conn, transaction); + }); +} + +template +TransactionCallback DatabaseWorkerPool::AsyncCommitTransaction(SQLTransaction transaction) +{ +#ifdef TRINITY_DEBUG + //! Only analyze transaction weaknesses in Debug mode. + //! Ideally we catch the faults in Debug mode and then correct them, + //! so there's no need to waste these CPU cycles in Release mode. + switch (transaction->GetSize()) + { + case 0: + TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing."); + break; + case 1: + TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code."); + break; + default: + break; + } +#endif // TRINITY_DEBUG + + std::future result = boost::asio::post(_ioContext->get_executor(), boost::asio::use_future([this, transaction, tracker = QueueSizeTracker(this)] + { + T* conn = GetAsyncConnectionForCurrentThread(); + return TransactionTask::Execute(conn, transaction); + })); + return TransactionCallback(std::move(result)); } template -void DatabaseWorkerPool::DirectCommitTransaction(SQLTransaction& transaction) +void DatabaseWorkerPool::DirectCommitTransaction(SQLTransaction& transaction) { T* connection = GetFreeConnection(); int errorCode = connection->ExecuteTransaction(transaction); @@ -254,6 +374,7 @@ void DatabaseWorkerPool::DirectCommitTransaction(SQLTransaction& transaction) /// @todo More elegant way if (errorCode == ER_LOCK_DEADLOCK) { + //todo: handle multiple sync threads deadlocking in a similar way as async threads uint8 loopBreaker = 5; for (uint8 i = 0; i < loopBreaker; ++i) { @@ -269,9 +390,9 @@ void DatabaseWorkerPool::DirectCommitTransaction(SQLTransaction& transaction) } template -PreparedStatement* DatabaseWorkerPool::GetPreparedStatement(PreparedStatementIndex index) +PreparedStatement* DatabaseWorkerPool::GetPreparedStatement(PreparedStatementIndex index) { - return new PreparedStatement(index); + return new PreparedStatement(index, _preparedStatementSize[index]); } template @@ -304,26 +425,32 @@ void DatabaseWorkerPool::KeepAlive() //! as the sole purpose is to prevent connections from idling. auto const count = _connections[IDX_ASYNC].size(); for (uint8 i = 0; i < count; ++i) - Enqueue(new PingOperation); + { + boost::asio::post(_ioContext->get_executor(), [this, tracker = QueueSizeTracker(this)] + { + T* conn = GetAsyncConnectionForCurrentThread(); + conn->Ping(); + }); + } } +#ifdef TRINITY_DEBUG +template +void DatabaseWorkerPool::WarnAboutSyncQueries([[maybe_unused]] bool warn) +{ + WarnSyncQueries = warn; +} +#endif + template uint32 DatabaseWorkerPool::OpenConnections(InternalIndex type, uint8 numConnections) { for (uint8 i = 0; i < numConnections; ++i) { // Create the connection - auto connection = [&] { - switch (type) - { - case IDX_ASYNC: - return Trinity::make_unique(_queue.get(), *_connectionInfo); - case IDX_SYNCH: - return Trinity::make_unique(*_connectionInfo); - default: - ABORT(); - } - }(); + constexpr std::array flags = { { CONNECTION_ASYNC, CONNECTION_SYNCH } }; + + std::unique_ptr connection = std::make_unique(*_connectionInfo, flags[type]); if (uint32 error = connection->Open()) { @@ -331,9 +458,18 @@ uint32 DatabaseWorkerPool::OpenConnections(InternalIndex type, uint8 numConne _connections[type].clear(); return error; } - else if (mysql_get_server_version(connection->GetHandle()) < MIN_MYSQL_SERVER_VERSION) +#ifndef LIBMARIADB + else if (connection->GetServerVersion() < MIN_MYSQL_SERVER_VERSION) +#else + else if (connection->GetServerVersion() < MIN_MARIADB_SERVER_VERSION) +#endif { - TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1"); +#ifndef LIBMARIADB + TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below " MIN_MYSQL_SERVER_VERSION_STRING " (found id %u, need id >= %u), please update your MySQL server", connection->GetServerVersion(), MIN_MYSQL_SERVER_VERSION); +#else + TC_LOG_ERROR("sql.driver", "TrinityCore does not support MariaDB versions below " MIN_MARIADB_SERVER_VERSION_STRING " (found id %u, need id >= %u), please update your MySQL server", connection->GetServerVersion(), MIN_MARIADB_SERVER_VERSION); +#endif + return 1; } else @@ -347,24 +483,32 @@ uint32 DatabaseWorkerPool::OpenConnections(InternalIndex type, uint8 numConne } template -unsigned long DatabaseWorkerPool::EscapeString(char *to, const char *from, unsigned long length) +unsigned long DatabaseWorkerPool::EscapeString(char* to, char const* from, unsigned long length) { if (!to || !from || !length) return 0; - return mysql_real_escape_string( - _connections[IDX_SYNCH].front()->GetHandle(), to, from, length); + return _connections[IDX_SYNCH].front()->EscapeString(to, from, length); } template -void DatabaseWorkerPool::Enqueue(SQLOperation* op) +size_t DatabaseWorkerPool::QueueSize() const { - _queue->Push(op); + return _queueSize; } template T* DatabaseWorkerPool::GetFreeConnection() { +#ifdef TRINITY_DEBUG + if (WarnSyncQueries) + { + std::ostringstream ss; + ss << boost::stacktrace::stacktrace(); + TC_LOG_WARN("sql.performances", "Sync query at:\n%s", ss.str()); + } +#endif + uint8 i = 0; auto const num_cons = _connections[IDX_SYNCH].size(); T* connection = nullptr; @@ -380,6 +524,17 @@ T* DatabaseWorkerPool::GetFreeConnection() return connection; } +template +T* DatabaseWorkerPool::GetAsyncConnectionForCurrentThread() const +{ + std::thread::id id = std::this_thread::get_id(); + for (auto&& connection : _connections[IDX_ASYNC]) + if (connection->GetWorkerThreadId() == id) + return connection.get(); + + return nullptr; +} + template char const* DatabaseWorkerPool::GetDatabaseName() const { @@ -387,38 +542,44 @@ char const* DatabaseWorkerPool::GetDatabaseName() const } template -void DatabaseWorkerPool::Execute(const char* sql) +void DatabaseWorkerPool::Execute(char const* sql) { - if (Trinity::IsFormatEmptyOrNull(sql)) + if (!sql) return; - BasicStatementTask* task = new BasicStatementTask(sql); - Enqueue(task); + boost::asio::post(_ioContext->get_executor(), [this, sql = std::string(sql), tracker = QueueSizeTracker(this)] + { + T* conn = GetAsyncConnectionForCurrentThread(); + BasicStatementTask::Execute(conn, sql.c_str()); + }); } template -void DatabaseWorkerPool::Execute(PreparedStatement* stmt) +void DatabaseWorkerPool::Execute(PreparedStatement* stmt) { - PreparedStatementTask* task = new PreparedStatementTask(stmt); - Enqueue(task); + boost::asio::post(_ioContext->get_executor(), [this, stmt = std::unique_ptr>(stmt), tracker = QueueSizeTracker(this)] + { + T* conn = GetAsyncConnectionForCurrentThread(); + PreparedStatementTask::Execute(conn, stmt.get()); + }); } template -void DatabaseWorkerPool::DirectExecute(const char* sql) +void DatabaseWorkerPool::DirectExecute(char const* sql) { - if (Trinity::IsFormatEmptyOrNull(sql)) + if (!sql) return; T* connection = GetFreeConnection(); - connection->Execute(sql); + BasicStatementTask::Execute(connection, sql); connection->Unlock(); } template -void DatabaseWorkerPool::DirectExecute(PreparedStatement* stmt) +void DatabaseWorkerPool::DirectExecute(PreparedStatement* stmt) { T* connection = GetFreeConnection(); - connection->Execute(stmt); + PreparedStatementTask::Execute(connection, stmt); connection->Unlock(); //! Delete proxy-class. Not needed anymore @@ -426,7 +587,7 @@ void DatabaseWorkerPool::DirectExecute(PreparedStatement* stmt) } template -void DatabaseWorkerPool::ExecuteOrAppend(SQLTransaction& trans, const char* sql) +void DatabaseWorkerPool::ExecuteOrAppend(SQLTransaction& trans, char const* sql) { if (!trans) Execute(sql); @@ -435,7 +596,7 @@ void DatabaseWorkerPool::ExecuteOrAppend(SQLTransaction& trans, const char* s } template -void DatabaseWorkerPool::ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt) +void DatabaseWorkerPool::ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt) { if (!trans) Execute(stmt); diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index a1a3469e725..69de682d720 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,17 +18,16 @@ #ifndef _DATABASEWORKERPOOL_H #define _DATABASEWORKERPOOL_H +#include "AsioHacksFwd.h" #include "Define.h" #include "DatabaseEnvFwd.h" +#include "IoContext.h" #include "StringFormat.h" #include +#include #include #include -template -class ProducerConsumerQueue; - -class SQLOperation; struct MySQLConnectionInfo; template @@ -68,22 +67,22 @@ class DatabaseWorkerPool //! Enqueues a one-way SQL operation in string format that will be executed asynchronously. //! This method should only be used for queries that are only executed once, e.g during startup. - void Execute(const char* sql); + void Execute(char const* sql); //! Enqueues a one-way SQL operation in string format -with variable args- that will be executed asynchronously. //! This method should only be used for queries that are only executed once, e.g during startup. - template - void PExecute(Format&& sql, Args&&... args) + template + void PExecute(std::string_view sql, Args&&... args) { if (Trinity::IsFormatEmptyOrNull(sql)) return; - Execute(Trinity::StringFormat(std::forward(sql), std::forward(args)...).c_str()); + Execute(Trinity::StringFormat(sql, std::forward(args)...).c_str()); } //! Enqueues a one-way SQL operation in prepared statement format that will be executed asynchronously. //! Statement must be prepared with CONNECTION_ASYNC flag. - void Execute(PreparedStatement* stmt); + void Execute(PreparedStatement* stmt); /** Direct synchronous one-way statement methods. @@ -91,22 +90,22 @@ class DatabaseWorkerPool //! Directly executes a one-way SQL operation in string format, that will block the calling thread until finished. //! This method should only be used for queries that are only executed once, e.g during startup. - void DirectExecute(const char* sql); + void DirectExecute(char const* sql); //! Directly executes a one-way SQL operation in string format -with variable args-, that will block the calling thread until finished. //! This method should only be used for queries that are only executed once, e.g during startup. - template - void DirectPExecute(Format&& sql, Args&&... args) + template + void DirectPExecute(std::string_view sql, Args&&... args) { if (Trinity::IsFormatEmptyOrNull(sql)) return; - DirectExecute(Trinity::StringFormat(std::forward(sql), std::forward(args)...).c_str()); + DirectExecute(Trinity::StringFormat(sql, std::forward(args)...).c_str()); } //! Directly executes a one-way SQL operation in prepared statement format, that will block the calling thread until finished. //! Statement must be prepared with the CONNECTION_SYNCH flag. - void DirectExecute(PreparedStatement* stmt); + void DirectExecute(PreparedStatement* stmt); /** Synchronous query (with resultset) methods. @@ -114,34 +113,34 @@ class DatabaseWorkerPool //! Directly executes an SQL query in string format that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. - QueryResult Query(const char* sql, T* connection = nullptr); + QueryResult Query(char const* sql, T* connection = nullptr); //! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. - template - QueryResult PQuery(Format&& sql, T* conn, Args&&... args) + template + QueryResult PQuery(std::string_view sql, T* conn, Args&&... args) { if (Trinity::IsFormatEmptyOrNull(sql)) return QueryResult(nullptr); - return Query(Trinity::StringFormat(std::forward(sql), std::forward(args)...).c_str(), conn); + return Query(Trinity::StringFormat(sql, std::forward(args)...).c_str(), conn); } //! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. - template - QueryResult PQuery(Format&& sql, Args&&... args) + template + QueryResult PQuery(std::string_view sql, Args&&... args) { if (Trinity::IsFormatEmptyOrNull(sql)) return QueryResult(nullptr); - return Query(Trinity::StringFormat(std::forward(sql), std::forward(args)...).c_str()); + return Query(Trinity::StringFormat(sql, std::forward(args)...).c_str()); } //! Directly executes an SQL query in prepared format that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. //! Statement must be prepared with CONNECTION_SYNCH flag. - PreparedQueryResult Query(PreparedStatement* stmt); + PreparedQueryResult Query(PreparedStatement* stmt); /** Asynchronous query (with resultset) methods. @@ -149,41 +148,45 @@ class DatabaseWorkerPool //! Enqueues a query in string format that will set the value of the QueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. - QueryCallback AsyncQuery(const char* sql); + QueryCallback AsyncQuery(char const* sql); //! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. //! Statement must be prepared with CONNECTION_ASYNC flag. - QueryCallback AsyncQuery(PreparedStatement* stmt); + QueryCallback AsyncQuery(PreparedStatement* stmt); //! Enqueues a vector of SQL operations (can be both adhoc and prepared) that will set the value of the QueryResultHolderFuture //! return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. //! Any prepared statements added to this holder need to be prepared with the CONNECTION_ASYNC flag. - QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder); + SQLQueryHolderCallback DelayQueryHolder(std::shared_ptr> holder); /** Transaction context methods. */ //! Begins an automanaged transaction pointer that will automatically rollback if not commited. (Autocommit=0) - SQLTransaction BeginTransaction(); + SQLTransaction BeginTransaction(); //! Enqueues a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations //! were appended to the transaction will be respected during execution. - void CommitTransaction(SQLTransaction transaction); + void CommitTransaction(SQLTransaction transaction); + + //! Enqueues a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations + //! were appended to the transaction will be respected during execution. + TransactionCallback AsyncCommitTransaction(SQLTransaction transaction); //! Directly executes a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations //! were appended to the transaction will be respected during execution. - void DirectCommitTransaction(SQLTransaction& transaction); + void DirectCommitTransaction(SQLTransaction& transaction); //! Method used to execute ad-hoc statements in a diverse context. //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. - void ExecuteOrAppend(SQLTransaction& trans, const char* sql); + void ExecuteOrAppend(SQLTransaction& trans, char const* sql); //! Method used to execute prepared statements in a diverse context. //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. - void ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt); + void ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt); /** Other @@ -194,7 +197,7 @@ class DatabaseWorkerPool //! Automanaged (internally) pointer to a prepared statement object for usage in upper level code. //! Pointer is deleted in this->DirectExecute(PreparedStatement*), this->Query(PreparedStatement*) or PreparedStatementTask::~PreparedStatementTask. //! This object is not tied to the prepared statement on the MySQL context yet until execution. - PreparedStatement* GetPreparedStatement(PreparedStatementIndex index); + PreparedStatement* GetPreparedStatement(PreparedStatementIndex index); //! Apply escape string'ing for current collation. (utf8) void EscapeString(std::string& str); @@ -202,23 +205,36 @@ class DatabaseWorkerPool //! Keeps all our MySQL connections alive, prevent the server from disconnecting us. void KeepAlive(); +#ifdef TRINITY_DEBUG + static void WarnAboutSyncQueries(bool warn); +#else + static void WarnAboutSyncQueries([[maybe_unused]] bool warn) { } +#endif + + size_t QueueSize() const; + private: uint32 OpenConnections(InternalIndex type, uint8 numConnections); - unsigned long EscapeString(char *to, const char *from, unsigned long length); - - void Enqueue(SQLOperation* op); + unsigned long EscapeString(char* to, char const* from, unsigned long length); //! Gets a free connection in the synchronous connection pool. //! Caller MUST call t->Unlock() after touching the MySQL context to prevent deadlocks. T* GetFreeConnection(); + T* GetAsyncConnectionForCurrentThread() const; + char const* GetDatabaseName() const; + struct QueueSizeTracker; + friend QueueSizeTracker; + //! Queue shared by async worker threads. - std::unique_ptr> _queue; + std::unique_ptr _ioContext; + std::atomic _queueSize; std::array>, IDX_SIZE> _connections; std::unique_ptr _connectionInfo; + std::vector _preparedStatementSize; uint8 _async_threads, _synch_threads; }; diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp index 1e97d6d3c96..664090839c0 100644 --- a/src/server/database/Database/Field.cpp +++ b/src/server/database/Database/Field.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -16,335 +16,161 @@ */ #include "Field.h" -#include "Log.h" +#include "Errors.h" +#include "FieldValueConverter.h" +#include -Field::Field() +Field::Field() : _value(nullptr), _length(0), _meta(nullptr) { - data.value = NULL; - data.type = DatabaseFieldTypes::Null; - data.length = 0; - data.raw = false; } -Field::~Field() -{ - CleanUp(); -} +Field::~Field() = default; uint8 Field::GetUInt8() const { - if (!data.value) - return 0; - -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Int8)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(strtoul((char*)data.value, nullptr, 10)); + return _meta->Converter->GetUInt8(_value, _length, _meta); } int8 Field::GetInt8() const { - if (!data.value) - return 0; - -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Int8)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(strtol((char*)data.value, NULL, 10)); + return _meta->Converter->GetInt8(_value, _length, _meta); } uint16 Field::GetUInt16() const { - if (!data.value) + if (!_value) return 0; -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Int16)) - { - LogWrongType(__FUNCTION__); - return 0; - } -#endif - - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(strtoul((char*)data.value, nullptr, 10)); + return _meta->Converter->GetUInt16(_value, _length, _meta); } int16 Field::GetInt16() const { - if (!data.value) - return 0; - -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Int16)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(strtol((char*)data.value, NULL, 10)); + return _meta->Converter->GetInt16(_value, _length, _meta); } uint32 Field::GetUInt32() const { - if (!data.value) - return 0; - -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Int32)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(strtoul((char*)data.value, nullptr, 10)); + return _meta->Converter->GetUInt32(_value, _length, _meta); } int32 Field::GetInt32() const { - if (!data.value) + if (!_value) return 0; -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Int32)) - { - LogWrongType(__FUNCTION__); - return 0; - } -#endif - - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(strtol((char*)data.value, NULL, 10)); + return _meta->Converter->GetInt32(_value, _length, _meta); } uint64 Field::GetUInt64() const { - if (!data.value) - return 0; - -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Int64)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(strtoull((char*)data.value, nullptr, 10)); + return _meta->Converter->GetUInt64(_value, _length, _meta); } int64 Field::GetInt64() const { - if (!data.value) - return 0; - -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Int64)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(strtoll((char*)data.value, NULL, 10)); + return _meta->Converter->GetInt64(_value, _length, _meta); } float Field::GetFloat() const { - if (!data.value) + if (!_value) return 0.0f; -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Float)) - { - LogWrongType(__FUNCTION__); - return 0.0f; - } -#endif - - if (data.raw) - return *reinterpret_cast(data.value); - return static_cast(atof((char*)data.value)); + return _meta->Converter->GetFloat(_value, _length, _meta); } double Field::GetDouble() const { - if (!data.value) - return 0.0f; + if (!_value) + return 0.0; -#ifdef TRINITY_DEBUG - if (!IsType(DatabaseFieldTypes::Double) && !IsType(DatabaseFieldTypes::Decimal)) - { - LogWrongType(__FUNCTION__); - return 0.0f; - } -#endif + return _meta->Converter->GetDouble(_value, _length, _meta); +} - if (data.raw && !IsType(DatabaseFieldTypes::Decimal)) - return *reinterpret_cast(data.value); - return static_cast(atof((char*)data.value)); +SystemTimePoint Field::GetDate() const +{ + if (!_value) + return SystemTimePoint::min(); + + return _meta->Converter->GetDate(_value, _length, _meta); } char const* Field::GetCString() const { - if (!data.value) - return NULL; - -#ifdef TRINITY_DEBUG - if (IsNumeric() && data.raw) - { - LogWrongType(__FUNCTION__); - return NULL; - } -#endif - return static_cast(data.value); + if (!_value) + return nullptr; + + return _meta->Converter->GetCString(_value, _length, _meta); } std::string Field::GetString() const { - if (!data.value) + if (!_value) return ""; char const* string = GetCString(); if (!string) return ""; - return std::string(string, data.length); + return std::string(string, _length); } -std::vector Field::GetBinary() const +std::string_view Field::GetStringView() const { - std::vector result; - if (!data.value || !data.length) - return result; + if (!_value) + return {}; - result.resize(data.length); - memcpy(result.data(), data.value, data.length); - return result; -} - -void Field::SetByteValue(void* newValue, DatabaseFieldTypes newType, uint32 length) -{ - // This value stores raw bytes that have to be explicitly cast later - data.value = newValue; - data.length = length; - data.type = newType; - data.raw = true; -} + char const* const string = GetCString(); + if (!string) + return {}; -void Field::SetStructuredValue(char* newValue, DatabaseFieldTypes newType, uint32 length) -{ - if (data.value) - CleanUp(); - - // This value stores somewhat structured data that needs function style casting - if (newValue) - { - data.value = new char[length + 1]; - memcpy(data.value, newValue, length); - *(reinterpret_cast(data.value) + length) = '\0'; - data.length = length; - } - - data.type = newType; - data.raw = false; + return { string, _length }; } -bool Field::IsType(DatabaseFieldTypes type) const +std::vector Field::GetBinary() const { - return data.type == type; -} + std::vector result; + if (!_value || !_length) + return result; -bool Field::IsNumeric() const -{ - return (data.type == DatabaseFieldTypes::Int8 || - data.type == DatabaseFieldTypes::Int16 || - data.type == DatabaseFieldTypes::Int32 || - data.type == DatabaseFieldTypes::Int64 || - data.type == DatabaseFieldTypes::Float || - data.type == DatabaseFieldTypes::Double); + result.resize(_length); + memcpy(result.data(), _value, _length); + return result; } -#ifdef TRINITY_DEBUG - -void Field::LogWrongType(char const* getter) const +void Field::GetBinarySizeChecked(uint8* buf, size_t length) const { - TC_LOG_WARN("sql.sql", "Warning: %s on %s field %s.%s (%s.%s) at index %u.", - getter, meta.Type, meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index); + ASSERT(_value && (_length == length), "Expected %zu-byte binary blob, got %sdata (%u bytes) instead", length, _value ? "" : "no ", _length); + memcpy(buf, _value, length); } -#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7 -#include -#endif -#include - -static char const* FieldTypeToString(enum_field_types type) +void Field::SetValue(char const* newValue, uint32 length) { - switch (type) - { - case MYSQL_TYPE_BIT: return "BIT"; - case MYSQL_TYPE_BLOB: return "BLOB"; - case MYSQL_TYPE_DATE: return "DATE"; - case MYSQL_TYPE_DATETIME: return "DATETIME"; - case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL"; - case MYSQL_TYPE_DECIMAL: return "DECIMAL"; - case MYSQL_TYPE_DOUBLE: return "DOUBLE"; - case MYSQL_TYPE_ENUM: return "ENUM"; - case MYSQL_TYPE_FLOAT: return "FLOAT"; - case MYSQL_TYPE_GEOMETRY: return "GEOMETRY"; - case MYSQL_TYPE_INT24: return "INT24"; - case MYSQL_TYPE_LONG: return "LONG"; - case MYSQL_TYPE_LONGLONG: return "LONGLONG"; - case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB"; - case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB"; - case MYSQL_TYPE_NEWDATE: return "NEWDATE"; - case MYSQL_TYPE_NULL: return "NULL"; - case MYSQL_TYPE_SET: return "SET"; - case MYSQL_TYPE_SHORT: return "SHORT"; - case MYSQL_TYPE_STRING: return "STRING"; - case MYSQL_TYPE_TIME: return "TIME"; - case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP"; - case MYSQL_TYPE_TINY: return "TINY"; - case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB"; - case MYSQL_TYPE_VAR_STRING: return "VAR_STRING"; - case MYSQL_TYPE_YEAR: return "YEAR"; - default: return "-Unknown-"; - } + // This value stores raw bytes that have to be explicitly cast later + _value = newValue; + _length = length; } -void Field::SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex) +void Field::SetMetadata(QueryResultFieldMetadata const* meta) { - meta.TableName = field->org_table; - meta.TableAlias = field->table; - meta.Name = field->org_name; - meta.Alias = field->name; - meta.Type = FieldTypeToString(field->type); - meta.Index = fieldIndex; + _meta = meta; } -#endif diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h index a106b34e969..1d28d8cf713 100644 --- a/src/server/database/Database/Field.h +++ b/src/server/database/Database/Field.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -15,27 +15,49 @@ * with this program. If not, see . */ -#ifndef _FIELD_H -#define _FIELD_H +#ifndef TRINITY_DATABASE_FIELD_H +#define TRINITY_DATABASE_FIELD_H #include "Define.h" -#include "DatabaseEnvFwd.h" +#include "Duration.h" +#include +#include +#include #include +class BaseDatabaseResultValueConverter; + enum class DatabaseFieldTypes : uint8 { Null, + UInt8, Int8, + UInt16, Int16, + UInt32, Int32, + UInt64, Int64, Float, Double, Decimal, Date, + Time, Binary }; +struct QueryResultFieldMetadata +{ + char const* TableName = nullptr; + char const* TableAlias = nullptr; + char const* Name = nullptr; + char const* Alias = nullptr; + char const* TypeName = nullptr; + uint32 Index = 0; + DatabaseFieldTypes Type = DatabaseFieldTypes::Null; + BaseDatabaseResultValueConverter const* Converter = nullptr; +}; + /** @class Field @@ -90,57 +112,34 @@ class TC_DATABASE_API Field int64 GetInt64() const; float GetFloat() const; double GetDouble() const; + SystemTimePoint GetDate() const; char const* GetCString() const; std::string GetString() const; + std::string_view GetStringView() const; std::vector GetBinary() const; - - bool IsNull() const + template + std::array GetBinary() const { - return data.value == NULL; + std::array buf; + GetBinarySizeChecked(buf.data(), S); + return buf; } - struct Metadata - { - char const* TableName; - char const* TableAlias; - char const* Name; - char const* Alias; - char const* Type; - uint32 Index; - }; - - protected: - #pragma pack(push, 1) - struct - { - uint32 length; // Length (prepared strings only) - void* value; // Actual data in memory - DatabaseFieldTypes type; // Field type - bool raw; // Raw bytes? (Prepared statement or ad hoc) - } data; - #pragma pack(pop) - - void SetByteValue(void* newValue, DatabaseFieldTypes newType, uint32 length); - void SetStructuredValue(char* newValue, DatabaseFieldTypes newType, uint32 length); - - void CleanUp() + bool IsNull() const { - // Field does not own the data if fetched with prepared statement - if (!data.raw) - delete[] ((char*)data.value); - data.value = NULL; + return _value == nullptr; } - bool IsType(DatabaseFieldTypes type) const; + private: + char const* _value; // Actual data in memory + uint32 _length; // Length - bool IsNumeric() const; + void SetValue(char const* newValue, uint32 length); - private: - #ifdef TRINITY_DEBUG - void LogWrongType(char const* getter) const; - void SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex); - Metadata meta; - #endif + QueryResultFieldMetadata const* _meta; + void SetMetadata(QueryResultFieldMetadata const* meta); + + void GetBinarySizeChecked(uint8* buf, size_t size) const; }; #endif diff --git a/src/server/database/Database/FieldValueConverter.cpp b/src/server/database/Database/FieldValueConverter.cpp new file mode 100644 index 00000000000..6e36c1c8703 --- /dev/null +++ b/src/server/database/Database/FieldValueConverter.cpp @@ -0,0 +1,50 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "FieldValueConverter.h" +#include "Errors.h" +#include "Field.h" + +BaseDatabaseResultValueConverter::BaseDatabaseResultValueConverter() = default; +BaseDatabaseResultValueConverter::~BaseDatabaseResultValueConverter() = default; + +void BaseDatabaseResultValueConverter::LogTruncation(char const* getter, QueryResultFieldMetadata const* meta) +{ + char const* expectedAccessor = ""; + switch (meta->Type) + { + case DatabaseFieldTypes::UInt8: expectedAccessor = "Field::GetUInt8"; break; + case DatabaseFieldTypes::Int8: expectedAccessor = "Field::GetInt8"; break; + case DatabaseFieldTypes::UInt16: expectedAccessor = "Field::GetUInt16"; break; + case DatabaseFieldTypes::Int16: expectedAccessor = "Field::GetInt16"; break; + case DatabaseFieldTypes::UInt32: expectedAccessor = "Field::GetUIn32"; break; + case DatabaseFieldTypes::Int32: expectedAccessor = "Field::GetInt32"; break; + case DatabaseFieldTypes::UInt64: expectedAccessor = "Field::GetUIn64"; break; + case DatabaseFieldTypes::Int64: expectedAccessor = "Field::GetInt64"; break; + case DatabaseFieldTypes::Float: expectedAccessor = "Field::GetFloat"; break; + case DatabaseFieldTypes::Double: expectedAccessor = "Field::GetDouble"; break; + case DatabaseFieldTypes::Decimal: expectedAccessor = "Field::GetDouble or Field::GetString"; break; + case DatabaseFieldTypes::Date: expectedAccessor = "Field::GetDate"; break; + case DatabaseFieldTypes::Time: expectedAccessor = "Field::GetTime"; break; + case DatabaseFieldTypes::Binary: expectedAccessor = "Field::GetString or Field::GetBinary"; break; + default: + break; + } + + ASSERT(false, "%s on %s field %s.%s (%s.%s) at index %u caused value to be truncated. Use %s instead.", + getter, meta->TypeName, meta->TableAlias, meta->Alias, meta->TableName, meta->Name, meta->Index, expectedAccessor); +} diff --git a/src/server/database/Database/FieldValueConverter.h b/src/server/database/Database/FieldValueConverter.h new file mode 100644 index 00000000000..8023ff48e2b --- /dev/null +++ b/src/server/database/Database/FieldValueConverter.h @@ -0,0 +1,52 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef TRINITY_FIELD_VALUE_CONVERTER_H +#define TRINITY_FIELD_VALUE_CONVERTER_H + +#include "Define.h" +#include "Duration.h" + +struct QueryResultFieldMetadata; + +class BaseDatabaseResultValueConverter +{ +public: + BaseDatabaseResultValueConverter(); + BaseDatabaseResultValueConverter(BaseDatabaseResultValueConverter const&) = delete; + BaseDatabaseResultValueConverter(BaseDatabaseResultValueConverter&&) = delete; + BaseDatabaseResultValueConverter& operator=(BaseDatabaseResultValueConverter const&) = delete; + BaseDatabaseResultValueConverter& operator=(BaseDatabaseResultValueConverter&&) = delete; + virtual ~BaseDatabaseResultValueConverter(); + + virtual uint8 GetUInt8(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual int8 GetInt8(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual uint16 GetUInt16(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual int16 GetInt16(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual uint32 GetUInt32(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual int32 GetInt32(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual uint64 GetUInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual int64 GetInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual float GetFloat(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual double GetDouble(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual SystemTimePoint GetDate(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual char const* GetCString(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + + static void LogTruncation(char const* getter, QueryResultFieldMetadata const* meta); +}; + +#endif // TRINITY_FIELD_VALUE_CONVERTER_H diff --git a/src/server/database/Database/FieldValueConverters.h b/src/server/database/Database/FieldValueConverters.h new file mode 100644 index 00000000000..fc6dec8682d --- /dev/null +++ b/src/server/database/Database/FieldValueConverters.h @@ -0,0 +1,131 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef TRINITY_FIELD_VALUE_CONVERTERS_H +#define TRINITY_FIELD_VALUE_CONVERTERS_H + +#include "FieldValueConverter.h" +#include "StringConvert.h" + +// converts string value returned from query to type specified in column metadata +template +class FromStringToDatabaseTypeConverter +{ +public: + static DatabaseType GetDatabaseValue(char const* data, uint32 size) + { + return Trinity::StringTo({ data, size }).template value_or(0); + } + + static char const* GetStringValue(char const* data) + { + return data; + } +}; + +// converts binary value returned from query to type specified in column metadata +template +class FromBinaryToDatabaseTypeConverter +{ +public: + static DatabaseType GetDatabaseValue(char const* data, uint32 /*size*/) + { + return *reinterpret_cast(data); + } + + static char const* GetStringValue(char const* /*data*/) + { + return nullptr; + } +}; + +// converts column value from type specified in column metadata to type requested by Field::Get* function +template typename ToDatabaseTypeConverter> +class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter +{ +public: + template + static T GetNumericValue(char const* data, uint32 size, QueryResultFieldMetadata const* meta, char const* func) + { + DatabaseType source = ToDatabaseTypeConverter::GetDatabaseValue(data, size); + T result = static_cast(source); + if (static_cast(result) != source) + { + LogTruncation(func, meta); + return T(); + } + return result; + } + + uint8 GetUInt8(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetUInt8"); } + int8 GetInt8(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetInt8"); } + uint16 GetUInt16(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetUInt16"); } + int16 GetInt16(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetInt16"); } + uint32 GetUInt32(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetUInt32"); } + int32 GetInt32(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetInt32"); } + uint64 GetUInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetUInt64"); } + int64 GetInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetInt64"); } + float GetFloat(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetFloat"); } + double GetDouble(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetDouble"); } + SystemTimePoint GetDate(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDate", meta); return SystemTimePoint::min(); } + char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override + { + char const* result = ToDatabaseTypeConverter::GetStringValue(data); + if (data && !result) + LogTruncation("Field::GetCString", meta); + return result; + } +}; + +template<> +class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter +{ +public: + uint8 GetUInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt8", meta); return 0; } + int8 GetInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt8", meta); return 0; } + uint16 GetUInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt16", meta); return 0; } + int16 GetInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt16", meta); return 0; } + uint32 GetUInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt32", meta); return 0; } + int32 GetInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt32", meta); return 0; } + uint64 GetUInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt64", meta); return 0; } + int64 GetInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt64", meta); return 0; } + float GetFloat(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetFloat", meta); return 0.0f; } + double GetDouble(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDouble", meta); return 0.0; } + SystemTimePoint GetDate(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDate", meta); return SystemTimePoint::min(); } + char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* /*meta*/) const override { return data; } +}; + +using StringResultValueConverter = PrimitiveResultValueConverter; + +class NotImplementedResultValueConverter : public BaseDatabaseResultValueConverter +{ +public: + uint8 GetUInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt8", meta); return 0; } + int8 GetInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt8", meta); return 0; } + uint16 GetUInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt16", meta); return 0; } + int16 GetInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt16", meta); return 0; } + uint32 GetUInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt32", meta); return 0; } + int32 GetInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt32", meta); return 0; } + uint64 GetUInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt64", meta); return 0; } + int64 GetInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt64", meta); return 0; } + float GetFloat(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetFloat", meta); return 0.0f; } + double GetDouble(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDouble", meta); return 0.0; } + SystemTimePoint GetDate(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDate", meta); return SystemTimePoint::min(); } + char const* GetCString(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetCString", meta); return nullptr; } +}; + +#endif // TRINITY_FIELD_VALUE_CONVERTERS_H diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 28834ccf6c0..ae0f9cd31f1 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -16,7 +16,7 @@ */ #include "CharacterDatabase.h" -#include "PreparedStatement.h" +#include "MySQLPreparedStatement.h" void CharacterDatabaseConnection::DoPrepareStatements() { @@ -34,126 +34,126 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_EXPIRED_BANS, "UPDATE character_banned SET active = 0 WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_GUID_BY_NAME, "SELECT guid FROM characters WHERE name = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_GUID_BY_NAME, "SELECT `guid` FROM characters WHERE name = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHECK_NAME, "SELECT 1 FROM characters WHERE name = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_CHECK_GUID, "SELECT 1 FROM characters WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_SUM_CHARS, "SELECT COUNT(guid) FROM characters WHERE account = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_CHECK_GUID, "SELECT 1 FROM characters WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_SUM_CHARS, "SELECT COUNT(`guid`) FROM characters WHERE account = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHAR_CREATE_INFO, "SELECT level, race, class FROM characters WHERE account = ? LIMIT 0, ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHARACTER_BAN, "INSERT INTO character_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHARACTER_BAN, "UPDATE character_banned SET active = 0 WHERE guid = ? AND active != 0", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_BAN, "DELETE cb FROM character_banned cb INNER JOIN characters c ON c.guid = cb.guid WHERE c.account = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_BANINFO, "SELECT bandate, unbandate-bandate, active, unbandate, banreason, bannedby FROM character_banned WHERE guid = ? ORDER BY bandate ASC", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_GUID_BY_NAME_FILTER, "SELECT guid, name FROM characters WHERE name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_BANINFO_LIST, "SELECT bandate, unbandate, bannedby, banreason FROM character_banned WHERE guid = ? ORDER BY unbandate", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_BANNED_NAME, "SELECT characters.name FROM characters, character_banned WHERE character_banned.guid = ? AND character_banned.guid = characters.guid", CONNECTION_SYNCH); + PrepareStatement(CHAR_UPD_CHARACTER_BAN, "UPDATE character_banned SET active = 0 WHERE `guid` = ? AND active != 0", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_BAN, "DELETE cb FROM character_banned cb INNER JOIN characters c ON c.`guid` = cb.`guid` WHERE c.account = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_BANINFO, "SELECT bandate, unbandate-bandate, active, unbandate, banreason, bannedby FROM character_banned WHERE `guid` = ? ORDER BY bandate ASC", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_GUID_BY_NAME_FILTER, "SELECT `guid`, name FROM characters WHERE name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_BANINFO_LIST, "SELECT bandate, unbandate, bannedby, banreason FROM character_banned WHERE `guid` = ? ORDER BY unbandate", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_BANNED_NAME, "SELECT characters.name FROM characters, character_banned WHERE character_banned.`guid` = ? AND character_banned.`guid` = characters.`guid`", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAIL_LIST_COUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? ", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_MAIL_LIST_INFO, "SELECT id, sender, (SELECT name FROM characters WHERE guid = sender) AS sendername, receiver, (SELECT name FROM characters WHERE guid = receiver) AS receivername, " + PrepareStatement(CHAR_SEL_MAIL_LIST_INFO, "SELECT id, sender, (SELECT name FROM characters WHERE `guid` = sender) AS sendername, receiver, (SELECT name FROM characters WHERE `guid` = receiver) AS receivername, " "subject, deliver_time, expire_time, money, has_items FROM mail WHERE receiver = ? ", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_MAIL_LIST_ITEMS, "SELECT itemEntry,count FROM item_instance WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.customDisplay1, c.customDisplay2, c.customDisplay3, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " - "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, c.slot, c.logout_time, c.activeTalentGroup, c.lastLoginBuild " - "FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.active = 1 LEFT JOIN guild_member AS gm ON c.guid = gm.guid " - "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.customDisplay1, c.customDisplay2, c.customDisplay3, c.level, c.zone, c.map, " + PrepareStatement(CHAR_SEL_MAIL_LIST_ITEMS, "SELECT itemEntry,count FROM item_instance WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_ENUM, "SELECT c.`guid`, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.customDisplay1, c.customDisplay2, c.customDisplay3, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " + "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.`guid`, c.slot, c.logout_time, c.activeTalentGroup, c.lastLoginBuild " + "FROM characters AS c LEFT JOIN character_pet AS cp ON c.`guid` = cp.owner AND cp.active = 1 LEFT JOIN guild_member AS gm ON c.`guid` = gm.`guid` " + "LEFT JOIN character_banned AS cb ON c.`guid` = cb.`guid` AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, "SELECT c.`guid`, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.customDisplay1, c.customDisplay2, c.customDisplay3, c.level, c.zone, c.map, " "c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, " - "cb.guid, c.slot, c.logout_time, c.activeTalentGroup, c.lastLoginBuild, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.active = 1 " - "LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid " - "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_UNDELETE_ENUM, "SELECT c.guid, c.deleteInfos_Name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.customDisplay1, c.customDisplay2, c.customDisplay3, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " - "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, c.slot, c.logout_time, c.activeTalentGroup, c.lastLoginBuild " - "FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.active = 1 LEFT JOIN guild_member AS gm ON c.guid = gm.guid " - "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.deleteInfos_Account = ? AND c.deleteInfos_Name IS NOT NULL", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME, "SELECT c.guid, c.deleteInfos_Name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.customDisplay1, c.customDisplay2, c.customDisplay3, c.level, c.zone, c.map, " + "cb.`guid`, c.slot, c.logout_time, c.activeTalentGroup, c.lastLoginBuild, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.`guid` = cp.owner AND cp.active = 1 " + "LEFT JOIN character_declinedname AS cd ON c.`guid` = cd.`guid` LEFT JOIN guild_member AS gm ON c.`guid` = gm.`guid` " + "LEFT JOIN character_banned AS cb ON c.`guid` = cb.`guid` AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_UNDELETE_ENUM, "SELECT c.`guid`, c.deleteInfos_Name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.customDisplay1, c.customDisplay2, c.customDisplay3, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " + "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.`guid`, c.slot, c.logout_time, c.activeTalentGroup, c.lastLoginBuild " + "FROM characters AS c LEFT JOIN character_pet AS cp ON c.`guid` = cp.owner AND cp.active = 1 LEFT JOIN guild_member AS gm ON c.`guid` = gm.`guid` " + "LEFT JOIN character_banned AS cb ON c.`guid` = cb.`guid` AND cb.active = 1 WHERE c.deleteInfos_Account = ? AND c.deleteInfos_Name IS NOT NULL", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME, "SELECT c.`guid`, c.deleteInfos_Name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.customDisplay1, c.customDisplay2, c.customDisplay3, c.level, c.zone, c.map, " "c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, " - "cb.guid, c.slot, c.logout_time, c.activeTalentGroup, c.lastLoginBuild, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.active = 1 " - "LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid " - "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.deleteInfos_Account = ? AND c.deleteInfos_Name IS NOT NULL", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_FREE_NAME, "SELECT name, at_login FROM characters WHERE guid = ? AND NOT EXISTS (SELECT NULL FROM characters WHERE name = ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME, "SELECT guid, race, account FROM characters WHERE name = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_CHAR_LEVEL, "SELECT level FROM characters WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_ZONE, "SELECT zone FROM characters WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_POSITION_XYZ, "SELECT map, position_x, position_y, position_z FROM characters WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE guid = ?", CONNECTION_SYNCH); + "cb.`guid`, c.slot, c.logout_time, c.activeTalentGroup, c.lastLoginBuild, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.`guid` = cp.owner AND cp.active = 1 " + "LEFT JOIN character_declinedname AS cd ON c.`guid` = cd.`guid` LEFT JOIN guild_member AS gm ON c.`guid` = gm.`guid` " + "LEFT JOIN character_banned AS cb ON c.`guid` = cb.`guid` AND cb.active = 1 WHERE c.deleteInfos_Account = ? AND c.deleteInfos_Name IS NOT NULL", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_FREE_NAME, "SELECT name, at_login FROM characters WHERE `guid` = ? AND NOT EXISTS (SELECT NULL FROM characters WHERE name = ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME, "SELECT `guid`, race, account FROM characters WHERE name = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_CHAR_LEVEL, "SELECT level FROM characters WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_ZONE, "SELECT zone FROM characters WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_POSITION_XYZ, "SELECT map, position_x, position_y, position_z FROM characters WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE `guid` = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM_ALL, "DELETE FROM character_battleground_random", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (`guid`) VALUES (?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER, "SELECT c.guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, customDisplay1, customDisplay2, customDisplay3, inventorySlots, bankSlots, restState, playerFlags, playerFlagsEx, " + PrepareStatement(CHAR_SEL_CHARACTER, "SELECT c.`guid`, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, customDisplay1, customDisplay2, customDisplay3, inventorySlots, bankSlots, restState, playerFlags, playerFlagsEx, " "position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " "resettalents_time, primarySpecialization, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeonDifficulty, " "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, " "health, power1, power2, power3, power4, power5, power6, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, grantableLevels, raidDifficulty, legacyRaidDifficulty, xpRate, fishingSteps, " "honor, honorLevel, prestigeLevel, honorRestState, honorRestBonus " - "FROM characters c LEFT JOIN character_fishingsteps cfs ON c.guid = cfs.guid WHERE c.guid = ?", CONNECTION_ASYNC); - - PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime, entranceId FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemLevel FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_AURA_EFFECTS, "SELECT casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount FROM character_aura_effect WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, timer, explored FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES, "SELECT quest, objective, data FROM character_queststatus_objectives WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA, "SELECT questObjectiveId FROM character_queststatus_objectives_criteria WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "SELECT criteriaId, counter, date FROM character_queststatus_objectives_criteria_progress WHERE guid = ?", CONNECTION_ASYNC); - - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY, "SELECT quest FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_SEASONAL, "DELETE FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_DAILY, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_WEEKLY, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_MONTHLY, "INSERT INTO character_queststatus_monthly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES (?, ?, ?)", CONNECTION_ASYNC); + "FROM characters c LEFT JOIN character_fishingsteps cfs ON c.`guid` = cfs.`guid` WHERE c.`guid` = ?", CONNECTION_ASYNC); + + PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT `guid` FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime, entranceId FROM character_instance LEFT JOIN instance ON instance = id WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemLevel FROM character_aura WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_AURA_EFFECTS, "SELECT casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount FROM character_aura_effect WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, timer, explored FROM character_queststatus WHERE `guid` = ? AND status <> 0", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES, "SELECT quest, objective, data FROM character_queststatus_objectives WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA, "SELECT questObjectiveId FROM character_queststatus_objectives_criteria WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "SELECT criteriaId, counter, date FROM character_queststatus_objectives_criteria_progress WHERE `guid` = ?", CONNECTION_ASYNC); + + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY, "SELECT quest FROM character_queststatus_monthly WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event FROM character_queststatus_seasonal WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_SEASONAL, "DELETE FROM character_queststatus_seasonal WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_DAILY, "INSERT INTO character_queststatus_daily (`guid`, quest, time) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_WEEKLY, "INSERT INTO character_queststatus_weekly (`guid`, quest) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_MONTHLY, "INSERT INTO character_queststatus_monthly (`guid`, quest) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (`guid`, quest, event) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT " SelectItemInstanceContent ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE ci.guid = ? ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT " SelectItemInstanceContent ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.`guid` LEFT JOIN item_instance_gems ig ON ii.`guid` = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.`guid` = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.`guid` = im.itemGuid WHERE ci.`guid` = ? ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.`guid` = c.`guid` AND a.spec = c.activeTalentGroup AND a.`guid` = ? ORDER BY button", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_MAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND (checked & 1) = 0", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_MAIL_COUNT, "SELECT COUNT(*) FROM mail WHERE receiver = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHARACTER_SOCIALLIST, "SELECT cs.friend, c.account, cs.flags, cs.note FROM character_social cs JOIN characters c ON c.guid = cs.friend WHERE cs.guid = ? AND c.deleteinfos_name IS NULL LIMIT 255", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time, categoryId, categoryEnd FROM character_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_SPELL_CHARGES, "SELECT categoryId, rechargeStart, rechargeEnd FROM character_spell_charges WHERE guid = ? AND rechargeEnd > UNIX_TIMESTAMP() ORDER BY rechargeEnd", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, rank FROM guild_member WHERE guid = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_CHARACTER_SOCIALLIST, "SELECT cs.friend, c.account, cs.flags, cs.note FROM character_social cs JOIN characters c ON c.`guid` = cs.friend WHERE cs.`guid` = ? AND c.deleteinfos_name IS NULL LIMIT 255", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time, categoryId, categoryEnd FROM character_spell_cooldown WHERE `guid` = ? AND time > UNIX_TIMESTAMP()", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_SPELL_CHARGES, "SELECT categoryId, rechargeStart, rechargeEnd FROM character_spell_charges WHERE `guid` = ? AND rechargeEnd > UNIX_TIMESTAMP() ORDER BY rechargeEnd", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, `rank` FROM guild_member WHERE `guid` = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gr.rname, gr.rid, gm.pnote, gm.offnote " "FROM guild g JOIN guild_member gm ON g.guildid = gm.guildid " - "JOIN guild_rank gr ON g.guildid = gr.guildid AND gm.rank = gr.rid WHERE gm.guid = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS, "SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = ?", CONNECTION_ASYNC); + "JOIN guild_rank gr ON g.guildid = gr.guildid AND gm.`rank` = gr.rid WHERE gm.`guid` = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS, "SELECT criteria, counter, date FROM character_achievement_progress WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, AssignedSpecIndex, item0, item1, item2, item3, item4, item5, item6, item7, item8, " - "item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC); + "item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE `guid` = ? ORDER BY setindex", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS, "SELECT setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, appearance3, appearance4, " "appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, appearance16, " - "appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_ARENA_DATA, "SELECT slot, rating, bestRatingOfWeek, bestRatingOfSeason, matchMakerRating, weekGames, weekWins, prevWeekGames, prevWeekWins, seasonGames, seasonWins FROM character_arena_data WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT talentId, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_PVP_TALENTS, "SELECT talentId, talentGroup FROM character_pvp_talent WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW, "SELECT quest FROM character_queststatus_rewarded WHERE guid = ? AND active = 1", CONNECTION_ASYNC); + "appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE `guid` = ? ORDER BY setindex", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_ARENA_DATA, "SELECT slot, rating, bestRatingOfWeek, bestRatingOfSeason, matchMakerRating, weekGames, weekWins, prevWeekGames, prevWeekWins, seasonGames, seasonWins FROM character_arena_data WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT talentId, talentGroup FROM character_talent WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_PVP_TALENTS, "SELECT talentId, talentGroup FROM character_pvp_talent WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT `guid` FROM character_battleground_random WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT `guid` FROM character_banned WHERE `guid` = ? AND active = 1", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW, "SELECT quest FROM character_queststatus_rewarded WHERE `guid` = ? AND active = 1", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_ARCHAEOLOGY_DIGSITES, "SELECT digsiteId, point_x, point_y, count FROM character_archaeology_digsites WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_ARCHAEOLOGY_BRANCHS, "SELECT projectId FROM character_archaeology_branchs WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_ARCHAEOLOGY_HISTORY, "SELECT projectId, time, count FROM character_archaeology_history WHERE guid = ?", CONNECTION_ASYNC); - - PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT " SelectItemInstanceContent ", ii.owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE mail_id = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT " SelectItemInstanceContent " FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARACTER_ARCHAEOLOGY_DIGSITES, "SELECT digsiteId, point_x, point_y, count FROM character_archaeology_digsites WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_ARCHAEOLOGY_BRANCHS, "SELECT projectId FROM character_archaeology_branchs WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_ARCHAEOLOGY_HISTORY, "SELECT projectId, time, count FROM character_archaeology_history WHERE `guid` = ?", CONNECTION_ASYNC); + + PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE `guid` = ? AND spec = ? ORDER BY button", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT " SelectItemInstanceContent ", ii.owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.`guid` LEFT JOIN item_instance_gems ig ON ii.`guid` = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.`guid` = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.`guid` = im.itemGuid WHERE mail_id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT " SelectItemInstanceContent " FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.`guid` LEFT JOIN item_instance_gems ig ON ii.`guid` = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.`guid` = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.`guid` = im.itemGuid", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.`guid` = ah.itemguid", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, auctioneerguid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_AUCTION, "DELETE FROM auctionhouse WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_AUCTION_BID, "UPDATE auctionhouse SET buyguid = ?, lastbid = ? WHERE id = ?", CONNECTION_ASYNC); @@ -164,47 +164,47 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_INVALID_MAIL_ITEM, "DELETE FROM mail_items WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_EMPTY_EXPIRED_MAIL, "DELETE FROM mail WHERE expire_time < ? AND has_items = 0 AND body = ''", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_EXPIRED_MAIL, "SELECT id, messageType, sender, receiver, has_items, expire_time, cod, checked, mailTemplateId FROM mail WHERE expire_time < ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_EXPIRED_MAIL_ITEMS, "SELECT item_guid, itemEntry, mail_id FROM mail_items mi INNER JOIN item_instance ii ON ii.guid = mi.item_guid LEFT JOIN mail mm ON mi.mail_id = mm.id WHERE mm.id IS NOT NULL AND mm.expire_time < ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_EXPIRED_MAIL_ITEMS, "SELECT item_guid, itemEntry, mail_id FROM mail_items mi INNER JOIN item_instance ii ON ii.`guid` = mi.item_guid LEFT JOIN mail mm ON mi.mail_id = mm.id WHERE mm.id IS NOT NULL AND mm.expire_time < ?", CONNECTION_SYNCH); PrepareStatement(CHAR_UPD_MAIL_RETURNED, "UPDATE mail SET sender = ?, receiver = ?, expire_time = ?, deliver_time = ?, cod = 0, checked = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_MAIL_ITEM_RECEIVER, "UPDATE mail_items SET receiver = ? WHERE item_guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_ITEM_OWNER, "UPDATE item_instance SET owner_guid = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ITEM_OWNER, "UPDATE item_instance SET owner_guid = ? WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_ITEM_REFUNDS, "SELECT paidMoney, paidExtendedCost FROM item_refund_instance WHERE item_guid = ? AND player_guid = ? LIMIT 1", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ITEM_BOP_TRADE, "SELECT allowedPlayers FROM item_soulbound_trade_data WHERE itemGuid = ? LIMIT 1", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_ITEM_BOP_TRADE, "DELETE FROM item_soulbound_trade_data WHERE itemGuid = ? LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_BOP_TRADE, "INSERT INTO item_soulbound_trade_data VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_REP_INVENTORY_ITEM, "REPLACE INTO character_inventory (guid, bag, slot, item) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_REP_INVENTORY_ITEM, "REPLACE INTO character_inventory (`guid`, bag, slot, item) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_ITEM_INSTANCE, "REPLACE INTO item_instance (itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyType, randomPropertyId, durability, playedTime, text, upgradeId, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, context, bonusListIDs, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyType = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ?, upgradeId = ?, battlePetSpeciesId = ?, battlePetBreedData = ?, battlePetLevel = ?, battlePetDisplayId = ?, context = ?, bonusListIDs = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, randomPropertyType = ?, randomPropertyId = ?, durability = ?, upgradeId = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ITEM_INSTANCE, "DELETE FROM item_instance WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyType = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ?, upgradeId = ?, battlePetSpeciesId = ?, battlePetBreedData = ?, battlePetLevel = ?, battlePetDisplayId = ?, context = ?, bonusListIDs = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, randomPropertyType = ?, randomPropertyId = ?, durability = ?, upgradeId = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE, "DELETE FROM item_instance WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER, "DELETE FROM item_instance WHERE owner_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_INSTANCE_GEMS, "INSERT INTO item_instance_gems (itemGuid, gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_GEMS, "DELETE FROM item_instance_gems WHERE itemGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ITEM_INSTANCE_GEMS_BY_OWNER, "DELETE iig FROM item_instance_gems iig LEFT JOIN item_instance ii ON iig.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE_GEMS_BY_OWNER, "DELETE iig FROM item_instance_gems iig LEFT JOIN item_instance ii ON iig.itemGuid = ii.`guid` WHERE ii.owner_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_INSTANCE_TRANSMOG, "INSERT INTO item_instance_transmog (itemGuid, itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, " "spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG, "DELETE FROM item_instance_transmog WHERE itemGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG_BY_OWNER, "DELETE iit FROM item_instance_transmog iit LEFT JOIN item_instance ii ON iit.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_ITEM_INSTANCE_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.itemGuid WHERE ci.guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG_BY_OWNER, "DELETE iit FROM item_instance_transmog iit LEFT JOIN item_instance ii ON iit.itemGuid = ii.`guid` WHERE ii.owner_guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_ITEM_INSTANCE_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.itemGuid WHERE ci.`guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT, "INSERT INTO item_instance_artifact (itemGuid, xp, artifactAppearanceId, artifactTierId) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT, "DELETE FROM item_instance_artifact WHERE itemGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER, "DELETE iia FROM item_instance_artifact iia LEFT JOIN item_instance ii ON iia.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER, "DELETE iia FROM item_instance_artifact iia LEFT JOIN item_instance ii ON iia.itemGuid = ii.`guid` WHERE ii.owner_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT_POWERS, "INSERT INTO item_instance_artifact_powers (itemGuid, artifactPowerId, purchasedRank) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS, "DELETE FROM item_instance_artifact_powers WHERE itemGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS_BY_OWNER, "DELETE iiap FROM item_instance_artifact_powers iiap LEFT JOIN item_instance ii ON iiap.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS_BY_OWNER, "DELETE iiap FROM item_instance_artifact_powers iiap LEFT JOIN item_instance ii ON iiap.itemGuid = ii.`guid` WHERE ii.owner_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_INSTANCE_MODIFIERS, "INSERT INTO item_instance_modifiers (itemGuid, fixedScalingLevel, artifactKnowledgeLevel, challengeId, challengeLevel, challengeAffix1, challengeAffix2, challengeAffix3, challengeIsCharged) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS, "DELETE FROM item_instance_modifiers WHERE itemGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER, "DELETE im FROM item_instance_modifiers im LEFT JOIN item_instance ii ON im.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_GIFT_OWNER, "UPDATE character_gifts SET guid = ? WHERE item_guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER, "DELETE im FROM item_instance_modifiers im LEFT JOIN item_instance ii ON im.itemGuid = ii.`guid` WHERE ii.owner_guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GIFT_OWNER, "UPDATE character_gifts SET `guid` = ? WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GIFT, "DELETE FROM character_gifts WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM, "SELECT entry, flags FROM character_gifts WHERE item_guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ACCOUNT_BY_NAME, "SELECT account FROM characters WHERE name = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_UPD_ACCOUNT_BY_GUID, "UPDATE characters SET account = ? WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_UPD_ACCOUNT_BY_GUID, "UPDATE characters SET account = ? WHERE `guid` = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES, "DELETE FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES, "INSERT INTO account_instance_times (accountId, instanceId, releaseTime) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_COUNT, "SELECT account, COUNT(guid) FROM characters WHERE account = ? GROUP BY account", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_NAME_BY_GUID, "UPDATE characters SET name = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_NAME_BY_GUID, "UPDATE characters SET name = ? WHERE `guid` = ?", CONNECTION_ASYNC); // Guild handling // 0: uint32, 1: string, 2: uint32, 3: string, 4: string, 5: uint64, 6-10: uint32, 11: uint64 @@ -213,8 +213,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() // 0: string, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_NAME, "UPDATE guild SET name = ? WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint32, 2: uint8, 4: string, 5: string - PrepareStatement(CHAR_INS_GUILD_MEMBER, "INSERT INTO guild_member (guildid, guid, rank, pnote, offnote) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_GUILD_MEMBER, "DELETE FROM guild_member WHERE guid = ?", CONNECTION_ASYNC); // 0: uint32 + PrepareStatement(CHAR_INS_GUILD_MEMBER, "INSERT INTO guild_member (guildid, `guid`, `rank`, pnote, offnote) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GUILD_MEMBER, "DELETE FROM guild_member WHERE `guid` = ?", CONNECTION_ASYNC); // 0: uint32 PrepareStatement(CHAR_DEL_GUILD_MEMBERS, "DELETE FROM guild_member WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32 // 0: uint32, 1: uint8, 3: string, 4: uint32, 5: uint32 PrepareStatement(CHAR_INS_GUILD_RANK, "INSERT INTO guild_rank (guildid, rid, rname, rights, BankMoneyPerDay) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); @@ -226,7 +226,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() // 0: uint32, 1: uint8, 2: uint8, 3: uint32, 4: uint32 PrepareStatement(CHAR_INS_GUILD_BANK_ITEM, "INSERT INTO guild_bank_item (guildid, TabId, SlotId, item_guid) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint8, 2: uint8 - PrepareStatement(CHAR_SEL_GUILD_BANK_ITEMS, "SELECT " SelectItemInstanceContent ", guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_GUILD_BANK_ITEMS, "SELECT " SelectItemInstanceContent ", guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.`guid` LEFT JOIN item_instance_gems ig ON ii.`guid` = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.`guid` = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.`guid` = im.itemGuid", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_GUILD_BANK_ITEMS, "DELETE FROM guild_bank_item WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32 // 0: uint32, 1: uint8, 2: uint8, 3: uint8, 4: uint32 PrepareStatement(CHAR_INS_GUILD_BANK_RIGHT, "INSERT INTO guild_bank_right (guildid, TabId, rid, gbright, SlotPerDay) VALUES (?, ?, ?, ?, ?) " @@ -241,9 +241,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_GUILD_EVENTLOG, "INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_EVENTLOG, "DELETE FROM guild_eventlog WHERE guildid = ? AND LogGuid = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint32 PrepareStatement(CHAR_DEL_GUILD_EVENTLOGS, "DELETE FROM guild_eventlog WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32 - PrepareStatement(CHAR_UPD_GUILD_MEMBER_PNOTE, "UPDATE guild_member SET pnote = ? WHERE guid = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 - PrepareStatement(CHAR_UPD_GUILD_MEMBER_OFFNOTE, "UPDATE guild_member SET offnote = ? WHERE guid = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 - PrepareStatement(CHAR_UPD_GUILD_MEMBER_RANK, "UPDATE guild_member SET rank = ? WHERE guid = ?", CONNECTION_ASYNC); // 0: uint8, 1: uint32 + PrepareStatement(CHAR_UPD_GUILD_MEMBER_PNOTE, "UPDATE guild_member SET pnote = ? WHERE `guid` = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 + PrepareStatement(CHAR_UPD_GUILD_MEMBER_OFFNOTE, "UPDATE guild_member SET offnote = ? WHERE `guid` = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 + PrepareStatement(CHAR_UPD_GUILD_MEMBER_RANK, "UPDATE guild_member SET `rank` = ? WHERE `guid` = ?", CONNECTION_ASYNC); // 0: uint8, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_MOTD, "UPDATE guild SET motd = ? WHERE guildid = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_INFO, "UPDATE guild SET info = ? WHERE guildid = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_LEADER, "UPDATE guild SET leaderguid = ? WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint32 @@ -259,13 +259,13 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_GUILD_BANK_TAB_TEXT, "UPDATE guild_bank_tab SET TabText = ? WHERE guildid = ? AND TabId = ?", CONNECTION_ASYNC); // 0: string, 1: uint32, 2: uint8 PrepareStatement(CHAR_INS_GUILD_MEMBER_WITHDRAW_TABS, - "INSERT INTO guild_member_withdraw (guid, tab0, tab1, tab2, tab3, tab4, tab5, tab6, tab7) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) " + "INSERT INTO guild_member_withdraw (`guid`, tab0, tab1, tab2, tab3, tab4, tab5, tab6, tab7) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) " "ON DUPLICATE KEY UPDATE tab0 = VALUES (tab0), tab1 = VALUES (tab1), tab2 = VALUES (tab2), tab3 = VALUES (tab3), tab4 = VALUES (tab4), tab5 = VALUES (tab5), tab6 = VALUES (tab6), tab7 = VALUES (tab7)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_GUILD_MEMBER_WITHDRAW_MONEY, "INSERT INTO guild_member_withdraw (guid, money) VALUES (?, ?) ON DUPLICATE KEY UPDATE money = VALUES (money)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_GUILD_MEMBER_WITHDRAW_MONEY, "INSERT INTO guild_member_withdraw (`guid`, money) VALUES (?, ?) ON DUPLICATE KEY UPDATE money = VALUES (money)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_MEMBER_WITHDRAW, "DELETE FROM guild_member_withdraw", CONNECTION_ASYNC); // 0: uint32, 1: uint32, 2: uint32 - PrepareStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD, "SELECT name, level, class, gender, zone, account FROM characters WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD, "SELECT name, level, class, gender, zone, account FROM characters WHERE `guid` = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_GUILD_ACHIEVEMENT, "DELETE FROM guild_achievement WHERE guildId = ? AND achievement = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_GUILD_ACHIEVEMENT, "INSERT INTO guild_achievement (guildId, achievement, date, guids) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_ACHIEVEMENT_CRITERIA, "DELETE FROM guild_achievement_progress WHERE guildId = ? AND criteria = ?", CONNECTION_ASYNC); @@ -289,23 +289,23 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_EQUIP_SET, "UPDATE character_equipmentsets SET name=?, iconname=?, ignore_mask=?, AssignedSpecIndex=?, item0=?, item1=?, item2=?, item3=?, " "item4=?, item5=?, item6=?, item7=?, item8=?, item9=?, item10=?, item11=?, item12=?, item13=?, item14=?, item15=?, item16=?, " "item17=?, item18=? WHERE guid=? AND setguid=? AND setindex=?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_EQUIP_SET, "INSERT INTO character_equipmentsets (guid, setguid, setindex, name, iconname, ignore_mask, AssignedSpecIndex, item0, item1, item2, item3, " + PrepareStatement(CHAR_INS_EQUIP_SET, "INSERT INTO character_equipmentsets (`guid`, setguid, setindex, name, iconname, ignore_mask, AssignedSpecIndex, item0, item1, item2, item3, " "item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_EQUIP_SET, "DELETE FROM character_equipmentsets WHERE setguid=?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_TRANSMOG_OUTFIT, "UPDATE character_transmog_outfits SET name=?, iconname=?, ignore_mask=?, appearance0=?, appearance1=?, appearance2=?, appearance3=?, " "appearance4=?, appearance5=?, appearance6=?, appearance7=?, appearance8=?, appearance9=?, appearance10=?, appearance11=?, appearance12=?, appearance13=?, appearance14=?, " "appearance15=?, appearance16=?, appearance17=?, appearance18=?, mainHandEnchant=?, offHandEnchant=? WHERE guid=? AND setguid=? AND setindex=?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_TRANSMOG_OUTFIT, "INSERT INTO character_transmog_outfits (guid, setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, " + PrepareStatement(CHAR_INS_TRANSMOG_OUTFIT, "INSERT INTO character_transmog_outfits (`guid`, setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, " "appearance3, appearance4, appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, " "appearance16, appearance17, appearance18, mainHandEnchant, offHandEnchant) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_TRANSMOG_OUTFIT, "DELETE FROM character_transmog_outfits WHERE setguid=?", CONNECTION_ASYNC); // Auras - PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemLevel) " + PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (`guid`, casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemLevel) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_AURA_EFFECT, "INSERT INTO character_aura_effect (guid, casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount) " + PrepareStatement(CHAR_INS_AURA_EFFECT, "INSERT INTO character_aura_effect (`guid`, casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); // Currency @@ -318,9 +318,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_ACCOUNT_DATA, "SELECT type, time, data FROM account_data WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_ACCOUNT_DATA, "REPLACE INTO account_data (accountId, type, time, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ACCOUNT_DATA, "DELETE FROM account_data WHERE accountId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA, "SELECT type, time, data FROM character_account_data WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_REP_PLAYER_ACCOUNT_DATA, "REPLACE INTO character_account_data(guid, type, time, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_PLAYER_ACCOUNT_DATA, "DELETE FROM character_account_data WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA, "SELECT type, time, data FROM character_account_data WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_REP_PLAYER_ACCOUNT_DATA, "REPLACE INTO character_account_data(`guid`, type, time, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PLAYER_ACCOUNT_DATA, "DELETE FROM character_account_data WHERE `guid` = ?", CONNECTION_ASYNC); // Tutorials PrepareStatement(CHAR_SEL_TUTORIALS, "SELECT tut0, tut1, tut2, tut3, tut4, tut5, tut6, tut7 FROM account_tutorial WHERE accountId = ?", CONNECTION_ASYNC); @@ -352,39 +352,39 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_PETITION_SIG_BY_GUID, "SELECT ownerguid, petitionguid FROM petition_sign WHERE playerguid = ?", CONNECTION_SYNCH); // Character arena data - PrepareStatement(CHAR_INS_CHARACTER_ARENA_DATA, "INSERT INTO character_arena_data (guid, slot, rating, bestRatingOfWeek, bestRatingOfSeason, matchMakerRating, weekGames, weekWins, prevWeekGames, prevWeekWins, seasonGames, seasonWins) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_ARENA_DATA, "DELETE FROM character_arena_data WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_ARENA_DATA, "INSERT INTO character_arena_data (`guid`, slot, rating, bestRatingOfWeek, bestRatingOfSeason, matchMakerRating, weekGames, weekWins, prevWeekGames, prevWeekWins, seasonGames, seasonWins) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_ARENA_DATA, "DELETE FROM character_arena_data WHERE `guid` = ?", CONNECTION_ASYNC); // Character battleground data - PrepareStatement(CHAR_INS_PLAYER_BGDATA, "INSERT INTO character_battleground_data (guid, instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_PLAYER_BGDATA, "DELETE FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_PLAYER_BGDATA, "INSERT INTO character_battleground_data (`guid`, instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PLAYER_BGDATA, "DELETE FROM character_battleground_data WHERE `guid` = ?", CONNECTION_ASYNC); // Character homebind - PrepareStatement(CHAR_INS_PLAYER_HOMEBIND, "INSERT INTO character_homebind (guid, mapId, zoneId, posX, posY, posZ) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_PLAYER_HOMEBIND, "UPDATE character_homebind SET mapId = ?, zoneId = ?, posX = ?, posY = ?, posZ = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_PLAYER_HOMEBIND, "DELETE FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_PLAYER_HOMEBIND, "INSERT INTO character_homebind (`guid`, mapId, zoneId, posX, posY, posZ) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_PLAYER_HOMEBIND, "UPDATE character_homebind SET mapId = ?, zoneId = ?, posX = ?, posY = ?, posZ = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PLAYER_HOMEBIND, "DELETE FROM character_homebind WHERE `guid` = ?", CONNECTION_ASYNC); // Corpse - PrepareStatement(CHAR_SEL_CORPSES, "SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, guid FROM corpse WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_INS_CORPSE, "INSERT INTO corpse (guid, posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CORPSE, "DELETE FROM corpse WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CORPSES_FROM_MAP, "DELETE cp, c FROM corpse_phases cp INNER JOIN corpse c ON cp.OwnerGuid = c.guid WHERE c.mapId = ? AND c.instanceId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CORPSE_PHASES, "SELECT cp.OwnerGuid, cp.PhaseId FROM corpse_phases cp LEFT JOIN corpse c ON cp.OwnerGuid = c.guid WHERE c.mapId = ? AND c.instanceId = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CORPSES, "SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, `guid` FROM corpse WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_CORPSE, "INSERT INTO corpse (`guid`, posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CORPSE, "DELETE FROM corpse WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CORPSES_FROM_MAP, "DELETE cp, c FROM corpse_phases cp INNER JOIN corpse c ON cp.OwnerGuid = c.`guid` WHERE c.mapId = ? AND c.instanceId = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CORPSE_PHASES, "SELECT cp.OwnerGuid, cp.PhaseId FROM corpse_phases cp LEFT JOIN corpse c ON cp.OwnerGuid = c.`guid` WHERE c.mapId = ? AND c.instanceId = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_CORPSE_PHASES, "INSERT INTO corpse_phases (OwnerGuid, PhaseId) VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CORPSE_PHASES, "DELETE FROM corpse_phases WHERE OwnerGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CORPSE_LOCATION, "SELECT mapId, posX, posY, posZ, orientation FROM corpse WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CORPSE_LOCATION, "SELECT mapId, posX, posY, posZ, orientation FROM corpse WHERE `guid` = ?", CONNECTION_ASYNC); // Creature respawn - PrepareStatement(CHAR_SEL_CREATURE_RESPAWNS, "SELECT guid, respawnTime FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_REP_CREATURE_RESPAWN, "REPLACE INTO creature_respawn (guid, respawnTime, mapId, instanceId) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CREATURE_RESPAWN, "DELETE FROM creature_respawn WHERE guid = ? AND mapId = ? AND instanceId = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CREATURE_RESPAWNS, "SELECT `guid`, respawnTime FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_REP_CREATURE_RESPAWN, "REPLACE INTO creature_respawn (`guid`, respawnTime, mapId, instanceId) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CREATURE_RESPAWN, "DELETE FROM creature_respawn WHERE `guid` = ? AND mapId = ? AND instanceId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CREATURE_RESPAWN_BY_INSTANCE, "DELETE FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_MAX_CREATURE_RESPAWNS, "SELECT MAX(respawnTime), instanceId FROM creature_respawn WHERE instanceId > 0 GROUP BY instanceId", CONNECTION_SYNCH); // Gameobject respawn - PrepareStatement(CHAR_SEL_GO_RESPAWNS, "SELECT guid, respawnTime FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_REP_GO_RESPAWN, "REPLACE INTO gameobject_respawn (guid, respawnTime, mapId, instanceId) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_GO_RESPAWN, "DELETE FROM gameobject_respawn WHERE guid = ? AND mapId = ? AND instanceId = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_GO_RESPAWNS, "SELECT `guid`, respawnTime FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_REP_GO_RESPAWN, "REPLACE INTO gameobject_respawn (`guid`, respawnTime, mapId, instanceId) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GO_RESPAWN, "DELETE FROM gameobject_respawn WHERE `guid` = ? AND mapId = ? AND instanceId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GO_RESPAWN_BY_INSTANCE, "DELETE FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC); // GM Bug @@ -410,11 +410,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_ALL_GM_SUGGESTIONS, "DELETE FROM gm_suggestion", CONNECTION_ASYNC); // LFG Data - PrepareStatement(CHAR_INS_LFG_DATA, "INSERT INTO lfg_data (guid, dungeon, state) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_LFG_DATA, "DELETE FROM lfg_data WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_LFG_DATA, "INSERT INTO lfg_data (`guid`, dungeon, state) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_LFG_DATA, "DELETE FROM lfg_data WHERE `guid` = ?", CONNECTION_ASYNC); // Player saving - PrepareStatement(CHAR_INS_CHARACTER, "INSERT INTO characters (guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, customDisplay1, customDisplay2, customDisplay3, inventorySlots, bankSlots, restState, playerFlags, playerFlagsEx, " + PrepareStatement(CHAR_INS_CHARACTER, "INSERT INTO characters (`guid`, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, customDisplay1, customDisplay2, customDisplay3, inventorySlots, bankSlots, restState, playerFlags, playerFlagsEx, " "map, instance_id, dungeonDifficulty, raidDifficulty, legacyRaidDifficulty, position_x, position_y, position_z, orientation, trans_x, trans_y, trans_z, trans_o, transguid, " "taximask, cinematic, " "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, primarySpecialization, " @@ -430,196 +430,196 @@ void CharacterDatabaseConnection::DoPrepareStatements() "watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,power6=?,latency=?,activeTalentGroup=?,lootSpecId=?,exploredZones=?," "equipmentCache=?,knownTitles=?,actionBars=?,grantableLevels=?,xpRate=?,online=?,honor=?,honorLevel=?,prestigeLevel=?,honorRestState=?,honorRestBonus=?,lastLoginBuild=? WHERE guid=?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ALL_AT_LOGIN_FLAGS, "UPDATE characters SET at_login = at_login | ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_BUG_REPORT, "INSERT INTO bugreport (type, content) VALUES(?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_PETITION_NAME, "UPDATE petition SET name = ? WHERE petitionguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PETITION_SIGNATURE, "INSERT INTO petition_sign (ownerguid, petitionguid, playerguid, player_account) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ACCOUNT_ONLINE, "UPDATE characters SET online = 0 WHERE account = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_GROUP, "INSERT INTO groups (guid, leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raidDifficulty, legacyRaidDifficulty, masterLooterGuid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_GROUP_MEMBER, "INSERT INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_GROUP, "INSERT INTO `groups` (`guid`, leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raidDifficulty, legacyRaidDifficulty, masterLooterGuid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_GROUP_MEMBER, "INSERT INTO group_member (`guid`, memberGuid, memberFlags, subgroup, roles) VALUES(?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GROUP_MEMBER, "DELETE FROM group_member WHERE memberGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_GROUP_INSTANCE_PERM_BINDING, "DELETE FROM group_instance WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_GROUP_LEADER, "UPDATE groups SET leaderGuid = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_GROUP_TYPE, "UPDATE groups SET groupType = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GROUP_INSTANCE_PERM_BINDING, "DELETE FROM group_instance WHERE `guid` = ? AND instance = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GROUP_LEADER, "update `groups` SET leaderGuid = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GROUP_TYPE, "update `groups` SET groupType = ? WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP, "UPDATE group_member SET subgroup = ? WHERE memberGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GROUP_MEMBER_FLAG, "UPDATE group_member SET memberFlags = ? WHERE memberGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_GROUP_DIFFICULTY, "UPDATE groups SET difficulty = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY, "UPDATE groups SET raidDifficulty = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_GROUP_LEGACY_RAID_DIFFICULTY, "UPDATE groups SET legacyRaidDifficulty = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GROUP_DIFFICULTY, "update `groups` SET difficulty = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY, "update `groups` SET raidDifficulty = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GROUP_LEGACY_RAID_DIFFICULTY, "update `groups` SET legacyRaidDifficulty = ? WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_SPELL_SPELLS, "DELETE FROM character_spell WHERE spell = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = '', account = 0 WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_RESTORE_DELETE_INFO, "UPDATE characters SET name = ?, account = ?, deleteDate = NULL, deleteInfos_Name = NULL, deleteInfos_Account = NULL WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_ZONE, "UPDATE characters SET zone = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_LEVEL, "UPDATE characters SET level = ?, xp = 0 WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = '', account = 0 WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_RESTORE_DELETE_INFO, "UPDATE characters SET name = ?, account = ?, deleteDate = NULL, deleteInfos_Name = NULL, deleteInfos_Account = NULL WHERE deleteDate IS NOT NULL AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ZONE, "UPDATE characters SET zone = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_LEVEL, "UPDATE characters SET level = ?, xp = 0 WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA, "DELETE FROM character_achievement_progress WHERE criteria = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA_GUILD, "DELETE FROM guild_achievement_progress WHERE criteria = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_ACHIEVMENT, "DELETE FROM character_achievement WHERE achievement = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_PET_SPELL, "DELETE FROM pet_spell WHERE spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE, "DELETE FROM group_instance WHERE instance = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_GROUP_INSTANCE_BY_GUID, "DELETE FROM group_instance WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_REP_GROUP_INSTANCE, "REPLACE INTO group_instance (guid, instance, permanent) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GROUP_INSTANCE_BY_GUID, "DELETE FROM group_instance WHERE `guid` = ? AND instance = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_REP_GROUP_INSTANCE, "REPLACE INTO group_instance (`guid`, instance, permanent) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_INSTANCE_RESETTIME, "UPDATE instance SET resettime = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GLOBAL_INSTANCE_RESETTIME, "UPDATE instance_reset SET resettime = ? WHERE mapid = ? AND difficulty = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_ONLINE, "UPDATE characters SET online = 1 WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN, "UPDATE characters SET name = ?, at_login = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_ONLINE, "UPDATE characters SET online = 1 WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN, "UPDATE characters SET name = ?, at_login = ? WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_WORLDSTATE, "UPDATE worldstates SET value = ? WHERE entry = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_WORLDSTATE, "INSERT INTO worldstates (entry, value) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID, "DELETE FROM character_instance WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_INSTANCE, "UPDATE character_instance SET instance = ?, permanent = ?, extendState = ? WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_INSTANCE, "INSERT INTO character_instance (guid, instance, permanent, extendState) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_GENDER_AND_APPEARANCE, "UPDATE characters SET gender = ?, skin = ?, face = ?, hairStyle = ?, hairColor = ?, facialStyle = ?, customDisplay1 = ?, customDisplay2 = ?, customDisplay3 = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHARACTER_SOCIAL_FLAGS, "UPDATE character_social SET flags = ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_SOCIAL, "INSERT INTO character_social (guid, friend, flags) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_SOCIAL, "DELETE FROM character_social WHERE guid = ? AND friend = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHARACTER_SOCIAL_NOTE, "UPDATE character_social SET note = ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHARACTER_POSITION, "UPDATE characters SET position_x = ?, position_y = ?, position_z = ?, orientation = ?, map = ?, zone = ?, trans_x = 0, trans_y = 0, trans_z = 0, transguid = 0, taxi_path = '' WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name, character_aura.remainTime FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID, "DELETE FROM character_instance WHERE `guid` = ? AND instance = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_INSTANCE, "UPDATE character_instance SET instance = ?, permanent = ?, extendState = ? WHERE `guid` = ? AND instance = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_INSTANCE, "INSERT INTO character_instance (`guid`, instance, permanent, extendState) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GENDER_AND_APPEARANCE, "UPDATE characters SET gender = ?, skin = ?, face = ?, hairStyle = ?, hairColor = ?, facialStyle = ?, customDisplay1 = ?, customDisplay2 = ?, customDisplay3 = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_SKILL, "DELETE FROM character_skills WHERE `guid` = ? AND skill = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHARACTER_SOCIAL_FLAGS, "UPDATE character_social SET flags = ? WHERE `guid` = ? AND friend = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_SOCIAL, "INSERT INTO character_social (`guid`, friend, flags) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_SOCIAL, "DELETE FROM character_social WHERE `guid` = ? AND friend = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHARACTER_SOCIAL_NOTE, "UPDATE character_social SET note = ? WHERE `guid` = ? AND friend = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHARACTER_POSITION, "UPDATE characters SET position_x = ?, position_y = ?, position_z = ?, orientation = ?, map = ?, zone = ?, trans_x = 0, trans_y = 0, trans_z = 0, transguid = 0, taxi_path = '' WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name, character_aura.remainTime FROM characters LEFT JOIN character_aura ON (characters.`guid` = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHARACTER_ONLINE, "SELECT name, account, map, zone FROM characters WHERE online > 0", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_DEL_INFO, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID, "SELECT guid FROM characters WHERE account = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_PINFO, "SELECT totaltime, level, money, account, race, class, map, zone, gender, health, playerFlags FROM characters WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM character_banned WHERE guid = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT `guid`, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND `guid` = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT `guid`, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_DEL_INFO, "SELECT `guid`, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID, "SELECT `guid` FROM characters WHERE account = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_PINFO, "SELECT totaltime, level, money, account, race, class, map, zone, gender, health, playerFlags FROM characters WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM character_banned WHERE `guid` = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH); //0: lowGUID PrepareStatement(CHAR_SEL_PINFO_MAILS, "SELECT SUM(CASE WHEN (checked & 1) THEN 1 ELSE 0 END) AS 'readmail', COUNT(*) AS 'totalmail' FROM mail WHERE `receiver` = ?", CONNECTION_SYNCH); //0: lowGUID - PrepareStatement(CHAR_SEL_PINFO_XP, "SELECT a.xp, b.guid FROM characters a LEFT JOIN guild_member b ON a.guid = b.guid WHERE a.guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_GUID_NAME_BY_ACC, "SELECT guid, name FROM characters WHERE account = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PINFO_XP, "SELECT a.xp, b.`guid` FROM characters a LEFT JOIN guild_member b ON a.`guid` = b.`guid` WHERE a.`guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_GUID_NAME_BY_ACC, "SELECT `guid`, name FROM characters WHERE account = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_POOL_QUEST_SAVE, "SELECT quest_id FROM pool_quest_save WHERE pool_id = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_CUSTOMIZE_INFO, "SELECT name, race, class, gender, at_login FROM characters WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS, "SELECT at_login, knownTitles FROM characters WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHAR_CUSTOMIZE_INFO, "SELECT name, race, class, gender, at_login FROM characters WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS, "SELECT at_login, knownTitles FROM characters WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_INSTANCE, "SELECT data, completedEncounters, entranceId FROM instance WHERE map = ? AND id = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE, "SELECT guid FROM character_instance WHERE instance = ? and permanent = 1", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE, "SELECT `guid` FROM character_instance WHERE instance = ? and permanent = 1", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL, "SELECT id, messageType, mailTemplateId, sender, subject, body, money, has_items FROM mail WHERE receiver = ? AND has_items <> 0 AND cod <> 0", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_SOCIAL, "SELECT DISTINCT guid FROM character_social WHERE friend = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_OLD_CHARS, "SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, "SELECT arena_team_member.arenateamid FROM arena_team_member JOIN arena_team ON arena_team_member.arenateamid = arena_team.arenateamid WHERE guid = ? AND type = ? LIMIT 1", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_SOCIAL, "SELECT DISTINCT `guid` FROM character_social WHERE friend = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_OLD_CHARS, "SELECT `guid`, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, "SELECT arena_team_member.arenateamid FROM arena_team_member JOIN arena_team ON arena_team_member.arenateamid = arena_team.arenateamid WHERE `guid` = ? AND type = ? LIMIT 1", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId FROM mail WHERE receiver = ? ORDER BY id DESC", CONNECTION_SYNCH); - PrepareStatement(CHAR_DEL_CHAR_AURA_FROZEN, "DELETE FROM character_aura WHERE spell = 9454 AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM character_inventory ci INNER JOIN item_instance ii ON ii.guid = ci.item WHERE itemEntry = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_MAIL_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM mail_items mi INNER JOIN item_instance ii ON ii.guid = mi.item_guid WHERE itemEntry = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_AUCTIONHOUSE_COUNT_ITEM,"SELECT COUNT(itemEntry) FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid WHERE itemEntry = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_GUILD_BANK_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM guild_bank_item gbi INNER JOIN item_instance ii ON ii.guid = gbi.item_guid WHERE itemEntry = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_CHAR_AURA_FROZEN, "DELETE FROM character_aura WHERE spell = 9454 AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM character_inventory ci INNER JOIN item_instance ii ON ii.`guid` = ci.item WHERE itemEntry = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAIL_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM mail_items mi INNER JOIN item_instance ii ON ii.`guid` = mi.item_guid WHERE itemEntry = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_AUCTIONHOUSE_COUNT_ITEM,"SELECT COUNT(itemEntry) FROM auctionhouse ah INNER JOIN item_instance ii ON ii.`guid` = ah.itemguid WHERE itemEntry = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_GUILD_BANK_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM guild_bank_item gbi INNER JOIN item_instance ii ON ii.`guid` = gbi.item_guid WHERE itemEntry = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_INVENTORY_ITEM_BY_ENTRY, "SELECT ci.item, cb.slot AS bag, ci.slot, ci.guid, c.account, c.name FROM characters c " - "INNER JOIN character_inventory ci ON ci.guid = c.guid " - "INNER JOIN item_instance ii ON ii.guid = ci.item " + "INNER JOIN character_inventory ci ON ci.`guid` = c.`guid` " + "INNER JOIN item_instance ii ON ii.`guid` = ci.item " "LEFT JOIN character_inventory cb ON cb.item = ci.bag WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAIL_ITEMS_BY_ENTRY, "SELECT mi.item_guid, m.sender, m.receiver, cs.account, cs.name, cr.account, cr.name " - "FROM mail m INNER JOIN mail_items mi ON mi.mail_id = m.id INNER JOIN item_instance ii ON ii.guid = mi.item_guid " - "INNER JOIN characters cs ON cs.guid = m.sender INNER JOIN characters cr ON cr.guid = m.receiver WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_AUCTIONHOUSE_ITEM_BY_ENTRY, "SELECT ah.itemguid, ah.itemowner, c.account, c.name FROM auctionhouse ah INNER JOIN characters c ON c.guid = ah.itemowner INNER JOIN item_instance ii ON ii.guid = ah.itemguid WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_GUILD_BANK_ITEM_BY_ENTRY, "SELECT gi.item_guid, gi.guildid, g.name FROM guild_bank_item gi INNER JOIN guild g ON g.guildid = gi.guildid INNER JOIN item_instance ii ON ii.guid = gi.item_guid WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT, "DELETE FROM character_achievement WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS, "DELETE FROM character_achievement_progress WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT, "INSERT INTO character_achievement (guid, achievement, date) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA, "DELETE FROM character_achievement_progress WHERE guid = ? AND criteria = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS, "INSERT INTO character_achievement_progress (guid, criteria, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_REPUTATION_BY_FACTION, "DELETE FROM character_reputation WHERE guid = ? AND faction = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_REPUTATION_BY_FACTION, "INSERT INTO character_reputation (guid, faction, standing, flags) VALUES (?, ?, ? , ?)", CONNECTION_ASYNC); + "FROM mail m INNER JOIN mail_items mi ON mi.mail_id = m.id INNER JOIN item_instance ii ON ii.`guid` = mi.item_guid " + "INNER JOIN characters cs ON cs.`guid` = m.sender INNER JOIN characters cr ON cr.`guid` = m.receiver WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_AUCTIONHOUSE_ITEM_BY_ENTRY, "SELECT ah.itemguid, ah.itemowner, c.account, c.name FROM auctionhouse ah INNER JOIN characters c ON c.`guid` = ah.itemowner INNER JOIN item_instance ii ON ii.`guid` = ah.itemguid WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_GUILD_BANK_ITEM_BY_ENTRY, "SELECT gi.item_guid, gi.guildid, g.name FROM guild_bank_item gi INNER JOIN guild g ON g.guildid = gi.guildid INNER JOIN item_instance ii ON ii.`guid` = gi.item_guid WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT, "DELETE FROM character_achievement WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS, "DELETE FROM character_achievement_progress WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT, "INSERT INTO character_achievement (`guid`, achievement, date) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA, "DELETE FROM character_achievement_progress WHERE `guid` = ? AND criteria = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS, "INSERT INTO character_achievement_progress (`guid`, criteria, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_REPUTATION_BY_FACTION, "DELETE FROM character_reputation WHERE `guid` = ? AND faction = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_REPUTATION_BY_FACTION, "INSERT INTO character_reputation (`guid`, faction, standing, flags) VALUES (?, ?, ? , ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_REFUND_INSTANCE, "DELETE FROM item_refund_instance WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_REFUND_INSTANCE, "INSERT INTO item_refund_instance (item_guid, player_guid, paidMoney, paidExtendedCost) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_GROUP, "DELETE FROM groups WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_GROUP_MEMBER_ALL, "DELETE FROM group_member WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_GIFT, "INSERT INTO character_gifts (guid, item_guid, entry, flags) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GROUP, "DELETE FROM `groups` WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GROUP_MEMBER_ALL, "DELETE FROM group_member WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_GIFT, "INSERT INTO character_gifts (`guid`, item_guid, entry, flags) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INSTANCE_BY_INSTANCE, "DELETE FROM instance WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE, "DELETE FROM character_instance WHERE instance = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF, "DELETE FROM character_instance USING character_instance LEFT JOIN instance ON character_instance.instance = id WHERE (extendState = 0 or permanent = 0) and map = ? and difficulty = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GROUP_INSTANCE_BY_MAP_DIFF, "DELETE FROM group_instance USING group_instance LEFT JOIN instance ON group_instance.instance = id WHERE map = ? and difficulty = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_EXPIRED_INSTANCE_BY_MAP_DIFF, "DELETE FROM instance WHERE map = ? and difficulty = ? and (SELECT guid FROM character_instance WHERE extendState != 0 AND instance = id LIMIT 1) IS NULL", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_EXPIRED_INSTANCE_BY_MAP_DIFF, "DELETE FROM instance WHERE map = ? and difficulty = ? and (SELECT `guid` FROM character_instance WHERE extendState != 0 AND instance = id LIMIT 1) IS NULL", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_EXPIRE_CHAR_INSTANCE_BY_MAP_DIFF, "UPDATE character_instance LEFT JOIN instance ON character_instance.instance = id SET extendState = extendState-1 WHERE map = ? and difficulty = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_MAIL_ITEM_BY_ID, "DELETE FROM mail_items WHERE mail_id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PETITION, "INSERT INTO petition (ownerguid, petitionguid, name) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_BY_GUID, "DELETE FROM petition WHERE petitionguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_GUID, "DELETE FROM petition_sign WHERE petitionguid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_DECLINED_NAME, "DELETE FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_DECLINED_NAME, "INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_RACE, "UPDATE characters SET race = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SKILL_LANGUAGES, "DELETE FROM character_skills WHERE skill IN (98, 113, 759, 111, 313, 109, 115, 315, 673, 137) AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_SKILL_LANGUAGE, "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (?, ?, 300, 300)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_TAXI_PATH, "UPDATE characters SET taxi_path = '' WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_TAXIMASK, "UPDATE characters SET taximask = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS, "DELETE FROM character_queststatus WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES, "DELETE FROM character_queststatus_objectives WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA, "DELETE FROM character_queststatus_objectives_criteria WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "DELETE FROM character_queststatus_objectives_criteria_progress WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS_BY_CRITERIA, "DELETE FROM character_queststatus_objectives_criteria_progress WHERE guid = ? AND criteriaId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID, "DELETE FROM character_social WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_DECLINED_NAME, "DELETE FROM character_declinedname WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_DECLINED_NAME, "INSERT INTO character_declinedname (`guid`, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_RACE, "UPDATE characters SET race = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_SKILL_LANGUAGES, "DELETE FROM character_skills WHERE skill IN (98, 113, 759, 111, 313, 109, 115, 315, 673, 137) AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_SKILL_LANGUAGE, "INSERT INTO `character_skills` (`guid`, skill, value, max) VALUES (?, ?, 300, 300)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_TAXI_PATH, "UPDATE characters SET taxi_path = '' WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_TAXIMASK, "UPDATE characters SET taximask = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS, "DELETE FROM character_queststatus WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES, "DELETE FROM character_queststatus_objectives WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA, "DELETE FROM character_queststatus_objectives_criteria WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "DELETE FROM character_queststatus_objectives_criteria_progress WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS_BY_CRITERIA, "DELETE FROM character_queststatus_objectives_criteria_progress WHERE `guid` = ? AND criteriaId = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID, "DELETE FROM character_social WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND, "DELETE FROM character_social WHERE friend = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT, "DELETE FROM character_achievement WHERE achievement = ? AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_ACHIEVEMENT, "UPDATE character_achievement SET achievement = ? where achievement = ? AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE, "UPDATE item_instance ii, character_inventory ci SET ii.itemEntry = ? WHERE ii.itemEntry = ? AND ci.guid = ? AND ci.item = ii.guid", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL, "DELETE FROM character_spell WHERE spell = ? AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_SPELL_FACTION_CHANGE, "UPDATE character_spell SET spell = ? where spell = ? AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHAR_REP_BY_FACTION, "SELECT standing FROM character_reputation WHERE faction = ? AND guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_DEL_CHAR_REP_BY_FACTION, "DELETE FROM character_reputation WHERE faction = ? AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE, "UPDATE character_reputation SET faction = ?, standing = ? WHERE faction = ? AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET knownTitles = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET chosenTitle = 0 WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS, "DELETE FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_SPELL_COOLDOWN, "INSERT INTO character_spell_cooldown (guid, spell, item, time, categoryId, categoryEnd) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SPELL_CHARGES, "DELETE FROM character_spell_charges WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_SPELL_CHARGES, "INSERT INTO character_spell_charges (guid, categoryId, rechargeStart, rechargeEnd) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER, "DELETE FROM characters WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_ACTION, "DELETE FROM character_action WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_AURA, "DELETE FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_AURA_EFFECT, "DELETE FROM character_aura_effect WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_GIFT, "DELETE FROM character_gifts WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_INSTANCE, "DELETE FROM character_instance WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_INVENTORY, "DELETE FROM character_inventory WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED, "DELETE FROM character_queststatus_rewarded WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_REPUTATION, "DELETE FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SPELL, "DELETE FROM character_spell WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT, "DELETE FROM character_achievement WHERE achievement = ? AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_ACHIEVEMENT, "UPDATE character_achievement SET achievement = ? where achievement = ? AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE, "UPDATE item_instance ii, character_inventory ci SET ii.itemEntry = ? WHERE ii.itemEntry = ? AND ci.`guid` = ? AND ci.item = ii.guid", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL, "DELETE FROM character_spell WHERE spell = ? AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_SPELL_FACTION_CHANGE, "UPDATE character_spell SET spell = ? where spell = ? AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHAR_REP_BY_FACTION, "SELECT standing FROM character_reputation WHERE faction = ? AND `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_CHAR_REP_BY_FACTION, "DELETE FROM character_reputation WHERE faction = ? AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE, "UPDATE character_reputation SET faction = ?, standing = ? WHERE faction = ? AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET knownTitles = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET chosenTitle = 0 WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS, "DELETE FROM character_spell_cooldown WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_SPELL_COOLDOWN, "INSERT INTO character_spell_cooldown (`guid`, spell, item, time, categoryId, categoryEnd) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_SPELL_CHARGES, "DELETE FROM character_spell_charges WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_SPELL_CHARGES, "INSERT INTO character_spell_charges (`guid`, categoryId, rechargeStart, rechargeEnd) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER, "DELETE FROM characters WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_ACTION, "DELETE FROM character_action WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_AURA, "DELETE FROM character_aura WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_AURA_EFFECT, "DELETE FROM character_aura_effect WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_GIFT, "DELETE FROM character_gifts WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_INSTANCE, "DELETE FROM character_instance WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_INVENTORY, "DELETE FROM character_inventory WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED, "DELETE FROM character_queststatus_rewarded WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_REPUTATION, "DELETE FROM character_reputation WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_SPELL, "DELETE FROM character_spell WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_MAIL, "DELETE FROM mail WHERE receiver = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_MAIL_ITEMS, "DELETE FROM mail_items WHERE receiver = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENTS, "DELETE FROM character_achievement WHERE guid = ? AND achievement NOT IN (456,457,458,459,460,461,462,463,464,465,466,467,1400,1402,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1463,3117,3259,4078,4576,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,6433,6523,6524,6743,6744,6745,6746,6747,6748,6749,6750,6751,6752,6829,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872,6873)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_EQUIPMENTSETS, "DELETE FROM character_equipmentsets WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFITS, "DELETE FROM character_transmog_outfits WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENTS, "DELETE FROM character_achievement WHERE `guid` = ? AND achievement NOT IN (456,457,458,459,460,461,462,463,464,465,466,467,1400,1402,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1463,3117,3259,4078,4576,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,6433,6523,6524,6743,6744,6745,6746,6747,6748,6749,6750,6751,6752,6829,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872,6873)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_EQUIPMENTSETS, "DELETE FROM character_equipmentsets WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFITS, "DELETE FROM character_transmog_outfits WHERE `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, "DELETE FROM guild_eventlog WHERE PlayerGuid1 = ? OR PlayerGuid2 = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, "DELETE FROM guild_bank_eventlog WHERE PlayerGuid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_GLYPHS, "DELETE FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_TALENT, "DELETE FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_PVP_TALENT, "DELETE FROM character_pvp_talent WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SKILLS, "DELETE FROM character_skills WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_MONEY, "UPDATE characters SET money = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_ACTION, "INSERT INTO character_action (guid, spec, button, action, type) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_ACTION, "UPDATE character_action SET action = ?, type = ? WHERE guid = ? AND button = ? AND spec = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC, "DELETE FROM character_action WHERE guid = ? and button = ? and spec = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_GLYPHS, "DELETE FROM character_glyphs WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_TALENT, "DELETE FROM character_talent WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_PVP_TALENT, "DELETE FROM character_pvp_talent WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_SKILLS, "DELETE FROM character_skills WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_MONEY, "UPDATE characters SET money = ? WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_ACTION, "INSERT INTO character_action (`guid`, spec, button, action, type) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_ACTION, "UPDATE character_action SET action = ?, type = ? WHERE `guid` = ? AND button = ? AND spec = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC, "DELETE FROM character_action WHERE `guid` = ? and button = ? and spec = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM, "DELETE FROM character_inventory WHERE item = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_INVENTORY_BY_BAG_SLOT, "DELETE FROM character_inventory WHERE bag = ? AND slot = ? AND guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_INVENTORY_BY_BAG_SLOT, "DELETE FROM character_inventory WHERE bag = ? AND slot = ? AND `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_MAIL, "UPDATE mail SET has_items = ?, expire_time = ?, deliver_time = ?, money = ?, cod = ?, checked = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS, "REPLACE INTO character_queststatus (guid, quest, status, timer, explored) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, "DELETE FROM character_queststatus WHERE guid = ? AND quest = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES, "REPLACE INTO character_queststatus_objectives (guid, quest, objective, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_BY_QUEST, "DELETE FROM character_queststatus_objectives WHERE guid = ? AND quest = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA, "INSERT INTO character_queststatus_objectives_criteria (guid, questObjectiveId) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "INSERT INTO character_queststatus_objectives_criteria_progress (guid, criteriaId, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_REWARDED, "INSERT IGNORE INTO character_queststatus_rewarded (guid, quest, active) VALUES (?, ?, 1)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, "DELETE FROM character_queststatus_rewarded WHERE guid = ? AND quest = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE, "UPDATE character_queststatus_rewarded SET quest = ? WHERE quest = ? AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE, "UPDATE character_queststatus_rewarded SET active = 1 WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, "UPDATE character_queststatus_rewarded SET active = 0 WHERE quest = ? AND guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS, "REPLACE INTO character_queststatus (`guid`, quest, status, timer, explored) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, "DELETE FROM character_queststatus WHERE `guid` = ? AND quest = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES, "REPLACE INTO character_queststatus_objectives (`guid`, quest, objective, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_BY_QUEST, "DELETE FROM character_queststatus_objectives WHERE `guid` = ? AND quest = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA, "INSERT INTO character_queststatus_objectives_criteria (`guid`, questObjectiveId) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "INSERT INTO character_queststatus_objectives_criteria_progress (`guid`, criteriaId, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_REWARDED, "INSERT IGNORE INTO character_queststatus_rewarded (`guid`, quest, active) VALUES (?, ?, 1)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, "DELETE FROM character_queststatus_rewarded WHERE `guid` = ? AND quest = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE, "UPDATE character_queststatus_rewarded SET quest = ? WHERE quest = ? AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE, "UPDATE character_queststatus_rewarded SET active = 1 WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, "UPDATE character_queststatus_rewarded SET active = 0 WHERE quest = ? AND `guid` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_QUEST_PROGRESS_CRITERIA, "DELETE FROM character_queststatus_objectives_criteria WHERE questObjectiveId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_SKILLS, "INSERT INTO character_skills (guid, skill, value, max) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_SKILLS, "UPDATE character_skills SET value = ?, max = ? WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_SPELL, "INSERT INTO character_spell (guid, spell, active, disabled) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_STATS, "DELETE FROM character_stats WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_STATS, "INSERT INTO character_stats (guid, maxhealth, maxpower1, maxpower2, maxpower3, maxpower4, maxpower5, maxpower6, strength, agility, stamina, intellect, " + PrepareStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL, "DELETE FROM character_skills WHERE `guid` = ? AND skill = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_SKILLS, "INSERT INTO character_skills (`guid`, skill, value, max) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_SKILLS, "UPDATE character_skills SET value = ?, max = ? WHERE `guid` = ? AND skill = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_SPELL, "INSERT INTO character_spell (`guid`, spell, active, disabled) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_STATS, "DELETE FROM character_stats WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_STATS, "INSERT INTO character_stats (`guid`, maxhealth, maxpower1, maxpower2, maxpower3, maxpower4, maxpower5, maxpower6, strength, agility, stamina, intellect, " "armor, resHoly, resFire, resNature, resFrost, resShadow, resArcane, blockPct, dodgePct, parryPct, critPct, rangedCritPct, spellCritPct, attackPower, rangedAttackPower, " "spellPower, resilience) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_BY_OWNER, "DELETE FROM petition WHERE ownerguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs VALUES(?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, talentId, talentGroup) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_PVP_TALENT, "INSERT INTO character_pvp_talent (guid, talentId, talentGroup) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_FISHINGSTEPS, "INSERT INTO character_fishingsteps (guid, fishingSteps) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_FISHINGSTEPS, "DELETE FROM character_fishingsteps WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (`guid`, talentId, talentGroup) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_PVP_TALENT, "INSERT INTO character_pvp_talent (`guid`, talentId, talentGroup) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE `guid` = ? AND account = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_FISHINGSTEPS, "INSERT INTO character_fishingsteps (`guid`, fishingSteps) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_FISHINGSTEPS, "DELETE FROM character_fishingsteps WHERE `guid` = ?", CONNECTION_ASYNC); // Void Storage PrepareStatement(CHAR_SEL_CHAR_VOID_STORAGE, "SELECT itemId, itemEntry, slot, creatorGuid, randomPropertyType, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, challengeId, challengeLevel, challengeAffix1, challengeAffix2, challengeAffix3, challengeIsCharged, context, bonusListIDs FROM character_void_storage WHERE playerGuid = ?", CONNECTION_ASYNC); @@ -628,10 +628,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_SLOT, "DELETE FROM character_void_storage WHERE slot = ? AND playerGuid = ?", CONNECTION_ASYNC); // CompactUnitFrame profiles - PrepareStatement(CHAR_SEL_CHAR_CUF_PROFILES, "SELECT id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, topPoint, bottomPoint, leftPoint, topOffset, bottomOffset, leftOffset FROM character_cuf_profiles WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_REP_CHAR_CUF_PROFILES, "REPLACE INTO character_cuf_profiles (guid, id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, topPoint, bottomPoint, leftPoint, topOffset, bottomOffset, leftOffset) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_CUF_PROFILES_BY_ID, "DELETE FROM character_cuf_profiles WHERE guid = ? AND id = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_CUF_PROFILES, "DELETE FROM character_cuf_profiles WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHAR_CUF_PROFILES, "SELECT id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, topPoint, bottomPoint, leftPoint, topOffset, bottomOffset, leftOffset FROM character_cuf_profiles WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_REP_CHAR_CUF_PROFILES, "REPLACE INTO character_cuf_profiles (`guid`, id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, topPoint, bottomPoint, leftPoint, topOffset, bottomOffset, leftOffset) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_CUF_PROFILES_BY_ID, "DELETE FROM character_cuf_profiles WHERE `guid` = ? AND id = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_CUF_PROFILES, "DELETE FROM character_cuf_profiles WHERE `guid` = ?", CONNECTION_ASYNC); // Guild Finder PrepareStatement(CHAR_REP_GUILD_FINDER_APPLICANT, "REPLACE INTO guild_finder_applicant (guildId, playerGuid, availability, classRole, interests, comment, submitTime) VALUES(?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); @@ -659,36 +659,36 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_PET_SLOTS_DETAIL, "SELECT slot, id, entry, modelid, level, name FROM character_pet WHERE owner = ? AND slot >= ? AND slot <= ? ORDER BY slot", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_PET_ENTRY, "SELECT entry FROM character_pet WHERE owner = ? AND id = ? AND slot >= ? AND slot <= ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_PET_SLOT_BY_ID, "SELECT slot, id, entry FROM character_pet WHERE owner = ? AND id = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_PET_SPELL_LIST, "SELECT DISTINCT pet_spell.spell FROM pet_spell, character_pet WHERE character_pet.owner = ? AND character_pet.id = pet_spell.guid AND character_pet.id <> ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PET_SPELL_LIST, "SELECT DISTINCT pet_spell.spell FROM pet_spell, character_pet WHERE character_pet.owner = ? AND character_pet.id = pet_spell.`guid` AND character_pet.id <> ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_PETS, "SELECT id FROM character_pet WHERE owner = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE owner = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_PET_AURA_EFFECT, "SELECT casterGuid, spell, effectMask, effectIndex, amount, baseAmount FROM pet_aura_effect WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time, categoryId, categoryEnd FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges FROM pet_aura WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PET_AURA_EFFECT, "SELECT casterGuid, spell, effectMask, effectIndex, amount, baseAmount FROM pet_aura_effect WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time, categoryId, categoryEnd FROM pet_spell_cooldown WHERE `guid` = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_DECLINED_NAME, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = ? AND id = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_DEL_PET_AURAS, "DELETE FROM pet_aura WHERE guid = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_DEL_PET_AURA_EFFECTS, "DELETE FROM pet_aura_effect WHERE guid = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_DEL_PET_SPELLS, "DELETE FROM pet_spell WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_PET_SPELL_COOLDOWNS, "DELETE FROM pet_spell_cooldown WHERE guid = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_INS_PET_SPELL_COOLDOWN, "INSERT INTO pet_spell_cooldown (guid, spell, time, categoryId, categoryEnd) VALUES (?, ?, ?, ?, ?)", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_PET_SPELL_CHARGES, "SELECT categoryId, rechargeStart, rechargeEnd FROM pet_spell_charges WHERE guid = ? AND rechargeEnd > UNIX_TIMESTAMP() ORDER BY rechargeEnd", CONNECTION_SYNCH); - PrepareStatement(CHAR_DEL_PET_SPELL_CHARGES, "DELETE FROM pet_spell_charges WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_PET_SPELL_CHARGES, "INSERT INTO pet_spell_charges (guid, categoryId, rechargeStart, rechargeEnd) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_PET_SPELL_BY_SPELL, "DELETE FROM pet_spell WHERE guid = ? and spell = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_PET_SPELL, "INSERT INTO pet_spell (guid, spell, active) VALUES (?, ?, ?)", CONNECTION_BOTH); - PrepareStatement(CHAR_INS_PET_AURA, "INSERT INTO pet_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges) " + PrepareStatement(CHAR_DEL_PET_AURAS, "DELETE FROM pet_aura WHERE `guid` = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_DEL_PET_AURA_EFFECTS, "DELETE FROM pet_aura_effect WHERE `guid` = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_DEL_PET_SPELLS, "DELETE FROM pet_spell WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PET_SPELL_COOLDOWNS, "DELETE FROM pet_spell_cooldown WHERE `guid` = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_INS_PET_SPELL_COOLDOWN, "INSERT INTO pet_spell_cooldown (`guid`, spell, time, categoryId, categoryEnd) VALUES (?, ?, ?, ?, ?)", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_PET_SPELL_CHARGES, "SELECT categoryId, rechargeStart, rechargeEnd FROM pet_spell_charges WHERE `guid` = ? AND rechargeEnd > UNIX_TIMESTAMP() ORDER BY rechargeEnd", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_PET_SPELL_CHARGES, "DELETE FROM pet_spell_charges WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_PET_SPELL_CHARGES, "INSERT INTO pet_spell_charges (`guid`, categoryId, rechargeStart, rechargeEnd) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PET_SPELL_BY_SPELL, "DELETE FROM pet_spell WHERE `guid` = ? and spell = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_PET_SPELL, "INSERT INTO pet_spell (`guid`, spell, active) VALUES (?, ?, ?)", CONNECTION_BOTH); + PrepareStatement(CHAR_INS_PET_AURA, "INSERT INTO pet_aura (`guid`, casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); - PrepareStatement(CHAR_INS_PET_AURA_EFFECT, "INSERT INTO pet_aura_effect (guid, casterGuid, spell, effectMask, effectIndex, amount, baseAmount) " + PrepareStatement(CHAR_INS_PET_AURA_EFFECT, "INSERT INTO pet_aura_effect (`guid`, casterGuid, spell, effectMask, effectIndex, amount, baseAmount) " "VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); PrepareStatement(CHAR_DEL_CHAR_PET_BY_OWNER, "DELETE FROM character_pet WHERE owner = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_SLOT, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER, "DELETE FROM pet_spell WHERE guid in (SELECT id FROM character_pet WHERE owner=?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER, "DELETE FROM pet_spell WHERE `guid` in (SELECT id FROM character_pet WHERE owner=?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_PET_SPECS_BY_OWNER, "UPDATE character_pet SET specialization = 0 WHERE owner=?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PET, "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, active, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); @@ -697,13 +697,13 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_ALL_PETS_DETAIL, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, active, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? ORDER BY slot", CONNECTION_ASYNC); // Archaeology - PrepareStatement(CHAR_INS_ARCHAEOLOGY_BRANCH, "INSERT INTO character_archaeology_branchs (guid, projectId) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_ARCHAEOLOGY_DIGSITE, "INSERT INTO character_archaeology_digsites (guid, digsiteId, point_x, point_y, count) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_ARCHAEOLOGY_ARTIFACT, "SELECT time, projectId, count FROM character_archaeology_history WHERE guid = ? AND projectId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_ARCHAEOLOGY_HISTORY, "INSERT INTO character_archaeology_history (guid, projectId, time, count) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ARCHAEOLOGY_DIGSITES, "DELETE FROM character_archaeology_digsites WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ARCHAEOLOGY_BRANCHS, "DELETE FROM character_archaeology_branchs WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ARCHAEOLOGY_HISTORY, "DELETE FROM character_archaeology_history WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_ARCHAEOLOGY_BRANCH, "INSERT INTO character_archaeology_branchs (`guid`, projectId) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_ARCHAEOLOGY_DIGSITE, "INSERT INTO character_archaeology_digsites (`guid`, digsiteId, point_x, point_y, count) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_ARCHAEOLOGY_ARTIFACT, "SELECT time, projectId, count FROM character_archaeology_history WHERE `guid` = ? AND projectId = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_ARCHAEOLOGY_HISTORY, "INSERT INTO character_archaeology_history (`guid`, projectId, time, count) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ARCHAEOLOGY_DIGSITES, "DELETE FROM character_archaeology_digsites WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ARCHAEOLOGY_BRANCHS, "DELETE FROM character_archaeology_branchs WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ARCHAEOLOGY_HISTORY, "DELETE FROM character_archaeology_history WHERE `guid` = ?", CONNECTION_ASYNC); // PvPstats PrepareStatement(CHAR_SEL_PVPSTATS_MAXID, "SELECT MAX(id) FROM pvpstats_battlegrounds", CONNECTION_SYNCH); @@ -722,23 +722,23 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_CHARACTER_GARRISON, "INSERT INTO `character_garrison` (`guid`, `type`, `siteLevelId`, `followerActivationsRemainingToday`) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_GARRISON, "DELETE FROM `character_garrison` WHERE `guid` = ? AND `type` = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS, "UPDATE character_garrison SET followerActivationsRemainingToday = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS, "SELECT buildingId FROM character_garrison_blueprints WHERE guid = ? AND garrison_type = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS, "INSERT INTO character_garrison_blueprints (guid, garrison_type, buildingId) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS, "DELETE FROM character_garrison_blueprints WHERE guid = ? AND garrison_type = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, "SELECT plotInstanceId, buildingId, timeBuilt, active FROM character_garrison_buildings WHERE guid = ? AND garrison_type = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS, "INSERT INTO character_garrison_buildings (guid, garrison_type, plotInstanceId, buildingId, timeBuilt, active) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS, "DELETE FROM character_garrison_buildings WHERE guid = ? AND garrison_type = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS, "SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ? AND garrison_type = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS, "INSERT INTO character_garrison_followers (dbId, guid, garrison_type, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS, "DELETE gfab, gf FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE gf.guid = ? AND gf.garrison_type = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "SELECT gfab.dbId, gfab.abilityId FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE guid = ? AND garrison_type = ? ORDER BY gfab.slot", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS, "SELECT buildingId FROM character_garrison_blueprints WHERE `guid` = ? AND garrison_type = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS, "INSERT INTO character_garrison_blueprints (`guid`, garrison_type, buildingId) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS, "DELETE FROM character_garrison_blueprints WHERE `guid` = ? AND garrison_type = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, "SELECT plotInstanceId, buildingId, timeBuilt, active FROM character_garrison_buildings WHERE `guid` = ? AND garrison_type = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS, "INSERT INTO character_garrison_buildings (`guid`, garrison_type, plotInstanceId, buildingId, timeBuilt, active) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS, "DELETE FROM character_garrison_buildings WHERE `guid` = ? AND garrison_type = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS, "SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE `guid` = ? AND garrison_type = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS, "INSERT INTO character_garrison_followers (dbId, `guid`, garrison_type, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS, "DELETE gfab, gf FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE gf.`guid` = ? AND gf.garrison_type = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "SELECT gfab.dbId, gfab.abilityId FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE `guid` = ? AND garrison_type = ? ORDER BY gfab.slot", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "INSERT INTO character_garrison_follower_abilities (dbId, abilityId, slot) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_MISSIONS, "SELECT dbId, missionId, offerTime, startTime, status FROM character_garrison_missions WHERE guid = ? AND garrison_type = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_MISSIONS, "SELECT dbId, missionId, offerTime, startTime, status FROM character_garrison_missions WHERE `guid` = ? AND garrison_type = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_UPD_CHARACTER_GARRISON_MISSIONS, "UPDATE character_garrison_missions SET status = ? WHERE dbId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_GARRISON_MISSIONS, "INSERT INTO character_garrison_missions (dbId, guid, garrison_type, missionId, offerTime, startTime, status) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_MISSIONS, "DELETE gfmr, gm FROM character_garrison_mission_rewards gfmr INNER JOIN character_garrison_missions gm ON gfmr.dbId = gm.dbId WHERE guid = ? AND garrison_type = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_MISSIONS, "INSERT INTO character_garrison_missions (dbId, `guid`, garrison_type, missionId, offerTime, startTime, status) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_MISSIONS, "DELETE gfmr, gm FROM character_garrison_mission_rewards gfmr INNER JOIN character_garrison_missions gm ON gfmr.dbId = gm.dbId WHERE `guid` = ? AND garrison_type = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_MISSION, "DELETE gfmr, gm FROM character_garrison_mission_rewards gfmr INNER JOIN character_garrison_missions gm ON gfmr.dbId = gm.dbId WHERE gm.dbId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_MISSION_REWARDS, "SELECT gfmr.dbId, gfmr.type, gfmr.itemId, gfmr.itemQuantity, gfmr.currencyId, gfmr.currencyQuantity, gfmr.FollowerXP, gfmr.BonusAbilityId FROM character_garrison_mission_rewards gfmr INNER JOIN character_garrison_missions gm ON gfmr.dbId = gm.dbId WHERE guid = ? AND garrison_type = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_MISSION_REWARDS, "SELECT gfmr.dbId, gfmr.type, gfmr.itemId, gfmr.itemQuantity, gfmr.currencyId, gfmr.currencyQuantity, gfmr.FollowerXP, gfmr.BonusAbilityId FROM character_garrison_mission_rewards gfmr INNER JOIN character_garrison_missions gm ON gfmr.dbId = gm.dbId WHERE `guid` = ? AND garrison_type = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_CHARACTER_GARRISON_MISSION_REWARDS, "INSERT INTO character_garrison_mission_rewards (dbId, type, itemId, itemQuantity, currencyId, currencyQuantity, FollowerXP, BonusAbilityId) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); // Black Market @@ -759,7 +759,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_REP_WORLD_QUEST, "REPLACE INTO world_quest (id, rewardid, starttime) VALUES (?, ?, ?)", CONNECTION_ASYNC); // Custom - PrepareStatement(CHAR_UPD_XP_RATE, "UPDATE characters SET xpRate = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_XP_RATE, "UPDATE characters SET xpRate = ? WHERE `guid` = ?", CONNECTION_ASYNC); // Logs PrepareStatement(CHAR_LOG_GM_COMMAND, "INSERT INTO `log_gm` (`id`, `date`, " @@ -768,18 +768,14 @@ void CharacterDatabaseConnection::DoPrepareStatements() "VALUES (0, NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); // Shop - PrepareStatement(CHAR_SEL_SHOP, "SELECT id, type, itemId, itemCount FROM character_shop WHERE guid = ? AND delivered = 0", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_SHOP, "SELECT id, type, itemId, itemCount FROM character_shop WHERE `guid` = ? AND delivered = 0", CONNECTION_SYNCH); PrepareStatement(CHAR_UPD_SHOP_DELIVERED, "UPDATE character_shop SET delivered = 1 WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_RECOVERY, "SELECT id, race, class, level, skill1, skill1_value, skill2, skill2_value, items, spells, at_login FROM character_recovery WHERE account = ? and delivered = 0", CONNECTION_SYNCH); PrepareStatement(CHAR_UPD_RECOVERY_DELIVERED, "UPDATE character_recovery SET delivered = 1 WHERE id = ?", CONNECTION_ASYNC); } -CharacterDatabaseConnection::CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) -{ -} - -CharacterDatabaseConnection::CharacterDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +CharacterDatabaseConnection::CharacterDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags) : MySQLConnection(connInfo, connectionFlags) { } diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index 22bc1da7d55..6bdcb0eca4e 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -661,13 +661,12 @@ class TC_DATABASE_API CharacterDatabaseConnection : public MySQLConnection public: typedef CharacterDatabaseStatements Statements; - //- Constructors for sync and async connections - CharacterDatabaseConnection(MySQLConnectionInfo& connInfo); - CharacterDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo); + CharacterDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags); ~CharacterDatabaseConnection(); //- Loads database type specific prepared statements void DoPrepareStatements() override; }; + #endif diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 64875adf453..409be505df0 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -19,7 +19,7 @@ // Autogenerated from DB2Structure.h #include "HotfixDatabase.h" -#include "PreparedStatement.h" +#include "MySQLPreparedStatement.h" // Force locale statments to appear exactly in locale declaration order, right after normal data fetch statement #define PREPARE_LOCALE_STMT(stmtBase, sql, con) \ @@ -1165,11 +1165,7 @@ void HotfixDatabaseConnection::DoPrepareStatements() PREPARE_LOCALE_STMT(HOTFIX_SEL_WORLD_SAFE_LOCS, "SELECT ID, AreaName_lang FROM world_safe_locs_locale WHERE locale = ?", CONNECTION_SYNCH); } -HotfixDatabaseConnection::HotfixDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) -{ -} - -HotfixDatabaseConnection::HotfixDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +HotfixDatabaseConnection::HotfixDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags) : MySQLConnection(connInfo, connectionFlags) { } diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index 592996db54c..52aa907d718 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -624,9 +624,7 @@ class TC_DATABASE_API HotfixDatabaseConnection : public MySQLConnection public: typedef HotfixDatabaseStatements Statements; - //- Constructors for sync and async connections - HotfixDatabaseConnection(MySQLConnectionInfo& connInfo); - HotfixDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo); + HotfixDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags); ~HotfixDatabaseConnection(); //- Loads database type specific prepared statements diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 3809a944248..ff3dc4ad16a 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -16,7 +16,7 @@ */ #include "LoginDatabase.h" -#include "PreparedStatement.h" +#include "MySQLPreparedStatement.h" void LoginDatabaseConnection::DoPrepareStatements() { @@ -109,8 +109,8 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT_MUTE, "INSERT INTO account_muted VALUES (?, UNIX_TIMESTAMP(), ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO, "SELECT mutedate, mutetime, mutereason, mutedby FROM account_muted WHERE guid = ? ORDER BY mutedate ASC", CONNECTION_SYNCH); - PrepareStatement(LOGIN_DEL_ACCOUNT_MUTED, "DELETE FROM account_muted WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO, "SELECT mutedate, mutetime, mutereason, mutedby FROM account_muted WHERE `guid` = ? ORDER BY mutedate ASC", CONNECTION_SYNCH); + PrepareStatement(LOGIN_DEL_ACCOUNT_MUTED, "DELETE FROM account_muted WHERE `guid` = ?", CONNECTION_ASYNC); #define BnetAccountInfo "ba.id, UPPER(ba.email), ba.locked, ba.lock_country, ba.last_ip, ba.LoginTicketExpiry, bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, bab.unbandate = bab.bandate" #define BnetGameAccountInfo "a.id, a.username, ab.unbandate, ab.unbandate = ab.bandate, aa.gmlevel" @@ -156,9 +156,9 @@ void LoginDatabaseConnection::DoPrepareStatements() // Battle Pets PrepareStatement(LOGIN_SEL_BATTLE_PETS, "SELECT guid, species, breed, level, exp, health, quality, flags, name FROM battle_pets WHERE battlenetAccountId = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_INS_BATTLE_PETS, "INSERT INTO battle_pets (guid, battlenetAccountId, species, breed, level, exp, health, quality, flags, name) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(LOGIN_DEL_BATTLE_PETS, "DELETE FROM battle_pets WHERE battlenetAccountId = ? AND guid = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_BATTLE_PETS, "UPDATE battle_pets SET level = ?, exp = ?, health = ?, quality = ?, flags = ?, name = ? WHERE battlenetAccountId = ? AND guid = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_BATTLE_PETS, "INSERT INTO battle_pets (`guid`, battlenetAccountId, species, breed, level, exp, health, quality, flags, name) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_BATTLE_PETS, "DELETE FROM battle_pets WHERE battlenetAccountId = ? AND `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_BATTLE_PETS, "UPDATE battle_pets SET level = ?, exp = ?, health = ?, quality = ?, flags = ?, name = ? WHERE battlenetAccountId = ? AND `guid` = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BATTLE_PET_SLOTS, "SELECT id, battlePetGuid, locked FROM battle_pet_slots WHERE battlenetAccountId = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_BATTLE_PET_SLOTS, "INSERT INTO battle_pet_slots (id, battlenetAccountId, battlePetGuid, locked) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_BATTLE_PET_SLOTS, "DELETE FROM battle_pet_slots WHERE battlenetAccountId = ?", CONNECTION_ASYNC); @@ -179,11 +179,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_BNET_ITEM_FAVORITE_APPEARANCE, "DELETE FROM battlenet_item_favorite_appearances WHERE battlenetAccountId = ? AND itemModifiedAppearanceId = ?", CONNECTION_ASYNC); } -LoginDatabaseConnection::LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) -{ -} - -LoginDatabaseConnection::LoginDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +LoginDatabaseConnection::LoginDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags) : MySQLConnection(connInfo, connectionFlags) { } diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index bcea6bab8e7..4a83c24f0af 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -172,9 +172,7 @@ class TC_DATABASE_API LoginDatabaseConnection : public MySQLConnection public: typedef LoginDatabaseStatements Statements; - //- Constructors for sync and async connections - LoginDatabaseConnection(MySQLConnectionInfo& connInfo); - LoginDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo); + LoginDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags); ~LoginDatabaseConnection(); //- Loads database type specific prepared statements diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index c14187dd353..a5bde9cd918 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -16,7 +16,7 @@ */ #include "WorldDatabase.h" -#include "PreparedStatement.h" +#include "MySQLPreparedStatement.h" void WorldDatabaseConnection::DoPrepareStatements() { @@ -79,7 +79,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); @@ -96,11 +96,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_GUILD_REWARDS_REQ_ACHIEVEMENTS, "SELECT AchievementRequired FROM guild_rewards_req_achievements WHERE ItemID = ?", CONNECTION_SYNCH); } -WorldDatabaseConnection::WorldDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) -{ -} - -WorldDatabaseConnection::WorldDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +WorldDatabaseConnection::WorldDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags) : MySQLConnection(connInfo, connectionFlags) { } diff --git a/src/server/database/Database/Implementation/WorldDatabase.h b/src/server/database/Database/Implementation/WorldDatabase.h index 6fb5efddd96..79538b55b64 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.h +++ b/src/server/database/Database/Implementation/WorldDatabase.h @@ -106,16 +106,14 @@ enum WorldDatabaseStatements : uint32 class TC_DATABASE_API WorldDatabaseConnection : public MySQLConnection { -public: - typedef WorldDatabaseStatements Statements; + public: + typedef WorldDatabaseStatements Statements; - //- Constructors for sync and async connections - WorldDatabaseConnection(MySQLConnectionInfo& connInfo); - WorldDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo); - ~WorldDatabaseConnection(); + WorldDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags); + ~WorldDatabaseConnection(); - //- Loads database type specific prepared statements - void DoPrepareStatements() override; + //- Loads database type specific prepared statements + void DoPrepareStatements() override; }; #endif diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp index 56397c974aa..bfd7fc1668a 100644 --- a/src/server/database/Database/MySQLConnection.cpp +++ b/src/server/database/Database/MySQLConnection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -17,53 +17,50 @@ #include "MySQLConnection.h" #include "Common.h" -#include "DatabaseWorker.h" +#include "IoContext.h" #include "Log.h" +#include "MySQLHacks.h" +#include "MySQLPreparedStatement.h" #include "PreparedStatement.h" #include "QueryResult.h" +#include "StringConvert.h" #include "Timer.h" #include "Transaction.h" #include "Util.h" -#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7 -#include -#endif #include -#include +#include "MySQLWorkaround.h" #include MySQLConnectionInfo::MySQLConnectionInfo(std::string const& infoString) { - Tokenizer tokens(infoString, ';'); + std::vector tokens = Trinity::Tokenize(infoString, ';', true); - if (tokens.size() != 5) + if (tokens.size() != 5 && tokens.size() != 6) return; - uint8 i = 0; + host.assign(tokens[0]); + port_or_socket.assign(tokens[1]); + user.assign(tokens[2]); + password.assign(tokens[3]); + database.assign(tokens[4]); - host.assign(tokens[i++]); - port_or_socket.assign(tokens[i++]); - user.assign(tokens[i++]); - password.assign(tokens[i++]); - database.assign(tokens[i++]); + if (tokens.size() == 6) + ssl.assign(tokens[5]); } -MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) : -m_reconnecting(false), -m_prepareError(false), -m_queue(NULL), -m_Mysql(NULL), -m_connectionInfo(connInfo), -m_connectionFlags(CONNECTION_SYNCH) { } +struct MySQLConnection::WorkerThread +{ + std::thread ThreadHandle; + boost::asio::executor_work_guard WorkGuard; +}; -MySQLConnection::MySQLConnection(ProducerConsumerQueue* queue, MySQLConnectionInfo& connInfo) : +MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags) : m_reconnecting(false), m_prepareError(false), -m_queue(queue), -m_Mysql(NULL), +m_Mysql(nullptr), m_connectionInfo(connInfo), -m_connectionFlags(CONNECTION_ASYNC) +m_connectionFlags(connectionFlags) { - m_worker = Trinity::make_unique(m_queue, this); } MySQLConnection::~MySQLConnection() @@ -74,7 +71,12 @@ MySQLConnection::~MySQLConnection() void MySQLConnection::Close() { // Stop the worker thread before the statements are cleared - m_worker.reset(); + if (m_workerThread) + { + m_workerThread->WorkGuard.reset(); + m_workerThread->ThreadHandle.join(); + m_workerThread.reset(); + } m_stmts.clear(); @@ -88,50 +90,67 @@ void MySQLConnection::Close() uint32 MySQLConnection::Open() { MYSQL *mysqlInit; - mysqlInit = mysql_init(NULL); + mysqlInit = mysql_init(nullptr); if (!mysqlInit) { TC_LOG_ERROR("sql.sql", "Could not initialize Mysql connection to database `%s`", m_connectionInfo.database.c_str()); return CR_UNKNOWN_ERROR; } - int port; - char const* unix_socket; + int port = 0; + char const* unix_socket = nullptr; //unsigned int timeout = 10; - mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8"); + mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8mb4"); //mysql_options(mysqlInit, MYSQL_OPT_READ_TIMEOUT, (char const*)&timeout); - #ifdef _WIN32 - if (m_connectionInfo.host == ".") // named pipe use option (Windows) + if (m_connectionInfo.host != ".") { - unsigned int opt = MYSQL_PROTOCOL_PIPE; - mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt); - port = 0; - unix_socket = 0; - } - else // generic case - { - port = atoi(m_connectionInfo.port_or_socket.c_str()); - unix_socket = 0; + port = Trinity::StringTo(m_connectionInfo.port_or_socket).value_or(0); } - #else - if (m_connectionInfo.host == ".") // socket use option (Unix/Linux) + else // named pipe/unix socket option { - unsigned int opt = MYSQL_PROTOCOL_SOCKET; - mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt); +#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS + unsigned int opt = MYSQL_PROTOCOL_PIPE; +#else m_connectionInfo.host = "localhost"; - port = 0; unix_socket = m_connectionInfo.port_or_socket.c_str(); + unsigned int opt = MYSQL_PROTOCOL_SOCKET; +#endif + mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt); + +#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000 + /* + ensure connections over named pipes work for users authenticating with caching_sha2_password + + If the mysql server is restarted, and you connect it using named pipe, the connection will fail and it will continue to fail until you connect it using tcp. + Source: https://bugs.mysql.com/bug.php?id=106852 + */ + MySQLBool geterverPublicKey = MySQLBool(1); + mysql_options(mysqlInit, MYSQL_OPT_GET_SERVER_PUBLIC_KEY, (char const*)&geterverPublicKey); +#endif } - else // generic case + + if (!m_connectionInfo.ssl.empty()) { - port = atoi(m_connectionInfo.port_or_socket.c_str()); - unix_socket = nullptr; +#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000 + mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED; + if (m_connectionInfo.ssl == "ssl") + { + opt_use_ssl = SSL_MODE_REQUIRED; + } + mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl); +#else + MySQLBool opt_use_ssl = MySQLBool(0); + if (m_connectionInfo.ssl == "ssl") + { + opt_use_ssl = MySQLBool(1); + } + mysql_options(mysqlInit, MYSQL_OPT_SSL_ENFORCE, (char const*)&opt_use_ssl); +#endif } - #endif - m_Mysql = mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(), - m_connectionInfo.password.c_str(), m_connectionInfo.database.c_str(), port, unix_socket, 0); + m_Mysql = reinterpret_cast(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(), + m_connectionInfo.password.c_str(), m_connectionInfo.database.c_str(), port, unix_socket, 0)); if (m_Mysql) { @@ -149,14 +168,15 @@ uint32 MySQLConnection::Open() // set connection properties to UTF8 to properly handle locales for different // server configs - core sends data in UTF8, so MySQL must expect UTF8 too - mysql_set_character_set(m_Mysql, "utf8"); + mysql_set_character_set(m_Mysql, "utf8mb4"); return 0; } else { TC_LOG_ERROR("sql.sql", "Could not connect to MySQL database at %s: %s", m_connectionInfo.host.c_str(), mysql_error(mysqlInit)); + uint32 errorCode = mysql_errno(mysqlInit); mysql_close(mysqlInit); - return mysql_errno(mysqlInit); + return errorCode; } } @@ -166,7 +186,7 @@ bool MySQLConnection::PrepareStatements() return !m_prepareError; } -bool MySQLConnection::Execute(const char* sql) +bool MySQLConnection::Execute(char const* sql) { if (!m_Mysql) return false; @@ -193,130 +213,143 @@ bool MySQLConnection::Execute(const char* sql) return true; } -bool MySQLConnection::Execute(PreparedStatement* stmt) +static auto mysql_bind_param_no_deprecated(MYSQL_STMT* stmt, MYSQL_BIND* bnd) +{ +#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#else +#pragma warning(push) +#pragma warning(disable: 4996) +#endif + + return mysql_stmt_bind_param(stmt, bnd); + +#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#pragma GCC diagnostic pop +#else +#pragma warning(pop) +#endif +} + +bool MySQLConnection::Execute(PreparedStatementBase* stmt) { if (!m_Mysql) return false; - uint32 index = stmt->m_index; - { - MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); - ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query - m_mStmt->m_stmt = stmt; // Cross reference them for debug output - stmt->m_stmt = m_mStmt; /// @todo Cleaner way - - stmt->BindParameters(); + uint32 index = stmt->GetIndex(); - MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); - MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); + MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); + ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query - uint32 _s = getMSTime(); + m_mStmt->BindParameters(stmt); - if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) - { - uint32 lErrno = mysql_errno(m_Mysql); - TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); + MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); + MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); - if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) - return Execute(stmt); // Try again + uint32 _s = getMSTime(); - m_mStmt->ClearParameters(); - return false; - } + if (mysql_bind_param_no_deprecated(msql_STMT, msql_BIND)) + { + uint32 lErrno = mysql_errno(m_Mysql); + TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT)); - if (mysql_stmt_execute(msql_STMT)) - { - uint32 lErrno = mysql_errno(m_Mysql); - TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); + if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) + return Execute(stmt); // Try again - if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) - return Execute(stmt); // Try again + m_mStmt->ClearParameters(); + return false; + } - m_mStmt->ClearParameters(); - return false; - } + if (mysql_stmt_execute(msql_STMT)) + { + uint32 lErrno = mysql_errno(m_Mysql); + TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT)); - TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str()); + if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) + return Execute(stmt); // Try again m_mStmt->ClearParameters(); - return true; + return false; } + + TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString().c_str()); + + m_mStmt->ClearParameters(); + return true; } -bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint64* pRowCount, uint32* pFieldCount) +bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement** mysqlStmt, MySQLResult** pResult, uint64* pRowCount, uint32* pFieldCount) { if (!m_Mysql) return false; - uint32 index = stmt->m_index; - { - MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); - ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query - m_mStmt->m_stmt = stmt; // Cross reference them for debug output - stmt->m_stmt = m_mStmt; /// @todo Cleaner way + uint32 index = stmt->GetIndex(); - stmt->BindParameters(); + MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); + ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query - MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); - MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); + m_mStmt->BindParameters(stmt); + *mysqlStmt = m_mStmt; - uint32 _s = getMSTime(); + MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); + MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); - if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) - { - uint32 lErrno = mysql_errno(m_Mysql); - TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); + uint32 _s = getMSTime(); - if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) - return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again - - m_mStmt->ClearParameters(); - return false; - } + if (mysql_bind_param_no_deprecated(msql_STMT, msql_BIND)) + { + uint32 lErrno = mysql_errno(m_Mysql); + TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT)); - if (mysql_stmt_execute(msql_STMT)) - { - uint32 lErrno = mysql_errno(m_Mysql); - TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", - m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); + if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) + return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again - if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) - return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again + m_mStmt->ClearParameters(); + return false; + } - m_mStmt->ClearParameters(); - return false; - } + if (mysql_stmt_execute(msql_STMT)) + { + uint32 lErrno = mysql_errno(m_Mysql); + TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", + m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT)); - TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str()); + if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) + return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again m_mStmt->ClearParameters(); + return false; + } - *pResult = mysql_stmt_result_metadata(msql_STMT); - *pRowCount = mysql_stmt_num_rows(msql_STMT); - *pFieldCount = mysql_stmt_field_count(msql_STMT); + TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString().c_str()); - return true; + m_mStmt->ClearParameters(); - } + *pResult = reinterpret_cast(mysql_stmt_result_metadata(msql_STMT)); + *pRowCount = mysql_stmt_num_rows(msql_STMT); + *pFieldCount = mysql_stmt_field_count(msql_STMT); + + return true; } -ResultSet* MySQLConnection::Query(const char* sql) +ResultSet* MySQLConnection::Query(char const* sql) { if (!sql) - return NULL; + return nullptr; - MYSQL_RES *result = NULL; - MYSQL_FIELD *fields = NULL; + MySQLResult* result = nullptr; + MySQLField* fields = nullptr; uint64 rowCount = 0; uint32 fieldCount = 0; if (!_Query(sql, &result, &fields, &rowCount, &fieldCount)) - return NULL; + return nullptr; return new ResultSet(result, fields, rowCount, fieldCount); } -bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount) +bool MySQLConnection::_Query(const char* sql, MySQLResult** pResult, MySQLField** pFields, uint64* pRowCount, uint32* pFieldCount) { if (!m_Mysql) return false; @@ -338,7 +371,7 @@ bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD * else TC_LOG_DEBUG("sql.sql", "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql); - *pResult = mysql_store_result(m_Mysql); + *pResult = reinterpret_cast(mysql_store_result(m_Mysql)); *pRowCount = mysql_affected_rows(m_Mysql); *pFieldCount = mysql_field_count(m_Mysql); } @@ -352,7 +385,7 @@ bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD * return false; } - *pFields = mysql_fetch_fields(*pResult); + *pFields = reinterpret_cast(mysql_fetch_fields(*pResult)); return true; } @@ -372,9 +405,9 @@ void MySQLConnection::CommitTransaction() Execute("COMMIT"); } -int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) +int MySQLConnection::ExecuteTransaction(std::shared_ptr transaction) { - std::vector const& queries = transaction->m_queries; + std::vector const& queries = transaction->m_queries; if (queries.empty()) return -1; @@ -382,35 +415,12 @@ int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) for (auto itr = queries.begin(); itr != queries.end(); ++itr) { - SQLElementData const& data = *itr; - switch (itr->type) + if (!std::visit([this](auto&& data) { return this->Execute(TransactionData::ToExecutable(data)); }, itr->query)) { - case SQL_ELEMENT_PREPARED: - { - PreparedStatement* stmt = data.element.stmt; - ASSERT(stmt); - if (!Execute(stmt)) - { - TC_LOG_WARN("sql.sql", "Transaction aborted. %u queries not executed.", (uint32)queries.size()); - int errorCode = GetLastError(); - RollbackTransaction(); - return errorCode; - } - } - break; - case SQL_ELEMENT_RAW: - { - const char* sql = data.element.query; - ASSERT(sql); - if (!Execute(sql)) - { - TC_LOG_WARN("sql.sql", "Transaction aborted. %u queries not executed.", (uint32)queries.size()); - int errorCode = GetLastError(); - RollbackTransaction(); - return errorCode; - } - } - break; + TC_LOG_WARN("sql.sql", "Transaction aborted. %zu queries not executed.", queries.size()); + int errorCode = GetLastError(); + RollbackTransaction(); + return errorCode; } } @@ -423,6 +433,11 @@ int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) return 0; } +size_t MySQLConnection::EscapeString(char* to, const char* from, size_t length) +{ + return mysql_real_escape_string(m_Mysql, to, from, length); +} + void MySQLConnection::Ping() { mysql_ping(m_Mysql); @@ -433,6 +448,24 @@ uint32 MySQLConnection::GetLastError() return mysql_errno(m_Mysql); } +void MySQLConnection::StartWorkerThread(Trinity::Asio::IoContext* context) +{ + boost::asio::executor_work_guard executorWorkGuard = boost::asio::make_work_guard(context->get_executor()); // construct guard before thread starts running + + m_workerThread = std::make_unique(WorkerThread{ + .ThreadHandle = std::thread([context] { context->run(); }), + .WorkGuard = std::move(executorWorkGuard) + }); +} + +std::thread::id MySQLConnection::GetWorkerThreadId() const +{ + if (m_workerThread) + return m_workerThread->ThreadHandle.get_id(); + + return {}; +} + bool MySQLConnection::LockIfReady() { return m_Mutex.try_lock(); @@ -443,9 +476,15 @@ void MySQLConnection::Unlock() m_Mutex.unlock(); } +uint32 MySQLConnection::GetServerVersion() const +{ + return mysql_get_server_version(m_Mysql); +} + MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index) { - ASSERT(index < m_stmts.size()); + ASSERT(index < m_stmts.size(), "Tried to access invalid prepared statement index %u (max index " SZFMTD ") on database `%s`, connection type: %s", + index, m_stmts.size(), m_connectionInfo.database.c_str(), (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); MySQLPreparedStatement* ret = m_stmts[index].get(); if (!ret) TC_LOG_ERROR("sql.sql", "Could not fetch prepared statement %u on database `%s`, connection type: %s.", @@ -454,10 +493,8 @@ MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index) return ret; } -void MySQLConnection::PrepareStatement(uint32 index, const char* sql, ConnectionFlags flags) +void MySQLConnection::PrepareStatement(uint32 index, std::string_view sql, ConnectionFlags flags) { - m_queries.insert(PreparedStatementMap::value_type(index, std::make_pair(sql, flags))); - // Check if specified query should be prepared on this connection // i.e. don't prepare async statements on synchronous connections // to save memory that will not be used. @@ -476,7 +513,7 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection } else { - if (mysql_stmt_prepare(stmt, sql, static_cast(strlen(sql)))) + if (mysql_stmt_prepare(stmt, sql.data(), static_cast(sql.size()))) { TC_LOG_ERROR("sql.sql", "In mysql_stmt_prepare() id: %u, sql: \"%s\"", index, sql); TC_LOG_ERROR("sql.sql", "%s", mysql_stmt_error(stmt)); @@ -484,26 +521,25 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection m_prepareError = true; } else - { - m_stmts[index] = Trinity::make_unique(stmt); - } + m_stmts[index] = std::make_unique(reinterpret_cast(stmt), std::string(sql)); } } -PreparedResultSet* MySQLConnection::Query(PreparedStatement* stmt) +PreparedResultSet* MySQLConnection::Query(PreparedStatementBase* stmt) { - MYSQL_RES *result = NULL; + MySQLPreparedStatement* mysqlStmt = nullptr; + MySQLResult* result = nullptr; uint64 rowCount = 0; uint32 fieldCount = 0; - if (!_Query(stmt, &result, &rowCount, &fieldCount)) - return NULL; + if (!_Query(stmt, &mysqlStmt, &result, &rowCount, &fieldCount)) + return nullptr; if (mysql_more_results(m_Mysql)) { mysql_next_result(m_Mysql); } - return new PreparedResultSet(stmt->m_stmt->GetSTMT(), result, rowCount, fieldCount); + return new PreparedResultSet(mysqlStmt->GetSTMT(), result, rowCount, fieldCount); } bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/) @@ -518,11 +554,10 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/) { TC_LOG_ERROR("sql.sql", "Lost the connection to the MySQL server!"); - mysql_close(GetHandle()); + mysql_close(m_Mysql); m_Mysql = nullptr; } - - /*no break*/ + [[fallthrough]]; } case CR_CONN_HOST_ERROR: { @@ -538,7 +573,7 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/) { TC_LOG_FATAL("sql.sql", "Could not re-prepare statements!"); std::this_thread::sleep_for(std::chrono::seconds(10)); - std::abort(); + ABORT(); } TC_LOG_INFO("sql.sql", "Successfully reconnected to %s @%s:%s (%s).", @@ -558,7 +593,7 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/) // We could also initiate a shutdown through using std::raise(SIGTERM) std::this_thread::sleep_for(std::chrono::seconds(10)); - std::abort(); + ABORT(); } else { @@ -581,12 +616,12 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/) case ER_NO_SUCH_TABLE: TC_LOG_ERROR("sql.sql", "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders."); std::this_thread::sleep_for(std::chrono::seconds(10)); - std::abort(); + ABORT(); return false; case ER_PARSE_ERROR: TC_LOG_ERROR("sql.sql", "Error while parsing SQL. Core fix required."); std::this_thread::sleep_for(std::chrono::seconds(10)); - std::abort(); + ABORT(); return false; default: TC_LOG_ERROR("sql.sql", "Unhandled MySQL errno %u. Unexpected behaviour possible.", errNo); diff --git a/src/server/database/Database/MySQLConnection.h b/src/server/database/Database/MySQLConnection.h index f98aaa35b07..2b9a96e6a28 100644 --- a/src/server/database/Database/MySQLConnection.h +++ b/src/server/database/Database/MySQLConnection.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,20 +18,16 @@ #ifndef _MYSQLCONNECTION_H #define _MYSQLCONNECTION_H +#include "AsioHacksFwd.h" #include "Define.h" #include "DatabaseEnvFwd.h" -#include #include #include #include +#include #include -template -class ProducerConsumerQueue; - -class DatabaseWorker; class MySQLPreparedStatement; -class SQLOperation; enum ConnectionFlags { @@ -49,42 +45,42 @@ struct TC_DATABASE_API MySQLConnectionInfo std::string database; std::string host; std::string port_or_socket; + std::string ssl; }; -typedef std::map > PreparedStatementMap; - class TC_DATABASE_API MySQLConnection { template friend class DatabaseWorkerPool; friend class PingOperation; public: - MySQLConnection(MySQLConnectionInfo& connInfo); //! Constructor for synchronous connections. - MySQLConnection(ProducerConsumerQueue* queue, MySQLConnectionInfo& connInfo); //! Constructor for asynchronous connections. + MySQLConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags); virtual ~MySQLConnection(); - virtual uint32 Open(); + uint32 Open(); void Close(); bool PrepareStatements(); - public: - bool Execute(const char* sql); - bool Execute(PreparedStatement* stmt); - ResultSet* Query(const char* sql); - PreparedResultSet* Query(PreparedStatement* stmt); - bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount); - bool _Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint64* pRowCount, uint32* pFieldCount); + bool Execute(char const* sql); + bool Execute(PreparedStatementBase* stmt); + ResultSet* Query(char const* sql); + PreparedResultSet* Query(PreparedStatementBase* stmt); + bool _Query(char const* sql, MySQLResult** pResult, MySQLField** pFields, uint64* pRowCount, uint32* pFieldCount); + bool _Query(PreparedStatementBase* stmt, MySQLPreparedStatement** mysqlStmt, MySQLResult** pResult, uint64* pRowCount, uint32* pFieldCount); void BeginTransaction(); void RollbackTransaction(); void CommitTransaction(); - int ExecuteTransaction(SQLTransaction& transaction); - + int ExecuteTransaction(std::shared_ptr transaction); + size_t EscapeString(char* to, const char* from, size_t length); void Ping(); uint32 GetLastError(); + void StartWorkerThread(Trinity::Asio::IoContext* context); + std::thread::id GetWorkerThreadId() const; + protected: /// Tries to acquire lock. If lock is acquired by another thread /// the calling parent will just try another connection @@ -93,27 +89,26 @@ class TC_DATABASE_API MySQLConnection /// Called by parent databasepool. Will let other threads access this connection void Unlock(); - MYSQL* GetHandle() { return m_Mysql; } + uint32 GetServerVersion() const; MySQLPreparedStatement* GetPreparedStatement(uint32 index); - void PrepareStatement(uint32 index, const char* sql, ConnectionFlags flags); + void PrepareStatement(uint32 index, std::string_view sql, ConnectionFlags flags); virtual void DoPrepareStatements() = 0; - protected: - std::vector> m_stmts; //! PreparedStatements storage - PreparedStatementMap m_queries; //! Query storage - bool m_reconnecting; //! Are we reconnecting? - bool m_prepareError; //! Was there any error while preparing statements? + typedef std::vector> PreparedStatementContainer; + + PreparedStatementContainer m_stmts; //!< PreparedStatements storage + bool m_reconnecting; //!< Are we reconnecting? + bool m_prepareError; //!< Was there any error while preparing statements? private: bool _HandleMySQLErrno(uint32 errNo, uint8 attempts = 5); - private: - ProducerConsumerQueue* m_queue; //! Queue shared with other asynchronous connections. - std::unique_ptr m_worker; //! Core worker task. - MYSQL* m_Mysql; //! MySQL Handle. - MySQLConnectionInfo& m_connectionInfo; //! Connection info (used for logging) - ConnectionFlags m_connectionFlags; //! Connection flags (for preparing relevant statements) + struct WorkerThread; + std::unique_ptr m_workerThread; //!< Core worker thread. + MySQLHandle* m_Mysql; //!< MySQL Handle. + MySQLConnectionInfo& m_connectionInfo; //!< Connection info (used for logging) + ConnectionFlags m_connectionFlags; //!< Connection flags (for preparing relevant statements) std::mutex m_Mutex; MySQLConnection(MySQLConnection const& right) = delete; diff --git a/src/server/database/Database/QueryCallbackProcessor.h b/src/server/database/Database/MySQLHacks.h similarity index 50% rename from src/server/database/Database/QueryCallbackProcessor.h rename to src/server/database/Database/MySQLHacks.h index d5ff959a32f..6f2767fb1d1 100644 --- a/src/server/database/Database/QueryCallbackProcessor.h +++ b/src/server/database/Database/MySQLHacks.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -15,28 +15,20 @@ * with this program. If not, see . */ -#ifndef QueryCallbackProcessor_h__ -#define QueryCallbackProcessor_h__ +#ifndef MySQLHacks_h__ +#define MySQLHacks_h__ -#include "Define.h" -#include +#include "MySQLWorkaround.h" +#include -class QueryCallback; +struct MySQLHandle : MYSQL { }; +struct MySQLResult : MYSQL_RES { }; +struct MySQLField : MYSQL_FIELD { }; +struct MySQLBind : MYSQL_BIND { }; +struct MySQLStmt : MYSQL_STMT { }; -class TC_DATABASE_API QueryCallbackProcessor -{ -public: - QueryCallbackProcessor(); - ~QueryCallbackProcessor(); +// mysql 8 removed my_bool typedef (it was char) and started using bools directly +// to maintain compatibility we use this trick to retrieve which type is being used +using MySQLBool = std::remove_pointer_t().is_null)>; - void AddQuery(QueryCallback&& query); - void ProcessReadyQueries(); - -private: - QueryCallbackProcessor(QueryCallbackProcessor const&) = delete; - QueryCallbackProcessor& operator=(QueryCallbackProcessor const&) = delete; - - std::vector _callbacks; -}; - -#endif // QueryCallbackProcessor_h__ +#endif // MySQLHacks_h__ diff --git a/src/server/database/Database/MySQLPreparedStatement.cpp b/src/server/database/Database/MySQLPreparedStatement.cpp new file mode 100644 index 00000000000..5c8da20caee --- /dev/null +++ b/src/server/database/Database/MySQLPreparedStatement.cpp @@ -0,0 +1,229 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "MySQLPreparedStatement.h" +#include "Errors.h" +#include "Log.h" +#include "MySQLHacks.h" +#include "PreparedStatement.h" +#include +#include + +template +struct MySQLType { }; + +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; + +MySQLPreparedStatement::MySQLPreparedStatement(MySQLStmt* stmt, std::string queryString) : + m_stmt(nullptr), m_Mstmt(stmt), m_bind(nullptr), m_queryString(std::move(queryString)) +{ + /// Initialize variable parameters + m_paramCount = mysql_stmt_param_count(stmt); + m_paramsSet.assign(m_paramCount, false); + m_bind = new MySQLBind[m_paramCount]; + memset(m_bind, 0, sizeof(MySQLBind) * m_paramCount); + + /// "If set to 1, causes mysql_stmt_store_result() to update the metadata MYSQL_FIELD->max_length value." + MySQLBool bool_tmp = MySQLBool(1); + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &bool_tmp); +} + +MySQLPreparedStatement::~MySQLPreparedStatement() +{ + ClearParameters(); + if (m_Mstmt->bind_result_done) + { + delete[] m_Mstmt->bind->length; + delete[] m_Mstmt->bind->is_null; + } + mysql_stmt_close(m_Mstmt); + delete[] m_bind; +} + +void MySQLPreparedStatement::BindParameters(PreparedStatementBase* stmt) +{ + m_stmt = stmt; // Cross reference them for debug output + + uint8 pos = 0; + for (PreparedStatementData const& data : stmt->GetParameters()) + { + std::visit([&](auto&& param) + { + SetParameter(pos, param); + }, data.data); + ++pos; + } +#ifdef _DEBUG + if (pos < m_paramCount) + TC_LOG_WARN("sql.sql", "[WARNING]: BindParameters() for statement %u did not bind all allocated parameters", stmt->GetIndex()); +#endif +} + +void MySQLPreparedStatement::ClearParameters() +{ + for (uint32 i=0; i < m_paramCount; ++i) + { + delete m_bind[i].length; + m_bind[i].length = nullptr; + delete[] (char*) m_bind[i].buffer; + m_bind[i].buffer = nullptr; + m_paramsSet[i] = false; + } +} + +static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount) +{ + TC_LOG_ERROR("sql.driver", "Attempted to bind parameter %u%s on a PreparedStatement %u (statement has only %u parameters)", uint32(index) + 1, (index == 1 ? "st" : (index == 2 ? "nd" : (index == 3 ? "rd" : "nd"))), stmtIndex, paramCount); + return false; +} + +//- Bind on mysql level +void MySQLPreparedStatement::AssertValidIndex(uint8 index) +{ + ASSERT(index < m_paramCount || ParamenterIndexAssertFail(m_stmt->GetIndex(), index, m_paramCount)); + + if (m_paramsSet[index]) + TC_LOG_ERROR("sql.sql", "[ERROR] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->GetIndex(), index); +} + +void MySQLPreparedStatement::SetParameter(uint8 index, std::nullptr_t) +{ + AssertValidIndex(index); + m_paramsSet[index] = true; + MYSQL_BIND* param = &m_bind[index]; + param->buffer_type = MYSQL_TYPE_NULL; + delete[] static_cast(param->buffer); + param->buffer = nullptr; + param->buffer_length = 0; + param->is_null_value = 1; + delete param->length; + param->length = nullptr; +} + +void MySQLPreparedStatement::SetParameter(uint8 index, bool value) +{ + SetParameter(index, uint8(value ? 1 : 0)); +} + +template +void MySQLPreparedStatement::SetParameter(uint8 index, T value) +{ + AssertValidIndex(index); + m_paramsSet[index] = true; + MYSQL_BIND* param = &m_bind[index]; + uint32 len = uint32(sizeof(T)); + param->buffer_type = MySQLType::value; + delete[] static_cast(param->buffer); + param->buffer = new char[len]; + param->buffer_length = 0; + param->is_null_value = 0; + param->length = nullptr; // Only != NULL for strings + param->is_unsigned = std::is_unsigned_v; + + memcpy(param->buffer, &value, len); +} + +void MySQLPreparedStatement::SetParameter(uint8 index, SystemTimePoint value) +{ + AssertValidIndex(index); + m_paramsSet[index] = true; + MYSQL_BIND* param = &m_bind[index]; + uint32 len = sizeof(MYSQL_TIME); + param->buffer_type = MYSQL_TYPE_DATETIME; + delete[] static_cast(param->buffer); + param->buffer = new char[len]; + param->buffer_length = len; + param->is_null_value = 0; + delete param->length; + param->length = new unsigned long(len); + + std::chrono::year_month_day ymd(time_point_cast(value)); + std::chrono::hh_mm_ss hms(duration_cast(value - std::chrono::sys_days(ymd))); + + MYSQL_TIME* time = reinterpret_cast(static_cast(param->buffer)); + time->year = static_cast(ymd.year()); + time->month = static_cast(ymd.month()); + time->day = static_cast(ymd.day()); + time->hour = hms.hours().count(); + time->minute = hms.minutes().count(); + time->second = hms.seconds().count(); + time->second_part = hms.subseconds().count(); +} + +void MySQLPreparedStatement::SetParameter(uint8 index, std::string const& value) +{ + AssertValidIndex(index); + m_paramsSet[index] = true; + MYSQL_BIND* param = &m_bind[index]; + uint32 len = uint32(value.size()); + param->buffer_type = MYSQL_TYPE_VAR_STRING; + delete [] static_cast(param->buffer); + param->buffer = new char[len]; + param->buffer_length = len; + param->is_null_value = 0; + delete param->length; + param->length = new unsigned long(len); + + memcpy(param->buffer, value.c_str(), len); +} + +void MySQLPreparedStatement::SetParameter(uint8 index, std::vector const& value) +{ + AssertValidIndex(index); + m_paramsSet[index] = true; + MYSQL_BIND* param = &m_bind[index]; + uint32 len = uint32(value.size()); + param->buffer_type = MYSQL_TYPE_BLOB; + delete [] static_cast(param->buffer); + param->buffer = new char[len]; + param->buffer_length = len; + param->is_null_value = 0; + delete param->length; + param->length = new unsigned long(len); + + memcpy(param->buffer, value.data(), len); +} + +std::string MySQLPreparedStatement::getQueryString() const +{ + std::string queryString(m_queryString); + + size_t pos = 0; + for (PreparedStatementData const& data : m_stmt->GetParameters()) + { + pos = queryString.find('?', pos); + + std::string replaceStr = std::visit([&](auto&& data) + { + return PreparedStatementData::ToString(data); + }, data.data); + + queryString.replace(pos, 1, replaceStr); + pos += replaceStr.length(); + } + + return queryString; +} diff --git a/src/server/database/Database/MySQLPreparedStatement.h b/src/server/database/Database/MySQLPreparedStatement.h new file mode 100644 index 00000000000..e30152f7f04 --- /dev/null +++ b/src/server/database/Database/MySQLPreparedStatement.h @@ -0,0 +1,73 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef MySQLPreparedStatement_h__ +#define MySQLPreparedStatement_h__ + +#include "DatabaseEnvFwd.h" +#include "Define.h" +#include "Duration.h" +#include +#include + +class MySQLConnection; +class PreparedStatementBase; + +//- Class of which the instances are unique per MySQLConnection +//- access to these class objects is only done when a prepared statement task +//- is executed. +class TC_DATABASE_API MySQLPreparedStatement +{ + friend class MySQLConnection; + friend class PreparedStatementBase; + + public: + MySQLPreparedStatement(MySQLStmt* stmt, std::string queryString); + ~MySQLPreparedStatement(); + + void BindParameters(PreparedStatementBase* stmt); + + uint32 GetParameterCount() const { return m_paramCount; } + + protected: + void SetParameter(uint8 index, std::nullptr_t); + void SetParameter(uint8 index, bool value); + template + void SetParameter(uint8 index, T value); + void SetParameter(uint8 index, SystemTimePoint value); + void SetParameter(uint8 index, std::string const& value); + void SetParameter(uint8 index, std::vector const& value); + + MySQLStmt* GetSTMT() { return m_Mstmt; } + MySQLBind* GetBind() { return m_bind; } + PreparedStatementBase* m_stmt; + void ClearParameters(); + void AssertValidIndex(uint8 index); + std::string getQueryString() const; + + private: + MySQLStmt* m_Mstmt; + uint32 m_paramCount; + std::vector m_paramsSet; + MySQLBind* m_bind; + std::string const m_queryString; + + MySQLPreparedStatement(MySQLPreparedStatement const& right) = delete; + MySQLPreparedStatement& operator=(MySQLPreparedStatement const& right) = delete; +}; + +#endif // MySQLPreparedStatement_h__ diff --git a/src/server/database/Database/MySQLThreading.cpp b/src/server/database/Database/MySQLThreading.cpp index a021a225e19..e3f396d543c 100644 --- a/src/server/database/Database/MySQLThreading.cpp +++ b/src/server/database/Database/MySQLThreading.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -16,17 +16,19 @@ */ #include "MySQLThreading.h" -#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7 -#include -#endif -#include +#include "MySQLWorkaround.h" void MySQL::Library_Init() { - mysql_library_init(-1, NULL, NULL); + mysql_library_init(-1, nullptr, nullptr); } void MySQL::Library_End() { mysql_library_end(); } + +uint32 MySQL::GetLibraryVersion() +{ + return MYSQL_VERSION_ID; +} diff --git a/src/server/database/Database/MySQLThreading.h b/src/server/database/Database/MySQLThreading.h index ad3ed6ce590..6e75bdee939 100644 --- a/src/server/database/Database/MySQLThreading.h +++ b/src/server/database/Database/MySQLThreading.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -22,8 +22,9 @@ namespace MySQL { - void TC_DATABASE_API Library_Init(); - void TC_DATABASE_API Library_End(); + TC_DATABASE_API void Library_Init(); + TC_DATABASE_API void Library_End(); + TC_DATABASE_API uint32 GetLibraryVersion(); }; #endif diff --git a/src/server/game/Scripting/JSEngine.h b/src/server/database/Database/MySQLWorkaround.h similarity index 65% rename from src/server/game/Scripting/JSEngine.h rename to src/server/database/Database/MySQLWorkaround.h index 16542c4d943..b9e15c260e8 100644 --- a/src/server/game/Scripting/JSEngine.h +++ b/src/server/database/Database/MySQLWorkaround.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 AshamaneProject + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -15,11 +15,12 @@ * with this program. If not, see . */ -#include "duktape\duktape.h" -#include "dukglue\dukglue.h" +#ifndef MySQLWorkaround_h__ +#define MySQLWorkaround_h__ -class JSEngine -{ -public: +#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7 +#include +#endif +#include -}; +#endif // MySQLWorkaround_h__ diff --git a/src/server/database/Database/PreparedStatement.cpp b/src/server/database/Database/PreparedStatement.cpp index 3a21dc634b5..ec2fb49907e 100644 --- a/src/server/database/Database/PreparedStatement.cpp +++ b/src/server/database/Database/PreparedStatement.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -19,488 +19,176 @@ #include "Errors.h" #include "MySQLConnection.h" #include "QueryResult.h" -#include "Log.h" -#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7 -#include -#endif -#include -#include +#include "StringFormat.h" +#include -PreparedStatement::PreparedStatement(uint32 index) : -m_stmt(NULL), -m_index(index) { } +PreparedStatementBase::PreparedStatementBase(uint32 index, uint8 capacity) : + m_index(index), statement_data(capacity) { } -PreparedStatement::~PreparedStatement() { } - -void PreparedStatement::BindParameters() -{ - ASSERT(m_stmt); - - uint8 i = 0; - for (; i < statement_data.size(); i++) - { - switch (statement_data[i].type) - { - case TYPE_BOOL: - m_stmt->setBool(i, statement_data[i].data.boolean); - break; - case TYPE_UI8: - m_stmt->setUInt8(i, statement_data[i].data.ui8); - break; - case TYPE_UI16: - m_stmt->setUInt16(i, statement_data[i].data.ui16); - break; - case TYPE_UI32: - m_stmt->setUInt32(i, statement_data[i].data.ui32); - break; - case TYPE_I8: - m_stmt->setInt8(i, statement_data[i].data.i8); - break; - case TYPE_I16: - m_stmt->setInt16(i, statement_data[i].data.i16); - break; - case TYPE_I32: - m_stmt->setInt32(i, statement_data[i].data.i32); - break; - case TYPE_UI64: - m_stmt->setUInt64(i, statement_data[i].data.ui64); - break; - case TYPE_I64: - m_stmt->setInt64(i, statement_data[i].data.i64); - break; - case TYPE_FLOAT: - m_stmt->setFloat(i, statement_data[i].data.f); - break; - case TYPE_DOUBLE: - m_stmt->setDouble(i, statement_data[i].data.d); - break; - case TYPE_STRING: - m_stmt->setBinary(i, statement_data[i].binary, true); - break; - case TYPE_BINARY: - m_stmt->setBinary(i, statement_data[i].binary, false); - break; - case TYPE_NULL: - m_stmt->setNull(i); - break; - } - } - #ifdef _DEBUG - if (i < m_stmt->m_paramCount) - TC_LOG_WARN("sql.sql", "[WARNING]: BindParameters() for statement %u did not bind all allocated parameters", m_index); - #endif -} +PreparedStatementBase::~PreparedStatementBase() { } //- Bind to buffer -void PreparedStatement::setBool(const uint8 index, const bool value) +void PreparedStatementBase::setBool(uint8 index, bool value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.boolean = value; - statement_data[index].type = TYPE_BOOL; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setUInt8(const uint8 index, const uint8 value) +void PreparedStatementBase::setUInt8(uint8 index, uint8 value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.ui8 = value; - statement_data[index].type = TYPE_UI8; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setUInt16(const uint8 index, const uint16 value) +void PreparedStatementBase::setUInt16(uint8 index, uint16 value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.ui16 = value; - statement_data[index].type = TYPE_UI16; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setUInt32(const uint8 index, const uint32 value) +void PreparedStatementBase::setUInt32(uint8 index, uint32 value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.ui32 = value; - statement_data[index].type = TYPE_UI32; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setUInt64(const uint8 index, const uint64 value) +void PreparedStatementBase::setUInt64(uint8 index, uint64 value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.ui64 = value; - statement_data[index].type = TYPE_UI64; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setInt8(const uint8 index, const int8 value) +void PreparedStatementBase::setInt8(uint8 index, int8 value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.i8 = value; - statement_data[index].type = TYPE_I8; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setInt16(const uint8 index, const int16 value) +void PreparedStatementBase::setInt16(uint8 index, int16 value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.i16 = value; - statement_data[index].type = TYPE_I16; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setInt32(const uint8 index, const int32 value) +void PreparedStatementBase::setInt32(uint8 index, int32 value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.i32 = value; - statement_data[index].type = TYPE_I32; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setInt64(const uint8 index, const int64 value) +void PreparedStatementBase::setInt64(uint8 index, int64 value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.i64 = value; - statement_data[index].type = TYPE_I64; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setFloat(const uint8 index, const float value) +void PreparedStatementBase::setFloat(uint8 index, float value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.f = value; - statement_data[index].type = TYPE_FLOAT; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setDouble(const uint8 index, const double value) +void PreparedStatementBase::setDouble(uint8 index, double value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].data.d = value; - statement_data[index].type = TYPE_DOUBLE; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setString(const uint8 index, const std::string& value) +void PreparedStatementBase::setDate(uint8 index, SystemTimePoint value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].binary.resize(value.length() + 1); - memcpy(statement_data[index].binary.data(), value.c_str(), value.length() + 1); - statement_data[index].type = TYPE_STRING; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setBinary(const uint8 index, const std::vector& value) +void PreparedStatementBase::setString(uint8 index, std::string const& value) { - if (index >= statement_data.size()) - statement_data.resize(index + 1); - - statement_data[index].binary = value; - statement_data[index].type = TYPE_BINARY; + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -void PreparedStatement::setNull(const uint8 index) +void PreparedStatementBase::setStringView(uint8 index, std::string_view value) { - if (index >= statement_data.size()) - statement_data.resize(index+1); - - statement_data[index].type = TYPE_NULL; + ASSERT(index < statement_data.size()); + statement_data[index].data.emplace(value); } -MySQLPreparedStatement::MySQLPreparedStatement(MYSQL_STMT* stmt) : -m_stmt(NULL), -m_Mstmt(stmt), -m_bind(NULL) +void PreparedStatementBase::setBinary(uint8 index, std::vector const& value) { - /// Initialize variable parameters - m_paramCount = mysql_stmt_param_count(stmt); - m_paramsSet.assign(m_paramCount, false); - m_bind = new MYSQL_BIND[m_paramCount]; - memset(m_bind, 0, sizeof(MYSQL_BIND)*m_paramCount); - - /// "If set to 1, causes mysql_stmt_store_result() to update the metadata MYSQL_FIELD->max_length value." - my_bool bool_tmp = 1; - mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &bool_tmp); + ASSERT(index < statement_data.size()); + statement_data[index].data = value; } -MySQLPreparedStatement::~MySQLPreparedStatement() +void PreparedStatementBase::setNull(uint8 index) { - ClearParameters(); - if (m_Mstmt->bind_result_done) - { - delete[] m_Mstmt->bind->length; - delete[] m_Mstmt->bind->is_null; - } - mysql_stmt_close(m_Mstmt); - delete[] m_bind; + ASSERT(index < statement_data.size()); + statement_data[index].data = nullptr; } -void MySQLPreparedStatement::ClearParameters() +//- Execution +PreparedQueryResult PreparedStatementTask::Query(MySQLConnection* conn, PreparedStatementBase* stmt) { - for (uint32 i=0; i < m_paramCount; ++i) + PreparedResultSet* result = conn->Query(stmt); + if (!result || !result->GetRowCount()) { - delete m_bind[i].length; - m_bind[i].length = NULL; - delete[] (char*) m_bind[i].buffer; - m_bind[i].buffer = NULL; - m_paramsSet[i] = false; + delete result; + result = nullptr; } -} - -static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount) -{ - TC_LOG_ERROR("sql.driver", "Attempted to bind parameter %u%s on a PreparedStatement %u (statement has only %u parameters)", uint32(index) + 1, (index == 1 ? "st" : (index == 2 ? "nd" : (index == 3 ? "rd" : "nd"))), stmtIndex, paramCount); - return false; -} -static void SetParameterValue(MYSQL_BIND* param, enum_field_types type, const void* value, uint32 len, bool isUnsigned) -{ - param->buffer_type = type; - delete[] static_cast(param->buffer); - param->buffer = new char[len]; - param->buffer_length = 0; - param->is_null_value = 0; - param->length = NULL; // Only != NULL for strings - param->is_unsigned = isUnsigned; - - memcpy(param->buffer, value, len); + return PreparedQueryResult(result); } -//- Bind on mysql level -void MySQLPreparedStatement::CheckValidIndex(uint8 index) +bool PreparedStatementTask::Execute(MySQLConnection* conn, PreparedStatementBase* stmt) { - ASSERT(index < m_paramCount || ParamenterIndexAssertFail(m_stmt->m_index, index, m_paramCount)); - - if (m_paramsSet[index]) - TC_LOG_WARN("sql.sql", "[WARNING] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->m_index, index); + return conn->Execute(stmt); } -void MySQLPreparedStatement::setNull(const uint8 index) +template +std::string PreparedStatementData::ToString(T value) { - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - param->buffer_type = MYSQL_TYPE_NULL; - delete[] static_cast(param->buffer); - param->buffer = NULL; - param->buffer_length = 0; - param->is_null_value = 1; - delete param->length; - param->length = NULL; + return fmt::format("{}", value); } -void MySQLPreparedStatement::setBool(const uint8 index, const bool value) +std::string PreparedStatementData::ToString(bool value) { - setUInt8(index, value ? 1 : 0); + return ToString(value); } -void MySQLPreparedStatement::setUInt8(const uint8 index, const uint8 value) +std::string PreparedStatementData::ToString(uint8 value) { - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_TINY, &value, sizeof(uint8), true); + return ToString(value); } -void MySQLPreparedStatement::setUInt16(const uint8 index, const uint16 value) -{ - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_SHORT, &value, sizeof(uint16), true); -} +template std::string PreparedStatementData::ToString(uint16); +template std::string PreparedStatementData::ToString(uint32); +template std::string PreparedStatementData::ToString(uint64); -void MySQLPreparedStatement::setUInt32(const uint8 index, const uint32 value) +std::string PreparedStatementData::ToString(int8 value) { - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_LONG, &value, sizeof(uint32), true); + return ToString(value); } -void MySQLPreparedStatement::setUInt64(const uint8 index, const uint64 value) -{ - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(uint64), true); -} +template std::string PreparedStatementData::ToString(int16); +template std::string PreparedStatementData::ToString(int32); +template std::string PreparedStatementData::ToString(int64); +template std::string PreparedStatementData::ToString(float); +template std::string PreparedStatementData::ToString(double); -void MySQLPreparedStatement::setInt8(const uint8 index, const int8 value) +std::string PreparedStatementData::ToString(std::string const& value) { - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_TINY, &value, sizeof(int8), false); + return fmt::format("'{}'", value); } -void MySQLPreparedStatement::setInt16(const uint8 index, const int16 value) +std::string PreparedStatementData::ToString(std::vector const& /*value*/) { - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_SHORT, &value, sizeof(int16), false); + return "BINARY"; } -void MySQLPreparedStatement::setInt32(const uint8 index, const int32 value) +std::string PreparedStatementData::ToString(SystemTimePoint value) { - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_LONG, &value, sizeof(int32), false); + return fmt::format("{:%F %T}", value); } -void MySQLPreparedStatement::setInt64(const uint8 index, const int64 value) +std::string PreparedStatementData::ToString(std::nullptr_t) { - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(int64), false); -} - -void MySQLPreparedStatement::setFloat(const uint8 index, const float value) -{ - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_FLOAT, &value, sizeof(float), (value > 0.0f)); -} - -void MySQLPreparedStatement::setDouble(const uint8 index, const double value) -{ - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_DOUBLE, &value, sizeof(double), (value > 0.0f)); -} - -void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector& value, bool isString) -{ - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - uint32 len = uint32(value.size()); - param->buffer_type = MYSQL_TYPE_BLOB; - delete [] static_cast(param->buffer); - param->buffer = new char[len]; - param->buffer_length = len; - param->is_null_value = 0; - delete param->length; - param->length = new unsigned long(len); - if (isString) - { - *param->length -= 1; - param->buffer_type = MYSQL_TYPE_VAR_STRING; - } - - memcpy(param->buffer, value.data(), len); -} - -std::string MySQLPreparedStatement::getQueryString(std::string const& sqlPattern) const -{ - std::string queryString = sqlPattern; - - size_t pos = 0; - for (uint32 i = 0; i < m_stmt->statement_data.size(); i++) - { - pos = queryString.find('?', pos); - std::stringstream ss; - - switch (m_stmt->statement_data[i].type) - { - case TYPE_BOOL: - ss << uint16(m_stmt->statement_data[i].data.boolean); - break; - case TYPE_UI8: - ss << uint16(m_stmt->statement_data[i].data.ui8); // stringstream will append a character with that code instead of numeric representation - break; - case TYPE_UI16: - ss << m_stmt->statement_data[i].data.ui16; - break; - case TYPE_UI32: - ss << m_stmt->statement_data[i].data.ui32; - break; - case TYPE_I8: - ss << int16(m_stmt->statement_data[i].data.i8); // stringstream will append a character with that code instead of numeric representation - break; - case TYPE_I16: - ss << m_stmt->statement_data[i].data.i16; - break; - case TYPE_I32: - ss << m_stmt->statement_data[i].data.i32; - break; - case TYPE_UI64: - ss << m_stmt->statement_data[i].data.ui64; - break; - case TYPE_I64: - ss << m_stmt->statement_data[i].data.i64; - break; - case TYPE_FLOAT: - ss << m_stmt->statement_data[i].data.f; - break; - case TYPE_DOUBLE: - ss << m_stmt->statement_data[i].data.d; - break; - case TYPE_STRING: - ss << '\'' << (char const*)m_stmt->statement_data[i].binary.data() << '\''; - break; - case TYPE_BINARY: - ss << "BINARY"; - break; - case TYPE_NULL: - ss << "NULL"; - break; - } - - std::string replaceStr = ss.str(); - queryString.replace(pos, 1, replaceStr); - pos += replaceStr.length(); - } - - return queryString; -} - -//- Execution -PreparedStatementTask::PreparedStatementTask(PreparedStatement* stmt, bool async) : -m_stmt(stmt), m_result(nullptr) -{ - m_has_result = async; // If it's async, then there's a result - if (async) - m_result = new PreparedQueryResultPromise(); -} - -PreparedStatementTask::~PreparedStatementTask() -{ - delete m_stmt; - if (m_has_result && m_result != nullptr) - delete m_result; -} - -bool PreparedStatementTask::Execute() -{ - if (m_has_result) - { - PreparedResultSet* result = m_conn->Query(m_stmt); - if (!result || !result->GetRowCount()) - { - delete result; - m_result->set_value(PreparedQueryResult(NULL)); - return false; - } - m_result->set_value(PreparedQueryResult(result)); - return true; - } - - return m_conn->Execute(m_stmt); + return "NULL"; } diff --git a/src/server/database/Database/PreparedStatement.h b/src/server/database/Database/PreparedStatement.h index 32909ef94e6..88151ef193b 100644 --- a/src/server/database/Database/PreparedStatement.h +++ b/src/server/database/Database/PreparedStatement.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,155 +18,112 @@ #ifndef _PREPAREDSTATEMENT_H #define _PREPAREDSTATEMENT_H +#include "DatabaseEnvFwd.h" #include "Define.h" -#include "SQLOperation.h" -#include +#include "Duration.h" +#include +#include +#include #include -#ifdef __APPLE__ -#undef TYPE_BOOL -#endif - -//- Union for data buffer (upper-level bind -> queue -> lower-level bind) -union PreparedStatementDataUnion -{ - bool boolean; - uint8 ui8; - int8 i8; - uint16 ui16; - int16 i16; - uint32 ui32; - int32 i32; - uint64 ui64; - int64 i64; - float f; - double d; -}; - -//- This enum helps us differ data held in above union -enum PreparedStatementValueType -{ - TYPE_BOOL, - TYPE_UI8, - TYPE_UI16, - TYPE_UI32, - TYPE_UI64, - TYPE_I8, - TYPE_I16, - TYPE_I32, - TYPE_I64, - TYPE_FLOAT, - TYPE_DOUBLE, - TYPE_STRING, - TYPE_BINARY, - TYPE_NULL -}; +class MySQLConnection; struct PreparedStatementData { - PreparedStatementDataUnion data; - PreparedStatementValueType type; - std::vector binary; + std::variant< + bool, + uint8, + uint16, + uint32, + uint64, + int8, + int16, + int32, + int64, + float, + double, + std::string, + std::vector, + SystemTimePoint, + std::nullptr_t + > data; + + template + static std::string ToString(T value); + + static std::string ToString(bool value); + static std::string ToString(uint8 value); + static std::string ToString(int8 value); + static std::string ToString(std::string const& value); + static std::string ToString(std::vector const& value); + static std::string ToString(SystemTimePoint value); + static std::string ToString(std::nullptr_t); }; -//- Forward declare -class MySQLPreparedStatement; - //- Upper-level class that is used in code -class TC_DATABASE_API PreparedStatement +class TC_DATABASE_API PreparedStatementBase { friend class PreparedStatementTask; - friend class MySQLPreparedStatement; - friend class MySQLConnection; public: - explicit PreparedStatement(uint32 index); - ~PreparedStatement(); - - void setBool(const uint8 index, const bool value); - void setUInt8(const uint8 index, const uint8 value); - void setUInt16(const uint8 index, const uint16 value); - void setUInt32(const uint8 index, const uint32 value); - void setUInt64(const uint8 index, const uint64 value); - void setInt8(const uint8 index, const int8 value); - void setInt16(const uint8 index, const int16 value); - void setInt32(const uint8 index, const int32 value); - void setInt64(const uint8 index, const int64 value); - void setFloat(const uint8 index, const float value); - void setDouble(const uint8 index, const double value); - void setString(const uint8 index, const std::string& value); - void setBinary(const uint8 index, const std::vector& value); - void setNull(const uint8 index); - - protected: - void BindParameters(); + explicit PreparedStatementBase(uint32 index, uint8 capacity); + virtual ~PreparedStatementBase(); + + void setNull(uint8 index); + void setBool(uint8 index, bool value); + void setUInt8(uint8 index, uint8 value); + void setUInt16(uint8 index, uint16 value); + void setUInt32(uint8 index, uint32 value); + void setUInt64(uint8 index, uint64 value); + void setInt8(uint8 index, int8 value); + void setInt16(uint8 index, int16 value); + void setInt32(uint8 index, int32 value); + void setInt64(uint8 index, int64 value); + void setFloat(uint8 index, float value); + void setDouble(uint8 index, double value); + void setDate(uint8 index, SystemTimePoint value); + void setString(uint8 index, std::string const& value); + void setStringView(uint8 index, std::string_view value); + void setBinary(uint8 index, std::vector const& value); + template + void setBinary(const uint8 index, std::array const& value) + { + std::vector vec(value.begin(), value.end()); + setBinary(index, vec); + } + + uint32 GetIndex() const { return m_index; } + std::vector const& GetParameters() const { return statement_data; } protected: - MySQLPreparedStatement* m_stmt; uint32 m_index; - std::vector statement_data; //- Buffer of parameters, not tied to MySQL in any way yet - PreparedStatement(PreparedStatement const& right) = delete; - PreparedStatement& operator=(PreparedStatement const& right) = delete; + //- Buffer of parameters, not tied to MySQL in any way yet + std::vector statement_data; + + PreparedStatementBase(PreparedStatementBase const& right) = delete; + PreparedStatementBase& operator=(PreparedStatementBase const& right) = delete; }; -//- Class of which the instances are unique per MySQLConnection -//- access to these class objects is only done when a prepared statement task -//- is executed. -class TC_DATABASE_API MySQLPreparedStatement +template +class PreparedStatement : public PreparedStatementBase { - friend class MySQLConnection; - friend class PreparedStatement; - - public: - MySQLPreparedStatement(MYSQL_STMT* stmt); - ~MySQLPreparedStatement(); - - void setNull(const uint8 index); - void setBool(const uint8 index, const bool value); - void setUInt8(const uint8 index, const uint8 value); - void setUInt16(const uint8 index, const uint16 value); - void setUInt32(const uint8 index, const uint32 value); - void setUInt64(const uint8 index, const uint64 value); - void setInt8(const uint8 index, const int8 value); - void setInt16(const uint8 index, const int16 value); - void setInt32(const uint8 index, const int32 value); - void setInt64(const uint8 index, const int64 value); - void setFloat(const uint8 index, const float value); - void setDouble(const uint8 index, const double value); - void setBinary(const uint8 index, const std::vector& value, bool isString); - - protected: - MYSQL_STMT* GetSTMT() { return m_Mstmt; } - MYSQL_BIND* GetBind() { return m_bind; } - PreparedStatement* m_stmt; - void ClearParameters(); - void CheckValidIndex(uint8 index); - std::string getQueryString(std::string const& sqlPattern) const; - - private: - MYSQL_STMT* m_Mstmt; - uint32 m_paramCount; - std::vector m_paramsSet; - MYSQL_BIND* m_bind; - - MySQLPreparedStatement(MySQLPreparedStatement const& right) = delete; - MySQLPreparedStatement& operator=(MySQLPreparedStatement const& right) = delete; +public: + explicit PreparedStatement(uint32 index, uint8 capacity) : PreparedStatementBase(index, capacity) + { + } + +private: + PreparedStatement(PreparedStatement const& right) = delete; + PreparedStatement& operator=(PreparedStatement const& right) = delete; }; //- Lower-level class, enqueuable operation -class TC_DATABASE_API PreparedStatementTask : public SQLOperation +class TC_DATABASE_API PreparedStatementTask { - public: - PreparedStatementTask(PreparedStatement* stmt, bool async = false); - ~PreparedStatementTask(); - - bool Execute() override; - PreparedQueryResultFuture GetFuture() { return m_result->get_future(); } - - protected: - PreparedStatement* m_stmt; - bool m_has_result; - PreparedQueryResultPromise* m_result; +public: + static PreparedQueryResult Query(MySQLConnection* conn, PreparedStatementBase* stmt); + static bool Execute(MySQLConnection* conn, PreparedStatementBase* stmt); }; + #endif diff --git a/src/server/database/Database/QueryCallback.cpp b/src/server/database/Database/QueryCallback.cpp index fecae0efb57..528605da708 100644 --- a/src/server/database/Database/QueryCallback.cpp +++ b/src/server/database/Database/QueryCallback.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -16,206 +16,92 @@ */ #include "QueryCallback.h" +#include "Duration.h" #include "Errors.h" -template -inline void Construct(T& t, Args&&... args) +QueryCallback::QueryCallback(std::future&& result) : _query(std::move(result)) { - new (&t) T(std::forward(args)...); } -template -inline void Destroy(T& t) +QueryCallback::QueryCallback(std::future&& result) : _query(std::move(result)) { - t.~T(); } -template -inline void ConstructActiveMember(T* obj) +QueryCallback::QueryCallback(QueryCallback&& right) noexcept : _query(std::move(right._query)), _callbacks(std::move(right._callbacks)) { - if (!obj->_isPrepared) - Construct(obj->_string); - else - Construct(obj->_prepared); } -template -inline void DestroyActiveMember(T* obj) -{ - if (!obj->_isPrepared) - Destroy(obj->_string); - else - Destroy(obj->_prepared); -} - -template -inline void MoveFrom(T* to, T&& from) -{ - ASSERT(to->_isPrepared == from._isPrepared); - - if (!to->_isPrepared) - to->_string = std::move(from._string); - else - to->_prepared = std::move(from._prepared); -} - -struct QueryCallback::QueryCallbackData -{ -public: - friend class QueryCallback; - - QueryCallbackData(std::function&& callback) : _string(std::move(callback)), _isPrepared(false) { } - QueryCallbackData(std::function&& callback) : _prepared(std::move(callback)), _isPrepared(true) { } - QueryCallbackData(QueryCallbackData&& right) - { - _isPrepared = right._isPrepared; - ConstructActiveMember(this); - MoveFrom(this, std::move(right)); - } - QueryCallbackData& operator=(QueryCallbackData&& right) - { - if (this != &right) - { - if (_isPrepared != right._isPrepared) - { - DestroyActiveMember(this); - _isPrepared = right._isPrepared; - ConstructActiveMember(this); - } - MoveFrom(this, std::move(right)); - } - return *this; - } - ~QueryCallbackData() { DestroyActiveMember(this); } - -private: - QueryCallbackData(QueryCallbackData const&) = delete; - QueryCallbackData& operator=(QueryCallbackData const&) = delete; - - template friend void ConstructActiveMember(T* obj); - template friend void DestroyActiveMember(T* obj); - template friend void MoveFrom(T* to, T&& from); - - union - { - std::function _string; - std::function _prepared; - }; - bool _isPrepared; -}; - -// Not using initialization lists to work around segmentation faults when compiling with clang without precompiled headers -QueryCallback::QueryCallback(std::future&& result) -{ - _isPrepared = false; - Construct(_string, std::move(result)); -} - -QueryCallback::QueryCallback(std::future&& result) -{ - _isPrepared = true; - Construct(_prepared, std::move(result)); -} - -QueryCallback::QueryCallback(QueryCallback&& right) -{ - _isPrepared = right._isPrepared; - ConstructActiveMember(this); - MoveFrom(this, std::move(right)); - _callbacks = std::move(right._callbacks); -} - -QueryCallback& QueryCallback::operator=(QueryCallback&& right) +QueryCallback& QueryCallback::operator=(QueryCallback&& right) noexcept { if (this != &right) { - if (_isPrepared != right._isPrepared) - { - DestroyActiveMember(this); - _isPrepared = right._isPrepared; - ConstructActiveMember(this); - } - MoveFrom(this, std::move(right)); + _query = std::move(right._query); _callbacks = std::move(right._callbacks); } return *this; } -QueryCallback::~QueryCallback() -{ - DestroyActiveMember(this); -} +QueryCallback::~QueryCallback() = default; QueryCallback&& QueryCallback::WithCallback(std::function&& callback) { - return WithChainingCallback([callback](QueryCallback& /*this*/, QueryResult result) { callback(std::move(result)); }); + return WithChainingCallback([callback = std::move(callback)](QueryCallback& /*this*/, QueryResult result) { callback(std::move(result)); }); } QueryCallback&& QueryCallback::WithPreparedCallback(std::function&& callback) { - return WithChainingPreparedCallback([callback](QueryCallback& /*this*/, PreparedQueryResult result) { callback(std::move(result)); }); + return WithChainingPreparedCallback([callback = std::move(callback)](QueryCallback& /*this*/, PreparedQueryResult result) { callback(std::move(result)); }); } QueryCallback&& QueryCallback::WithChainingCallback(std::function&& callback) { - ASSERT(!_callbacks.empty() || !_isPrepared, "Attempted to set callback function for string query on a prepared async query"); + ASSERT(!_callbacks.empty() || std::holds_alternative>(_query), "Attempted to set callback function for string query on a prepared async query"); _callbacks.emplace(std::move(callback)); return std::move(*this); } QueryCallback&& QueryCallback::WithChainingPreparedCallback(std::function&& callback) { - ASSERT(!_callbacks.empty() || _isPrepared, "Attempted to set callback function for prepared query on a string async query"); + ASSERT(!_callbacks.empty() || std::holds_alternative>(_query), "Attempted to set callback function for prepared query on a string async query"); _callbacks.emplace(std::move(callback)); return std::move(*this); } void QueryCallback::SetNextQuery(QueryCallback&& next) { - MoveFrom(this, std::move(next)); + if (this != &next) + _query = std::move(next)._query; } -QueryCallback::Status QueryCallback::InvokeIfReady() +bool QueryCallback::InvokeIfReady() { - QueryCallbackData& callback = _callbacks.front(); auto checkStateAndReturnCompletion = [this]() { _callbacks.pop(); - bool hasNext = !_isPrepared ? _string.valid() : _prepared.valid(); + bool hasNext = std::visit([](auto const& future) { return future.valid(); }, _query); if (_callbacks.empty()) { ASSERT(!hasNext); - return Completed; + return true; } // abort chain if (!hasNext) - return Completed; + return true; - ASSERT(_isPrepared == _callbacks.front()._isPrepared); - return NextStep; + ASSERT(_query.index() == _callbacks.front().index()); + return false; }; - if (!_isPrepared) - { - if (_string.valid() && _string.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - QueryResultFuture f(std::move(_string)); - std::function cb(std::move(callback._string)); - cb(*this, f.get()); - return checkStateAndReturnCompletion(); - } - } - else + return std::visit([&](std::future&& future) { - if (_prepared.valid() && _prepared.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + if (future.valid() && future.wait_for(0s) == std::future_status::ready) { - PreparedQueryResultFuture f(std::move(_prepared)); - std::function cb(std::move(callback._prepared)); + std::future f(std::move(future)); + std::function cb(std::get>(std::move(_callbacks.front()))); cb(*this, f.get()); return checkStateAndReturnCompletion(); } - } - - return NotReady; + return false; + }, std::move(_query)); } diff --git a/src/server/database/Database/QueryCallback.h b/src/server/database/Database/QueryCallback.h index 9d04e3ca9ab..72b4ca1202a 100644 --- a/src/server/database/Database/QueryCallback.h +++ b/src/server/database/Database/QueryCallback.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,21 +18,21 @@ #ifndef _QUERY_CALLBACK_H #define _QUERY_CALLBACK_H -#include "Define.h" #include "DatabaseEnvFwd.h" +#include "Define.h" #include #include #include #include -#include +#include class TC_DATABASE_API QueryCallback { public: - explicit QueryCallback(QueryResultFuture&& result); - explicit QueryCallback(PreparedQueryResultFuture&& result); - QueryCallback(QueryCallback&& right); - QueryCallback& operator=(QueryCallback&& right); + explicit QueryCallback(std::future&& result); + explicit QueryCallback(std::future&& result); + QueryCallback(QueryCallback&& right) noexcept; + QueryCallback& operator=(QueryCallback&& right) noexcept; ~QueryCallback(); QueryCallback&& WithCallback(std::function&& callback); @@ -44,31 +44,16 @@ class TC_DATABASE_API QueryCallback // Moves std::future from next to this object void SetNextQuery(QueryCallback&& next); - enum Status - { - NotReady, - NextStep, - Completed - }; - - Status InvokeIfReady(); + // returns true when completed + bool InvokeIfReady(); private: QueryCallback(QueryCallback const& right) = delete; QueryCallback& operator=(QueryCallback const& right) = delete; - template friend void ConstructActiveMember(T* obj); - template friend void DestroyActiveMember(T* obj); - template friend void MoveFrom(T* to, T&& from); - - union - { - QueryResultFuture _string; - PreparedQueryResultFuture _prepared; - }; - bool _isPrepared; + std::variant, std::future> _query; - struct QueryCallbackData; + using QueryCallbackData = std::variant, std::function>; std::queue> _callbacks; }; diff --git a/src/server/database/Database/QueryCallbackProcessor.cpp b/src/server/database/Database/QueryCallbackProcessor.cpp deleted file mode 100644 index a0982b7c1cb..00000000000 --- a/src/server/database/Database/QueryCallbackProcessor.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * 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 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "QueryCallbackProcessor.h" -#include "QueryCallback.h" -#include - -QueryCallbackProcessor::QueryCallbackProcessor() -{ -} - -QueryCallbackProcessor::~QueryCallbackProcessor() -{ -} - -void QueryCallbackProcessor::AddQuery(QueryCallback&& query) -{ - _callbacks.emplace_back(std::move(query)); -} - -void QueryCallbackProcessor::ProcessReadyQueries() -{ - if (_callbacks.empty()) - return; - - std::vector updateCallbacks{ std::move(_callbacks) }; - - updateCallbacks.erase(std::remove_if(updateCallbacks.begin(), updateCallbacks.end(), [](QueryCallback& callback) - { - return callback.InvokeIfReady() == QueryCallback::Completed; - }), updateCallbacks.end()); - - _callbacks.insert(_callbacks.end(), std::make_move_iterator(updateCallbacks.begin()), std::make_move_iterator(updateCallbacks.end())); -} diff --git a/src/server/database/Database/QueryHolder.cpp b/src/server/database/Database/QueryHolder.cpp index 1c9bce76120..77e02893179 100644 --- a/src/server/database/Database/QueryHolder.cpp +++ b/src/server/database/Database/QueryHolder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -15,13 +15,14 @@ * with this program. If not, see . */ -#include "MySQLConnection.h" #include "QueryHolder.h" -#include "PreparedStatement.h" +#include "Errors.h" #include "Log.h" +#include "MySQLConnection.h" +#include "PreparedStatement.h" #include "QueryResult.h" -bool SQLQueryHolder::SetPreparedQuery(size_t index, PreparedStatement* stmt) +bool SQLQueryHolderBase::SetPreparedQueryImpl(size_t index, PreparedStatementBase* stmt) { if (m_queries.size() <= index) { @@ -33,21 +34,21 @@ bool SQLQueryHolder::SetPreparedQuery(size_t index, PreparedStatement* stmt) return true; } -PreparedQueryResult SQLQueryHolder::GetPreparedResult(size_t index) +PreparedQueryResult SQLQueryHolderBase::GetPreparedResult(size_t index) const { // Don't call to this function if the index is of a prepared statement - if (index < m_queries.size()) - return m_queries[index].second; - else - return PreparedQueryResult(nullptr); + ASSERT(index < m_queries.size(), "Query holder result index out of range, tried to access index " SZFMTD " but there are only " SZFMTD " results", + index, m_queries.size()); + + return m_queries[index].second; } -void SQLQueryHolder::SetPreparedResult(size_t index, PreparedResultSet* result) +void SQLQueryHolderBase::SetPreparedResult(size_t index, PreparedResultSet* result) { if (result && !result->GetRowCount()) { delete result; - result = NULL; + result = nullptr; } /// store the result in the holder @@ -55,40 +56,39 @@ void SQLQueryHolder::SetPreparedResult(size_t index, PreparedResultSet* result) m_queries[index].second = PreparedQueryResult(result); } -SQLQueryHolder::~SQLQueryHolder() +SQLQueryHolderBase::~SQLQueryHolderBase() { - for (size_t i = 0; i < m_queries.size(); i++) + for (std::pair& query : m_queries) { /// if the result was never used, free the resources /// results used already (getresult called) are expected to be deleted - delete m_queries[i].first; + delete query.first; } } -void SQLQueryHolder::SetSize(size_t size) +void SQLQueryHolderBase::SetSize(size_t size) { /// to optimize push_back, reserve the number of queries about to be executed m_queries.resize(size); } -SQLQueryHolderTask::~SQLQueryHolderTask() +bool SQLQueryHolderTask::Execute(MySQLConnection* conn, SQLQueryHolderBase* holder) { - if (!m_executed) - delete m_holder; + /// execute all queries in the holder and pass the results + for (size_t i = 0; i < holder->m_queries.size(); ++i) + if (PreparedStatementBase* stmt = holder->m_queries[i].first) + holder->SetPreparedResult(i, conn->Query(stmt)); + + return true; } -bool SQLQueryHolderTask::Execute() +bool SQLQueryHolderCallback::InvokeIfReady() { - m_executed = true; - - if (!m_holder) - return false; - - /// execute all queries in the holder and pass the results - for (size_t i = 0; i < m_holder->m_queries.size(); i++) - if (PreparedStatement* stmt = m_holder->m_queries[i].first) - m_holder->SetPreparedResult(i, m_conn->Query(stmt)); + if (m_future.valid() && m_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + m_callback(*m_holder); + return true; + } - m_result.set_value(m_holder); - return true; + return false; } diff --git a/src/server/database/Database/QueryHolder.h b/src/server/database/Database/QueryHolder.h index fd4826a5e14..a0a0b2b2d0f 100644 --- a/src/server/database/Database/QueryHolder.h +++ b/src/server/database/Database/QueryHolder.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -18,37 +18,65 @@ #ifndef _QUERYHOLDER_H #define _QUERYHOLDER_H -#include "SQLOperation.h" +#include "Define.h" +#include "DatabaseEnvFwd.h" +#include +#include -class TC_DATABASE_API SQLQueryHolder +class MySQLConnection; + +class TC_DATABASE_API SQLQueryHolderBase { friend class SQLQueryHolderTask; private: - std::vector> m_queries; + std::vector> m_queries; public: - SQLQueryHolder() { } - virtual ~SQLQueryHolder(); - bool SetPreparedQuery(size_t index, PreparedStatement* stmt); + SQLQueryHolderBase() = default; + virtual ~SQLQueryHolderBase(); void SetSize(size_t size); - PreparedQueryResult GetPreparedResult(size_t index); + PreparedQueryResult GetPreparedResult(size_t index) const; void SetPreparedResult(size_t index, PreparedResultSet* result); + + protected: + bool SetPreparedQueryImpl(size_t index, PreparedStatementBase* stmt); }; -class TC_DATABASE_API SQLQueryHolderTask : public SQLOperation +template +class SQLQueryHolder : public SQLQueryHolderBase { - private: - SQLQueryHolder* m_holder; - QueryResultHolderPromise m_result; - bool m_executed; +public: + bool SetPreparedQuery(size_t index, PreparedStatement* stmt) + { + return SetPreparedQueryImpl(index, stmt); + } +}; - public: - SQLQueryHolderTask(SQLQueryHolder* holder) - : m_holder(holder), m_executed(false) { } +class TC_DATABASE_API SQLQueryHolderTask +{ +public: + static bool Execute(MySQLConnection* conn, SQLQueryHolderBase* holder); +}; + +class TC_DATABASE_API SQLQueryHolderCallback +{ +public: + SQLQueryHolderCallback(std::shared_ptr&& holder, std::future&& future) + : m_holder(std::move(holder)), m_future(std::move(future)) { } + + SQLQueryHolderCallback(SQLQueryHolderCallback&&) = default; + + SQLQueryHolderCallback& operator=(SQLQueryHolderCallback&&) = default; + + void AfterComplete(std::function callback) & + { + m_callback = std::move(callback); + } - ~SQLQueryHolderTask(); + bool InvokeIfReady(); - bool Execute() override; - QueryResultHolderFuture GetFuture() { return m_result.get_future(); } + std::shared_ptr m_holder; + std::future m_future; + std::function m_callback; }; #endif diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp index 7d27aafef45..a22f48c9a9b 100644 --- a/src/server/database/Database/QueryResult.cpp +++ b/src/server/database/Database/QueryResult.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore - * Copyright (C) 2005-2009 MaNGOS + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -19,12 +18,15 @@ #include "QueryResult.h" #include "Errors.h" #include "Field.h" +#include "FieldValueConverters.h" #include "Log.h" -#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7 -#include -#endif -#include +#include "MySQLHacks.h" +#include "MySQLWorkaround.h" +#include +#include +namespace +{ static uint32 SizeForType(MYSQL_FIELD* field) { switch (field->type) @@ -75,23 +77,23 @@ static uint32 SizeForType(MYSQL_FIELD* field) } } -DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type) +DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type, uint32 flags) { switch (type) { case MYSQL_TYPE_NULL: return DatabaseFieldTypes::Null; case MYSQL_TYPE_TINY: - return DatabaseFieldTypes::Int8; + return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt8 : DatabaseFieldTypes::Int8; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: - return DatabaseFieldTypes::Int16; + return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt16 : DatabaseFieldTypes::Int16; case MYSQL_TYPE_INT24: case MYSQL_TYPE_LONG: - return DatabaseFieldTypes::Int32; + return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt32 : DatabaseFieldTypes::Int32; case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_BIT: - return DatabaseFieldTypes::Int64; + return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt64 : DatabaseFieldTypes::Int64; case MYSQL_TYPE_FLOAT: return DatabaseFieldTypes::Float; case MYSQL_TYPE_DOUBLE: @@ -101,9 +103,10 @@ DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type) return DatabaseFieldTypes::Decimal; case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATETIME: return DatabaseFieldTypes::Date; + case MYSQL_TYPE_TIME: + return DatabaseFieldTypes::Time; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: @@ -119,24 +122,297 @@ DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type) return DatabaseFieldTypes::Null; } -ResultSet::ResultSet(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount) : +static char const* FieldTypeToString(enum_field_types type, uint32 flags) +{ + switch (type) + { + case MYSQL_TYPE_BIT: return "BIT"; + case MYSQL_TYPE_BLOB: return "BLOB"; + case MYSQL_TYPE_DATE: return "DATE"; + case MYSQL_TYPE_DATETIME: return "DATETIME"; + case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL"; + case MYSQL_TYPE_DECIMAL: return "DECIMAL"; + case MYSQL_TYPE_DOUBLE: return "DOUBLE"; + case MYSQL_TYPE_ENUM: return "ENUM"; + case MYSQL_TYPE_FLOAT: return "FLOAT"; + case MYSQL_TYPE_GEOMETRY: return "GEOMETRY"; + case MYSQL_TYPE_INT24: return (flags & UNSIGNED_FLAG) ? "UNSIGNED INT24" : "INT24"; + case MYSQL_TYPE_LONG: return (flags & UNSIGNED_FLAG) ? "UNSIGNED LONG" : "LONG"; + case MYSQL_TYPE_LONGLONG: return (flags & UNSIGNED_FLAG) ? "UNSIGNED LONGLONG" : "LONGLONG"; + case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB"; + case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB"; + case MYSQL_TYPE_NEWDATE: return "NEWDATE"; + case MYSQL_TYPE_NULL: return "NULL"; + case MYSQL_TYPE_SET: return "SET"; + case MYSQL_TYPE_SHORT: return (flags & UNSIGNED_FLAG) ? "UNSIGNED SHORT" : "SHORT"; + case MYSQL_TYPE_STRING: return "STRING"; + case MYSQL_TYPE_TIME: return "TIME"; + case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP"; + case MYSQL_TYPE_TINY: return (flags & UNSIGNED_FLAG) ? "UNSIGNED TINY" : "TINY"; + case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB"; + case MYSQL_TYPE_VAR_STRING: return "VAR_STRING"; + case MYSQL_TYPE_YEAR: return "YEAR"; + default: return "-Unknown-"; + } +} + +template +class FromStringToMYSQL_TIME +{ +public: + static MYSQL_TIME GetDatabaseValue(char const* data, uint32 size) + { + MYSQL_TIME result = {}; + if (!data || !size) + { + result.time_type = MYSQL_TIMESTAMP_NONE; + return result; + } + + std::string_view in(data, size); + + size_t firstSeparatorIndex = in.find_first_of(":-"); + if (firstSeparatorIndex == std::string_view::npos) + { + result.time_type = MYSQL_TIMESTAMP_NONE; + return result; + } + + char firstSeparator = in[firstSeparatorIndex]; + + auto parseNextComponent = [&](uint32& value, char requiredSeparator = '\0') -> bool + { + std::from_chars_result parseResult = std::from_chars(in.data(), in.data() + in.size(), value); + if (parseResult.ec != std::errc()) + return false; + + in.remove_prefix(parseResult.ptr - in.data()); + if (requiredSeparator) + { + if (in.empty() || in[0] != requiredSeparator) + return false; + + in.remove_prefix(1); + } + + return true; + }; + + uint32 yearOrHours = 0; + uint32 monthOrMinutes = 0; + uint32 dayOrSeconds = 0; + if (!parseNextComponent(yearOrHours, firstSeparator) + || !parseNextComponent(monthOrMinutes, firstSeparator) + || !parseNextComponent(dayOrSeconds)) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + if (firstSeparator == ':') + { + if (!in.empty()) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + // time + result.hour = yearOrHours; + result.minute = monthOrMinutes; + result.second = dayOrSeconds; + result.time_type = MYSQL_TIMESTAMP_TIME; + } + else + { + if (in.empty()) + { + // date + result.year = yearOrHours; + result.month = monthOrMinutes; + result.day = dayOrSeconds; + result.time_type = MYSQL_TIMESTAMP_DATE; + return result; + } + + // date+time + if (in[0] != ' ') + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + in.remove_prefix(1); + + uint32 hours = 0; + uint32 minutes = 0; + uint32 seconds = 0; + if (!parseNextComponent(hours, ':') + || !parseNextComponent(minutes, ':') + || !parseNextComponent(seconds)) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + uint32 microseconds = 0; + if (!in.empty()) + { + if (in[0] != '.') + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + in.remove_prefix(1); + if (!parseNextComponent(microseconds)) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + if (!in.empty()) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + } + + result.year = yearOrHours; + result.month = monthOrMinutes; + result.day = dayOrSeconds; + result.hour = hours; + result.minute = minutes; + result.second = seconds; + result.second_part = microseconds; + result.time_type = MYSQL_TIMESTAMP_DATETIME; + } + + return result; + } + + static char const* GetStringValue(char const* data) + { + return data; + } +}; + +template typename ToDatabaseTypeConverter> +class DateResultValueConverter : public BaseDatabaseResultValueConverter +{ + uint8 GetUInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt8", meta); return 0; } + int8 GetInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt8", meta); return 0; } + uint16 GetUInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt16", meta); return 0; } + int16 GetInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt16", meta); return 0; } + uint32 GetUInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt32", meta); return 0; } + int32 GetInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt32", meta); return 0; } + uint64 GetUInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt64", meta); return 0; } + int64 GetInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt64", meta); return 0; } + float GetFloat(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetFloat", meta); return 0.0f; } + double GetDouble(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDouble", meta); return 0.0; } + + SystemTimePoint GetDate(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override + { + using namespace std::chrono; + MYSQL_TIME source = ToDatabaseTypeConverter::GetDatabaseValue(data, size); + switch (source.time_type) + { + case MYSQL_TIMESTAMP_DATE: + return sys_days(year(source.year) / month(source.month) / day(source.day)); + case MYSQL_TIMESTAMP_DATETIME: + return sys_days(year(source.year) / month(source.month) / day(source.day)) + + hours(source.hour) + + minutes(source.minute) + + seconds(source.second) + + microseconds(source.second_part); + default: + break; + } + + LogTruncation("Field::GetDate", meta); + return SystemTimePoint(); + } + + char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override + { + char const* result = ToDatabaseTypeConverter::GetStringValue(data); + if (data && !result) + LogTruncation("Field::GetCString", meta); + return result; + } +}; + +std::unique_ptr const FromStringValueConverters[15] = +{ + nullptr, + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique(), // DatabaseFieldTypes::Time + std::make_unique() +}; + +std::unique_ptr const BinaryValueConverters[15] = +{ + nullptr, + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_unique>(), // always sent as string + std::make_unique>(), + std::make_unique(), // DatabaseFieldTypes::Time + std::make_unique() +}; + +void InitializeDatabaseFieldMetadata(QueryResultFieldMetadata* meta, MySQLField const* field, uint32 fieldIndex, bool binaryProtocol) +{ + meta->TableName = field->org_table; + meta->TableAlias = field->table; + meta->Name = field->org_name; + meta->Alias = field->name; + meta->TypeName = FieldTypeToString(field->type, field->flags); + meta->Index = fieldIndex; + meta->Type = MysqlTypeToFieldType(field->type, field->flags); + meta->Converter = binaryProtocol ? BinaryValueConverters[AsUnderlyingType(meta->Type)].get() : FromStringValueConverters[AsUnderlyingType(meta->Type)].get(); +} +} + +ResultSet::ResultSet(MySQLResult* result, MySQLField* fields, uint64 rowCount, uint32 fieldCount) : _rowCount(rowCount), _fieldCount(fieldCount), _result(result), _fields(fields) { + _fieldMetadata.resize(_fieldCount); _currentRow = new Field[_fieldCount]; -#ifdef TRINITY_DEBUG for (uint32 i = 0; i < _fieldCount; i++) - _currentRow[i].SetMetadata(&_fields[i], i); -#endif + { + InitializeDatabaseFieldMetadata(&_fieldMetadata[i], &_fields[i], i, false); + _currentRow[i].SetMetadata(&_fieldMetadata[i]); + } } -PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) : +PreparedResultSet::PreparedResultSet(MySQLStmt* stmt, MySQLResult* result, uint64 rowCount, uint32 fieldCount) : m_rowCount(rowCount), m_rowPosition(0), m_fieldCount(fieldCount), -m_rBind(NULL), +m_rBind(nullptr), m_stmt(stmt), m_metadataResult(result) { @@ -149,16 +425,16 @@ m_metadataResult(result) delete[] m_stmt->bind->is_null; } - m_rBind = new MYSQL_BIND[m_fieldCount]; + m_rBind = new MySQLBind[m_fieldCount]; //- for future readers wondering where the fuck this is freed - mysql_stmt_bind_result moves pointers to these // from m_rBind to m_stmt->bind and it is later freed by the `if (m_stmt->bind_result_done)` block just above here // MYSQL_STMT lifetime is equal to connection lifetime - my_bool* m_isNull = new my_bool[m_fieldCount]; + MySQLBool* m_isNull = new MySQLBool[m_fieldCount]; unsigned long* m_length = new unsigned long[m_fieldCount]; - memset(m_isNull, 0, sizeof(my_bool) * m_fieldCount); - memset(m_rBind, 0, sizeof(MYSQL_BIND) * m_fieldCount); + memset(m_isNull, 0, sizeof(MySQLBool) * m_fieldCount); + memset(m_rBind, 0, sizeof(MySQLBind) * m_fieldCount); memset(m_length, 0, sizeof(unsigned long) * m_fieldCount); //- This is where we store the (entire) resultset @@ -174,18 +450,21 @@ m_metadataResult(result) m_rowCount = mysql_stmt_num_rows(m_stmt); //- This is where we prepare the buffer based on metadata - MYSQL_FIELD* field = mysql_fetch_fields(m_metadataResult); + MySQLField* field = reinterpret_cast(mysql_fetch_fields(m_metadataResult)); + m_fieldMetadata.resize(m_fieldCount); std::size_t rowSize = 0; for (uint32 i = 0; i < m_fieldCount; ++i) { uint32 size = SizeForType(&field[i]); rowSize += size; + InitializeDatabaseFieldMetadata(&m_fieldMetadata[i], &field[i], i, true); + m_rBind[i].buffer_type = field[i].type; m_rBind[i].buffer_length = size; m_rBind[i].length = &m_length[i]; m_rBind[i].is_null = &m_isNull[i]; - m_rBind[i].error = NULL; + m_rBind[i].error = nullptr; m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG; } @@ -207,11 +486,13 @@ m_metadataResult(result) return; } - m_rows.resize(uint32(m_rowCount) * m_fieldCount); + m_rows.resize(std::size_t(m_rowCount) * m_fieldCount); while (_NextRow()) { for (uint32 fIndex = 0; fIndex < m_fieldCount; ++fIndex) { + m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&m_fieldMetadata[fIndex]); + unsigned long buffer_length = m_rBind[fIndex].buffer_length; unsigned long fetched_length = *m_rBind[fIndex].length; if (!*m_rBind[fIndex].is_null) @@ -229,7 +510,7 @@ m_metadataResult(result) // when mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED // we cannot blindly null-terminate the data either as it may be retrieved as binary blob and not specifically a string // in this case using Field::GetCString will result in garbage - // TODO: remove Field::GetCString and use boost::string_ref (currently proposed for TS as string_view, maybe in C++17) + // TODO: remove Field::GetCString and use std::string_view in C++17 if (fetched_length < buffer_length) *((char*)buffer + fetched_length) = '\0'; break; @@ -237,9 +518,8 @@ m_metadataResult(result) break; } - m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue( - buffer, - MysqlTypeToFieldType(m_rBind[fIndex].buffer_type), + m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetValue( + (char const*)buffer, fetched_length); // move buffer pointer to next part @@ -247,15 +527,10 @@ m_metadataResult(result) } else { - m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue( + m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetValue( nullptr, - MysqlTypeToFieldType(m_rBind[fIndex].buffer_type), *m_rBind[fIndex].length); } - -#ifdef TRINITY_DEBUG - m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&field[fIndex], fIndex); -#endif } m_rowPosition++; } @@ -277,12 +552,10 @@ PreparedResultSet::~PreparedResultSet() bool ResultSet::NextRow() { - MYSQL_ROW row; - if (!_result) return false; - row = mysql_fetch_row(_result); + MYSQL_ROW row = mysql_fetch_row(_result); if (!row) { CleanUp(); @@ -298,7 +571,7 @@ bool ResultSet::NextRow() } for (uint32 i = 0; i < _fieldCount; i++) - _currentRow[i].SetStructuredValue(row[i], MysqlTypeToFieldType(_fields[i].type), lengths[i]); + _currentRow[i].SetValue(row[i], lengths[i]); return true; } @@ -329,13 +602,13 @@ void ResultSet::CleanUp() if (_currentRow) { delete [] _currentRow; - _currentRow = NULL; + _currentRow = nullptr; } if (_result) { mysql_free_result(_result); - _result = NULL; + _result = nullptr; } } @@ -354,19 +627,31 @@ void PreparedResultSet::CleanUp() Field const& ResultSet::operator[](std::size_t index) const { - ASSERT(index < _fieldCount); + ASSERT(index < std::size_t(_fieldCount)); return _currentRow[index]; } +QueryResultFieldMetadata const& ResultSet::GetFieldMetadata(std::size_t index) const +{ + ASSERT(index < std::size_t(_fieldCount)); + return _fieldMetadata[index]; +} + Field* PreparedResultSet::Fetch() const { ASSERT(m_rowPosition < m_rowCount); - return const_cast(&m_rows[uint32(m_rowPosition) * m_fieldCount]); + return const_cast(&m_rows[std::size_t(m_rowPosition) * m_fieldCount]); } Field const& PreparedResultSet::operator[](std::size_t index) const { ASSERT(m_rowPosition < m_rowCount); - ASSERT(index < m_fieldCount); - return m_rows[uint32(m_rowPosition) * m_fieldCount + index]; + ASSERT(index < std::size_t(m_fieldCount)); + return m_rows[std::size_t(m_rowPosition) * m_fieldCount + index]; +} + +QueryResultFieldMetadata const& PreparedResultSet::GetFieldMetadata(std::size_t index) const +{ + ASSERT(index < std::size_t(m_fieldCount)); + return m_fieldMetadata[index]; } diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h index 649149e4e4e..a6d964f846d 100644 --- a/src/server/database/Database/QueryResult.h +++ b/src/server/database/Database/QueryResult.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore - * Copyright (C) 2005-2009 MaNGOS + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -26,7 +25,7 @@ class TC_DATABASE_API ResultSet { public: - ResultSet(MYSQL_RES* result, MYSQL_FIELD* fields, uint64 rowCount, uint32 fieldCount); + ResultSet(MySQLResult* result, MySQLField* fields, uint64 rowCount, uint32 fieldCount); ~ResultSet(); bool NextRow(); @@ -36,15 +35,18 @@ class TC_DATABASE_API ResultSet Field* Fetch() const { return _currentRow; } Field const& operator[](std::size_t index) const; + QueryResultFieldMetadata const& GetFieldMetadata(std::size_t index) const; + protected: + std::vector _fieldMetadata; uint64 _rowCount; Field* _currentRow; uint32 _fieldCount; private: void CleanUp(); - MYSQL_RES* _result; - MYSQL_FIELD* _fields; + MySQLResult* _result; + MySQLField* _fields; ResultSet(ResultSet const& right) = delete; ResultSet& operator=(ResultSet const& right) = delete; @@ -53,7 +55,7 @@ class TC_DATABASE_API ResultSet class TC_DATABASE_API PreparedResultSet { public: - PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES* result, uint64 rowCount, uint32 fieldCount); + PreparedResultSet(MySQLStmt* stmt, MySQLResult* result, uint64 rowCount, uint32 fieldCount); ~PreparedResultSet(); bool NextRow(); @@ -63,16 +65,19 @@ class TC_DATABASE_API PreparedResultSet Field* Fetch() const; Field const& operator[](std::size_t index) const; + QueryResultFieldMetadata const& GetFieldMetadata(std::size_t index) const; + protected: + std::vector m_fieldMetadata; std::vector m_rows; uint64 m_rowCount; uint64 m_rowPosition; uint32 m_fieldCount; private: - MYSQL_BIND* m_rBind; - MYSQL_STMT* m_stmt; - MYSQL_RES* m_metadataResult; ///< Field metadata, returned by mysql_stmt_result_metadata + MySQLBind* m_rBind; + MySQLStmt* m_stmt; + MySQLResult* m_metadataResult; ///< Field metadata, returned by mysql_stmt_result_metadata void CleanUp(); bool _NextRow(); diff --git a/src/server/database/Database/SQLOperation.h b/src/server/database/Database/SQLOperation.h deleted file mode 100644 index 13be1de2485..00000000000 --- a/src/server/database/Database/SQLOperation.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * 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 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef _SQLOPERATION_H -#define _SQLOPERATION_H - -#include "Define.h" -#include "DatabaseEnvFwd.h" - -//- Union that holds element data -union SQLElementUnion -{ - PreparedStatement* stmt; - const char* query; -}; - -//- Type specifier of our element data -enum SQLElementDataType -{ - SQL_ELEMENT_RAW, - SQL_ELEMENT_PREPARED -}; - -//- The element -struct SQLElementData -{ - SQLElementUnion element; - SQLElementDataType type; -}; - -//- For ambigious resultsets -union SQLResultSetUnion -{ - PreparedResultSet* presult; - ResultSet* qresult; -}; - -class MySQLConnection; - -class TC_DATABASE_API SQLOperation -{ - public: - SQLOperation(): m_conn(NULL) { } - virtual ~SQLOperation() { } - - virtual int call() - { - Execute(); - return 0; - } - virtual bool Execute() = 0; - virtual void SetConnection(MySQLConnection* con) { m_conn = con; } - - MySQLConnection* m_conn; - - private: - SQLOperation(SQLOperation const& right) = delete; - SQLOperation& operator=(SQLOperation const& right) = delete; -}; - -#endif diff --git a/src/server/database/Database/Transaction.cpp b/src/server/database/Database/Transaction.cpp index d5c5cfeb84a..ddfb2995b89 100644 --- a/src/server/database/Database/Transaction.cpp +++ b/src/server/database/Database/Transaction.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -16,71 +16,92 @@ */ #include "Transaction.h" +#include "Errors.h" +#include "Log.h" #include "MySQLConnection.h" #include "PreparedStatement.h" +#include "Timer.h" #include +#include +#include +#include std::mutex TransactionTask::_deadlockLock; +#define DEADLOCK_MAX_RETRY_TIME_MS 60000 + //- Append a raw ad-hoc query to the transaction -void Transaction::Append(const char* sql) +void TransactionBase::Append(char const* sql) { - SQLElementData data; - data.type = SQL_ELEMENT_RAW; - data.element.query = strdup(sql); - m_queries.push_back(data); + ASSERT(sql); + m_queries.emplace_back(std::in_place_type, sql); } //- Append a prepared statement to the transaction -void Transaction::Append(PreparedStatement* stmt) +void TransactionBase::AppendPreparedStatement(PreparedStatementBase* stmt) { - SQLElementData data; - data.type = SQL_ELEMENT_PREPARED; - data.element.stmt = stmt; - m_queries.push_back(data); + ASSERT(stmt); + m_queries.emplace_back(std::in_place_type>, stmt); } -void Transaction::Cleanup() +void TransactionBase::Cleanup() { // This might be called by explicit calls to Cleanup or by the auto-destructor if (_cleanedUp) return; - for (SQLElementData const &data : m_queries) - { - switch (data.type) - { - case SQL_ELEMENT_PREPARED: - delete data.element.stmt; - break; - case SQL_ELEMENT_RAW: - free((void*)(data.element.query)); - break; - } - } - m_queries.clear(); _cleanedUp = true; } -bool TransactionTask::Execute() +bool TransactionTask::Execute(MySQLConnection* conn, std::shared_ptr trans) { - int errorCode = m_conn->ExecuteTransaction(m_trans); + int errorCode = TryExecute(conn, trans); if (!errorCode) return true; if (errorCode == ER_LOCK_DEADLOCK) { + std::string threadId = []() + { + // wrapped in lambda to fix false positive analysis warning C26115 + std::ostringstream threadIdStream; + threadIdStream << std::this_thread::get_id(); + return threadIdStream.str(); + }(); + // Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other std::lock_guard lock(_deadlockLock); - uint8 loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself - for (uint8 i = 0; i < loopBreaker; ++i) - if (!m_conn->ExecuteTransaction(m_trans)) + + for (uint32 loopDuration = 0, startMSTime = getMSTime(); loopDuration <= DEADLOCK_MAX_RETRY_TIME_MS; loopDuration = GetMSTimeDiffToNow(startMSTime)) + { + if (!TryExecute(conn, trans)) return true; + + TC_LOG_WARN("sql.sql", "Deadlocked SQL Transaction, retrying. Loop timer: %u ms, Thread Id: %s", loopDuration, threadId.c_str()); + } + + TC_LOG_ERROR("sql.sql", "Fatal deadlocked SQL Transaction, it will not be retried anymore. Thread Id: %s", threadId.c_str()); } // Clean up now. - m_trans->Cleanup(); + trans->Cleanup(); + + return false; +} + +int TransactionTask::TryExecute(MySQLConnection* conn, std::shared_ptr trans) +{ + return conn->ExecuteTransaction(trans); +} + +bool TransactionCallback::InvokeIfReady() +{ + if (m_future.valid() && m_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + m_callback(m_future.get()); + return true; + } return false; } diff --git a/src/server/database/Database/Transaction.h b/src/server/database/Database/Transaction.h index a25d46a5671..174ba75e58f 100644 --- a/src/server/database/Database/Transaction.h +++ b/src/server/database/Database/Transaction.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -20,13 +20,28 @@ #include "Define.h" #include "DatabaseEnvFwd.h" -#include "SQLOperation.h" #include "StringFormat.h" +#include +#include #include +#include #include +class MySQLConnection; + +struct TransactionData +{ + std::variant, std::string> query; + + template + TransactionData(Args&&... args) : query(std::forward(args)...) { } + + static PreparedStatementBase* ToExecutable(std::unique_ptr const& stmt) { return stmt.get(); } + static char const* ToExecutable(std::string const& sql) { return sql.c_str(); } +}; + /*! Transactions, high level class. */ -class TC_DATABASE_API Transaction +class TC_DATABASE_API TransactionBase { friend class TransactionTask; friend class MySQLConnection; @@ -35,43 +50,71 @@ class TC_DATABASE_API Transaction friend class DatabaseWorkerPool; public: - Transaction() : _cleanedUp(false) { } - ~Transaction() { Cleanup(); } + TransactionBase() : _cleanedUp(false) { } + TransactionBase(TransactionBase const&) = delete; + TransactionBase(TransactionBase &&) noexcept = default; + TransactionBase& operator=(TransactionBase const&) = delete; + TransactionBase& operator=(TransactionBase &&) noexcept = default; + virtual ~TransactionBase() { Cleanup(); } - void Append(PreparedStatement* statement); - void Append(const char* sql); - template - void PAppend(Format&& sql, Args&&... args) + void Append(char const* sql); + template + void PAppend(std::string_view sql, Args&&... args) { - Append(Trinity::StringFormat(std::forward(sql), std::forward(args)...).c_str()); + Append(Trinity::StringFormat(sql, std::forward(args)...).c_str()); } std::size_t GetSize() const { return m_queries.size(); } protected: + void AppendPreparedStatement(PreparedStatementBase* statement); void Cleanup(); - std::vector m_queries; + std::vector m_queries; private: bool _cleanedUp; +}; +template +class Transaction : public TransactionBase +{ +public: + using TransactionBase::Append; + void Append(PreparedStatement* statement) + { + AppendPreparedStatement(statement); + } }; /*! Low level class*/ -class TC_DATABASE_API TransactionTask : public SQLOperation +class TC_DATABASE_API TransactionTask { - template friend class DatabaseWorkerPool; - friend class DatabaseWorker; +public: + static bool Execute(MySQLConnection* conn, std::shared_ptr trans); - public: - TransactionTask(SQLTransaction trans) : m_trans(trans) { } - ~TransactionTask() { } +private: + static int TryExecute(MySQLConnection* conn, std::shared_ptr trans); - protected: - bool Execute() override; + static std::mutex _deadlockLock; +}; + +class TC_DATABASE_API TransactionCallback +{ +public: + TransactionCallback(std::future&& future) : m_future(std::move(future)) { } + TransactionCallback(TransactionCallback&&) = default; + + TransactionCallback& operator=(TransactionCallback&&) = default; + + void AfterComplete(std::function callback) & + { + m_callback = std::move(callback); + } + + bool InvokeIfReady(); - SQLTransaction m_trans; - static std::mutex _deadlockLock; + std::future m_future; + std::function m_callback; }; #endif diff --git a/src/server/database/Logging/AppenderDB.cpp b/src/server/database/Logging/AppenderDB.cpp index 9b13f2c3ef6..ba049244789 100644 --- a/src/server/database/Logging/AppenderDB.cpp +++ b/src/server/database/Logging/AppenderDB.cpp @@ -31,7 +31,7 @@ void AppenderDB::_write(LogMessage const* message) if (!enabled || (message->type.find("sql") != std::string::npos)) return; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG); stmt->setUInt64(0, message->mtime); stmt->setUInt32(1, realmId); stmt->setString(2, message->type); diff --git a/src/server/database/PrecompiledHeaders/databasePCH.h b/src/server/database/PrecompiledHeaders/databasePCH.h index 39701ca8ca9..d8c2af9bb0e 100644 --- a/src/server/database/PrecompiledHeaders/databasePCH.h +++ b/src/server/database/PrecompiledHeaders/databasePCH.h @@ -1,15 +1,20 @@ -#include "Define.h" -#include "Errors.h" -#include "Field.h" +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "DatabaseEnv.h" #include "Log.h" -#include "MySQLConnection.h" -#include "PreparedStatement.h" -#include "QueryResult.h" -#include "SQLOperation.h" -#include "Transaction.h" -#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7 -#include -#endif -#include -#include -#include +#include "MySQLHacks.h" diff --git a/src/server/database/Updater/UpdateFetcher.cpp b/src/server/database/Updater/UpdateFetcher.cpp index dbed9b000e1..88ca5284554 100644 --- a/src/server/database/Updater/UpdateFetcher.cpp +++ b/src/server/database/Updater/UpdateFetcher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -16,13 +16,13 @@ */ #include "UpdateFetcher.h" -#include "Common.h" #include "DBUpdater.h" #include "Field.h" #include "Log.h" #include "QueryResult.h" #include "Util.h" #include "SHA1.h" +#include #include #include #include @@ -34,7 +34,6 @@ struct UpdateFetcher::DirectoryEntry DirectoryEntry(Path const& path_, State state_) : path(path_), state(state_) { } Path const path; - State const state; }; @@ -42,7 +41,7 @@ UpdateFetcher::UpdateFetcher(Path const& sourceDirectory, std::function const& apply, std::function const& applyFile, std::function const& retrieve) : - _sourceDirectory(Trinity::make_unique(sourceDirectory)), _apply(apply), _applyFile(applyFile), + _sourceDirectory(std::make_unique(sourceDirectory)), _apply(apply), _applyFile(applyFile), _retrieve(retrieve) { } @@ -307,7 +306,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, { case MODE_APPLY: speed = Apply(availableQuery.first); - /*no break*/ + [[fallthrough]]; case MODE_REHASH: UpdateEntry(file, speed); break; @@ -338,7 +337,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, CleanUp(applied); else { - TC_LOG_ERROR("sql.updates", "Cleanup is disabled! There were " SZFMTD " dirty files applied to your database, " \ + TC_LOG_ERROR("sql.updates", "Cleanup is disabled! There were %zu dirty files applied to your database, " \ "but they are now missing in your source directory!", applied.size()); } } @@ -413,7 +412,7 @@ void UpdateFetcher::CleanUp(AppliedFileStorage const& storage) const void UpdateFetcher::UpdateState(std::string const& name, State const state) const { - std::string const update = "UPDATE `updates` SET `state`=\'" + AppliedFileEntry::StateConvert(state) + "\' WHERE `name`=\"" + name + "\""; + std::string const update = Trinity::StringFormat(R"(UPDATE `updates` SET `state`='%s' WHERE `name`="%s")", AppliedFileEntry::StateConvert(state), name); // Update database _apply(update); diff --git a/src/server/database/Updater/UpdateFetcher.h b/src/server/database/Updater/UpdateFetcher.h index 97ef787ca1a..3accf8e3a92 100644 --- a/src/server/database/Updater/UpdateFetcher.h +++ b/src/server/database/Updater/UpdateFetcher.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -20,6 +20,7 @@ #include "Define.h" #include "DatabaseEnvFwd.h" +#include #include #include #include diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 014bb8a62d8..8a18342629a 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -44,7 +44,7 @@ void SmartWaypointMgr::LoadFromDB() waypoint_map.clear(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMARTAI_WP); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMARTAI_WP); PreparedQueryResult result = WorldDatabase.Query(stmt); if (!result) @@ -113,7 +113,7 @@ void SmartAIMgr::LoadSmartAIFromDB() for (uint8 i = 0; i < SMART_SCRIPT_TYPE_MAX; i++) mEventMap[i].clear(); //Drop Existing SmartAI List - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMART_SCRIPTS); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMART_SCRIPTS); PreparedQueryResult result = WorldDatabase.Query(stmt); if (!result) diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index b73117689c3..7626cb8a0c6 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -57,7 +57,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass if (GetId(username)) return AccountOpResult::AOR_NAME_ALREADY_EXIST; // username does already exist - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); stmt->setString(0, username); stmt->setString(1, CalculateShaPassHash(username, password)); @@ -85,7 +85,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) { // Check if accounts exists - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -93,11 +93,11 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) return AccountOpResult::AOR_NAME_NOT_EXIST; // Obtain accounts characters - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); + CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); - stmt->setUInt32(0, accountId); + stmt2->setUInt32(0, accountId); - result = CharacterDatabase.Query(stmt); + result = CharacterDatabase.Query(stmt2); if (result) { @@ -118,19 +118,19 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) } // table realm specific but common for all characters of account for realm - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TUTORIALS); - stmt->setUInt32(0, accountId); - CharacterDatabase.Execute(stmt); + stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TUTORIALS); + stmt2->setUInt32(0, accountId); + CharacterDatabase.Execute(stmt2); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_DATA); - stmt->setUInt32(0, accountId); - CharacterDatabase.Execute(stmt); + stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_DATA); + stmt2->setUInt32(0, accountId); + CharacterDatabase.Execute(stmt2); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BAN); - stmt->setUInt32(0, accountId); - CharacterDatabase.Execute(stmt); + stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BAN); + stmt2->setUInt32(0, accountId); + CharacterDatabase.Execute(stmt2); - SQLTransaction trans = LoginDatabase.BeginTransaction(); + LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT); stmt->setUInt32(0, accountId); @@ -160,7 +160,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) { // Check if accounts exists - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -206,7 +206,7 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(newPassword); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD); stmt->setString(0, CalculateShaPassHash(username, newPassword)); stmt->setUInt32(1, accountId); @@ -244,7 +244,7 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(newEmail); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL); stmt->setString(0, newEmail); stmt->setUInt32(1, accountId); @@ -274,7 +274,7 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(newEmail); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REG_EMAIL); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REG_EMAIL); stmt->setString(0, newEmail); stmt->setUInt32(1, accountId); @@ -287,7 +287,7 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai uint32 AccountMgr::GetId(std::string const& username) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); stmt->setString(0, username); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -296,7 +296,7 @@ uint32 AccountMgr::GetId(std::string const& username) uint32 AccountMgr::GetSecurity(uint32 accountId) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -305,7 +305,7 @@ uint32 AccountMgr::GetSecurity(uint32 accountId) uint32 AccountMgr::GetSecurity(uint32 accountId, int32 realmId) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); stmt->setUInt32(0, accountId); stmt->setInt32(1, realmId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -315,7 +315,7 @@ uint32 AccountMgr::GetSecurity(uint32 accountId, int32 realmId) bool AccountMgr::GetName(uint32 accountId, std::string& name) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -330,7 +330,7 @@ bool AccountMgr::GetName(uint32 accountId, std::string& name) bool AccountMgr::GetEmail(uint32 accountId, std::string& email) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_EMAIL_BY_ID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_EMAIL_BY_ID); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -353,7 +353,7 @@ bool AccountMgr::CheckPassword(uint32 accountId, std::string password) Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(password); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); stmt->setUInt32(0, accountId); stmt->setString(1, CalculateShaPassHash(username, password)); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -381,7 +381,7 @@ bool AccountMgr::CheckEmail(uint32 accountId, std::string newEmail) uint32 AccountMgr::GetCharactersCount(uint32 accountId) { // check character count - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); stmt->setUInt32(0, accountId); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -402,7 +402,7 @@ std::string AccountMgr::CalculateShaPassHash(std::string const& name, std::strin bool AccountMgr::IsBannedAccount(std::string const& name) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME); stmt->setString(0, name); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -519,17 +519,17 @@ void AccountMgr::UpdateAccountAccess(rbac::RBACData* rbac, uint32 accountId, uin if (rbac && securityLevel != rbac->GetSecurityLevel()) rbac->SetSecurityLevel(securityLevel); - SQLTransaction trans = LoginDatabase.BeginTransaction(); + LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); // Delete old security level from DB if (realmId == -1) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); stmt->setUInt32(0, accountId); trans->Append(stmt); } else { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM); stmt->setUInt32(0, accountId); stmt->setUInt32(1, realmId); trans->Append(stmt); @@ -538,7 +538,7 @@ void AccountMgr::UpdateAccountAccess(rbac::RBACData* rbac, uint32 accountId, uin // Add new security level if (securityLevel) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS); stmt->setUInt32(0, accountId); stmt->setUInt8(1, securityLevel); stmt->setInt32(2, realmId); diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp index 8472e8914a8..8c10f85d295 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.cpp +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -37,7 +37,7 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, if (GetId(email)) return AccountOpResult::AOR_NAME_ALREADY_EXIST; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT); stmt->setString(0, email); stmt->setString(1, CalculateShaPassHash(email, password)); LoginDatabase.DirectExecute(stmt); @@ -65,7 +65,7 @@ AccountOpResult Battlenet::AccountMgr::ChangePassword(uint32 accountId, std::str if (utf8length(newPassword) > MAX_PASS_STR) return AccountOpResult::AOR_PASS_TOO_LONG; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD); stmt->setString(0, CalculateShaPassHash(username, newPassword)); stmt->setUInt32(1, accountId); LoginDatabase.Execute(stmt); @@ -83,7 +83,7 @@ bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(password); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); stmt->setUInt32(0, accountId); stmt->setString(1, CalculateShaPassHash(username, password)); @@ -103,7 +103,7 @@ AccountOpResult Battlenet::AccountMgr::LinkWithGameAccount(std::string const& em if (GetIdByGameAccount(gameAccountId)) return AccountOpResult::AOR_ACCOUNT_BAD_LINK; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LINK); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LINK); stmt->setUInt32(0, bnetAccountId); stmt->setUInt8(1, GetMaxIndex(bnetAccountId) + 1); stmt->setUInt32(2, gameAccountId); @@ -120,7 +120,7 @@ AccountOpResult Battlenet::AccountMgr::UnlinkGameAccount(std::string const& game if (!GetIdByGameAccount(gameAccountId)) return AccountOpResult::AOR_ACCOUNT_BAD_LINK; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LINK); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LINK); stmt->setNull(0); stmt->setNull(1); stmt->setUInt32(2, gameAccountId); @@ -130,7 +130,7 @@ AccountOpResult Battlenet::AccountMgr::UnlinkGameAccount(std::string const& game uint32 Battlenet::AccountMgr::GetId(std::string const& username) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL); stmt->setString(0, username); if (PreparedQueryResult result = LoginDatabase.Query(stmt)) return (*result)[0].GetUInt32(); @@ -140,7 +140,7 @@ uint32 Battlenet::AccountMgr::GetId(std::string const& username) bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); stmt->setUInt32(0, accountId); if (PreparedQueryResult result = LoginDatabase.Query(stmt)) { @@ -153,7 +153,7 @@ bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) uint32 Battlenet::AccountMgr::GetIdByGameAccount(uint32 gameAccountId) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT); stmt->setUInt32(0, gameAccountId); if (PreparedQueryResult result = LoginDatabase.Query(stmt)) return (*result)[0].GetUInt32(); @@ -163,7 +163,7 @@ uint32 Battlenet::AccountMgr::GetIdByGameAccount(uint32 gameAccountId) uint8 Battlenet::AccountMgr::GetMaxIndex(uint32 accountId) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_MAX_ACCOUNT_INDEX); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_MAX_ACCOUNT_INDEX); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp index 7e5557ce27c..f9b645df235 100644 --- a/src/server/game/Accounts/RBAC.cpp +++ b/src/server/game/Accounts/RBAC.cpp @@ -130,7 +130,7 @@ RBACCommandResult RBACData::DenyPermission(uint32 permissionId, int32 realmId /* void RBACData::SavePermission(uint32 permission, bool granted, int32 realmId) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, permission); stmt->setBool(2, granted); @@ -156,7 +156,7 @@ RBACCommandResult RBACData::RevokePermission(uint32 permissionId, int32 realmId { TC_LOG_TRACE("rbac", "RBACData::RevokePermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok and DB updated", GetId(), GetName().c_str(), permissionId, realmId); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, permissionId); stmt->setInt32(2, realmId); @@ -177,7 +177,7 @@ void RBACData::LoadFromDB() TC_LOG_DEBUG("rbac", "RBACData::LoadFromDB [Id: %u Name: %s]: Loading permissions", GetId(), GetName().c_str()); // Load account permissions (granted and denied) that affect current realm - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS); stmt->setUInt32(0, GetId()); stmt->setInt32(1, GetRealmId()); @@ -190,7 +190,7 @@ QueryCallback RBACData::LoadFromDBAsync() TC_LOG_DEBUG("rbac", "RBACData::LoadFromDB [Id: %u Name: %s]: Loading permissions", GetId(), GetName().c_str()); // Load account permissions (granted and denied) that affect current realm - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS); stmt->setUInt32(0, GetId()); stmt->setInt32(1, GetRealmId()); diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 67026ba32ce..279e7c237fe 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -214,9 +214,9 @@ void PlayerAchievementMgr::Reset() void PlayerAchievementMgr::DeleteFromDB(ObjectGuid const& guid) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT); stmt->setUInt64(0, guid.GetCounter()); trans->Append(stmt); @@ -272,7 +272,7 @@ void PlayerAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Pre // Removing non-existing criteria data for all characters TC_LOG_ERROR("criteria.achievement", "Non-existing achievement criteria %u data has been removed from the table `character_achievement_progress`.", id); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA); stmt->setUInt32(0, id); CharacterDatabase.Execute(stmt); @@ -290,7 +290,7 @@ void PlayerAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Pre } } -void PlayerAchievementMgr::SaveToDB(SQLTransaction& trans) +void PlayerAchievementMgr::SaveToDB(CharacterDatabaseTransaction& trans) { if (!_completedAchievements.empty()) { @@ -299,7 +299,7 @@ void PlayerAchievementMgr::SaveToDB(SQLTransaction& trans) if (!iter->second.Changed) continue; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT); stmt->setUInt32(0, iter->first); stmt->setUInt64(1, _owner->GetGUID().GetCounter()); trans->Append(stmt); @@ -321,7 +321,7 @@ void PlayerAchievementMgr::SaveToDB(SQLTransaction& trans) if (!iter->second.Changed) continue; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA); stmt->setUInt64(0, _owner->GetGUID().GetCounter()); stmt->setUInt32(1, iter->first); trans->Append(stmt); @@ -552,7 +552,7 @@ void PlayerAchievementMgr::CompletedAchievement(AchievementEntry const* achievem draft = MailDraft(subject, text); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); Item* item = reward->ItemId ? Item::CreateItem(reward->ItemId, 1, _owner) : NULL; if (item) @@ -682,9 +682,9 @@ void GuildAchievementMgr::Reset() void GuildAchievementMgr::DeleteFromDB(ObjectGuid const& guid) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GUILD_ACHIEVEMENTS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GUILD_ACHIEVEMENTS); stmt->setUInt64(0, guid.GetCounter()); trans->Append(stmt); @@ -738,7 +738,7 @@ void GuildAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Prep // we will remove not existed criteria for all guilds TC_LOG_ERROR("criteria.achievement", "Non-existing achievement criteria %u data removed from table `guild_achievement_progress`.", id); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA_GUILD); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA_GUILD); stmt->setUInt32(0, id); CharacterDatabase.Execute(stmt); continue; @@ -756,9 +756,9 @@ void GuildAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Prep } } -void GuildAchievementMgr::SaveToDB(SQLTransaction& trans) +void GuildAchievementMgr::SaveToDB(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; std::ostringstream guidstr; for (auto itr = _completedAchievements.begin(); itr != _completedAchievements.end(); ++itr) { @@ -1117,7 +1117,7 @@ void AchievementGlobalMgr::LoadCompletedAchievements() // Remove non-existing achievements from all characters TC_LOG_ERROR("criteria.achievement", "Non-existing achievement %u data has been removed from the table `character_achievement`.", achievementId); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEVMENT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEVMENT); stmt->setUInt32(0, achievementId); CharacterDatabase.Execute(stmt); diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 9b358404f4f..3144a27e7c0 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -82,7 +82,7 @@ class TC_GAME_API PlayerAchievementMgr : public AchievementMgr static void DeleteFromDB(ObjectGuid const& guid); void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult); - void SaveToDB(SQLTransaction& trans); + void SaveToDB(CharacterDatabaseTransaction& trans); void ResetCriteria(CriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); void ResetCriteriaId(CriteriaTypes type, uint32 id); @@ -118,7 +118,7 @@ class TC_GAME_API GuildAchievementMgr : public AchievementMgr static void DeleteFromDB(ObjectGuid const& guid); void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult); - void SaveToDB(SQLTransaction& trans); + void SaveToDB(CharacterDatabaseTransaction& trans); void SendAllData(Player const* receiver) const override; void SendAchievementInfo(Player* receiver, uint32 achievementId = 0) const; diff --git a/src/server/game/Archaeology/ArchaeologyMgr.cpp b/src/server/game/Archaeology/ArchaeologyMgr.cpp index efd4f437826..f8238ec8f27 100644 --- a/src/server/game/Archaeology/ArchaeologyMgr.cpp +++ b/src/server/game/Archaeology/ArchaeologyMgr.cpp @@ -35,7 +35,7 @@ void ArchaeologyMgr::LoadDigsites() mResearchDigsitesMap.clear(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_ARCHAEOLOGY_DIGSITES); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_ARCHAEOLOGY_DIGSITES); PreparedQueryResult result = WorldDatabase.Query(stmt); if (!result) @@ -272,7 +272,7 @@ int ArchaeologyMgr::GetArtifactSkillReqLevel(uint32 spellId) { uint8 reqSkillLevel = 1; - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_ARCHAEOLOGY_ARTIFACT); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_ARCHAEOLOGY_ARTIFACT); stmt->setUInt32(0, spellId); PreparedQueryResult result = WorldDatabase.Query(stmt); diff --git a/src/server/game/Archaeology/ArchaeologyPlayerMgr.cpp b/src/server/game/Archaeology/ArchaeologyPlayerMgr.cpp index aa2051eed62..ce87fc7a5fd 100644 --- a/src/server/game/Archaeology/ArchaeologyPlayerMgr.cpp +++ b/src/server/game/Archaeology/ArchaeologyPlayerMgr.cpp @@ -83,9 +83,9 @@ void ArchaeologyPlayerMgr::LoadArchaeologyHistory(PreparedQueryResult result) while (result->NextRow()); } -void ArchaeologyPlayerMgr::SaveArchaeologyDigSites(SQLTransaction& trans) +void ArchaeologyPlayerMgr::SaveArchaeologyDigSites(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARCHAEOLOGY_DIGSITES); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARCHAEOLOGY_DIGSITES); stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter()); trans->Append(stmt); std::vector digsites = GetPlayer()->GetDynamicValues(PLAYER_DYNAMIC_FIELD_RESEARCH_SITE); @@ -94,7 +94,7 @@ void ArchaeologyPlayerMgr::SaveArchaeologyDigSites(SQLTransaction& trans) { uint16 digsiteId = digsites[i]; Digsite digsite = GetDigsitePosition(i); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARCHAEOLOGY_DIGSITE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARCHAEOLOGY_DIGSITE); stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter()); stmt->setUInt16(1, digsiteId); @@ -106,9 +106,9 @@ void ArchaeologyPlayerMgr::SaveArchaeologyDigSites(SQLTransaction& trans) } } -void ArchaeologyPlayerMgr::SaveArchaeologyBranchs(SQLTransaction& trans) +void ArchaeologyPlayerMgr::SaveArchaeologyBranchs(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARCHAEOLOGY_BRANCHS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARCHAEOLOGY_BRANCHS); stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter()); trans->Append(stmt); @@ -118,7 +118,7 @@ void ArchaeologyPlayerMgr::SaveArchaeologyBranchs(SQLTransaction& trans) { uint16 projectId = GetPlayer()->GetUInt16Value(PLAYER_FIELD_RESEARCHING_1 + i / 2, i % 2); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARCHAEOLOGY_BRANCH); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARCHAEOLOGY_BRANCH); stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter()); stmt->setUInt16(1, projectId); trans->Append(stmt); @@ -126,9 +126,9 @@ void ArchaeologyPlayerMgr::SaveArchaeologyBranchs(SQLTransaction& trans) } } -void ArchaeologyPlayerMgr::SaveArchaeologyHistory(SQLTransaction& trans) +void ArchaeologyPlayerMgr::SaveArchaeologyHistory(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARCHAEOLOGY_HISTORY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARCHAEOLOGY_HISTORY); stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter()); trans->Append(stmt); diff --git a/src/server/game/Archaeology/ArchaeologyPlayerMgr.h b/src/server/game/Archaeology/ArchaeologyPlayerMgr.h index bc43b285a25..319d6838660 100644 --- a/src/server/game/Archaeology/ArchaeologyPlayerMgr.h +++ b/src/server/game/Archaeology/ArchaeologyPlayerMgr.h @@ -57,9 +57,9 @@ class ArchaeologyPlayerMgr void LoadArchaeologyDigSites(PreparedQueryResult result); void LoadArchaeologyBranchs(PreparedQueryResult result); void LoadArchaeologyHistory(PreparedQueryResult result); - void SaveArchaeologyDigSites(SQLTransaction& trans); - void SaveArchaeologyBranchs(SQLTransaction& trans); - void SaveArchaeologyHistory(SQLTransaction& trans); + void SaveArchaeologyDigSites(CharacterDatabaseTransaction& trans); + void SaveArchaeologyBranchs(CharacterDatabaseTransaction& trans); + void SaveArchaeologyHistory(CharacterDatabaseTransaction& trans); ArchaeologyHistoryMap& GetHistory() { return m_ArchaeologyHistoryMap; } diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 3c9cebc3950..76d0363a60a 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -107,7 +107,7 @@ uint64 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 } //does not clear ram -void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& trans) +void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans) { Item* item = GetAItem(auction->itemGUIDLow); if (!item) @@ -153,7 +153,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& { // set owner to bidder (to prevent delete item with sender char deleting) // owner in `data` will set at mail receive and item extracting - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER); stmt->setUInt64(0, auction->bidder); stmt->setUInt64(1, item->GetGUID().GetCounter()); trans->Append(stmt); @@ -176,7 +176,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& } } -void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry* auction, SQLTransaction& trans) +void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans) { ObjectGuid owner_guid = ObjectGuid::Create(auction->owner); Player* owner = ObjectAccessor::FindConnectedPlayer(owner_guid); @@ -188,7 +188,7 @@ void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry* auction, SQLTrans } //call this method to send mail to auction owner, when auction is successful, it does not clear ram -void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry* auction, SQLTransaction& trans) +void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans) { ObjectGuid owner_guid = ObjectGuid::Create(auction->owner); Player* owner = ObjectAccessor::FindConnectedPlayer(owner_guid); @@ -216,7 +216,7 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry* auction, SQLTransa } //does not clear ram -void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, SQLTransaction& trans) +void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans) { //return an item in auction to its owner by mail Item* item = GetAItem(auction->itemGUIDLow); @@ -244,7 +244,7 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, SQLTransacti } //this function sends mail to old bidder -void AuctionHouseMgr::SendAuctionOutbiddedMail(AuctionEntry* auction, uint64 /*newPrice*/, Player* /*newBidder*/, SQLTransaction& trans) +void AuctionHouseMgr::SendAuctionOutbiddedMail(AuctionEntry* auction, uint64 /*newPrice*/, Player* /*newBidder*/, CharacterDatabaseTransaction& trans) { ObjectGuid oldBidder_guid = ObjectGuid::Create(auction->bidder); Player* oldBidder = ObjectAccessor::FindConnectedPlayer(oldBidder_guid); @@ -268,7 +268,7 @@ void AuctionHouseMgr::SendAuctionOutbiddedMail(AuctionEntry* auction, uint64 /*n } //this function sends mail, when auction is cancelled to old bidder -void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans) +void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans) { ObjectGuid bidder_guid = ObjectGuid::Create(auction->bidder); Player* bidder = ObjectAccessor::FindConnectedPlayer(bidder_guid); @@ -299,7 +299,7 @@ void AuctionHouseMgr::LoadAuctionItems() } // data needs to be at first place for Item::LoadFromDB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_AUCTION_ITEMS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_AUCTION_ITEMS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -343,7 +343,7 @@ void AuctionHouseMgr::LoadAuctions() { uint32 oldMSTime = getMSTime(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_AUCTIONS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_AUCTIONS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -354,7 +354,7 @@ void AuctionHouseMgr::LoadAuctions() uint32 count = 0; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); do { Field* fields = result->Fetch(); @@ -392,7 +392,7 @@ bool AuctionHouseMgr::RemoveAItem(ObjectGuid::LowType id, bool deleteItem) if (deleteItem) { - SQLTransaction trans = SQLTransaction(nullptr); + CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr); i->second->FSetState(ITEM_REMOVED); i->second->SaveToDB(trans); } @@ -432,7 +432,7 @@ void AuctionHouseMgr::PendingAuctionProcess(Player* player) PlayerAuctions* thisAH = iterMap->second.first; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); uint32 totalItems = 0; for (auto itrAH = thisAH->begin(); itrAH != thisAH->end(); ++itrAH) @@ -495,7 +495,7 @@ void AuctionHouseMgr::UpdatePendingAuctions() TC_LOG_WARN("auctionHouse", "Player %s was offline, unable to retrieve deposit!", playerGUID.ToString().c_str()); PlayerAuctions* thisAH = itr->second.first; ++itr; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); for (auto AHitr = thisAH->begin(); AHitr != thisAH->end();) { AuctionEntry* AH = (*AHitr); @@ -598,7 +598,7 @@ void AuctionHouseObject::Update() ++itr; } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); for (AuctionEntryMap::iterator it = AuctionsMap.begin(); it != AuctionsMap.end();) { @@ -880,16 +880,16 @@ uint64 AuctionEntry::GetAuctionOutBid() const return outbid ? outbid : 1; } -void AuctionEntry::DeleteFromDB(SQLTransaction& trans) const +void AuctionEntry::DeleteFromDB(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_AUCTION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_AUCTION); stmt->setUInt32(0, Id); trans->Append(stmt); } -void AuctionEntry::SaveToDB(SQLTransaction& trans) const +void AuctionEntry::SaveToDB(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AUCTION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AUCTION); stmt->setUInt32(0, Id); stmt->setUInt64(1, auctioneer); stmt->setUInt64(2, itemGUIDLow); diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h index 071f55c6807..c1d3d6be12a 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.h +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h @@ -102,8 +102,8 @@ struct TC_GAME_API AuctionEntry uint64 GetAuctionCut() const; uint64 GetAuctionOutBid() const; void BuildAuctionInfo(std::vector& items, bool listAuctionItems, Item* sourceItem = nullptr) const; - void DeleteFromDB(SQLTransaction& trans) const; - void SaveToDB(SQLTransaction& trans) const; + void DeleteFromDB(CharacterDatabaseTransaction& trans) const; + void SaveToDB(CharacterDatabaseTransaction& trans) const; bool LoadFromDB(Field* fields); std::string BuildAuctionMailSubject(MailAuctionAnswers response) const; static std::string BuildAuctionMailBody(uint64 lowGuid, uint64 bid, uint64 buyout, uint64 deposit, uint64 cut); @@ -211,12 +211,12 @@ class TC_GAME_API AuctionHouseMgr } //auction messages - void SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& trans); - void SendAuctionSalePendingMail(AuctionEntry* auction, SQLTransaction& trans); - void SendAuctionSuccessfulMail(AuctionEntry* auction, SQLTransaction& trans); - void SendAuctionExpiredMail(AuctionEntry* auction, SQLTransaction& trans); - void SendAuctionOutbiddedMail(AuctionEntry* auction, uint64 newPrice, Player* newBidder, SQLTransaction& trans); - void SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans); + void SendAuctionWonMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans); + void SendAuctionSalePendingMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans); + void SendAuctionSuccessfulMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans); + void SendAuctionExpiredMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans); + void SendAuctionOutbiddedMail(AuctionEntry* auction, uint64 newPrice, Player* newBidder, CharacterDatabaseTransaction& trans); + void SendAuctionCancelledToBidderMail(AuctionEntry* auction, CharacterDatabaseTransaction& trans); static uint64 GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count); static AuctionHouseEntry const* GetAuctionHouseEntry(uint32 factionTemplateId, uint32* houseId); diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp index a066fe8e361..28a77263908 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp @@ -60,7 +60,7 @@ bool AuctionBotConfig::Initialize() if (uint32 ahBotAccId = GetConfig(CONFIG_AHBOT_ACCOUNT_ID)) { // find account guids associated with ahbot account - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); stmt->setUInt32(0, ahBotAccId); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) { diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp index 65a81cac3ca..16f28804c3a 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp @@ -390,7 +390,7 @@ void AuctionBotBuyer::BuyEntry(AuctionEntry* auction, AuctionHouseObject* auctio { TC_LOG_DEBUG("ahbot", "AHBot: Entry %u bought at %.2fg", auction->Id, float(auction->buyout) / GOLD); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Send mail to previous bidder if any if (auction->bidder && !sAuctionBotConfig->IsBotChar(auction->bidder)) @@ -421,7 +421,7 @@ void AuctionBotBuyer::PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice) { TC_LOG_DEBUG("ahbot", "AHBot: Bid placed to entry %u, %.2fg", auction->Id, float(bidPrice) / GOLD); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Send mail to previous bidder if any if (auction->bidder && !sAuctionBotConfig->IsBotChar(auction->bidder)) @@ -432,7 +432,7 @@ void AuctionBotBuyer::PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice) auction->bid = bidPrice; // Update auction to DB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID); stmt->setUInt64(0, auction->bidder); stmt->setUInt32(1, auction->bid); stmt->setUInt32(2, auction->Id); diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp index 8b7adb2f2a0..8ca5ef96fc2 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp @@ -921,7 +921,7 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config) AllItemsArray allItems(MAX_AUCTION_QUALITY, std::vector(MAX_ITEM_CLASS)); // Main loop // getRandomArray will give what categories of items should be added (return true if there is at least 1 items missed) - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); while (GetItemsToSell(config, itemsToSell, allItems) && items > 0) { --items; diff --git a/src/server/game/BattlePets/BattlePetMgr.cpp b/src/server/game/BattlePets/BattlePetMgr.cpp index 2cc7536aded..2dba38f4dab 100644 --- a/src/server/game/BattlePets/BattlePetMgr.cpp +++ b/src/server/game/BattlePets/BattlePetMgr.cpp @@ -97,9 +97,9 @@ void BattlePetMgr::LoadFromDB(PreparedQueryResult pets, PreparedQueryResult slot } } -void BattlePetMgr::SaveToDB(SQLTransaction& trans) +void BattlePetMgr::SaveToDB(LoginDatabaseTransaction& trans) { - PreparedStatement* stmt = nullptr; + LoginDatabasePreparedStatement* stmt = nullptr; for (auto itr = _pets.begin(); itr != _pets.end();) { diff --git a/src/server/game/BattlePets/BattlePetMgr.h b/src/server/game/BattlePets/BattlePetMgr.h index 5ed516f7c24..9cbb941e493 100644 --- a/src/server/game/BattlePets/BattlePetMgr.h +++ b/src/server/game/BattlePets/BattlePetMgr.h @@ -31,7 +31,7 @@ class BattlePetMgr explicit BattlePetMgr(WorldSession* owner); void LoadFromDB(PreparedQueryResult pets, PreparedQueryResult slots); - void SaveToDB(SQLTransaction& trans); + void SaveToDB(LoginDatabaseTransaction& trans); BattlePet* GetPet(ObjectGuid guid); void AddPet(BattlePet* battlePet); diff --git a/src/server/game/Battlegrounds/Arena.cpp b/src/server/game/Battlegrounds/Arena.cpp index 7392ff54adb..8504ff70f24 100644 --- a/src/server/game/Battlegrounds/Arena.cpp +++ b/src/server/game/Battlegrounds/Arena.cpp @@ -102,7 +102,7 @@ void Arena::BuildPvPLogDataPacket(WorldPackets::Battleground::PVPLogData& pvpLog if (isRated()) { - pvpLogData.Ratings = boost::in_place(); + pvpLogData.Ratings.emplace(); for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) { diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index d75e2a44b32..23a4c9671f6 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -734,7 +734,7 @@ void Battleground::EndBattleground(uint32 winner) SetWinner(BG_TEAM_NEUTRAL); } - PreparedStatement* stmt = nullptr; + CharacterDatabasePreparedStatement* stmt = nullptr; uint64 battlegroundId = 1; if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) { @@ -924,7 +924,7 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen } else { - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); Player::OfflineResurrect(guid, trans); } @@ -964,7 +964,7 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen if (Group* group = GetBgRaid(team)) { if (!group->RemoveMember(guid)) // group was disbanded - SetBgRaid(team, NULL); + SetBgRaid(team, nullptr); } DecreaseInvitedCount(team); //we should update battleground queue, but only if bg isn't ending diff --git a/src/server/game/Battlegrounds/BattlegroundScore.cpp b/src/server/game/Battlegrounds/BattlegroundScore.cpp index a9e65090201..82a87527ceb 100644 --- a/src/server/game/Battlegrounds/BattlegroundScore.cpp +++ b/src/server/game/Battlegrounds/BattlegroundScore.cpp @@ -63,7 +63,7 @@ void BattlegroundScore::BuildPvPLogPlayerDataPacket(WorldPackets::Battleground:: playerData.Faction = TeamId; if (HonorableKills || Deaths || BonusHonor) { - playerData.Honor = boost::in_place(); + playerData.Honor.emplace(); playerData.Honor->HonorKills = HonorableKills; playerData.Honor->Deaths = Deaths; playerData.Honor->ContributionPoints = BonusHonor; diff --git a/src/server/game/BlackMarket/BlackMarketMgr.cpp b/src/server/game/BlackMarket/BlackMarketMgr.cpp index 3ca9551569a..f5609ce055e 100644 --- a/src/server/game/BlackMarket/BlackMarketMgr.cpp +++ b/src/server/game/BlackMarket/BlackMarketMgr.cpp @@ -101,7 +101,7 @@ void BlackMarketMgr::LoadAuctions() _auctions.clear(); } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BLACKMARKET_AUCTIONS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BLACKMARKET_AUCTIONS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { @@ -111,7 +111,7 @@ void BlackMarketMgr::LoadAuctions() _lastUpdate = time(nullptr); //Set update time before loading - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); do { Field* fields = result->Fetch(); @@ -134,7 +134,7 @@ void BlackMarketMgr::LoadAuctions() void BlackMarketMgr::Update(bool updateTime) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); time_t now = time(nullptr); for (BlackMarketEntryMap::iterator itr = _auctions.begin(); itr != _auctions.end();) { @@ -168,7 +168,7 @@ void BlackMarketMgr::RefreshAuctions() if (auctionDiff <= 0) return; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); std::list templates; for (auto const& pair : _templates) @@ -246,7 +246,7 @@ void BlackMarketMgr::AddTemplate(BlackMarketTemplate* templ) _templates[templ->MarketID] = templ; } -void BlackMarketMgr::SendAuctionWonMail(BlackMarketEntry* entry, SQLTransaction& trans) +void BlackMarketMgr::SendAuctionWonMail(BlackMarketEntry* entry, CharacterDatabaseTransaction& trans) { // Mail already sent if (entry->GetMailSent()) @@ -306,7 +306,7 @@ void BlackMarketMgr::SendAuctionWonMail(BlackMarketEntry* entry, SQLTransaction& entry->MailSent(); } -void BlackMarketMgr::SendAuctionOutbidMail(BlackMarketEntry* entry, SQLTransaction& trans) +void BlackMarketMgr::SendAuctionOutbidMail(BlackMarketEntry* entry, CharacterDatabaseTransaction& trans) { ObjectGuid oldBidder_guid = ObjectGuid::Create(entry->GetBidder()); Player* oldBidder = ObjectAccessor::FindConnectedPlayer(oldBidder_guid); @@ -362,7 +362,7 @@ bool BlackMarketTemplate::LoadFromDB(Field* fields) if (!bonusListIDs.empty()) { - Item.ItemBonus = boost::in_place(); + Item.ItemBonus.emplace(); Item.ItemBonus->BonusListIDs = bonusListIDs; } @@ -421,9 +421,9 @@ bool BlackMarketEntry::LoadFromDB(Field* fields) return true; } -void BlackMarketEntry::SaveToDB(SQLTransaction& trans) const +void BlackMarketEntry::SaveToDB(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BLACKMARKET_AUCTIONS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BLACKMARKET_AUCTIONS); stmt->setInt32(0, _marketId); stmt->setUInt64(1, _currentBid); @@ -434,9 +434,9 @@ void BlackMarketEntry::SaveToDB(SQLTransaction& trans) const trans->Append(stmt); } -void BlackMarketEntry::DeleteFromDB(SQLTransaction& trans) const +void BlackMarketEntry::DeleteFromDB(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BLACKMARKET_AUCTIONS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BLACKMARKET_AUCTIONS); stmt->setInt32(0, _marketId); trans->Append(stmt); } @@ -455,7 +455,7 @@ bool BlackMarketEntry::ValidateBid(uint64 bid) const return true; } -void BlackMarketEntry::PlaceBid(uint64 bid, Player* player, SQLTransaction& trans) +void BlackMarketEntry::PlaceBid(uint64 bid, Player* player, CharacterDatabaseTransaction& trans) { if (bid < _currentBid) return; @@ -467,7 +467,7 @@ void BlackMarketEntry::PlaceBid(uint64 bid, Player* player, SQLTransaction& tran player->ModifyMoney(-static_cast(bid)); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_BLACKMARKET_AUCTIONS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_BLACKMARKET_AUCTIONS); stmt->setUInt64(0, _currentBid); stmt->setInt32(1, GetExpirationTime()); stmt->setInt32(2, _numBids); diff --git a/src/server/game/BlackMarket/BlackMarketMgr.h b/src/server/game/BlackMarket/BlackMarketMgr.h index 9570b99d863..d7f69ca89e7 100644 --- a/src/server/game/BlackMarket/BlackMarketMgr.h +++ b/src/server/game/BlackMarket/BlackMarketMgr.h @@ -98,13 +98,13 @@ class BlackMarketEntry time_t GetExpirationTime() const; bool IsCompleted() const; - void DeleteFromDB(SQLTransaction& trans) const; - void SaveToDB(SQLTransaction& trans) const; + void DeleteFromDB(CharacterDatabaseTransaction& trans) const; + void SaveToDB(CharacterDatabaseTransaction& trans) const; bool LoadFromDB(Field* fields); uint64 GetMinIncrement() const { return (_currentBid / 20) - ((_currentBid / 20) % GOLD); } //5% increase every bid (has to be round gold value) bool ValidateBid(uint64 bid) const; - void PlaceBid(uint64 bid, Player* player, SQLTransaction& trans); + void PlaceBid(uint64 bid, Player* player, CharacterDatabaseTransaction& trans); std::string BuildAuctionMailSubject(BMAHMailAuctionAnswers response) const; std::string BuildAuctionMailBody(); @@ -151,8 +151,8 @@ class TC_GAME_API BlackMarketMgr void AddAuction(BlackMarketEntry* auction); void AddTemplate(BlackMarketTemplate* templ); - void SendAuctionWonMail(BlackMarketEntry* entry, SQLTransaction& trans); - void SendAuctionOutbidMail(BlackMarketEntry* entry, SQLTransaction& trans); // Call before incrementing bid + void SendAuctionWonMail(BlackMarketEntry* entry, CharacterDatabaseTransaction& trans); + void SendAuctionOutbidMail(BlackMarketEntry* entry, CharacterDatabaseTransaction& trans); // Call before incrementing bid private: BlackMarketEntryMap _auctions; diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 6bc0492fde2..bc700216ead 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -34,15 +34,12 @@ add_library(game-interface INTERFACE) target_include_directories(game-interface INTERFACE - ${PUBLIC_INCLUDES} - ${DUKGLUE_HEADERS}) + ${PUBLIC_INCLUDES}) target_link_libraries(game-interface INTERFACE shared - Detour - duktape - dukglue) + Detour) add_library(game ${PRIVATE_SOURCES}) diff --git a/src/server/game/Calendar/CalendarMgr.cpp b/src/server/game/Calendar/CalendarMgr.cpp index cf4898d8099..20f2f5f3fb2 100644 --- a/src/server/game/Calendar/CalendarMgr.cpp +++ b/src/server/game/Calendar/CalendarMgr.cpp @@ -136,11 +136,11 @@ void CalendarMgr::AddEvent(CalendarEvent* calendarEvent, CalendarSendEventType s void CalendarMgr::AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite) { - SQLTransaction dummy; + CharacterDatabaseTransaction dummy; AddInvite(calendarEvent, invite, dummy); } -void CalendarMgr::AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite, SQLTransaction& trans) +void CalendarMgr::AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite, CharacterDatabaseTransaction& trans) { if (!calendarEvent->IsGuildAnnouncement() && calendarEvent->GetOwnerGUID() != invite->GetInviteeGUID()) SendCalendarEventInvite(*invite); @@ -167,8 +167,8 @@ void CalendarMgr::RemoveEvent(uint64 eventId, ObjectGuid remover) SendCalendarEventRemovedAlert(*calendarEvent); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt; + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabasePreparedStatement* stmt; MailDraft mail(calendarEvent->BuildCalendarMailSubject(remover), calendarEvent->BuildCalendarMailBody()); CalendarInviteStore& eventInvites = _invites[eventId]; @@ -213,8 +213,8 @@ void CalendarMgr::RemoveInvite(uint64 inviteId, uint64 eventId, ObjectGuid /*rem if (itr == _invites[eventId].end()) return; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CALENDAR_INVITE); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CALENDAR_INVITE); stmt->setUInt64(0, (*itr)->GetInviteId()); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); @@ -235,7 +235,7 @@ void CalendarMgr::RemoveInvite(uint64 inviteId, uint64 eventId, ObjectGuid /*rem void CalendarMgr::UpdateEvent(CalendarEvent* calendarEvent) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CALENDAR_EVENT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CALENDAR_EVENT); stmt->setUInt64(0, calendarEvent->GetEventId()); stmt->setUInt64(1, calendarEvent->GetOwnerGUID().GetCounter()); stmt->setString(2, calendarEvent->GetTitle()); @@ -250,13 +250,13 @@ void CalendarMgr::UpdateEvent(CalendarEvent* calendarEvent) void CalendarMgr::UpdateInvite(CalendarInvite* invite) { - SQLTransaction dummy; + CharacterDatabaseTransaction dummy; UpdateInvite(invite, dummy); } -void CalendarMgr::UpdateInvite(CalendarInvite* invite, SQLTransaction& trans) +void CalendarMgr::UpdateInvite(CalendarInvite* invite, CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CALENDAR_INVITE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CALENDAR_INVITE); stmt->setUInt64(0, invite->GetInviteId()); stmt->setUInt64(1, invite->GetEventId()); stmt->setUInt64(2, invite->GetInviteeGUID().GetCounter()); diff --git a/src/server/game/Calendar/CalendarMgr.h b/src/server/game/Calendar/CalendarMgr.h index 0610c4f5409..e004f7b422d 100644 --- a/src/server/game/Calendar/CalendarMgr.h +++ b/src/server/game/Calendar/CalendarMgr.h @@ -313,10 +313,10 @@ class TC_GAME_API CalendarMgr void UpdateEvent(CalendarEvent* calendarEvent); void AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite); - void AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite, SQLTransaction& trans); + void AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite, CharacterDatabaseTransaction& trans); void RemoveInvite(uint64 inviteId, uint64 eventId, ObjectGuid remover); void UpdateInvite(CalendarInvite* invite); - void UpdateInvite(CalendarInvite* invite, SQLTransaction& trans); + void UpdateInvite(CalendarInvite* invite, CharacterDatabaseTransaction& trans); void RemoveAllPlayerEventsAndInvites(ObjectGuid guid); void RemovePlayerGuildEventsAndSignups(ObjectGuid guid, ObjectGuid::LowType guildId); diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 944e573ad07..7e9ef2383be 100644 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -73,7 +73,7 @@ Channel::Channel(std::string const& name, uint32 team /*= 0*/) : // If storing custom channels in the db is enabled either load or save the channel if (sWorld->getBoolConfig(CONFIG_PRESERVE_CUSTOM_CHANNELS)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHANNEL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHANNEL); stmt->setString(0, _channelName); stmt->setUInt32(1, _channelTeam); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) // load @@ -147,7 +147,7 @@ void Channel::UpdateChannelInDB() const for (ObjectGuid const& guid : _bannedStore) banlist << guid << ' '; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL); stmt->setBool(0, _announceEnabled); stmt->setBool(1, _ownershipEnabled); stmt->setString(2, _channelPassword); @@ -162,7 +162,7 @@ void Channel::UpdateChannelInDB() const void Channel::UpdateChannelUseageInDB() const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_USAGE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_USAGE); stmt->setString(0, _channelName); stmt->setUInt32(1, _channelTeam); CharacterDatabase.Execute(stmt); @@ -172,7 +172,7 @@ void Channel::CleanOldChannelsInDB() { if (sWorld->getIntConfig(CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION) > 0) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_CHANNELS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_CHANNELS); stmt->setUInt32(0, sWorld->getIntConfig(CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION) * DAY); CharacterDatabase.Execute(stmt); diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 7fea3c7edcf..6878aaf28ae 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -56,7 +56,7 @@ std::vector const& ChatHandler::getCommandTable() // calls getCommandTable() recursively. commandTableCache = sScriptMgr->GetChatCommands(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_COMMANDS); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_COMMANDS); PreparedQueryResult result = WorldDatabase.Query(stmt); if (result) { @@ -346,7 +346,7 @@ bool ChatHandler::ExecuteCommandInTable(std::vector const& table, c guid.ToString().c_str()); uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOG_GM_COMMAND); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOG_GM_COMMAND); stmt->setUInt32(index++, player->GetSession()->GetAccountId()); stmt->setString(index++, player->GetSession()->GetBattlenetAccountName()); stmt->setUInt32(index++, player->GetGUID().GetCounter()); diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h index eee05ae4b84..af314c325f9 100644 --- a/src/server/game/DungeonFinding/LFG.h +++ b/src/server/game/DungeonFinding/LFG.h @@ -135,6 +135,9 @@ TC_GAME_API std::string ConcatenateDungeons(LfgDungeonSet const& dungeons); TC_GAME_API std::string GetRolesString(uint8 roles); TC_GAME_API std::string GetStateString(LfgState state); +// allow implicit enum to int conversions for formatting +inline int32 format_as(LfgUpdateType e) { return e; } +inline uint8 format_as(LfgState e) { return e; } } // namespace lfg #endif diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index f517dcce7b3..4cef438900c 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -102,9 +102,9 @@ void LFGMgr::_SaveToDB(ObjectGuid guid, uint32 db_guid) if (!guid.IsParty()) return; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA); stmt->setUInt32(0, db_guid); trans->Append(stmt); @@ -650,7 +650,7 @@ void LFGMgr::LeaveLfg(ObjectGuid guid, Optional queueId /*= {}*/, bool d { if (!gguid.IsEmpty()) { - if (queueId.is_initialized()) + if (queueId.has_value()) { LFGQueue& queue = GetQueue(gguid, *queueId); queue.RemoveFromQueue(gguid); @@ -671,7 +671,7 @@ void LFGMgr::LeaveLfg(ObjectGuid guid, Optional queueId /*= {}*/, bool d } else { - if (queueId.is_initialized()) + if (queueId.has_value()) { LFGQueue& queue = GetQueue(guid, *queueId); queue.RemoveFromQueue(guid); diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index ba89f2a9cb9..7744b6bb4b5 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -518,6 +518,11 @@ class TC_GAME_API LFGMgr LfgGroupDataContainer GroupsStore; ///< Group data }; +inline int32 format_as(LFGMgrEnum e) { return e; } +inline int32 format_as(LfgProposalState e) { return e; } +inline uint8 format_as(LfgTeleportResult e) { return e; } +inline int32 format_as(LfgJoinResult e) { return e; } +inline int32 format_as(LfgRoleCheckState e) { return e; } } // namespace lfg #define sLFGMgr lfg::LFGMgr::instance() diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index 07ce060b8a6..0195c32f4f8 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -753,7 +753,7 @@ void AreaTrigger::InitSplines(std::vector splinePoints, uint32 tim WorldPackets::AreaTrigger::AreaTriggerReShape reshape; reshape.TriggerGUID = GetGUID(); - reshape.AreaTriggerSpline = boost::in_place(); + reshape.AreaTriggerSpline.emplace(); reshape.AreaTriggerSpline->ElapsedTimeForMovement = GetElapsedTimeForMovement(); reshape.AreaTriggerSpline->TimeToTarget = timeToTarget; for (auto point : _spline->getPoints()) @@ -806,7 +806,7 @@ bool AreaTrigger::SetDestination(Position const& pos, uint32 timeToTarget) void AreaTrigger::InitCircularMovement(AreaTriggerCircularMovementInfo const& cmi, uint32 timeToTarget) { // Circular movement requires either a center position or an attached unit - ASSERT(cmi.Center.is_initialized() || cmi.TargetGUID.is_initialized()); + ASSERT(cmi.Center.has_value() || cmi.TargetGUID.has_value()); // should be sent in object create packets only m_uint32Values[AREATRIGGER_TIME_TO_TARGET] = timeToTarget; @@ -828,19 +828,19 @@ void AreaTrigger::InitCircularMovement(AreaTriggerCircularMovementInfo const& cm bool AreaTrigger::HasCircularMovement() const { - return _circularMovementInfo.is_initialized(); + return _circularMovementInfo.has_value(); } Position const* AreaTrigger::GetCircularMovementCenterPosition() const { - if (_circularMovementInfo.is_initialized()) + if (_circularMovementInfo.has_value()) return nullptr; - if (_circularMovementInfo->TargetGUID.is_initialized()) + if (_circularMovementInfo->TargetGUID.has_value()) if (WorldObject* center = ObjectAccessor::GetWorldObject(*this, *_circularMovementInfo->TargetGUID)) return center; - if (_circularMovementInfo->Center.is_initialized()) + if (_circularMovementInfo->Center.has_value()) return &_circularMovementInfo->Center->Pos; return nullptr; diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index a62b2ecbbc1..2199bedd3cb 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -98,11 +98,11 @@ bool Corpse::Create(ObjectGuid::LowType guidlow, Player* owner) void Corpse::SaveToDB() { // prevent DB data inconsistence problems and duplicates - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); DeleteFromDB(trans); uint16 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CORPSE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CORPSE); stmt->setUInt64(index++, GetOwnerGUID().GetCounter()); // guid stmt->setFloat (index++, GetPositionX()); // posX stmt->setFloat (index++, GetPositionY()); // posY @@ -132,14 +132,14 @@ void Corpse::SaveToDB() CharacterDatabase.CommitTransaction(trans); } -void Corpse::DeleteFromDB(SQLTransaction& trans) +void Corpse::DeleteFromDB(CharacterDatabaseTransaction& trans) { DeleteFromDB(GetOwnerGUID(), trans); } -void Corpse::DeleteFromDB(ObjectGuid const& ownerGuid, SQLTransaction& trans) +void Corpse::DeleteFromDB(ObjectGuid const& ownerGuid, CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE); stmt->setUInt64(0, ownerGuid.GetCounter()); CharacterDatabase.ExecuteOrAppend(trans, stmt); diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h index 41d74d5ce53..ca2ba270254 100644 --- a/src/server/game/Entities/Corpse/Corpse.h +++ b/src/server/game/Entities/Corpse/Corpse.h @@ -62,8 +62,8 @@ class TC_GAME_API Corpse : public WorldObject, public GridObject void SaveToDB(); bool LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields); - void DeleteFromDB(SQLTransaction& trans); - static void DeleteFromDB(ObjectGuid const& ownerGuid, SQLTransaction& trans); + void DeleteFromDB(CharacterDatabaseTransaction& trans); + static void DeleteFromDB(ObjectGuid const& ownerGuid, CharacterDatabaseTransaction& trans); ObjectGuid GetOwnerGUID() const { return GetGuidValue(CORPSE_FIELD_OWNER); } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index cc222a7f088..41d2e28e23c 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1234,9 +1234,9 @@ void Creature::SaveToDB(uint32 mapid, std::vector const& spawnDiffic data.phaseGroup = GetDBPhase() < 0 ? -GetDBPhase() : data.phaseGroup; // update in DB - SQLTransaction trans = WorldDatabase.BeginTransaction(); + WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_CREATURE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_CREATURE); stmt->setUInt64(0, m_spawnId); trans->Append(stmt); @@ -1648,9 +1648,9 @@ void Creature::DeleteFromDB() GetMap()->RemoveCreatureRespawnTime(m_spawnId); sObjectMgr->DeleteCreatureData(m_spawnId); - SQLTransaction trans = WorldDatabase.BeginTransaction(); + WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_CREATURE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_CREATURE); stmt->setUInt64(0, m_spawnId); trans->Append(stmt); @@ -2582,7 +2582,7 @@ void Creature::AllLootRemovedFromCorpse() bool Creature::HasScalableLevels() const { CreatureTemplate const* cinfo = GetCreatureTemplate(); - return !IsPet() && cinfo->levelScaling.is_initialized(); + return !IsPet() && cinfo->levelScaling.has_value(); } float Creature::GetHealthMultiplierForTarget(WorldObject const* target) const @@ -3137,7 +3137,7 @@ void Creature::ReLoad(bool skipDB) PreparedQueryResult result; if (!skipDB) { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE); stmt->setUInt32(0, entry); result = WorldDatabase.Query(stmt); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index f004f7d27e6..6e7e166cd12 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -970,11 +970,11 @@ void GameObject::SaveToDB(uint32 mapid, std::vector const& spawnDiff data.phaseGroup = GetDBPhase() < 0 ? -GetDBPhase() : data.phaseGroup; // Update in DB - SQLTransaction trans = WorldDatabase.BeginTransaction(); + WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction(); uint8 index = 0; - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT); stmt->setUInt64(0, m_spawnId); trans->Append(stmt); @@ -1071,7 +1071,7 @@ void GameObject::DeleteFromDB() GetMap()->RemoveGORespawnTime(m_spawnId); sObjectMgr->DeleteGOData(m_spawnId); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT); stmt->setUInt64(0, m_spawnId); diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp index 9203ef3bd85..3e163fe6818 100644 --- a/src/server/game/Entities/Item/Container/Bag.cpp +++ b/src/server/game/Entities/Item/Container/Bag.cpp @@ -107,7 +107,7 @@ bool Bag::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner return true; } -void Bag::SaveToDB(SQLTransaction& trans) +void Bag::SaveToDB(CharacterDatabaseTransaction& trans) { Item::SaveToDB(trans); } @@ -130,7 +130,7 @@ bool Bag::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fie return true; } -void Bag::DeleteFromDB(SQLTransaction& trans) +void Bag::DeleteFromDB(CharacterDatabaseTransaction& trans) { for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) if (m_bagslot[i]) diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h index 6cf0ed110b7..51c9d41727f 100644 --- a/src/server/game/Entities/Item/Container/Bag.h +++ b/src/server/game/Entities/Item/Container/Bag.h @@ -51,11 +51,11 @@ class TC_GAME_API Bag : public Item // DB operations // overwrite virtual Item::SaveToDB - void SaveToDB(SQLTransaction& trans) override; + void SaveToDB(CharacterDatabaseTransaction& trans) override; // overwrite virtual Item::LoadFromDB bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fields, uint32 entry, Player const* owner = nullptr) override; // overwrite virtual Item::DeleteFromDB - void DeleteFromDB(SQLTransaction& trans) override; + void DeleteFromDB(CharacterDatabaseTransaction& trans) override; void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override; diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 22f861b4143..aad89cc2eec 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -381,7 +381,7 @@ void Item::UpdateDuration(Player* owner, uint32 diff) SetState(ITEM_CHANGED, owner); // save new time in database } -void Item::SaveToDB(SQLTransaction& trans) +void Item::SaveToDB(CharacterDatabaseTransaction& trans) { bool isInTransaction = bool(trans); if (!isInTransaction) @@ -393,7 +393,7 @@ void Item::SaveToDB(SQLTransaction& trans) case ITEM_CHANGED: { uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(uState == ITEM_NEW ? CHAR_REP_ITEM_INSTANCE : CHAR_UPD_ITEM_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(uState == ITEM_NEW ? CHAR_REP_ITEM_INSTANCE : CHAR_UPD_ITEM_INSTANCE); stmt->setUInt32( index, GetEntry()); stmt->setUInt64(++index, GetOwnerGUID().GetCounter()); stmt->setUInt64(++index, GetGuidValue(ITEM_FIELD_CREATOR).GetCounter()); @@ -587,7 +587,7 @@ void Item::SaveToDB(SQLTransaction& trans) } case ITEM_REMOVED: { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -804,7 +804,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie if (need_save) // normal item changed state set not work at loading { uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD); stmt->setUInt32(index++, GetUInt32Value(ITEM_FIELD_DURATION)); stmt->setUInt32(index++, GetUInt32Value(ITEM_FIELD_FLAGS)); stmt->setUInt8(index++, uint8(GetItemRandomEnchantmentId().Type)); @@ -904,14 +904,14 @@ void Item::CheckArtifactRelicSlotUnlock(Player const* owner) } /*static*/ -void Item::DeleteFromDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid) +void Item::DeleteFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType itemGuid) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); stmt->setUInt64(0, itemGuid); trans->Append(stmt); } -void Item::DeleteFromDB(SQLTransaction& trans) +void Item::DeleteFromDB(CharacterDatabaseTransaction& trans) { DeleteFromDB(trans, GetGUID().GetCounter()); @@ -921,14 +921,14 @@ void Item::DeleteFromDB(SQLTransaction& trans) } /*static*/ -void Item::DeleteFromInventoryDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid) +void Item::DeleteFromInventoryDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType itemGuid) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM); stmt->setUInt64(0, itemGuid); trans->Append(stmt); } -void Item::DeleteFromInventoryDB(SQLTransaction& trans) +void Item::DeleteFromInventoryDB(CharacterDatabaseTransaction& trans) { DeleteFromInventoryDB(trans, GetGUID().GetCounter()); } @@ -1580,9 +1580,9 @@ void Item::RemoveFromObjectUpdate() void Item::SaveRefundDataToDB() { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_REFUND_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_REFUND_INSTANCE); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -1596,18 +1596,18 @@ void Item::SaveRefundDataToDB() CharacterDatabase.CommitTransaction(trans); } -void Item::DeleteRefundDataFromDB(SQLTransaction* trans) +void Item::DeleteRefundDataFromDB(CharacterDatabaseTransaction* trans) { if (trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_REFUND_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_REFUND_INSTANCE); stmt->setUInt64(0, GetGUID().GetCounter()); (*trans)->Append(stmt); } } -void Item::SetNotRefundable(Player* owner, bool changestate /*= true*/, SQLTransaction* trans /*= nullptr*/, bool addToCollection /*= true*/) +void Item::SetNotRefundable(Player* owner, bool changestate /*= true*/, CharacterDatabaseTransaction* trans /*= nullptr*/, bool addToCollection /*= true*/) { if (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE)) return; @@ -1686,7 +1686,7 @@ void Item::ClearSoulboundTradeable(Player* currentOwner) currentOwner->GetSession()->GetCollectionMgr()->AddItemAppearance(this); allowedGUIDs.clear(); SetState(ITEM_CHANGED, currentOwner); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_BOP_TRADE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_BOP_TRADE); stmt->setUInt64(0, GetGUID().GetCounter()); CharacterDatabase.Execute(stmt); } @@ -2049,14 +2049,14 @@ void Item::ItemContainerSaveLootToDB() if (loot.isLooted()) // no money and no loot return; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); loot.containerID = GetGUID(); // Save this for when a LootItem is removed // Save money if (loot.gold > 0) { - PreparedStatement* stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); + CharacterDatabasePreparedStatement* stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); stmt_money->setUInt64(0, loot.containerID.GetCounter()); trans->Append(stmt_money); @@ -2069,7 +2069,7 @@ void Item::ItemContainerSaveLootToDB() // Save items if (!loot.isLooted()) { - PreparedStatement* stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS); + CharacterDatabasePreparedStatement* stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS); stmt_items->setUInt64(0, loot.containerID.GetCounter()); trans->Append(stmt_items); @@ -2126,7 +2126,7 @@ bool Item::ItemContainerLoadLootFromDB() loot.containerID = GetGUID(); // First, see if there was any money loot. This gets added directly to the container. - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY); stmt->setUInt64(0, loot.containerID.GetCounter()); PreparedQueryResult money_result = CharacterDatabase.Query(stmt); @@ -2203,7 +2203,7 @@ bool Item::ItemContainerLoadLootFromDB() void Item::ItemContainerDeleteLootItemsFromDB() { // Deletes items associated with an openable item from the DB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS); stmt->setUInt64(0, GetGUID().GetCounter()); CharacterDatabase.Execute(stmt); } @@ -2211,7 +2211,7 @@ void Item::ItemContainerDeleteLootItemsFromDB() void Item::ItemContainerDeleteLootItemFromDB(uint32 itemID) { // Deletes a single item associated with an openable item from the DB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM); stmt->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt32(1, itemID); CharacterDatabase.Execute(stmt); @@ -2220,7 +2220,7 @@ void Item::ItemContainerDeleteLootItemFromDB(uint32 itemID) void Item::ItemContainerDeleteLootMoneyFromDB() { // Deletes the money loot associated with an openable item from the DB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); stmt->setUInt64(0, GetGUID().GetCounter()); CharacterDatabase.Execute(stmt); } diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index e6ec71692da..a31d1f24640 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -153,16 +153,16 @@ class TC_GAME_API Item : public Object bool IsBattlenetAccountBound() const { return (GetTemplate()->GetFlags2() & ITEM_FLAG2_BNET_ACCOUNT_TRADE_OK) != 0; } bool IsBindedNotWith(Player const* player) const; bool IsBoundByEnchant() const; - virtual void SaveToDB(SQLTransaction& trans); + virtual void SaveToDB(CharacterDatabaseTransaction& trans); virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry, Player const* owner = nullptr); void LoadArtifactData(Player* owner, uint64 xp, uint32 artifactAppearanceId, uint32 artifactTier, std::vector& powers); // must be called after LoadFromDB to have gems (relics) initialized void CheckArtifactRelicSlotUnlock(Player const* owner); void AddBonuses(uint32 bonusListID); - static void DeleteFromDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid); - virtual void DeleteFromDB(SQLTransaction& trans); - static void DeleteFromInventoryDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid); + static void DeleteFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType itemGuid); + virtual void DeleteFromDB(CharacterDatabaseTransaction& trans); + static void DeleteFromInventoryDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType itemGuid); // Lootable items and their contents void ItemContainerSaveLootToDB(); @@ -172,9 +172,9 @@ class TC_GAME_API Item : public Object void ItemContainerDeleteLootMoneyFromDB(); void ItemContainerDeleteLootMoneyAndLootItemsFromDB(); - void DeleteFromInventoryDB(SQLTransaction& trans); + void DeleteFromInventoryDB(CharacterDatabaseTransaction& trans); void SaveRefundDataToDB(); - void DeleteRefundDataFromDB(SQLTransaction* trans); + void DeleteRefundDataFromDB(CharacterDatabaseTransaction* trans); Bag* ToBag() { if (IsBag()) return reinterpret_cast(this); else return NULL; } const Bag* ToBag() const { if (IsBag()) return reinterpret_cast(this); else return NULL; } @@ -284,7 +284,7 @@ class TC_GAME_API Item : public Object void SetFixedLevel(uint8 level); // Item Refund system - void SetNotRefundable(Player* owner, bool changestate = true, SQLTransaction* trans = nullptr, bool addToCollection = true); + void SetNotRefundable(Player* owner, bool changestate = true, CharacterDatabaseTransaction* trans = nullptr, bool addToCollection = true); void SetRefundRecipient(ObjectGuid const& guid) { m_refundRecipient = guid; } void SetPaidMoney(uint64 money) { m_paidMoney = money; } void SetPaidExtendedCost(uint32 iece) { m_paidExtendedCost = iece; } diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index bf4a8ab4253..335d00c4337 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -590,7 +590,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation bool isActiveObject() const { return m_isActive; } void setActive(bool isActiveObject); - bool IsVisibilityOverridden() const { return m_visibilityDistanceOverride.is_initialized(); } + bool IsVisibilityOverridden() const { return m_visibilityDistanceOverride.has_value(); } void SetVisibilityDistanceOverride(VisibilityDistanceType type); void SetWorldObject(bool apply); bool IsPermanentWorldObject() const { return m_isWorldObject; } diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 3242d4593d0..1123827e5a3 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -313,7 +313,7 @@ bool Pet::LoadPetData(Player* owner, uint32 petEntry, uint32 petnumber, bool cur if (getPetType() == HUNTER_PET) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_DECLINED_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_DECLINED_NAME); stmt->setUInt64(0, owner->GetGUID().GetCounter()); stmt->setUInt32(1, GetCharmInfo()->GetPetNumber()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -359,7 +359,7 @@ void Pet::SavePetToDB(PetSaveMode mode) uint32 curhealth = GetHealth(); uint32 curmana = GetPower(POWER_MANA); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // save auras before possibly removing them _SaveAuras(trans); @@ -398,7 +398,7 @@ void Pet::SavePetToDB(PetSaveMode mode) trans = CharacterDatabase.BeginTransaction(); // remove current data - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_ID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_ID); stmt->setUInt32(0, m_charmInfo->GetPetNumber()); trans->Append(stmt); @@ -479,9 +479,9 @@ void Pet::SavePetToDB(PetSaveMode mode) void Pet::DeleteFromDB(uint32 guidlow) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_ID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_ID); stmt->setUInt32(0, guidlow); trans->Append(stmt); @@ -1044,7 +1044,7 @@ uint32 Pet::GetCurrentFoodBenefitLevel(uint32 itemlevel) const void Pet::_LoadSpellCooldowns() { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_COOLDOWN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_COOLDOWN); stmt->setUInt32(0, m_charmInfo->GetPetNumber()); PreparedQueryResult cooldownsResult = CharacterDatabase.Query(stmt); @@ -1057,7 +1057,7 @@ void Pet::_LoadSpellCooldowns() void Pet::_LoadSpells() { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL); stmt->setUInt32(0, m_charmInfo->GetPetNumber()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -1073,7 +1073,7 @@ void Pet::_LoadSpells() } } -void Pet::_SaveSpells(SQLTransaction& trans) +void Pet::_SaveSpells(CharacterDatabaseTransaction& trans) { for (PetSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next) { @@ -1083,7 +1083,7 @@ void Pet::_SaveSpells(SQLTransaction& trans) if (itr->second.type == PETSPELL_FAMILY) continue; - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; switch (itr->second.state) { @@ -1131,7 +1131,7 @@ void Pet::_LoadAuras(uint32 timediff) SELECT casterGuid, spell, effectMask, effectIndex, amount, baseAmount FROM pet_aura_effect WHERE guid = ? */ - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_AURA_EFFECT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_AURA_EFFECT); stmt->setUInt32(0, m_charmInfo->GetPetNumber()); ObjectGuid casterGuid, itemGuid; @@ -1226,9 +1226,9 @@ void Pet::_LoadAuras(uint32 timediff) } } -void Pet::_SaveAuras(SQLTransaction& trans) +void Pet::_SaveAuras(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_AURA_EFFECTS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_AURA_EFFECTS); stmt->setUInt32(0, m_charmInfo->GetPetNumber()); trans->Append(stmt); @@ -1293,7 +1293,7 @@ bool Pet::addSpell(uint32 spellId, ActiveStates active /*= ACT_DECIDE*/, PetSpel { TC_LOG_ERROR("entities.pet", "Pet::addSpell: Non-existed in SpellStore spell #%u request, deleting for all pets in `pet_spell`.", spellId); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_PET_SPELL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_PET_SPELL); stmt->setUInt32(0, spellId); diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index b81cf8ac784..c419cc36240 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -123,9 +123,9 @@ class TC_GAME_API Pet : public Guardian void _LoadSpellCooldowns(); void _LoadAuras(uint32 timediff); - void _SaveAuras(SQLTransaction& trans); + void _SaveAuras(CharacterDatabaseTransaction& trans); void _LoadSpells(); - void _SaveSpells(SQLTransaction& trans); + void _SaveSpells(CharacterDatabaseTransaction& trans); bool addSpell(uint32 spellId, ActiveStates active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL); bool learnSpell(uint32 spell_id); diff --git a/src/server/game/Entities/Player/CollectionMgr.cpp b/src/server/game/Entities/Player/CollectionMgr.cpp index 1d7ac4db185..fbaa48d0dd4 100644 --- a/src/server/game/Entities/Player/CollectionMgr.cpp +++ b/src/server/game/Entities/Player/CollectionMgr.cpp @@ -110,9 +110,9 @@ void CollectionMgr::LoadAccountToys(PreparedQueryResult result) } while (result->NextRow()); } -void CollectionMgr::SaveAccountToys(SQLTransaction& trans) +void CollectionMgr::SaveAccountToys(LoginDatabaseTransaction& trans) { - PreparedStatement* stmt = nullptr; + LoginDatabasePreparedStatement* stmt = nullptr; for (auto const& toy : _toys) { stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_ACCOUNT_TOYS); @@ -173,9 +173,9 @@ void CollectionMgr::LoadAccountHeirlooms(PreparedQueryResult result) } while (result->NextRow()); } -void CollectionMgr::SaveAccountHeirlooms(SQLTransaction& trans) +void CollectionMgr::SaveAccountHeirlooms(LoginDatabaseTransaction& trans) { - PreparedStatement* stmt = nullptr; + LoginDatabasePreparedStatement* stmt = nullptr; for (auto const& heirloom : _heirlooms) { stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_ACCOUNT_HEIRLOOMS); @@ -363,11 +363,11 @@ void CollectionMgr::LoadAccountMounts(PreparedQueryResult result) } while (result->NextRow()); } -void CollectionMgr::SaveAccountMounts(SQLTransaction& trans) +void CollectionMgr::SaveAccountMounts(LoginDatabaseTransaction& trans) { for (auto const& mount : _mounts) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_ACCOUNT_MOUNTS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_ACCOUNT_MOUNTS); stmt->setUInt32(0, _owner->GetBattlenetAccountId()); stmt->setUInt32(1, mount.first); stmt->setUInt8(2, mount.second); @@ -518,14 +518,14 @@ void CollectionMgr::LoadAccountItemAppearances(PreparedQueryResult knownAppearan } } -void CollectionMgr::SaveAccountItemAppearances(SQLTransaction& trans) +void CollectionMgr::SaveAccountItemAppearances(LoginDatabaseTransaction& trans) { uint16 blockIndex = 0; boost::to_block_range(*_appearances, DynamicBitsetBlockOutputIterator([this, &blockIndex, trans](uint32 blockValue) { if (blockValue) // this table is only appended/bits are set (never cleared) so don't save empty blocks { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ITEM_APPEARANCES); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ITEM_APPEARANCES); stmt->setUInt32(0, _owner->GetBattlenetAccountId()); stmt->setUInt16(1, blockIndex); stmt->setUInt32(2, blockValue); @@ -535,7 +535,7 @@ void CollectionMgr::SaveAccountItemAppearances(SQLTransaction& trans) ++blockIndex; })); - PreparedStatement* stmt; + LoginDatabasePreparedStatement* stmt; for (auto itr = _favoriteAppearances.begin(); itr != _favoriteAppearances.end();) { switch (itr->second) diff --git a/src/server/game/Entities/Player/CollectionMgr.h b/src/server/game/Entities/Player/CollectionMgr.h index 20d18985792..e201f20e493 100644 --- a/src/server/game/Entities/Player/CollectionMgr.h +++ b/src/server/game/Entities/Player/CollectionMgr.h @@ -77,7 +77,7 @@ class TC_GAME_API CollectionMgr // Account-wide toys void LoadToys(); void LoadAccountToys(PreparedQueryResult result); - void SaveAccountToys(SQLTransaction& trans); + void SaveAccountToys(LoginDatabaseTransaction& trans); void ToySetFavorite(uint32 itemId, bool favorite); bool AddToy(uint32 itemId, bool isFavourite /*= false*/); @@ -91,7 +91,7 @@ class TC_GAME_API CollectionMgr // Account-wide heirlooms void LoadHeirlooms(); void LoadAccountHeirlooms(PreparedQueryResult result); - void SaveAccountHeirlooms(SQLTransaction& trans); + void SaveAccountHeirlooms(LoginDatabaseTransaction& trans); void AddHeirloom(uint32 itemId, uint32 flags, Player* owner = nullptr); void UpgradeHeirloom(uint32 itemId, int32 castItem); void CheckHeirloomUpgrades(Item* item); @@ -104,7 +104,7 @@ class TC_GAME_API CollectionMgr // Account-wide mounts void LoadMounts(); void LoadAccountMounts(PreparedQueryResult result); - void SaveAccountMounts(SQLTransaction& trans); + void SaveAccountMounts(LoginDatabaseTransaction& trans); bool AddMount(uint32 spellId, MountStatusFlags flags, bool factionMount = false, bool learned = false); void MountSetFavorite(uint32 spellId, bool favorite); void SendSingleMountUpdate(std::pair mount); @@ -113,7 +113,7 @@ class TC_GAME_API CollectionMgr // Appearances void LoadItemAppearances(); void LoadAccountItemAppearances(PreparedQueryResult knownAppearances, PreparedQueryResult favoriteAppearances); - void SaveAccountItemAppearances(SQLTransaction& trans); + void SaveAccountItemAppearances(LoginDatabaseTransaction& trans); void AddItemAppearance(Item* item); void AddItemAppearance(uint32 itemId, uint32 appearanceModId = 0); void AddTransmogSet(uint32 transmogSetId); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c45825141bd..c94455ff4fb 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1149,7 +1149,7 @@ void Player::Update(uint32 p_time) if (GetSession()->m_muteTime && GetSession()->m_muteTime < now) { GetSession()->m_muteTime = 0; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); stmt->setInt64(0, 0); // Set the mute time to 0 stmt->setString(1, ""); stmt->setString(2, ""); @@ -1684,7 +1684,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati transferPending.OldMapPosition = GetPosition(); if (Transport* transport = GetTransport()) { - transferPending.Ship = boost::in_place(); + transferPending.Ship.emplace(); transferPending.Ship->ID = transport->GetEntry(); transferPending.Ship->OriginMapID = GetMapId(); } @@ -2673,7 +2673,7 @@ void Player::GiveLevel(uint8 level) if (MailLevelReward const* mailReward = sObjectMgr->GetMailLevelReward(level, getRaceMask())) { /// @todo Poor design of mail system - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); MailDraft(mailReward->mailTemplateId).SendMailTo(trans, this, MailSender(MAIL_CREATURE, uint64(mailReward->senderEntry))); CharacterDatabase.CommitTransaction(trans); } @@ -3000,7 +3000,7 @@ void Player::AddNewMailDeliverTime(time_t deliver_time) void DeleteSpellFromAllPlayers(uint32 spellId) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL_SPELLS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL_SPELLS); stmt->setUInt32(0, spellId); CharacterDatabase.Execute(stmt); } @@ -3740,7 +3740,7 @@ bool Player::ResetTalents(bool noCost) RemoveTalent(talentInfo); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); _SaveTalents(trans); _SaveSpells(trans); CharacterDatabase.CommitTransaction(trans); @@ -3780,7 +3780,7 @@ void Player::ResetPvpTalents() RemovePvpTalent(talentInfo); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); _SaveTalents(trans); _SaveSpells(trans); CharacterDatabase.CommitTransaction(trans); @@ -3937,13 +3937,13 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe charDeleteMethod = CHAR_DELETE_REMOVE; } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (ObjectGuid::LowType guildId = GetGuildIdFromDB(playerguid)) if (Guild* guild = sGuildMgr->GetGuildById(guildId)) guild->DeleteMember(trans, playerguid, false, false, true); // the player was uninvited already on logout so just remove from group - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); stmt->setUInt64(0, guid); PreparedQueryResult resultGroup = CharacterDatabase.Query(stmt); @@ -4337,7 +4337,7 @@ void Player::DeleteOldCharacters(uint32 keepDays) { TC_LOG_INFO("entities.player", "Player::DeleteOldCharacters: Deleting all characters which have been deleted %u days before...", keepDays); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_OLD_CHARS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_OLD_CHARS); stmt->setUInt32(0, uint32(time(nullptr) - time_t(keepDays * DAY))); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -4528,10 +4528,10 @@ void Player::KillPlayer() UpdateObjectVisibility(); } -void Player::OfflineResurrect(ObjectGuid const& guid, SQLTransaction& trans) +void Player::OfflineResurrect(ObjectGuid const& guid, CharacterDatabaseTransaction& trans) { Corpse::DeleteFromDB(guid, trans); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_RESURRECT)); stmt->setUInt64(1, guid.GetCounter()); CharacterDatabase.ExecuteOrAppend(trans, stmt); @@ -6876,9 +6876,9 @@ void Player::_LoadCurrency(PreparedQueryResult result) } while (result->NextRow()); } -void Player::_SaveCurrency(SQLTransaction& trans) +void Player::_SaveCurrency(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; for (PlayerCurrenciesMap::iterator itr = _currencyStorage.begin(); itr != _currencyStorage.end(); ++itr) { CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(itr->first); @@ -7252,7 +7252,7 @@ void Player::SetInGuild(ObjectGuid::LowType guildId) ObjectGuid::LowType Player::GetGuildIdFromDB(ObjectGuid guid) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); stmt->setUInt64(0, guid.GetCounter()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) return result->Fetch()[0].GetUInt64(); @@ -7262,7 +7262,7 @@ ObjectGuid::LowType Player::GetGuildIdFromDB(ObjectGuid guid) uint8 Player::GetRankFromDB(ObjectGuid guid) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); stmt->setUInt64(0, guid.GetCounter()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) return result->Fetch()[1].GetUInt8(); @@ -7273,7 +7273,7 @@ uint8 Player::GetRankFromDB(ObjectGuid guid) uint32 Player::GetZoneIdFromDB(ObjectGuid guid) { ObjectGuid::LowType guidLow = guid.GetCounter(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_ZONE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_ZONE); stmt->setUInt64(0, guidLow); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -7318,7 +7318,7 @@ uint32 Player::GetZoneIdFromDB(ObjectGuid guid) uint32 Player::GetLevelFromDB(ObjectGuid guid) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_LEVEL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_LEVEL); stmt->setUInt64(0, guid.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -10371,7 +10371,7 @@ void Player::SetInventorySlotCount(uint8 slots) { std::size_t fullBatches = unstorableItems.size() / MAX_MAIL_ITEMS; std::size_t remainder = unstorableItems.size() % MAX_MAIL_ITEMS; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); auto sendItemsBatch = [this, &trans, &unstorableItems](std::size_t batchNumber, std::size_t batchSize) { @@ -12213,7 +12213,7 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat for (++itr; itr != allowedLooters.end(); ++itr) ss << ' ' << *itr; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_BOP_TRADE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_BOP_TRADE); stmt->setUInt64(0, item->GetGUID().GetCounter()); stmt->setString(1, ss.str()); CharacterDatabase.Execute(stmt); @@ -12813,7 +12813,7 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); stmt->setUInt64(0, pItem->GetGUID().GetCounter()); @@ -15635,7 +15635,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled { // prepare Quest Tracker datas - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_QUEST_TRACK); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_QUEST_TRACK); stmt->setUInt32(0, quest_id); stmt->setUInt64(1, GetGUID().GetCounter()); stmt->setString(2, GitRevision::GetHash()); @@ -15738,7 +15738,7 @@ void Player::CompleteQuest(uint32 quest_id) if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled { // prepare Quest Tracker data - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_COMPLETE_TIME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_COMPLETE_TIME); stmt->setUInt32(0, quest_id); stmt->setUInt64(1, GetGUID().GetCounter()); @@ -15982,7 +15982,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, if (uint32 mail_template_id = quest->GetRewMailTemplateId()) { /// @todo Poor design of mail system - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (uint32 questMailSender = quest->GetRewMailSenderEntry()) MailDraft(mail_template_id).SendMailTo(trans, this, questMailSender, MAIL_CHECK_MASK_HAS_BODY, quest->GetRewMailDelaySecs()); else @@ -16014,7 +16014,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, // StoreNewItem, mail reward, etc. save data directly to the database // to prevent exploitable data desynchronisation we save the quest status to the database too // (to prevent rewarding this quest another time while rewards were already given out) - SQLTransaction trans = SQLTransaction(nullptr); + CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr); _SaveQuestStatus(trans); SendQuestReward(quest, questGiver ? questGiver->ToCreature() : nullptr, XP, !announce); @@ -18121,7 +18121,7 @@ void Player::_LoadBGData(PreparedQueryResult result) bool Player::LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid guid) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_POSITION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_POSITION); stmt->setUInt64(0, guid.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -18147,7 +18147,7 @@ void Player::SetHomebind(WorldLocation const& loc, uint32 areaId) m_homebindAreaId = areaId; // update sql homebind - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_HOMEBIND); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_HOMEBIND); stmt->setUInt16(0, m_homebindMapId); stmt->setUInt16(1, m_homebindAreaId); stmt->setFloat (2, m_homebindX); @@ -18188,7 +18188,7 @@ bool Player::IsLoading() const return GetSession()->PlayerLoading(); } -bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) +bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& holder) { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 //"SELECT guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, customDisplay1, customDisplay2, customDisplay3, inventorySlots, bankSlots, restState, playerFlags, playerFlagsEx, " @@ -18204,7 +18204,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) //"honor, honorLevel, prestigeLevel, honor_rest_state, honor_rest_bonus " // //"FROM characters WHERE guid = ?", CONNECTION_ASYNC); - PreparedQueryResult result = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM); + PreparedQueryResult result = holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM); if (!result) { std::string name = ""; @@ -18225,7 +18225,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) return false; } - if (holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BANNED)) + if (holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BANNED)) { TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) is banned, can't load.", guid.ToString().c_str()); return false; @@ -18239,7 +18239,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) if (ObjectMgr::CheckPlayerName(m_name, GetSession()->GetSessionDbcLocale()) != CHAR_NAME_SUCCESS || (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(m_name))) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_RENAME)); stmt->setUInt64(1, guid.GetCounter()); CharacterDatabase.Execute(stmt); @@ -18279,8 +18279,8 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); // load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateCriteria) - m_achievementMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS)); - m_questObjectiveCriteriaMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS)); + m_achievementMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS)); + m_questObjectiveCriteriaMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS)); uint64 money = fields[8].GetUInt64(); if (money > MAX_MONEY_AMOUNT) @@ -18348,7 +18348,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) setFactionForRace(getRace()); // load home bind and check in same time class/race pair, it used later for restore broken positions - if (!_LoadHomeBind(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_HOME_BIND))) + if (!_LoadHomeBind(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_HOME_BIND))) return false; InitPrimaryProfessions(); // to max set before any spell loaded @@ -18369,17 +18369,17 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) #define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); } - _LoadGroup(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GROUP)); - _LoadArenaData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARENA_DATA)); + _LoadGroup(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GROUP)); + _LoadArenaData(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARENA_DATA)); - _LoadCurrency(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CURRENCY)); + _LoadCurrency(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CURRENCY)); SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, fields[50].GetUInt32()); SetUInt16Value(PLAYER_FIELD_KILLS, PLAYER_FIELD_KILLS_OFFSET_TODAY_KILLS, fields[51].GetUInt16()); SetUInt16Value(PLAYER_FIELD_KILLS, PLAYER_FIELD_KILLS_OFFSET_YESTERDAY_KILLS, fields[52].GetUInt16()); - _LoadBoundInstances(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES)); - _LoadInstanceTimeRestrictions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES)); - _LoadBGData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BG_DATA)); + _LoadBoundInstances(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES)); + _LoadInstanceTimeRestrictions(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES)); + _LoadBGData(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BG_DATA)); GetSession()->SetPlayer(this); MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); @@ -18730,7 +18730,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) _restMgr->LoadRestBonus(REST_TYPE_XP, PlayerRestState(fields[19].GetUInt8()), fields[31].GetFloat()); // load skills after InitStatsForLevel because it triggering aura apply also - _LoadSkills(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SKILLS)); + _LoadSkills(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SKILLS)); UpdateSkillsForLevel(); //update skills after load, to make sure they are correctly update at player load SetPrimarySpecialization(fields[36].GetUInt32()); @@ -18748,9 +18748,9 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, spec->ID); UpdateDisplayPower(); - _LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS)); - _LoadPvpTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS)); - _LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS)); + _LoadTalents(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS)); + _LoadPvpTalents(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS)); + _LoadSpells(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS)); GetSession()->GetCollectionMgr()->LoadToys(); GetSession()->GetCollectionMgr()->LoadHeirlooms(); GetSession()->GetCollectionMgr()->LoadMounts(); @@ -18758,22 +18758,22 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) LearnSpecializationSpells(); - _LoadGlyphs(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GLYPHS)); - _LoadAuras(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURAS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS), time_diff); + _LoadGlyphs(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GLYPHS)); + _LoadAuras(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURAS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS), time_diff); _LoadGlyphAuras(); // add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura) if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) m_deathState = DEAD; // after spell load, learn rewarded spell if need also - _LoadQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS)); - _LoadQuestStatusObjectives(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES)); - _LoadQuestStatusRewarded(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW)); - _LoadDailyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS)); - _LoadWeeklyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS)); - _LoadSeasonalQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS)); - _LoadMonthlyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS)); - _LoadRandomBGStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG)); + _LoadQuestStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS)); + _LoadQuestStatusObjectives(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES)); + _LoadQuestStatusRewarded(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW)); + _LoadDailyQuestStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS)); + _LoadWeeklyQuestStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS)); + _LoadSeasonalQuestStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS)); + _LoadMonthlyQuestStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS)); + _LoadRandomBGStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG)); // after spell and quest load InitTalentForLevel(); @@ -18783,22 +18783,22 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) ResetPvpTalents(); // must be before inventory (some items required reputation check) - m_reputationMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_REPUTATION)); + m_reputationMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_REPUTATION)); - _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS), time_diff); + _LoadInventory(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS), time_diff); if (IsVoidStorageUnlocked()) - _LoadVoidStorage(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE)); + _LoadVoidStorage(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE)); // update items with duration and realtime UpdateItemDuration(time_diff, true); - _LoadActions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACTIONS)); + _LoadActions(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACTIONS)); // unread mails and next delivery time, actual mails not loaded - _LoadMailInit(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE)); + _LoadMailInit(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE)); - m_social = sSocialMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST), GetGUID()); + m_social = sSocialMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST), GetGUID()); // check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES // note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded @@ -18811,7 +18811,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // has to be called after last Relocate() in Player::LoadFromDB SetFallInformation(0, GetPositionZ()); - GetSpellHistory()->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_CHARGES)); + GetSpellHistory()->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_CHARGES)); // Spell code allow apply any auras to dead character in load time in aura/spell/item loading // Do now before stats re-calculation cleanup for ghost state unexpected auras @@ -18916,16 +18916,16 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) if (m_grantableLevels > 0) SetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_RAF_GRANTABLE_LEVEL, 0x01); - _LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES)); + _LoadDeclinedNames(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES)); - _LoadEquipmentSets(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS)); - _LoadTransmogOutfits(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS)); + _LoadEquipmentSets(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS)); + _LoadTransmogOutfits(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS)); - _LoadCUFProfiles(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES)); + _LoadCUFProfiles(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES)); - GetArchaeologyMgr().LoadArchaeologyDigSites(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARCHAEOLOGY_DIGSITES)); - GetArchaeologyMgr().LoadArchaeologyBranchs(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARCHAEOLOGY_BRANCHS)); - GetArchaeologyMgr().LoadArchaeologyHistory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARCHAEOLOGY_HISTORY)); + GetArchaeologyMgr().LoadArchaeologyDigSites(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARCHAEOLOGY_DIGSITES)); + GetArchaeologyMgr().LoadArchaeologyBranchs(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARCHAEOLOGY_BRANCHS)); + GetArchaeologyMgr().LoadArchaeologyHistory(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARCHAEOLOGY_HISTORY)); std::unique_ptr wodGarrison = Trinity::make_unique(this); if (wodGarrison->LoadFromDB()) @@ -19263,7 +19263,7 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti std::map bagMap; // fast guid lookup for bags std::map invalidBagMap; // fast guid lookup for bags std::list problematicItems; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Prevent items from being added to the queue while loading m_itemUpdateQueueBlocked = true; @@ -19462,7 +19462,7 @@ void Player::_LoadVoidStorage(PreparedQueryResult result) while (result->NextRow()); } -Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields) +Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields) { Item* item = nullptr; ObjectGuid::LowType itemGuid = fields[0].GetUInt64(); @@ -19473,7 +19473,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F item = NewItemOrBag(proto); if (item->LoadFromDB(itemGuid, GetGUID(), fields, itemEntry, this)) { - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; // Do not allow to have item limited to another map/zone in alive state if (IsAlive() && item->IsLimitedToAnotherMapOrZone(GetMapId(), zoneId)) @@ -19593,7 +19593,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F void Player::_LoadMailedItems(Mail* mail) { // data needs to be at first place for Item::LoadFromDB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS); stmt->setUInt32(0, mail->messageID); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -19637,7 +19637,7 @@ void Player::_LoadMailedItems(Mail* mail) item->FSetState(ITEM_REMOVED); - SQLTransaction temp = SQLTransaction(nullptr); + CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr); item->SaveToDB(temp); // it also deletes item object ! continue; } @@ -19664,7 +19664,7 @@ void Player::_LoadMail() { m_mail.clear(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL); stmt->setUInt64(0, GetGUID().GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -20240,7 +20240,7 @@ void Player::_LoadBoundInstances(PreparedQueryResult result) if (deleteInstance) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID); stmt->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt32(1, instanceId); @@ -20324,7 +20324,7 @@ void Player::UnbindInstance(BoundInstancesMap::mapped_type::iterator& itr, Bound { if (!unload) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID); stmt->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt32(1, itr->second.save->GetInstanceId()); @@ -20359,7 +20359,7 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, B // update the save when the group kills a boss if (permanent != bind.perm || save != bind.save || extendState != bind.extendState) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INSTANCE); stmt->setUInt32(0, save->GetInstanceId()); stmt->setBool(1, permanent); @@ -20372,7 +20372,7 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, B } else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_INSTANCE); stmt->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt32(1, save->GetInstanceId()); @@ -20647,7 +20647,7 @@ bool Player::_LoadHomeBind(PreparedQueryResult result) ok = true; else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND); stmt->setUInt64(0, GetGUID().GetCounter()); CharacterDatabase.Execute(stmt); } @@ -20661,7 +20661,7 @@ bool Player::_LoadHomeBind(PreparedQueryResult result) m_homebindY = info->positionY; m_homebindZ = info->positionZ; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND); stmt->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt16(1, m_homebindMapId); stmt->setUInt16(2, m_homebindAreaId); @@ -20702,8 +20702,8 @@ void Player::SaveToDB(bool create /*=false*/) if (!create) sScriptMgr->OnPlayerSave(this); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = nullptr; + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabasePreparedStatement* stmt = nullptr; uint8 index = 0; stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_FISHINGSTEPS); @@ -21054,30 +21054,30 @@ void Player::SaveToDB(bool create /*=false*/) CharacterDatabase.CommitTransaction(trans); // TODO: Move this out - trans = LoginDatabase.BeginTransaction(); - GetSession()->GetCollectionMgr()->SaveAccountToys(trans); - GetSession()->GetBattlePetMgr()->SaveToDB(trans); - GetSession()->GetCollectionMgr()->SaveAccountHeirlooms(trans); - GetSession()->GetCollectionMgr()->SaveAccountMounts(trans); - GetSession()->GetCollectionMgr()->SaveAccountItemAppearances(trans); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_LAST_PLAYER_CHARACTERS); - stmt->setUInt32(0, GetSession()->GetAccountId()); - stmt->setUInt8(1, realm.Id.Region); - stmt->setUInt8(2, realm.Id.Site); - trans->Append(stmt); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_LAST_PLAYER_CHARACTERS); - stmt->setUInt32(0, GetSession()->GetAccountId()); - stmt->setUInt8(1, realm.Id.Region); - stmt->setUInt8(2, realm.Id.Site); - stmt->setUInt32(3, realm.Id.Realm); - stmt->setString(4, GetName()); - stmt->setUInt64(5, GetGUID().GetCounter()); - stmt->setUInt32(6, time(nullptr)); - trans->Append(stmt); - - LoginDatabase.CommitTransaction(trans); + LoginDatabaseTransaction trans2 = LoginDatabase.BeginTransaction(); + GetSession()->GetCollectionMgr()->SaveAccountToys(trans2); + GetSession()->GetBattlePetMgr()->SaveToDB(trans2); + GetSession()->GetCollectionMgr()->SaveAccountHeirlooms(trans2); + GetSession()->GetCollectionMgr()->SaveAccountMounts(trans2); + GetSession()->GetCollectionMgr()->SaveAccountItemAppearances(trans2); + + LoginDatabasePreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_LAST_PLAYER_CHARACTERS); + stmt2->setUInt32(0, GetSession()->GetAccountId()); + stmt2->setUInt8(1, realm.Id.Region); + stmt2->setUInt8(2, realm.Id.Site); + trans2->Append(stmt2); + + stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_LAST_PLAYER_CHARACTERS); + stmt2->setUInt32(0, GetSession()->GetAccountId()); + stmt2->setUInt8(1, realm.Id.Region); + stmt2->setUInt8(2, realm.Id.Site); + stmt2->setUInt32(3, realm.Id.Realm); + stmt2->setString(4, GetName()); + stmt2->setUInt64(5, GetGUID().GetCounter()); + stmt2->setUInt32(6, time(nullptr)); + trans2->Append(stmt2); + + LoginDatabase.CommitTransaction(trans2); // save pet (hunter pet level and experience and all type pets health/mana). if (Pet* pet = GetPet()) @@ -21085,24 +21085,24 @@ void Player::SaveToDB(bool create /*=false*/) } // fast save function for item/money cheating preventing - save only inventory and money state -void Player::SaveInventoryAndGoldToDB(SQLTransaction& trans) +void Player::SaveInventoryAndGoldToDB(CharacterDatabaseTransaction& trans) { _SaveInventory(trans); _SaveCurrency(trans); SaveGoldToDB(trans); } -void Player::SaveGoldToDB(SQLTransaction& trans) const +void Player::SaveGoldToDB(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_MONEY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_MONEY); stmt->setUInt64(0, GetMoney()); stmt->setUInt64(1, GetGUID().GetCounter()); trans->Append(stmt); } -void Player::_SaveActions(SQLTransaction& trans) +void Player::_SaveActions(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; for (ActionButtonList::iterator itr = m_actionButtons.begin(); itr != m_actionButtons.end();) { @@ -21148,9 +21148,9 @@ void Player::_SaveActions(SQLTransaction& trans) } } -void Player::_SaveAuras(SQLTransaction& trans) +void Player::_SaveAuras(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_EFFECT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_EFFECT); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -21203,9 +21203,9 @@ void Player::_SaveAuras(SQLTransaction& trans) } } -void Player::_SaveInventory(SQLTransaction& trans) +void Player::_SaveInventory(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; // force items in buyback slots to new state // and remove those that aren't already for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; ++i) @@ -21328,9 +21328,9 @@ void Player::_SaveInventory(SQLTransaction& trans) m_itemUpdateQueue.clear(); } -void Player::_SaveVoidStorage(SQLTransaction& trans) +void Player::_SaveVoidStorage(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = nullptr; + CharacterDatabasePreparedStatement* stmt = nullptr; for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) { @@ -21373,9 +21373,9 @@ void Player::_SaveVoidStorage(SQLTransaction& trans) } } -void Player::_SaveCUFProfiles(SQLTransaction& trans) +void Player::_SaveCUFProfiles(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) { if (!_CUFProfiles[i]) // unused profile @@ -21409,12 +21409,12 @@ void Player::_SaveCUFProfiles(SQLTransaction& trans) } } -void Player::_SaveMail(SQLTransaction& trans) +void Player::_SaveMail(CharacterDatabaseTransaction& trans) { if (!m_mailsLoaded) return; - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) { @@ -21482,7 +21482,7 @@ void Player::_SaveMail(SQLTransaction& trans) m_mailsUpdated = false; } -void Player::_SaveQuestStatus(SQLTransaction& trans) +void Player::_SaveQuestStatus(CharacterDatabaseTransaction& trans) { bool isTransaction = bool(trans); if (!isTransaction) @@ -21490,7 +21490,7 @@ void Player::_SaveQuestStatus(SQLTransaction& trans) QuestStatusSaveMap::iterator saveItr; QuestStatusMap::iterator statusItr; - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; bool keepAbandoned = !(sWorld->GetCleaningFlags() & CharacterDatabaseCleaner::CLEANING_FLAG_QUESTSTATUS); @@ -21566,7 +21566,7 @@ void Player::_SaveQuestStatus(SQLTransaction& trans) CharacterDatabase.CommitTransaction(trans); } -void Player::_SaveDailyQuestStatus(SQLTransaction& trans) +void Player::_SaveDailyQuestStatus(CharacterDatabaseTransaction& trans) { if (!m_DailyQuestChanged) return; @@ -21576,7 +21576,7 @@ void Player::_SaveDailyQuestStatus(SQLTransaction& trans) // save last daily quest time for all quests: we need only mostly reset time for reset check anyway // we don't need transactions here. - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -21603,13 +21603,13 @@ void Player::_SaveDailyQuestStatus(SQLTransaction& trans) } } -void Player::_SaveWeeklyQuestStatus(SQLTransaction& trans) +void Player::_SaveWeeklyQuestStatus(CharacterDatabaseTransaction& trans) { if (!m_WeeklyQuestChanged || m_weeklyquests.empty()) return; // we don't need transactions here. - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -21626,13 +21626,13 @@ void Player::_SaveWeeklyQuestStatus(SQLTransaction& trans) m_WeeklyQuestChanged = false; } -void Player::_SaveSeasonalQuestStatus(SQLTransaction& trans) +void Player::_SaveSeasonalQuestStatus(CharacterDatabaseTransaction& trans) { if (!m_SeasonalQuestChanged || m_seasonalquests.empty()) return; // we don't need transactions here. - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_SEASONAL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_SEASONAL); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -21655,13 +21655,13 @@ void Player::_SaveSeasonalQuestStatus(SQLTransaction& trans) m_SeasonalQuestChanged = false; } -void Player::_SaveMonthlyQuestStatus(SQLTransaction& trans) +void Player::_SaveMonthlyQuestStatus(CharacterDatabaseTransaction& trans) { if (!m_MonthlyQuestChanged || m_monthlyquests.empty()) return; // we don't need transactions here. - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -21678,9 +21678,9 @@ void Player::_SaveMonthlyQuestStatus(SQLTransaction& trans) m_MonthlyQuestChanged = false; } -void Player::_SaveSkills(SQLTransaction& trans) +void Player::_SaveSkills(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; // we don't need transactions here. for (SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end();) { @@ -21734,9 +21734,9 @@ void Player::_SaveSkills(SQLTransaction& trans) } } -void Player::_SaveSpells(SQLTransaction& trans) +void Player::_SaveSpells(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end();) { @@ -21774,13 +21774,13 @@ void Player::_SaveSpells(SQLTransaction& trans) // save player stats -- only for external usage // real stats will be recalculated on player login -void Player::_SaveStats(SQLTransaction& trans) const +void Player::_SaveStats(CharacterDatabaseTransaction& trans) const { // check if stat saving is enabled and if char level is high enough if (!sWorld->getIntConfig(CONFIG_MIN_LEVEL_STAT_SAVE) || getLevel() < sWorld->getIntConfig(CONFIG_MIN_LEVEL_STAT_SAVE)) return; - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_STATS); stmt->setUInt64(0, GetGUID().GetCounter()); @@ -21877,9 +21877,9 @@ bool Player::CanSpeak() const /*** LOW LEVEL FUNCTIONS:Notifiers ***/ /*********************************************************/ -void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, SQLTransaction& trans) +void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_POSITION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_POSITION); stmt->setFloat(0, loc.GetPositionX()); stmt->setFloat(1, loc.GetPositionY()); @@ -22809,7 +22809,7 @@ void Player::SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) const void Player::RemovePetitionsAndSigns(ObjectGuid guid) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIG_BY_GUID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIG_BY_GUID); stmt->setUInt64(0, guid.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -22834,7 +22834,7 @@ void Player::RemovePetitionsAndSigns(ObjectGuid guid) CharacterDatabase.Execute(stmt); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_BY_OWNER); stmt->setUInt64(0, guid.GetCounter()); @@ -25565,7 +25565,7 @@ void Player::AutoUnequip(Item* item) else { MoveItemFromInventory(INVENTORY_SLOT_BAG_0, item->GetSlot(), true); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); // deletes item from character's inventory item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone @@ -25897,7 +25897,7 @@ void Player::SetPersonnalXpRate(float personnalXPRate) { _PersonnalXpRate = personnalXPRate; - PreparedStatement* statement = CharacterDatabase.GetPreparedStatement(CHAR_UPD_XP_RATE); + CharacterDatabasePreparedStatement* statement = CharacterDatabase.GetPreparedStatement(CHAR_UPD_XP_RATE); statement->setFloat(0, personnalXPRate); statement->setUInt64(1, GetGUID().GetCounter()); CharacterDatabase.Execute(statement); @@ -26759,7 +26759,7 @@ void Player::_LoadSkills(PreparedQueryResult result) TC_LOG_ERROR("entities.player", "Player::_LoadSkills: Player '%s' (%s) has skill %u with value 0, deleted.", GetName().c_str(), GetGUID().ToString().c_str(), skill); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL); stmt->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt16(1, skill); @@ -27529,12 +27529,12 @@ void Player::SetEquipmentSet(EquipmentSetInfo::EquipmentSetData const& newEqSet) eqSlot.State = eqSlot.State == EQUIPMENT_SET_NEW ? EQUIPMENT_SET_NEW : EQUIPMENT_SET_CHANGED; } -void Player::_SaveEquipmentSets(SQLTransaction& trans) +void Player::_SaveEquipmentSets(CharacterDatabaseTransaction& trans) { for (EquipmentSetContainer::iterator itr = _equipmentSets.begin(); itr != _equipmentSets.end();) { EquipmentSetInfo& eqSet = itr->second; - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; uint8 j = 0; switch (eqSet.State) { @@ -27622,9 +27622,9 @@ void Player::_SaveEquipmentSets(SQLTransaction& trans) } } -void Player::_SaveArenaData(SQLTransaction& trans) +void Player::_SaveArenaData(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_ARENA_DATA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_ARENA_DATA); stmt->setUInt32(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -27649,9 +27649,9 @@ void Player::_SaveArenaData(SQLTransaction& trans) } } -void Player::_SaveBGData(SQLTransaction& trans) +void Player::_SaveBGData(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); /* guid, bgInstanceID, bgTeam, x, y, z, o, map, taxi[0], taxi[1], mountSpell */ @@ -27692,7 +27692,7 @@ void Player::RemoveAtLoginFlag(AtLoginFlags flags, bool persist /*= false*/) if (persist) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_REM_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_REM_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(flags)); stmt->setUInt64(1, GetGUID().GetCounter()); @@ -27742,9 +27742,9 @@ void Player::_LoadGlyphs(PreparedQueryResult result) } while (result->NextRow()); } -void Player::_SaveGlyphs(SQLTransaction& trans) const +void Player::_SaveGlyphs(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -27788,9 +27788,9 @@ void Player::_LoadPvpTalents(PreparedQueryResult result) } } -void Player::_SaveTalents(SQLTransaction& trans) +void Player::_SaveTalents(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT); stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); @@ -27848,7 +27848,7 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec) if (IsNonMeleeSpellCast(false)) InterruptNonMeleeSpells(false); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); _SaveActions(trans); CharacterDatabase.CommitTransaction(trans); @@ -28005,7 +28005,7 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec) InitTalentForLevel(); { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC); stmt->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt8(1, GetActiveTalentGroup()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) @@ -28206,7 +28206,7 @@ void Player::SendItemRefundResult(Item* item, ItemExtendedCostEntry const* iece, itemPurchaseRefundResult.Result = error; if (!error) { - itemPurchaseRefundResult.Contents = boost::in_place(); + itemPurchaseRefundResult.Contents.emplace(); itemPurchaseRefundResult.Contents->Money = item->GetPaidMoney(); for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) // item cost data { @@ -28285,7 +28285,7 @@ void Player::RefundItem(Item* item) uint64 moneyRefund = item->GetPaidMoney(); // item-> will be invalidated in DestroyItem // Save all relevant data to DB to prevent desynchronisation exploits - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Delete any references to the refund data item->SetNotRefundable(this, true, &trans, false); @@ -28334,7 +28334,7 @@ void Player::SendItemRetrievalMail(uint32 itemEntry, uint32 count) { MailSender sender(MAIL_CREATURE, UI64LIT(34337) /* The Postmaster */); MailDraft draft("Recovered Item", "We recovered a lost item in the twisting nether and noted that it was yours.$B$BPlease find said object enclosed."); // This is the text used in Cataclysm, it probably wasn't changed. - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (Item* item = Item::CreateItem(itemEntry, count, nullptr)) { @@ -28351,7 +28351,7 @@ void Player::SetRandomWinner(bool isWinner) m_IsBGRandomWinner = isWinner; if (m_IsBGRandomWinner) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BATTLEGROUND_RANDOM); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BATTLEGROUND_RANDOM); stmt->setUInt64(0, GetGUID().GetCounter()); @@ -28546,12 +28546,12 @@ void Player::_LoadInstanceTimeRestrictions(PreparedQueryResult result) } while (result->NextRow()); } -void Player::_SaveInstanceTimeRestrictions(SQLTransaction& trans) +void Player::_SaveInstanceTimeRestrictions(CharacterDatabaseTransaction& trans) { if (_instanceResetTimes.empty()) return; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES); stmt->setUInt32(0, GetSession()->GetAccountId()); trans->Append(stmt); @@ -28741,7 +28741,7 @@ void Player::SendGarrisonInfo() const { garrisonInfo.Plots.push_back(&plot->PacketInfo); if (plot->BuildingInfo.PacketInfo) - garrisonInfo.Buildings.push_back(plot->BuildingInfo.PacketInfo.get_ptr()); + garrisonInfo.Buildings.push_back(std::to_address(plot->BuildingInfo.PacketInfo)); } } @@ -28881,7 +28881,7 @@ void Player::SendPlayerChoice(ObjectGuid sender, int32 choiceId) if (playerChoiceResponseTemplate.Reward) { - playerChoiceResponse.Reward = boost::in_place(); + playerChoiceResponse.Reward.emplace(); playerChoiceResponse.Reward->TitleID = playerChoiceResponseTemplate.Reward->TitleId; playerChoiceResponse.Reward->PackageID = playerChoiceResponseTemplate.Reward->PackageId; playerChoiceResponse.Reward->SkillLineID = playerChoiceResponseTemplate.Reward->SkillLineId; @@ -28898,7 +28898,7 @@ void Player::SendPlayerChoice(ObjectGuid sender, int32 choiceId) rewardEntry.Quantity = item.Quantity; if (!item.BonusListIDs.empty()) { - rewardEntry.Item.ItemBonus = boost::in_place(); + rewardEntry.Item.ItemBonus.emplace(); rewardEntry.Item.ItemBonus->BonusListIDs = item.BonusListIDs; } } @@ -29687,14 +29687,14 @@ void Player::UpdateShop(uint32 diff) m_shopTimer = SHOP_UPDATE_INTERVAL; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SHOP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SHOP); stmt->setUInt64(0, GetGUID().GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) return; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); do { @@ -29792,7 +29792,7 @@ void Player::UpdateShop(uint32 diff) if (delivered) { - PreparedStatement* deliveredStmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_SHOP_DELIVERED); + CharacterDatabasePreparedStatement* deliveredStmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_SHOP_DELIVERED); deliveredStmt->setUInt32(0, id); trans->Append(deliveredStmt); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index a8110d11810..cb2741f822b 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1551,7 +1551,7 @@ class TC_GAME_API Player : public Unit, public GridObject /*** LOAD SYSTEM ***/ /*********************************************************/ - bool LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder); + bool LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& holder); bool IsLoading() const override; static uint32 GetUInt32ValueFromArray(Tokenizer const& data, uint16 index); @@ -1570,11 +1570,11 @@ class TC_GAME_API Player : public Unit, public GridObject /*********************************************************/ void SaveToDB(bool create = false); - void SaveInventoryAndGoldToDB(SQLTransaction& trans); // fast save function for item/money cheating preventing - void SaveGoldToDB(SQLTransaction& trans) const; + void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction& trans); // fast save function for item/money cheating preventing + void SaveGoldToDB(CharacterDatabaseTransaction& trans) const; static void SetUInt32ValueInArray(Tokenizer& data, uint16 index, uint32 value); - static void SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, SQLTransaction& trans); + static void SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction& trans); static void DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars = true, bool deleteFinally = false); static void DeleteOldCharacters(); @@ -1968,7 +1968,7 @@ class TC_GAME_API Player : public Unit, public GridObject void SpawnCorpseBones(bool triggerSave = true); Corpse* CreateCorpse(); void KillPlayer(); - static void OfflineResurrect(ObjectGuid const& guid, SQLTransaction& trans); + static void OfflineResurrect(ObjectGuid const& guid, CharacterDatabaseTransaction& trans); bool HasCorpse() const { return _corpseLocation.GetMapId() != MAPID_INVALID; } WorldLocation GetCorpseLocation() const { return _corpseLocation; } void InitializeSelfResurrectionSpells(); @@ -2615,27 +2615,27 @@ class TC_GAME_API Player : public Unit, public GridObject /*** SAVE SYSTEM ***/ /*********************************************************/ - void _SaveActions(SQLTransaction& trans); - void _SaveAuras(SQLTransaction& trans); - void _SaveInventory(SQLTransaction& trans); - void _SaveVoidStorage(SQLTransaction& trans); - void _SaveMail(SQLTransaction& trans); - void _SaveQuestStatus(SQLTransaction& trans); - void _SaveDailyQuestStatus(SQLTransaction& trans); - void _SaveWeeklyQuestStatus(SQLTransaction& trans); - void _SaveMonthlyQuestStatus(SQLTransaction& trans); - void _SaveSeasonalQuestStatus(SQLTransaction& trans); - void _SaveSkills(SQLTransaction& trans); - void _SaveSpells(SQLTransaction& trans); - void _SaveEquipmentSets(SQLTransaction& trans); - void _SaveArenaData(SQLTransaction& trans); - void _SaveBGData(SQLTransaction& trans); - void _SaveGlyphs(SQLTransaction& trans) const; - void _SaveTalents(SQLTransaction& trans); - void _SaveStats(SQLTransaction& trans) const; - void _SaveInstanceTimeRestrictions(SQLTransaction& trans); - void _SaveCurrency(SQLTransaction& trans); - void _SaveCUFProfiles(SQLTransaction& trans); + void _SaveActions(CharacterDatabaseTransaction& trans); + void _SaveAuras(CharacterDatabaseTransaction& trans); + void _SaveInventory(CharacterDatabaseTransaction& trans); + void _SaveVoidStorage(CharacterDatabaseTransaction& trans); + void _SaveMail(CharacterDatabaseTransaction& trans); + void _SaveQuestStatus(CharacterDatabaseTransaction& trans); + void _SaveDailyQuestStatus(CharacterDatabaseTransaction& trans); + void _SaveWeeklyQuestStatus(CharacterDatabaseTransaction& trans); + void _SaveMonthlyQuestStatus(CharacterDatabaseTransaction& trans); + void _SaveSeasonalQuestStatus(CharacterDatabaseTransaction& trans); + void _SaveSkills(CharacterDatabaseTransaction& trans); + void _SaveSpells(CharacterDatabaseTransaction& trans); + void _SaveEquipmentSets(CharacterDatabaseTransaction& trans); + void _SaveArenaData(CharacterDatabaseTransaction& trans); + void _SaveBGData(CharacterDatabaseTransaction& trans); + void _SaveGlyphs(CharacterDatabaseTransaction& trans) const; + void _SaveTalents(CharacterDatabaseTransaction& trans); + void _SaveStats(CharacterDatabaseTransaction& trans) const; + void _SaveInstanceTimeRestrictions(CharacterDatabaseTransaction& trans); + void _SaveCurrency(CharacterDatabaseTransaction& trans); + void _SaveCUFProfiles(CharacterDatabaseTransaction& trans); /*********************************************************/ /*** ENVIRONMENTAL SYSTEM ***/ @@ -2803,7 +2803,7 @@ class TC_GAME_API Player : public Unit, public GridObject InventoryResult CanStoreItem_InBag(uint8 bag, ItemPosCountVec& dest, ItemTemplate const* pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const; InventoryResult CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 slot_end, ItemPosCountVec& dest, ItemTemplate const* pProto, uint32& count, bool merge, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const; Item* _StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool update); - Item* _LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields); + Item* _LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields); CinematicMgr* _cinematicMgr; diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index d0370e08eae..b36fba7dc4a 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -46,7 +46,7 @@ bool PlayerSocial::AddToSocialList(ObjectGuid const& friendGuid, SocialFlag flag { itr->second.Flags |= flag; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_SOCIAL_FLAGS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_SOCIAL_FLAGS); stmt->setUInt8(0, itr->second.Flags); stmt->setUInt64(1, GetPlayerGUID().GetCounter()); @@ -58,7 +58,7 @@ bool PlayerSocial::AddToSocialList(ObjectGuid const& friendGuid, SocialFlag flag { _playerSocialMap[friendGuid].Flags |= flag; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_SOCIAL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_SOCIAL); stmt->setUInt64(0, GetPlayerGUID().GetCounter()); stmt->setUInt64(1, friendGuid.GetCounter()); @@ -80,7 +80,7 @@ void PlayerSocial::RemoveFromSocialList(ObjectGuid const& friendGuid, SocialFlag if (!itr->second.Flags) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SOCIAL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SOCIAL); stmt->setUInt64(0, GetPlayerGUID().GetCounter()); stmt->setUInt64(1, friendGuid.GetCounter()); @@ -91,7 +91,7 @@ void PlayerSocial::RemoveFromSocialList(ObjectGuid const& friendGuid, SocialFlag } else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_SOCIAL_FLAGS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_SOCIAL_FLAGS); stmt->setUInt8(0, itr->second.Flags); stmt->setUInt64(1, GetPlayerGUID().GetCounter()); @@ -110,7 +110,7 @@ void PlayerSocial::SetFriendNote(ObjectGuid const& friendGuid, std::string const itr->second.Note = note; utf8truncate(itr->second.Note, 48); // DB and client size limitation - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_SOCIAL_NOTE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_SOCIAL_NOTE); stmt->setString(0, itr->second.Note); stmt->setUInt64(1, GetPlayerGUID().GetCounter()); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 788f6cb1666..a81a5d17f24 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -5464,7 +5464,7 @@ void Unit::SendAttackStateUpdate(CalcDamageInfo* damageInfo) int32 overkill = damageInfo->damage - damageInfo->target->GetHealth(); packet.OverDamage = (overkill < 0 ? -1 : overkill); - packet.SubDmg = boost::in_place(); + packet.SubDmg.emplace(); packet.SubDmg->SchoolMask = damageInfo->damageSchoolMask; // School of sub damage packet.SubDmg->FDamage = damageInfo->damage; // sub damage packet.SubDmg->Damage = damageInfo->damage; // Sub Damage diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 87a04cced8c..a45eac94c55 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -202,8 +202,8 @@ void GameEventMgr::StopEvent(uint16 event_id, bool overwrite) for (itr = data.conditions.begin(); itr != data.conditions.end(); ++itr) itr->second.done = 0; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GAME_EVENT_CONDITION_SAVE); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GAME_EVENT_CONDITION_SAVE); stmt->setUInt8(0, uint8(event_id)); trans->Append(stmt); @@ -1608,9 +1608,9 @@ void GameEventMgr::HandleQuestComplete(uint32 quest_id) if (citr->second.done > citr->second.reqNum) citr->second.done = citr->second.reqNum; // save the change to db - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GAME_EVENT_CONDITION_SAVE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GAME_EVENT_CONDITION_SAVE); stmt->setUInt8(0, uint8(event_id)); stmt->setUInt32(1, condition); trans->Append(stmt); @@ -1653,9 +1653,9 @@ bool GameEventMgr::CheckOneGameEventConditions(uint16 event_id) void GameEventMgr::SaveWorldEventStateToDB(uint16 event_id) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GAME_EVENT_SAVE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GAME_EVENT_SAVE); stmt->setUInt8(0, uint8(event_id)); trans->Append(stmt); diff --git a/src/server/game/Garrison/ClassHall/ClassHall.cpp b/src/server/game/Garrison/ClassHall/ClassHall.cpp index b0523aaf657..3b8219c1448 100644 --- a/src/server/game/Garrison/ClassHall/ClassHall.cpp +++ b/src/server/game/Garrison/ClassHall/ClassHall.cpp @@ -38,7 +38,7 @@ bool ClassHall::LoadFromDB() return true; } -void ClassHall::SaveToDB(SQLTransaction& trans) +void ClassHall::SaveToDB(CharacterDatabaseTransaction& trans) { Garrison::SaveToDB(trans); } @@ -53,7 +53,7 @@ bool ClassHall::Create(uint32 garrSiteId) void ClassHall::Delete() { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/game/Garrison/ClassHall/ClassHall.h b/src/server/game/Garrison/ClassHall/ClassHall.h index 69ff0ad9a2b..241f8cd5c99 100644 --- a/src/server/game/Garrison/ClassHall/ClassHall.h +++ b/src/server/game/Garrison/ClassHall/ClassHall.h @@ -32,7 +32,7 @@ class TC_GAME_API ClassHall : public Garrison explicit ClassHall(Player* owner); bool LoadFromDB() override; - void SaveToDB(SQLTransaction& trans) override; + void SaveToDB(CharacterDatabaseTransaction& trans) override; bool Create(uint32 garrSiteId) override; void Delete() override; diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp index 9064d25d537..95703a14830 100644 --- a/src/server/game/Garrison/Garrison.cpp +++ b/src/server/game/Garrison/Garrison.cpp @@ -83,7 +83,7 @@ bool Garrison::LoadFromDB() { ObjectGuid::LowType lowGuid = _owner->GetGUID().GetCounter(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON); stmt->setUInt64(0, lowGuid); stmt->setUInt8(1, _garrisonType); PreparedQueryResult garrisonStmt = CharacterDatabase.Query(stmt); @@ -237,11 +237,11 @@ bool Garrison::LoadFromDB() return true; } -void Garrison::SaveToDB(SQLTransaction& trans) +void Garrison::SaveToDB(CharacterDatabaseTransaction& trans) { DeleteFromDB(trans); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON); stmt->setUInt64(0, _owner->GetGUID().GetCounter()); stmt->setUInt8(1, _garrisonType); stmt->setUInt32(2, _siteLevel->ID); @@ -312,14 +312,14 @@ void Garrison::SaveToDB(SQLTransaction& trans) } } -void Garrison::DeleteFromDB(SQLTransaction& trans) +void Garrison::DeleteFromDB(CharacterDatabaseTransaction& trans) { DeleteFromDB(trans, _owner->GetGUID().GetCounter(), GetType()); } -void Garrison::DeleteFromDB(SQLTransaction& trans, ObjectGuid::LowType guid, GarrisonType garrType) +void Garrison::DeleteFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType guid, GarrisonType garrType) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON); stmt->setUInt64(0, guid); stmt->setUInt8(1, garrType); trans->Append(stmt); @@ -415,7 +415,7 @@ void Garrison::AddFollower(uint32 garrFollowerId) _owner->UpdateCriteria(CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER, follower.PacketInfo.DbID); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } @@ -631,7 +631,7 @@ void Garrison::GenerateMissions() availableMissionWithWeights.second.erase(weightItr); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } diff --git a/src/server/game/Garrison/Garrison.h b/src/server/game/Garrison/Garrison.h index 8482fc6edb1..eccd7ac823b 100644 --- a/src/server/game/Garrison/Garrison.h +++ b/src/server/game/Garrison/Garrison.h @@ -59,9 +59,9 @@ class TC_GAME_API Garrison Player* GetOwner() const { return _owner; } virtual bool LoadFromDB(); - virtual void SaveToDB(SQLTransaction& trans); - void DeleteFromDB(SQLTransaction& trans); - static void DeleteFromDB(SQLTransaction& trans, ObjectGuid::LowType guid, GarrisonType garrType); + virtual void SaveToDB(CharacterDatabaseTransaction& trans); + void DeleteFromDB(CharacterDatabaseTransaction& trans); + static void DeleteFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType guid, GarrisonType garrType); virtual bool Create(uint32 garrSiteId); void Update(uint32 const diff); diff --git a/src/server/game/Garrison/WodGarrison/WodGarrison.cpp b/src/server/game/Garrison/WodGarrison/WodGarrison.cpp index 42e472b8e0a..6f63ec316d5 100644 --- a/src/server/game/Garrison/WodGarrison/WodGarrison.cpp +++ b/src/server/game/Garrison/WodGarrison/WodGarrison.cpp @@ -39,7 +39,7 @@ bool WodGarrison::LoadFromDB() ObjectGuid::LowType lowGuid = _owner->GetGUID().GetCounter(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS); stmt->setUInt64(0, lowGuid); stmt->setUInt8(1, _garrisonType); PreparedQueryResult blueprints = CharacterDatabase.Query(stmt); @@ -80,7 +80,7 @@ bool WodGarrison::LoadFromDB() if (!sGarrBuildingStore.LookupEntry(buildingId)) continue; - plot->BuildingInfo.PacketInfo = boost::in_place(); + plot->BuildingInfo.PacketInfo.emplace(); plot->BuildingInfo.PacketInfo->GarrPlotInstanceID = plotInstanceId; plot->BuildingInfo.PacketInfo->GarrBuildingID = buildingId; plot->BuildingInfo.PacketInfo->TimeBuilt = timeBuilt; @@ -92,13 +92,13 @@ bool WodGarrison::LoadFromDB() return true; } -void WodGarrison::SaveToDB(SQLTransaction& trans) +void WodGarrison::SaveToDB(CharacterDatabaseTransaction& trans) { Garrison::SaveToDB(trans); for (uint32 building : _knownBuildings) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS); stmt->setUInt64(0, _owner->GetGUID().GetCounter()); stmt->setUInt8(1, _garrisonType); stmt->setUInt32(2, building); @@ -110,7 +110,7 @@ void WodGarrison::SaveToDB(SQLTransaction& trans) Plot const& plot = p.second; if (plot.BuildingInfo.PacketInfo) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS); stmt->setUInt64(0, _owner->GetGUID().GetCounter()); stmt->setUInt8(1, _garrisonType); stmt->setUInt32(2, plot.BuildingInfo.PacketInfo->GarrPlotInstanceID); @@ -202,7 +202,7 @@ void WodGarrison::TeleportOwnerAndPlayMovie() const void WodGarrison::Delete() { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); @@ -687,7 +687,7 @@ void WodGarrison::Plot::ClearBuildingInfo(Player* owner) plotPlaced.PlotInfo = &PacketInfo; owner->SendDirectMessage(plotPlaced.Write()); - BuildingInfo.PacketInfo = boost::none; + BuildingInfo.PacketInfo = std::nullopt; } void WodGarrison::Plot::SetBuildingInfo(WorldPackets::Garrison::GarrisonBuildingInfo const& buildingInfo, Player* owner) diff --git a/src/server/game/Garrison/WodGarrison/WodGarrison.h b/src/server/game/Garrison/WodGarrison/WodGarrison.h index 0dbf93953fe..270043ef37c 100644 --- a/src/server/game/Garrison/WodGarrison/WodGarrison.h +++ b/src/server/game/Garrison/WodGarrison/WodGarrison.h @@ -79,7 +79,7 @@ class TC_GAME_API WodGarrison : public Garrison explicit WodGarrison(Player* owner); bool LoadFromDB() override; - void SaveToDB(SQLTransaction& trans) override; + void SaveToDB(CharacterDatabaseTransaction& trans) override; bool Create(uint32 garrSiteId) override; bool CanUpgrade(bool checkCost = true); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index a236a6d8f9d..9704edf818b 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -417,8 +417,8 @@ void ObjectMgr::LoadCreatureTemplates() QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, " // 9 10 11 12 13 14 15 16 17 18 19 20 "modelid4, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, " - // 21 22 23 24 25 26 27 28 29 30 31 - "faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, " + // 21 22 23 24 25 26 27 28 29 30 31 + "faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, " // 32 33 34 35 36 37 38 39 "unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, " // 40 41 42 43 44 45 46 47 48 49 50 @@ -1918,7 +1918,7 @@ bool ObjectMgr::SetCreatureLinkedRespawn(ObjectGuid::LowType guidLow, ObjectGuid if (!linkedGuidLow) // we're removing the linking { _linkedRespawnStore.erase(guid); - PreparedStatement *stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_CRELINKED_RESPAWN); + WorldDatabasePreparedStatement *stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_CRELINKED_RESPAWN); stmt->setUInt64(0, guidLow); WorldDatabase.Execute(stmt); return true; @@ -1948,7 +1948,7 @@ bool ObjectMgr::SetCreatureLinkedRespawn(ObjectGuid::LowType guidLow, ObjectGuid ObjectGuid linkedGuid = ObjectGuid::Create(slave->mapid, slave->id, linkedGuidLow); _linkedRespawnStore[guid] = linkedGuid; - PreparedStatement *stmt = WorldDatabase.GetPreparedStatement(WORLD_REP_CREATURE_LINKED_RESPAWN); + WorldDatabasePreparedStatement *stmt = WorldDatabase.GetPreparedStatement(WORLD_REP_CREATURE_LINKED_RESPAWN); stmt->setUInt64(0, guidLow); stmt->setUInt64(1, linkedGuidLow); WorldDatabase.Execute(stmt); @@ -2295,7 +2295,7 @@ void ObjectMgr::LoadCreatures() if (data.areaId) { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA); stmt->setUInt32(0, zoneId); stmt->setUInt32(1, data.areaId); @@ -2669,7 +2669,7 @@ void ObjectMgr::LoadGameobjects() if (data.areaId) { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA); stmt->setUInt32(0, zoneId); stmt->setUInt32(1, data.areaId); @@ -2718,7 +2718,7 @@ void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectDat // name must be checked to correctness (if received) before call this function ObjectGuid ObjectMgr::GetPlayerGUIDByName(std::string const& name) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME); stmt->setString(0, name); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) @@ -2767,7 +2767,7 @@ uint32 ObjectMgr::GetPlayerAccountIdByGUID(ObjectGuid const& guid) uint32 ObjectMgr::GetPlayerAccountIdByPlayerName(std::string const& name) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_BY_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_BY_NAME); stmt->setString(0, name); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) @@ -5460,7 +5460,7 @@ void ObjectMgr::LoadWaypointScripts() for (ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr) actionSet.insert(itr->first); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_ACTION); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_ACTION); PreparedQueryResult result = WorldDatabase.Query(stmt); if (result) @@ -5926,11 +5926,11 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) // Delete all old mails without item and without body immediately, if starting server if (!serverUp) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EMPTY_EXPIRED_MAIL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EMPTY_EXPIRED_MAIL); stmt->setUInt64(0, basetime); CharacterDatabase.Execute(stmt); } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL); stmt->setUInt64(0, basetime); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -6666,7 +6666,7 @@ bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool per // add link to DB if (persist) { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_GRAVEYARD_ZONE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_GRAVEYARD_ZONE); stmt->setUInt32(0, id); stmt->setUInt32(1, zoneId); @@ -6717,7 +6717,7 @@ void ObjectMgr::RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool // remove link from DB if (persist) { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GRAVEYARD_ZONE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GRAVEYARD_ZONE); stmt->setUInt32(0, id); stmt->setUInt32(1, zoneId); @@ -6948,11 +6948,11 @@ AreaTriggerTeleportStruct const* ObjectMgr::GetMapEntranceTrigger(uint32 Map) co void ObjectMgr::SetHighestGuids() { - QueryResult result = CharacterDatabase.Query("SELECT MAX(guid) FROM characters"); + QueryResult result = CharacterDatabase.Query("SELECT MAX(`guid`) FROM characters"); if (result) GetGuidSequenceGenerator().Set((*result)[0].GetUInt64() + 1); - result = CharacterDatabase.Query("SELECT MAX(guid) FROM item_instance"); + result = CharacterDatabase.Query("SELECT MAX(`guid`) FROM item_instance"); if (result) GetGuidSequenceGenerator().Set((*result)[0].GetUInt64() + 1); @@ -6982,7 +6982,7 @@ void ObjectMgr::SetHighestGuids() if (result) sGuildMgr->SetNextGuildId((*result)[0].GetUInt64()+1); - result = CharacterDatabase.Query("SELECT MAX(guid) FROM groups"); + result = CharacterDatabase.Query("SELECT MAX(`guid`) FROM `groups`"); if (result) sGroupMgr->SetGroupDbStoreSize((*result)[0].GetUInt32()+1); @@ -6990,11 +6990,11 @@ void ObjectMgr::SetHighestGuids() if (result) _voidItemId = (*result)[0].GetUInt64()+1; - result = WorldDatabase.Query("SELECT MAX(guid) FROM creature"); + result = WorldDatabase.Query("SELECT MAX(`guid`) FROM creature"); if (result) _creatureSpawnId = (*result)[0].GetUInt64() + 1; - result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject"); + result = WorldDatabase.Query("SELECT MAX(`guid`) FROM gameobject"); if (result) _gameObjectSpawnId = (*result)[0].GetUInt64() + 1; } @@ -8670,7 +8670,7 @@ bool ObjectMgr::AddGameTele(GameTele& tele) _gameTeleStore[new_id] = tele; - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_GAME_TELE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_GAME_TELE); stmt->setUInt32(0, new_id); stmt->setFloat(1, tele.position_x); @@ -8699,7 +8699,7 @@ bool ObjectMgr::DeleteGameTele(const std::string& name) { if (itr->second.wnameLow == wname) { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAME_TELE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAME_TELE); stmt->setString(0, itr->second.name); @@ -9043,7 +9043,7 @@ void ObjectMgr::LoadCreatureDefaultTrainers() int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, std::set *skip_vendors) { // find all items from the reference vendor - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_NPC_VENDOR_REF); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_NPC_VENDOR_REF); stmt->setUInt32(0, uint32(item)); PreparedQueryResult result = WorldDatabase.Query(stmt); @@ -9297,7 +9297,7 @@ void ObjectMgr::AddVendorItem(uint32 entry, VendorItem const& vItem, bool persis if (persist) { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_NPC_VENDOR); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_NPC_VENDOR); stmt->setUInt32(0, entry); stmt->setUInt32(1, vItem.item); @@ -9321,7 +9321,7 @@ bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, uint8 type, bool per if (persist) { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_NPC_VENDOR); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_NPC_VENDOR); stmt->setUInt32(0, entry); stmt->setUInt32(1, item); @@ -10602,9 +10602,8 @@ void ObjectMgr::LoadPlayerChoices() continue; } - responseItr->Reward = boost::in_place(); - - PlayerChoiceResponseReward* reward = responseItr->Reward.get_ptr(); + ; + PlayerChoiceResponseReward* reward = &responseItr->Reward.emplace(); reward->TitleId = fields[2].GetInt32(); reward->PackageId = fields[3].GetInt32(); reward->SkillLineId = fields[4].GetInt32(); diff --git a/src/server/game/Grids/NGrid.h b/src/server/game/Grids/NGrid.h index c38b19d2038..5dee583da5e 100644 --- a/src/server/game/Grids/NGrid.h +++ b/src/server/game/Grids/NGrid.h @@ -90,7 +90,6 @@ class NGrid } uint32 GetGridId(void) const { return i_gridId; } - void SetGridId(const uint32 id) const { i_gridId = id; } grid_state_t GetGridState(void) const { return i_cellstate; } void SetGridState(grid_state_t s) { i_cellstate = s; } int32 getX() const { return i_x; } diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 1ec901bfddc..1529f9ebbcb 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -146,7 +146,7 @@ bool Group::Create(Player* leader) sGroupMgr->RegisterGroupDbStoreId(m_dbStoreId, this); // Store group in database - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GROUP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GROUP); uint8 index = 0; @@ -220,7 +220,7 @@ void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uin // skip non-existed member if (!ObjectMgr::GetPlayerNameAndClassByGUID(member.guid, member.name, member._class)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); stmt->setUInt64(0, guidLow); CharacterDatabase.Execute(stmt); return; @@ -245,7 +245,7 @@ void Group::ConvertToLFG() m_lootMethod = GROUP_LOOT; if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE); stmt->setUInt8(0, uint8(m_groupFlags)); stmt->setUInt32(1, m_dbStoreId); @@ -264,7 +264,7 @@ void Group::ConvertToRaid() if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE); stmt->setUInt8(0, uint8(m_groupFlags)); stmt->setUInt32(1, m_dbStoreId); @@ -295,7 +295,7 @@ void Group::ConvertToGroup() if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE); stmt->setUInt8(0, uint8(m_groupFlags)); stmt->setUInt32(1, m_dbStoreId); @@ -438,7 +438,7 @@ bool Group::AddMember(Player* player) // insert into the table if we're not a battleground group if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GROUP_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GROUP_MEMBER); stmt->setUInt32(0, m_dbStoreId); stmt->setUInt64(1, member.guid.GetCounter()); @@ -600,7 +600,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R // Remove player from group in DB if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); stmt->setUInt64(0, guid.GetCounter()); CharacterDatabase.Execute(stmt); DelinkMember(guid); @@ -706,7 +706,7 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid, int8 partyIndex) if (!isBGGroup() && !isBFGroup()) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Remove the groups permanent instance bindings for (auto difficultyItr = m_boundInstances.begin(); difficultyItr != m_boundInstances.end(); ++difficultyItr) @@ -717,7 +717,7 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid, int8 partyIndex) // forcing a new instance with another leader requires group disbanding (confirmed on retail) if (itr->second.perm && !sMapMgr->FindMap(itr->first, itr->second.save->GetInstanceId())) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_PERM_BINDING); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_PERM_BINDING); stmt->setUInt32(0, m_dbStoreId); stmt->setUInt32(1, itr->second.save->GetInstanceId()); trans->Append(stmt); @@ -734,7 +734,7 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid, int8 partyIndex) Group::ConvertLeaderInstancesToGroup(newLeader, this, true); // Update the group leader - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_LEADER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_LEADER); stmt->setUInt64(0, newLeader->GetGUID().GetCounter()); stmt->setUInt32(1, m_dbStoreId); @@ -839,9 +839,9 @@ void Group::Disband(bool hideDestroy /* = false */) if (!isBGGroup() && !isBFGroup()) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP); stmt->setUInt32(0, m_dbStoreId); trans->Append(stmt); @@ -1684,13 +1684,13 @@ void Group::SendUpdateToPlayer(ObjectGuid playerGUID, MemberSlot* slot) if (GetMembersCount() > 1) { // LootSettings - partyUpdate.LootSettings = boost::in_place(); + partyUpdate.LootSettings.emplace(); partyUpdate.LootSettings->Method = m_lootMethod; partyUpdate.LootSettings->Threshold = m_lootThreshold; partyUpdate.LootSettings->LootMaster = m_lootMethod == MASTER_LOOT ? m_masterLooterGuid : ObjectGuid::Empty; // Difficulty Settings - partyUpdate.DifficultySettings = boost::in_place(); + partyUpdate.DifficultySettings.emplace(); partyUpdate.DifficultySettings->DungeonDifficultyID = m_dungeonDifficulty; partyUpdate.DifficultySettings->RaidDifficultyID = m_raidDifficulty; partyUpdate.DifficultySettings->LegacyRaidDifficultyID = m_legacyRaidDifficulty; @@ -1699,7 +1699,7 @@ void Group::SendUpdateToPlayer(ObjectGuid playerGUID, MemberSlot* slot) // LfgInfos if (isLFGGroup()) { - partyUpdate.LfgInfos = boost::in_place(); + partyUpdate.LfgInfos.emplace(); partyUpdate.LfgInfos->Slot = sLFGMgr->GetLFGDungeonEntry(sLFGMgr->GetDungeon(m_guid)); partyUpdate.LfgInfos->BootCount = 0; @@ -1797,7 +1797,7 @@ bool Group::_setMembersGroup(ObjectGuid guid, uint8 group) if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); stmt->setUInt8(0, group); stmt->setUInt64(1, guid.GetCounter()); @@ -1848,7 +1848,7 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) // Preserve new sub group in database for non-raid groups if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); stmt->setUInt8(0, group); stmt->setUInt64(1, guid.GetCounter()); @@ -1890,13 +1890,13 @@ void Group::SwapMembersGroups(ObjectGuid firstGuid, ObjectGuid secondGuid) slots[0]->group = slots[1]->group; slots[1]->group = tmp; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); for (uint8 i = 0; i < 2; i++) { // Preserve new sub group in database for non-raid groups if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); stmt->setUInt8(0, slots[i]->group); stmt->setUInt64(1, slots[i]->guid.GetCounter()); @@ -2113,7 +2113,7 @@ void Group::SetDungeonDifficultyID(Difficulty difficulty) m_dungeonDifficulty = difficulty; if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_DIFFICULTY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_DIFFICULTY); stmt->setUInt8(0, uint8(m_dungeonDifficulty)); stmt->setUInt32(1, m_dbStoreId); @@ -2137,7 +2137,7 @@ void Group::SetRaidDifficultyID(Difficulty difficulty) m_raidDifficulty = difficulty; if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY); stmt->setUInt8(0, uint8(m_raidDifficulty)); stmt->setUInt32(1, m_dbStoreId); @@ -2161,7 +2161,7 @@ void Group::SetLegacyRaidDifficultyID(Difficulty difficulty) m_legacyRaidDifficulty = difficulty; if (!isBGGroup() && !isBFGroup()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_LEGACY_RAID_DIFFICULTY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_LEGACY_RAID_DIFFICULTY); stmt->setUInt8(0, uint8(m_legacyRaidDifficulty)); stmt->setUInt32(1, m_dbStoreId); @@ -2275,7 +2275,7 @@ void Group::ResetInstances(uint8 method, bool isRaid, bool isLegacy, Player* Sen instanceSave->DeleteFromDB(); else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE); stmt->setUInt32(0, instanceSave->GetInstanceId()); @@ -2338,7 +2338,7 @@ InstanceGroupBind* Group::BindToInstance(InstanceSave* save, bool permanent, boo InstanceGroupBind& bind = m_boundInstances[save->GetDifficultyID()][save->GetMapId()]; if (!load && (!bind.save || permanent != bind.perm || save != bind.save)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GROUP_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GROUP_INSTANCE); stmt->setUInt32(0, m_dbStoreId); stmt->setUInt32(1, save->GetInstanceId()); @@ -2374,7 +2374,7 @@ void Group::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload) { if (!unload) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_GUID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_GUID); stmt->setUInt32(0, m_dbStoreId); stmt->setUInt32(1, itr->second.save->GetInstanceId()); @@ -2770,7 +2770,7 @@ void Group::SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags fla ToggleGroupMemberFlag(slot, flag, apply); // Preserve the new setting in the db - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_FLAG); stmt->setUInt8(0, slot->flags); stmt->setUInt64(1, guid.GetCounter()); diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp index c8af6cfd4e6..a10fab7e18b 100644 --- a/src/server/game/Groups/GroupMgr.cpp +++ b/src/server/game/Groups/GroupMgr.cpp @@ -125,14 +125,14 @@ void GroupMgr::LoadGroups() uint32 oldMSTime = getMSTime(); // Delete all groups whose leader does not exist - CharacterDatabase.DirectExecute("DELETE FROM groups WHERE leaderGuid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.DirectExecute("DELETE FROM `groups` WHERE leaderGuid NOT IN (SELECT guid FROM characters)"); // Delete all groups with less than 2 members - CharacterDatabase.DirectExecute("DELETE FROM groups WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)"); + CharacterDatabase.DirectExecute("DELETE FROM `groups` WHERE `guid` NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)"); // 0 1 2 3 4 5 6 7 8 9 QueryResult result = CharacterDatabase.Query("SELECT g.leaderGuid, g.lootMethod, g.looterGuid, g.lootThreshold, g.icon1, g.icon2, g.icon3, g.icon4, g.icon5, g.icon6" // 10 11 12 13 14 15 16 17 18 19 - ", g.icon7, g.icon8, g.groupType, g.difficulty, g.raiddifficulty, g.legacyRaidDifficulty, g.masterLooterGuid, g.guid, lfg.dungeon, lfg.state FROM groups g LEFT JOIN lfg_data lfg ON lfg.guid = g.guid ORDER BY g.guid ASC"); + ", g.icon7, g.icon8, g.groupType, g.difficulty, g.raiddifficulty, g.legacyRaidDifficulty, g.masterLooterGuid, g.guid, lfg.dungeon, lfg.state FROM `groups` g LEFT JOIN lfg_data lfg ON lfg.`guid` = g.`guid` ORDER BY g.`guid` ASC"); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 group definitions. DB table `groups` is empty!"); @@ -206,7 +206,7 @@ void GroupMgr::LoadGroups() // 0 1 2 3 4 5 6 7 QueryResult result = CharacterDatabase.Query("SELECT gi.guid, i.map, gi.instance, gi.permanent, i.difficulty, i.resettime, i.entranceId, COUNT(g.guid) " "FROM group_instance gi INNER JOIN instance i ON gi.instance = i.id " - "LEFT JOIN character_instance ci LEFT JOIN groups g ON g.leaderGuid = ci.guid ON ci.instance = gi.instance AND ci.permanent = 1 GROUP BY gi.instance ORDER BY gi.guid"); + "LEFT JOIN character_instance ci LEFT JOIN `groups` g ON g.leaderGuid = ci.guid ON ci.instance = gi.instance AND ci.permanent = 1 GROUP BY gi.instance ORDER BY gi.guid"); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 group-instance saves. DB table `group_instance` is empty!"); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 0a62b8e29df..55a68c64b47 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -92,7 +92,7 @@ inline void Guild::LogHolder::LoadEvent(LogEntry* entry) // Adds new event happened in game. // If maximum number of events is reached, oldest event is removed from collection. -inline void Guild::LogHolder::AddEvent(SQLTransaction& trans, LogEntry* entry) +inline void Guild::LogHolder::AddEvent(CharacterDatabaseTransaction& trans, LogEntry* entry) { // Check max records limit if (m_log.size() >= m_maxRecords) @@ -119,9 +119,9 @@ inline uint32 Guild::LogHolder::GetNextGUID() } // EventLogEntry -void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const +void Guild::EventLogEntry::SaveToDB(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG); stmt->setUInt64(0, m_guildId); stmt->setUInt32(1, m_guid); trans->Append(stmt); @@ -153,11 +153,11 @@ void Guild::EventLogEntry::WritePacket(WorldPackets::Guild::GuildEventLogQueryRe } // BankEventLogEntry -void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const +void Guild::BankEventLogEntry::SaveToDB(CharacterDatabaseTransaction& trans) const { uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_EVENTLOG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_EVENTLOG); stmt->setUInt64( index, m_guildId); stmt->setUInt32(++index, m_guid); stmt->setUInt8 (++index, m_bankTabId); @@ -208,10 +208,10 @@ void Guild::BankEventLogEntry::WritePacket(WorldPackets::Guild:: GuildBankLogQue packet.Entry.push_back(bankLogEntry); } -void Guild::NewsLogEntry::SaveToDB(SQLTransaction& trans) const +void Guild::NewsLogEntry::SaveToDB(CharacterDatabaseTransaction& trans) const { uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_NEWS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_NEWS); stmt->setUInt64( index, m_guildId); stmt->setUInt32(++index, GetGUID()); stmt->setUInt8 (++index, GetType()); @@ -257,9 +257,9 @@ void Guild::RankInfo::LoadFromDB(Field* fields) m_rights |= GR_RIGHT_ALL; } -void Guild::RankInfo::SaveToDB(SQLTransaction& trans) const +void Guild::RankInfo::SaveToDB(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_RANK); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_RANK); stmt->setUInt64(0, m_guildId); stmt->setUInt8 (1, m_rankId); stmt->setString(2, m_name); @@ -268,7 +268,7 @@ void Guild::RankInfo::SaveToDB(SQLTransaction& trans) const CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Guild::RankInfo::CreateMissingTabsIfNeeded(uint8 tabs, SQLTransaction& trans, bool logOnCreate /* = false */) +void Guild::RankInfo::CreateMissingTabsIfNeeded(uint8 tabs, CharacterDatabaseTransaction& trans, bool logOnCreate /* = false */) { for (uint8 i = 0; i < tabs; ++i) { @@ -283,7 +283,7 @@ void Guild::RankInfo::CreateMissingTabsIfNeeded(uint8 tabs, SQLTransaction& tran if (logOnCreate) TC_LOG_ERROR("guild", "Guild " UI64FMTD " has broken Tab %u for rank %u. Created default tab.", m_guildId, i, m_rankId); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_RIGHT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_RIGHT); stmt->setUInt64(0, m_guildId); stmt->setUInt8(1, i); stmt->setUInt8(2, m_rankId); @@ -300,7 +300,7 @@ void Guild::RankInfo::SetName(std::string const& name) m_name = name; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RANK_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RANK_NAME); stmt->setString(0, m_name); stmt->setUInt8 (1, m_rankId); stmt->setUInt64(2, m_guildId); @@ -317,7 +317,7 @@ void Guild::RankInfo::SetRights(uint32 rights) m_rights = rights; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RANK_RIGHTS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RANK_RIGHTS); stmt->setUInt32(0, m_rights); stmt->setUInt8 (1, m_rankId); stmt->setUInt64(2, m_guildId); @@ -331,7 +331,7 @@ void Guild::RankInfo::SetBankMoneyPerDay(uint32 money) m_bankMoneyPerDay = money; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RANK_BANK_MONEY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RANK_BANK_MONEY); stmt->setUInt32(0, money); stmt->setUInt8 (1, m_rankId); stmt->setUInt64(2, m_guildId); @@ -348,7 +348,7 @@ void Guild::RankInfo::SetBankTabSlotsAndRights(GuildBankRightsAndSlots rightsAnd if (saveToDB) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_RIGHT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_RIGHT); stmt->setUInt64(0, m_guildId); stmt->setUInt8 (1, guildBR.GetTabId()); stmt->setUInt8 (2, m_rankId); @@ -394,7 +394,7 @@ bool Guild::BankTab::LoadItemFromDB(Field* fields) { TC_LOG_ERROR("guild", "Item (GUID " UI64FMTD ", id: %u) not found in item_instance, deleting from guild bank!", itemGuid, itemEntry); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM); stmt->setUInt64(0, m_guildId); stmt->setUInt8 (1, m_tabId); stmt->setUInt8 (2, slotId); @@ -410,7 +410,7 @@ bool Guild::BankTab::LoadItemFromDB(Field* fields) } // Deletes contents of the tab from the world (and from DB if necessary) -void Guild::BankTab::Delete(SQLTransaction& trans, bool removeItemsFromDB) +void Guild::BankTab::Delete(CharacterDatabaseTransaction& trans, bool removeItemsFromDB) { for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) { @@ -433,7 +433,7 @@ void Guild::BankTab::SetInfo(std::string const& name, std::string const& icon) m_name = name; m_icon = icon; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_BANK_TAB_INFO); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_BANK_TAB_INFO); stmt->setString(0, m_name); stmt->setString(1, m_icon); stmt->setUInt64(2, m_guildId); @@ -449,7 +449,7 @@ void Guild::BankTab::SetText(std::string const& text) m_text = text; utf8truncate(m_text, MAX_GUILD_BANK_TAB_TEXT_LEN); // DB and client size limitation - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_BANK_TAB_TEXT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_BANK_TAB_TEXT); stmt->setString(0, m_text); stmt->setUInt64(1, m_guildId); stmt->setUInt8 (2, m_tabId); @@ -458,14 +458,14 @@ void Guild::BankTab::SetText(std::string const& text) // Sets/removes contents of specified slot. // If pItem == nullptr contents are removed. -bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item) +bool Guild::BankTab::SetItem(CharacterDatabaseTransaction& trans, uint8 slotId, Item* item) { if (slotId >= GUILD_BANK_MAX_SLOTS) return false; m_items[slotId] = item; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_ITEM); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_ITEM); stmt->setUInt64(0, m_guildId); stmt->setUInt8 (1, m_tabId); stmt->setUInt8 (2, slotId); @@ -559,7 +559,7 @@ void Guild::Member::SetPublicNote(std::string const& publicNote) m_publicNote = publicNote; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_PNOTE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_PNOTE); stmt->setString(0, publicNote); stmt->setUInt64(1, m_guid.GetCounter()); CharacterDatabase.Execute(stmt); @@ -572,13 +572,13 @@ void Guild::Member::SetOfficerNote(std::string const& officerNote) m_officerNote = officerNote; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_OFFNOTE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_OFFNOTE); stmt->setString(0, officerNote); stmt->setUInt64(1, m_guid.GetCounter()); CharacterDatabase.Execute(stmt); } -void Guild::Member::ChangeRank(SQLTransaction& trans, uint8 newRank) +void Guild::Member::ChangeRank(CharacterDatabaseTransaction& trans, uint8 newRank) { m_rankId = newRank; @@ -586,15 +586,15 @@ void Guild::Member::ChangeRank(SQLTransaction& trans, uint8 newRank) if (Player* player = FindConnectedPlayer()) player->SetGuildRank(newRank); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_RANK); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_RANK); stmt->setUInt8 (0, newRank); stmt->setUInt64(1, m_guid.GetCounter()); CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Guild::Member::SaveToDB(SQLTransaction& trans) const +void Guild::Member::SaveToDB(CharacterDatabaseTransaction& trans) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_MEMBER); stmt->setUInt64(0, m_guildId); stmt->setUInt64(1, m_guid.GetCounter()); stmt->setUInt8 (2, m_rankId); @@ -666,11 +666,11 @@ float Guild::Member::GetInactiveDays() const } // Decreases amount of slots left for today. -void Guild::Member::UpdateBankTabWithdrawValue(SQLTransaction& trans, uint8 tabId, uint32 amount) +void Guild::Member::UpdateBankTabWithdrawValue(CharacterDatabaseTransaction& trans, uint8 tabId, uint32 amount) { m_bankWithdraw[tabId] += amount; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_MEMBER_WITHDRAW_TABS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_MEMBER_WITHDRAW_TABS); stmt->setUInt64(0, m_guid.GetCounter()); for (uint8 i = 0; i < GUILD_BANK_MAX_TABS;) { @@ -682,11 +682,11 @@ void Guild::Member::UpdateBankTabWithdrawValue(SQLTransaction& trans, uint8 tabI } // Decreases amount of money left for today. -void Guild::Member::UpdateBankMoneyWithdrawValue(SQLTransaction& trans, uint64 amount) +void Guild::Member::UpdateBankMoneyWithdrawValue(CharacterDatabaseTransaction& trans, uint64 amount) { m_bankWithdrawMoney += amount; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_MEMBER_WITHDRAW_MONEY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_MEMBER_WITHDRAW_MONEY); stmt->setUInt64(0, m_guid.GetCounter()); stmt->setUInt64(1, m_bankWithdrawMoney); CharacterDatabase.ExecuteOrAppend(trans, stmt); @@ -747,7 +747,7 @@ bool EmblemInfo::LoadFromDB(Field* fields) void EmblemInfo::SaveToDB(ObjectGuid::LowType guildId) const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_EMBLEM_INFO); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_EMBLEM_INFO); stmt->setUInt32(0, m_style); stmt->setUInt32(1, m_color); stmt->setUInt32(2, m_borderStyle); @@ -835,7 +835,7 @@ bool Guild::PlayerMoveItemData::InitItem() return (m_pItem != nullptr); } -void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* /*pOther*/, uint32 splitedAmount) +void Guild::PlayerMoveItemData::RemoveItem(CharacterDatabaseTransaction& trans, MoveItemData* /*pOther*/, uint32 splitedAmount) { if (splitedAmount) { @@ -851,7 +851,7 @@ void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* } } -Item* Guild::PlayerMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem) +Item* Guild::PlayerMoveItemData::StoreItem(CharacterDatabaseTransaction& trans, Item* pItem) { ASSERT(pItem); m_pPlayer->MoveItemToInventory(m_vec, pItem, true); @@ -859,7 +859,7 @@ Item* Guild::PlayerMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem) return pItem; } -void Guild::PlayerMoveItemData::LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const +void Guild::PlayerMoveItemData::LogBankEvent(CharacterDatabaseTransaction& trans, MoveItemData* pFrom, uint32 count) const { ASSERT(pFrom); // Bank -> Char @@ -902,7 +902,7 @@ bool Guild::BankMoveItemData::HasWithdrawRights(MoveItemData* pOther) const return slots != 0; } -void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) +void Guild::BankMoveItemData::RemoveItem(CharacterDatabaseTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) { ASSERT(m_pItem); if (splitedAmount) @@ -921,7 +921,7 @@ void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pO m_pGuild->_UpdateMemberWithdrawSlots(trans, m_pPlayer->GetGUID(), m_container); } -Item* Guild::BankMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem) +Item* Guild::BankMoveItemData::StoreItem(CharacterDatabaseTransaction& trans, Item* pItem) { if (!pItem) return nullptr; @@ -943,7 +943,7 @@ Item* Guild::BankMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem) return pLastItem; } -void Guild::BankMoveItemData::LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const +void Guild::BankMoveItemData::LogBankEvent(CharacterDatabaseTransaction& trans, MoveItemData* pFrom, uint32 count) const { ASSERT(pFrom->GetItem()); if (pFrom->IsBank()) @@ -969,7 +969,7 @@ void Guild::BankMoveItemData::LogAction(MoveItemData* pFrom) const } } -Item* Guild::BankMoveItemData::_StoreItem(SQLTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const +Item* Guild::BankMoveItemData::_StoreItem(CharacterDatabaseTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const { uint8 slotId = uint8(pos.pos); uint32 count = pos.count; @@ -1107,7 +1107,7 @@ Guild::Guild(): Guild::~Guild() { - SQLTransaction temp(nullptr); + CharacterDatabaseTransaction temp(nullptr); _DeleteBankItems(temp); // Cleanup @@ -1152,9 +1152,9 @@ bool Guild::Create(Player* pLeader, std::string const& name) TC_LOG_DEBUG("guild", "GUILD: creating guild [%s] for leader %s (%s)", name.c_str(), pLeader->GetName().c_str(), m_leaderGuid.ToString().c_str()); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBERS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBERS); stmt->setUInt64(0, m_id); trans->Append(stmt); @@ -1200,7 +1200,7 @@ void Guild::Disband() WorldPackets::Guild::GuildEventDisbanded packet; BroadcastPacket(packet.Write()); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Remove all members while (!m_members.empty()) { @@ -1208,7 +1208,7 @@ void Guild::Disband() DeleteMember(trans, itr->second->GetGUID(), true); } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD); stmt->setUInt64(0, m_id); trans->Append(stmt); @@ -1248,7 +1248,7 @@ void Guild::Disband() void Guild::SaveToDB() { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); m_achievementMgr.SaveToDB(trans); @@ -1294,7 +1294,7 @@ bool Guild::SetName(std::string const& name) return false; m_name = name; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_NAME); stmt->setString(0, m_name); stmt->setUInt64(1, GetId()); CharacterDatabase.Execute(stmt); @@ -1359,7 +1359,7 @@ void Guild::SendQueryResponse(WorldSession* session) { WorldPackets::Guild::QueryGuildInfoResponse response; response.GuildGuid = GetGUID(); - response.Info = boost::in_place(); + response.Info.emplace(); response.Info->GuildGUID = GetGUID(); response.Info->VirtualRealmAddress = GetVirtualRealmAddress(); @@ -1463,7 +1463,7 @@ void Guild::HandleSetMOTD(WorldSession* session, std::string const& motd) sScriptMgr->OnGuildMOTDChanged(this, motd); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MOTD); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MOTD); stmt->setString(0, motd); stmt->setUInt64(1, m_id); CharacterDatabase.Execute(stmt); @@ -1484,7 +1484,7 @@ void Guild::HandleSetInfo(WorldSession* session, std::string const& info) sScriptMgr->OnGuildInfoChanged(this, info); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_INFO); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_INFO); stmt->setString(0, info); stmt->setUInt64(1, m_id); CharacterDatabase.Execute(stmt); @@ -1545,7 +1545,7 @@ void Guild::HandleSetNewGuildMaster(WorldSession* session, std::string const& na return; } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); _SetLeader(trans, newGuildMaster); oldGuildMaster->ChangeRank(trans, GR_INITIATE); @@ -1736,7 +1736,7 @@ void Guild::HandleAcceptMember(WorldSession* session) player->GetTeam() != ObjectMgr::GetPlayerTeamByGUID(GetLeaderGUID())) return; - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); AddMember(trans, player->GetGUID()); } @@ -1763,7 +1763,7 @@ void Guild::HandleLeaveMember(WorldSession* session) _LogEvent(GUILD_EVENT_LOG_LEAVE_GUILD, player->GetGUID().GetCounter()); SendEventPlayerLeft(GetMember(player->GetGUID())); - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); DeleteMember(trans, player->GetGUID(), false, false); SendCommandResult(session, GUILD_COMMAND_LEAVE_GUILD, ERR_GUILD_COMMAND_SUCCESS, m_name); @@ -1801,7 +1801,7 @@ void Guild::HandleRemoveMember(WorldSession* session, ObjectGuid guid) SendEventPlayerLeft(member, memberMe, true); // After call to DeleteMember pointer to member becomes invalid - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); DeleteMember(trans, guid, false, true); SendCommandResult(session, GUILD_COMMAND_REMOVE_PLAYER, ERR_GUILD_COMMAND_SUCCESS, name); @@ -1858,7 +1858,7 @@ void Guild::HandleUpdateMemberRank(WorldSession* session, ObjectGuid guid, bool } uint32 newRankId = member->GetRankId() + (demote ? 1 : -1); - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); member->ChangeRank(trans, newRankId); _LogEvent(demote ? GUILD_EVENT_LOG_DEMOTE_PLAYER : GUILD_EVENT_LOG_PROMOTE_PLAYER, player->GetGUID().GetCounter(), member->GetGUID().GetCounter(), newRankId); //_BroadcastEvent(demote ? GE_DEMOTION : GE_PROMOTION, ObjectGuid::Empty, player->GetName().c_str(), name.c_str(), _GetRankName(newRankId).c_str()); @@ -1906,7 +1906,7 @@ void Guild::HandleAddNewRank(WorldSession* session, std::string const& name) // Only leader can add new rank if (_IsLeader(session->GetPlayer())) { - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); if (_CreateRank(trans, name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK)) { WorldPackets::Guild::GuildEventRanksUpdated eventPacket; @@ -1922,7 +1922,7 @@ void Guild::HandleRemoveRank(WorldSession* session, uint8 rankId) return; // Delete bank rights for rank - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS_FOR_RANK); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS_FOR_RANK); stmt->setUInt64(0, m_id); stmt->setUInt8(1, rankId); CharacterDatabase.Execute(stmt); @@ -1951,7 +1951,7 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint64 amount, bool // Call script after validation and before money transfer. sScriptMgr->OnGuildMemberDepositMoney(this, player, amount); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); _ModifyBankMoney(trans, amount, true); if (!cashFlow) { @@ -1995,7 +1995,7 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint64 amount, bool // Call script after validation and before money transfer. sScriptMgr->OnGuildMemberWitdrawMoney(this, player, amount, repair); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Add money to player (if required) if (!repair) { @@ -2366,7 +2366,7 @@ bool Guild::LoadMemberFromDB(Field* fields) Member *member = new Member(m_id, ObjectGuid::Create(lowguid), fields[2].GetUInt8()); if (!member->LoadFromDB(fields)) { - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); Guild::_DeleteMemberFromDB(trans, lowguid); delete member; return false; @@ -2488,7 +2488,7 @@ bool Guild::Validate() bool broken_ranks = false; uint8 ranks = _GetRanksSize(); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (ranks < GUILD_RANKS_MIN_COUNT || ranks > GUILD_RANKS_MAX_COUNT) { TC_LOG_ERROR("guild", "Guild " UI64FMTD " has invalid number of ranks, creating new...", m_id); @@ -2526,7 +2526,7 @@ bool Guild::Validate() Member* leader = GetMember(m_leaderGuid); if (!leader) { - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); DeleteMember(trans, m_leaderGuid); // If no more members left, disband guild if (m_members.empty()) @@ -2630,7 +2630,7 @@ void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 max } // Members handling -bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) +bool Guild::AddMember(CharacterDatabaseTransaction& trans, ObjectGuid guid, uint8 rankId) { Player* player = ObjectAccessor::FindConnectedPlayer(guid); // Player cannot be in guild @@ -2670,7 +2670,7 @@ bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) bool ok = false; // Player must exist - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD); stmt->setUInt64(0, lowguid); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) { @@ -2715,7 +2715,7 @@ bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) return true; } -void Guild::DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild) +void Guild::DeleteMember(CharacterDatabaseTransaction& trans, ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild) { // Guild master can be deleted when loading guild and guid doesn't exist in characters table // or when he is removed from guild by gm command @@ -2772,7 +2772,7 @@ void Guild::DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbandi _UpdateAccountsNumber(); } -bool Guild::ChangeMemberRank(SQLTransaction& trans, ObjectGuid guid, uint8 newRank) +bool Guild::ChangeMemberRank(CharacterDatabaseTransaction& trans, ObjectGuid guid, uint8 newRank) { if (newRank <= _GetLowestRankId()) // Validate rank (allow only existing ranks) { @@ -2842,9 +2842,9 @@ bool Guild::_HasRankRight(Player const* player, uint32 right) const return false; } -void Guild::_DeleteMemberFromDB(SQLTransaction& trans, ObjectGuid::LowType lowguid) +void Guild::_DeleteMemberFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType lowguid) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER); stmt->setUInt64(0, lowguid); CharacterDatabase.ExecuteOrAppend(trans, stmt); } @@ -2863,9 +2863,9 @@ void Guild::_CreateNewBankTab() uint8 tabId = _GetPurchasedTabsSize(); // Next free id m_bankTabs.push_back(new BankTab(m_id, tabId)); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_TAB); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_TAB); stmt->setUInt64(0, m_id); stmt->setUInt8 (1, tabId); trans->Append(stmt); @@ -2882,11 +2882,11 @@ void Guild::_CreateNewBankTab() CharacterDatabase.CommitTransaction(trans); } -void Guild::_CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc) +void Guild::_CreateDefaultGuildRanks(CharacterDatabaseTransaction& trans, LocaleConstant loc) { ASSERT(trans); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS); stmt->setUInt64(0, m_id); trans->Append(stmt); @@ -2901,7 +2901,7 @@ void Guild::_CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc) _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_INITIATE, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); } -bool Guild::_CreateRank(SQLTransaction& trans, std::string const& name, uint32 rights) +bool Guild::_CreateRank(CharacterDatabaseTransaction& trans, std::string const& name, uint32 rights) { uint8 newRankId = _GetRanksSize(); if (newRankId >= GUILD_RANKS_MAX_COUNT) @@ -2948,7 +2948,7 @@ bool Guild::_IsLeader(Player* player) const return false; } -void Guild::_DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB) +void Guild::_DeleteBankItems(CharacterDatabaseTransaction& trans, bool removeItemsFromDB) { for (uint8 tabId = 0; tabId < _GetPurchasedTabsSize(); ++tabId) { @@ -2959,7 +2959,7 @@ void Guild::_DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB) m_bankTabs.clear(); } -bool Guild::_ModifyBankMoney(SQLTransaction& trans, uint64 amount, bool add) +bool Guild::_ModifyBankMoney(CharacterDatabaseTransaction& trans, uint64 amount, bool add) { if (add) m_bankMoney += amount; @@ -2971,14 +2971,14 @@ bool Guild::_ModifyBankMoney(SQLTransaction& trans, uint64 amount, bool add) m_bankMoney -= amount; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_BANK_MONEY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_BANK_MONEY); stmt->setUInt64(0, m_bankMoney); stmt->setUInt64(1, m_id); trans->Append(stmt); return true; } -void Guild::_SetLeader(SQLTransaction& trans, Member* leader) +void Guild::_SetLeader(CharacterDatabaseTransaction& trans, Member* leader) { if (!leader) return; @@ -2990,7 +2990,7 @@ void Guild::_SetLeader(SQLTransaction& trans, Member* leader) m_leaderGuid = leader->GetGUID(); leader->ChangeRank(trans, GR_GUILDMASTER); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_LEADER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_LEADER); stmt->setUInt64(0, m_leaderGuid.GetCounter()); stmt->setUInt64(1, m_id); trans->Append(stmt); @@ -3085,7 +3085,7 @@ inline int64 Guild::_GetMemberRemainingMoney(Member const* member) const return 0; } -inline void Guild::_UpdateMemberWithdrawSlots(SQLTransaction& trans, ObjectGuid guid, uint8 tabId) +inline void Guild::_UpdateMemberWithdrawSlots(CharacterDatabaseTransaction& trans, ObjectGuid guid, uint8 tabId) { if (Member* member = GetMember(guid)) member->UpdateBankTabWithdrawValue(trans, tabId, 1); @@ -3106,7 +3106,7 @@ inline bool Guild::_MemberHasTabRights(ObjectGuid guid, uint8 tabId, int32 right // Add new event log record inline void Guild::_LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); m_eventLog->AddEvent(trans, new EventLogEntry(m_id, m_eventLog->GetNextGUID(), eventType, playerGuid1, playerGuid2, newRank)); CharacterDatabase.CommitTransaction(trans); @@ -3114,7 +3114,7 @@ inline void Guild::_LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType p } // Add new bank event log record -void Guild::_LogBankEvent(SQLTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType lowguid, uint64 itemOrMoney, uint16 itemStackCount, uint8 destTabId) +void Guild::_LogBankEvent(CharacterDatabaseTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType lowguid, uint64 itemOrMoney, uint16 itemStackCount, uint8 destTabId) { if (tabId > GUILD_BANK_MAX_TABS) return; @@ -3142,7 +3142,7 @@ inline Item* Guild::_GetItem(uint8 tabId, uint8 slotId) const return nullptr; } -inline void Guild::_RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId) +inline void Guild::_RemoveItem(CharacterDatabaseTransaction& trans, uint8 tabId, uint8 slotId) { if (BankTab* pTab = GetBankTab(tabId)) pTab->SetItem(trans, slotId, nullptr); @@ -3229,7 +3229,7 @@ bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError if (swap) pSrc->LogAction(pDest); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // 3. Log bank events pDest->LogBankEvent(trans, pSrc, pSrcItem->GetCount()); if (swap) @@ -3428,7 +3428,7 @@ void Guild::SendGuildRanksUpdate(ObjectGuid setterGuid, ObjectGuid targetGuid, u rankChange.Promote = (rank < member->GetRankId()); BroadcastPacket(rankChange.Write()); - SQLTransaction trans; + CharacterDatabaseTransaction trans; member->ChangeRank(trans, rank); TC_LOG_DEBUG("network", "SMSG_GUILD_RANKS_UPDATE [Broadcast] Target: %s, Issuer: %s, RankId: %u", @@ -3452,7 +3452,7 @@ void Guild::AddGuildNews(uint8 type, ObjectGuid guid, uint32 flags, uint32 value { NewsLogEntry* news = new NewsLogEntry(m_id, m_newsLog->GetNextGUID(), GuildNews(type), guid, flags, value); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); m_newsLog->AddEvent(trans, news); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 2da976b652b..3e448690464 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -352,7 +352,7 @@ class TC_GAME_API Guild void ResetFlags() { m_flags = GUILDMEMBER_STATUS_NONE; } bool LoadFromDB(Field* fields); - void SaveToDB(SQLTransaction& trans) const; + void SaveToDB(CharacterDatabaseTransaction& trans) const; ObjectGuid const& GetGUID() const { return m_guid; } std::string const& GetName() const { return m_name; } @@ -379,15 +379,15 @@ class TC_GAME_API Guild bool IsOnline() const { return (m_flags & GUILDMEMBER_STATUS_ONLINE); } - void ChangeRank(SQLTransaction& trans, uint8 newRank); + void ChangeRank(CharacterDatabaseTransaction& trans, uint8 newRank); inline void UpdateLogoutTime() { m_logoutTime = ::time(nullptr); } inline bool IsRank(uint8 rankId) const { return m_rankId == rankId; } inline bool IsRankNotLower(uint8 rankId) const { return m_rankId <= rankId; } inline bool IsSamePlayer(ObjectGuid guid) const { return m_guid == guid; } - void UpdateBankTabWithdrawValue(SQLTransaction& trans, uint8 tabId, uint32 amount); - void UpdateBankMoneyWithdrawValue(SQLTransaction& trans, uint64 amount); + void UpdateBankTabWithdrawValue(CharacterDatabaseTransaction& trans, uint8 tabId, uint32 amount); + void UpdateBankMoneyWithdrawValue(CharacterDatabaseTransaction& trans, uint64 amount); uint32 GetBankTabWithdrawValue(uint8 tabId) const { return m_bankWithdraw[tabId]; }; uint64 GetBankMoneyWithdrawValue() const { return m_bankWithdrawMoney; }; void ResetValues(bool weekly = false); @@ -434,7 +434,7 @@ class TC_GAME_API Guild uint32 GetGUID() const { return m_guid; } uint64 GetTimestamp() const { return m_timestamp; } - virtual void SaveToDB(SQLTransaction& trans) const = 0; + virtual void SaveToDB(CharacterDatabaseTransaction& trans) const = 0; protected: ObjectGuid::LowType m_guildId; @@ -454,7 +454,7 @@ class TC_GAME_API Guild ~EventLogEntry() { } - void SaveToDB(SQLTransaction& trans) const override; + void SaveToDB(CharacterDatabaseTransaction& trans) const override; void WritePacket(WorldPackets::Guild::GuildEventLogQueryResults& packet) const; private: @@ -492,7 +492,7 @@ class TC_GAME_API Guild ~BankEventLogEntry() { } - void SaveToDB(SQLTransaction& trans) const override; + void SaveToDB(CharacterDatabaseTransaction& trans) const override; void WritePacket(WorldPackets::Guild::GuildBankLogQueryResults& packet) const; private: @@ -528,7 +528,7 @@ class TC_GAME_API Guild m_flags &= ~1; } - void SaveToDB(SQLTransaction& trans) const override; + void SaveToDB(CharacterDatabaseTransaction& trans) const override; void WritePacket(WorldPackets::Guild::GuildNews& newsPacket) const; private: @@ -553,7 +553,7 @@ class TC_GAME_API Guild // Adds event from DB to collection void LoadEvent(LogEntry* entry); // Adds new event to collection and saves it to DB - void AddEvent(SQLTransaction& trans, LogEntry* entry); + void AddEvent(CharacterDatabaseTransaction& trans, LogEntry* entry); uint32 GetNextGUID(); GuildLog* GetGuildLog() { return &m_log; } @@ -573,7 +573,7 @@ class TC_GAME_API Guild m_guildId(guildId), m_rankId(rankId), m_name(name), m_rights(rights), m_bankMoneyPerDay(money) { } void LoadFromDB(Field* fields); - void SaveToDB(SQLTransaction& trans) const; + void SaveToDB(CharacterDatabaseTransaction& trans) const; uint8 GetId() const { return m_rankId; } @@ -601,7 +601,7 @@ class TC_GAME_API Guild } void SetBankTabSlotsAndRights(GuildBankRightsAndSlots rightsAndSlots, bool saveToDB); - void CreateMissingTabsIfNeeded(uint8 ranks, SQLTransaction& trans, bool logOnCreate = false); + void CreateMissingTabsIfNeeded(uint8 ranks, CharacterDatabaseTransaction& trans, bool logOnCreate = false); private: ObjectGuid::LowType m_guildId; @@ -619,7 +619,7 @@ class TC_GAME_API Guild void LoadFromDB(Field* fields); bool LoadItemFromDB(Field* fields); - void Delete(SQLTransaction& trans, bool removeItemsFromDB = false); + void Delete(CharacterDatabaseTransaction& trans, bool removeItemsFromDB = false); void SetInfo(std::string const& name, std::string const& icon); void SetText(std::string const& text); @@ -630,7 +630,7 @@ class TC_GAME_API Guild std::string const& GetText() const { return m_text; } inline Item* GetItem(uint8 slotId) const { return slotId < GUILD_BANK_MAX_SLOTS ? m_items[slotId] : nullptr; } - bool SetItem(SQLTransaction& trans, uint8 slotId, Item* item); + bool SetItem(CharacterDatabaseTransaction& trans, uint8 slotId, Item* item); private: ObjectGuid::LowType m_guildId; @@ -663,11 +663,11 @@ class TC_GAME_API Guild // Clones stored item bool CloneItem(uint32 count); // Remove item from container (if splited update items fields) - virtual void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) = 0; + virtual void RemoveItem(CharacterDatabaseTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) = 0; // Saves item to container - virtual Item* StoreItem(SQLTransaction& trans, Item* pItem) = 0; + virtual Item* StoreItem(CharacterDatabaseTransaction& trans, Item* pItem) = 0; // Log bank event - virtual void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const = 0; + virtual void LogBankEvent(CharacterDatabaseTransaction& trans, MoveItemData* pFrom, uint32 count) const = 0; // Log GM action virtual void LogAction(MoveItemData* pFrom) const; // Copy slots id from position vector @@ -697,9 +697,9 @@ class TC_GAME_API Guild bool IsBank() const override { return false; } bool InitItem() override; - void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) override; - Item* StoreItem(SQLTransaction& trans, Item* pItem) override; - void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override; + void RemoveItem(CharacterDatabaseTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) override; + Item* StoreItem(CharacterDatabaseTransaction& trans, Item* pItem) override; + void LogBankEvent(CharacterDatabaseTransaction& trans, MoveItemData* pFrom, uint32 count) const override; protected: InventoryResult CanStore(Item* pItem, bool swap) override; @@ -715,16 +715,16 @@ class TC_GAME_API Guild bool InitItem() override; bool HasStoreRights(MoveItemData* pOther) const override; bool HasWithdrawRights(MoveItemData* pOther) const override; - void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) override; - Item* StoreItem(SQLTransaction& trans, Item* pItem) override; - void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override; + void RemoveItem(CharacterDatabaseTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) override; + Item* StoreItem(CharacterDatabaseTransaction& trans, Item* pItem) override; + void LogBankEvent(CharacterDatabaseTransaction& trans, MoveItemData* pFrom, uint32 count) const override; void LogAction(MoveItemData* pFrom) const override; protected: InventoryResult CanStore(Item* pItem, bool swap) override; private: - Item* _StoreItem(SQLTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const; + Item* _StoreItem(CharacterDatabaseTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const; bool _ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count); void CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count); }; @@ -839,9 +839,9 @@ class TC_GAME_API Guild // Members // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned. - bool AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE); - void DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); - bool ChangeMemberRank(SQLTransaction& trans, ObjectGuid guid, uint8 newRank); + bool AddMember(CharacterDatabaseTransaction& trans, ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE); + void DeleteMember(CharacterDatabaseTransaction& trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); + bool ChangeMemberRank(CharacterDatabaseTransaction& trans, ObjectGuid guid, uint8 newRank); bool IsMember(ObjectGuid guid) const; uint32 GetMembersCount() const { return uint32(m_members.size()); } @@ -921,22 +921,22 @@ class TC_GAME_API Guild return nullptr; } - static void _DeleteMemberFromDB(SQLTransaction& trans, ObjectGuid::LowType lowguid); + static void _DeleteMemberFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType lowguid); // Creates log holders (either when loading or when creating guild) void _CreateLogHolders(); // Tries to create new bank tab void _CreateNewBankTab(); // Creates default guild ranks with names in given locale - void _CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc); + void _CreateDefaultGuildRanks(CharacterDatabaseTransaction& trans, LocaleConstant loc); // Creates new rank - bool _CreateRank(SQLTransaction& trans, std::string const& name, uint32 rights); + bool _CreateRank(CharacterDatabaseTransaction& trans, std::string const& name, uint32 rights); // Update account number when member added/removed from guild void _UpdateAccountsNumber(); bool _IsLeader(Player* player) const; - void _DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB = false); - bool _ModifyBankMoney(SQLTransaction& trans, uint64 amount, bool add); - void _SetLeader(SQLTransaction& trans, Member* leader); + void _DeleteBankItems(CharacterDatabaseTransaction& trans, bool removeItemsFromDB = false); + bool _ModifyBankMoney(CharacterDatabaseTransaction& trans, uint64 amount, bool add); + void _SetLeader(CharacterDatabaseTransaction& trans, Member* leader); void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay); void _SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB = true); @@ -948,14 +948,14 @@ class TC_GAME_API Guild int32 _GetMemberRemainingSlots(Member const* member, uint8 tabId) const; int64 _GetMemberRemainingMoney(Member const* member) const; - void _UpdateMemberWithdrawSlots(SQLTransaction& trans, ObjectGuid guid, uint8 tabId); + void _UpdateMemberWithdrawSlots(CharacterDatabaseTransaction& trans, ObjectGuid guid, uint8 tabId); bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, int32 rights) const; void _LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2 = UI64LIT(0), uint8 newRank = 0); - void _LogBankEvent(SQLTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint64 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0); + void _LogBankEvent(CharacterDatabaseTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint64 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0); Item* _GetItem(uint8 tabId, uint8 slotId) const; - void _RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId); + void _RemoveItem(CharacterDatabaseTransaction& trans, uint8 tabId, uint8 slotId); void _MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount) const; static bool _DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount = 0); diff --git a/src/server/game/Guilds/GuildFinderMgr.cpp b/src/server/game/Guilds/GuildFinderMgr.cpp index ff3e314d8e4..5dfe7b494ef 100644 --- a/src/server/game/Guilds/GuildFinderMgr.cpp +++ b/src/server/game/Guilds/GuildFinderMgr.cpp @@ -132,8 +132,8 @@ void GuildFinderMgr::AddMembershipRequest(ObjectGuid const& guildGuid, Membershi _membershipRequestsByGuild[guildGuid][request.GetPlayerGUID()] = request; _membershipRequestsByPlayer[request.GetPlayerGUID()][guildGuid] = request; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GUILD_FINDER_APPLICANT); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GUILD_FINDER_APPLICANT); stmt->setUInt64(0, request.GetGuildGuid().GetCounter()); stmt->setUInt64(1, request.GetPlayerGUID().GetCounter()); stmt->setUInt8(2, request.GetAvailability()); @@ -159,10 +159,10 @@ void GuildFinderMgr::RemoveAllMembershipRequestsFromPlayer(ObjectGuid const& pla if (playerItr == _membershipRequestsByPlayer.end()) return; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); for (auto& guildRequestPair : playerItr->second) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); stmt->setUInt64(0, guildRequestPair.first.GetCounter()); stmt->setUInt64(1, playerId.GetCounter()); trans->Append(stmt); @@ -203,9 +203,9 @@ void GuildFinderMgr::RemoveMembershipRequest(ObjectGuid const& playerId, ObjectG _membershipRequestsByPlayer.erase(playerItr); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); stmt->setUInt64(0, guildId.GetCounter()); stmt->setUInt64(1, playerId.GetCounter()); trans->Append(stmt); @@ -285,9 +285,9 @@ void GuildFinderMgr::SetGuildSettings(ObjectGuid const& guildGuid, LFGuildSettin { _guildSettings[guildGuid] = settings; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GUILD_FINDER_GUILD_SETTINGS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GUILD_FINDER_GUILD_SETTINGS); stmt->setUInt64(0, settings.GetGUID().GetCounter()); stmt->setUInt8(1, settings.GetAvailability()); stmt->setUInt8(2, settings.GetClassRoles()); @@ -302,13 +302,13 @@ void GuildFinderMgr::SetGuildSettings(ObjectGuid const& guildGuid, LFGuildSettin void GuildFinderMgr::DeleteGuild(ObjectGuid const& guildId) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); auto guildItr = _membershipRequestsByGuild.find(guildId); if (guildItr != _membershipRequestsByGuild.end()) { for (auto playerRequestPair : guildItr->second) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); stmt->setUInt64(0, guildId.GetCounter()); stmt->setUInt64(1, playerRequestPair.first.GetCounter()); trans->Append(stmt); @@ -327,7 +327,7 @@ void GuildFinderMgr::DeleteGuild(ObjectGuid const& guildId) } } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_GUILD_SETTINGS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_GUILD_SETTINGS); stmt->setUInt64(0, guildId.GetCounter()); trans->Append(stmt); diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 324908753c4..eb26e9d6f28 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -459,7 +459,7 @@ void GuildMgr::LoadGuilds() PreparedQueryResult criteriaResult; for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_ACHIEVEMENT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_ACHIEVEMENT); stmt->setUInt64(0, itr->first); achievementResult = CharacterDatabase.Query(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_ACHIEVEMENT_CRITERIA); @@ -530,7 +530,7 @@ void GuildMgr::LoadGuildRewards() continue; } - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_GUILD_REWARDS_REQ_ACHIEVEMENTS); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_GUILD_REWARDS_REQ_ACHIEVEMENTS); stmt->setUInt32(0, reward.ItemID); PreparedQueryResult reqAchievementResult = WorldDatabase.Query(stmt); if (reqAchievementResult) diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index f5a4911ec6a..f90b2325dde 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -273,7 +273,7 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); @@ -331,7 +331,7 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); @@ -344,13 +344,13 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell _player->ItemRemovedQuestCheck(item2->GetEntry(), packet.Items[i].UseCount); item2->SendUpdateToPlayer(_player); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); @@ -421,7 +421,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPackets::AuctionHouse::AuctionPlac return; } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (packet.BidAmount < auction->buyout || auction->buyout == 0) { @@ -443,7 +443,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPackets::AuctionHouse::AuctionPlac auction->bid = packet.BidAmount; GetPlayer()->UpdateCriteria(CRITERIA_TYPE_HIGHEST_AUCTION_BID, packet.BidAmount); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID); stmt->setUInt64(0, auction->bidder); stmt->setUInt64(1, auction->bid); stmt->setUInt32(2, auction->Id); @@ -508,7 +508,7 @@ void WorldSession::HandleAuctionRemoveItem(WorldPackets::AuctionHouse::AuctionRe AuctionEntry* auction = auctionHouse->GetAuction(packet.AuctionItemID); Player* player = GetPlayer(); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (auction && auction->owner == player->GetGUID().GetCounter()) { Item* item = sAuctionMgr->GetAItem(auction->itemGUIDLow); @@ -634,7 +634,7 @@ void WorldSession::HandleAuctionListItems(WorldPackets::AuctionHouse::AuctionLis WorldPackets::AuctionHouse::AuctionListItemsResult result; if (!packet.ClassFilters.empty()) { - filters = boost::in_place(); + filters.emplace(); for (auto const& classFilter : packet.ClassFilters) { diff --git a/src/server/game/Handlers/AuthHandler.cpp b/src/server/game/Handlers/AuthHandler.cpp index 296bf506edc..6cf4ae2f06e 100644 --- a/src/server/game/Handlers/AuthHandler.cpp +++ b/src/server/game/Handlers/AuthHandler.cpp @@ -33,7 +33,7 @@ void WorldSession::SendAuthResponse(uint32 code, bool queued, uint32 queuePos) if (code == ERROR_OK) { - response.SuccessInfo = boost::in_place(); + response.SuccessInfo.emplace(); response.SuccessInfo->AccountExpansionLevel = GetAccountExpansion(); response.SuccessInfo->ActiveExpansionLevel = GetExpansion(); @@ -52,7 +52,7 @@ void WorldSession::SendAuthResponse(uint32 code, bool queued, uint32 queuePos) if (queued) { - response.WaitInfo = boost::in_place(); + response.WaitInfo.emplace(); response.WaitInfo->WaitCount = queuePos; } diff --git a/src/server/game/Handlers/BlackMarketHandler.cpp b/src/server/game/Handlers/BlackMarketHandler.cpp index 6d4ecb33778..9b50fe1824e 100644 --- a/src/server/game/Handlers/BlackMarketHandler.cpp +++ b/src/server/game/Handlers/BlackMarketHandler.cpp @@ -115,7 +115,7 @@ void WorldSession::HandleBlackMarketBidOnItem(WorldPackets::BlackMarket::BlackMa return; } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); sBlackMarketMgr->SendAuctionOutbidMail(entry, trans); entry->PlaceBid(blackMarketBidOnItem.BidAmount, player, trans); diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index bf9ddd12b7b..534c7ed0fec 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -155,7 +155,7 @@ void WorldSession::HandleCalendarAddEvent(WorldPackets::Calendar::CalendarAddEve } else { - SQLTransaction trans; + CharacterDatabaseTransaction trans; if (calendarAddEvent.EventInfo.Invites.size() > 1) trans = CharacterDatabase.BeginTransaction(); @@ -224,7 +224,7 @@ void WorldSession::HandleCalendarCopyEvent(WorldPackets::Calendar::CalendarCopyE sCalendarMgr->AddEvent(newEvent, CALENDAR_SENDTYPE_COPY); CalendarInviteStore invites = sCalendarMgr->GetEventInvites(calendarCopyEvent.EventID); - SQLTransaction trans; + CharacterDatabaseTransaction trans; if (invites.size() > 1) trans = CharacterDatabase.BeginTransaction(); @@ -257,7 +257,7 @@ void WorldSession::HandleCalendarEventInvite(WorldPackets::Calendar::CalendarEve else { // Invitee offline, get data from database - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME); stmt->setString(0, calendarEventInvite.Name); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) { diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index f16464bd532..bc692fa3726 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -60,7 +60,7 @@ #include "Util.h" #include "World.h" -class LoginQueryHolder : public SQLQueryHolder +class LoginQueryHolder : public CharacterDatabaseQueryHolder { private: uint32 m_accountId; @@ -80,7 +80,7 @@ bool LoginQueryHolder::Initialize() bool res = true; ObjectGuid::LowType lowGuid = m_guid.GetCounter(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER); stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_FROM, stmt); @@ -315,7 +315,7 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result) if (!(charInfo.CustomizationFlag == CHAR_CUSTOMIZE_FLAG_CUSTOMIZE)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE)); stmt->setUInt64(1, charInfo.Guid.GetCounter()); CharacterDatabase.Execute(stmt); @@ -361,7 +361,7 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result) void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/) { // remove expired bans - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_BANS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_BANS); CharacterDatabase.Execute(stmt); /// get all the data necessary for loading all characters (along with their pets) on the account @@ -373,7 +373,7 @@ void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters& stmt->setUInt32(0, GetAccountId()); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharEnum, this, std::placeholders::_1))); + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharEnum, this, std::placeholders::_1))); } void WorldSession::HandleCharUndeleteEnum(PreparedQueryResult result) @@ -406,7 +406,7 @@ void WorldSession::HandleCharUndeleteEnum(PreparedQueryResult result) void WorldSession::HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/) { /// get all the data necessary for loading all undeleted characters (along with their pets) on the account - PreparedStatement* stmt = nullptr; + CharacterDatabasePreparedStatement* stmt = nullptr; if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME); else @@ -414,7 +414,7 @@ void WorldSession::HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCha stmt->setUInt32(0, GetAccountId()); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharUndeleteEnum, this, std::placeholders::_1))); + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharUndeleteEnum, this, std::placeholders::_1))); } void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharacter& charCreate) @@ -540,10 +540,10 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact } std::shared_ptr createInfo = charCreate.CreateInfo; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, charCreate.CreateInfo->Name); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result) { if (result) @@ -552,7 +552,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact return; } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SUM_REALM_CHARACTERS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SUM_REALM_CHARACTERS); stmt->setUInt32(0, GetAccountId()); queryCallback.SetNextQuery(LoginDatabase.AsyncQuery(stmt)); }) @@ -571,7 +571,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact return; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); stmt->setUInt32(0, GetAccountId()); queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); }) @@ -711,9 +711,9 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact newChar.SaveToDB(true); createInfo->CharCount += 1; - SQLTransaction trans = LoginDatabase.BeginTransaction(); + LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); stmt->setUInt32(0, GetAccountId()); stmt->setUInt32(1, realm.Id.Realm); trans->Append(stmt); @@ -741,7 +741,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact return; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CREATE_INFO); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CREATE_INFO); stmt->setUInt32(0, GetAccountId()); stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEMON_HUNTER) ? 12 : 1); queryCallback.WithPreparedCallback(std::move(finalizeCharacterCreation)).SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); @@ -837,17 +837,19 @@ void WorldSession::HandleContinuePlayerLogin() return; } - LoginQueryHolder* holder = new LoginQueryHolder(GetAccountId(), m_playerLoading); + std::shared_ptr holder = std::make_shared(GetAccountId(), m_playerLoading); if (!holder->Initialize()) { - delete holder; // delete all unprocessed queries m_playerLoading.Clear(); return; } SendPacket(WorldPackets::Auth::ResumeComms(CONNECTION_TYPE_INSTANCE).Write()); - _charLoginCallback = CharacterDatabase.DelayQueryHolder(holder); + AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& holder) + { + HandlePlayerLogin(dynamic_cast(holder)); + }); } void WorldSession::AbortLogin(WorldPackets::Character::LoginFailureReason reason) @@ -867,9 +869,9 @@ void WorldSession::HandleLoadScreenOpcode(WorldPackets::Character::LoadingScreen // TODO: Do something with this packet } -void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) +void WorldSession::HandlePlayerLogin(LoginQueryHolder const& holder) { - ObjectGuid playerGuid = holder->GetGuid(); + ObjectGuid playerGuid = holder.GetGuid(); Player* pCurrChar = new Player(this); // for send server info and strings (config) @@ -881,7 +883,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) SetPlayer(NULL); KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick delete pCurrChar; // delete it manually - delete holder; // delete all unprocessed queries m_playerLoading.Clear(); return; } @@ -899,7 +900,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) SendPacket(loginVerifyWorld.Write()); // load player specific part before send times - LoadAccountData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA), PER_CHARACTER_CACHE_MASK); + LoadAccountData(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA), PER_CHARACTER_CACHE_MASK); WorldPackets::ClientConfig::AccountDataTimes accountDataTimes; accountDataTimes.PlayerGuid = playerGuid; @@ -938,7 +939,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) } //QueryResult* result = CharacterDatabase.PQuery("SELECT guildid, rank FROM guild_member WHERE guid = '%u'", pCurrChar->GetGUIDLow()); - if (PreparedQueryResult resultGuild = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GUILD)) + if (PreparedQueryResult resultGuild = holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GUILD)) { Field* fields = resultGuild->Fetch(); pCurrChar->SetInGuild(fields[0].GetUInt64()); @@ -1027,13 +1028,13 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) pCurrChar->SendInitialPacketsAfterAddToMap(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ONLINE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ONLINE); stmt->setUInt64(0, pCurrChar->GetGUID().GetCounter()); CharacterDatabase.Execute(stmt); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE); - stmt->setUInt32(0, GetAccountId()); - LoginDatabase.Execute(stmt); + LoginDatabasePreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE); + stmt2->setUInt32(0, GetAccountId()); + LoginDatabase.Execute(stmt2); pCurrChar->SetInGameTime(getMSTime()); @@ -1049,7 +1050,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) sSocialMgr->SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUID(), true); // Place character in world (and load zone) before some object loading - pCurrChar->LoadCorpse(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION)); + pCurrChar->LoadCorpse(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION)); // setting Ghost+speed if dead if (pCurrChar->m_deathState != ALIVE) @@ -1070,17 +1071,17 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) { // Delete all of the player's pet spells - PreparedStatement* stmtSpells = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER); + CharacterDatabasePreparedStatement* stmtSpells = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER); stmtSpells->setUInt64(0, pCurrChar->GetGUID().GetCounter()); CharacterDatabase.Execute(stmtSpells); // Then reset all of the player's pet specualizations - PreparedStatement* stmtSpec = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PET_SPECS_BY_OWNER); + CharacterDatabasePreparedStatement* stmtSpec = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PET_SPECS_BY_OWNER); stmtSpec->setUInt64(0, pCurrChar->GetGUID().GetCounter()); CharacterDatabase.Execute(stmtSpec); } - pCurrChar->LoadPetsFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ALL_PETS)); + pCurrChar->LoadPetsFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ALL_PETS)); // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) pCurrChar->LoadPet(); @@ -1144,8 +1145,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin); TC_METRIC_EVENT("player_events", "Login", pCurrChar->GetName()); - - delete holder; } void WorldSession::SendFeatureSystemStatus() @@ -1165,7 +1164,7 @@ void WorldSession::SendFeatureSystemStatus() features.VoiceEnabled = false; features.BrowserEnabled = false; // Has to be false, otherwise client will crash if "Customer Support" is opened - features.EuropaTicketSystemStatus = boost::in_place(); + features.EuropaTicketSystemStatus.emplace(); features.EuropaTicketSystemStatus->ThrottleState.MaxTries = 10; features.EuropaTicketSystemStatus->ThrottleState.PerMilliseconds = 60000; features.EuropaTicketSystemStatus->ThrottleState.TryCount = 1; @@ -1281,11 +1280,11 @@ void WorldSession::HandleCharRenameOpcode(WorldPackets::Character::CharacterRena } // Ensure that there is no character with the desired new name - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_FREE_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_FREE_NAME); stmt->setUInt64(0, request.RenameInfo->Guid.GetCounter()); stmt->setString(1, request.RenameInfo->NewName); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback(std::bind(&WorldSession::HandleCharRenameCallBack, this, request.RenameInfo, std::placeholders::_1))); } @@ -1310,11 +1309,11 @@ void WorldSession::HandleCharRenameCallBack(std::shared_ptrGuid.GetCounter(); // Update name and at_login flag in the db - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN); stmt->setString(0, renameInfo->NewName); stmt->setUInt16(1, atLoginFlags); stmt->setUInt64(2, lowGuid); @@ -1378,9 +1377,9 @@ void WorldSession::HandleSetPlayerDeclinedNames(WorldPackets::Character::SetPlay for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) CharacterDatabase.EscapeString(packet.DeclinedNames.name[i]); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME); stmt->setUInt64(0, packet.Player.GetCounter()); trans->Append(stmt); @@ -1491,10 +1490,10 @@ void WorldSession::HandleCharCustomizeOpcode(WorldPackets::Character::CharCustom return; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUSTOMIZE_INFO); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUSTOMIZE_INFO); stmt->setUInt64(0, packet.CustomizeInfo->CharGUID.GetCounter()); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback(std::bind(&WorldSession::HandleCharCustomizeCallback, this, packet.CustomizeInfo, std::placeholders::_1))); } @@ -1569,8 +1568,8 @@ void WorldSession::HandleCharCustomizeCallback(std::shared_ptrCharGUID.GetCounter(); @@ -1776,10 +1775,10 @@ void WorldSession::HandleCharRaceOrFactionChangeOpcode(WorldPackets::Character:: return; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS); stmt->setUInt64(0, packet.RaceOrFactionChangeInfo->Guid.GetCounter()); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback(std::bind(&WorldSession::HandleCharRaceOrFactionChangeCallback, this, packet.RaceOrFactionChangeInfo, std::placeholders::_1))); } @@ -1897,8 +1896,8 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(std::shared_ptrGuid.GetCounter(); - PreparedStatement* stmt = nullptr; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabasePreparedStatement* stmt = nullptr; + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // resurrect the character in case he's dead Player::OfflineResurrect(factionChangeInfo->Guid, trans); @@ -2322,11 +2321,11 @@ void WorldSession::HandleRandomizeCharNameOpcode(WorldPackets::Character::Genera void WorldSession::HandleReorderCharacters(WorldPackets::Character::ReorderCharacters& reorderChars) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); for (WorldPackets::Character::ReorderCharacters::ReorderInfo const& reorderInfo : reorderChars.Entries) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_LIST_SLOT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_LIST_SLOT); stmt->setUInt8(0, reorderInfo.NewPosition); stmt->setUInt64(1, reorderInfo.PlayerGUID.GetCounter()); stmt->setUInt32(2, GetAccountId()); @@ -2353,10 +2352,10 @@ void WorldSession::HandleOpeningCinematic(WorldPackets::Misc::OpeningCinematic& void WorldSession::HandleGetUndeleteCooldownStatus(WorldPackets::Character::GetUndeleteCharacterCooldownStatus& /*getCooldown*/) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE); stmt->setUInt32(0, GetBattlenetAccountId()); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleUndeleteCooldownStatusCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleUndeleteCooldownStatusCallback, this, std::placeholders::_1))); } void WorldSession::HandleUndeleteCooldownStatusCallback(PreparedQueryResult result) @@ -2382,11 +2381,11 @@ void WorldSession::HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCha return; } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE); stmt->setUInt32(0, GetBattlenetAccountId()); std::shared_ptr undeleteInfo = undeleteCharacter.UndeleteInfo; - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt) .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result) { if (result) @@ -2400,7 +2399,7 @@ void WorldSession::HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCha } } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID); stmt->setUInt64(0, undeleteInfo->CharacterGuid.GetCounter()); queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); }) @@ -2422,7 +2421,7 @@ void WorldSession::HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCha return; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, undeleteInfo->Name); queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); }) @@ -2440,7 +2439,7 @@ void WorldSession::HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCha /// * max demon hunter count /// * team violation - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); stmt->setUInt32(0, GetAccountId()); queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); }) @@ -2457,15 +2456,15 @@ void WorldSession::HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCha } } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_RESTORE_DELETE_INFO); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_RESTORE_DELETE_INFO); stmt->setString(0, undeleteInfo->Name); stmt->setUInt32(1, GetAccountId()); stmt->setUInt64(2, undeleteInfo->CharacterGuid.GetCounter()); CharacterDatabase.Execute(stmt); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_CHAR_UNDELETE); - stmt->setUInt32(0, GetBattlenetAccountId()); - LoginDatabase.Execute(stmt); + LoginDatabasePreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_CHAR_UNDELETE); + stmt2->setUInt32(0, GetBattlenetAccountId()); + LoginDatabase.Execute(stmt2); sWorld->UpdateCharacterInfoDeleted(undeleteInfo->CharacterGuid, false, &undeleteInfo->Name); @@ -2524,7 +2523,7 @@ void WorldSession::SendCharFactionChange(ResponseCodes result, WorldPackets::Cha if (result == RESPONSE_SUCCESS) { - packet.Display = boost::in_place(); + packet.Display.emplace(); packet.Display->Name = factionChangeInfo->Name; packet.Display->SexID = factionChangeInfo->SexID; packet.Display->SkinID = factionChangeInfo->SkinID; diff --git a/src/server/game/Handlers/GuildFinderHandler.cpp b/src/server/game/Handlers/GuildFinderHandler.cpp index f4b90b2d23d..024cc40d2d8 100644 --- a/src/server/game/Handlers/GuildFinderHandler.cpp +++ b/src/server/game/Handlers/GuildFinderHandler.cpp @@ -144,7 +144,7 @@ void WorldSession::HandleGuildFinderGetGuildPost(WorldPackets::GuildFinder::LFGu if (guild->GetLeaderGUID() == player->GetGUID()) { LFGuildSettings const& settings = sGuildFinderMgr->GetGuildSettings(guild->GetGUID()); - lfGuildPost.Post = boost::in_place(); + lfGuildPost.Post.emplace(); lfGuildPost.Post->Active = settings.IsListed(); lfGuildPost.Post->PlayStyle = settings.GetInterests(); lfGuildPost.Post->Availability = settings.GetAvailability(); diff --git a/src/server/game/Handlers/HotfixHandler.cpp b/src/server/game/Handlers/HotfixHandler.cpp index 0d887769d08..ebf3064673f 100644 --- a/src/server/game/Handlers/HotfixHandler.cpp +++ b/src/server/game/Handlers/HotfixHandler.cpp @@ -75,7 +75,7 @@ void WorldSession::HandleHotfixRequest(WorldPackets::Hotfix::HotfixRequest& hotf hotfixData.RecordID = *hotfix; if (storage->HasRecord(hotfixData.RecordID)) { - hotfixData.Data = boost::in_place(); + hotfixData.Data.emplace(); storage->WriteRecord(hotfixData.RecordID, GetSessionDbcLocale(), *hotfixData.Data); } diff --git a/src/server/game/Handlers/InspectHandler.cpp b/src/server/game/Handlers/InspectHandler.cpp index 2d8c559de51..cf3450b99dd 100644 --- a/src/server/game/Handlers/InspectHandler.cpp +++ b/src/server/game/Handlers/InspectHandler.cpp @@ -66,7 +66,7 @@ void WorldSession::HandleInspectOpcode(WorldPackets::Inspect::Inspect& inspect) if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) { - inspectResult.GuildData = boost::in_place(); + inspectResult.GuildData.emplace(); inspectResult.GuildData->GuildGUID = guild->GetGUID(); inspectResult.GuildData->NumGuildMembers = guild->GetMembersCount(); inspectResult.GuildData->AchievementPoints = guild->GetAchievementMgr().GetAchievementPoints(); diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 64586d4872f..fbb218c1329 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -671,7 +671,7 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid) item.Item.ItemID = vendorItem->item; if (!vendorItem->BonusListIDs.empty()) { - item.Item.ItemBonus = boost::in_place(); + item.Item.ItemBonus.emplace(); item.Item.ItemBonus->BonusListIDs = vendorItem->BonusListIDs; } } @@ -859,9 +859,9 @@ void WorldSession::HandleWrapItem(WorldPackets::Item::WrapItem& packet) return; } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GIFT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GIFT); stmt->setUInt64(0, item->GetOwnerGUID().GetCounter()); stmt->setUInt64(1, item->GetGUID().GetCounter()); stmt->setUInt32(2, item->GetEntry()); diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index 2de568bd9e9..d8752e036ac 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -161,7 +161,7 @@ void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& packet) { receiverTeam = ObjectMgr::GetPlayerTeamByGUID(receiverGuid); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_COUNT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_COUNT); stmt->setUInt64(0, receiverGuid.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -283,7 +283,7 @@ void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& packet) MailDraft draft(packet.Info.Subject, packet.Info.Body); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (!packet.Info.Attachments.empty() || packet.Info.SendMoney > 0) { @@ -395,9 +395,9 @@ void WorldSession::HandleMailReturnToSender(WorldPackets::Mail::MailReturnToSend return; } //we can return mail now, so firstly delete the old one - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); stmt->setUInt32(0, packet.MailID); trans->Append(stmt); @@ -469,7 +469,7 @@ void WorldSession::HandleMailTakeItem(WorldPackets::Mail::MailTakeItem& packet) uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false); if (msg == EQUIP_ERR_OK) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); m->RemoveItem(packet.AttachID); m->removedItems.push_back(packet.AttachID); @@ -559,7 +559,7 @@ void WorldSession::HandleMailTakeMoney(WorldPackets::Mail::MailTakeMoney& packet player->SendMailResult(packet.MailID, MAIL_MONEY_TAKEN, MAIL_OK); // save money and mail to prevent cheating - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); player->SaveGoldToDB(trans); player->_SaveMail(trans); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 08f8ac19dd1..c1f877b23e8 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -714,7 +714,7 @@ void WorldSession::HandleWhoIsOpcode(WorldPackets::Who::WhoIsRequest& packet) return; } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_WHOIS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_WHOIS); stmt->setUInt32(0, player->GetSession()->GetAccountId()); PreparedQueryResult result = LoginDatabase.Query(stmt); diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 9ec3e3eac83..f04e29a8cee 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -520,7 +520,7 @@ void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet) ObjectGuid petguid = packet.RenameData.PetGUID; std::string name = packet.RenameData.NewName; - DeclinedName* declinedname = packet.RenameData.DeclinedNames.get_ptr(); + DeclinedName const* declinedname = std::to_address(packet.RenameData.DeclinedNames); Pet* pet = ObjectAccessor::GetPet(*_player, petguid); // check it! @@ -561,10 +561,10 @@ void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet) } } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (declinedname) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME); stmt->setUInt32(0, pet->GetCharmInfo()->GetPetNumber()); trans->Append(stmt); @@ -578,7 +578,7 @@ void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet) trans->Append(stmt); } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_NAME); stmt->setString(0, name); stmt->setUInt64(1, _player->GetGUID().GetCounter()); stmt->setUInt32(2, pet->GetCharmInfo()->GetPetNumber()); @@ -717,7 +717,7 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& } } -void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName) +void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName const* declinedName) { WorldPackets::Pet::PetNameInvalid petNameInvalid; petNameInvalid.Result = error; @@ -737,7 +737,7 @@ void WorldSession::UpdatePetSlot(uint32 petNumberA, uint8 oldPetSlot, uint8 newP PlayerPetData* playerPetDataA = _player->GetPlayerPetDataById(petNumberA); PlayerPetData* playerPetDataB = _player->GetPlayerPetDataBySlot(newPetSlot); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // If Slot is already in use if (playerPetDataB) @@ -752,7 +752,7 @@ void WorldSession::UpdatePetSlot(uint32 petNumberA, uint8 oldPetSlot, uint8 newP } else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_SLOT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_SLOT); stmt->setUInt32(0, oldPetSlot); stmt->setUInt64(1, _player->GetGUID().GetCounter()); stmt->setUInt32(2, newPetSlot); @@ -771,7 +771,7 @@ void WorldSession::UpdatePetSlot(uint32 petNumberA, uint8 oldPetSlot, uint8 newP } else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID); stmt->setUInt32(0, newPetSlot); stmt->setUInt64(1, _player->GetGUID().GetCounter()); stmt->setUInt32(2, petNumberA); diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp index 6b038746ba4..ed7fd99a80f 100644 --- a/src/server/game/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -105,7 +105,7 @@ void WorldSession::HandlePetitionBuy(WorldPackets::Petition::PetitionBuy& packet // a petition is invalid, if both the owner and the type matches // we checked above, if this player is in an ArenaGroup, so this must be // datacorruption - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_BY_OWNER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_BY_OWNER); stmt->setUInt64(0, _player->GetGUID().GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -125,7 +125,7 @@ void WorldSession::HandlePetitionBuy(WorldPackets::Petition::PetitionBuy& packet TC_LOG_DEBUG("network", "Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); CharacterDatabase.EscapeString(packet.Title); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); trans->PAppend("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); trans->PAppend("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); @@ -146,7 +146,7 @@ void WorldSession::HandlePetitionShowSignatures(WorldPackets::Petition::Petition if (_player->GetGuildId()) return; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); stmt->setUInt64(0, packet.Item.GetCounter()); @@ -198,7 +198,7 @@ void WorldSession::SendPetitionQueryOpcode(ObjectGuid petitionGUID) WorldPackets::Petition::QueryPetitionResponse responsePacket; responsePacket.PetitionID = uint32(petitionGUID.GetCounter()); // PetitionID (in Trinity always same as GUID_LOPART(petition guid)) - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); stmt->setUInt64(0, petitionGUID.GetCounter()); @@ -252,7 +252,7 @@ void WorldSession::HandlePetitionRenameGuild(WorldPackets::Petition::PetitionRen return; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PETITION_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PETITION_NAME); stmt->setString(0, packet.NewGuildName); stmt->setUInt64(1, packet.PetitionGuid.GetCounter()); @@ -269,7 +269,7 @@ void WorldSession::HandlePetitionRenameGuild(WorldPackets::Petition::PetitionRen void WorldSession::HandleSignPetition(WorldPackets::Petition::SignPetition& packet) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURES); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURES); stmt->setUInt64(0, packet.PetitionGUID.GetCounter()); stmt->setUInt64(1, packet.PetitionGUID.GetCounter()); @@ -363,7 +363,7 @@ void WorldSession::HandleDeclinePetition(WorldPackets::Petition::DeclinePetition { TC_LOG_DEBUG("network", "Petition %s declined by %s", packet.PetitionGUID.ToString().c_str(), _player->GetGUID().ToString().c_str()); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_OWNER_BY_GUID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_OWNER_BY_GUID); stmt->setUInt64(0, packet.PetitionGUID.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -411,7 +411,7 @@ void WorldSession::HandleOfferPetition(WorldPackets::Petition::OfferPetition& pa return; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); stmt->setUInt64(0, packet.ItemGUID.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -458,7 +458,7 @@ void WorldSession::HandleTurnInPetition(WorldPackets::Petition::TurnInPetition& ObjectGuid ownerguid; std::string name; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); stmt->setUInt64(0, packet.Item.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -537,7 +537,7 @@ void WorldSession::HandleTurnInPetition(WorldPackets::Petition::TurnInPetition& Guild::SendCommandResult(this, GUILD_COMMAND_CREATE_GUILD, ERR_GUILD_COMMAND_SUCCESS, name); { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Add members from signatures for (uint8 i = 0; i < signatures; ++i) @@ -553,7 +553,7 @@ void WorldSession::HandleTurnInPetition(WorldPackets::Petition::TurnInPetition& CharacterDatabase.CommitTransaction(trans); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_BY_GUID); stmt->setUInt64(0, packet.Item.GetCounter()); diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 6decce77255..9bd5414321d 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -465,7 +465,7 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled { // prepare Quest Tracker datas - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_ABANDON_TIME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_ABANDON_TIME); stmt->setUInt32(0, questId); stmt->setUInt64(1, _player->GetGUID().GetCounter()); diff --git a/src/server/game/Handlers/SocialHandler.cpp b/src/server/game/Handlers/SocialHandler.cpp index 3761d81e945..50dae432ca4 100644 --- a/src/server/game/Handlers/SocialHandler.cpp +++ b/src/server/game/Handlers/SocialHandler.cpp @@ -42,10 +42,10 @@ void WorldSession::HandleAddFriendOpcode(WorldPackets::Social::AddFriend& packet TC_LOG_DEBUG("network", "WorldSession::HandleAddFriendOpcode: %s asked to add friend: %s", GetPlayerInfo().c_str(), packet.Name.c_str()); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME); stmt->setString(0, packet.Name); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback(std::bind(&WorldSession::HandleAddFriendOpcodeCallBack, this, std::move(packet.Notes), std::placeholders::_1))); } @@ -113,10 +113,10 @@ void WorldSession::HandleAddIgnoreOpcode(WorldPackets::Social::AddIgnore& packet TC_LOG_DEBUG("network", "WorldSession::HandleAddIgnoreOpcode: %s asked to Ignore: %s", GetPlayerInfo().c_str(), packet.Name.c_str()); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME); stmt->setString(0, packet.Name); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleAddIgnoreOpcodeCallBack, this, std::placeholders::_1))); + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleAddIgnoreOpcodeCallBack, this, std::placeholders::_1))); } void WorldSession::HandleAddIgnoreOpcodeCallBack(PreparedQueryResult result) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 5170f1b4395..e16bea3f38e 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -185,7 +185,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPackets::Spells::OpenItem& packet) if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))// wrapped? { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM); stmt->setUInt64(0, item->GetGUID().GetCounter()); diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index abb05a2a0c9..5db1191cdaf 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -101,7 +101,7 @@ void WorldSession::SendTaxiMenu(Creature* unit) TC_LOG_DEBUG("network", "WORLD: CMSG_TAXINODE_STATUS_QUERY %u ", curloc); WorldPackets::Taxi::ShowTaxiNodes data; - data.WindowInfo = boost::in_place(); + data.WindowInfo.emplace(); data.WindowInfo->UnitGUID = unit->GetGUID(); data.WindowInfo->CurrentNode = curloc; diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp index 34ad26a0f6c..6ec7271b1a4 100644 --- a/src/server/game/Handlers/TicketHandler.cpp +++ b/src/server/game/Handlers/TicketHandler.cpp @@ -93,7 +93,7 @@ void WorldSession::HandleBugReportOpcode(WorldPackets::Ticket::BugReport& bugRep if (!sSupportMgr->GetBugSystemStatus()) return; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BUG_REPORT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BUG_REPORT); stmt->setString(0, bugReport.Text); stmt->setString(1, bugReport.DiagInfo); CharacterDatabase.Execute(stmt); diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index a58d04bfe3e..244c1c16309 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -70,7 +70,7 @@ void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) tradeItem.GiftCreator = item->GetGuidValue(ITEM_FIELD_GIFTCREATOR); if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { - tradeItem.Unwrapped = boost::in_place(); + tradeItem.Unwrapped.emplace(); tradeItem.Unwrapped->EnchantID = item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT); tradeItem.Unwrapped->OnUseEnchantmentID = item->GetEnchantmentId(USE_ENCHANTMENT_SLOT); @@ -545,7 +545,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPackets::Trade::AcceptTrade& acc trader->m_trade = NULL; // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); _player->SaveInventoryAndGoldToDB(trans); trader->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index e542a19f58d..05f72273a2a 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -137,9 +137,9 @@ InstanceSave* InstanceSaveManager::GetInstanceSave(uint32 InstanceId) void InstanceSaveManager::DeleteInstanceFromDB(uint32 instanceid) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INSTANCE_BY_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INSTANCE_BY_INSTANCE); stmt->setUInt32(0, instanceid); trans->Append(stmt); @@ -167,7 +167,7 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 InstanceId) // save the resettime for normal instances only when they get unloaded if (time_t resettime = itr->second->GetResetTimeForDB()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_INSTANCE_RESETTIME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_INSTANCE_RESETTIME); stmt->setUInt32(0, uint32(resettime)); stmt->setUInt32(1, InstanceId); @@ -220,7 +220,7 @@ void InstanceSave::SaveToDB() scenario->SaveToDB(); } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_INSTANCE_SAVE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_INSTANCE_SAVE); stmt->setUInt32(0, m_instanceid); stmt->setUInt16(1, GetMapId()); stmt->setUInt32(2, uint32(GetResetTimeForDB())); @@ -286,7 +286,7 @@ void InstanceSaveManager::LoadInstances() // Delete invalid character_instance and group_instance references CharacterDatabase.DirectExecute("DELETE ci.* FROM character_instance AS ci LEFT JOIN characters AS c ON ci.guid = c.guid WHERE c.guid IS NULL"); - CharacterDatabase.DirectExecute("DELETE gi.* FROM group_instance AS gi LEFT JOIN groups AS g ON gi.guid = g.guid WHERE g.guid IS NULL"); + CharacterDatabase.DirectExecute("DELETE gi.* FROM group_instance AS gi LEFT JOIN `groups` AS g ON gi.guid = g.guid WHERE g.guid IS NULL"); // Delete invalid instance references CharacterDatabase.DirectExecute("DELETE i.* FROM instance AS i LEFT JOIN character_instance AS ci ON i.id = ci.instance LEFT JOIN group_instance AS gi ON i.id = gi.instance WHERE ci.guid IS NULL AND gi.guid IS NULL"); @@ -664,9 +664,9 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b return; // delete/promote instance binds from the DB, even if not loaded - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF); stmt->setUInt16(0, uint16(mapid)); stmt->setUInt8(1, uint8(difficulty)); trans->Append(stmt); diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index cf046918aec..3cd0b43bba4 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -78,7 +78,7 @@ void InstanceScript::SaveToDB() if (data.empty()) return; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_INSTANCE_DATA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_INSTANCE_DATA); stmt->setUInt32(0, GetCompletedEncounterMask()); stmt->setString(1, data); stmt->setUInt32(2, _entranceId); @@ -1163,7 +1163,7 @@ void InstanceScript::StartChallengeMode(uint8 level) entranceLocation.Relocate(areaTrigger->target_X, areaTrigger->target_Y, areaTrigger->target_Z, areaTrigger->target_Orientation); DoNearTeleportPlayers(entranceLocation); - if (_challengeModeDoorPosition.is_initialized()) + if (_challengeModeDoorPosition.has_value()) instance->SummonGameObject(GOB_CHALLENGER_DOOR, *_challengeModeDoorPosition, QuaternionData(), WEEK); WorldPackets::ChallengeMode::ChangePlayerDifficultyResult changePlayerDifficultyResult(11); diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp index 111236b9743..3e783e1eb52 100644 --- a/src/server/game/Loot/Loot.cpp +++ b/src/server/game/Loot/Loot.cpp @@ -125,7 +125,7 @@ Loot::~Loot() void Loot::DeleteLootItemFromContainerItemDB(uint32 itemID) { // Deletes a single item associated with an openable item from the DB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM); stmt->setUInt64(0, containerID.GetCounter()); stmt->setUInt32(1, itemID); CharacterDatabase.Execute(stmt); @@ -144,7 +144,7 @@ void Loot::DeleteLootItemFromContainerItemDB(uint32 itemID) void Loot::DeleteLootMoneyFromContainerItemDB() { // Deletes money loot associated with an openable item from the DB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); stmt->setUInt64(0, containerID.GetCounter()); CharacterDatabase.Execute(stmt); } diff --git a/src/server/game/Mails/Mail.cpp b/src/server/game/Mails/Mail.cpp index 527d00ca5a3..f7464af6e75 100644 --- a/src/server/game/Mails/Mail.cpp +++ b/src/server/game/Mails/Mail.cpp @@ -95,7 +95,7 @@ MailDraft& MailDraft::AddItem(Item* item) return *this; } -void MailDraft::prepareItems(Player* receiver, SQLTransaction& trans) +void MailDraft::prepareItems(Player* receiver, CharacterDatabaseTransaction& trans) { if (!m_mailTemplateId || !m_mailTemplateItemsNeed) return; @@ -121,7 +121,7 @@ void MailDraft::prepareItems(Player* receiver, SQLTransaction& trans) } } -void MailDraft::deleteIncludedItems(SQLTransaction& trans, bool inDB /*= false*/ ) +void MailDraft::deleteIncludedItems(CharacterDatabaseTransaction& trans, bool inDB /*= false*/ ) { for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { @@ -129,7 +129,7 @@ void MailDraft::deleteIncludedItems(SQLTransaction& trans, bool inDB /*= false*/ if (inDB) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); stmt->setUInt64(0, item->GetGUID().GetCounter()); trans->Append(stmt); } @@ -140,7 +140,7 @@ void MailDraft::deleteIncludedItems(SQLTransaction& trans, bool inDB /*= false*/ m_items.clear(); } -void MailDraft::SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender_guid, ObjectGuid::LowType receiver_guid, SQLTransaction& trans) +void MailDraft::SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender_guid, ObjectGuid::LowType receiver_guid, CharacterDatabaseTransaction& trans) { ObjectGuid receiverGuid = ObjectGuid::Create(receiver_guid); Player* receiver = ObjectAccessor::FindConnectedPlayer(receiverGuid); @@ -169,7 +169,7 @@ void MailDraft::SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender Item* item = mailItemIter->second; item->SaveToDB(trans); // item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER); stmt->setUInt64(0, receiver_guid); stmt->setUInt64(1, item->GetGUID().GetCounter()); trans->Append(stmt); @@ -183,7 +183,7 @@ void MailDraft::SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender SendMailTo(trans, MailReceiver(receiver, receiver_guid), MailSender(MAIL_NORMAL, sender_guid), MAIL_CHECK_MASK_RETURNED, deliver_delay); } -void MailDraft::SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay) +void MailDraft::SendMailTo(CharacterDatabaseTransaction& trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay) { Player* pReceiver = receiver.GetPlayer(); // can be NULL Player* pSender = ObjectAccessor::FindPlayer(ObjectGuid::Create(sender.GetSenderId())); @@ -214,7 +214,7 @@ void MailDraft::SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, // Add to DB uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_MAIL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_MAIL); stmt->setUInt32( index, mailId); stmt->setUInt8 (++index, uint8(sender.GetMailMessageType())); stmt->setInt8 (++index, int8(sender.GetStationery())); @@ -281,13 +281,13 @@ void MailDraft::SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, } else if (!m_items.empty()) { - SQLTransaction temp = SQLTransaction(NULL); + CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(NULL); deleteIncludedItems(temp); } } else if (!m_items.empty()) { - SQLTransaction temp = SQLTransaction(NULL); + CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(NULL); deleteIncludedItems(temp); } } diff --git a/src/server/game/Mails/Mail.h b/src/server/game/Mails/Mail.h index 46cbdc54536..f57b00d0d49 100644 --- a/src/server/game/Mails/Mail.h +++ b/src/server/game/Mails/Mail.h @@ -142,12 +142,12 @@ class TC_GAME_API MailDraft MailDraft& AddCOD(uint64 COD) { m_COD = COD; return *this; } public: // finishers - void SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender_guid, ObjectGuid::LowType receiver_guid, SQLTransaction& trans); - void SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked = MAIL_CHECK_MASK_NONE, uint32 deliver_delay = 0); + void SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender_guid, ObjectGuid::LowType receiver_guid, CharacterDatabaseTransaction& trans); + void SendMailTo(CharacterDatabaseTransaction& trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked = MAIL_CHECK_MASK_NONE, uint32 deliver_delay = 0); private: - void deleteIncludedItems(SQLTransaction& trans, bool inDB = false); - void prepareItems(Player* receiver, SQLTransaction& trans); // called from SendMailTo for generate mailTemplateBase items + void deleteIncludedItems(CharacterDatabaseTransaction& trans, bool inDB = false); + void prepareItems(Player* receiver, CharacterDatabaseTransaction& trans); // called from SendMailTo for generate mailTemplateBase items uint16 m_mailTemplateId; bool m_mailTemplateItemsNeed; diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 9f141309f75..8f2e18209b7 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -3571,7 +3571,7 @@ void InstanceMap::CreateInstanceData(bool load) if (load) { /// @todo make a global storage for this - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_INSTANCE); stmt->setUInt16(0, uint16(GetId())); stmt->setUInt32(1, i_InstanceId); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -3839,7 +3839,7 @@ bool Map::GetEntrancePos(int32 &mapid, float &x, float &y) bool InstanceMap::HasPermBoundPlayers() const { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE); stmt->setUInt16(0,GetInstanceId()); return !!CharacterDatabase.Query(stmt); } @@ -4020,7 +4020,7 @@ void Map::SaveCreatureRespawnTime(ObjectGuid::LowType dbGuid, time_t respawnTime _creatureRespawnTimes[dbGuid] = respawnTime; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CREATURE_RESPAWN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CREATURE_RESPAWN); stmt->setUInt64(0, dbGuid); stmt->setUInt32(1, uint32(respawnTime)); stmt->setUInt16(2, GetId()); @@ -4032,7 +4032,7 @@ void Map::RemoveCreatureRespawnTime(ObjectGuid::LowType dbGuid) { _creatureRespawnTimes.erase(dbGuid); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CREATURE_RESPAWN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CREATURE_RESPAWN); stmt->setUInt64(0, dbGuid); stmt->setUInt16(1, GetId()); stmt->setUInt32(2, GetInstanceId()); @@ -4050,7 +4050,7 @@ void Map::SaveGORespawnTime(ObjectGuid::LowType dbGuid, time_t respawnTime) _goRespawnTimes[dbGuid] = respawnTime; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GO_RESPAWN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GO_RESPAWN); stmt->setUInt64(0, dbGuid); stmt->setUInt32(1, uint32(respawnTime)); stmt->setUInt16(2, GetId()); @@ -4062,7 +4062,7 @@ void Map::RemoveGORespawnTime(ObjectGuid::LowType dbGuid) { _goRespawnTimes.erase(dbGuid); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GO_RESPAWN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GO_RESPAWN); stmt->setUInt64(0, dbGuid); stmt->setUInt16(1, GetId()); stmt->setUInt32(2, GetInstanceId()); @@ -4071,7 +4071,7 @@ void Map::RemoveGORespawnTime(ObjectGuid::LowType dbGuid) void Map::LoadRespawnTimes() { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CREATURE_RESPAWNS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CREATURE_RESPAWNS); stmt->setUInt16(0, GetId()); stmt->setUInt32(1, GetInstanceId()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) @@ -4112,7 +4112,7 @@ void Map::DeleteRespawnTimes() void Map::DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CREATURE_RESPAWN_BY_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CREATURE_RESPAWN_BY_INSTANCE); stmt->setUInt16(0, mapId); stmt->setUInt32(1, instanceId); CharacterDatabase.Execute(stmt); @@ -4143,7 +4143,7 @@ void Map::LoadCorpseData() { std::unordered_map> phases; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_PHASES); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_PHASES); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, GetInstanceId()); @@ -4202,7 +4202,7 @@ void Map::LoadCorpseData() void Map::DeleteCorpseData() { // DELETE cp, c FROM corpse_phases cp INNER JOIN corpse c ON cp.OwnerGuid = c.guid WHERE c.mapId = ? AND c.instanceId = ? - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSES_FROM_MAP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSES_FROM_MAP); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, GetInstanceId()); CharacterDatabase.Execute(stmt); @@ -4248,7 +4248,7 @@ Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*= RemoveCorpse(corpse); // remove corpse from DB - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); corpse->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp index f6dc2f537bb..e41f1cdf664 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.cpp +++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp @@ -95,7 +95,7 @@ void WaypointMgr::ReloadPath(uint32 id) _waypointStore.erase(itr); } - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID); stmt->setUInt32(0, id); diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp index eaaa8dd3375..dbb9166aa33 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp @@ -183,7 +183,7 @@ bool OPvPCapturePoint::DelCreature(uint32 type) //if (Map* map = sMapMgr->FindMap(cr->GetMapId())) // map->Remove(cr, false); // delete respawn time for this creature - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CREATURE_RESPAWN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CREATURE_RESPAWN); stmt->setUInt64(0, spawnId); stmt->setUInt16(1, m_PvP->GetMap()->GetId()); stmt->setUInt32(2, 0); // instance id, always 0 for world maps diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp index 378360105ac..0ebbf654bb1 100644 --- a/src/server/game/Pools/PoolMgr.cpp +++ b/src/server/game/Pools/PoolMgr.cpp @@ -455,7 +455,7 @@ void PoolGroup::SpawnObject(ActivePoolData& spawns, uint32 limit, uint64 // load state from db if (!triggerFrom) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_POOL_QUEST_SAVE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_POOL_QUEST_SAVE); stmt->setUInt32(0, poolId); @@ -808,7 +808,7 @@ void PoolMgr::LoadFromDB() { uint32 oldMSTime = getMSTime(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_QUEST_POOLS); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_QUEST_POOLS); PreparedQueryResult result = WorldDatabase.Query(stmt); if (!result) @@ -976,13 +976,13 @@ void PoolMgr::LoadQuestPools() void PoolMgr::SaveQuestsToDB() { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); for (PoolGroupQuestMap::iterator itr = mPoolQuestGroups.begin(); itr != mPoolQuestGroups.end(); ++itr) { if (itr->second.isEmpty()) continue; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_POOL_SAVE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_POOL_SAVE); stmt->setUInt32(0, itr->second.GetPoolId()); trans->Append(stmt); } @@ -991,7 +991,7 @@ void PoolMgr::SaveQuestsToDB() { if (IsSpawnedObject(itr->first)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_QUEST_POOL_SAVE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_QUEST_POOL_SAVE); stmt->setUInt32(0, itr->second); stmt->setUInt32(1, itr->first); trans->Append(stmt); diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp index 55f605df1df..b6773ab841f 100644 --- a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp @@ -53,9 +53,9 @@ void QuestObjectiveCriteriaMgr::Reset() void QuestObjectiveCriteriaMgr::DeleteFromDB(ObjectGuid const& guid) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA); stmt->setUInt64(0, guid.GetCounter()); trans->Append(stmt); @@ -99,7 +99,7 @@ void QuestObjectiveCriteriaMgr::LoadFromDB(PreparedQueryResult objectiveResult, // Removing non-existing criteria data for all characters TC_LOG_ERROR("criteria.quest", "Non-existing quest objective criteria %u data has been removed from the table `character_queststatus_objectives_criteria_progress`.", criteriaId); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_QUEST_PROGRESS_CRITERIA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_QUEST_PROGRESS_CRITERIA); stmt->setUInt32(0, criteriaId); CharacterDatabase.Execute(stmt); @@ -117,9 +117,9 @@ void QuestObjectiveCriteriaMgr::LoadFromDB(PreparedQueryResult objectiveResult, } } -void QuestObjectiveCriteriaMgr::SaveToDB(SQLTransaction& trans) +void QuestObjectiveCriteriaMgr::SaveToDB(CharacterDatabaseTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA); stmt->setUInt64(0, _owner->GetGUID().GetCounter()); trans->Append(stmt); diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.h b/src/server/game/Quests/QuestObjectiveCriteriaMgr.h index 931f5464024..1a96f99ba96 100644 --- a/src/server/game/Quests/QuestObjectiveCriteriaMgr.h +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.h @@ -32,7 +32,7 @@ class TC_GAME_API QuestObjectiveCriteriaMgr : public CriteriaHandler static void DeleteFromDB(ObjectGuid const& guid); void LoadFromDB(PreparedQueryResult objectiveResult, PreparedQueryResult criteriaResult); - void SaveToDB(SQLTransaction& trans); + void SaveToDB(CharacterDatabaseTransaction& trans); void ResetCriteria(CriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); void ResetCriteriaTree(uint32 criteriaTreeId); diff --git a/src/server/game/Quests/WorldQuestMgr.cpp b/src/server/game/Quests/WorldQuestMgr.cpp index 88170c210b9..8bdbac9f083 100644 --- a/src/server/game/Quests/WorldQuestMgr.cpp +++ b/src/server/game/Quests/WorldQuestMgr.cpp @@ -105,7 +105,7 @@ void WorldQuestMgr::LoadWorldQuestRewardTemplates() void WorldQuestMgr::LoadActiveWorldQuests() { // not asynch, only at startup - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_WORLD_QUEST); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_WORLD_QUEST); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -202,7 +202,7 @@ void WorldQuestMgr::ActivateQuest(WorldQuestTemplate* worldQuestTemplate) player->AddQuest(quest, nullptr); } - PreparedStatement* stmt = nullptr; + CharacterDatabasePreparedStatement* stmt = nullptr; stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_WORLD_QUEST); stmt->setUInt32(0, activeWorldQuest->QuestId); stmt->setUInt32(1, activeWorldQuest->RewardId); @@ -239,7 +239,7 @@ void WorldQuestMgr::DisableQuest(ActiveWorldQuest* activeWorldQuest, bool delete for (auto criteria : GetCriteriasForQuest(quest->GetQuestId())) CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE criteria = %u", criteria->ID); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_WORLD_QUEST); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_WORLD_QUEST); stmt->setUInt32(0, quest->GetQuestId()); CharacterDatabase.Execute(stmt); CharacterDatabase.PExecute("DELETE FROM character_queststatus WHERE quest = %u", quest->GetQuestId()); diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp index 6a1d8253a58..2cef0e5635d 100644 --- a/src/server/game/Reputation/ReputationMgr.cpp +++ b/src/server/game/Reputation/ReputationMgr.cpp @@ -553,13 +553,13 @@ void ReputationMgr::LoadFromDB(PreparedQueryResult result) } } -void ReputationMgr::SaveToDB(SQLTransaction& trans) +void ReputationMgr::SaveToDB(CharacterDatabaseTransaction& trans) { for (FactionStateList::iterator itr = _factions.begin(); itr != _factions.end(); ++itr) { if (itr->second.needSave) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_REPUTATION_BY_FACTION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_REPUTATION_BY_FACTION); stmt->setUInt64(0, _player->GetGUID().GetCounter()); stmt->setUInt16(1, uint16(itr->second.ID)); trans->Append(stmt); diff --git a/src/server/game/Reputation/ReputationMgr.h b/src/server/game/Reputation/ReputationMgr.h index 6a8afb04a55..2e3b7c1df44 100644 --- a/src/server/game/Reputation/ReputationMgr.h +++ b/src/server/game/Reputation/ReputationMgr.h @@ -70,7 +70,7 @@ class TC_GAME_API ReputationMgr _visibleFactionCount(0), _honoredFactionCount(0), _reveredFactionCount(0), _exaltedFactionCount(0), _sendFactionIncreased(false) { } ~ReputationMgr() { } - void SaveToDB(SQLTransaction& trans); + void SaveToDB(CharacterDatabaseTransaction& trans); void LoadFromDB(PreparedQueryResult result); public: // statics static const int32 PointsInRank[MAX_REPUTATION_RANK]; diff --git a/src/server/game/Scenarios/InstanceScenario.cpp b/src/server/game/Scenarios/InstanceScenario.cpp index d1274c55791..e1734ec9ebc 100644 --- a/src/server/game/Scenarios/InstanceScenario.cpp +++ b/src/server/game/Scenarios/InstanceScenario.cpp @@ -53,7 +53,7 @@ void InstanceScenario::SaveToDB() return; } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); for (auto iter = _criteriaProgress.begin(); iter != _criteriaProgress.end(); ++iter) { if (!iter->second.Changed) @@ -71,7 +71,7 @@ void InstanceScenario::SaveToDB() if (iter->second.Counter) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_SCENARIO_INSTANCE_CRITERIA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_SCENARIO_INSTANCE_CRITERIA); stmt->setUInt32(0, id); stmt->setUInt32(1, iter->first); trans->Append(stmt); @@ -92,13 +92,13 @@ void InstanceScenario::SaveToDB() void InstanceScenario::LoadInstanceData(uint32 instanceId) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE); stmt->setUInt32(0, instanceId); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); time_t now = time(nullptr); std::vector criteriaTrees; diff --git a/src/server/game/Scripting/JSEngine.cpp b/src/server/game/Scripting/JSEngine.cpp deleted file mode 100644 index 05fbe20c4e7..00000000000 --- a/src/server/game/Scripting/JSEngine.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2017-2018 AshamaneProject - * - * 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 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - - diff --git a/src/server/game/Scripting/ScriptReloadMgr.cpp b/src/server/game/Scripting/ScriptReloadMgr.cpp index 7fcbcc7566d..a39adc83cee 100644 --- a/src/server/game/Scripting/ScriptReloadMgr.cpp +++ b/src/server/game/Scripting/ScriptReloadMgr.cpp @@ -275,7 +275,7 @@ Optional> path.generic_string().c_str()); } - return boost::none; + return std::nullopt; } // Use RAII to release the library on failure. @@ -302,7 +302,7 @@ Optional> TC_LOG_ERROR("scripts.hotswap", "Could not extract all required functions from the shared library \"%s\"!", path.generic_string().c_str()); - return boost::none; + return std::nullopt; } } diff --git a/src/server/game/Server/Packets/AreaTriggerPackets.cpp b/src/server/game/Server/Packets/AreaTriggerPackets.cpp index f99d9831f91..24ba1770eb7 100644 --- a/src/server/game/Server/Packets/AreaTriggerPackets.cpp +++ b/src/server/game/Server/Packets/AreaTriggerPackets.cpp @@ -33,8 +33,8 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::AreaTrigger::AreaTriggerS ByteBuffer& operator<<(ByteBuffer& data, AreaTriggerCircularMovementInfo const& areaTriggerCircularMovement) { - data.WriteBit(areaTriggerCircularMovement.TargetGUID.is_initialized()); - data.WriteBit(areaTriggerCircularMovement.Center.is_initialized()); + data.WriteBit(areaTriggerCircularMovement.TargetGUID.has_value()); + data.WriteBit(areaTriggerCircularMovement.Center.has_value()); data.WriteBit(areaTriggerCircularMovement.CounterClockwise); data.WriteBit(areaTriggerCircularMovement.CanLoop); @@ -83,8 +83,8 @@ WorldPacket const* WorldPackets::AreaTrigger::AreaTriggerReShape::Write() { _worldPacket << TriggerGUID; - _worldPacket.WriteBit(AreaTriggerSpline.is_initialized()); - _worldPacket.WriteBit(AreaTriggerCircularMovement.is_initialized()); + _worldPacket.WriteBit(AreaTriggerSpline.has_value()); + _worldPacket.WriteBit(AreaTriggerCircularMovement.has_value()); _worldPacket.FlushBits(); if (AreaTriggerSpline) diff --git a/src/server/game/Server/Packets/AuthenticationPackets.cpp b/src/server/game/Server/Packets/AuthenticationPackets.cpp index c28b8281ede..ba8ef1fb06c 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.cpp +++ b/src/server/game/Server/Packets/AuthenticationPackets.cpp @@ -118,8 +118,8 @@ WorldPackets::Auth::AuthResponse::AuthResponse() WorldPacket const* WorldPackets::Auth::AuthResponse::Write() { _worldPacket << uint32(Result); - _worldPacket.WriteBit(SuccessInfo.is_initialized()); - _worldPacket.WriteBit(WaitInfo.is_initialized()); + _worldPacket.WriteBit(SuccessInfo.has_value()); + _worldPacket.WriteBit(WaitInfo.has_value()); _worldPacket.FlushBits(); if (SuccessInfo) @@ -143,8 +143,8 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() _worldPacket.WriteBit(SuccessInfo->IsExpansionTrial); _worldPacket.WriteBit(SuccessInfo->ForceCharacterTemplate); - _worldPacket.WriteBit(SuccessInfo->NumPlayersHorde.is_initialized()); - _worldPacket.WriteBit(SuccessInfo->NumPlayersAlliance.is_initialized()); + _worldPacket.WriteBit(SuccessInfo->NumPlayersHorde.has_value()); + _worldPacket.WriteBit(SuccessInfo->NumPlayersAlliance.has_value()); _worldPacket.FlushBits(); { diff --git a/src/server/game/Server/Packets/AuthenticationPackets.h b/src/server/game/Server/Packets/AuthenticationPackets.h index 97662944f09..a36aa999746 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.h +++ b/src/server/game/Server/Packets/AuthenticationPackets.h @@ -131,6 +131,8 @@ namespace WorldPackets public: struct AuthSuccessInfo { + AuthSuccessInfo() { } // allows emplace() with clang + struct BillingInfo { uint32 BillingPlan = 0; diff --git a/src/server/game/Server/Packets/BattlePetPackets.cpp b/src/server/game/Server/Packets/BattlePetPackets.cpp index 93e3f43cdcc..577d6773d75 100644 --- a/src/server/game/Server/Packets/BattlePetPackets.cpp +++ b/src/server/game/Server/Packets/BattlePetPackets.cpp @@ -44,7 +44,7 @@ ByteBuffer& operator<<(ByteBuffer& data, ::BattlePet const& pet) data << uint32(pet.Speed); data << uint8(pet.Quality); data.WriteBits(pet.Name.size(), 7); - data.WriteBit(pet.OwnerInfo.is_initialized()); + data.WriteBit(pet.OwnerInfo.has_value()); data.WriteBit(pet.Name.empty()); // NoRename data.FlushBits(); diff --git a/src/server/game/Server/Packets/BattlegroundPackets.cpp b/src/server/game/Server/Packets/BattlegroundPackets.cpp index 905e99b5018..8e8ce5861ec 100644 --- a/src/server/game/Server/Packets/BattlegroundPackets.cpp +++ b/src/server/game/Server/Packets/BattlegroundPackets.cpp @@ -75,11 +75,11 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::PVPLogData: data.WriteBit(playerData.Faction != 0); data.WriteBit(playerData.IsInWorld); - data.WriteBit(playerData.Honor.is_initialized()); - data.WriteBit(playerData.PreMatchRating.is_initialized()); - data.WriteBit(playerData.RatingChange.is_initialized()); - data.WriteBit(playerData.PreMatchMMR.is_initialized()); - data.WriteBit(playerData.MmrChange.is_initialized()); + data.WriteBit(playerData.Honor.has_value()); + data.WriteBit(playerData.PreMatchRating.has_value()); + data.WriteBit(playerData.RatingChange.has_value()); + data.WriteBit(playerData.PreMatchMMR.has_value()); + data.WriteBit(playerData.MmrChange.has_value()); data.FlushBits(); if (playerData.Honor) @@ -104,12 +104,12 @@ WorldPacket const* WorldPackets::Battleground::PVPLogData::Write() { _worldPacket.reserve(Players.size() * sizeof(PlayerData) + sizeof(PVPLogData)); - _worldPacket.WriteBit(Ratings.is_initialized()); - _worldPacket.WriteBit(Winner.is_initialized()); + _worldPacket.WriteBit(Ratings.has_value()); + _worldPacket.WriteBit(Winner.has_value()); _worldPacket << uint32(Players.size()); _worldPacket.append(PlayerCount, 2); - if (Ratings.is_initialized()) + if (Ratings.has_value()) _worldPacket << *Ratings; if (Winner) diff --git a/src/server/game/Server/Packets/BattlegroundPackets.h b/src/server/game/Server/Packets/BattlegroundPackets.h index e37b6b9fad7..24c64ecc7d3 100644 --- a/src/server/game/Server/Packets/BattlegroundPackets.h +++ b/src/server/game/Server/Packets/BattlegroundPackets.h @@ -97,6 +97,8 @@ namespace WorldPackets struct RatingData { + RatingData() { } // allows emplace() with clang + int32 Prematch[2] = { }; int32 Postmatch[2] = { }; int32 PrematchMMR[2] = { }; @@ -104,6 +106,8 @@ namespace WorldPackets struct HonorData { + HonorData() { } // allows emplace() with clang + uint32 HonorKills = 0; uint32 Deaths = 0; uint32 ContributionPoints = 0; diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index 538a2c7e1d5..522b1be105a 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -204,7 +204,7 @@ WorldPacket const* WorldPackets::Character::EnumCharactersResult::Write() _worldPacket.WriteBit(IsDemonHunterCreationAllowed); _worldPacket.WriteBit(HasDemonHunterOnRealm); _worldPacket.WriteBit(Unknown7x); - _worldPacket.WriteBit(DisabledClassesMask.is_initialized()); + _worldPacket.WriteBit(DisabledClassesMask.has_value()); _worldPacket.WriteBit(IsAlliedRacesCreationAllowed); _worldPacket << uint32(Characters.size()); _worldPacket << int32(MaxCharacterLevel); @@ -270,7 +270,7 @@ void WorldPackets::Character::CharacterRenameRequest::Read() WorldPacket const* WorldPackets::Character::CharacterRenameResult::Write() { _worldPacket << uint8(Result); - _worldPacket.WriteBit(Guid.is_initialized()); + _worldPacket.WriteBit(Guid.has_value()); _worldPacket.WriteBits(Name.length(), 6); _worldPacket.FlushBits(); @@ -320,7 +320,7 @@ WorldPacket const* WorldPackets::Character::CharFactionChangeResult::Write() { _worldPacket << uint8(Result); _worldPacket << Guid; - _worldPacket.WriteBit(Display.is_initialized()); + _worldPacket.WriteBit(Display.has_value()); _worldPacket.FlushBits(); if (Display) diff --git a/src/server/game/Server/Packets/CharacterPackets.h b/src/server/game/Server/Packets/CharacterPackets.h index 31fe579e24f..09ec4f68c93 100644 --- a/src/server/game/Server/Packets/CharacterPackets.h +++ b/src/server/game/Server/Packets/CharacterPackets.h @@ -328,6 +328,8 @@ namespace WorldPackets public: struct CharFactionChangeDisplayInfo { + CharFactionChangeDisplayInfo() { } // allows emplace() with clang + std::string Name; uint8 SexID = 0; uint8 SkinID = 0; diff --git a/src/server/game/Server/Packets/CombatLogPackets.cpp b/src/server/game/Server/Packets/CombatLogPackets.cpp index 22196336960..618b2769ebb 100644 --- a/src/server/game/Server/Packets/CombatLogPackets.cpp +++ b/src/server/game/Server/Packets/CombatLogPackets.cpp @@ -35,7 +35,7 @@ WorldPacket const* WorldPackets::CombatLog::SpellNonMeleeDamageLog::Write() WriteBits(Flags, 7); WriteBit(false); // Debug info WriteLogDataBit(); - WriteBit(SandboxScaling.is_initialized()); + WriteBit(SandboxScaling.has_value()); FlushBits(); WriteLogData(); if (SandboxScaling) @@ -122,10 +122,10 @@ WorldPacket const* WorldPackets::CombatLog::SpellHealLog::Write() *this << int32(OverHeal); *this << int32(Absorbed); WriteBit(Crit); - WriteBit(CritRollMade.is_initialized()); - WriteBit(CritRollNeeded.is_initialized()); + WriteBit(CritRollMade.has_value()); + WriteBit(CritRollNeeded.has_value()); WriteLogDataBit(); - WriteBit(SandboxScaling.is_initialized()); + WriteBit(SandboxScaling.has_value()); FlushBits(); WriteLogData(); @@ -160,8 +160,8 @@ WorldPacket const* WorldPackets::CombatLog::SpellPeriodicAuraLog::Write() *this << int32(effect.AbsorbedOrAmplitude); *this << int32(effect.Resisted); WriteBit(effect.Crit); - WriteBit(effect.DebugInfo.is_initialized()); - WriteBit(effect.SandboxScaling.is_initialized()); + WriteBit(effect.DebugInfo.has_value()); + WriteBit(effect.SandboxScaling.has_value()); FlushBits(); if (effect.SandboxScaling) @@ -227,7 +227,7 @@ ByteBuffer& operator<<(ByteBuffer& buffer, WorldPackets::CombatLog::SpellLogMiss { buffer << missEntry.Victim; buffer << uint8(missEntry.MissReason); - if (buffer.WriteBit(missEntry.Debug.is_initialized())) + if (buffer.WriteBit(missEntry.Debug.has_value())) buffer << *missEntry.Debug; buffer.FlushBits(); @@ -250,8 +250,8 @@ WorldPacket const* WorldPackets::CombatLog::ProcResist::Write() _worldPacket << Caster; _worldPacket << Target; _worldPacket << int32(SpellID); - _worldPacket.WriteBit(Rolled.is_initialized()); - _worldPacket.WriteBit(Needed.is_initialized()); + _worldPacket.WriteBit(Rolled.has_value()); + _worldPacket.WriteBit(Needed.has_value()); _worldPacket.FlushBits(); if (Rolled) @@ -298,7 +298,7 @@ WorldPacket const* WorldPackets::CombatLog::AttackerStateUpdate::Write() attackRoundInfo << VictimGUID; attackRoundInfo << int32(Damage); attackRoundInfo << int32(OverDamage); - attackRoundInfo << uint8(SubDmg.is_initialized()); + attackRoundInfo << uint8(SubDmg.has_value()); if (SubDmg) { attackRoundInfo << int32(SubDmg->SchoolMask); @@ -363,11 +363,11 @@ ByteBuffer& operator<<(ByteBuffer& buffer, WorldPackets::CombatLog::SpellDispell { buffer << int32(dispellData.SpellID); buffer.WriteBit(dispellData.Harmful); - buffer.WriteBit(dispellData.Rolled.is_initialized()); - buffer.WriteBit(dispellData.Needed.is_initialized()); - if (dispellData.Rolled.is_initialized()) + buffer.WriteBit(dispellData.Rolled.has_value()); + buffer.WriteBit(dispellData.Needed.has_value()); + if (dispellData.Rolled.has_value()) buffer << int32(*dispellData.Rolled); - if (dispellData.Needed.is_initialized()) + if (dispellData.Needed.has_value()) buffer << int32(*dispellData.Needed); buffer.FlushBits(); diff --git a/src/server/game/Server/Packets/GuildFinderPackets.cpp b/src/server/game/Server/Packets/GuildFinderPackets.cpp index ac8bcfea9df..fce463ea08b 100644 --- a/src/server/game/Server/Packets/GuildFinderPackets.cpp +++ b/src/server/game/Server/Packets/GuildFinderPackets.cpp @@ -115,7 +115,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::GuildFinder::GuildPostDat WorldPacket const* WorldPackets::GuildFinder::LFGuildPost::Write() { - _worldPacket.WriteBit(Post.is_initialized()); + _worldPacket.WriteBit(Post.has_value()); _worldPacket.FlushBits(); if (Post) _worldPacket << *Post; diff --git a/src/server/game/Server/Packets/GuildPackets.cpp b/src/server/game/Server/Packets/GuildPackets.cpp index ea38da9180f..3bf6b27d0c5 100644 --- a/src/server/game/Server/Packets/GuildPackets.cpp +++ b/src/server/game/Server/Packets/GuildPackets.cpp @@ -29,7 +29,7 @@ WorldPackets::Guild::QueryGuildInfoResponse::QueryGuildInfoResponse() WorldPacket const* WorldPackets::Guild::QueryGuildInfoResponse::Write() { _worldPacket << GuildGuid; - _worldPacket.WriteBit(Info.is_initialized()); + _worldPacket.WriteBit(Info.has_value()); _worldPacket.FlushBits(); if (Info) @@ -715,7 +715,7 @@ WorldPacket const* WorldPackets::Guild::GuildBankLogQueryResults::Write() { _worldPacket << Tab; _worldPacket << uint32(Entry.size()); - _worldPacket.WriteBit(WeeklyBonusMoney.is_initialized()); + _worldPacket.WriteBit(WeeklyBonusMoney.has_value()); _worldPacket.FlushBits(); for (GuildBankLogEntry const& logEntry : Entry) @@ -724,22 +724,22 @@ WorldPacket const* WorldPackets::Guild::GuildBankLogQueryResults::Write() _worldPacket << logEntry.TimeOffset; _worldPacket << logEntry.EntryType; - _worldPacket.WriteBit(logEntry.Money.is_initialized()); - _worldPacket.WriteBit(logEntry.ItemID.is_initialized()); - _worldPacket.WriteBit(logEntry.Count.is_initialized()); - _worldPacket.WriteBit(logEntry.OtherTab.is_initialized()); + _worldPacket.WriteBit(logEntry.Money.has_value()); + _worldPacket.WriteBit(logEntry.ItemID.has_value()); + _worldPacket.WriteBit(logEntry.Count.has_value()); + _worldPacket.WriteBit(logEntry.OtherTab.has_value()); _worldPacket.FlushBits(); - if (logEntry.Money.is_initialized()) + if (logEntry.Money.has_value()) _worldPacket << *logEntry.Money; - if (logEntry.ItemID.is_initialized()) + if (logEntry.ItemID.has_value()) _worldPacket << *logEntry.ItemID; - if (logEntry.Count.is_initialized()) + if (logEntry.Count.has_value()) _worldPacket << *logEntry.Count; - if (logEntry.OtherTab.is_initialized()) + if (logEntry.OtherTab.has_value()) _worldPacket << *logEntry.OtherTab; } @@ -793,7 +793,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Guild::GuildNewsEvent con for (ObjectGuid memberGuid : newsEvent.MemberList) data << memberGuid; - data.WriteBit(newsEvent.Item.is_initialized()); + data.WriteBit(newsEvent.Item.has_value()); data.FlushBits(); if (newsEvent.Item) diff --git a/src/server/game/Server/Packets/GuildPackets.h b/src/server/game/Server/Packets/GuildPackets.h index 63d749f0192..d2eaec847f3 100644 --- a/src/server/game/Server/Packets/GuildPackets.h +++ b/src/server/game/Server/Packets/GuildPackets.h @@ -43,6 +43,8 @@ namespace WorldPackets public: struct GuildInfo { + GuildInfo() { } // allows emplace() with clang + ObjectGuid GuildGUID; uint32 VirtualRealmAddress = 0; ///< a special identifier made from the Index, BattleGroup and Region. diff --git a/src/server/game/Server/Packets/HotfixPackets.cpp b/src/server/game/Server/Packets/HotfixPackets.cpp index e3555e8ba3b..41b3fd42a25 100644 --- a/src/server/game/Server/Packets/HotfixPackets.cpp +++ b/src/server/game/Server/Packets/HotfixPackets.cpp @@ -69,7 +69,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Hotfix::HotfixResponse::H { data << uint64(hotfixData.ID); data << int32(hotfixData.RecordID); - data.WriteBit(hotfixData.Data.is_initialized()); + data.WriteBit(hotfixData.Data.has_value()); if (hotfixData.Data) { data << uint32(hotfixData.Data->size()); diff --git a/src/server/game/Server/Packets/InspectPackets.cpp b/src/server/game/Server/Packets/InspectPackets.cpp index df9b540e164..6909be6df21 100644 --- a/src/server/game/Server/Packets/InspectPackets.cpp +++ b/src/server/game/Server/Packets/InspectPackets.cpp @@ -102,7 +102,7 @@ WorldPacket const* WorldPackets::Inspect::InspectResult::Write() if (!PvpTalents.empty()) _worldPacket.append(PvpTalents.data(), PvpTalents.size()); - _worldPacket.WriteBit(GuildData.is_initialized()); + _worldPacket.WriteBit(GuildData.has_value()); _worldPacket.FlushBits(); for (size_t i = 0; i < Items.size(); ++i) diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index 87599873de5..2e241498174 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -106,7 +106,7 @@ WorldPacket const* WorldPackets::Item::ItemPurchaseRefundResult::Write() { _worldPacket << ItemGUID; _worldPacket << uint8(Result); - _worldPacket.WriteBit(Contents.is_initialized()); + _worldPacket.WriteBit(Contents.has_value()); _worldPacket.FlushBits(); if (Contents) _worldPacket << *Contents; diff --git a/src/server/game/Server/Packets/ItemPacketsCommon.cpp b/src/server/game/Server/Packets/ItemPacketsCommon.cpp index c0c5e84c3d7..a226036f8de 100644 --- a/src/server/game/Server/Packets/ItemPacketsCommon.cpp +++ b/src/server/game/Server/Packets/ItemPacketsCommon.cpp @@ -38,14 +38,14 @@ void WorldPackets::Item::ItemInstance::Initialize(::Item const* item) std::vector const& bonusListIds = item->GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS); if (!bonusListIds.empty()) { - ItemBonus = boost::in_place(); + ItemBonus.emplace(); ItemBonus->BonusListIDs.insert(ItemBonus->BonusListIDs.end(), bonusListIds.begin(), bonusListIds.end()); ItemBonus->Context = item->GetUInt32Value(ITEM_FIELD_CONTEXT); } if (uint32 mask = item->GetUInt32Value(ITEM_FIELD_MODIFIERS_MASK)) { - Modifications = boost::in_place(); + Modifications.emplace(); for (size_t i = 0; mask != 0; mask >>= 1, ++i) if ((mask & 1) != 0) @@ -76,14 +76,14 @@ void WorldPackets::Item::ItemInstance::Initialize(::LootItem const& lootItem) if (!lootItem.BonusListIDs.empty()) { - ItemBonus = boost::in_place(); + ItemBonus.emplace(); ItemBonus->BonusListIDs = lootItem.BonusListIDs; ItemBonus->Context = lootItem.context; } if (lootItem.upgradeId) { - Modifications = boost::in_place(); + Modifications.emplace(); Modifications->Insert(ITEM_MODIFIER_UPGRADE_ID, lootItem.upgradeId); } } @@ -97,7 +97,7 @@ void WorldPackets::Item::ItemInstance::Initialize(::VoidStorageItem const* voidI if (voidItem->ItemUpgradeId || voidItem->FixedScalingLevel || voidItem->ArtifactKnowledgeLevel) { - Modifications = boost::in_place(); + Modifications.emplace(); if (voidItem->ItemUpgradeId) Modifications->Insert(ITEM_MODIFIER_UPGRADE_ID, voidItem->ItemUpgradeId); if (voidItem->FixedScalingLevel) @@ -108,7 +108,7 @@ void WorldPackets::Item::ItemInstance::Initialize(::VoidStorageItem const* voidI if (!voidItem->BonusListIDs.empty()) { - ItemBonus = boost::in_place(); + ItemBonus.emplace(); ItemBonus->Context = voidItem->Context; ItemBonus->BonusListIDs = voidItem->BonusListIDs; } @@ -119,13 +119,13 @@ bool WorldPackets::Item::ItemInstance::operator==(ItemInstance const& r) const if (ItemID != r.ItemID || RandomPropertiesID != r.RandomPropertiesID || RandomPropertiesSeed != r.RandomPropertiesSeed) return false; - if (ItemBonus.is_initialized() != r.ItemBonus.is_initialized() || Modifications.is_initialized() != r.Modifications.is_initialized()) + if (ItemBonus.has_value() != r.ItemBonus.has_value() || Modifications.has_value() != r.Modifications.has_value()) return false; - if (Modifications.is_initialized() && *Modifications != *r.Modifications) + if (Modifications.has_value() && *Modifications != *r.Modifications) return false; - if (ItemBonus.is_initialized() && *ItemBonus != *r.ItemBonus) + if (ItemBonus.has_value() && *ItemBonus != *r.ItemBonus) return false; return true; @@ -164,8 +164,8 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Item::ItemInstance const& data << int32(itemInstance.RandomPropertiesSeed); data << int32(itemInstance.RandomPropertiesID); - data.WriteBit(itemInstance.ItemBonus.is_initialized()); - data.WriteBit(itemInstance.Modifications.is_initialized()); + data.WriteBit(itemInstance.ItemBonus.has_value()); + data.WriteBit(itemInstance.Modifications.has_value()); data.FlushBits(); if (itemInstance.ItemBonus) @@ -189,13 +189,13 @@ ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Item::ItemInstance& itemI if (hasItemBonus) { - itemInstance.ItemBonus = boost::in_place(); + itemInstance.ItemBonus.emplace(); data >> *itemInstance.ItemBonus; } if (hasModifications) { - itemInstance.Modifications = boost::in_place(); + itemInstance.Modifications.emplace(); data >> *itemInstance.Modifications; } diff --git a/src/server/game/Server/Packets/LFGPackets.cpp b/src/server/game/Server/Packets/LFGPackets.cpp index 5b8d66afd6a..dd2807811b2 100644 --- a/src/server/game/Server/Packets/LFGPackets.cpp +++ b/src/server/game/Server/Packets/LFGPackets.cpp @@ -75,7 +75,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LFGBlackListSlot con ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LFGBlackList const& blackList) { - data.WriteBit(blackList.PlayerGuid.is_initialized()); + data.WriteBit(blackList.PlayerGuid.has_value()); data << uint32(blackList.Slot.size()); if (blackList.PlayerGuid) data << *blackList.PlayerGuid; @@ -120,10 +120,10 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LfgPlayerQuestReward for (WorldPackets::LFG::LfgPlayerQuestRewardCurrency const& bonusCurrency : playerQuestReward.BonusCurrency) data << bonusCurrency; - data.WriteBit(playerQuestReward.RewardSpellID.is_initialized()); - data.WriteBit(playerQuestReward.Unused1.is_initialized()); - data.WriteBit(playerQuestReward.Unused2.is_initialized()); - data.WriteBit(playerQuestReward.Honor.is_initialized()); + data.WriteBit(playerQuestReward.RewardSpellID.has_value()); + data.WriteBit(playerQuestReward.Unused1.has_value()); + data.WriteBit(playerQuestReward.Unused2.has_value()); + data.WriteBit(playerQuestReward.Honor.has_value()); data.FlushBits(); if (playerQuestReward.RewardSpellID) diff --git a/src/server/game/Server/Packets/LootPackets.cpp b/src/server/game/Server/Packets/LootPackets.cpp index 0a789044ae5..89c24736808 100644 --- a/src/server/game/Server/Packets/LootPackets.cpp +++ b/src/server/game/Server/Packets/LootPackets.cpp @@ -129,8 +129,8 @@ WorldPacket const* WorldPackets::Loot::LootList::Write() _worldPacket << Owner; _worldPacket << LootObj; - _worldPacket.WriteBit(Master.is_initialized()); - _worldPacket.WriteBit(RoundRobinWinner.is_initialized()); + _worldPacket.WriteBit(Master.has_value()); + _worldPacket.WriteBit(RoundRobinWinner.has_value()); _worldPacket.FlushBits(); diff --git a/src/server/game/Server/Packets/MailPackets.cpp b/src/server/game/Server/Packets/MailPackets.cpp index da2ccbbb0ac..d208fd88ebf 100644 --- a/src/server/game/Server/Packets/MailPackets.cpp +++ b/src/server/game/Server/Packets/MailPackets.cpp @@ -123,8 +123,8 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Mail::MailListEntry const data << float(entry.DaysLeft); data << int32(entry.MailTemplateID); data << uint32(entry.Attachments.size()); - data.WriteBit(entry.SenderCharacter.is_initialized()); - data.WriteBit(entry.AltSenderID.is_initialized()); + data.WriteBit(entry.SenderCharacter.has_value()); + data.WriteBit(entry.AltSenderID.has_value()); data.WriteBits(entry.Subject.size(), 8); data.WriteBits(entry.Body.size(), 13); data.FlushBits(); diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index 0e7ae7b07c5..4a13e6cc05c 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -51,9 +51,9 @@ WorldPacket const* WorldPackets::Misc::SetCurrency::Write() _worldPacket << int32(Type); _worldPacket << int32(Quantity); _worldPacket << uint32(Flags); - _worldPacket.WriteBit(WeeklyQuantity.is_initialized()); - _worldPacket.WriteBit(TrackedQuantity.is_initialized()); - _worldPacket.WriteBit(MaxQuantity.is_initialized()); + _worldPacket.WriteBit(WeeklyQuantity.has_value()); + _worldPacket.WriteBit(TrackedQuantity.has_value()); + _worldPacket.WriteBit(MaxQuantity.has_value()); _worldPacket.WriteBit(SuppressChatLog); _worldPacket.FlushBits(); @@ -83,10 +83,10 @@ WorldPacket const* WorldPackets::Misc::SetupCurrency::Write() _worldPacket << int32(data.Type); _worldPacket << int32(data.Quantity); - _worldPacket.WriteBit(data.WeeklyQuantity.is_initialized()); - _worldPacket.WriteBit(data.MaxWeeklyQuantity.is_initialized()); - _worldPacket.WriteBit(data.TrackedQuantity.is_initialized()); - _worldPacket.WriteBit(data.MaxQuantity.is_initialized()); + _worldPacket.WriteBit(data.WeeklyQuantity.has_value()); + _worldPacket.WriteBit(data.MaxWeeklyQuantity.has_value()); + _worldPacket.WriteBit(data.TrackedQuantity.has_value()); + _worldPacket.WriteBit(data.MaxQuantity.has_value()); _worldPacket.WriteBits(data.Flags, 5); _worldPacket.FlushBits(); @@ -166,9 +166,9 @@ WorldPacket const* WorldPackets::Misc::WorldServerInfo::Write() _worldPacket << uint32(DifficultyID); _worldPacket << uint8(IsTournamentRealm); _worldPacket.WriteBit(XRealmPvpAlert); - _worldPacket.WriteBit(RestrictedAccountMaxLevel.is_initialized()); - _worldPacket.WriteBit(RestrictedAccountMaxMoney.is_initialized()); - _worldPacket.WriteBit(InstanceGroupSize.is_initialized()); + _worldPacket.WriteBit(RestrictedAccountMaxLevel.has_value()); + _worldPacket.WriteBit(RestrictedAccountMaxMoney.has_value()); + _worldPacket.WriteBit(InstanceGroupSize.has_value()); if (RestrictedAccountMaxLevel) _worldPacket << uint32(*RestrictedAccountMaxLevel); @@ -674,8 +674,8 @@ WorldPacket const* WorldPackets::Misc::OverrideLight::Write() WorldPacket const* WorldPackets::Misc::DisplayGameError::Write() { _worldPacket << uint32(Error); - _worldPacket.WriteBit(Arg.is_initialized()); - _worldPacket.WriteBit(Arg2.is_initialized()); + _worldPacket.WriteBit(Arg.has_value()); + _worldPacket.WriteBit(Arg2.has_value()); _worldPacket.FlushBits(); if (Arg) diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp index 8792d27df20..92ba0e3d3ad 100644 --- a/src/server/game/Server/Packets/MovementPackets.cpp +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -233,8 +233,8 @@ ByteBuffer& WorldPackets::operator<<(ByteBuffer& data, Movement::MovementSpline data.WriteBits(movementSpline.Face, 2); data.WriteBits(movementSpline.Points.size(), 16); data.WriteBits(movementSpline.PackedDeltas.size(), 16); - data.WriteBit(movementSpline.SplineFilter.is_initialized()); - data.WriteBit(movementSpline.SpellEffectExtraData.is_initialized()); + data.WriteBit(movementSpline.SplineFilter.has_value()); + data.WriteBit(movementSpline.SpellEffectExtraData.has_value()); data.FlushBits(); if (movementSpline.SplineFilter) @@ -305,7 +305,7 @@ void WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(:: data.WriteBits(moveSpline.getPath().size(), 16); data.WriteBits(uint8(moveSpline.spline.mode()), 2); // Mode data.WriteBit(0); // HasSplineFilter - data.WriteBit(moveSpline.spell_effect_extra.is_initialized()); // HasSpellEffectExtraData + data.WriteBit(moveSpline.spell_effect_extra.has_value()); // HasSpellEffectExtraData data.FlushBits(); //if (HasSplineFilterKey) @@ -397,7 +397,7 @@ void WorldPackets::Movement::MonsterMove::InitializeSplineData(::Movement::MoveS if (moveSpline.spell_effect_extra) { - movementSpline.SpellEffectExtraData = boost::in_place(); + movementSpline.SpellEffectExtraData.emplace(); movementSpline.SpellEffectExtraData->TargetGUID = moveSpline.spell_effect_extra->Target; movementSpline.SpellEffectExtraData->SpellVisualID = moveSpline.spell_effect_extra->SpellVisualId; movementSpline.SpellEffectExtraData->ProgressCurveID = moveSpline.spell_effect_extra->ProgressCurveId; @@ -498,8 +498,8 @@ WorldPacket const* WorldPackets::Movement::TransferPending::Write() { _worldPacket << int32(MapID); _worldPacket << OldMapPosition; - _worldPacket.WriteBit(Ship.is_initialized()); - _worldPacket.WriteBit(TransferSpellID.is_initialized()); + _worldPacket.WriteBit(Ship.has_value()); + _worldPacket.WriteBit(TransferSpellID.has_value()); if (Ship) { _worldPacket << uint32(Ship->ID); @@ -541,8 +541,8 @@ WorldPacket const* WorldPackets::Movement::MoveTeleport::Write() _worldPacket << float(Facing); _worldPacket << uint8(PreloadWorld); - _worldPacket.WriteBit(TransportGUID.is_initialized()); - _worldPacket.WriteBit(Vehicle.is_initialized()); + _worldPacket.WriteBit(TransportGUID.has_value()); + _worldPacket.WriteBit(Vehicle.has_value()); _worldPacket.FlushBits(); if (Vehicle) @@ -577,15 +577,15 @@ WorldPacket const* WorldPackets::Movement::MoveUpdateTeleport::Write() _worldPacket << *Status; _worldPacket << uint32(MovementForces.size()); - _worldPacket.WriteBit(WalkSpeed.is_initialized()); - _worldPacket.WriteBit(RunSpeed.is_initialized()); - _worldPacket.WriteBit(RunBackSpeed.is_initialized()); - _worldPacket.WriteBit(SwimSpeed.is_initialized()); - _worldPacket.WriteBit(SwimBackSpeed.is_initialized()); - _worldPacket.WriteBit(FlightSpeed.is_initialized()); - _worldPacket.WriteBit(FlightBackSpeed.is_initialized()); - _worldPacket.WriteBit(TurnRate.is_initialized()); - _worldPacket.WriteBit(PitchRate.is_initialized()); + _worldPacket.WriteBit(WalkSpeed.has_value()); + _worldPacket.WriteBit(RunSpeed.has_value()); + _worldPacket.WriteBit(RunBackSpeed.has_value()); + _worldPacket.WriteBit(SwimSpeed.has_value()); + _worldPacket.WriteBit(SwimBackSpeed.has_value()); + _worldPacket.WriteBit(FlightSpeed.has_value()); + _worldPacket.WriteBit(FlightBackSpeed.has_value()); + _worldPacket.WriteBit(TurnRate.has_value()); + _worldPacket.WriteBit(PitchRate.has_value()); _worldPacket.FlushBits(); for (WorldPackets::Movement::MovementForce const& force : MovementForces) @@ -697,7 +697,7 @@ void WorldPackets::Movement::MoveKnockBackAck::Read() bool hasSpeeds = _worldPacket.ReadBit(); if (hasSpeeds) { - Speeds = boost::in_place(); + Speeds.emplace(); _worldPacket >> *Speeds; } } @@ -833,12 +833,12 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MoveSetCompound { data << uint16(stateChange.MessageID); data << uint32(stateChange.SequenceIndex); - data.WriteBit(stateChange.Speed.is_initialized()); - data.WriteBit(stateChange.KnockBack.is_initialized()); - data.WriteBit(stateChange.VehicleRecID.is_initialized()); - data.WriteBit(stateChange.CollisionHeight.is_initialized()); - data.WriteBit(stateChange.MovementForce_.is_initialized()); - data.WriteBit(stateChange.Unknown.is_initialized()); + data.WriteBit(stateChange.Speed.has_value()); + data.WriteBit(stateChange.KnockBack.has_value()); + data.WriteBit(stateChange.VehicleRecID.has_value()); + data.WriteBit(stateChange.CollisionHeight.has_value()); + data.WriteBit(stateChange.MovementForce_.has_value()); + data.WriteBit(stateChange.Unknown.has_value()); data.FlushBits(); if (stateChange.CollisionHeight) diff --git a/src/server/game/Server/Packets/MovementPackets.h b/src/server/game/Server/Packets/MovementPackets.h index 490b7082916..cf42edaa726 100644 --- a/src/server/game/Server/Packets/MovementPackets.h +++ b/src/server/game/Server/Packets/MovementPackets.h @@ -189,6 +189,8 @@ namespace WorldPackets { struct ShipTransferPending { + ShipTransferPending() { } // allows emplace() with clang + uint32 ID = 0; ///< gameobject_template.entry of the transport the player is teleporting on int32 OriginMapID = -1; ///< Map id the player is currently on (before teleport) }; diff --git a/src/server/game/Server/Packets/PartyPackets.cpp b/src/server/game/Server/Packets/PartyPackets.cpp index 939f0a65db1..d14f4ccebdb 100644 --- a/src/server/game/Server/Packets/PartyPackets.cpp +++ b/src/server/game/Server/Packets/PartyPackets.cpp @@ -113,7 +113,7 @@ void WorldPackets::Party::PartyInviteResponse::Read() bool hasRolesDesired = _worldPacket.ReadBit(); if (hasRolesDesired) { - RolesDesired = boost::in_place(); + RolesDesired.emplace(); _worldPacket >> *RolesDesired; } } @@ -218,10 +218,10 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::PartyMemberStats c for (WorldPackets::Party::PartyMemberAuraStates const& aura : memberStats.Auras) data << aura; - data.WriteBit(memberStats.PetStats.is_initialized()); + data.WriteBit(memberStats.PetStats.has_value()); data.FlushBits(); - if (memberStats.PetStats.is_initialized()) + if (memberStats.PetStats.has_value()) data << *memberStats.PetStats; return data; @@ -477,21 +477,21 @@ WorldPacket const* WorldPackets::Party::PartyUpdate::Write() _worldPacket << uint32(SequenceNum); _worldPacket << LeaderGUID; _worldPacket << uint32(PlayerList.size()); - _worldPacket.WriteBit(LfgInfos.is_initialized()); - _worldPacket.WriteBit(LootSettings.is_initialized()); - _worldPacket.WriteBit(DifficultySettings.is_initialized()); + _worldPacket.WriteBit(LfgInfos.has_value()); + _worldPacket.WriteBit(LootSettings.has_value()); + _worldPacket.WriteBit(DifficultySettings.has_value()); _worldPacket.FlushBits(); for (WorldPackets::Party::PartyPlayerInfo const& playerInfos : PlayerList) _worldPacket << playerInfos; - if (LootSettings.is_initialized()) + if (LootSettings.has_value()) _worldPacket << *LootSettings; - if (DifficultySettings.is_initialized()) + if (DifficultySettings.has_value()) _worldPacket << *DifficultySettings; - if (LfgInfos.is_initialized()) + if (LfgInfos.has_value()) _worldPacket << *LfgInfos; return &_worldPacket; @@ -633,7 +633,7 @@ void WorldPackets::Party::PartyMemberState::Initialize(Player const* player) { ::Pet* pet = player->GetPet(); - MemberStats.PetStats = boost::in_place(); + MemberStats.PetStats.emplace(); MemberStats.PetStats->GUID = pet->GetGUID(); MemberStats.PetStats->Name = pet->GetName(); diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp index 9bc1de1777b..fb6cf737f2f 100644 --- a/src/server/game/Server/Packets/PetPackets.cpp +++ b/src/server/game/Server/Packets/PetPackets.cpp @@ -97,7 +97,7 @@ WorldPacket const* WorldPackets::Pet::PetNameInvalid::Write() _worldPacket << uint8(RenameData.NewName.length()); - _worldPacket.WriteBit(RenameData.DeclinedNames.is_initialized()); + _worldPacket.WriteBit(RenameData.DeclinedNames.has_value()); _worldPacket.FlushBits(); if (RenameData.DeclinedNames) @@ -126,7 +126,7 @@ void WorldPackets::Pet::PetRename::Read() if (_worldPacket.ReadBit()) { - RenameData.DeclinedNames = boost::in_place(); + RenameData.DeclinedNames.emplace(); int32 count[MAX_DECLINED_NAME_CASES]; for (int32 i = 0; i < MAX_DECLINED_NAME_CASES; i++) count[i] = _worldPacket.ReadBits(7); diff --git a/src/server/game/Server/Packets/QueryPackets.cpp b/src/server/game/Server/Packets/QueryPackets.cpp index c640394be93..285daf9afb4 100644 --- a/src/server/game/Server/Packets/QueryPackets.cpp +++ b/src/server/game/Server/Packets/QueryPackets.cpp @@ -93,8 +93,8 @@ void WorldPackets::Query::QueryPlayerName::Read() ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Query::PlayerGuidLookupHint const& lookupHint) { - data.WriteBit(lookupHint.VirtualRealmAddress.is_initialized()); - data.WriteBit(lookupHint.NativeRealmAddress.is_initialized()); + data.WriteBit(lookupHint.VirtualRealmAddress.has_value()); + data.WriteBit(lookupHint.NativeRealmAddress.has_value()); data.FlushBits(); if (lookupHint.VirtualRealmAddress) diff --git a/src/server/game/Server/Packets/QuestPackets.cpp b/src/server/game/Server/Packets/QuestPackets.cpp index a21540ba13b..a6328ac925f 100644 --- a/src/server/game/Server/Packets/QuestPackets.cpp +++ b/src/server/game/Server/Packets/QuestPackets.cpp @@ -677,7 +677,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::PlayerChoiceRespon data.WriteBits(playerChoiceResponse.Header.length(), 9); data.WriteBits(playerChoiceResponse.Description.length(), 11); data.WriteBits(playerChoiceResponse.Confirmation.length(), 7); - data.WriteBit(playerChoiceResponse.Reward.is_initialized()); + data.WriteBit(playerChoiceResponse.Reward.has_value()); data.FlushBits(); if (playerChoiceResponse.Reward) diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index ec6d57f2748..dfd215eff9a 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -99,13 +99,13 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::AuraDataInfo cons data << uint32(auraData.ActiveFlags); data << uint16(auraData.CastLevel); data << uint8(auraData.Applications); - data.WriteBit(auraData.CastUnit.is_initialized()); - data.WriteBit(auraData.Duration.is_initialized()); - data.WriteBit(auraData.Remaining.is_initialized()); - data.WriteBit(auraData.TimeMod.is_initialized()); + data.WriteBit(auraData.CastUnit.has_value()); + data.WriteBit(auraData.Duration.has_value()); + data.WriteBit(auraData.Remaining.has_value()); + data.WriteBit(auraData.TimeMod.has_value()); data.WriteBits(auraData.Points.size(), 6); data.WriteBits(auraData.EstimatedPoints.size(), 6); - data.WriteBit(auraData.SandboxScaling.is_initialized()); + data.WriteBit(auraData.SandboxScaling.has_value()); if (auraData.SandboxScaling) data << *auraData.SandboxScaling; @@ -134,7 +134,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::AuraDataInfo cons ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::AuraInfo const& aura) { data << aura.Slot; - data.WriteBit(aura.AuraData.is_initialized()); + data.WriteBit(aura.AuraData.has_value()); data.FlushBits(); if (aura.AuraData) @@ -157,7 +157,7 @@ WorldPacket const* WorldPackets::Spells::AuraUpdate::Write() ByteBuffer& operator>>(ByteBuffer& buffer, Optional& location) { - location = boost::in_place(); + location.emplace(); buffer >> location->Transport; buffer >> location->Location.m_positionX; buffer >> location->Location.m_positionY; @@ -219,7 +219,7 @@ ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::SpellCastReques if (hasMoveUpdate) { - request.MoveUpdate = boost::in_place(); + request.MoveUpdate.emplace(); buffer >> *request.MoveUpdate; } @@ -273,10 +273,10 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::TargetLocation co ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellTargetData const& spellTargetData) { data.WriteBits(spellTargetData.Flags, 25); - data.WriteBit(spellTargetData.SrcLocation.is_initialized()); - data.WriteBit(spellTargetData.DstLocation.is_initialized()); - data.WriteBit(spellTargetData.Orientation.is_initialized()); - data.WriteBit(spellTargetData.MapID.is_initialized()); + data.WriteBit(spellTargetData.SrcLocation.has_value()); + data.WriteBit(spellTargetData.DstLocation.has_value()); + data.WriteBit(spellTargetData.Orientation.has_value()); + data.WriteBit(spellTargetData.MapID.has_value()); data.WriteBits(spellTargetData.Name.size(), 7); data.FlushBits(); @@ -377,7 +377,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellCastData con data.WriteBits(spellCastData.MissTargets.size(), 16); data.WriteBits(spellCastData.MissStatus.size(), 16); data.WriteBits(spellCastData.RemainingPower.size(), 9); - data.WriteBit(spellCastData.RemainingRunes.is_initialized()); + data.WriteBit(spellCastData.RemainingRunes.has_value()); data.WriteBits(spellCastData.TargetPoints.size(), 16); data.FlushBits(); @@ -609,8 +609,8 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellHistoryEntry data << int32(historyEntry.RecoveryTime); data << int32(historyEntry.CategoryRecoveryTime); data << float(historyEntry.ModRate); - data.WriteBit(historyEntry.unused622_1.is_initialized()); - data.WriteBit(historyEntry.unused622_2.is_initialized()); + data.WriteBit(historyEntry.unused622_1.has_value()); + data.WriteBit(historyEntry.unused622_2.has_value()); data.WriteBit(historyEntry.OnHold); if (historyEntry.unused622_1) data << uint32(*historyEntry.unused622_1); @@ -780,8 +780,8 @@ WorldPacket const* WorldPackets::Spells::SpellChannelStart::Write() _worldPacket << int32(SpellID); _worldPacket << int32(SpellXSpellVisualID); _worldPacket << uint32(ChannelDuration); - _worldPacket.WriteBit(InterruptImmunities.is_initialized()); - _worldPacket.WriteBit(HealPrediction.is_initialized()); + _worldPacket.WriteBit(InterruptImmunities.has_value()); + _worldPacket.WriteBit(HealPrediction.has_value()); _worldPacket.FlushBits(); if (InterruptImmunities) @@ -913,7 +913,7 @@ void WorldPackets::Spells::UpdateMissileTrajectory::Read() _worldPacket.ResetBitPos(); if (hasStatus) { - Status = boost::in_place(); + Status.emplace(); _worldPacket >> *Status; } } diff --git a/src/server/game/Server/Packets/SystemPackets.cpp b/src/server/game/Server/Packets/SystemPackets.cpp index da674178456..971d0a00e17 100644 --- a/src/server/game/Server/Packets/SystemPackets.cpp +++ b/src/server/game/Server/Packets/SystemPackets.cpp @@ -38,14 +38,14 @@ WorldPacket const* WorldPackets::System::FeatureSystemStatus::Write() _worldPacket << uint32(BpayStoreProductDeliveryDelay); _worldPacket.WriteBit(VoiceEnabled); - _worldPacket.WriteBit(EuropaTicketSystemStatus.is_initialized()); + _worldPacket.WriteBit(EuropaTicketSystemStatus.has_value()); _worldPacket.WriteBit(ScrollOfResurrectionEnabled); _worldPacket.WriteBit(BpayStoreEnabled); _worldPacket.WriteBit(BpayStoreAvailable); _worldPacket.WriteBit(BpayStoreDisabledByParentalControls); _worldPacket.WriteBit(ItemRestorationButtonEnabled); _worldPacket.WriteBit(BrowserEnabled); - _worldPacket.WriteBit(SessionAlert.is_initialized()); + _worldPacket.WriteBit(SessionAlert.has_value()); _worldPacket.WriteBit(RecruitAFriendSendingEnabled); _worldPacket.WriteBit(CharUndeleteEnabled); _worldPacket.WriteBit(RestrictedAccount); @@ -57,7 +57,7 @@ WorldPacket const* WorldPackets::System::FeatureSystemStatus::Write() _worldPacket.WriteBit(WillKickFromWorld); _worldPacket.WriteBit(KioskModeEnabled); _worldPacket.WriteBit(CompetitiveModeEnabled); - _worldPacket.WriteBit(RaceClassExpansionLevels.is_initialized()); + _worldPacket.WriteBit(RaceClassExpansionLevels.has_value()); _worldPacket.WriteBit(TokenBalanceEnabled); _worldPacket.FlushBits(); diff --git a/src/server/game/Server/Packets/SystemPackets.h b/src/server/game/Server/Packets/SystemPackets.h index 34d6622286e..306aa3a738a 100644 --- a/src/server/game/Server/Packets/SystemPackets.h +++ b/src/server/game/Server/Packets/SystemPackets.h @@ -39,6 +39,8 @@ namespace WorldPackets struct EuropaTicketConfig { + EuropaTicketConfig() { } // allows emplace() with clang + bool TicketsEnabled = false; bool BugsEnabled = false; bool ComplaintsEnabled = false; diff --git a/src/server/game/Server/Packets/TaxiPackets.cpp b/src/server/game/Server/Packets/TaxiPackets.cpp index 9e8e552f363..acc6e927c1d 100644 --- a/src/server/game/Server/Packets/TaxiPackets.cpp +++ b/src/server/game/Server/Packets/TaxiPackets.cpp @@ -33,13 +33,13 @@ WorldPacket const* WorldPackets::Taxi::TaxiNodeStatus::Write() WorldPacket const* WorldPackets::Taxi::ShowTaxiNodes::Write() { - _worldPacket.WriteBit(WindowInfo.is_initialized()); + _worldPacket.WriteBit(WindowInfo.has_value()); _worldPacket.FlushBits(); _worldPacket << uint32(CanLandNodes->size()); _worldPacket << uint32(CanUseNodes->size()); - if (WindowInfo.is_initialized()) + if (WindowInfo.has_value()) { _worldPacket << WindowInfo->UnitGUID; _worldPacket << uint32(WindowInfo->CurrentNode); diff --git a/src/server/game/Server/Packets/TicketPackets.cpp b/src/server/game/Server/Packets/TicketPackets.cpp index cafb723c062..b3f457d1bd4 100644 --- a/src/server/game/Server/Packets/TicketPackets.cpp +++ b/src/server/game/Server/Packets/TicketPackets.cpp @@ -111,7 +111,7 @@ ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubm ByteBuffer& operator>>(ByteBuffer& data, Optional& mail) { - mail = boost::in_place(); + mail.emplace(); data >> mail->MailID; uint32 bodyLength = data.ReadBits(13); @@ -124,7 +124,7 @@ ByteBuffer& operator>>(ByteBuffer& data, Optional>(ByteBuffer& data, Optional& event) { - event = boost::in_place(); + event.emplace(); data >> event->EventID; data >> event->InviteID; @@ -135,7 +135,7 @@ ByteBuffer& operator>>(ByteBuffer& data, Optional>(ByteBuffer& data, Optional& pet) { - pet = boost::in_place(); + pet.emplace(); data >> pet->PetID; pet->PetName = data.ReadString(data.ReadBits(8)); @@ -145,7 +145,7 @@ ByteBuffer& operator>>(ByteBuffer& data, Optional>(ByteBuffer& data, Optional& guild) { - guild = boost::in_place(); + guild.emplace(); uint32 nameLength = data.ReadBits(7); data >> guild->GuildID; @@ -156,7 +156,7 @@ ByteBuffer& operator>>(ByteBuffer& data, Optional>(ByteBuffer& data, Optional& lfgListSearchResult) { - lfgListSearchResult = boost::in_place(); + lfgListSearchResult.emplace(); data >> lfgListSearchResult->RideTicket; data >> lfgListSearchResult->GroupFinderActivityID; @@ -179,7 +179,7 @@ ByteBuffer& operator>>(ByteBuffer& data, Optional>(ByteBuffer& data, Optional& lfgListApplicant) { - lfgListApplicant = boost::in_place(); + lfgListApplicant.emplace(); data >> lfgListApplicant->RideTicket; lfgListApplicant->Comment = data.ReadString(data.ReadBits(9)); diff --git a/src/server/game/Server/Packets/TicketPackets.h b/src/server/game/Server/Packets/TicketPackets.h index 6e25f3da4a9..8d4ff676260 100644 --- a/src/server/game/Server/Packets/TicketPackets.h +++ b/src/server/game/Server/Packets/TicketPackets.h @@ -134,6 +134,8 @@ namespace WorldPackets struct SupportTicketMailInfo { + SupportTicketMailInfo() { } // allows emplace() with clang + int32 MailID = 0; std::string MailSubject; std::string MailBody; @@ -160,6 +162,8 @@ namespace WorldPackets struct SupportTicketLFGListSearchResult { + SupportTicketLFGListSearchResult() { } // allows emplace() with clang + WorldPackets::LFG::RideTicket RideTicket; uint32 GroupFinderActivityID = 0; ObjectGuid LastTitleAuthorGuid; diff --git a/src/server/game/Server/Packets/TradePackets.cpp b/src/server/game/Server/Packets/TradePackets.cpp index 9b347f942ad..17056413dac 100644 --- a/src/server/game/Server/Packets/TradePackets.cpp +++ b/src/server/game/Server/Packets/TradePackets.cpp @@ -106,7 +106,7 @@ ByteBuffer& operator<<(ByteBuffer& buffer, WorldPackets::Trade::TradeUpdated::Tr buffer << uint32(tradeItem.StackCount); buffer << tradeItem.GiftCreator; buffer << tradeItem.Item; - buffer.WriteBit(tradeItem.Unwrapped.is_initialized()); + buffer.WriteBit(tradeItem.Unwrapped.has_value()); buffer.FlushBits(); if (tradeItem.Unwrapped) buffer << *tradeItem.Unwrapped; diff --git a/src/server/game/Server/Packets/TradePackets.h b/src/server/game/Server/Packets/TradePackets.h index 8fd32582480..8097bd6967d 100644 --- a/src/server/game/Server/Packets/TradePackets.h +++ b/src/server/game/Server/Packets/TradePackets.h @@ -155,6 +155,8 @@ namespace WorldPackets public: struct UnwrappedTradeItem { + UnwrappedTradeItem() { } // allows emplace() with clang + WorldPackets::Item::ItemInstance Item; int32 EnchantID = 0; int32 OnUseEnchantmentID = 0; diff --git a/src/server/game/Server/Packets/WhoPackets.cpp b/src/server/game/Server/Packets/WhoPackets.cpp index afc6c3bdd28..11f1e7e37c4 100644 --- a/src/server/game/Server/Packets/WhoPackets.cpp +++ b/src/server/game/Server/Packets/WhoPackets.cpp @@ -42,7 +42,7 @@ ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Who::WhoWord& word) ByteBuffer& operator>>(ByteBuffer& data, Optional& serverInfo) { - serverInfo = boost::in_place(); + serverInfo.emplace(); data >> serverInfo->FactionGroup; data >> serverInfo->Locale; diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index f73ca906307..09e5b421d0b 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -629,7 +629,7 @@ void WorldSession::LogoutPlayer(bool save) TC_LOG_DEBUG("network", "SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); //! Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE); stmt->setUInt32(0, GetAccountId()); CharacterDatabase.Execute(stmt); } @@ -776,7 +776,7 @@ void WorldSession::SetAccountData(AccountDataType type, uint32 time, std::string { if ((1 << type) & GLOBAL_CACHE_MASK) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_ACCOUNT_DATA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_ACCOUNT_DATA); stmt->setUInt32(0, GetAccountId()); stmt->setUInt8(1, type); stmt->setUInt32(2, time); @@ -789,7 +789,7 @@ void WorldSession::SetAccountData(AccountDataType type, uint32 time, std::string if (!m_GUIDLow) return; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_PLAYER_ACCOUNT_DATA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_PLAYER_ACCOUNT_DATA); stmt->setUInt64(0, m_GUIDLow); stmt->setUInt8(1, type); stmt->setUInt32(2, time); @@ -819,13 +819,13 @@ void WorldSession::SendTutorialsData() SendPacket(packet.Write()); } -void WorldSession::SaveTutorialsData(SQLTransaction& trans) +void WorldSession::SaveTutorialsData(CharacterDatabaseTransaction& trans) { if (!(_tutorialsChanged & TUTORIALS_FLAG_CHANGED)) return; bool const hasTutorialsInDB = (_tutorialsChanged & TUTORIALS_FLAG_LOADED_FROM_DB) != 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(hasTutorialsInDB ? CHAR_UPD_TUTORIALS : CHAR_INS_TUTORIALS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(hasTutorialsInDB ? CHAR_UPD_TUTORIALS : CHAR_INS_TUTORIALS); for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) stmt->setUInt32(i, _tutorials[i]); stmt->setUInt32(MAX_ACCOUNT_TUTORIAL_VALUES, GetAccountId()); @@ -879,15 +879,19 @@ void WorldSession::SetPlayer(Player* player) void WorldSession::ProcessQueryCallbacks() { - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); + _transactionCallbacks.ProcessReadyCallbacks(); + _queryHolderProcessor.ProcessReadyCallbacks(); +} - if (_realmAccountLoginCallback.valid() && _realmAccountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready && - _accountLoginCallback.valid() && _accountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - InitializeSessionCallback(_realmAccountLoginCallback.get(), _accountLoginCallback.get()); +TransactionCallback& WorldSession::AddTransactionCallback(TransactionCallback&& callback) +{ + return _transactionCallbacks.AddCallback(std::move(callback)); +} - //! HandlePlayerLoginOpcode - if (_charLoginCallback.valid() && _charLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - HandlePlayerLogin(reinterpret_cast(_charLoginCallback.get())); +SQLQueryHolderCallback& WorldSession::AddQueryHolderCallback(SQLQueryHolderCallback&& callback) +{ + return _queryHolderProcessor.AddCallback(std::move(callback)); } void WorldSession::InitWarden(BigNumber* k) @@ -931,7 +935,7 @@ QueryCallback WorldSession::LoadPermissionsAsync() return _RBACData->LoadFromDBAsync(); } -class AccountInfoQueryHolderPerRealm : public SQLQueryHolder +class AccountInfoQueryHolderPerRealm : public CharacterDatabaseQueryHolder { public: enum @@ -948,7 +952,7 @@ class AccountInfoQueryHolderPerRealm : public SQLQueryHolder { bool ok = true; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_DATA); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_DATA); stmt->setUInt32(0, accountId); ok = SetPreparedQuery(GLOBAL_ACCOUNT_DATA, stmt) && ok; @@ -960,7 +964,7 @@ class AccountInfoQueryHolderPerRealm : public SQLQueryHolder } }; -class AccountInfoQueryHolder : public SQLQueryHolder +class AccountInfoQueryHolder : public LoginDatabaseQueryHolder { public: enum @@ -983,7 +987,7 @@ class AccountInfoQueryHolder : public SQLQueryHolder { bool ok = true; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_TOYS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_TOYS); stmt->setUInt32(0, battlenetAccountId); ok = SetPreparedQuery(GLOBAL_ACCOUNT_TOYS, stmt) && ok; @@ -1021,35 +1025,51 @@ class AccountInfoQueryHolder : public SQLQueryHolder void WorldSession::InitializeSession() { - AccountInfoQueryHolderPerRealm* realmHolder = new AccountInfoQueryHolderPerRealm(); + std::shared_ptr realmHolder = std::make_shared(); if (!realmHolder->Initialize(GetAccountId(), GetBattlenetAccountId())) { - delete realmHolder; SendAuthResponse(ERROR_INTERNAL, false); return; } - AccountInfoQueryHolder* holder = new AccountInfoQueryHolder(); + std::shared_ptr holder = std::make_shared(); if (!holder->Initialize(GetAccountId(), GetBattlenetAccountId())) { - delete realmHolder; - delete holder; SendAuthResponse(ERROR_INTERNAL, false); return; } - _realmAccountLoginCallback = CharacterDatabase.DelayQueryHolder(realmHolder); - _accountLoginCallback = LoginDatabase.DelayQueryHolder(holder); + struct ForkJoinState + { + std::shared_ptr Character; + std::shared_ptr Login; + }; + + std::shared_ptr state = std::make_shared(); + + AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(realmHolder)).AfterComplete([this, state, realmHolder](SQLQueryHolderBase const& /*result*/) + { + state->Character = realmHolder; + if (state->Login && state->Character) + InitializeSessionCallback(*state->Login, *state->Character); + }); + + AddQueryHolderCallback(LoginDatabase.DelayQueryHolder(holder)).AfterComplete([this, state, holder](SQLQueryHolderBase const& /*result*/) + { + state->Login = holder; + if (state->Login && state->Character) + InitializeSessionCallback(*state->Login, *state->Character); + }); } -void WorldSession::InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQueryHolder* holder) +void WorldSession::InitializeSessionCallback(LoginDatabaseQueryHolder const& holder, CharacterDatabaseQueryHolder const& realmHolder) { - LoadAccountData(realmHolder->GetPreparedResult(AccountInfoQueryHolderPerRealm::GLOBAL_ACCOUNT_DATA), GLOBAL_CACHE_MASK); - LoadTutorialsData(realmHolder->GetPreparedResult(AccountInfoQueryHolderPerRealm::TUTORIALS)); - _collectionMgr->LoadAccountToys(holder->GetPreparedResult(AccountInfoQueryHolder::GLOBAL_ACCOUNT_TOYS)); - _collectionMgr->LoadAccountHeirlooms(holder->GetPreparedResult(AccountInfoQueryHolder::GLOBAL_ACCOUNT_HEIRLOOMS)); - _collectionMgr->LoadAccountMounts(holder->GetPreparedResult(AccountInfoQueryHolder::MOUNTS)); - _collectionMgr->LoadAccountItemAppearances(holder->GetPreparedResult(AccountInfoQueryHolder::ITEM_APPEARANCES), holder->GetPreparedResult(AccountInfoQueryHolder::ITEM_FAVORITE_APPEARANCES)); + LoadAccountData(realmHolder.GetPreparedResult(AccountInfoQueryHolderPerRealm::GLOBAL_ACCOUNT_DATA), GLOBAL_CACHE_MASK); + LoadTutorialsData(realmHolder.GetPreparedResult(AccountInfoQueryHolderPerRealm::TUTORIALS)); + _collectionMgr->LoadAccountToys(holder.GetPreparedResult(AccountInfoQueryHolder::GLOBAL_ACCOUNT_TOYS)); + _collectionMgr->LoadAccountHeirlooms(holder.GetPreparedResult(AccountInfoQueryHolder::GLOBAL_ACCOUNT_HEIRLOOMS)); + _collectionMgr->LoadAccountMounts(holder.GetPreparedResult(AccountInfoQueryHolder::MOUNTS)); + _collectionMgr->LoadAccountItemAppearances(holder.GetPreparedResult(AccountInfoQueryHolder::ITEM_APPEARANCES), holder.GetPreparedResult(AccountInfoQueryHolder::ITEM_FAVORITE_APPEARANCES)); if (!m_inQueue) SendAuthResponse(ERROR_OK, false); @@ -1065,7 +1085,7 @@ void WorldSession::InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQue SendAvailableHotfixes(int32(sWorld->getIntConfig(CONFIG_HOTFIX_CACHE_VERSION))); SendTutorialsData(); - if (PreparedQueryResult characterCountsResult = holder->GetPreparedResult(AccountInfoQueryHolder::GLOBAL_REALM_CHARACTER_COUNTS)) + if (PreparedQueryResult characterCountsResult = holder.GetPreparedResult(AccountInfoQueryHolder::GLOBAL_REALM_CHARACTER_COUNTS)) { do { @@ -1079,11 +1099,8 @@ void WorldSession::InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQue bnetConnected.State = 1; SendPacket(bnetConnected.Write()); - _battlePetMgr->LoadFromDB(holder->GetPreparedResult(AccountInfoQueryHolder::BATTLE_PETS), - holder->GetPreparedResult(AccountInfoQueryHolder::BATTLE_PET_SLOTS)); - - delete realmHolder; - delete holder; + _battlePetMgr->LoadFromDB(holder.GetPreparedResult(AccountInfoQueryHolder::BATTLE_PETS), + holder.GetPreparedResult(AccountInfoQueryHolder::BATTLE_PET_SLOTS)); } rbac::RBACData* WorldSession::GetRBACData() @@ -1409,7 +1426,7 @@ void WorldSession::LoadRecoveries() if (AccountMgr::GetCharactersCount(GetAccountId()) >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) return; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_RECOVERY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_RECOVERY); stmt->setUInt32(0, GetAccountId()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -1525,7 +1542,7 @@ void WorldSession::LoadRecoveries() else loc.WorldRelocate(1, 1569.96f, -4397.41f, 16.05f, 0.543025f); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); Player::SavePositionInDB(loc, 0, newChar.GetGUID(), trans); newChar.CleanupsBeforeDelete(); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 032cb7eadc9..5a9bae28c1a 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -23,14 +23,15 @@ #ifndef __WORLDSESSION_H #define __WORLDSESSION_H +#include "AsyncCallbackProcessor.h" #include "Common.h" #include "DatabaseEnvFwd.h" #include "LockedQueue.h" #include "ObjectGuid.h" #include "Packet.h" -#include "QueryCallbackProcessor.h" #include "SharedDefines.h" #include +#include #include #include @@ -967,7 +968,7 @@ class TC_GAME_API WorldSession void SendNotification(char const* format, ...) ATTR_PRINTF(2, 3); void SendNotification(uint32 stringId, ...); - void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName *declinedName); + void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName const* declinedName); void SendPartyResult(PartyOperation operation, std::string const& member, PartyResult res, uint32 val = 0); void SendQueryTimeResponse(); @@ -976,7 +977,7 @@ class TC_GAME_API WorldSession void SendAvailableHotfixes(int32 version); void InitializeSession(); - void InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQueryHolder* holder); + void InitializeSessionCallback(LoginDatabaseQueryHolder const& holder, CharacterDatabaseQueryHolder const& realmHolder); rbac::RBACData* GetRBACData(); bool HasPermission(uint32 permissionId); @@ -1073,7 +1074,7 @@ class TC_GAME_API WorldSession void LoadTutorialsData(PreparedQueryResult result); void SendTutorialsData(); - void SaveTutorialsData(SQLTransaction& trans); + void SaveTutorialsData(CharacterDatabaseTransaction& trans); uint32 GetTutorialInt(uint8 index) const { return _tutorials[index]; } void SetTutorialInt(uint8 index, uint32 value) { @@ -1179,7 +1180,7 @@ class TC_GAME_API WorldSession void HandleContinuePlayerLogin(); void AbortLogin(WorldPackets::Character::LoginFailureReason reason); void HandleLoadScreenOpcode(WorldPackets::Character::LoadingScreenNotify& loadingScreenNotify); - void HandlePlayerLogin(LoginQueryHolder* holder); + void HandlePlayerLogin(LoginQueryHolder const& holder); void HandleCharRenameOpcode(WorldPackets::Character::CharacterRenameRequest& request); void HandleCharRenameCallBack(std::shared_ptr renameInfo, PreparedQueryResult result); void HandleSetPlayerDeclinedNames(WorldPackets::Character::SetPlayerDeclinedNames& packet); @@ -1839,14 +1840,18 @@ class TC_GAME_API WorldSession uint64 GetConnectToInstanceKey() const { return _instanceConnectKey.Raw; } void LoadRecoveries(); + + public: + QueryCallbackProcessor& GetQueryProcessor() { return _queryProcessor; } + TransactionCallback& AddTransactionCallback(TransactionCallback&& callback); + SQLQueryHolderCallback& AddQueryHolderCallback(SQLQueryHolderCallback&& callback); + private: void ProcessQueryCallbacks(); - QueryResultHolderFuture _realmAccountLoginCallback; - QueryResultHolderFuture _accountLoginCallback; - QueryResultHolderFuture _charLoginCallback; - QueryCallbackProcessor _queryProcessor; + AsyncCallbackProcessor _transactionCallbacks; + AsyncCallbackProcessor _queryHolderProcessor; friend class World; protected: diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 32ec19e4c5b..07be2c74257 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -91,10 +91,10 @@ WorldSocket::~WorldSocket() void WorldSocket::Start() { std::string ip_address = GetRemoteIpAddress().to_string(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); stmt->setString(0, ip_address); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1))); } void WorldSocket::CheckIpCallback(PreparedQueryResult result) @@ -232,7 +232,7 @@ bool WorldSocket::Update() if (!BaseSocket::Update()) return false; - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); return true; } @@ -640,11 +640,11 @@ struct AccountInfo void WorldSocket::HandleAuthSession(std::shared_ptr authSession) { // Get the account information from the auth database - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); stmt->setInt32(0, int32(realm.Id.Realm)); stmt->setString(1, authSession->RealmJoinTicket); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1))); } void WorldSocket::HandleAuthSessionCallback(std::shared_ptr authSession, PreparedQueryResult result) @@ -714,7 +714,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptrsetString(0, address); stmt->setString(1, authSession->RealmJoinTicket); LoginDatabase.Execute(stmt); @@ -838,7 +838,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptrInitWarden(&_sessionKey); - _queryProcessor.AddQuery(_worldSession->LoadPermissionsAsync().WithPreparedCallback(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(_worldSession->LoadPermissionsAsync().WithPreparedCallback(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1))); AsyncRead(); } @@ -864,10 +864,10 @@ void WorldSocket::HandleAuthContinuedSession(std::shared_ptrsetUInt32(0, accountId); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1))); } void WorldSocket::HandleAuthContinuedSessionCallback(std::shared_ptr authSession, PreparedQueryResult result) diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 63eb7b9f8d2..6e1be9a287f 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -19,11 +19,11 @@ #ifndef __WORLDSOCKET_H__ #define __WORLDSOCKET_H__ +#include "AsyncCallbackProcessor.h" #include "Common.h" #include "BigNumber.h" #include "DatabaseEnvFwd.h" #include "MessageBuffer.h" -#include "QueryCallbackProcessor.h" #include "Socket.h" #include "WorldPacketCrypt.h" #include "MPSCQueue.h" diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 8146b772945..31f6db6eb69 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -171,7 +171,7 @@ void AuraApplication::SendFakeAuraUpdate(uint32 auraId, bool remove) WorldPackets::Spells::AuraInfo inf; BuildUpdatePacket(inf, remove); - if (inf.AuraData.is_initialized()) + if (inf.AuraData.has_value()) inf.AuraData->SpellID = auraId; data.Auras.push_back(inf); @@ -187,11 +187,11 @@ void AuraApplication::BuildUpdatePacket(WorldPackets::Spells::AuraInfo& auraInfo if (remove) return; - auraInfo.AuraData = boost::in_place(); + auraInfo.AuraData.emplace(); Aura const* aura = GetBase(); - WorldPackets::Spells::AuraDataInfo& auraData = auraInfo.AuraData.get(); + WorldPackets::Spells::AuraDataInfo& auraData = *auraInfo.AuraData; auraData.CastID = aura->GetCastGUID(); auraData.SpellID = aura->GetId(); auraData.SpellXSpellVisualID = aura->GetSpellXSpellVisualId(); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index cee5ae18d75..89090b332d8 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -198,7 +198,7 @@ void SpellCastTargets::Write(WorldPackets::Spells::SpellTargetData& data) if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION) { - data.SrcLocation = boost::in_place(); + data.SrcLocation.emplace(); data.SrcLocation->Transport = m_src._transportGUID; // relative position guid here - transport for example if (!m_src._transportGUID.IsEmpty()) data.SrcLocation->Location = m_src._transportOffset; @@ -208,7 +208,7 @@ void SpellCastTargets::Write(WorldPackets::Spells::SpellTargetData& data) if (m_targetMask & TARGET_FLAG_DEST_LOCATION) { - data.DstLocation = boost::in_place(); + data.DstLocation.emplace(); data.DstLocation->Transport = m_dst._transportGUID; // relative position guid here - transport for example if (!m_dst._transportGUID.IsEmpty()) data.DstLocation->Location = m_dst._transportOffset; @@ -4193,7 +4193,7 @@ void Spell::SendSpellStart() if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list { - castData.RemainingRunes = boost::in_place(); + castData.RemainingRunes.emplace(); //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster @@ -4311,7 +4311,7 @@ void Spell::SendSpellGo() if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list { - castData.RemainingRunes = boost::in_place(); + castData.RemainingRunes.emplace(); //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster @@ -4612,7 +4612,7 @@ void Spell::SendChannelStart(uint32 duration) if (schoolImmunityMask || mechanicImmunityMask) { - spellChannelStart.InterruptImmunities = boost::in_place(); + spellChannelStart.InterruptImmunities.emplace(); spellChannelStart.InterruptImmunities->SchoolImmunities = schoolImmunityMask; spellChannelStart.InterruptImmunities->Immunities = mechanicImmunityMask; } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 62a5ee6d3fb..a54b2856a81 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2310,8 +2310,8 @@ void Spell::EffectDispel(SpellEffIndex effIndex) WorldPackets::CombatLog::SpellDispellData dispellData; dispellData.SpellID = dispelableAura.GetAura()->GetId(); dispellData.Harmful = false; // TODO: use me - dispellData.Rolled = boost::none; // TODO: use me - dispellData.Needed = boost::none; // TODO: use me + dispellData.Rolled = std::nullopt; // TODO: use me + dispellData.Needed = std::nullopt; // TODO: use me unitTarget->RemoveAurasDueToSpellByDispel(dispelableAura.GetAura()->GetId(), m_spellInfo->Id, dispelableAura.GetAura()->GetCasterGUID(), m_caster, dispelableAura.GetDispelCharges()); @@ -4457,7 +4457,7 @@ void Spell::EffectCharge(SpellEffIndex effIndex) Optional spellEffectExtraData; if (effectInfo->MiscValueB) { - spellEffectExtraData = boost::in_place(); + spellEffectExtraData.emplace(); spellEffectExtraData->Target = unitTarget->GetGUID(); spellEffectExtraData->SpellVisualId = effectInfo->MiscValueB; } @@ -4466,10 +4466,10 @@ void Spell::EffectCharge(SpellEffIndex effIndex) { //unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ); Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster)); - m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed, EVENT_CHARGE, false, unitTarget, spellEffectExtraData.get_ptr()); + m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed, EVENT_CHARGE, false, unitTarget, std::to_address(spellEffectExtraData)); } else - m_caster->GetMotionMaster()->MoveCharge(*m_preGeneratedPath, speed, unitTarget, spellEffectExtraData.get_ptr()); + m_caster->GetMotionMaster()->MoveCharge(*m_preGeneratedPath, speed, unitTarget, std::to_address(spellEffectExtraData)); } if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET) @@ -5201,8 +5201,8 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex /*effIndex*/) WorldPackets::CombatLog::SpellDispellData dispellData; dispellData.SpellID = dispell.first; dispellData.Harmful = false; // TODO: use me - dispellData.Rolled = boost::none; // TODO: use me - dispellData.Needed = boost::none; // TODO: use me + dispellData.Rolled = std::nullopt; // TODO: use me + dispellData.Needed = std::nullopt; // TODO: use me unitTarget->RemoveAurasDueToSpellBySteal(dispell.first, dispell.second, m_caster); diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index ae3fe645497..3ea2736e705 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -40,7 +40,7 @@ struct SpellHistory::PersistenceHelper static CharacterDatabaseStatements const ChargesDeleteStatement = CHAR_DEL_CHAR_SPELL_CHARGES; static CharacterDatabaseStatements const ChargesInsertStatement = CHAR_INS_CHAR_SPELL_CHARGES; - static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt64(index, owner->GetGUID().GetCounter()); } + static void SetIdentifier(CharacterDatabasePreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt64(index, owner->GetGUID().GetCounter()); } static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry) { @@ -67,7 +67,7 @@ struct SpellHistory::PersistenceHelper return true; } - static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown) + static void WriteCooldown(CharacterDatabasePreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown) { stmt->setUInt32(index++, cooldown.first); stmt->setUInt32(index++, cooldown.second.ItemId); @@ -76,7 +76,7 @@ struct SpellHistory::PersistenceHelper stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CategoryEnd))); } - static void WriteCharge(PreparedStatement* stmt, uint8& index, uint32 chargeCategory, ChargeEntry const& charge) + static void WriteCharge(CharacterDatabasePreparedStatement* stmt, uint8& index, uint32 chargeCategory, ChargeEntry const& charge) { stmt->setUInt32(index++, chargeCategory); stmt->setUInt32(index++, uint32(Clock::to_time_t(charge.RechargeStart))); @@ -92,7 +92,7 @@ struct SpellHistory::PersistenceHelper static CharacterDatabaseStatements const ChargesDeleteStatement = CHAR_DEL_PET_SPELL_CHARGES; static CharacterDatabaseStatements const ChargesInsertStatement = CHAR_INS_PET_SPELL_CHARGES; - static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetCharmInfo()->GetPetNumber()); } + static void SetIdentifier(CharacterDatabasePreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetCharmInfo()->GetPetNumber()); } static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry) { @@ -119,7 +119,7 @@ struct SpellHistory::PersistenceHelper return true; } - static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown) + static void WriteCooldown(CharacterDatabasePreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown) { stmt->setUInt32(index++, cooldown.first); stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd))); @@ -127,7 +127,7 @@ struct SpellHistory::PersistenceHelper stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CategoryEnd))); } - static void WriteCharge(PreparedStatement* stmt, uint8& index, uint32 chargeCategory, ChargeEntry const& charge) + static void WriteCharge(CharacterDatabasePreparedStatement* stmt, uint8& index, uint32 chargeCategory, ChargeEntry const& charge) { stmt->setUInt32(index++, chargeCategory); stmt->setUInt32(index++, uint32(Clock::to_time_t(charge.RechargeStart))); @@ -171,12 +171,12 @@ void SpellHistory::LoadFromDB(PreparedQueryResult cooldownsResult, PreparedQuery } template -void SpellHistory::SaveToDB(SQLTransaction& trans) +void SpellHistory::SaveToDB(CharacterDatabaseTransaction& trans) { typedef PersistenceHelper StatementInfo; uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsDeleteStatement); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsDeleteStatement); StatementInfo::SetIdentifier(stmt, index++, _owner); trans->Append(stmt); @@ -1101,5 +1101,5 @@ void SpellHistory::RestoreCooldownStateAfterDuel() template void SpellHistory::LoadFromDB(PreparedQueryResult cooldownsResult, PreparedQueryResult chargesResult); template void SpellHistory::LoadFromDB(PreparedQueryResult cooldownsResult, PreparedQueryResult chargesResult); -template void SpellHistory::SaveToDB(SQLTransaction& trans); -template void SpellHistory::SaveToDB(SQLTransaction& trans); +template void SpellHistory::SaveToDB(CharacterDatabaseTransaction& trans); +template void SpellHistory::SaveToDB(CharacterDatabaseTransaction& trans); diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h index c2bbfde6fd7..ca8778155e2 100644 --- a/src/server/game/Spells/SpellHistory.h +++ b/src/server/game/Spells/SpellHistory.h @@ -76,7 +76,7 @@ class TC_GAME_API SpellHistory void LoadFromDB(PreparedQueryResult cooldownsResult, PreparedQueryResult chargesResult); template - void SaveToDB(SQLTransaction& trans); + void SaveToDB(CharacterDatabaseTransaction& trans); void Update(); diff --git a/src/server/game/Support/SupportMgr.cpp b/src/server/game/Support/SupportMgr.cpp index 73ac46f077d..5016b34c643 100644 --- a/src/server/game/Support/SupportMgr.cpp +++ b/src/server/game/Support/SupportMgr.cpp @@ -129,7 +129,7 @@ void BugTicket::LoadFromDB(Field* fields) void BugTicket::SaveToDB() const { uint8 idx = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_BUG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_BUG); stmt->setUInt32(idx, _id); stmt->setUInt64(++idx, _playerGuid.GetCounter()); stmt->setString(++idx, _note); @@ -147,7 +147,7 @@ void BugTicket::SaveToDB() const void BugTicket::DeleteFromDB() { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_BUG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_BUG); stmt->setUInt32(0, _id); CharacterDatabase.Execute(stmt); } @@ -224,10 +224,10 @@ void ComplaintTicket::LoadChatLineFromDB(Field* fields) void ComplaintTicket::SaveToDB() const { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); uint8 idx = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_COMPLAINT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_COMPLAINT); stmt->setUInt32(idx, _id); stmt->setUInt64(++idx, _playerGuid.GetCounter()); stmt->setString(++idx, _note); @@ -266,7 +266,7 @@ void ComplaintTicket::SaveToDB() const void ComplaintTicket::DeleteFromDB() { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_COMPLAINT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_COMPLAINT); stmt->setUInt32(0, _id); CharacterDatabase.Execute(stmt); @@ -338,7 +338,7 @@ void SuggestionTicket::LoadFromDB(Field* fields) void SuggestionTicket::SaveToDB() const { uint8 idx = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_SUGGESTION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_SUGGESTION); stmt->setUInt32(idx, _id); stmt->setUInt64(++idx, _playerGuid.GetCounter()); stmt->setString(++idx, _note); @@ -356,7 +356,7 @@ void SuggestionTicket::SaveToDB() const void SuggestionTicket::DeleteFromDB() { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_SUGGESTION); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_SUGGESTION); stmt->setUInt32(0, _id); CharacterDatabase.Execute(stmt); } @@ -514,7 +514,7 @@ void SupportMgr::LoadBugTickets() _lastBugId = 0; _openBugTicketCount = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_BUGS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_BUGS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { @@ -554,7 +554,7 @@ void SupportMgr::LoadComplaintTickets() _lastComplaintId = 0; _openComplaintTicketCount = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_COMPLAINTS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_COMPLAINTS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { @@ -563,7 +563,7 @@ void SupportMgr::LoadComplaintTickets() } uint32 count = 0; - PreparedStatement* chatLogStmt; + CharacterDatabasePreparedStatement* chatLogStmt; PreparedQueryResult chatLogResult; do { @@ -609,7 +609,7 @@ void SupportMgr::LoadSuggestionTickets() _lastSuggestionId = 0; _openSuggestionTicketCount = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_SUGGESTIONS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_SUGGESTIONS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { @@ -743,7 +743,7 @@ TC_GAME_API void SupportMgr::ResetTickets() _lastBugId = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_BUGS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_BUGS); CharacterDatabase.Execute(stmt); } @@ -756,7 +756,7 @@ TC_GAME_API void SupportMgr::ResetTickets() _lastComplaintId = 0; - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); trans->Append(CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_COMPLAINTS)); trans->Append(CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_COMPLAINT_CHATLOGS)); CharacterDatabase.CommitTransaction(trans); @@ -771,7 +771,7 @@ TC_GAME_API void SupportMgr::ResetTickets() _lastSuggestionId = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_SUGGESTIONS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_SUGGESTIONS); CharacterDatabase.Execute(stmt); } diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index e7f479248c5..b724214825b 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -91,7 +91,7 @@ void CreatureTextMgr::LoadCreatureTexts() mTextMap.clear(); // for reload case //all currently used temp texts are NOT reset - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEXT); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEXT); PreparedQueryResult result = WorldDatabase.Query(stmt); if (!result) diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 0f969c09a9f..6fc2c138ec3 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -471,7 +471,7 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s bool incHighest = true; if (guid && guid < sObjectMgr->GetGenerator().GetNextAfterMaxUsed()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_GUID); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_GUID); stmt->setUInt64(0, guid); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -489,7 +489,7 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s if (ObjectMgr::CheckPlayerName(name, sWorld->GetDefaultDbcLocale(), true) == CHAR_NAME_SUCCESS) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, name); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -518,7 +518,7 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s ObjectGuid::LowType itemLowGuidOffset = sObjectMgr->GetGenerator().GetNextAfterMaxUsed(); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); while (!feof(fin)) { if (!fgets(buf, 32000, fin)) @@ -597,7 +597,7 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s // check if the original name already exists name = GetNth(line, GetColNumber(tn, "name")); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, name); PreparedQueryResult result = CharacterDatabase.Query(stmt); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 33489b74fea..17babb96cf3 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2287,7 +2287,7 @@ void World::LoadAutobroadcasts() m_Autobroadcasts.clear(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST); stmt->setInt32(0, realm.Id.Realm); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -2447,7 +2447,7 @@ void World::Update(uint32 diff) m_timers[WUPDATE_UPTIME].Reset(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_UPTIME_PLAYERS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_UPTIME_PLAYERS); stmt->setUInt32(0, tmpDiff); stmt->setUInt16(1, uint16(maxOnlinePlayers)); @@ -2466,7 +2466,7 @@ void World::Update(uint32 diff) { m_timers[WUPDATE_CLEANDB].Reset(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_OLD_LOGS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_OLD_LOGS); stmt->setUInt32(0, sWorld->getIntConfig(CONFIG_LOGDB_CLEARTIME)); stmt->setUInt32(1, uint32(time(0))); @@ -2782,8 +2782,9 @@ BanReturn World::BanAccount(BanMode mode, std::string const& nameOrIP, std::stri /// Ban an account or ban an IP address, duration is in seconds if positive, otherwise permban BanReturn World::BanAccount(BanMode mode, std::string const& nameOrIP, uint32 duration_secs, std::string const& reason, std::string const& author) { - PreparedQueryResult resultAccounts = PreparedQueryResult(NULL); //used for kicking - PreparedStatement* stmt = NULL; + PreparedQueryResult resultAccounts = PreparedQueryResult(nullptr); //used for kicking + LoginDatabasePreparedStatement* stmt = nullptr; + CharacterDatabasePreparedStatement* cstmt = nullptr; // Prevent banning an already banned account if (mode == BAN_ACCOUNT && AccountMgr::IsBannedAccount(nameOrIP)) @@ -2812,9 +2813,9 @@ BanReturn World::BanAccount(BanMode mode, std::string const& nameOrIP, uint32 du break; case BAN_CHARACTER: // No SQL injection with prepared statements - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_BY_NAME); - stmt->setString(0, nameOrIP); - resultAccounts = CharacterDatabase.Query(stmt); + cstmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_BY_NAME); + cstmt->setString(0, nameOrIP); + resultAccounts = CharacterDatabase.Query(cstmt); break; default: return BAN_SYNTAX_ERROR; @@ -2829,7 +2830,7 @@ BanReturn World::BanAccount(BanMode mode, std::string const& nameOrIP, uint32 du } ///- Disconnect all affected players (for IP it can be several) - SQLTransaction trans = LoginDatabase.BeginTransaction(); + LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); do { Field* fieldsAccount = resultAccounts->Fetch(); @@ -2863,7 +2864,7 @@ BanReturn World::BanAccount(BanMode mode, std::string const& nameOrIP, uint32 du /// Remove a ban from an account or IP address bool World::RemoveBanAccount(BanMode mode, std::string const& nameOrIP) { - PreparedStatement* stmt = NULL; + LoginDatabasePreparedStatement* stmt = nullptr; if (mode == BAN_IP) { stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_IP_NOT_BANNED); @@ -2908,9 +2909,9 @@ BanReturn World::BanCharacter(std::string const& name, std::string const& durati guid = pBanned->GetGUID(); //Use transaction in order to ensure the order of the queries - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // make sure there is only one active ban - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_BAN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_BAN); stmt->setUInt64(0, guid.GetCounter()); trans->Append(stmt); @@ -2944,7 +2945,7 @@ bool World::RemoveBanCharacter(std::string const& name) else guid = pBanned->GetGUID(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_BAN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_BAN); stmt->setUInt64(0, guid.GetCounter()); CharacterDatabase.Execute(stmt); return true; @@ -3147,9 +3148,9 @@ void World::SendAutoBroadcast() void World::UpdateRealmCharCount(uint32 accountId) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT); stmt->setUInt32(0, accountId); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&World::_UpdateRealmCharCount, this, std::placeholders::_1))); + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&World::_UpdateRealmCharCount, this, std::placeholders::_1))); } void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount) @@ -3160,9 +3161,9 @@ void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount) uint32 accountId = fields[0].GetUInt32(); uint8 charCount = uint8(fields[1].GetUInt64()); - SQLTransaction trans = LoginDatabase.BeginTransaction(); + LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); stmt->setUInt32(0, accountId); stmt->setUInt32(1, realm.Id.Realm); trans->Append(stmt); @@ -3316,7 +3317,7 @@ void World::DailyReset() { TC_LOG_INFO("misc", "Daily quests reset for all characters."); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY); CharacterDatabase.Execute(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS); @@ -3345,7 +3346,7 @@ void World::ResetCurrencyWeekCap() void World::LoadDBAllowedSecurityLevel() { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL); stmt->setInt32(0, int32(realm.Id.Realm)); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -3366,7 +3367,7 @@ void World::ResetWeeklyQuests() { TC_LOG_INFO("misc", "Weekly quests reset for all characters."); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY); CharacterDatabase.Execute(stmt); for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) @@ -3384,7 +3385,7 @@ void World::ResetMonthlyQuests() { TC_LOG_INFO("misc", "Monthly quests reset for all characters."); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY); CharacterDatabase.Execute(stmt); for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) @@ -3428,7 +3429,7 @@ void World::ResetEventSeasonalQuests(uint16 event_id) { TC_LOG_INFO("misc", "Seasonal quests reset for all characters."); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT); stmt->setUInt16(0, event_id); CharacterDatabase.Execute(stmt); @@ -3441,7 +3442,7 @@ void World::ResetRandomBG() { TC_LOG_INFO("misc", "Random BG status reset for all characters."); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM_ALL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM_ALL); CharacterDatabase.Execute(stmt); for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) @@ -3540,7 +3541,7 @@ void World::setWorldState(uint32 index, uint32 value) if (it->second == value) return; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_WORLDSTATE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_WORLDSTATE); stmt->setUInt32(0, uint32(value)); stmt->setUInt32(1, index); @@ -3549,7 +3550,7 @@ void World::setWorldState(uint32 index, uint32 value) } else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_WORLDSTATE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_WORLDSTATE); stmt->setUInt32(0, index); stmt->setUInt32(1, uint32(value)); @@ -3567,7 +3568,7 @@ uint32 World::getWorldState(uint32 index) const void World::ProcessQueryCallbacks() { - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); } /** diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 652e1f16622..2929fd447f1 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -23,11 +23,11 @@ #ifndef __WORLD_H #define __WORLD_H +#include "AsyncCallbackProcessor.h" #include "Common.h" #include "DatabaseEnvFwd.h" #include "LockedQueue.h" #include "ObjectGuid.h" -#include "QueryCallbackProcessor.h" #include "SharedDefines.h" #include "Timer.h" diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index e33fb4f5e90..a466bade962 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -98,7 +98,7 @@ class account_commandscript : public CommandScript return false; } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPANSION); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPANSION); stmt->setUInt8(0, uint8(expansion)); stmt->setUInt32(1, accountId); @@ -232,7 +232,7 @@ class account_commandscript : public CommandScript static bool HandleAccountOnlineListCommand(ChatHandler* handler, char const* /*args*/) { ///- Get the list of accounts ID logged to the realm - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ONLINE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ONLINE); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -256,9 +256,9 @@ class account_commandscript : public CommandScript ///- Get the username, last IP and GM level of each account // No SQL injection. account is uint32. - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO); - stmt->setUInt32(0, account); - PreparedQueryResult resultLogin = LoginDatabase.Query(stmt); + LoginDatabasePreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO); + stmt2->setUInt32(0, account); + PreparedQueryResult resultLogin = LoginDatabase.Query(stmt2); if (resultLogin) { @@ -293,7 +293,7 @@ class account_commandscript : public CommandScript { if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(handler->GetSession()->GetRemoteAddress())) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK_COUNTRY); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK_COUNTRY); stmt->setString(0, location->CountryCode); stmt->setUInt32(1, handler->GetSession()->GetAccountId()); LoginDatabase.Execute(stmt); @@ -307,7 +307,7 @@ class account_commandscript : public CommandScript } else if (param == "off") { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK_COUNTRY); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK_COUNTRY); stmt->setString(0, "00"); stmt->setUInt32(1, handler->GetSession()->GetAccountId()); LoginDatabase.Execute(stmt); @@ -333,7 +333,7 @@ class account_commandscript : public CommandScript if (!param.empty()) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK); if (param == "on") { @@ -560,7 +560,7 @@ class account_commandscript : public CommandScript std::string emailoutput; uint32 accountId = handler->GetSession()->GetAccountId(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_EMAIL_BY_ID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_EMAIL_BY_ID); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -627,7 +627,7 @@ class account_commandscript : public CommandScript if (expansion > sWorld->getIntConfig(CONFIG_EXPANSION)) return false; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPANSION); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPANSION); stmt->setUInt8(0, expansion); stmt->setUInt32(1, accountId); @@ -710,7 +710,7 @@ class account_commandscript : public CommandScript // Check and abort if the target gm has a higher rank on one of the realms and the new realm is -1 if (gmRealmID == -1 && !AccountMgr::IsConsoleAccount(playerSecurity)) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS_GMLEVEL_TEST); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS_GMLEVEL_TEST); stmt->setUInt32(0, targetAccountId); stmt->setUInt8(1, uint8(gm)); diff --git a/src/server/scripts/Commands/cs_ban.cpp b/src/server/scripts/Commands/cs_ban.cpp index 5c9c89ab7eb..665b8940658 100644 --- a/src/server/scripts/Commands/cs_ban.cpp +++ b/src/server/scripts/Commands/cs_ban.cpp @@ -316,7 +316,7 @@ class ban_commandscript : public CommandScript else targetGuid = target->GetGUID(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BANINFO); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BANINFO); stmt->setUInt64(0, targetGuid.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -377,7 +377,7 @@ class ban_commandscript : public CommandScript static bool HandleBanListAccountCommand(ChatHandler* handler, char const* args) { - PreparedStatement* stmt = NULL; + LoginDatabasePreparedStatement* stmt = NULL; stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS); LoginDatabase.Execute(stmt); @@ -499,7 +499,7 @@ class ban_commandscript : public CommandScript return false; std::string filter(filterStr); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME_FILTER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME_FILTER); stmt->setString(0, filter); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -516,7 +516,7 @@ class ban_commandscript : public CommandScript do { Field* fields = result->Fetch(); - PreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BANNED_NAME); + CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BANNED_NAME); stmt2->setUInt64(0, fields[0].GetUInt64()); PreparedQueryResult banResult = CharacterDatabase.Query(stmt2); if (banResult) @@ -538,7 +538,7 @@ class ban_commandscript : public CommandScript std::string char_name = fields[1].GetString(); - PreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BANINFO_LIST); + CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BANINFO_LIST); stmt2->setUInt64(0, fields[0].GetUInt64()); PreparedQueryResult banInfo = CharacterDatabase.Query(stmt2); if (banInfo) @@ -579,7 +579,7 @@ class ban_commandscript : public CommandScript static bool HandleBanListIPCommand(ChatHandler* handler, char const* args) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS); LoginDatabase.Execute(stmt); char* filterStr = strtok((char*)args, " "); diff --git a/src/server/scripts/Commands/cs_battlenet_account.cpp b/src/server/scripts/Commands/cs_battlenet_account.cpp index 451f4904840..263119227a8 100644 --- a/src/server/scripts/Commands/cs_battlenet_account.cpp +++ b/src/server/scripts/Commands/cs_battlenet_account.cpp @@ -146,7 +146,7 @@ class battlenet_account_commandscript : public CommandScript { if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(handler->GetSession()->GetRemoteAddress())) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY); stmt->setString(0, location->CountryCode); stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId()); LoginDatabase.Execute(stmt); @@ -160,7 +160,7 @@ class battlenet_account_commandscript : public CommandScript } else if (param == "off") { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY); stmt->setString(0, "00"); stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId()); LoginDatabase.Execute(stmt); @@ -188,7 +188,7 @@ class battlenet_account_commandscript : public CommandScript if (!param.empty()) { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK); if (param == "on") { @@ -471,7 +471,7 @@ class battlenet_account_commandscript : public CommandScript return false; char* battlenetAccountName = strtok((char*)args, " "); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_LIST_SMALL); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_LIST_SMALL); stmt->setString(0, battlenetAccountName); if (PreparedQueryResult accountList = LoginDatabase.Query(stmt)) { diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index f62ae5f45ca..62d3c77acd1 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -101,7 +101,7 @@ class character_commandscript : public CommandScript static bool GetDeletedCharacterInfoList(DeletedInfoList& foundList, std::string searchString) { PreparedQueryResult result; - PreparedStatement* stmt; + CharacterDatabasePreparedStatement* stmt; if (!searchString.empty()) { // search by GUID @@ -220,7 +220,7 @@ class character_commandscript : public CommandScript return; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_RESTORE_DELETE_INFO); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_RESTORE_DELETE_INFO); stmt->setString(0, delInfo.name); stmt->setUInt32(1, delInfo.accountId); stmt->setUInt64(2, delInfo.guid.GetCounter()); @@ -250,7 +250,7 @@ class character_commandscript : public CommandScript else { // Update level and reset XP, everything else will be updated at login - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_LEVEL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_LEVEL); stmt->setUInt8(0, uint8(newLevel)); stmt->setUInt64(1, playerGuid.GetCounter()); CharacterDatabase.Execute(stmt); @@ -355,7 +355,7 @@ class character_commandscript : public CommandScript } } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, newName); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) @@ -417,7 +417,7 @@ class character_commandscript : public CommandScript std::string oldNameLink = handler->playerLink(targetName); handler->PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldNameLink.c_str(), targetGuid.ToString().c_str()); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_RENAME)); stmt->setUInt64(1, targetGuid.GetCounter()); CharacterDatabase.Execute(stmt); @@ -476,7 +476,7 @@ class character_commandscript : public CommandScript if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE)); if (target) { @@ -504,7 +504,7 @@ class character_commandscript : public CommandScript if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_FACTION)); if (target) { @@ -531,7 +531,7 @@ class character_commandscript : public CommandScript if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_RACE)); if (target) { @@ -584,7 +584,7 @@ class character_commandscript : public CommandScript return false; } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); stmt->setString(0, accountName); if (PreparedQueryResult result = LoginDatabase.Query(stmt)) newAccountId = (*result)[0].GetUInt32(); @@ -609,10 +609,10 @@ class character_commandscript : public CommandScript } } - stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_BY_GUID); - stmt->setUInt32(0, newAccountId); - stmt->setUInt32(1, targetGuid.GetCounter()); - CharacterDatabase.DirectExecute(stmt); + CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_BY_GUID); + stmt2->setUInt32(0, newAccountId); + stmt2->setUInt32(1, targetGuid.GetCounter()); + CharacterDatabase.DirectExecute(stmt2); sWorld->UpdateRealmCharCount(oldAccountId); sWorld->UpdateRealmCharCount(newAccountId); diff --git a/src/server/scripts/Commands/cs_disable.cpp b/src/server/scripts/Commands/cs_disable.cpp index 477e6f14272..fc91239b956 100644 --- a/src/server/scripts/Commands/cs_disable.cpp +++ b/src/server/scripts/Commands/cs_disable.cpp @@ -188,7 +188,7 @@ class disable_commandscript : public CommandScript break; } - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_DISABLES); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_DISABLES); stmt->setUInt32(0, entry); stmt->setUInt8(1, disableType); PreparedQueryResult result = WorldDatabase.Query(stmt); @@ -313,7 +313,7 @@ class disable_commandscript : public CommandScript break; } - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_DISABLES); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_DISABLES); stmt->setUInt32(0, entry); stmt->setUInt8(1, disableType); PreparedQueryResult result = WorldDatabase.Query(stmt); diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index ff1685ceef4..f5bf88672fe 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -170,7 +170,7 @@ class gm_commandscript : public CommandScript static bool HandleGMListFullCommand(ChatHandler* handler, char const* /*args*/) { ///- Get the accounts with GM Level >0 - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_GM_ACCOUNTS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_GM_ACCOUNTS); stmt->setUInt8(0, uint8(SEC_MODERATOR)); stmt->setInt32(1, int32(realm.Id.Realm)); PreparedQueryResult result = LoginDatabase.Query(stmt); diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 1951ae9464c..208e692832a 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -550,7 +550,7 @@ class gobject_commandscript : public CommandScript Player* player = handler->GetSession()->GetPlayer(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_GAMEOBJECT_NEAREST); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_GAMEOBJECT_NEAREST); stmt->setFloat(0, player->GetPositionX()); stmt->setFloat(1, player->GetPositionY()); stmt->setFloat(2, player->GetPositionZ()); diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp index bae4a73d959..6de6f286393 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -296,7 +296,7 @@ class group_commandscript : public CommandScript // If not, we extract it from the SQL. if (!groupTarget) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); stmt->setUInt64(0, guidTarget.GetCounter()); PreparedQueryResult resultGroup = CharacterDatabase.Query(stmt); if (resultGroup) diff --git a/src/server/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index 80cf14438ac..ce7037b7811 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -151,7 +151,7 @@ class guild_commandscript : public CommandScript return false; // player's guild membership checked in AddMember before add - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); return targetGuild->AddMember(trans, targetGuid); } @@ -170,7 +170,7 @@ class guild_commandscript : public CommandScript if (!targetGuild) return false; - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); targetGuild->DeleteMember(trans, targetGuid, false, true, true); return true; } @@ -198,7 +198,7 @@ class guild_commandscript : public CommandScript return false; uint8 newRank = uint8(atoi(rankStr)); - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); return targetGuild->ChangeMemberRank(trans, targetGuid, newRank); } diff --git a/src/server/scripts/Commands/cs_lfg.cpp b/src/server/scripts/Commands/cs_lfg.cpp index c511d0d5671..f42803b2c2f 100644 --- a/src/server/scripts/Commands/cs_lfg.cpp +++ b/src/server/scripts/Commands/cs_lfg.cpp @@ -99,7 +99,7 @@ class lfg_commandscript : public CommandScript groupTarget = playerTarget->GetGroup(); else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); stmt->setUInt64(0, guidTarget.GetCounter()); PreparedQueryResult resultGroup = CharacterDatabase.Query(stmt); if (resultGroup) diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp index 2a250656de0..8ab6cae5870 100644 --- a/src/server/scripts/Commands/cs_list.cpp +++ b/src/server/scripts/Commands/cs_list.cpp @@ -166,7 +166,7 @@ class list_commandscript : public CommandScript // inventory case uint32 inventoryCount = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM); stmt->setUInt32(0, itemId); result = CharacterDatabase.Query(stmt); @@ -478,7 +478,7 @@ class list_commandscript : public CommandScript Player* target; ObjectGuid targetGuid; std::string targetName; - PreparedStatement* stmt = NULL; + CharacterDatabasePreparedStatement* stmt = NULL; if (!*args) return false; diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 1c235bb8483..cbfe1f81f13 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -1298,7 +1298,7 @@ class lookup_commandscript : public CommandScript limit = limitStr ? atoi(limitStr) : -1; } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_IP); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_IP); stmt->setString(0, ip); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -1317,7 +1317,7 @@ class lookup_commandscript : public CommandScript if (!Utf8ToUpperOnlyLatin(account)) return false; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME); stmt->setString(0, account); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -1333,7 +1333,7 @@ class lookup_commandscript : public CommandScript char* limitStr = strtok(NULL, " "); int32 limit = limitStr ? atoi(limitStr) : -1; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL); stmt->setString(0, email); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -1365,7 +1365,7 @@ class lookup_commandscript : public CommandScript uint32 accountId = fields[0].GetUInt32(); std::string accountName = fields[1].GetString(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_GUID_NAME_BY_ACC); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_GUID_NAME_BY_ACC); stmt->setUInt32(0, accountId); PreparedQueryResult result2 = CharacterDatabase.Query(stmt); diff --git a/src/server/scripts/Commands/cs_message.cpp b/src/server/scripts/Commands/cs_message.cpp index f7b2b713eba..181d9cd48ae 100644 --- a/src/server/scripts/Commands/cs_message.cpp +++ b/src/server/scripts/Commands/cs_message.cpp @@ -115,7 +115,7 @@ class message_commandscript : public CommandScript if (channel) channel->SetOwnership(true); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_OWNERSHIP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_OWNERSHIP); stmt->setUInt8 (0, 1); stmt->setString(1, channelStr); CharacterDatabase.Execute(stmt); @@ -126,7 +126,7 @@ class message_commandscript : public CommandScript if (channel) channel->SetOwnership(false); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_OWNERSHIP); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_OWNERSHIP); stmt->setUInt8 (0, 0); stmt->setString(1, channelStr); CharacterDatabase.Execute(stmt); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 27818508b7f..f4d5f46bc9d 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -128,7 +128,7 @@ class misc_commandscript : public CommandScript { if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_FACTIONS_OVERALL); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_FACTIONS_OVERALL); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) @@ -607,7 +607,7 @@ class misc_commandscript : public CommandScript handler->PSendSysMessage(LANG_SUMMONING, nameLink.c_str(), handler->GetTrinityString(LANG_OFFLINE)); // in point where GM stay - SQLTransaction dummy; + CharacterDatabaseTransaction dummy; Player::SavePositionInDB(WorldLocation(handler->GetSession()->GetPlayer()->GetMapId(), handler->GetSession()->GetPlayer()->GetPositionX(), handler->GetSession()->GetPlayer()->GetPositionY(), @@ -667,7 +667,7 @@ class misc_commandscript : public CommandScript } else { - SQLTransaction trans(nullptr); + CharacterDatabaseTransaction trans(nullptr); Player::OfflineResurrect(targetGuid, trans); } @@ -1000,14 +1000,14 @@ class misc_commandscript : public CommandScript if (!player) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_HOMEBIND); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_HOMEBIND); stmt->setUInt64(0, targetGUID.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); - SQLTransaction dummy; + CharacterDatabaseTransaction dummy; Player::SavePositionInDB(WorldLocation(fields[0].GetUInt16(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat(), 0.0f), fields[1].GetUInt16(), targetGUID, dummy); return true; } @@ -1614,7 +1614,7 @@ class misc_commandscript : public CommandScript Player* target; ObjectGuid targetGuid; std::string targetName; - PreparedStatement* stmt = NULL; + CharacterDatabasePreparedStatement* stmt = NULL; // To make sure we get a target, we convert our guid to an omniversal... ObjectGuid parseGUID = ObjectGuid::Create(strtoull(args, nullptr, 10)); @@ -1768,10 +1768,10 @@ class misc_commandscript : public CommandScript } // Query the prepared statement for login data - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO); - stmt->setInt32(0, int32(realm.Id.Realm)); - stmt->setUInt32(1, accId); - PreparedQueryResult result = LoginDatabase.Query(stmt); + LoginDatabasePreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO); + stmt2->setInt32(0, int32(realm.Id.Realm)); + stmt2->setUInt32(1, accId); + PreparedQueryResult result = LoginDatabase.Query(stmt2); if (result) { @@ -1814,7 +1814,7 @@ class misc_commandscript : public CommandScript std::string nameLink = handler->playerLink(targetName); // Returns banType, banTime, bannedBy, banreason - PreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO_BANS); + stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO_BANS); stmt2->setUInt32(0, accId); PreparedQueryResult result2 = LoginDatabase.Query(stmt2); if (!result2) @@ -1834,9 +1834,9 @@ class misc_commandscript : public CommandScript } // Can be used to query data from Characters database - stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_XP); - stmt2->setUInt64(0, lowguid); - PreparedQueryResult result4 = CharacterDatabase.Query(stmt2); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_XP); + stmt->setUInt64(0, lowguid); + PreparedQueryResult result4 = CharacterDatabase.Query(stmt); if (result4) { @@ -1848,7 +1848,7 @@ class misc_commandscript : public CommandScript if (gguid) { // Guild Data - an own query, because it may not happen. - PreparedStatement* stmt3 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED); + CharacterDatabasePreparedStatement* stmt3 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED); stmt3->setUInt64(0, lowguid); PreparedQueryResult result5 = CharacterDatabase.Query(stmt3); if (result5) @@ -1952,7 +1952,7 @@ class misc_commandscript : public CommandScript // Mail Data - an own query, because it may or may not be useful. // SQL: "SELECT SUM(CASE WHEN (checked & 1) THEN 1 ELSE 0 END) AS 'readmail', COUNT(*) AS 'totalmail' FROM mail WHERE `receiver` = ?" - PreparedStatement* stmt4 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_MAILS); + CharacterDatabasePreparedStatement* stmt4 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_MAILS); stmt4->setUInt64(0, lowguid); PreparedQueryResult result6 = CharacterDatabase.Query(stmt4); if (result6) @@ -2029,7 +2029,7 @@ class misc_commandscript : public CommandScript if (handler->HasLowerSecurity (target, targetGuid, true)) return false; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); std::string muteBy = ""; if (handler->GetSession()) muteBy = handler->GetSession()->GetPlayerName(); @@ -2108,7 +2108,7 @@ class misc_commandscript : public CommandScript target->GetSession()->m_muteTime = 0; } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); stmt->setInt64(0, 0); stmt->setString(1, ""); stmt->setString(2, ""); @@ -2156,7 +2156,7 @@ class misc_commandscript : public CommandScript // helper for mutehistory static bool HandleMuteInfoHelper(uint32 accountId, char const* accountName, ChatHandler *handler) { - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO); + LoginDatabasePreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -2650,7 +2650,7 @@ class misc_commandscript : public CommandScript } // If player found: delete his freeze aura - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_FROZEN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_FROZEN); stmt->setUInt64(0, guid.GetCounter()); CharacterDatabase.Execute(stmt); @@ -2670,7 +2670,7 @@ class misc_commandscript : public CommandScript static bool HandleListFreezeCommand(ChatHandler* handler, char const* /*args*/) { // Get names from DB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURA_FROZEN); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURA_FROZEN); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index c140bfd1338..6382bb5a8cd 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -429,7 +429,7 @@ class npc_commandscript : public CommandScript wait = 0; // Update movement type - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE); stmt->setUInt8(0, uint8(WAYPOINT_MOTION_TYPE)); stmt->setUInt64(1, lowGuid); @@ -619,7 +619,7 @@ class npc_commandscript : public CommandScript const_cast(cinfo)->faction = factionId; // ..and DB - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_FACTION); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_FACTION); stmt->setUInt16(0, uint16(factionId)); stmt->setUInt32(1, creature->GetEntry()); @@ -648,7 +648,7 @@ class npc_commandscript : public CommandScript creature->SetUInt64Value(UNIT_NPC_FLAGS, npcFlags); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_NPCFLAG); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_NPCFLAG); stmt->setUInt64(0, npcFlags); stmt->setUInt32(1, creature->GetEntry()); @@ -799,7 +799,7 @@ class npc_commandscript : public CommandScript Player* player = handler->GetSession()->GetPlayer(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_NEAREST); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_NEAREST); stmt->setFloat(0, player->GetPositionX()); stmt->setFloat(1, player->GetPositionY()); stmt->setFloat(2, player->GetPositionZ()); @@ -901,7 +901,7 @@ class npc_commandscript : public CommandScript } } - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_POSITION); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_POSITION); stmt->setFloat(0, x); stmt->setFloat(1, y); @@ -1200,7 +1200,7 @@ class npc_commandscript : public CommandScript creature->Respawn(); } - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_DISTANCE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_DISTANCE); stmt->setFloat(0, option); stmt->setUInt8(1, uint8(mtype)); @@ -1231,7 +1231,7 @@ class npc_commandscript : public CommandScript ObjectGuid::LowType guidLow = creature->GetSpawnId(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS); stmt->setUInt32(0, spawnTime); stmt->setUInt64(1, guidLow); @@ -1603,7 +1603,7 @@ class npc_commandscript : public CommandScript sFormationMgr->CreatureGroupMap[lowguid] = group_member; creature->SearchFormation(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION); stmt->setUInt64(0, leaderGUID); stmt->setUInt64(1, lowguid); diff --git a/src/server/scripts/Commands/cs_quest.cpp b/src/server/scripts/Commands/cs_quest.cpp index 873e410b68e..8b1e7ad6026 100644 --- a/src/server/scripts/Commands/cs_quest.cpp +++ b/src/server/scripts/Commands/cs_quest.cpp @@ -190,7 +190,7 @@ class quest_commandscript : public CommandScript if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled { // prepare Quest Tracker datas - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_GM_COMPLETE); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_GM_COMPLETE); stmt->setUInt32(0, quest->GetQuestId()); stmt->setUInt64(1, player->GetGUID().GetCounter()); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 2fdf3dde956..0d448196e3f 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -432,7 +432,7 @@ class reload_commandscript : public CommandScript { uint32 entry = atoul(*itr); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE); stmt->setUInt32(0, entry); PreparedQueryResult result = WorldDatabase.Query(stmt); diff --git a/src/server/scripts/Commands/cs_reset.cpp b/src/server/scripts/Commands/cs_reset.cpp index 005a7b99b9b..5400e6f0d98 100644 --- a/src/server/scripts/Commands/cs_reset.cpp +++ b/src/server/scripts/Commands/cs_reset.cpp @@ -175,7 +175,7 @@ class reset_commandscript : public CommandScript } else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_RESET_SPELLS)); stmt->setUInt64(1, targetGuid.GetCounter()); CharacterDatabase.Execute(stmt); @@ -243,7 +243,7 @@ class reset_commandscript : public CommandScript } else if (!playerResult.Guid.IsEmpty()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_RESET_TALENTS | AT_LOGIN_RESET_PET_TALENTS)); stmt->setUInt64(1, playerResult.Guid.GetCounter()); CharacterDatabase.Execute(stmt); @@ -289,7 +289,7 @@ class reset_commandscript : public CommandScript return false; } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ALL_AT_LOGIN_FLAGS); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ALL_AT_LOGIN_FLAGS); stmt->setUInt16(0, uint16(atLogin)); CharacterDatabase.Execute(stmt); diff --git a/src/server/scripts/Commands/cs_send.cpp b/src/server/scripts/Commands/cs_send.cpp index e73b17a1914..4170c5d83dd 100644 --- a/src/server/scripts/Commands/cs_send.cpp +++ b/src/server/scripts/Commands/cs_send.cpp @@ -83,7 +83,7 @@ class send_commandscript : public CommandScript MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : UI64LIT(0), MAIL_STATIONERY_GM); /// @todo Fix poor design - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); MailDraft(subject, text) .SendMailTo(trans, MailReceiver(target, targetGuid.GetCounter()), sender); @@ -184,7 +184,7 @@ class send_commandscript : public CommandScript // fill mail MailDraft draft(subject, text); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); for (ItemPairs::const_iterator itr = items.begin(); itr != items.end(); ++itr) { @@ -241,7 +241,7 @@ class send_commandscript : public CommandScript // from console show nonexisting sender MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : UI64LIT(0), MAIL_STATIONERY_GM); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); MailDraft(subject, text) .AddMoney(money) diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index f274ddc2553..1ba012ce99b 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -30,6 +30,7 @@ EndScriptData */ #include "GitRevision.h" #include "Language.h" #include "Log.h" +#include "MySQLThreading.h" #include "ObjectAccessor.h" #include "Player.h" #include "RBAC.h" @@ -41,8 +42,8 @@ EndScriptData */ #include +#include #include -#include #include #include @@ -135,7 +136,7 @@ class server_commandscript : public CommandScript handler->PSendSysMessage("%s", GitRevision::GetFullVersion()); handler->PSendSysMessage("Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); handler->PSendSysMessage("Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); - handler->PSendSysMessage("Using MySQL version: %s", MYSQL_SERVER_VERSION); + handler->PSendSysMessage("Using MySQL version: %s", MySQL::GetLibraryVersion()); handler->PSendSysMessage("Using CMake version: %s", GitRevision::GetCMakeVersion()); handler->PSendSysMessage("Compiled on: %s", GitRevision::GetHostOSVersion()); diff --git a/src/server/scripts/Commands/cs_tele.cpp b/src/server/scripts/Commands/cs_tele.cpp index 658a0ed446b..dedd41dc0e2 100644 --- a/src/server/scripts/Commands/cs_tele.cpp +++ b/src/server/scripts/Commands/cs_tele.cpp @@ -138,7 +138,7 @@ class tele_commandscript : public CommandScript target->TeleportTo(target->m_homebindMapId, target->m_homebindX, target->m_homebindY, target->m_homebindZ, target->GetOrientation()); else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_HOMEBIND); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_HOMEBIND); stmt->setUInt64(0, target_guid.GetCounter()); PreparedQueryResult resultDB = CharacterDatabase.Query(stmt); @@ -148,7 +148,7 @@ class tele_commandscript : public CommandScript WorldLocation loc(fieldsDB[0].GetUInt16(), fieldsDB[2].GetFloat(), fieldsDB[3].GetFloat(), fieldsDB[4].GetFloat(), 0.0f); uint32 zoneId = fieldsDB[1].GetUInt16(); - SQLTransaction dummy; + CharacterDatabaseTransaction dummy; Player::SavePositionInDB(loc, zoneId, target_guid, dummy); } } @@ -206,7 +206,7 @@ class tele_commandscript : public CommandScript handler->PSendSysMessage(LANG_TELEPORTING_TO, nameLink.c_str(), handler->GetTrinityString(LANG_OFFLINE), tele->name.c_str()); - SQLTransaction dummy; + CharacterDatabaseTransaction dummy; Player::SavePositionInDB(WorldLocation(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation), sMapMgr->GetZoneId(PhasingHandler::GetEmptyPhaseShift(), tele->mapId, tele->position_x, tele->position_y, tele->position_z), target_guid, dummy); } diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index 8e6f486448a..7414d52bca1 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -98,7 +98,7 @@ class wp_commandscript : public CommandScript pathid = target->GetWaypointPath(); else { - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_MAX_ID); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_MAX_ID); PreparedQueryResult result = WorldDatabase.Query(stmt); @@ -119,7 +119,7 @@ class wp_commandscript : public CommandScript return true; } - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_MAX_POINT); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_MAX_POINT); stmt->setUInt32(0, pathid); PreparedQueryResult result = WorldDatabase.Query(stmt); @@ -186,7 +186,7 @@ class wp_commandscript : public CommandScript guidLow = target->GetSpawnId(); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_ADDON_BY_GUID); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_ADDON_BY_GUID); stmt->setUInt64(0, guidLow); @@ -243,7 +243,7 @@ class wp_commandscript : public CommandScript { Creature* target = handler->getSelectedCreature(); - PreparedStatement* stmt = NULL; + WorldDatabasePreparedStatement* stmt = NULL; if (!target) { @@ -291,7 +291,7 @@ class wp_commandscript : public CommandScript char* show_str = strtok((char*)args, " "); std::string show = show_str; - PreparedStatement* stmt = NULL; + WorldDatabasePreparedStatement* stmt = NULL; // Check if ((show != "add") && (show != "mod") && (show != "del") && (show != "listid")) @@ -572,7 +572,7 @@ class wp_commandscript : public CommandScript uint32 pathid = 0; uint32 point = 0; Creature* target = handler->getSelectedCreature(); - PreparedStatement* stmt = NULL; + WorldDatabasePreparedStatement* stmt = NULL; // User did select a visual waypoint? if (!target || target->GetEntry() != VISUAL_WAYPOINT) @@ -736,7 +736,7 @@ class wp_commandscript : public CommandScript uint32 pathid = 0; Creature* target = handler->getSelectedCreature(); - PreparedStatement* stmt = NULL; + WorldDatabasePreparedStatement* stmt = NULL; // Did player provide a PathID? diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp index a88f7ec30f0..0460335b44e 100644 --- a/src/server/scripts/Northrend/zone_dalaran.cpp +++ b/src/server/scripts/Northrend/zone_dalaran.cpp @@ -184,7 +184,7 @@ class npc_minigob_manabonk : public CreatureScript void SendMailToPlayer(Player* player) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); int16 deliverDelay = irand(MAIL_DELIVER_DELAY_MIN, MAIL_DELIVER_DELAY_MAX); MailDraft(MAIL_MINIGOB_ENTRY, true).SendMailTo(trans, MailReceiver(player), MailSender(MAIL_CREATURE, uint64(me->GetEntry())), MAIL_CHECK_MASK_NONE, deliverDelay); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/scripts/World/action_ip_logger.cpp b/src/server/scripts/World/action_ip_logger.cpp index 93b1d896bb8..8b2acccc2c5 100644 --- a/src/server/scripts/World/action_ip_logger.cpp +++ b/src/server/scripts/World/action_ip_logger.cpp @@ -136,7 +136,7 @@ class AccountActionIpLogger : public AccountScript { // As we can assume most account actions are NOT failed login, so this is the more accurate check. // For those, we need last_ip... - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ALDL_IP_LOGGING); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ALDL_IP_LOGGING); stmt->setUInt32(0, playerGuid); stmt->setUInt32(1, 0); @@ -147,7 +147,7 @@ class AccountActionIpLogger : public AccountScript } else // ... but for failed login, we query last_attempt_ip from account table. Which we do with an unique query { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FACL_IP_LOGGING); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FACL_IP_LOGGING); stmt->setUInt32(0, playerGuid); stmt->setUInt32(1, 0); @@ -228,7 +228,7 @@ class CharacterActionIpLogger : public PlayerScript } // Once we have done everything, we can insert the new log. - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_CHAR_IP_LOGGING); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_CHAR_IP_LOGGING); stmt->setUInt32(0, playerGuid); stmt->setUInt64(1, player->GetGUID().GetCounter()); @@ -286,7 +286,7 @@ class CharacterDeleteActionIpLogger : public PlayerScript } // Once we have done everything, we can insert the new log. - PreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_INS_ALDL_IP_LOGGING); + LoginDatabasePreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_INS_ALDL_IP_LOGGING); stmt2->setUInt32(0, playerGuid); stmt2->setUInt64(1, guid.GetCounter()); diff --git a/src/server/scripts/World/rest_scripts.cpp b/src/server/scripts/World/rest_scripts.cpp index adec391f63b..6f2ffde3724 100644 --- a/src/server/scripts/World/rest_scripts.cpp +++ b/src/server/scripts/World/rest_scripts.cpp @@ -21,6 +21,7 @@ #include "ScriptMgr.h" #include "World.h" #include +#include class RestChannelPost : public RestScript { diff --git a/src/server/shared/DataStores/DB2DatabaseLoader.cpp b/src/server/shared/DataStores/DB2DatabaseLoader.cpp index 3619920c0c0..bbe9307e403 100644 --- a/src/server/shared/DataStores/DB2DatabaseLoader.cpp +++ b/src/server/shared/DataStores/DB2DatabaseLoader.cpp @@ -201,7 +201,7 @@ char* DB2DatabaseLoader::Load(uint32& records, char**& indexTable, char*& string void DB2DatabaseLoader::LoadStrings(uint32 locale, uint32 records, char** indexTable, std::vector& stringPool) { - PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(HotfixDatabaseStatements(_loadInfo->Statement + 1)); + HotfixDatabasePreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(HotfixDatabaseStatements(_loadInfo->Statement + 1)); stmt->setString(0, localeNames[locale]); PreparedQueryResult result = HotfixDatabase.Query(stmt); if (!result) diff --git a/src/server/shared/Realm/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp index be27b1e9f7c..e8b8191c0a7 100644 --- a/src/server/shared/Realm/RealmList.cpp +++ b/src/server/shared/Realm/RealmList.cpp @@ -54,7 +54,7 @@ void RealmList::Initialize(Trinity::Asio::IoContext& ioContext, uint32 updateInt { _updateInterval = updateInterval; _updateTimer = Trinity::make_unique(ioContext); - _resolver = Trinity::make_unique(ioContext); + _resolver = Trinity::make_unique(ioContext); LoadBuildInfo(); // Get the content of the realmlist table in the database @@ -132,7 +132,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) TC_LOG_DEBUG("realmlist", "Updating Realm List..."); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); PreparedQueryResult result = LoginDatabase.Query(stmt); std::map existingRealms; @@ -156,21 +156,21 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) std::string localAddressString = fields[3].GetString(); std::string localSubmaskString = fields[4].GetString(); - Optional externalAddress = Trinity::Net::Resolve(*_resolver, boost::asio::ip::tcp::v4(), externalAddressString, ""); + Optional externalAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), externalAddressString, ""); if (!externalAddress) { TC_LOG_ERROR("realmlist", "Could not resolve address %s for realm \"%s\" id %u", externalAddressString.c_str(), name.c_str(), realmId); continue; } - Optional localAddress = Trinity::Net::Resolve(*_resolver, boost::asio::ip::tcp::v4(), localAddressString, ""); + Optional localAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), localAddressString, ""); if (!localAddress) { TC_LOG_ERROR("realmlist", "Could not resolve localAddress %s for realm \"%s\" id %u", localAddressString.c_str(), name.c_str(), realmId); continue; } - Optional localSubmask = Trinity::Net::Resolve(*_resolver, boost::asio::ip::tcp::v4(), localSubmaskString, ""); + Optional localSubmask = _resolver->Resolve(boost::asio::ip::tcp::v4(), localSubmaskString, ""); if (!localSubmask) { TC_LOG_ERROR("realmlist", "Could not resolve localSubnetMask %s for realm \"%s\" id %u", localSubmaskString.c_str(), name.c_str(), realmId); @@ -407,7 +407,7 @@ uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip:: memcpy(&keyData[0], clientSecret.data(), 32); memcpy(&keyData[32], serverSecret.AsByteArray(32).get(), 32); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO); stmt->setString(0, ByteArrayToHexStr(keyData.data(), keyData.size())); stmt->setString(1, clientAddress.to_string()); stmt->setUInt8(2, locale); diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h index e49ecf5803d..3096bd17ceb 100644 --- a/src/server/shared/Realm/RealmList.h +++ b/src/server/shared/Realm/RealmList.h @@ -21,6 +21,7 @@ #include "Define.h" #include "Realm.h" +#include "Resolver.h" #include #include #include @@ -117,7 +118,7 @@ class TC_SHARED_API RealmList std::unordered_set _subRegions; uint32 _updateInterval; std::unique_ptr _updateTimer; - std::unique_ptr _resolver; + std::unique_ptr _resolver; }; #define sRealmList RealmList::Instance() diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index c215c79c47f..fea737755fa 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -51,8 +51,6 @@ if (WITH_CPR) scripts game readline - duktape - dukglue ${CPR_LIBRARIES}) else() target_link_libraries(worldserver @@ -61,9 +59,7 @@ else() PUBLIC scripts game - readline - duktape - dukglue) + readline) endif() CollectIncludeDirectories( @@ -76,7 +72,6 @@ if (WITH_CPR) target_include_directories(worldserver PUBLIC ${PUBLIC_INCLUDES} - ${DUKGLUE_HEADERS} ${CPR_INCLUDE_DIRS} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) @@ -84,7 +79,6 @@ else() target_include_directories(worldserver PUBLIC ${PUBLIC_INCLUDES} - ${DUKGLUE_HEADERS} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) endif() diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 16a59fec8cd..47a3691eb95 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -192,7 +193,7 @@ extern int main(int argc, char** argv) } ); - OpenSSLCrypto::threadsSetup(); + OpenSSLCrypto::threadsSetup(boost::dll::program_location().remove_filename()); std::shared_ptr opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); }); diff --git a/src/server/worldserver/RemoteAccess/RASession.cpp b/src/server/worldserver/RemoteAccess/RASession.cpp index 8131132c9ce..c4f334391f8 100644 --- a/src/server/worldserver/RemoteAccess/RASession.cpp +++ b/src/server/worldserver/RemoteAccess/RASession.cpp @@ -126,7 +126,7 @@ bool RASession::CheckAccessLevel(const std::string& user) Utf8ToUpperOnlyLatin(safeUser); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); stmt->setString(0, safeUser); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -162,7 +162,7 @@ bool RASession::CheckPassword(const std::string& user, const std::string& pass) std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME); stmt->setString(0, safe_user); stmt->setString(1, hash); diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 3de2f1908fa..7b7b826d9bb 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -27,6 +27,8 @@ #include "adt.h" #include "wdt.h" #include +#include +#include #include #include #include diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp index dc4af89d0b8..2dfc8800865 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -27,6 +27,8 @@ #include "wdtfile.h" #include "wmo.h" #include +#include +#include #include #include #include From ffee0b20bfeb851a3103912286a0d21195da30d6 Mon Sep 17 00:00:00 2001 From: TheGhost Date: Tue, 21 Oct 2025 16:08:27 +1300 Subject: [PATCH 02/49] Core/Crypto: update OpenSSL 3.x.x and enable C++17 --- dep/openssl/CMakeLists.txt | 4 +- src/common/Common.h | 7 ++ src/common/Cryptography/ARC4.cpp | 40 ++++++--- src/common/Cryptography/ARC4.h | 6 +- src/common/Cryptography/HmacHash.cpp | 34 +++----- src/common/Cryptography/HmacHash.h | 3 +- src/common/Cryptography/OpenSSLCrypto.cpp | 82 +++---------------- src/common/Cryptography/SHA1.cpp | 36 ++++++-- src/common/Cryptography/SHA1.h | 15 +++- src/common/Cryptography/SHA256.cpp | 16 ++-- src/common/Cryptography/SHA256.h | 3 +- src/common/Threading/ProducerConsumerQueue.h | 43 ++++++---- src/server/bnetserver/Main.cpp | 11 ++- .../database/Database/DatabaseWorkerPool.cpp | 5 +- src/server/game/Warden/WardenMac.cpp | 9 +- src/server/game/Warden/WardenWin.cpp | 9 +- src/server/worldserver/Main.cpp | 8 +- 17 files changed, 174 insertions(+), 157 deletions(-) diff --git a/dep/openssl/CMakeLists.txt b/dep/openssl/CMakeLists.txt index 22ff0406ea4..e30fa049056 100644 --- a/dep/openssl/CMakeLists.txt +++ b/dep/openssl/CMakeLists.txt @@ -11,9 +11,7 @@ # basic packagesearching and setup # (further support will be needed, this is a preliminary release!) -set(OPENSSL_EXPECTED_VERSION 1.0.0) - -find_package(OpenSSL REQUIRED) +find_package(OpenSSL 3 REQUIRED COMPONENTS Crypto SSL) add_library(openssl INTERFACE) diff --git a/src/common/Common.h b/src/common/Common.h index edd4fe97394..03a0096e0ee 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -211,6 +211,13 @@ namespace Ashamane private: std::unordered_map dataMap; }; + + template + struct unary_function + { + typedef ArgumentType argument_type; + typedef ResultType result_type; + }; } #endif diff --git a/src/common/Cryptography/ARC4.cpp b/src/common/Cryptography/ARC4.cpp index a5e77e92646..0a5e507a7d4 100644 --- a/src/common/Cryptography/ARC4.cpp +++ b/src/common/Cryptography/ARC4.cpp @@ -17,35 +17,49 @@ */ #include "ARC4.h" +#include "Errors.h" -ARC4::ARC4(uint32 len) : m_ctx(EVP_CIPHER_CTX_new()) +ARC4::ARC4(uint32 len) : _ctx(EVP_CIPHER_CTX_new()) { - EVP_CIPHER_CTX_init(m_ctx); - EVP_EncryptInit_ex(m_ctx, EVP_rc4(), nullptr, nullptr, nullptr); - EVP_CIPHER_CTX_set_key_length(m_ctx, len); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + _cipher = EVP_CIPHER_fetch(nullptr, "RC4", nullptr); +#else + EVP_CIPHER const *_cipher = EVP_rc4(); +#endif + EVP_CIPHER_CTX_init(_ctx); + EVP_EncryptInit_ex(_ctx, _cipher, nullptr, nullptr, nullptr); + EVP_CIPHER_CTX_set_key_length(_ctx, len); } -ARC4::ARC4(uint8* seed, uint32 len) : m_ctx(EVP_CIPHER_CTX_new()) +ARC4::ARC4(uint8* seed, uint32 len) : _ctx(EVP_CIPHER_CTX_new()) { - EVP_CIPHER_CTX_init(m_ctx); - EVP_EncryptInit_ex(m_ctx, EVP_rc4(), nullptr, nullptr, nullptr); - EVP_CIPHER_CTX_set_key_length(m_ctx, len); - EVP_EncryptInit_ex(m_ctx, nullptr, nullptr, seed, nullptr); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + _cipher = EVP_CIPHER_fetch(nullptr, "RC4", nullptr); +#else + EVP_CIPHER const *_cipher = EVP_rc4(); +#endif + EVP_CIPHER_CTX_init(_ctx); + EVP_EncryptInit_ex(_ctx, _cipher, nullptr, nullptr, nullptr); + EVP_CIPHER_CTX_set_key_length(_ctx, len); + EVP_EncryptInit_ex(_ctx, nullptr, nullptr, seed, nullptr); } ARC4::~ARC4() { - EVP_CIPHER_CTX_free(m_ctx); + EVP_CIPHER_CTX_free(_ctx); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_CIPHER_free(_cipher); +#endif } void ARC4::Init(uint8* seed) { - EVP_EncryptInit_ex(m_ctx, nullptr, nullptr, seed, nullptr); + EVP_EncryptInit_ex(_ctx, nullptr, nullptr, seed, nullptr); } void ARC4::UpdateData(int len, uint8* data) { int outlen = 0; - EVP_EncryptUpdate(m_ctx, data, &outlen, data, len); - EVP_EncryptFinal_ex(m_ctx, data, &outlen); + EVP_EncryptUpdate(_ctx, data, &outlen, data, len); + EVP_EncryptFinal_ex(_ctx, data, &outlen); } diff --git a/src/common/Cryptography/ARC4.h b/src/common/Cryptography/ARC4.h index 629be510bbc..69ef0ab0d1e 100644 --- a/src/common/Cryptography/ARC4.h +++ b/src/common/Cryptography/ARC4.h @@ -20,6 +20,7 @@ #define _AUTH_SARC4_H #include "Define.h" +#include #include class TC_COMMON_API ARC4 @@ -31,7 +32,10 @@ class TC_COMMON_API ARC4 void Init(uint8* seed); void UpdateData(int len, uint8* data); private: - EVP_CIPHER_CTX* m_ctx; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_CIPHER *_cipher; +#endif + EVP_CIPHER_CTX* _ctx; }; #endif diff --git a/src/common/Cryptography/HmacHash.cpp b/src/common/Cryptography/HmacHash.cpp index d5945517da0..9cdc76b9721 100644 --- a/src/common/Cryptography/HmacHash.cpp +++ b/src/common/Cryptography/HmacHash.cpp @@ -21,58 +21,46 @@ #include "Errors.h" #include -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L -HMAC_CTX* HMAC_CTX_new() -{ - HMAC_CTX *ctx = new HMAC_CTX(); - HMAC_CTX_init(ctx); - return ctx; -} - -void HMAC_CTX_free(HMAC_CTX* ctx) -{ - HMAC_CTX_cleanup(ctx); - delete ctx; -} -#endif - template -HmacHash::HmacHash(uint32 len, uint8 const* seed) : _ctx(HMAC_CTX_new()) +HmacHash::HmacHash(uint32 len, uint8 const* seed) : _ctx(EVP_MD_CTX_create()), _key(EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, seed, len)) { - HMAC_Init_ex(_ctx, seed, len, HashCreator(), nullptr); + EVP_DigestSignInit(_ctx, nullptr, HashCreator(), nullptr, _key); memset(_digest, 0, DigestLength); } template HmacHash::~HmacHash() { - HMAC_CTX_free(_ctx); + EVP_MD_CTX_destroy(_ctx); + _ctx = nullptr; + EVP_PKEY_free(_key); + _key = nullptr; } template void HmacHash::UpdateData(std::string const& str) { - HMAC_Update(_ctx, reinterpret_cast(str.c_str()), str.length()); + EVP_DigestSignUpdate(_ctx, reinterpret_cast(str.c_str()), str.length()); } template void HmacHash::UpdateData(uint8 const* data, size_t len) { - HMAC_Update(_ctx, data, len); + EVP_DigestSignUpdate(_ctx, data, len); } template void HmacHash::Finalize() { - uint32 length = 0; - HMAC_Final(_ctx, _digest, &length); + size_t length = DigestLength; + EVP_DigestSignFinal(_ctx, _digest, &length); ASSERT(length == DigestLength); } template uint8* HmacHash::ComputeHash(BigNumber* bn) { - HMAC_Update(_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); + EVP_DigestSignUpdate(_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); Finalize(); return _digest; } diff --git a/src/common/Cryptography/HmacHash.h b/src/common/Cryptography/HmacHash.h index a8c2eee6f09..8641775f58a 100644 --- a/src/common/Cryptography/HmacHash.h +++ b/src/common/Cryptography/HmacHash.h @@ -43,7 +43,8 @@ class TC_COMMON_API HmacHash uint8* GetDigest() { return _digest; } uint32 GetLength() const { return DigestLength; } private: - HMAC_CTX* _ctx; + EVP_MD_CTX* _ctx; + EVP_PKEY* _key; uint8 _digest[DigestLength]; }; diff --git a/src/common/Cryptography/OpenSSLCrypto.cpp b/src/common/Cryptography/OpenSSLCrypto.cpp index db5e2e01533..261af6cae6a 100644 --- a/src/common/Cryptography/OpenSSLCrypto.cpp +++ b/src/common/Cryptography/OpenSSLCrypto.cpp @@ -17,87 +17,29 @@ #include "OpenSSLCrypto.h" #include -#include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include OSSL_PROVIDER* LegacyProvider; - -void OpenSSLCrypto::threadsSetup([[maybe_unused]] boost::filesystem::path const& providerModulePath) -{ -#ifdef VALGRIND - ValgrindRandomSetup(); +OSSL_PROVIDER* DefaultProvider; #endif +void OpenSSLCrypto::threadsSetup([[maybe_unused]] boost::filesystem::path const &providerModulePath) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L #if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS OSSL_PROVIDER_set_default_search_path(nullptr, providerModulePath.string().c_str()); #endif - LegacyProvider = OSSL_PROVIDER_try_load(nullptr, "legacy", 1); + LegacyProvider = OSSL_PROVIDER_load(nullptr, "legacy"); + DefaultProvider = OSSL_PROVIDER_load(nullptr, "default"); +#endif } void OpenSSLCrypto::threadsCleanup() { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L OSSL_PROVIDER_unload(LegacyProvider); + OSSL_PROVIDER_unload(DefaultProvider); OSSL_PROVIDER_set_default_search_path(nullptr, nullptr); -} - -#ifdef VALGRIND -#include - -RAND_METHOD const* default_rand; - -static int Valgrind_RAND_seed(const void* buf, int num) -{ - VALGRIND_DISCARD(VALGRIND_MAKE_MEM_DEFINED(buf, num)); - return default_rand->seed(buf, num); -} - -static int Valgrind_RAND_bytes(unsigned char* buf, int num) -{ - int ret = default_rand->bytes(buf, num); - VALGRIND_DISCARD(VALGRIND_MAKE_MEM_DEFINED(buf, num)); - return ret; -} - -static void Valgrind_RAND_cleanup(void) -{ - default_rand->cleanup(); -} - -static int Valgrind_RAND_add(const void* buf, int num, double randomness) -{ - VALGRIND_DISCARD(VALGRIND_MAKE_MEM_DEFINED(buf, num)); - return default_rand->add(buf, num, randomness); -} - -static int Valgrind_RAND_pseudorand(unsigned char* buf, int num) -{ - int ret = default_rand->pseudorand(buf, num); - VALGRIND_DISCARD(VALGRIND_MAKE_MEM_DEFINED(buf, num)); - return ret; -} - -static int Valgrind_RAND_status(void) -{ - return default_rand->status(); -} - -static RAND_METHOD valgrind_rand; - -void ValgrindRandomSetup() -{ - memset(&valgrind_rand, 0, sizeof(RAND_METHOD)); - default_rand = RAND_get_rand_method(); - if (default_rand->seed) - valgrind_rand.seed = &Valgrind_RAND_seed; - if (default_rand->bytes) - valgrind_rand.bytes = &Valgrind_RAND_bytes; - if (default_rand->cleanup) - valgrind_rand.cleanup = &Valgrind_RAND_cleanup; - if (default_rand->add) - valgrind_rand.add = &Valgrind_RAND_add; - if (default_rand->pseudorand) - valgrind_rand.pseudorand = &Valgrind_RAND_pseudorand; - if (default_rand->status) - valgrind_rand.status = &Valgrind_RAND_status; - RAND_set_rand_method(&valgrind_rand); -} #endif +} diff --git a/src/common/Cryptography/SHA1.cpp b/src/common/Cryptography/SHA1.cpp index 4b3561cbb16..c3c509d20ee 100644 --- a/src/common/Cryptography/SHA1.cpp +++ b/src/common/Cryptography/SHA1.cpp @@ -24,18 +24,41 @@ SHA1Hash::SHA1Hash() { - SHA1_Init(&mC); - memset(mDigest, 0, SHA_DIGEST_LENGTH * sizeof(uint8)); + m_ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(m_ctx, EVP_sha1(), nullptr); +} + +SHA1Hash::SHA1Hash(const SHA1Hash &other) : SHA1Hash() // copy +{ + EVP_MD_CTX_copy_ex(m_ctx, other.m_ctx); + std::memcpy(m_digest, other.m_digest, SHA_DIGEST_LENGTH); +} + +SHA1Hash::SHA1Hash(SHA1Hash &&other) : SHA1Hash() // move +{ + Swap(other); +} + +SHA1Hash &SHA1Hash::operator=(SHA1Hash other) // assign +{ + Swap(other); + return *this; } SHA1Hash::~SHA1Hash() { - SHA1_Init(&mC); + EVP_MD_CTX_free(m_ctx); +} + +void SHA1Hash::Swap(SHA1Hash &other) throw() +{ + std::swap(m_ctx, other.m_ctx); + std::swap(m_digest, other.m_digest); } void SHA1Hash::UpdateData(const uint8 *dta, int len) { - SHA1_Update(&mC, dta, len); + EVP_DigestUpdate(m_ctx, dta, len); } void SHA1Hash::UpdateData(const std::string &str) @@ -60,12 +83,13 @@ void SHA1Hash::UpdateBigNumbers(BigNumber* bn0, ...) void SHA1Hash::Initialize() { - SHA1_Init(&mC); + EVP_DigestInit(m_ctx, EVP_sha1()); } void SHA1Hash::Finalize(void) { - SHA1_Final(mDigest, &mC); + uint32 length = SHA_DIGEST_LENGTH; + EVP_DigestFinal_ex(m_ctx, m_digest, &length); } std::string CalculateSHA1Hash(std::string const& content) diff --git a/src/common/Cryptography/SHA1.h b/src/common/Cryptography/SHA1.h index fa1fc2e5c17..e4ac3fa5794 100644 --- a/src/common/Cryptography/SHA1.h +++ b/src/common/Cryptography/SHA1.h @@ -23,6 +23,7 @@ #include #include #include +#include class BigNumber; @@ -32,8 +33,14 @@ class TC_COMMON_API SHA1Hash typedef std::integral_constant DigestLength; SHA1Hash(); + SHA1Hash(SHA1Hash const &other); // copy + SHA1Hash(SHA1Hash &&other); // move + SHA1Hash &operator=(SHA1Hash other); // assign ~SHA1Hash(); + void Swap(SHA1Hash &other) throw(); + friend void Swap(SHA1Hash &left, SHA1Hash &right) { left.Swap(right); } + void UpdateBigNumbers(BigNumber* bn0, ...); void UpdateData(const uint8 *dta, int len); @@ -42,12 +49,12 @@ class TC_COMMON_API SHA1Hash void Initialize(); void Finalize(); - uint8 *GetDigest(void) { return mDigest; } - int GetLength(void) const { return SHA_DIGEST_LENGTH; } + uint8 *GetDigest(void) { return m_digest; } + int GetLength() const { return SHA_DIGEST_LENGTH; } private: - SHA_CTX mC; - uint8 mDigest[SHA_DIGEST_LENGTH]; + EVP_MD_CTX *m_ctx; + uint8 m_digest[SHA_DIGEST_LENGTH]; }; /// Returns the SHA1 hash of the given content as hex string. diff --git a/src/common/Cryptography/SHA256.cpp b/src/common/Cryptography/SHA256.cpp index 980fc08a489..b616c329f7e 100644 --- a/src/common/Cryptography/SHA256.cpp +++ b/src/common/Cryptography/SHA256.cpp @@ -17,23 +17,25 @@ #include "SHA256.h" #include "BigNumber.h" +#include "Errors.h" #include #include -SHA256Hash::SHA256Hash() +SHA256Hash::SHA256Hash() : _ctx(EVP_MD_CTX_create()) { - SHA256_Init(&mC); + EVP_DigestInit_ex(_ctx, EVP_sha256(), nullptr); memset(mDigest, 0, SHA256_DIGEST_LENGTH * sizeof(uint8)); } SHA256Hash::~SHA256Hash() { - SHA256_Init(&mC); + EVP_MD_CTX_destroy(_ctx); + _ctx = nullptr; } void SHA256Hash::UpdateData(uint8 const* data, size_t len) { - SHA256_Update(&mC, data, len); + EVP_DigestUpdate(_ctx, data, len); } void SHA256Hash::UpdateData(const std::string &str) @@ -58,10 +60,12 @@ void SHA256Hash::UpdateBigNumbers(BigNumber* bn0, ...) void SHA256Hash::Initialize() { - SHA256_Init(&mC); + EVP_DigestInit_ex(_ctx, EVP_sha256(), nullptr); } void SHA256Hash::Finalize(void) { - SHA256_Final(mDigest, &mC); + uint32 length = SHA256_DIGEST_LENGTH; + EVP_DigestFinal_ex(_ctx, mDigest, &length); + ASSERT(length == SHA256_DIGEST_LENGTH); } diff --git a/src/common/Cryptography/SHA256.h b/src/common/Cryptography/SHA256.h index 4d5b13a5319..f036c650985 100644 --- a/src/common/Cryptography/SHA256.h +++ b/src/common/Cryptography/SHA256.h @@ -22,6 +22,7 @@ #include #include #include +#include class BigNumber; @@ -45,7 +46,7 @@ class TC_COMMON_API SHA256Hash uint32 GetLength() const { return SHA256_DIGEST_LENGTH; } private: - SHA256_CTX mC; + EVP_MD_CTX* _ctx; uint8 mDigest[SHA256_DIGEST_LENGTH]; }; diff --git a/src/common/Threading/ProducerConsumerQueue.h b/src/common/Threading/ProducerConsumerQueue.h index 6b7f65b0272..04c2017c1f7 100644 --- a/src/common/Threading/ProducerConsumerQueue.h +++ b/src/common/Threading/ProducerConsumerQueue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 @@ -15,8 +15,8 @@ * with this program. If not, see . */ -#ifndef _PCQ_H -#define _PCQ_H +#ifndef TRINITY_PRODUCER_CONSUMER_QUEUE_H +#define TRINITY_PRODUCER_CONSUMER_QUEUE_H #include #include @@ -28,16 +28,24 @@ template class ProducerConsumerQueue { private: - std::mutex _queueLock; + mutable std::mutex _queueLock; std::queue _queue; std::condition_variable _condition; std::atomic _shutdown; public: - ProducerConsumerQueue() : _shutdown(false) { } + ProducerConsumerQueue() : _shutdown(false) { } - void Push(const T& value) + void Push(T const& value) + { + std::lock_guard lock(_queueLock); + _queue.push(value); + + _condition.notify_one(); + } + + void Push(T&& value) { std::lock_guard lock(_queueLock); _queue.push(std::move(value)); @@ -45,13 +53,20 @@ class ProducerConsumerQueue _condition.notify_one(); } - bool Empty() + bool Empty() const { std::lock_guard lock(_queueLock); return _queue.empty(); } + size_t Size() const + { + std::lock_guard lock(_queueLock); + + return _queue.size(); + } + bool Pop(T& value) { std::lock_guard lock(_queueLock); @@ -59,7 +74,7 @@ class ProducerConsumerQueue if (_queue.empty() || _shutdown) return false; - value = _queue.front(); + value = std::move(_queue.front()); _queue.pop(); @@ -91,7 +106,8 @@ class ProducerConsumerQueue { T& value = _queue.front(); - DeleteQueuedObject(value); + if constexpr (std::is_pointer_v) + delete value; _queue.pop(); } @@ -100,13 +116,6 @@ class ProducerConsumerQueue _condition.notify_all(); } - -private: - template - typename std::enable_if::value>::type DeleteQueuedObject(E& obj) { delete obj; } - - template - typename std::enable_if::value>::type DeleteQueuedObject(E const& /*packet*/) { } }; -#endif +#endif // TRINITY_PRODUCER_CONSUMER_QUEUE_H diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index c06f6e7c29f..858a9420fec 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -33,14 +33,19 @@ #include "IPLocation.h" #include "LoginRESTService.h" #include "MySQLThreading.h" +#include "OpenSSLCrypto.h" #include "ProcessPriority.h" #include "RealmList.h" #include "SessionManager.h" #include "SslContext.h" #include "Util.h" #include +#include #include #include +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +#include +#endif #include #include #include @@ -120,11 +125,15 @@ int main(int argc, char** argv) []() { TC_LOG_INFO("server.bnetserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str()); - TC_LOG_INFO("server.bnetserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + TC_LOG_INFO("server.bnetserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION)); TC_LOG_INFO("server.bnetserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); } ); + OpenSSLCrypto::threadsSetup(boost::dll::program_location().remove_filename()); + + std::shared_ptr opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); }); + // Seed the OpenSSL's PRNG here. // That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login BigNumber seed; diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index ddd31b39d61..e9ce741b2b7 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -45,6 +45,10 @@ #define MIN_MYSQL_SERVER_VERSION_STRING "5.7" #define MIN_MYSQL_CLIENT_VERSION 50700u #define MIN_MYSQL_CLIENT_VERSION_STRING "5.7" +#define MIN_MARIADB_SERVER_VERSION 100209u +#define MIN_MARIADB_SERVER_VERSION_STRING "10.2.9" +#define MIN_MARIADB_CLIENT_VERSION 30003u +#define MIN_MARIADB_CLIENT_VERSION_STRING "3.0.3" #define MIN_MARIADB_SERVER_VERSION 100209u #define MIN_MARIADB_SERVER_VERSION_STRING "10.2.9" @@ -469,7 +473,6 @@ uint32 DatabaseWorkerPool::OpenConnections(InternalIndex type, uint8 numConne #else TC_LOG_ERROR("sql.driver", "TrinityCore does not support MariaDB versions below " MIN_MARIADB_SERVER_VERSION_STRING " (found id %u, need id >= %u), please update your MySQL server", connection->GetServerVersion(), MIN_MARIADB_SERVER_VERSION); #endif - return 1; } else diff --git a/src/server/game/Warden/WardenMac.cpp b/src/server/game/Warden/WardenMac.cpp index 644049bc7a8..1e5825f5e74 100644 --- a/src/server/game/Warden/WardenMac.cpp +++ b/src/server/game/Warden/WardenMac.cpp @@ -82,10 +82,11 @@ ClientWardenModule* WardenMac::GetModuleForClient() memcpy(mod->Key, Module_0DBBF209A27B1E279A9FEC5C168A15F7_Key, 16); // md5 hash - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, mod->CompressedData, len); - MD5_Final((uint8*)&mod->Id, &ctx); + EVP_MD_CTX *md5 = EVP_MD_CTX_new(); + EVP_DigestInit_ex(md5, EVP_md5(), nullptr); + EVP_DigestUpdate(md5, mod->CompressedData, len); + EVP_DigestFinal_ex(md5, (uint8 *)&mod->Id, &len); + EVP_MD_CTX_free(md5); return mod; } diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index 940127cd975..cf4bf2d7229 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -79,10 +79,11 @@ ClientWardenModule* WardenWin::GetModuleForClient() memcpy(mod->Key, Module.ModuleKey, 16); // md5 hash - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, mod->CompressedData, length); - MD5_Final((uint8*)&mod->Id, &ctx); + EVP_MD_CTX *md5 = EVP_MD_CTX_new(); + EVP_DigestInit_ex(md5, EVP_md5(), nullptr); + EVP_DigestUpdate(md5, mod->CompressedData, length); + EVP_DigestFinal_ex(md5, (uint8 *)&mod->Id, &length); + EVP_MD_CTX_free(md5); return mod; } diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 47a3691eb95..7e6ea07236a 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -50,8 +50,12 @@ #include "World.h" #include "WorldSocket.h" #include "WorldSocketMgr.h" -#include #include +#include +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +#include +#endif +#include #include #include #include @@ -188,7 +192,7 @@ extern int main(int argc, char** argv) []() { TC_LOG_INFO("server.worldserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str()); - TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION)); TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); } ); From b1da872997a601c239b7bc6509ccb8ffa9dcaa28 Mon Sep 17 00:00:00 2001 From: Killyana Date: Sun, 5 Feb 2017 19:54:09 +0100 Subject: [PATCH 03/49] DB/creature: Restore position for two Wrath Masters changed in a previous commit (cherrypicked from f91ba9c2a8ec2131df865f7490366288cec1bc91) --- .../world/master/2019_07_16_05_world_2017_02_05_03_world.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 sql/updates/world/master/2019_07_16_05_world_2017_02_05_03_world.sql diff --git a/sql/updates/world/master/2019_07_16_05_world_2017_02_05_03_world.sql b/sql/updates/world/master/2019_07_16_05_world_2017_02_05_03_world.sql new file mode 100644 index 00000000000..28c4cd4fb74 --- /dev/null +++ b/sql/updates/world/master/2019_07_16_05_world_2017_02_05_03_world.sql @@ -0,0 +1,3 @@ +-- +UPDATE `creature` SET `position_x`=-99.78, `position_y`=1892.9, `position_z`=77.35 WHERE `guid`=68313; +UPDATE `creature` SET `position_x`=-276.43, `position_y`=1529.1, `position_z`=31.8 WHERE `guid`=68311; From 6735b9fb45abdcee40404387b73a13f65716b91b Mon Sep 17 00:00:00 2001 From: Aokromes Date: Mon, 6 Feb 2017 17:19:59 +0100 Subject: [PATCH 04/49] DB/Misc: Fix one startup error (cherrypicked from d9c465ed870cd054289384610f4ece4857beb5ed) --- .../world/master/2019_07_18_00_world_2017_02_06_00_world.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 sql/updates/world/master/2019_07_18_00_world_2017_02_06_00_world.sql diff --git a/sql/updates/world/master/2019_07_18_00_world_2017_02_06_00_world.sql b/sql/updates/world/master/2019_07_18_00_world_2017_02_06_00_world.sql new file mode 100644 index 00000000000..69e47c93d53 --- /dev/null +++ b/sql/updates/world/master/2019_07_18_00_world_2017_02_06_00_world.sql @@ -0,0 +1,3 @@ +-- +DELETE FROM `creature_addon` WHERE `guid`=12776; +-- From 0c3da05af21d83edcb3d8285626f44650301d142 Mon Sep 17 00:00:00 2001 From: TheGhost Date: Wed, 22 Oct 2025 15:57:42 +1300 Subject: [PATCH 05/49] make game playable (#3) --- src/server/game/Entities/Unit/Unit.cpp | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index a81a5d17f24..90cd3853ed0 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -810,16 +810,16 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam else victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, 0); - // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots) - if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage) - if (victim != this && victim->GetTypeId() == TYPEID_PLAYER) - if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL]) - if (spell->getState() == SPELL_STATE_PREPARING) - { - uint32 interruptFlags = spell->m_spellInfo->InterruptFlags; - if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0) - victim->InterruptNonMeleeSpells(false); - } + // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots) + if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage) + if (victim != this && victim->GetTypeId() == TYPEID_PLAYER) + if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL]) + if (spell->getState() == SPELL_STATE_PREPARING) + { + uint32 interruptFlags = spell->m_spellInfo->InterruptFlags; + if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0) + victim->InterruptNonMeleeSpells(false); + } // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation @@ -867,7 +867,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam // duel ends when player has 1 or less hp bool duel_hasEnded = false; bool duel_wasMounted = false; - if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health-1)) + if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health - 1)) { // prevent kill only if killed in duel and killed by opponent or opponent controlled creature if (victim->ToPlayer()->duel->opponent == this || victim->ToPlayer()->duel->opponent->GetGUID() == GetOwnerGUID()) @@ -875,7 +875,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam duel_hasEnded = true; } - else if (victim->IsVehicle() && damage >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER) + else if (victim->IsVehicle() && damage >= (health - 1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER) { Player* victimRider = victim->GetCharmer()->ToPlayer(); @@ -943,16 +943,16 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0); victim->UpdateLastDamagedTime(spellProto); victim->SaveDamageHistory(damage); - } if (victim->GetTypeId() != TYPEID_PLAYER) victim->AddThreat(this, float(damage), damageSchoolMask, spellProto); - else // victim is a player + } + else // victim is a player { // random durability for items (HIT TAKEN) if (roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE))) { - EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1)); + EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END - 1)); victim->ToPlayer()->DurabilityPointLossForEquipSlot(slot); } } @@ -962,7 +962,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam // random durability for items (HIT DONE) if (roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE))) { - EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1)); + EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END - 1)); ToPlayer()->DurabilityPointLossForEquipSlot(slot); } } @@ -1004,7 +1004,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam he->duel->opponent->CombatStopWithPets(true); he->CombatStopWithPets(true); - he->CastSpell(he, 7267, true); // beg + he->CastSpell(he, 7267, true); // beg he->DuelComplete(DUEL_WON); } } From b0aa8260f91bf7438690cd732f27f19d6b8425aa Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Wed, 27 Nov 2024 08:42:31 -0600 Subject: [PATCH 06/49] Core/Network: set reuse_address option on acceptor (#4) --- src/server/shared/Networking/AsyncAcceptor.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h index 254d9336dc4..f8323dca083 100644 --- a/src/server/shared/Networking/AsyncAcceptor.h +++ b/src/server/shared/Networking/AsyncAcceptor.h @@ -84,6 +84,15 @@ class AsyncAcceptor return false; } +#if TRINITY_PLATFORM != TRINITY_PLATFORM_WINDOWS + _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode); + if (errorCode) + { + TC_LOG_INFO("network", "Failed to set reuse_address option on acceptor %s", errorCode.message().c_str()); + return false; + } +#endif + _acceptor.bind(_endpoint, errorCode); if (errorCode) { From 77db9c977e47737c5c4bfd2d0e4e87cd75b92e57 Mon Sep 17 00:00:00 2001 From: TheGhost Date: Fri, 24 Oct 2025 12:59:17 +1300 Subject: [PATCH 07/49] Core/Misc: unary_fuction is deprecated --- src/server/game/AI/CoreAI/UnitAI.h | 36 +++++++++++-------- src/server/game/AI/PlayerAI/PlayerAI.cpp | 6 +++- src/server/game/Loot/LootMgr.cpp | 6 +++- .../BaradinHold/boss_occuthar.cpp | 7 ++-- .../BastionOfTwilight/boss_sinestra.cpp | 7 ++-- ...erunak_stonespeaker_mindbender_ghursha.cpp | 6 +++- .../ZulGurub/boss_mandokir.cpp | 7 ++-- .../DragonSoul/boss_warmaster_blackhorn.cpp | 4 ++- .../Kalimdor/Firelands/boss_bethtilac.cpp | 6 ++-- .../boss_argent_challenge.cpp | 7 ++-- .../boss_northrend_beasts.cpp | 5 ++- .../IcecrownCitadel/boss_lord_marrowgar.cpp | 7 ++-- .../IcecrownCitadel/boss_the_lich_king.cpp | 7 ++-- .../boss_valithria_dreamwalker.cpp | 6 +++- .../Northrend/Naxxramas/boss_kelthuzad.cpp | 6 +++- .../Northrend/Naxxramas/boss_maexxna.cpp | 6 +++- .../Northrend/Ulduar/Ulduar/boss_kologarn.cpp | 5 ++- .../BlackTemple/boss_illidari_council.cpp | 4 ++- .../Pandaria/HeartOfFear/boss_garalon.cpp | 5 ++- .../Pandaria/HeartOfFear/boss_meljarak.cpp | 5 ++- .../Pandaria/HeartOfFear/boss_zorlok.cpp | 5 ++- .../Pandaria/WorldBosses/boss_oondasta.cpp | 5 ++- 22 files changed, 116 insertions(+), 42 deletions(-) diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 35486663d1f..413d044aceb 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -72,29 +72,37 @@ struct TC_GAME_API DefaultTargetSelector // Target selector for spell casts checking range, auras and attributes /// @todo Add more checks from Spell::CheckCast -struct TC_GAME_API SpellTargetSelector : public std::unary_function +struct TC_GAME_API SpellTargetSelector { - public: - SpellTargetSelector(Unit* caster, uint32 spellId); - bool operator()(Unit const* target) const; +public: + using argument_type = Unit*; + using result_type = bool; - private: - Unit const* _caster; - SpellInfo const* _spellInfo; + SpellTargetSelector(Unit* caster, uint32 spellId); + bool operator()(Unit const* target) const; + +private: + Unit const* _caster; + SpellInfo const* _spellInfo; }; // Very simple target selector, will just skip main target // NOTE: When passing to UnitAI::SelectTarget remember to use 0 as position for random selection // because tank will not be in the temporary list -struct TC_GAME_API NonTankTargetSelector : public std::unary_function +struct TC_GAME_API NonTankTargetSelector { - public: - NonTankTargetSelector(Unit* source, bool playerOnly = true) : _source(source), _playerOnly(playerOnly) { } - bool operator()(Unit const* target) const; +public: + using argument_type = Unit*; + using result_type = bool; - private: - Unit* _source; - bool _playerOnly; + NonTankTargetSelector(Unit* source, bool playerOnly = true) + : _source(source), _playerOnly(playerOnly) { } + + bool operator()(Unit const* target) const; + +private: + Unit* _source; + bool _playerOnly; }; TC_GAME_API void SortByDistanceTo(Unit* reference, std::list& targets); diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp index d05890150b6..a1e60d81992 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.cpp +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -653,8 +653,12 @@ Unit* PlayerAI::SelectAttackTarget() const return me->GetCharmer() ? me->GetCharmer()->GetVictim() : nullptr; } -struct UncontrolledTargetSelectPredicate : public std::unary_function +struct UncontrolledTargetSelectPredicate { +public: + using argument_type = Unit*; + using result_type = bool; + bool operator()(Unit const* target) const { return !target->HasBreakableByDamageCrowdControlAura(); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 965ffd5b133..6b59dc8a447 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -56,8 +56,12 @@ LootStore LootTemplates_Skinning("skinning_loot_template", "creature s LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false); // Selects invalid loot items to be removed from group possible entries (before rolling) -struct LootGroupInvalidSelector : public std::unary_function +struct LootGroupInvalidSelector { +public: + using argument_type = LootStoreItem*; + using result_type = bool; + explicit LootGroupInvalidSelector(Loot const& loot, uint16 lootMode) : _loot(loot), _lootMode(lootMode) { } bool operator()(LootStoreItem* item) const diff --git a/src/server/scripts/EasternKingdoms/BaradinHold/boss_occuthar.cpp b/src/server/scripts/EasternKingdoms/BaradinHold/boss_occuthar.cpp index 507a391e350..5d0a9f44d90 100644 --- a/src/server/scripts/EasternKingdoms/BaradinHold/boss_occuthar.cpp +++ b/src/server/scripts/EasternKingdoms/BaradinHold/boss_occuthar.cpp @@ -205,9 +205,12 @@ class npc_eyestalk : public CreatureScript } }; -class FocusedFireTargetSelector : public std::unary_function +class FocusedFireTargetSelector { - public: +public: + using argument_type = Unit*; + using result_type = bool; + FocusedFireTargetSelector(Creature* me, const Unit* victim) : _me(me), _victim(victim) { } bool operator() (WorldObject* target) diff --git a/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_sinestra.cpp b/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_sinestra.cpp index 44195bcc53d..2773ac9de66 100644 --- a/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_sinestra.cpp +++ b/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_sinestra.cpp @@ -682,9 +682,12 @@ class spell_sinestra_wrack_jump : public SpellScriptLoader } }; -class OrientationCheck : public std::unary_function +class OrientationCheck { - public: +public: + using argument_type = Unit*; + using result_type = bool; + explicit OrientationCheck(Unit* _orb1, Unit* _orb2) : orb1(_orb1), orb2(_orb2) { } bool operator()(WorldObject* object) { diff --git a/src/server/scripts/EasternKingdoms/ThroneOfTheTides/boss_erunak_stonespeaker_mindbender_ghursha.cpp b/src/server/scripts/EasternKingdoms/ThroneOfTheTides/boss_erunak_stonespeaker_mindbender_ghursha.cpp index a7523dbbcef..219ae3583da 100644 --- a/src/server/scripts/EasternKingdoms/ThroneOfTheTides/boss_erunak_stonespeaker_mindbender_ghursha.cpp +++ b/src/server/scripts/EasternKingdoms/ThroneOfTheTides/boss_erunak_stonespeaker_mindbender_ghursha.cpp @@ -83,8 +83,12 @@ enum Events }; // predicate function to select not charmed target -struct NotCharmedTargetSelector : public std::unary_function +struct NotCharmedTargetSelector { +public: + using argument_type = Unit*; + using result_type = bool; + NotCharmedTargetSelector() {} bool operator()(Unit const* target) const diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index fde2c21ff03..7476df160cb 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -548,9 +548,12 @@ class spell_mandokir_spirit_vengeance_cancel : public SpellScriptLoader } }; -class DevastatingSlamTargetSelector : public std::unary_function +class DevastatingSlamTargetSelector { - public: +public: + using argument_type = Unit*; + using result_type = bool; + DevastatingSlamTargetSelector(Creature* me, const Unit* victim) : _me(me), _victim(victim) {} bool operator() (WorldObject* target) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DragonSoul/boss_warmaster_blackhorn.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DragonSoul/boss_warmaster_blackhorn.cpp index 7568ce3087d..359117b92e2 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DragonSoul/boss_warmaster_blackhorn.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DragonSoul/boss_warmaster_blackhorn.cpp @@ -795,9 +795,11 @@ class npc_warmaster_blackhorn_goriona: public CreatureScript EventMap events; uint8 phase; - struct TwilightFlamesSelector : public std::unary_function + struct TwilightFlamesSelector { public: + using argument_type = Unit*; + using result_type = bool; TwilightFlamesSelector() {} diff --git a/src/server/scripts/Kalimdor/Firelands/boss_bethtilac.cpp b/src/server/scripts/Kalimdor/Firelands/boss_bethtilac.cpp index ea7a564c203..a5aa3b8602d 100644 --- a/src/server/scripts/Kalimdor/Firelands/boss_bethtilac.cpp +++ b/src/server/scripts/Kalimdor/Firelands/boss_bethtilac.cpp @@ -118,9 +118,11 @@ const Position addsPos[9] = {59.665f, 406.437f, 111.0f, 5.02f} }; -struct PositionSelector : public std::unary_function +struct PositionSelector { - public: +public: + using argument_type = Unit*; + using result_type = bool; PositionSelector(bool b, uint32 spellId) : _b(b), _spellId(spellId) {} diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp index e528970ebca..3e2f56562f6 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp @@ -112,9 +112,12 @@ enum Spells SPELL_WAKING_NIGHTMARE_H = 67677 }; -class OrientationCheck : public std::unary_function +class OrientationCheck { - public: +public: + using argument_type = Unit*; + using result_type = bool; + explicit OrientationCheck(Unit* _caster) : caster(_caster) { } bool operator()(WorldObject* object) { diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index 8cb3f23d346..a4e87fa460b 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -299,9 +299,12 @@ class boss_gormok : public CreatureScript } }; -class SnobolledTargetSelector : public std::unary_function +class SnobolledTargetSelector { public: + using argument_type = Unit*; + using result_type = bool; + SnobolledTargetSelector(Unit const* /*unit*/) { } bool operator()(Unit* unit) const diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index fd4cb1abd6e..baf0a23d682 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -102,9 +102,12 @@ enum Actions ACTION_TALK_ENTER_ZONE = 2 }; -class BoneSpikeTargetSelector : public std::unary_function +class BoneSpikeTargetSelector { - public: +public: + using argument_type = Unit*; + using result_type = bool; + BoneSpikeTargetSelector(UnitAI* ai) : _ai(ai) { } bool operator()(Unit* unit) const diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 270b05f677c..a8a50a41ee4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -358,9 +358,12 @@ enum Misc DATA_VILE = 45814622 }; -class NecroticPlagueTargetCheck : public std::unary_function +class NecroticPlagueTargetCheck { - public: +public: + using argument_type = Unit*; + using result_type = bool; + NecroticPlagueTargetCheck(Unit const* obj, uint32 notAura1 = 0, uint32 notAura2 = 0) : _sourceObj(obj), _notAura1(notAura1), _notAura2(notAura2) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index ee31a556759..5e8f4dd8d82 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -163,8 +163,12 @@ class RisenArchmageCheck } }; -struct ManaVoidSelector : public std::unary_function +struct ManaVoidSelector { +public: + using argument_type = Unit*; + using result_type = bool; + explicit ManaVoidSelector(WorldObject const* source) : _source(source) { } bool operator()(Unit* unit) const diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 746922eef0f..0cc7a446d8e 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -196,8 +196,12 @@ class KelThuzadCharmedPlayerAI : public SimpleCharmedPlayerAI } }; -struct ManaUserTargetSelector : public std::unary_function +struct ManaUserTargetSelector { +public: + using argument_type = Unit*; + using result_type = bool; + bool operator()(Unit const* target) const { return target->GetTypeId() == TYPEID_PLAYER && target->GetPowerType() == POWER_MANA; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index 9930d8a71e0..529078da613 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -72,8 +72,12 @@ enum Events const float WEB_WRAP_MOVE_SPEED = 20.0f; -struct WebTargetSelector : public std::unary_function +struct WebTargetSelector { +public: + using argument_type = Unit*; + using result_type = bool; + WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {} bool operator()(Unit const* target) const { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp index 55ee26da1b3..e220ede5887 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp @@ -363,9 +363,12 @@ class spell_ulduar_rubble_summon : public SpellScriptLoader }; // predicate function to select non main tank target -class StoneGripTargetSelector : public std::unary_function +class StoneGripTargetSelector { public: + using argument_type = Unit*; + using result_type = bool; + StoneGripTargetSelector(Creature* me, Unit const* victim) : _me(me), _victim(victim) { } bool operator()(WorldObject* target) diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp index 85bca6afda3..2e755a1991c 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp @@ -305,9 +305,11 @@ struct IllidariCouncilBossAI : public BossAI uint32 _bossId; }; -class HammerTargetSelector : public std::unary_function +class HammerTargetSelector { public: + using argument_type = Unit*; + using result_type = bool; HammerTargetSelector(Unit const* unit) : _me(unit) { } bool operator()(Unit* unit) const diff --git a/src/server/scripts/Pandaria/HeartOfFear/boss_garalon.cpp b/src/server/scripts/Pandaria/HeartOfFear/boss_garalon.cpp index 67af8ab59e7..c71aac3a654 100644 --- a/src/server/scripts/Pandaria/HeartOfFear/boss_garalon.cpp +++ b/src/server/scripts/Pandaria/HeartOfFear/boss_garalon.cpp @@ -987,9 +987,12 @@ class spell_garalon_crush_trigger: public SpellScriptLoader }; // Target check for Pheromones Taunt / Attack Me + Broken Leg spells. -class BossCheck : public std::unary_function +class BossCheck { public: + using argument_type = Unit*; + using result_type = bool; + explicit BossCheck(Unit* _caster) : caster(_caster) { } bool operator()(WorldObject* object) diff --git a/src/server/scripts/Pandaria/HeartOfFear/boss_meljarak.cpp b/src/server/scripts/Pandaria/HeartOfFear/boss_meljarak.cpp index 7895abd465b..aecfc7848f7 100644 --- a/src/server/scripts/Pandaria/HeartOfFear/boss_meljarak.cpp +++ b/src/server/scripts/Pandaria/HeartOfFear/boss_meljarak.cpp @@ -917,9 +917,12 @@ class npc_korthik_elite_blademaster: public CreatureScript }; -struct NonAlreadyAmberPrisoner : public std::unary_function +struct NonAlreadyAmberPrisoner { public: + using argument_type = Unit*; + using result_type = bool; + NonAlreadyAmberPrisoner() { } bool operator()(Unit const* target) const { diff --git a/src/server/scripts/Pandaria/HeartOfFear/boss_zorlok.cpp b/src/server/scripts/Pandaria/HeartOfFear/boss_zorlok.cpp index d0697cfe082..c59b152572b 100644 --- a/src/server/scripts/Pandaria/HeartOfFear/boss_zorlok.cpp +++ b/src/server/scripts/Pandaria/HeartOfFear/boss_zorlok.cpp @@ -1405,9 +1405,12 @@ class spell_sonic_pulse : public SpellScriptLoader } }; -class ExhaleTargetFilter : public std::unary_function +class ExhaleTargetFilter { public: + using argument_type = Unit*; + using result_type = bool; + explicit ExhaleTargetFilter(Unit* caster) : _caster(caster) { } bool operator()(WorldObject* object) const diff --git a/src/server/scripts/Pandaria/WorldBosses/boss_oondasta.cpp b/src/server/scripts/Pandaria/WorldBosses/boss_oondasta.cpp index 919e0bc11e2..de21a28c14c 100644 --- a/src/server/scripts/Pandaria/WorldBosses/boss_oondasta.cpp +++ b/src/server/scripts/Pandaria/WorldBosses/boss_oondasta.cpp @@ -147,9 +147,12 @@ class boss_oondasta : public CreatureScript }; // Tank check for Alpha Male. -class TankCheck : public std::unary_function +class TankCheck { public: + using argument_type = Unit*; + using result_type = bool; + explicit TankCheck(Unit* _caster) : caster(_caster) { } bool operator()(WorldObject* object) From c86c11370c57a833a2d14fb1d94eab43b73dd15e Mon Sep 17 00:00:00 2001 From: TheGhost Date: Fri, 24 Oct 2025 13:33:46 +1300 Subject: [PATCH 08/49] Core/Dep: Update protobuf --- dep/protobuf/CMakeLists.txt | 24 +- dep/protobuf/src/google/protobuf/descriptor.h | 4 + .../src/google/protobuf/repeated_field.h | 51 ++-- .../src/google/protobuf/stubs/atomicops.h | 10 +- .../atomicops_internals_generic_c11_atomic.h | 231 ++++++++++++++++++ .../stubs/atomicops_internals_pnacl.h | 73 ------ .../google/protobuf/stubs/platform_macros.h | 4 +- 7 files changed, 293 insertions(+), 104 deletions(-) create mode 100644 dep/protobuf/src/google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h delete mode 100644 dep/protobuf/src/google/protobuf/stubs/atomicops_internals_pnacl.h diff --git a/dep/protobuf/CMakeLists.txt b/dep/protobuf/CMakeLists.txt index 2bb93bf3b03..cce1181568a 100644 --- a/dep/protobuf/CMakeLists.txt +++ b/dep/protobuf/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2018 TrinityCore +# This file is part of the TrinityCore Project. See AUTHORS file for Copyright information # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -74,10 +74,10 @@ target_link_libraries(protobuf if (BUILD_SHARED_LIBS) target_compile_definitions(protobuf PRIVATE - -DLIBPROTOBUF_EXPORTS - -DLIBPROTOC_EXPORTS + LIBPROTOBUF_EXPORTS + LIBPROTOC_EXPORTS PUBLIC - -DPROTOBUF_USE_DLLS) + PROTOBUF_USE_DLLS) endif() if (MSVC) @@ -87,7 +87,7 @@ if (MSVC) target_compile_definitions(protobuf PRIVATE - -D_SCL_SECURE_NO_WARNINGS) + _SCL_SECURE_NO_WARNINGS) endif() set_target_properties(protobuf @@ -106,3 +106,17 @@ if (BUILD_SHARED_LIBS) DESTINATION "${CMAKE_INSTALL_PREFIX}") endif() endif() + +# Generate precompiled header +if(USE_COREPCH) + list(APPEND protobuf_PCH_HEADERS + + + + + + + ) + + add_cxx_pch(protobuf "${protobuf_PCH_HEADERS}") +endif() diff --git a/dep/protobuf/src/google/protobuf/descriptor.h b/dep/protobuf/src/google/protobuf/descriptor.h index 68013f8ee41..6f52b767b2a 100644 --- a/dep/protobuf/src/google/protobuf/descriptor.h +++ b/dep/protobuf/src/google/protobuf/descriptor.h @@ -59,6 +59,10 @@ #include #include +// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h. +#ifdef TYPE_BOOL +#undef TYPE_BOOL +#endif // TYPE_BOOL namespace google { namespace protobuf { diff --git a/dep/protobuf/src/google/protobuf/repeated_field.h b/dep/protobuf/src/google/protobuf/repeated_field.h index c4dced368de..b8e378ac3e0 100644 --- a/dep/protobuf/src/google/protobuf/repeated_field.h +++ b/dep/protobuf/src/google/protobuf/repeated_field.h @@ -1250,13 +1250,11 @@ namespace internal { // This code based on net/proto/proto-array-internal.h by Jeffrey Yasskin // (jyasskin@google.com). template -class RepeatedPtrIterator - : public std::iterator< - std::random_access_iterator_tag, Element> { +class RepeatedPtrIterator { public: typedef RepeatedPtrIterator iterator; - typedef std::iterator< - std::random_access_iterator_tag, Element> superclass; + + typedef std::random_access_iterator_tag iterator_category; // Shadow the value_type in std::iterator<> because const_iterator::value_type // needs to be T, not const T. @@ -1264,9 +1262,9 @@ class RepeatedPtrIterator // Let the compiler know that these are type names, so we don't have to // write "typename" in front of them everywhere. - typedef typename superclass::reference reference; - typedef typename superclass::pointer pointer; - typedef typename superclass::difference_type difference_type; + typedef Element& reference; + typedef Element* pointer; + typedef std::ptrdiff_t difference_type; RepeatedPtrIterator() : it_(NULL) {} explicit RepeatedPtrIterator(void* const* it) : it_(it) {} @@ -1346,12 +1344,11 @@ class RepeatedPtrIterator // referenced by the iterator. It should either be "void *" for a mutable // iterator, or "const void *" for a constant iterator. template -class RepeatedPtrOverPtrsIterator - : public std::iterator { +class RepeatedPtrOverPtrsIterator { public: typedef RepeatedPtrOverPtrsIterator iterator; - typedef std::iterator< - std::random_access_iterator_tag, Element*> superclass; + + typedef std::random_access_iterator_tag iterator_category; // Shadow the value_type in std::iterator<> because const_iterator::value_type // needs to be T, not const T. @@ -1359,9 +1356,9 @@ class RepeatedPtrOverPtrsIterator // Let the compiler know that these are type names, so we don't have to // write "typename" in front of them everywhere. - typedef typename superclass::reference reference; - typedef typename superclass::pointer pointer; - typedef typename superclass::difference_type difference_type; + typedef Element*& reference; + typedef Element** pointer; + typedef std::ptrdiff_t difference_type; RepeatedPtrOverPtrsIterator() : it_(NULL) {} explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {} @@ -1479,9 +1476,13 @@ RepeatedPtrField::pointer_end() const { namespace internal { // A back inserter for RepeatedField objects. -template class RepeatedFieldBackInsertIterator - : public std::iterator { +template class RepeatedFieldBackInsertIterator { public: + typedef std::output_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; explicit RepeatedFieldBackInsertIterator( RepeatedField* const mutable_field) : field_(mutable_field) { @@ -1505,9 +1506,13 @@ template class RepeatedFieldBackInsertIterator }; // A back inserter for RepeatedPtrField objects. -template class RepeatedPtrFieldBackInsertIterator - : public std::iterator { +template class RepeatedPtrFieldBackInsertIterator { public: + typedef std::output_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; RepeatedPtrFieldBackInsertIterator( RepeatedPtrField* const mutable_field) : field_(mutable_field) { @@ -1537,9 +1542,13 @@ template class RepeatedPtrFieldBackInsertIterator // A back inserter for RepeatedPtrFields that inserts by transfering ownership // of a pointer. -template class AllocatedRepeatedPtrFieldBackInsertIterator - : public std::iterator { +template class AllocatedRepeatedPtrFieldBackInsertIterator { public: + typedef std::output_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; explicit AllocatedRepeatedPtrFieldBackInsertIterator( RepeatedPtrField* const mutable_field) : field_(mutable_field) { diff --git a/dep/protobuf/src/google/protobuf/stubs/atomicops.h b/dep/protobuf/src/google/protobuf/stubs/atomicops.h index b1336e36b93..8b49f19fbb5 100644 --- a/dep/protobuf/src/google/protobuf/stubs/atomicops.h +++ b/dep/protobuf/src/google/protobuf/stubs/atomicops.h @@ -124,7 +124,7 @@ Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, #if defined(__MINGW32__) && defined(MemoryBarrier) #undef MemoryBarrier #endif -void MemoryBarrier(); +void (MemoryBarrier)(); void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value); void Acquire_Store(volatile Atomic32* ptr, Atomic32 value); void Release_Store(volatile Atomic32* ptr, Atomic32 value); @@ -172,7 +172,7 @@ Atomic64 Release_Load(volatile const Atomic64* ptr); #if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64) #include #else -GOOGLE_PROTOBUF_ATOMICOPS_ERROR +#include #endif // Solaris @@ -181,7 +181,11 @@ GOOGLE_PROTOBUF_ATOMICOPS_ERROR // Apple. #elif defined(GOOGLE_PROTOBUF_OS_APPLE) +#if __has_feature(cxx_atomic) || _GNUC_VER >= 407 +#include +#else // __has_feature(cxx_atomic) || _GNUC_VER >= 407 #include +#endif // __has_feature(cxx_atomic) || _GNUC_VER >= 407 // GCC. #elif defined(__GNUC__) @@ -196,7 +200,7 @@ GOOGLE_PROTOBUF_ATOMICOPS_ERROR #elif defined(GOOGLE_PROTOBUF_ARCH_MIPS) || defined(GOOGLE_PROTOBUF_ARCH_MIPS64) #include #elif defined(__native_client__) -#include +#include #elif (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)) #include #elif defined(__clang__) diff --git a/dep/protobuf/src/google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h b/dep/protobuf/src/google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h new file mode 100644 index 00000000000..9276436088b --- /dev/null +++ b/dep/protobuf/src/google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h @@ -0,0 +1,231 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 Google Inc. 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. + +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_C11_ATOMIC_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_C11_ATOMIC_H_ + +#include + +namespace google { +namespace protobuf { +namespace internal { + +// This implementation is transitional and maintains the original API for +// atomicops.h. This requires casting memory locations to the atomic types, and +// assumes that the API and the C++11 implementation are layout-compatible, +// which isn't true for all implementations or hardware platforms. The static +// assertion should detect this issue, were it to fire then this header +// shouldn't be used. +// +// TODO(jfb) If this header manages to stay committed then the API should be +// modified, and all call sites updated. +typedef volatile std::atomic* AtomicLocation32; +static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32), + "incompatible 32-bit atomic layout"); + +inline void (MemoryBarrier)() { +#if defined(__GLIBCXX__) + // Work around libstdc++ bug 51038 where atomic_thread_fence was declared but + // not defined, leading to the linker complaining about undefined references. + __atomic_thread_fence(std::memory_order_seq_cst); +#else + std::atomic_thread_fence(std::memory_order_seq_cst); +#endif +} + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + ((AtomicLocation32)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_relaxed, + std::memory_order_relaxed); + return old_value; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + return ((AtomicLocation32)ptr) + ->exchange(new_value, std::memory_order_relaxed); +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return increment + + ((AtomicLocation32)ptr) + ->fetch_add(increment, std::memory_order_relaxed); +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return increment + ((AtomicLocation32)ptr)->fetch_add(increment); +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + ((AtomicLocation32)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_acquire, + std::memory_order_acquire); + return old_value; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + ((AtomicLocation32)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_release, + std::memory_order_relaxed); + return old_value; +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed); +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed); + (MemoryBarrier)(); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + ((AtomicLocation32)ptr)->store(value, std::memory_order_release); +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed); +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + return ((AtomicLocation32)ptr)->load(std::memory_order_acquire); +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + (MemoryBarrier)(); + return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed); +} + +#if defined(GOOGLE_PROTOBUF_ARCH_64_BIT) + +typedef volatile std::atomic* AtomicLocation64; +static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64), + "incompatible 64-bit atomic layout"); + +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + ((AtomicLocation64)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_relaxed, + std::memory_order_relaxed); + return old_value; +} + +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + return ((AtomicLocation64)ptr) + ->exchange(new_value, std::memory_order_relaxed); +} + +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return increment + + ((AtomicLocation64)ptr) + ->fetch_add(increment, std::memory_order_relaxed); +} + +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return increment + ((AtomicLocation64)ptr)->fetch_add(increment); +} + +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + ((AtomicLocation64)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_acquire, + std::memory_order_acquire); + return old_value; +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + ((AtomicLocation64)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_release, + std::memory_order_relaxed); + return old_value; +} + +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { + ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed); +} + +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { + ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed); + (MemoryBarrier)(); +} + +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { + ((AtomicLocation64)ptr)->store(value, std::memory_order_release); +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed); +} + +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { + return ((AtomicLocation64)ptr)->load(std::memory_order_acquire); +} + +inline Atomic64 Release_Load(volatile const Atomic64* ptr) { + (MemoryBarrier)(); + return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed); +} + +#endif // defined(GOOGLE_PROTOBUF_ARCH_64_BIT) + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_C11_ATOMIC_H_ diff --git a/dep/protobuf/src/google/protobuf/stubs/atomicops_internals_pnacl.h b/dep/protobuf/src/google/protobuf/stubs/atomicops_internals_pnacl.h deleted file mode 100644 index b10ac02c407..00000000000 --- a/dep/protobuf/src/google/protobuf/stubs/atomicops_internals_pnacl.h +++ /dev/null @@ -1,73 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2012 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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 Google Inc. 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. - -// This file is an internal atomic implementation, use atomicops.h instead. - -#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ -#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ - -namespace google { -namespace protobuf { -namespace internal { - -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - return __sync_val_compare_and_swap(ptr, old_value, new_value); -} - -inline void MemoryBarrier() { - __sync_synchronize(); -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value); - MemoryBarrier(); - return ret; -} - -inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { - MemoryBarrier(); - *ptr = value; -} - -inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { - Atomic32 value = *ptr; - MemoryBarrier(); - return value; -} - -} // namespace internal -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ diff --git a/dep/protobuf/src/google/protobuf/stubs/platform_macros.h b/dep/protobuf/src/google/protobuf/stubs/platform_macros.h index 7956d076dcd..86b87ad3d91 100644 --- a/dep/protobuf/src/google/protobuf/stubs/platform_macros.h +++ b/dep/protobuf/src/google/protobuf/stubs/platform_macros.h @@ -49,10 +49,10 @@ #elif defined(__QNX__) #define GOOGLE_PROTOBUF_ARCH_ARM_QNX 1 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1 -#elif defined(__ARMEL__) +#elif defined(_M_ARM) || defined(__ARMEL__) #define GOOGLE_PROTOBUF_ARCH_ARM 1 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1 -#elif defined(__aarch64__) +#elif defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined (_M_ARM64EC) || defined(__aarch64__) #define GOOGLE_PROTOBUF_ARCH_AARCH64 1 #define GOOGLE_PROTOBUF_ARCH_64_BIT 1 #elif defined(__MIPSEL__) From 758348476869f51a416e6bdd2c53250f1cd002d2 Mon Sep 17 00:00:00 2001 From: TheGhost Date: Fri, 24 Oct 2025 13:39:15 +1300 Subject: [PATCH 09/49] Cmake: Update CMakeLists --- CMakeLists.txt | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a2317ecc9..0f14a105580 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2018 TrinityCore +# This file is part of the TrinityCore Project. See AUTHORS file for Copyright information # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -8,8 +8,7 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# We require CMake >= 3.2 -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.24) # add this options before PROJECT keyword set(CMAKE_DISABLE_SOURCE_CHANGES ON) @@ -18,18 +17,12 @@ set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) # Set projectname (must be done AFTER setting configurationtypes) project(AshamaneCore) -# CMake policies (can not be handled elsewhere) -cmake_policy(SET CMP0005 NEW) -if(POLICY CMP0043) - cmake_policy(SET CMP0043 NEW) # Disable 'Ignore COMPILE_DEFINITIONS_ properties' +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) # find_package() uses upper-case _ROOT variables endif() -if(POLICY CMP0054) - cmake_policy(SET CMP0054 NEW) # Only interpret if() arguments as variables or keywords when unquoted - prevents intepreting if (SOME_STRING_VARIABLE MATCHES "MSVC") as if (SOME_STRING_VARIABLE MATCHES "1") -endif() - -if(POLICY CMP0074) - cmake_policy(SET CMP0074 NEW) # find_package() uses _ROOT variables +if(POLICY CMP0153) + cmake_policy(SET CMP0153 NEW) # The exec_program() command should not be called endif() # Set RPATH-handing (CMake parameters) @@ -44,6 +37,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/dep/cotire/CMake") # build in Release-mode by default if not explicitly set +if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config") + set(CMAKE_DEFAULT_BUILD_TYPE "RelWithDebInfo" CACHE INTERNAL "") +endif() if( NOT CMAKE_BUILD_TYPE ) set(CMAKE_BUILD_TYPE "RelWithDebInfo") endif() @@ -71,9 +67,12 @@ find_package(PCHSupport) find_package(MySQL) if(NOT WITHOUT_GIT) - find_package(Git) + find_package(Git 1.7) endif() +# find mysql client binary (needed by genrev) +find_package(MySQL OPTIONAL_COMPONENTS binary) + # Find revision ID and hash of the sourcetree include(cmake/genrev.cmake) @@ -85,3 +84,9 @@ add_subdirectory(dep) # add core sources add_subdirectory(src) + +# Catch cmakefile messes with our settings we explicitly leave up to the user +# restore user preference + if (NOT WITH_SOURCE_TREE STREQUAL "hierarchical-folders") + set_property(GLOBAL PROPERTY USE_FOLDERS OFF) + endif() From 73eb3c1713f1c3f69f72e005c50fdb2c047e6e53 Mon Sep 17 00:00:00 2001 From: TheGhost Date: Sat, 25 Oct 2025 13:37:04 +1300 Subject: [PATCH 10/49] Update spell_item.cpp Small indent and codestyle fixes (cherrypicked from 149e449506abd75add8f9a73f744860e1e5ad0ae) --- src/server/scripts/Spells/spell_item.cpp | 135 +++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index f9b765ed88f..2a8ec1636f7 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -4634,6 +4634,141 @@ class spell_item_brutal_kinship : public SpellScriptLoader } }; +// 45051 - Mad Alchemist's Potion (34440) +class spell_item_mad_alchemists_potion : public SpellScriptLoader +{ +public: + spell_item_mad_alchemists_potion() : SpellScriptLoader("spell_item_mad_alchemists_potion") {} + + class mad_alchemists_potion_SpellScript : public SpellScript + { + PrepareSpellScript(mad_alchemists_potion_SpellScript); + + void SecondaryEffect() + { + std::vector availableElixirs = + { + // Battle Elixirs + 33720, // Onslaught Elixir (28102) + 54452, // Adept's Elixir (28103) + 33726, // Elixir of Mastery (28104) + 28490, // Elixir of Major Strength (22824) + 28491, // Elixir of Healing Power (22825) + 28493, // Elixir of Major Frost Power (22827) + 54494, // Elixir of Major Agility (22831) + 28501, // Elixir of Major Firepower (22833) + 28503,// Elixir of Major Shadow Power (22835) + 38954, // Fel Strength Elixir (31679) + // Guardian Elixirs + 39625, // Elixir of Major Fortitude (32062) + 39626, // Earthen Elixir (32063) + 39627, // Elixir of Draenic Wisdom (32067) + 39628, // Elixir of Ironskin (32068) + 28502, // Elixir of Major Defense (22834) + 28514, // Elixir of Empowerment (22848) + // Other + 28489, // Elixir of Camouflage (22823) + 28496 // Elixir of the Searching Eye (22830) + }; + + Unit* target = GetCaster(); + + if (target->GetPowerType() == POWER_MANA) + availableElixirs.push_back(28509); // Elixir of Major Mageblood (22840) + + uint32 chosenElixir = Trinity::Containers::SelectRandomContainerElement(availableElixirs); + + bool useElixir = true; + + SpellGroup chosenSpellGroup = SPELL_GROUP_NONE; + if (sSpellMgr->IsSpellMemberOfSpellGroup(chosenElixir, SPELL_GROUP_ELIXIR_BATTLE)) + chosenSpellGroup = SPELL_GROUP_ELIXIR_BATTLE; + if (sSpellMgr->IsSpellMemberOfSpellGroup(chosenElixir, SPELL_GROUP_ELIXIR_GUARDIAN)) + chosenSpellGroup = SPELL_GROUP_ELIXIR_GUARDIAN; + // If another spell of the same group is already active the elixir should not be cast + if (chosenSpellGroup != SPELL_GROUP_NONE) + { + Unit::AuraApplicationMap const& auraMap = target->GetAppliedAuras(); + for (auto itr = auraMap.begin(); itr != auraMap.end(); ++itr) + { + uint32 spellId = itr->second->GetBase()->GetId(); + if (sSpellMgr->IsSpellMemberOfSpellGroup(spellId, chosenSpellGroup) && spellId != chosenElixir) + { + useElixir = false; + break; + } + } + } + + if (useElixir) + target->CastSpell(target, chosenElixir, true, GetCastItem()); + } + + void Register() override + { + AfterCast += SpellCastFn(mad_alchemists_potion_SpellScript::SecondaryEffect); + } + + }; + + SpellScript* GetSpellScript() const override + { + return new mad_alchemists_potion_SpellScript(); + } +}; + +// 53750 - Crazy Alchemist's Potion (40077) +class spell_item_crazy_alchemists_potion : public SpellScriptLoader +{ +public: + spell_item_crazy_alchemists_potion() : SpellScriptLoader("spell_item_crazy_alchemists_potion") {} + + class crazy_alchemists_potion_SpellScript : public SpellScript + { + PrepareSpellScript(crazy_alchemists_potion_SpellScript); + + void SecondaryEffect() + { + std::vector availableElixirs = + { + 43185, // Runic Healing Potion (33447) + 53750, // Crazy Alchemist's Potion (40077) + 53761, // Powerful Rejuvenation Potion (40087) + 53762, // Indestructible Potion (40093) + 53908, // Potion of Speed (40211) + 53909, // Potion of Wild Magic (40212) + 53910, // Mighty Arcane Protection Potion (40213) + 53911, // Mighty Fire Protection Potion (40214) + 53913, // Mighty Frost Protection Potion (40215) + 53914, // Mighty Nature Protection Potion (40216) + 53915 // Mighty Shadow Protection Potion (40217) + }; + + Unit* target = GetCaster(); + + if (!target->IsInCombat()) + availableElixirs.push_back(53753); // Potion of Nightmares (40081) + if (target->GetPowerType() == POWER_MANA) + availableElixirs.push_back(43186); // Runic Mana Potion(33448) + + uint32 chosenElixir = Trinity::Containers::SelectRandomContainerElement(availableElixirs); + + target->CastSpell(target, chosenElixir, true, GetCastItem()); + } + + void Register() override + { + AfterCast += SpellCastFn(crazy_alchemists_potion_SpellScript::SecondaryEffect); + } + + }; + + SpellScript* GetSpellScript() const override + { + return new crazy_alchemists_potion_SpellScript(); + } +}; + enum BurningEssenceSpell { MODEL_DRUID_OF_THE_FLAMES = 38150 From 7c0048be5c1a1734d21dd35aac18d917a1c734f9 Mon Sep 17 00:00:00 2001 From: Rushor Date: Fri, 10 Feb 2017 15:00:52 +0100 Subject: [PATCH 11/49] DB/Creature: Living Cyclone Closes #19065 (cherrypicked from 43b09d2b6990f25294a7e828d30cb38a61b15b0c) --- ...019_07_18_01_world_2017_02_10_00_world.sql | 375 ++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 sql/updates/world/master/2019_07_18_01_world_2017_02_10_00_world.sql diff --git a/sql/updates/world/master/2019_07_18_01_world_2017_02_10_00_world.sql b/sql/updates/world/master/2019_07_18_01_world_2017_02_10_00_world.sql new file mode 100644 index 00000000000..843fb5ee882 --- /dev/null +++ b/sql/updates/world/master/2019_07_18_01_world_2017_02_10_00_world.sql @@ -0,0 +1,375 @@ +-- ---------------------------------------------------------- +-- Living Cyclone +-- ---------------------------------------------------------- + +-- Pathing for Entry: 17160 'TDB FORMAT' +SET @NPC := 60651; +SET @PATH := @NPC * 10; +SET @POINT := 0; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`action`,`delay`) VALUES +(@PATH,@POINT := @POINT + 1,-1148.237,8336.811, 21.63617,0,0,0), -- 22:19:50 +(@PATH,@POINT := @POINT + 1,-1196.33, 8344.121, 20.71226,0,0,0), -- 22:20:00 +(@PATH,@POINT := @POINT + 1,-1216.812,8323.146, 11.78852,0,0,0), -- 22:20:11 +(@PATH,@POINT := @POINT + 1,-1240.605,8299.116, 6.195087,0,0,0), -- 22:20:29 +(@PATH,@POINT := @POINT + 1,-1278.502,8285.098, 3.645116,0,0,0), -- 22:20:37 +(@PATH,@POINT := @POINT + 1,-1281.754,8266.367,- 1.034753,0,0,0), -- 22:20:53 +(@PATH,@POINT := @POINT + 1,-1249.098,8281.325, 3.381279,0,0,0), -- 22:21:08 +(@PATH,@POINT := @POINT + 1,-1213.483,8285.096, 8.44901, 0,0,0), -- 22:21:27 +(@PATH,@POINT := @POINT + 1,-1196.676,8272.297, 11.64876,0,0,0), -- 22:21:42 +(@PATH,@POINT := @POINT + 1,-1161.769,8247.777, 10.07712,0,0,0), -- 22:21:53 +(@PATH,@POINT := @POINT + 1,-1160.778,8211.513, 5.701956,0,0,0), -- 22:22:07 +(@PATH,@POINT := @POINT + 1,-1168.08, 8187.924, 1.462332,0,0,0), -- 22:22:23 +(@PATH,@POINT := @POINT + 1,-1174.12, 8155.979, 1.800441,0,0,0), -- 22:22:35 +(@PATH,@POINT := @POINT + 1,-1172.058,8176.729, 1.013165,0,0,0), -- 22:22:47 +(@PATH,@POINT := @POINT + 1,-1161.829,8204.387, 4.388052,0,0,0), -- 22:22:55 +(@PATH,@POINT := @POINT + 1,-1161.278,8241.381, 9.467208,0,0,0), -- 22:23:08 +(@PATH,@POINT := @POINT + 1,-1180.527,8259.756, 11.79787,0,0,0), -- 22:15:33 +(@PATH,@POINT := @POINT + 1,-1208.19, 8283.085, 9.375608,0,0,0), -- 22:15:46 +(@PATH,@POINT := @POINT + 1,-1243.406,8284.08, 4.280885,0,0,0), -- 22:15:57 +(@PATH,@POINT := @POINT + 1,-1279.378,8252.215,-0.9195747,0,0,0), -- 22:16:11 +(@PATH,@POINT := @POINT + 1,-1281.549,8282.41, 2.547065,0,0,0), -- 22:16:34 +(@PATH,@POINT := @POINT + 1,-1262.651,8289.77, 5.181315,0,0,0), -- 22:16:45 +(@PATH,@POINT := @POINT + 1,-1219.715,8320.075, 10.71095,0,0,0), -- 22:17:01 +(@PATH,@POINT := @POINT + 1,-1202.644,8340.688, 19.24014,0,0,0), -- 22:17:17 +(@PATH,@POINT := @POINT + 1,-1179.973,8345.475, 22.11248,0,0,0), -- 22:17:29 +(@PATH,@POINT := @POINT + 1,-1174.452,8345.74, 21.92912,0,0,0), -- 22:17:39 +(@PATH,@POINT := @POINT + 1,-1141.888,8333.143, 21.9819, 0,0,0), -- 22:17:55 +(@PATH,@POINT := @POINT + 1,-1114.821,8318.269, 21.72685,0,0,0), -- 22:18:08 +(@PATH,@POINT := @POINT + 1,-1051.624,8321.764, 21.82816,0,0,0), -- 22:18:18 +(@PATH,@POINT := @POINT + 1,-1013.136,8301.93, 15.25349,0,0,0), -- 22:18:34 +(@PATH,@POINT := @POINT + 1,-1041.813,8321.18, 21.19265,0,0,0), -- 22:18:56 +(@PATH,@POINT := @POINT + 1,-1078.513,8321.752, 21.43271,0,0,0), -- 22:19:05 +(@PATH,@POINT := @POINT + 1,-1087.745,8321.825, 21.25556,0,0,0), -- 22:19:25 +(@PATH,@POINT := @POINT + 1,-1146.156,8335.557, 21.69788,0,0,0); -- 22:19:34 +-- 0x203AF4424010C20000004E0000275972 .go -1180.527 8259.756 11.79787 + +-- Pathing for Entry: 17160 'TDB FORMAT' +SET @NPC := 60656; +SET @PATH := @NPC * 10; +SET @POINT := 0; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`action`,`delay`) VALUES +(@PATH, 1,-1751.981,8803.936,33.19414,0,0,0), -- 23:46:33 +(@PATH, 2,-1767.672,8809.592,28.82925,0,0,0), -- 23:46:49 +(@PATH, 3,-1813.099,8810.471,30.90652,0,0,0), -- 23:47:00 +(@PATH, 4,-1830.744,8819.027,27.90022,0,0,0), -- 23:47:15 +(@PATH, 5,-1876.968,8840.01, 29.69574,0,0,0), -- 23:47:30 +(@PATH, 6,-1895.012,8833.254,29.23977,0,0,0), -- 23:47:45 +(@PATH, 7,-1935.814,8823.287,29.24092,0,0,0), -- 23:47:57 +(@PATH, 8,-1961.692,8834.017,26.24941,0,0,0), -- 23:48:12 +(@PATH, 9,-1973.036,8845.234,23.9778, 0,0,0), -- 23:48:21 +(@PATH,10,-1977.742,8882.643,32.54356,0,0,0), -- 23:48:30 +(@PATH,11,-1972.041,8907.73, 39.49168,0,0,0), -- 23:48:43 +(@PATH,12,-1965.393,8911.664,40.52651,0,0,0), -- 23:48:56 +(@PATH,13,-1924.88, 8917.485,37.42287,0,0,0), -- 23:49:02 +(@PATH,14,-1900.034,8930.83, 36.97285,0,0,0), -- 23:49:15 +(@PATH,15,-1868.678,8943.331,41.89066,0,0,0), -- 23:49:27 +(@PATH,16,-1841.491,8948.025,41.04195,0,0,0), -- 23:49:42 +(@PATH,17,-1828.61, 8939.722,39.24327,0,0,0), -- 23:49:50 +(@PATH,18,-1819.398,8933.352,39.06162,0,0,0), -- 23:50:01 +(@PATH,19,-1786.593,8900.07, 35.72157,0,0,0), -- 23:50:10 +(@PATH,20,-1765.321,8885.568,30.71168,0,0,0), -- 23:50:21 +(@PATH,21,-1742.2,8862.65, 34.80313,0,0,0), -- 23:50:36 +(@PATH,22,-1720.517,8848.105,34.74336,0,0,0), -- 23:50:46 +(@PATH,23,-1692.387,8835.063,34.99734,0,0,0), -- 23:50:56 +(@PATH,24,-1668.529,8815.561,38.73476,0,0,0), -- 23:51:09 +(@PATH,25,-1695.455,8800.848,33.58766,0,0,0), -- 23:51:23 +(@PATH,26,-1712.963,8792.557,29.20308,0,0,0); -- 23:51:36 + +-- Pathing for Entry: 17160 'UDB FORMAT' +SET @NPC := 60642; +SET @PATH := @NPC * 10; +SET @POINT := 0; +UPDATE `creature` SET `position_x`=-2892.007,`position_y`=8032.865,`position_z`=-23.66417,`spawndist`=0,`MovementType`=2 WHERE `guid`=@NPC; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`) VALUES +(@PATH,@POINT := @POINT + 1,-2902.842,8048.745,-26.66047), +(@PATH,@POINT := @POINT + 1,-2914.729,8066.475,-25.52568), +(@PATH,@POINT := @POINT + 1,-2938.884,8100.713,-25.02592), +(@PATH,@POINT := @POINT + 1,-2943.569,8132.004,-28.15207), +(@PATH,@POINT := @POINT + 1,-2944.654,8176.88, -31.43717), +(@PATH,@POINT := @POINT + 1,-2944.602,8181.935,-31.56879), +(@PATH,@POINT := @POINT + 1,-2946.233,8238.481,-33.21107), +(@PATH,@POINT := @POINT + 1,-2919.206,8278.326,-34.03708), +(@PATH,@POINT := @POINT + 1,-2895.873,8311.135,-31.49319), +(@PATH,@POINT := @POINT + 1,-2884.136,8333.219,-30.39172), +(@PATH,@POINT := @POINT + 1,-2864.667,8367.906,-29.98889), +(@PATH,@POINT := @POINT + 1,-2858.159,8424.75, -28.00413), +(@PATH,@POINT := @POINT + 1,-2857.332,8445.623,-30.27376), +(@PATH,@POINT := @POINT + 1,-2857.916,8492.398,-27.0516), +(@PATH,@POINT := @POINT + 1,-2856.89,8513.271, -27.54033), +(@PATH,@POINT := @POINT + 1,-2854.011,8549.171,-29.94309), +(@PATH,@POINT := @POINT + 1,-2855.151,8581.621,-27.27717), +(@PATH,@POINT := @POINT + 1,-2849.889,8610.885,-26.69822), +(@PATH,@POINT := @POINT + 1,-2825.617,8633.844,-26.74743), +(@PATH,@POINT := @POINT + 1,-2848.538,8613.273,-26.45103), +(@PATH,@POINT := @POINT + 1,-2851.183,8604.577,-27.21329), +(@PATH,@POINT := @POINT + 1,-2853.803,8565.779,-28.95534), +(@PATH,@POINT := @POINT + 1,-2856.356,8518.246,-28.17264), +(@PATH,@POINT := @POINT + 1,-2857.425,8508.404,-26.85656), +(@PATH,@POINT := @POINT + 1,-2856.638,8454.516,-30.35899), +(@PATH,@POINT := @POINT + 1,-2858.411,8433.794,-28.33096), +(@PATH,@POINT := @POINT + 1,-2856.189,8408.215,-29.57974), +(@PATH,@POINT := @POINT + 1,-2870.651,8358.156,-30.76722), +(@PATH,@POINT := @POINT + 1,-2877.243,8347.382,-30.37623), +(@PATH,@POINT := @POINT + 1,-2912.378,8287.774,-34.04333), +(@PATH,@POINT := @POINT + 1,-2943.818,8246.348,-33.60338), +(@PATH,@POINT := @POINT + 1,-2947.081,8216.918,-32.04597), +(@PATH,@POINT := @POINT + 1,-2946.544,8202.71, -31.09262), +(@PATH,@POINT := @POINT + 1,-2944.957,8155.807,-28.39342), +(@PATH,@POINT := @POINT + 1,-2940.194,8106.408,-25.62632), +(@PATH,@POINT := @POINT + 1,-2925.042,8081.121,-25.07792), +(@PATH,@POINT := @POINT + 1,-2909.449,8058.207,-26.68425), +(@PATH,@POINT := @POINT + 1,-2892.007,8032.865,-23.66417); +-- 0x2030A0424010C2000069A500000B6635 .go -2877.137 8347.396 -30.36304 + +-- Pathing for Entry: 17160 'TDB FORMAT' +SET @GUID := 60646; +SET @PATH := @GUID * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@GUID; +DELETE FROM `creature_addon` WHERE `guid`=@GUID; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@GUID,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH, 1,-2218.909,8532.035,-14.55127,0,0,0,100,0), -- 18:55:58 +(@PATH, 2,-2213.463,8493.347,-15.9245, 0,0,0,100,0), -- 18:56:11 +(@PATH, 3,-2235.288,8487.771,-20.22474,0,0,0,100,0), -- 18:56:27 +(@PATH, 4,-2271.988,8484.273,-25.57598,0,0,0,100,0), -- 18:56:37 +(@PATH, 5,-2300.219,8478.117,-27.93031,0,0,0,100,0), -- 18:56:53 +(@PATH, 6,-2343.819,8477.945,-30.46092,0,0,0,100,0), -- 18:57:06 +(@PATH, 7,-2345.436,8478.367,-30.71931,0,0,0,100,0), -- 18:57:20 +(@PATH, 8,-2366.974,8534.188,-28.57604,0,0,0,100,0), -- 18:57:31 +(@PATH, 9,-2364.656,8538.896,-27.93513,0,0,0,100,0), -- 18:57:46 +(@PATH,10,-2337.154,8588.368,-22.77536,0,0,0,100,0), -- 18:57:57 +(@PATH,11,-2333.299,8614.905,-19.03483,0,0,0,100,0), -- 18:58:13 +(@PATH,12,-2323.921,8652.335,-14.08994,0,0,0,100,0), -- 18:58:29 +(@PATH,13,-2287.332,8677.703,-10.03967,0,0,0,100,0), -- 18:58:38 +(@PATH,14,-2259.379,8681.381,-6.591813,0,0,0,100,0), -- 18:58:58 +(@PATH,15,-2221.033,8678.025,-4.474685,0,0,0,100,0), -- 18:59:11 +(@PATH,16,-2190.501,8652.262,-2.895641,0,0,0,100,0), -- 18:59:24 +(@PATH,17,-2203.092,8626.182,-3.644493,0,0,0,100,0), -- 18:59:41 +(@PATH,18,-2230.453,8595.404,-9.703726,0,0,0,100,0), -- 18:59:55 +(@PATH,19,-2238.125,8550.227,-13.32629,0,0,0,100,0); -- 19:00:11 +-- 0x203AF4424010C20000004E0000273692 .go -2218.909 8532.035 -14.55127 + +-- Pathing for Entry: 17160 'TDB FORMAT' +SET @GUID := 60647; +SET @PATH := @GUID * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-2851.062,`position_y`=8604.486,`position_z`=-26.98985 WHERE `guid`=@GUID; +DELETE FROM `creature_addon` WHERE `guid`=@GUID; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@GUID,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH, 1,-2851.062,8604.486,-26.98985,0,0,0,100,0), -- 19:18:28 +(@PATH, 2,-2853.612,8565.762,-28.95748,0,0,0,100,0), -- 19:18:39 +(@PATH, 3,-2856.305,8518.212,-28.2282, 0,0,0,100,0), -- 19:18:49 +(@PATH, 4,-2857.343,8508.396,-26.69543,0,0,0,100,0), -- 19:19:06 +(@PATH, 5,-2856.817,8454.49, -30.37154,0,0,0,100,0), -- 19:19:14 +(@PATH, 6,-2858.391,8433.736,-28.13358,0,0,0,100,0), -- 19:19:33 +(@PATH, 7,-2856.243,8408.164,-29.54103,0,0,0,100,0), -- 19:19:42 +(@PATH, 8,-2870.582,8358.115,-30.76497,0,0,0,100,0), -- 19:19:59 +(@PATH, 9,-2877.267,8347.434,-30.35114,0,0,0,100,0), -- 19:20:18 +(@PATH,10,-2912.502,8287.769,-34.04604,0,0,0,100,0), -- 19:20:31 +(@PATH,11,-2943.914,8246.276,-33.56764,0,0,0,100,0), -- 19:20:48 +(@PATH,12,-2947.085,8216.837,-32.07269,0,0,0,100,0), -- 19:21:08 +(@PATH,13,-2946.495,8202.583,-31.15883,0,0,0,100,0), -- 19:21:21 +(@PATH,14,-2944.915,8155.916,-28.40335,0,0,0,100,0), -- 19:21:33 +(@PATH,15,-2940.201,8106.595,-25.62872,0,0,0,100,0), -- 19:21:49 +(@PATH,16,-2924.944,8081.14, -25.20331,0,0,0,100,0), -- 19:22:05 +(@PATH,17,-2909.327,8058.345,-26.6944, 0,0,0,100,0), -- 19:22:18 +(@PATH,18,-2891.889,8032.808,-23.66979,0,0,0,100,0), -- 19:22:30 +(@PATH,19,-2902.842,8048.745,-26.66047,0,0,0,100,0), -- 19:22:42 +(@PATH,20,-2914.708,8066.444,-25.521, 0,0,0,100,0), -- 19:22:51 +(@PATH,21,-2938.842,8100.649,-25.0303, 0,0,0,100,0), -- 19:23:03 +(@PATH,22,-2943.514,8131.927,-28.15734,0,0,0,100,0), -- 19:23:16 +(@PATH,23,-2944.651,8176.857,-31.43738,0,0,0,100,0), -- 19:23:32 +(@PATH,24,-2944.602,8181.904,-31.56922,0,0,0,100,0), -- 19:23:48 +(@PATH,25,-2946.227,8238.67, -33.21095,0,0,0,100,0), -- 19:24:00 +(@PATH,26,-2919.207,8278.54, -34.03411,0,0,0,100,0), -- 19:24:14 +(@PATH,27,-2895.867,8311.143,-31.49473,0,0,0,100,0), -- 19:24:32 +(@PATH,28,-2884.13,8333.227, -30.39072,0,0,0,100,0), -- 19:24:50 +(@PATH,29,-2864.657,8367.927,-29.98916,0,0,0,100,0), -- 19:25:03 +(@PATH,30,-2858.147,8424.769,-28.00387,0,0,0,100,0), -- 19:25:22 +(@PATH,31,-2857.332,8445.621,-30.27377,0,0,0,100,0), -- 19:25:39 +(@PATH,32,-2857.913,8492.428,-27.05224,0,0,0,100,0), -- 19:25:48 +(@PATH,33,-2856.889,8513.242,-27.54257,0,0,0,100,0), -- 19:26:05 +(@PATH,34,-2854.012,8549.157,-29.94097,0,0,0,100,0), -- 19:26:15 +(@PATH,35,-2855.15,8581.633, -27.27661,0,0,0,100,0), -- 19:26:32 +(@PATH,36,-2849.891,8610.896,-26.69648,0,0,0,100,0), -- 19:26:42 +(@PATH,37,-2825.622,8633.816,-26.75046,0,0,0,100,0), -- 19:26:54 +(@PATH,38,-2848.538,8613.273,-26.45103,0,0,0,100,0); -- 19:27:12 +-- 0x203AF4424010C20000004E0000271DE1 .go -2851.062 8604.486 -26.98985 + +-- Pathing for Entry: 17160 'TDB FORMAT' +SET @GUID := 60650; +SET @PATH := @GUID * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-1180.527,`position_y`=8259.756,`position_z`=11.79787 WHERE `guid`=@GUID; +DELETE FROM `creature_addon` WHERE `guid`=@GUID; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@GUID,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH, 1,-1180.527,8259.756,11.79787, 0,0,0,100,0), -- 22:15:33 +(@PATH, 2,-1208.19, 8283.085, 9.375608, 0,0,0,100,0), -- 22:15:46 +(@PATH, 3,-1243.406,8284.08, 4.280885, 0,0,0,100,0), -- 22:15:57 +(@PATH, 4,-1279.378,8252.215,-0.9195747,0,0,0,100,0), -- 22:16:11 +(@PATH, 5,-1281.549,8282.41, 2.547065, 0,0,0,100,0), -- 22:16:34 +(@PATH, 6,-1262.651,8289.77, 5.181315, 0,0,0,100,0), -- 22:16:45 +(@PATH, 7,-1219.715,8320.075,10.71095, 0,0,0,100,0), -- 22:17:01 +(@PATH, 8,-1202.644,8340.688,19.24014, 0,0,0,100,0), -- 22:17:17 +(@PATH, 9,-1179.973,8345.475,22.11248, 0,0,0,100,0), -- 22:17:29 +(@PATH,10,-1174.452,8345.74, 21.92912, 0,0,0,100,0), -- 22:17:39 +(@PATH,11,-1141.888,8333.143,21.9819, 0,0,0,100,0), -- 22:17:55 +(@PATH,12,-1114.821,8318.269,21.72685, 0,0,0,100,0), -- 22:18:08 +(@PATH,13,-1051.624,8321.764,21.82816, 0,0,0,100,0), -- 22:18:18 +(@PATH,14,-1013.136,8301.93, 15.25349, 0,0,0,100,0), -- 22:18:34 +(@PATH,15,-1041.813,8321.18, 21.19265, 0,0,0,100,0), -- 22:18:56 +(@PATH,16,-1078.513,8321.752,21.43271, 0,0,0,100,0), -- 22:19:05 +(@PATH,17,-1087.745,8321.825,21.25556, 0,0,0,100,0), -- 22:19:25 +(@PATH,18,-1146.156,8335.557,21.69788, 0,0,0,100,0), -- 22:19:34 +(@PATH,19,-1148.237,8336.811,21.63617, 0,0,0,100,0), -- 22:19:50 +(@PATH,20,-1196.33, 8344.121,20.71226, 0,0,0,100,0), -- 22:20:00 +(@PATH,21,-1216.812,8323.146,11.78852, 0,0,0,100,0), -- 22:20:11 +(@PATH,22,-1240.605,8299.116, 6.195087, 0,0,0,100,0), -- 22:20:29 +(@PATH,23,-1278.502,8285.098, 3.645116, 0,0,0,100,0), -- 22:20:37 +(@PATH,24,-1281.754,8266.367,-1.034753, 0,0,0,100,0), -- 22:20:53 +(@PATH,25,-1249.098,8281.325, 3.381279, 0,0,0,100,0), -- 22:21:08 +(@PATH,26,-1213.483,8285.096, 8.44901, 0,0,0,100,0), -- 22:21:27 +(@PATH,27,-1196.676,8272.297,11.64876, 0,0,0,100,0), -- 22:21:42 +(@PATH,28,-1161.769,8247.777,10.07712, 0,0,0,100,0), -- 22:21:53 +(@PATH,29,-1160.778,8211.513, 5.701956, 0,0,0,100,0), -- 22:22:07 +(@PATH,30,-1168.08, 8187.924, 1.462332, 0,0,0,100,0), -- 22:22:23 +(@PATH,31,-1174.12, 8155.979, 1.800441, 0,0,0,100,0), -- 22:22:35 +(@PATH,32,-1172.058,8176.729, 1.013165, 0,0,0,100,0), -- 22:22:47 +(@PATH,33,-1161.829,8204.387, 4.388052, 0,0,0,100,0), -- 22:22:55 +(@PATH,34,-1161.278,8241.381, 9.467208, 0,0,0,100,0); -- 22:23:08 +-- 0x203AF4424010C20000004E0000275972 .go -1180.527 8259.756 11.79787 + +-- Pathing for Entry: 17160 'TDB FORMAT' +SET @GUID := 60652; +SET @POINT := 0; +SET @PATH := @GUID * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@GUID; +DELETE FROM `creature_addon` WHERE `guid`=@GUID; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@GUID,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,@POINT := @POINT + 1,-847.6241,8506.102,46.51483,0,0,0,100,0), -- 22:44:48 +(@PATH,@POINT := @POINT + 1,-885.6124,8492.075,47.08598,0,0,0,100,0), -- 22:45:09 +(@PATH,@POINT := @POINT + 1,-910.4478,8501.637,45.99551,0,0,0,100,0), -- 22:45:20 +(@PATH,@POINT := @POINT + 1,-949.2445,8515.805,46.90946,0,0,0,100,0), -- 22:45:33 +(@PATH,@POINT := @POINT + 1,-976.4283,8513.402,45.46638,0,0,0,100,0), -- 22:45:49 +(@PATH,@POINT := @POINT + 1,-995.79, 8488.892,41.1385, 0,0,0,100,0), -- 22:46:03 +(@PATH,@POINT := @POINT + 1,-1001.121,8471.082,38.10412,0,0,0,100,0), -- 22:46:12 +(@PATH,@POINT := @POINT + 1,-995.4634,8451.914,40.31676,0,0,0,100,0), -- 22:46:27 +(@PATH,@POINT := @POINT + 1,-975.4257,8423.902,34.86913,0,0,0,100,0), -- 22:46:34 +(@PATH,@POINT := @POINT + 1,-957.0313,8412.603,36.46369,0,0,0,100,0), -- 22:46:45 +(@PATH,@POINT := @POINT + 1,-916.869, 8402.206,29.6397, 0,0,0,100,0), -- 22:47:03 +(@PATH,@POINT := @POINT + 1,-889.0398,8409.73, 33.77266,0,0,0,100,0), -- 22:47:10 +(@PATH,@POINT := @POINT + 1,-884.9122,8411.354,34.38969,0,0,0,100,0), -- 22:47:23 +(@PATH,@POINT := @POINT + 1,-851.2719,8457.979,34.22821,0,0,0,100,0), -- 22:47:38 +(@PATH,@POINT := @POINT + 1,-818.7665,8468.701,35.97379,0,0,0,100,0), -- 22:48:03 +(@PATH,@POINT := @POINT + 1,-788.2867,8481.544,39.92352,0,0,0,100,0), -- 22:48:05 +(@PATH,@POINT := @POINT + 1,-772.3636,8499.309,41.57874,0,0,0,100,0), -- 22:48:19 +(@PATH,@POINT := @POINT + 1,-760.1832,8535.275,46.50875,0,0,0,100,0), -- 22:48:31 +(@PATH,@POINT := @POINT + 1,-749.8218,8557.404,47.89983,0,0,0,100,0), -- 22:48:46 +(@PATH,@POINT := @POINT + 1,-727.6384,8550.875,49.25499,0,0,0,100,0), -- 22:48:53 +(@PATH,@POINT := @POINT + 1,-716.4973,8546.428,49.82978,0,0,0,100,0), -- 22:49:08 +(@PATH,@POINT := @POINT + 1,-702.9384,8521.404,47.29637,0,0,0,100,0), -- 22:49:10 +(@PATH,@POINT := @POINT + 1,-695.9539,8501.604,44.29335,0,0,0,100,0), -- 22:49:24 +(@PATH,@POINT := @POINT + 1,-714.644, 8474.453,37.31478,0,0,0,100,0), -- 22:49:34 +(@PATH,@POINT := @POINT + 1,-746.7903,8474.797,40.27406,0,0,0,100,0), -- 22:49:56 +(@PATH,@POINT := @POINT + 1,-759.4641,8483.564,41.5388, 0,0,0,100,0), -- 22:50:04 +(@PATH,@POINT := @POINT + 1,-808.5963,8521.328,46.28402,0,0,0,100,0); -- 22:50:20 +-- 0x203AF4424010C20000004E00002786A9 .go -749.7501 8557.416 47.83742 + +-- Pathing for Entry: 17160 'TDB FORMAT' +SET @GUID := 60654; +SET @POINT := 0; +SET @PATH := @GUID * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@GUID; +DELETE FROM `creature_addon` WHERE `guid`=@GUID; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@GUID,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,@POINT := @POINT + 1,-1329.849,8729.318,29.77645,0,0,0,100,0), -- 23:03:46 +(@PATH,@POINT := @POINT + 1,-1345.848,8732.217,28.78369,0,0,0,100,0), -- 23:03:58 +(@PATH,@POINT := @POINT + 1,-1371.013,8747.047,29.38465,0,0,0,100,0), -- 23:04:08 +(@PATH,@POINT := @POINT + 1,-1387.687,8770.004,31.64497,0,0,0,100,0), -- 23:04:20 +(@PATH,@POINT := @POINT + 1,-1416.33, 8781.183,29.89367,0,0,0,100,0), -- 23:04:28 +(@PATH,@POINT := @POINT + 1,-1417.822,8780.176,29.44069,0,0,0,100,0), -- 23:04:40 +(@PATH,@POINT := @POINT + 1,-1450.178,8799.719,28.27308,0,0,0,100,0), -- 23:04:50 +(@PATH,@POINT := @POINT + 1,-1474.821,8821.99, 33.64485,0,0,0,100,0), -- 23:05:01 +(@PATH,@POINT := @POINT + 1,-1481.276,8841.878,37.36152,0,0,0,100,0), -- 23:05:11 +(@PATH,@POINT := @POINT + 1,-1485.313,8880.046,37.81051,0,0,0,100,0), -- 23:05:23 +(@PATH,@POINT := @POINT + 1,-1486.957,8908.776,43.98286,0,0,0,100,0), -- 23:05:35 +(@PATH,@POINT := @POINT + 1,-1485.844,8884.578,38.73222,0,0,0,100,0), -- 23:05:48 +(@PATH,@POINT := @POINT + 1,-1484.083,8857.072,37.6493, 0,0,0,100,0), -- 23:05:58 +(@PATH,@POINT := @POINT + 1,-1477.65, 8826.271,34.6497, 0,0,0,100,0), -- 23:06:12 +(@PATH,@POINT := @POINT + 1,-1460.998,8811.525,29.23185,0,0,0,100,0), -- 23:06:23 +(@PATH,@POINT := @POINT + 1,-1444.991,8793.285,28.77672,0,0,0,100,0), -- 23:06:32 +(@PATH,@POINT := @POINT + 1,-1440.622,8787.981,28.97463,0,0,0,100,0), -- 23:06:43 +(@PATH,@POINT := @POINT + 1,-1395.341,8775.701,31.54462,0,0,0,100,0), -- 23:06:53 +(@PATH,@POINT := @POINT + 1,-1381.846,8759.529,30.3087, 0,0,0,100,0), -- 23:07:05 +(@PATH,@POINT := @POINT + 1,-1364.425,8740.752,28.97256,0,0,0,100,0), -- 23:07:14 +(@PATH,@POINT := @POINT + 1,-1348.235,8732.832,28.96984,0,0,0,100,0), -- 23:07:26 +(@PATH,@POINT := @POINT + 1,-1307.293,8728.733,30.60105,0,0,0,100,0), -- 23:07:37 +(@PATH,@POINT := @POINT + 1,-1282.64, 8738.605,34.46647,0,0,0,100,0), -- 23:07:49 +(@PATH,@POINT := @POINT + 1,-1267.958,8745.07, 35.43052,0,0,0,100,0), -- 23:08:00 +(@PATH,@POINT := @POINT + 1,-1222.84, 8736.021,37.51833,0,0,0,100,0), -- 23:08:11 +(@PATH,@POINT := @POINT + 1,-1206.838,8726.57, 39.76221,0,0,0,100,0), -- 23:08:24 +(@PATH,@POINT := @POINT + 1,-1193.413,8717.713,40.97464,0,0,0,100,0), -- 23:08:32 +(@PATH,@POINT := @POINT + 1,-1153.848,8719.697,43.48478,0,0,0,100,0), -- 23:08:47 +(@PATH,@POINT := @POINT + 1,-1169.735,8707.974,41.73248,0,0,0,100,0), -- 23:09:00 +(@PATH,@POINT := @POINT + 1,-1197.885,8720.727,40.34807,0,0,0,100,0), -- 23:02:46 +(@PATH,@POINT := @POINT + 1,-1218.948,8733.604,37.98303,0,0,0,100,0), -- 23:03:02 +(@PATH,@POINT := @POINT + 1,-1240.587,8745.244,35.22275,0,0,0,100,0), -- 23:03:09 +(@PATH,@POINT := @POINT + 1,-1252.183,8750.959,35.51665,0,0,0,100,0), -- 23:03:23 +(@PATH,@POINT := @POINT + 1,-1298.374,8730.303,31.508, 0,0,0,100,0); -- 23:03:34 +-- 0x203AF4424010C20000004E0000278EE4 .go -1197.885 8720.727 40.34807 + +-- Pathing for Entry: 17160 'TDB FORMAT' +SET @GUID := 60655; +SET @POINT := 0; +SET @PATH := @GUID * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@GUID; +DELETE FROM `creature_addon` WHERE `guid`=@GUID; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@GUID,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,@POINT := @POINT + 1,-1324.84, 8611.415,24.3239, 0,0,0,100,0), -- 23:19:08 +(@PATH,@POINT := @POINT + 1,-1329.201,8646.008,24.05163, 0,0,0,100,0), -- 23:19:29 +(@PATH,@POINT := @POINT + 1,-1327.408,8682.793,29.86036, 0,0,0,100,0), -- 23:19:42 +(@PATH,@POINT := @POINT + 1,-1320.487,8705.758,28.43415, 0,0,0,100,0), -- 23:20:11 +(@PATH,@POINT := @POINT + 1,-1310.705,8751.045,35.48253, 0,0,0,100,0), -- 23:20:11 +(@PATH,@POINT := @POINT + 1,-1307.466,8791.086,33.90017, 0,0,0,100,0), -- 23:13:13 +(@PATH,@POINT := @POINT + 1,-1304.622,8821.599,45.152412,0,0,0,100,0), -- 23:13:54 +(@PATH,@POINT := @POINT + 1,-1307.374,8792.206,33.71959, 0,0,0,100,0), -- 23:14:19 +(@PATH,@POINT := @POINT + 1,-1309.528,8763.512,35.85816, 0,0,0,100,0), -- 23:14:22 +(@PATH,@POINT := @POINT + 1,-1313.73, 8721.64, 29.05592, 0,0,0,100,0), -- 23:14:42 +(@PATH,@POINT := @POINT + 1,-1326.086,8692.776,30.10572, 0,0,0,100,0), -- 23:14:48 +(@PATH,@POINT := @POINT + 1,-1329.644,8654.186,23.90092, 0,0,0,100,0), -- 23:15:01 +(@PATH,@POINT := @POINT + 1,-1326.048,8614.336,24.7538, 0,0,0,100,0), -- 23:15:17 +(@PATH,@POINT := @POINT + 1,-1307.329,8592.754,20.00387, 0,0,0,100,0), -- 23:15:35 +(@PATH,@POINT := @POINT + 1,-1260.748,8563.608,23.83166, 0,0,0,100,0), -- 23:15:57 +(@PATH,@POINT := @POINT + 1,-1237.174,8556.889,30.38428, 0,0,0,100,0), -- 23:16:09 +(@PATH,@POINT := @POINT + 1,-1187.048,8526.018,30.46066, 0,0,0,100,0), -- 23:16:24 +(@PATH,@POINT := @POINT + 1,-1175.692,8520.717,31.32639, 0,0,0,100,0), -- 23:16:42 +(@PATH,@POINT := @POINT + 1,-1118.066,8509.112,32.60777, 0,0,0,100,0), -- 23:17:01 +(@PATH,@POINT := @POINT + 1,-1075.616,8490.703,37.06806, 0,0,0,100,0), -- 23:17:15 +(@PATH,@POINT := @POINT + 1,-1112.405,8507.679,33.73273, 0,0,0,100,0), -- 23:17:36 +(@PATH,@POINT := @POINT + 1,-1130.282,8509.166,31.58519, 0,0,0,100,0), -- 23:17:48 +(@PATH,@POINT := @POINT + 1,-1144.1, 8509.896,30.99378, 0,0,0,100,0), -- 23:18:03 +(@PATH,@POINT := @POINT + 1,-1220.687,8551.584,29.93642, 0,0,0,100,0), -- 23:18:19 +(@PATH,@POINT := @POINT + 1,-1258.476,8562.503,24.51159, 0,0,0,100,0), -- 23:18:37 +(@PATH,@POINT := @POINT + 1,-1294.4, 8579.377,20.14703, 0,0,0,100,0); -- 23:18:57 +-- 0x203AF4424010C20000004E000027852A .go -1310.659 8750.904 35.48589 From 9cd2f131927ae79b3b2e8f8137b8f7e0c2b341db Mon Sep 17 00:00:00 2001 From: Rushor Date: Fri, 10 Feb 2017 15:03:09 +0100 Subject: [PATCH 12/49] DB/Creature: Bleeding Hollow Peon Closes #19069 (cherrypicked from c5db14d449db1e503cf6be0a9e2fb4c86c72da12) --- ...019_07_18_02_world_2017_02_10_01_world.sql | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 sql/updates/world/master/2019_07_18_02_world_2017_02_10_01_world.sql diff --git a/sql/updates/world/master/2019_07_18_02_world_2017_02_10_01_world.sql b/sql/updates/world/master/2019_07_18_02_world_2017_02_10_01_world.sql new file mode 100644 index 00000000000..03a982a9c6e --- /dev/null +++ b/sql/updates/world/master/2019_07_18_02_world_2017_02_10_01_world.sql @@ -0,0 +1,114 @@ +-- Bleeding Hollow Peon - Movement + Emotescript +SET @MAXGUID := 945; +SET @SCRIPTID := 5862800; +DELETE FROM `waypoint_scripts` WHERE `id` IN (@SCRIPTID+0); +INSERT INTO `waypoint_scripts` (`id`,`delay`,`command`,`datalong`,`datalong2`,`dataint`,`x`,`y`,`z`,`o`,`guid`) VALUES +-- EMOTE (state) +(@SCRIPTID+0, 2, 1, 69, 1, 0, 0, 0, 0, 0, (@MAXGUID := @MAXGUID + 1)), +(@SCRIPTID+0, 42, 1, 0, 1, 0, 0, 0, 0, 0, (@MAXGUID := @MAXGUID + 1)); + +SET @NPC := 58628; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`= 0,`MovementType`= 2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`action`,`delay`) VALUES +(@PATH, 1, -1066.28, 2076.29, 65.2581, 2.20343, 0, 0), +(@PATH, 2, -1084.71, 2090.96, 64.0698, 2.9684, 0, 0), +(@PATH, 3, -1107.22, 2093.74, 67.0261, 3.23937, 0, 0), +(@PATH, 4, -1126.19, 2091.05, 67.6642, 3.41215, 0, 0), +(@PATH, 5, -1140.15, 2088.18, 67.046, 3.85198, 0, 0), +(@PATH, 6, -1144.39, 2084.57, 66.9404, 3.93593, @SCRIPTID, 45000), +(@PATH, 7, -1132.81, 2089.31, 67.6161, 0.167592,0, 0), +(@PATH, 8, -1115.34, 2093.11, 67.5254, 0.0058, 0, 0), +(@PATH, 9, -1091.94, 2092.04, 65.1282, 5.93556, 0, 0), +(@PATH, 10, -1073.86, 2086.69, 63.2546, 5.72507, 0, 0), +(@PATH, 11, -1064.04, 2075.59, 65.6203, 5.00251, 0, 0), +(@PATH, 12, -1064.26, 2062.38, 67.3094, 4.686, @SCRIPTID, 45000); + +SET @NPC := 58632; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`= 0,`MovementType`= 2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`action`,`delay`) VALUES +(@PATH, 1, -967.837, 2049.47, 66.9396, 1.04197, 0, 0), +(@PATH, 2, -961.27, 2056.9, 66.9396, 1.31921, 0, 0), +(@PATH, 3, -959.369, 2062.51, 66.9396, 1.27759, @SCRIPTID, 45000), +(@PATH, 4, -963.171, 2062.44, 66.9396, 2.69897, 0, 0), +(@PATH, 5, -972.978, 2069.15, 67.2109, 2.68091, 0, 0), +(@PATH, 6, -980.363, 2071.69, 68.1111, 3.50008, 0, 0), +(@PATH, 7, -983.956, 2068.97, 67.4094, 4.27448, 0, 0), +(@PATH, 8, -985.507, 2063.74, 66.9396, 4.73079, 0, 0), +(@PATH, 9, -981.499, 2052.05, 67.3838, 5.23737, 0, 0), +(@PATH, 10, -969.215, 2033.99, 66.9399, 5.01824, 0, 0), +(@PATH, 11, -967.02, 2022.12, 66.9399, 4.62633, 0, 0), +(@PATH, 12, -967.238, 2012.22, 66.9399, 4.5423, @SCRIPTID, 45000), +(@PATH, 13, -966.301, 2034.51, 66.9405, 1.55778, 0, 0); + +SET @NPC := 58635; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`= 0,`MovementType`= 2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`action`,`delay`) VALUES +(@PATH, 1, -930.128, 2000.58, 65.8055, 3.10085, 0, 0), +(@PATH, 2, -943.891, 2000.6, 66.8665, 3.1574, @SCRIPTID, 45000), +(@PATH, 3, -927.429, 1999.94, 65.7533, 5.91571, 0, 0), +(@PATH, 4, -916.524, 1997.9, 66.3727, 5.4429, 0, 0), +(@PATH, 5, -911.155, 1991.46, 67.3741, 5.12875, 0, 0), +(@PATH, 6, -906.294, 1982.16, 67.5317, 5.10519, @SCRIPTID, 45000), +(@PATH, 7, -912.459, 1992.95, 67.1693, 2.59192, 0, 0), +(@PATH, 8, -925.844, 1998.59, 65.8413, 2.45997, 0, 0); + +SET @NPC := 58636; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`= 0,`MovementType`= 2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`action`,`delay`) VALUES +(@PATH, 1, -989.995, 1941.95, 71.4595, 2.19392, 0, 0), +(@PATH, 2, -1008.41, 1959.06, 68.9236, 2.41776, 0, 0), +(@PATH, 3, -1019.71, 1969.1, 68.6018, 2.38635, 0, 0), +(@PATH, 4, -1026.27, 1974.99, 70.055, 1.87191, 0, 0), +(@PATH, 5, -1026.92, 1982.57, 69.3283, 1.70698, @SCRIPTID, 45000), +(@PATH, 6, -1025.51, 1975.34, 69.8823, 5.22006, 0, 0), +(@PATH, 7, -1020.08, 1966.5, 68.308, 6.11541, 0, 0), +(@PATH, 8, -995.228, 1955.72, 69.9662, 5.31744, 0, 0), +(@PATH, 9, -978.143, 1924.37, 75.1594, 5.15555, 0, 0), +(@PATH, 10, -971.913, 1906.66, 81.0091, 4.7927, 0, 0), +(@PATH, 11, -969.988, 1896.65, 85.587, 4.44712, 0, 0), +(@PATH, 12, -968.026, 1884.12, 93.5716, 4.80605, @SCRIPTID, 45000), +(@PATH, 13, -968.339, 1894.25, 86.2747, 1.97154, 0, 0), +(@PATH, 14, -971.346, 1907.8, 80.164, 2.20952, 0, 0), +(@PATH, 15, -978.063, 1919.93, 76.9127, 2.11606, 0, 0); + +SET @NPC := 58638; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`= 0,`MovementType`= 2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`action`,`delay`) VALUES +(@PATH, 1, -969.117, 1895.51, 85.8342, 3.44732, 0, 0), +(@PATH, 2, -979.002, 1893.24, 92.7384, 3.86279, 0, 0), +(@PATH, 3, -980.753, 1889.95, 94.2667, 4.52409, @SCRIPTID, 45000), +(@PATH, 4, -969.104, 1893.87, 86.9405, 0.295507,0, 0), +(@PATH, 5, -943.258, 1896.12, 76.5289, 0.226394,0, 0), +(@PATH, 6, -927.465, 1904.29, 70.9232, 0.853927,0, 0), +(@PATH, 7, -918.028, 1919.59, 67.2824, 1.03928, 0, 0), +(@PATH, 8, -912.198, 1930.65, 66.9439, 0.900266,0, 0), +(@PATH, 9, -906.253, 1936.39, 66.9409, 6.10431, 0, 0), +(@PATH, 10, -902.916, 1935.38, 66.9409, 5.57889, 0, 0), +(@PATH, 11, -899.893, 1931.82, 66.9409, 5.33149, @SCRIPTID, 45000), +(@PATH, 12, -904.32, 1933.33, 66.9409, 3.3892, 0, 0), +(@PATH, 13, -909.279, 1931.34, 66.9409, 3.93348, 0, 0), +(@PATH, 14, -923.102, 1907.03, 69.6799, 3.97431, 0, 0), +(@PATH, 15, -935.694, 1898.91, 74.0559, 3.26588, 0, 0), +(@PATH, 16, -957.265, 1896.2, 79.8492, 3.07739, 0, 0); + +UPDATE `waypoint_data` SET `action_chance`= 100 WHERE `action` IN (@SCRIPTID); From edbd052e1301c2f0a38f15ff1ca912d160089b3b Mon Sep 17 00:00:00 2001 From: Rushor Date: Fri, 10 Feb 2017 15:09:43 +0100 Subject: [PATCH 13/49] DB/Creature: Mountain Gronns Closes #19094 (cherrypicked from 4e2a4b7b132be0fc917854cf675aa644429dd05f) --- ...019_07_18_03_world_2017_02_10_03_world.sql | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 sql/updates/world/master/2019_07_18_03_world_2017_02_10_03_world.sql diff --git a/sql/updates/world/master/2019_07_18_03_world_2017_02_10_03_world.sql b/sql/updates/world/master/2019_07_18_03_world_2017_02_10_03_world.sql new file mode 100644 index 00000000000..2489afc3f12 --- /dev/null +++ b/sql/updates/world/master/2019_07_18_03_world_2017_02_10_03_world.sql @@ -0,0 +1,149 @@ +-- ------------------------------------- +-- Mountain Gronns in Nagrand Entry: 19201 +-- ------------------------------------- + +-- The first two Gronn's are weird because they don't have a path back from their last waypoint. +-- They do random movement for a few minutes and then they just walk straight through the mountains back to the starting point. +-- Example: +-- (@GUID,66,-1086.546,8910.48,102.3874,0,0,0,0,0,0,0,0,0,0,0,0,0), +-- (@GUID,67,-1190.294,8772.655,44.03177,0,0,0,0,0,0,0,0,0,0,0,0,0), +-- I assume that Blizzard's intention was that they should despawn after reaching the last waypoint, so that's what I did. + +SET @MAXGUID := 947; +SET @SCRIPTID := 6873300; +DELETE FROM `waypoint_scripts` WHERE `id` IN (@SCRIPTID+0); +INSERT INTO `waypoint_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`, `guid`) VALUES +(@SCRIPTID+0, 1, 35, 1, 8, 0, 0, 0, 0, 0, (@MAXGUID := @MAXGUID + 1)), +(@SCRIPTID+0, 60, 18, 1000, 0, 0, 0, 0, 0, 0, (@MAXGUID := @MAXGUID + 1)); + +SET @NPC := 68733; +SET @PATH := @NPC * 10; +SET @POINT := 0; +UPDATE `creature` SET `position_x`=-1190.294,`position_y`=8772.655,`position_z`=44.03177 WHERE `guid`=@NPC; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`, `delay`, `action`) VALUES +(@PATH,@POINT := @POINT + 1,-1190.294,8772.655,44.03177,0,0), +(@PATH,@POINT := @POINT + 1,-1203.012,8742.168,42.7664, 0,0), +(@PATH,@POINT := @POINT + 1,-1199.56,8724.674,41.17319, 0,0), +(@PATH,@POINT := @POINT + 1,-1198.571,8721.961,40.50022,0,0), +(@PATH,@POINT := @POINT + 1,-1145.681519,8681.539063,43.931034,0,0), +(@PATH,@POINT := @POINT + 1,-1135.424,8685.5,48.49122,0,0), +(@PATH,@POINT := @POINT + 1,-1106.267,8698.869,61.74326,0,0), +(@PATH,@POINT := @POINT + 1,-1089.461,8709.732,68.98933,0,0), +(@PATH,@POINT := @POINT + 1,-1080.214,8724.287,77.56756,0,0), +(@PATH,@POINT := @POINT + 1,-1076.087,8730.615,80.32574,0,0), +(@PATH,@POINT := @POINT + 1,-1073.906,8743.322,83.13339,0,0), +(@PATH,@POINT := @POINT + 1,-1071.587,8769.987,88.95515,0,0), +(@PATH,@POINT := @POINT + 1,-1069.364,8792.963,93.90515,0,0), +(@PATH,@POINT := @POINT + 1,-1073.472,8810.984,98.12231,0,0), +(@PATH,@POINT := @POINT + 1,-1081.081,8848.842,102.7461,0,0), +(@PATH,@POINT := @POINT + 1,-1082.776,8856.875,102.9781,0,0), +(@PATH,@POINT := @POINT + 1,-1086.328735,8893.722656,102.045715,0,0), +(@PATH,@POINT := @POINT + 1,-1055.303467,8927.958984,100.954239,65000,@SCRIPTID); + +SET @NPC := 68734; +SET @PATH := @NPC * 10; +SET @POINT := 0; +UPDATE `creature` SET `position_x`=-984.8678,`position_y`=8734.932,`position_z`=132.8936 WHERE `guid`=@NPC; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`, `delay`, `action`) VALUES +(@PATH,@POINT := @POINT + 1,-984.8678,8734.932,132.8936,0,0), +(@PATH,@POINT := @POINT + 1,-999.9858,8740.252,125.7903,0,0), +(@PATH,@POINT := @POINT + 1,-1007.913,8747.668,121.9, 0,0), +(@PATH,@POINT := @POINT + 1,-1018.669983,8761.624023,118.182793,0,0), +(@PATH,@POINT := @POINT + 1,-1021.87,8774.891,117.6102 ,0,0), +(@PATH,@POINT := @POINT + 1,-1028.338,8786.554,114.4703,0,0), +(@PATH,@POINT := @POINT + 1,-1043.908,8807.875,110.2811,0,0), +(@PATH,@POINT := @POINT + 1,-1056.555,8834.715,107.1923,0,0), +(@PATH,@POINT := @POINT + 1,-1047.57,8848.311,116.0382 ,0,0), +(@PATH,@POINT := @POINT + 1,-1033.689,8858.738,125.4172,0,0), +(@PATH,@POINT := @POINT + 1,-1014.58,8869.018,133.7491 ,0,0), +(@PATH,@POINT := @POINT + 1,-995.608,8868.662,139.3823 ,0,0), +(@PATH,@POINT := @POINT + 1,-974.8796,8879.833,145.5816,0,0), +(@PATH,@POINT := @POINT + 1,-940.694,8902.678,150.1837,0,0), +(@PATH,@POINT := @POINT + 1,-924.4999,8913.035,151.7751,0,0), +(@PATH,@POINT := @POINT + 1,-908.0786,8923.119,153.3695,0,0), +(@PATH,@POINT := @POINT + 1,-886.0104,8933.393,155.4501,0,0), +(@PATH,@POINT := @POINT + 1,-874.3984,8936.214,156.2588,0,0), +(@PATH,@POINT := @POINT + 1,-855.9192,8931.477,158.7263,0,0), +(@PATH,@POINT := @POINT + 1,-845.134521,8925.713867,161.844772,0,0), +(@PATH,@POINT := @POINT + 1,-834.978149,8919.649414,165.966446,65000,@SCRIPTID); + +UPDATE `waypoint_data` SET `action_chance`=100 WHERE `action` IN (@SCRIPTID); + +SET @NPC := 68735; +SET @PATH := @NPC * 10; +SET @POINT := 0; +UPDATE `creature` SET `position_x`=-1800.628,`position_y`=8785.258,`position_z`=31.36622 WHERE `guid`=@NPC; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`, `delay`) VALUES +(@PATH,@POINT := @POINT + 1,-1800.628,8785.258,31.36622,0), -- 17:17:19 +(@PATH,@POINT := @POINT + 1,-1821.058,8778.673,30.80778,0), -- 17:17:24 +(@PATH,@POINT := @POINT + 1,-1848.456,8762.41,28.90891,0), -- 17:17:37 +(@PATH,@POINT := @POINT + 1,-1869.854,8754.341,26.27174,0), -- 17:17:46 +(@PATH,@POINT := @POINT + 1,-1904.505,8759.32,26.06429,0), -- 17:17:54 +(@PATH,@POINT := @POINT + 1,-1918.91,8769.67,26.86385,10000), -- 17:18:12 +(@PATH,@POINT := @POINT + 1,-1946.543091,8816.708984,28.342142,0), -- 17:20:29 +(@PATH,@POINT := @POINT + 1,-1981.723999,8863.507813,25.978216,0), -- 17:20:33 +(@PATH,@POINT := @POINT + 1,-2015.871,8875.336,30.86393,0), -- 17:20:36 +(@PATH,@POINT := @POINT + 1,-1997.016,8879.214,31.98178,0), -- 17:21:39 +(@PATH,@POINT := @POINT + 1,-1966.578,8847.789,26.00286,0), -- 17:21:52 +(@PATH,@POINT := @POINT + 1,-1946.478,8824.432,29.30156,0), -- 17:22:08 +(@PATH,@POINT := @POINT + 1,-1944.506,8822.006,29.37523,0), -- 17:22:22 +(@PATH,@POINT := @POINT + 1,-1925.181,8787.125,27.40347,0), -- 17:22:30 +(@PATH,@POINT := @POINT + 1,-1916.387,8762.832,26.09533,0), -- 17:22:42 +(@PATH,@POINT := @POINT + 1,-1874.201,8754.344,26.05693,0), -- 17:22:51 +(@PATH,@POINT := @POINT + 1,-1854.197,8759.664,28.04397,0), -- 17:23:09 +(@PATH,@POINT := @POINT + 1,-1840.163,8769.178,30.26139,0), -- 17:23:18 +(@PATH,@POINT := @POINT + 1,-1815.867,8780.174,31.31474,0), -- 17:23:26 +(@PATH,@POINT := @POINT + 1,-1791.843,8788.039,30.60195,0), -- 17:23:39 +(@PATH,@POINT := @POINT + 1,-1778.97,8792.19,28.33318,0), -- 17:23:44 +(@PATH,@POINT := @POINT + 1,-1785.26,8790.171,29.29748,0); -- 17:23:52 +-- 0x203AF4424012C04000004E0000273198 .go -1800.628 8785.258 31.36622 + +SET @NPC := 68736; +SET @PATH := @NPC * 10; +SET @POINT := 0; +UPDATE `creature` SET `position_x`=-1882.313,`position_y`=8993.66,`position_z`=38.3989 WHERE `guid`=@NPC; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`, `delay`) VALUES +(@PATH,@POINT := @POINT + 1,-1882.313,8993.66,38.3989,0), -- 17:35:09 +(@PATH,@POINT := @POINT + 1,-1871.939,8953.98,41.94349,0), -- 17:35:23 +(@PATH,@POINT := @POINT + 1,-1836.418,8920.867,36.96106,0), -- 17:35:36 +(@PATH,@POINT := @POINT + 1,-1832.932,8918.501,36.04041,0), -- 17:35:54 +(@PATH,@POINT := @POINT + 1,-1782.748,8893.457,34.7769,0), -- 17:36:08 +(@PATH,@POINT := @POINT + 1,-1749.646,8880.189,32.58824,30000), -- 17:36:18 +(@PATH,@POINT := @POINT + 1,-1749.675,8880.189,32.43178,0), -- 17:39:58 +(@PATH,@POINT := @POINT + 1,-1716.815,8865.834,35.36955,0), -- 17:40:13 +(@PATH,@POINT := @POINT + 1,-1701.336,8863.66,33.39202,0), -- 17:40:26 +(@PATH,@POINT := @POINT + 1,-1663.693,8847.714,34.84836,0), -- 17:40:42 +(@PATH,@POINT := @POINT + 1,-1666.743,8834.359,36.58212,0), -- 17:40:52 +(@PATH,@POINT := @POINT + 1,-1692.787,8829.908,35.22899,0), -- 17:40:58 +(@PATH,@POINT := @POINT + 1,-1728.21,8834.949,35.92305,0), -- 17:41:09 +(@PATH,@POINT := @POINT + 1,-1763.568,8846.715,28.71403,0), -- 17:41:28 +(@PATH,@POINT := @POINT + 1,-1786.974,8851.196,30.74931,0), -- 17:41:39 +(@PATH,@POINT := @POINT + 1,-1804.311,8857.869,29.32577,0), -- 17:41:51 +(@PATH,@POINT := @POINT + 1,-1836.927,8878.327,34.59752,0), -- 17:42:01 +(@PATH,@POINT := @POINT + 1,-1857.11,8892.201,36.93163,0), -- 17:42:12 +(@PATH,@POINT := @POINT + 1,-1886.158,8898.459,37.84557,0), -- 17:42:24 +(@PATH,@POINT := @POINT + 1,-1902.083,8901.02,38.78384,0), -- 17:42:37 +(@PATH,@POINT := @POINT + 1,-1966.359,8933.63,38.7355,0), -- 17:42:54 +(@PATH,@POINT := @POINT + 1,-1976.945,8945.818,37.83896,0), -- 17:43:13 +(@PATH,@POINT := @POINT + 1,-1972.83,9000.511,41.57624,0), -- 17:43:20 +(@PATH,@POINT := @POINT + 1,-1955.283,9009.258,41.16612,0), -- 17:43:39 +(@PATH,@POINT := @POINT + 1,-1924.979,9016.831,40.69277,0), -- 17:43:48 +(@PATH,@POINT := @POINT + 1,-1917.55,9015.53,40.05937,0), -- 17:44:00 +(@PATH,@POINT := @POINT + 1,-1885.793,9012.721,41.2858,0); -- 17:44:11 +-- 0x203AF4424012C04000004E0000274379 .go -1882.313 8993.66 38.3989 From ab9bf1f66bbca33040d986c1321e4be6eab30b74 Mon Sep 17 00:00:00 2001 From: Rushor Date: Fri, 10 Feb 2017 15:12:35 +0100 Subject: [PATCH 14/49] DB/Creature: Katherine Lee Closes #19095 (cherrypicked from bbc6799cd7c0a83b81496c01d21c110decebae6d) --- .../master/2019_07_18_03_world_2017_02_10_04_world.sql | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 sql/updates/world/master/2019_07_18_03_world_2017_02_10_04_world.sql diff --git a/sql/updates/world/master/2019_07_18_03_world_2017_02_10_04_world.sql b/sql/updates/world/master/2019_07_18_03_world_2017_02_10_04_world.sql new file mode 100644 index 00000000000..147fbe07baf --- /dev/null +++ b/sql/updates/world/master/2019_07_18_03_world_2017_02_10_04_world.sql @@ -0,0 +1,6 @@ +-- Katherine Lee SAI +SET @ENTRY := 28705; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0 AND `id`=5; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,5,0,64,0,100,0,0,0,0,0,54,180000,0,0,0,0,0,1,0,0,0,0,0,0,0,"Katherine Lee - On Gossip Hello - Pause Waypoint"); From 15c96026283c5fcaedff401e0d85b2f5b19ca1ea Mon Sep 17 00:00:00 2001 From: TheGhost Date: Wed, 24 Sep 2025 21:19:10 +1200 Subject: [PATCH 15/49] Core/Misc: Fix static analysis issues (cherrypicked from 865a3a47eaa518cb9c7827e863d679697e38b03e) --- src/server/game/Handlers/MailHandler.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index d8752e036ac..d322ce442f9 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -627,12 +627,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextIt if (m->mailTemplateId) { MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId); - if (!mailTemplateEntry) - { - player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); - return; - } - + ASSERT(mailTemplateEntry); bodyItem->SetText(mailTemplateEntry->Body->Str[GetSessionDbcLocale()]); } else From 3ec5287eedbc4a89a5ebc3e615ca9c059a804a39 Mon Sep 17 00:00:00 2001 From: TheGhost Date: Sat, 25 Oct 2025 13:40:37 +1300 Subject: [PATCH 16/49] Core/Misc: remove travis config file. Is not needed for this project --- .travis.yml | 60 ----------------------------------------------------- 1 file changed, 60 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6661d651d9c..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,60 +0,0 @@ -sudo: false -dist: trusty - -language: cpp -compiler: - - clang - -git: - depth: 1 - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - - sourceline: 'ppa:kzemek/boost' - packages: - - g++-6 - - libboost1.58-dev - - libboost-filesystem1.58-dev - - libboost-iostreams1.58-dev - - libboost-program-options1.58-dev - - libboost-regex1.58-dev - - libboost-system1.58-dev - - libboost-thread1.58-dev - - libssl-dev - - libmysqlclient-dev - - libreadline6-dev - - zlib1g-dev - - libbz2-dev - -services: - - mysql - -before_install: - - git config user.email "travis@build.bot" && git config user.name "Travis CI" - - git tag -a -m "Travis build" init - -install: - - mysql -uroot -e 'create database test_mysql;' - - mkdir bin - - cd bin - - cmake ../ -DWITH_WARNINGS=0 -DWITH_COREDEBUG=0 -DUSE_COREPCH=1 -DUSE_SCRIPTPCH=1 -DTOOLS=1 -DSCRIPTS=dynamic -DSERVERS=1 -DNOJEM=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror" -DCMAKE_C_FLAGS_DEBUG="-DNDEBUG" -DCMAKE_CXX_FLAGS_DEBUG="-DNDEBUG" -DCMAKE_INSTALL_PREFIX=check_install -DWITH_CPR=1 - - cd .. - - chmod +x contrib/check_updates.sh - -script: - - $CXX --version - - mysql -uroot < sql/create/create_mysql.sql - - mysql -utrinity -ptrinity auth < sql/base/auth_database.sql - - mysql -utrinity -ptrinity characters < sql/base/characters_database.sql - - mysql -utrinity -ptrinity world < sql/base/dev/world_database.sql - - mysql -utrinity -ptrinity hotfixes < sql/base/dev/hotfixes_database.sql - - cat sql/updates/world/master/*.sql | mysql -utrinity -ptrinity world - - cat sql/updates/hotfixes/master/*.sql | mysql -utrinity -ptrinity hotfixes - - mysql -uroot < sql/create/drop_mysql.sql - - cd bin - - make -j 4 -k && make install - - cd check_install/bin - - ./bnetserver --version - - ./worldserver --version From 63f3fe6d78828cf029c4405421c3353edecc6aad Mon Sep 17 00:00:00 2001 From: TheGhost Date: Wed, 24 Sep 2025 21:25:36 +1200 Subject: [PATCH 17/49] Core/Scripts Update boss Skadi the Ruthless (#19114) (cherrypicked from 4536846d7d30508a046f394d1f561a2c3fdcf5f0) --- ...019_07_18_04_world_2017_02_12_00_world.sql | 54 ++++ .../UtgardePinnacle/boss_skadi.cpp | 296 +++++++++--------- 2 files changed, 198 insertions(+), 152 deletions(-) create mode 100644 sql/updates/world/master/2019_07_18_04_world_2017_02_12_00_world.sql diff --git a/sql/updates/world/master/2019_07_18_04_world_2017_02_12_00_world.sql b/sql/updates/world/master/2019_07_18_04_world_2017_02_12_00_world.sql new file mode 100644 index 00000000000..7a86fc91e34 --- /dev/null +++ b/sql/updates/world/master/2019_07_18_04_world_2017_02_12_00_world.sql @@ -0,0 +1,54 @@ +SET @PATH := 2689300; + +DELETE FROM `waypoint_data` WHERE `id` IN(@PATH, @PATH+1, @PATH+2); +DELETE FROM `script_spline_chain_meta` WHERE `entry`=26893; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(26893, 1, 0, 15064, 0), +(26893, 2, 0, 3397, 0), +(26893, 3, 0, 4472, 0), +(26893, 4, 0, 23930, 0), +(26893, 5, 0, 24026, 0); + +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=26893; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(26893, 1, 0, 0, 341.74110, -516.95450, 104.66950), -- INITIAL +(26893, 1, 0, 1, 310.21650, -510.53020, 120.54870), +(26893, 1, 0, 2, 300.86850, -520.32490, 133.36640), +(26893, 1, 0, 3, 298.34470, -529.48180, 137.28310), +(26893, 1, 0, 4, 309.09590, -540.31950, 134.97740), +(26893, 1, 0, 5, 323.64150, -547.97150, 130.31060), +(26893, 1, 0, 6, 357.07800, -549.15970, 116.31050), +(26893, 1, 0, 7, 401.25730, -550.27680, 114.92160), +(26893, 1, 0, 8, 464.50620, -555.94420, 114.44940), +(26893, 1, 0, 9, 496.19200, -556.96280, 114.86610), +(26893, 1, 0, 10, 523.20110, -548.99160, 114.86610), +(26893, 2, 0, 0, 520.48270, -541.56330, 119.84160), -- BREACH RIGHT +(26893, 2, 0, 1, 496.43400, -517.57800, 120.00000), +(26893, 3, 0, 0, 520.48270, -541.56330, 119.84160), -- BREACH LEFT +(26893, 3, 0, 1, 500.24300, -501.69300, 120.00000), +(26893, 4, 0, 0, 496.43400, -517.57800, 120.00000), -- RIGHT +(26893, 4, 0, 1, 453.12420, -517.17000, 120.02730), +(26893, 4, 0, 2, 388.33120, -514.37680, 121.11930), +(26893, 4, 0, 3, 340.27520, -512.09260, 122.31380), +(26893, 4, 0, 4, 313.07560, -509.13800, 125.17500), +(26893, 4, 0, 5, 296.69640, -522.67050, 133.70260), +(26893, 4, 0, 6, 301.29570, -549.45830, 137.42490), +(26893, 4, 0, 7, 335.07460, -552.12110, 119.84160), +(26893, 4, 0, 8, 397.62370, -553.92030, 119.84160), +(26893, 4, 0, 9, 459.63210, -558.00780, 119.84160), +(26893, 4, 0, 10, 505.54580, -568.78150, 119.84160), +(26893, 4, 0, 11, 518.09900, -560.84990, 119.84160), +(26893, 4, 0, 12, 520.48270, -541.56330, 119.84160), +(26893, 5, 0, 0, 500.24300, -501.69300, 120.00000), -- LEFT +(26893, 5, 0, 1, 451.98240, -509.25080, 120.02730), +(26893, 5, 0, 2, 399.26070, -510.07190, 121.11930), +(26893, 5, 0, 3, 350.60990, -508.39010, 122.31380), +(26893, 5, 0, 4, 325.82170, -506.77690, 125.17500), +(26893, 5, 0, 5, 301.29410, -516.67060, 133.70260), +(26893, 5, 0, 6, 301.29570, -549.45830, 137.42490), +(26893, 5, 0, 7, 335.07460, -552.12110, 119.84160), +(26893, 5, 0, 8, 397.62370, -553.92030, 119.84160), +(26893, 5, 0, 9, 459.63210, -558.00780, 119.84160), +(26893, 5, 0, 10, 505.54580, -568.78150, 119.84160), +(26893, 5, 0, 11, 518.09900, -560.84990, 119.84160), +(26893, 5, 0, 12, 520.48270, -541.56330, 119.84160); diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index 6faba89ae44..03a8aa6d8c5 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -39,12 +39,10 @@ enum Spells SPELL_SKADI_TELEPORT = 61790, SPELL_LAUNCH_HARPOON = 48642, SPELL_SUMMON_GAUNLET_MOBS_PERIODIC = 59275, - SPELL_FREEZING_CLOUD = 47579, SPELL_RIDE_GRAUF = 61791, + SPELL_FREEZING_CLOUD = 47579, SPELL_FREEZING_CLOUD_RIGHT_PERIODIC = 47592, SPELL_FREEZING_CLOUD_LEFT_PERIODIC = 47590, - SPELL_FREEZING_CLOUD_RIGHT = 47593, - SPELL_FREEZING_CLOUD_LEFT = 47563, SPELL_FREEZING_CLOUD_RIGHT_AREA = 47594, SPELL_FREEZING_CLOUD_LEFT_AREA = 47574, SPELL_SUMMON_YMIRJAR_WARRIOR_W = 48631, @@ -65,64 +63,66 @@ enum Spells SPELL_SUMMON_HARPOON = 56789, }; -enum Yells +enum Texts { - SAY_AGGRO = 0, - SAY_KILL = 1, - SAY_DEATH = 3, - SAY_DRAKE_DEATH = 5, - SAY_DRAKE_BREATH = 6 + SAY_AGGRO = 0, + SAY_KILL = 1, + SAY_DEATH = 3, + SAY_DRAKE_DEATH = 5, + SAY_DRAKE_BREATH = 6, + EMOTE_BREATH = 0, + EMOTE_ON_RANGE = 1 }; -enum Emotes +enum Points { - EMOTE_BREATH = 0, - EMOTE_ON_RANGE + POINT_0 = 0, + POINT_1 = 1, + POINT_2 = 2, + POINT_BREACH = 0, + POINT_LEFT = 1, + POINT_RIGHT = 2 }; -enum Data +enum SplineChainIds { - - DATA_LOVE_TO_SKADI = 0, - FIRST_WAVE_MAX_WARRIORS = 10, - FIRST_WAVE_SIZE = 13, - GRAUF_PATH_INITIAL = 2689300, - GRAUF_PATH_RIGHT = 2689301, - GRAUF_PATH_LEFT = 2689302, - ACHIEV_LODI_DODI_WE_LOVES_THE_SKADI = 17726, -}; - -enum Points -{ - POINT_0 = 0, - POINT_1 = 1, - POINT_9 = 9, - POINT_11 = 11, - POINT_LEFT = 21, - POINT_RIGHT = 22 + SPLINE_CHAIN_INITIAL = 1, + SPLINE_CHAIN_BREACH_RIGHT = 2, + SPLINE_CHAIN_BREACH_LEFT = 3, + SPLINE_CHAIN_RIGHT = 4, + SPLINE_CHAIN_LEFT = 5 }; enum Actions { - ACTION_START_ENCOUNTER = 0, - ACTION_FLAME, + ACTION_START_ENCOUNTER = 0, + ACTION_DRAKE_BREATH, ACTION_GAUNTLET_END, ACTION_HARPOON_HIT, }; enum CombatPhase { - PHASE_FLYING = 0, + PHASE_FLYING = 0, PHASE_GROUND }; -Position const BreachPoint = { 0.0f, 0.0f, 0.0f, 2.670354f }; +enum MiscData +{ + + DATA_LOVE_TO_SKADI = 0, + FIRST_WAVE_MAX_WARRIORS = 10, + FIRST_WAVE_SIZE = 13, + ACHIEV_LODI_DODI_WE_LOVES_THE_SKADI = 17726, +}; + +float const BreachPoint = 2.670354f; +float const BreathPointRight = 3.124139f; +float const BreathPointLeft = 3.228859f; Position const SecondaryWavesInitialPoint = { 478.7434f, -505.5758f, 104.7237f }; Position const SecondaryWavesFinalPoint = { 318.177f, -503.8898f, 104.5326f }; Position const SpawnLoc = { 477.5808f, -484.5591f, 104.8221f, 4.677482f }; Position const GraufLoc = { 341.7411f, -516.9545f, 104.6695f, 3.124139f }; -Position const BreathPointRight = { 496.434f, -517.578f, 120.0f, 3.124139f }; -Position const BreathPointLeft = { 500.243f, -501.693f, 120.0f, 3.228859f }; Position const FirstWaveLocations[FIRST_WAVE_SIZE] = { { 458.5323f, -516.2537f, 104.617f }, @@ -155,8 +155,8 @@ class boss_skadi : public CreatureScript void Initialize() { firstWaveSummoned = false; - harpoonHit = 0; - loveSkadi = 0; + _harpoonHit = 0; + _loveSkadi = 0; _phase = PHASE_GROUND; me->GetScheduler().SetValidator([this] { @@ -257,9 +257,9 @@ class boss_skadi : public CreatureScript if (Creature* combatTrigger = me->SummonCreature(NPC_COMBAT_TRIGGER, SpawnLoc)) combatTrigger->AI()->DoZoneInCombat(); break; - case ACTION_FLAME: - if (loveSkadi == 1) - loveSkadi++; + case ACTION_DRAKE_BREATH: + if (_loveSkadi == 1) + _loveSkadi++; Talk(SAY_DRAKE_BREATH); break; case ACTION_GAUNTLET_END: @@ -290,9 +290,9 @@ class boss_skadi : public CreatureScript }); break; case ACTION_HARPOON_HIT: - harpoonHit++; - if (harpoonHit == 1) - loveSkadi = 1; + _harpoonHit++; + if (_harpoonHit == 1) + _loveSkadi = 1; break; } } @@ -300,7 +300,7 @@ class boss_skadi : public CreatureScript uint32 GetData(uint32 id) const override { if (id == DATA_LOVE_TO_SKADI) - return loveSkadi; + return _loveSkadi; return 0; } @@ -318,8 +318,8 @@ class boss_skadi : public CreatureScript private: CombatPhase _phase; - uint8 harpoonHit; - uint8 loveSkadi; + uint8 _harpoonHit; + uint8 _loveSkadi; bool firstWaveSummoned; }; @@ -336,16 +336,13 @@ class npc_grauf : public CreatureScript struct npc_graufAI : public ScriptedAI { - npc_graufAI(Creature* creature) : ScriptedAI(creature) - { - _isFirstFly = true; - _instance = me->GetInstanceScript(); - } + npc_graufAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } void Reset() override { me->SetReactState(REACT_PASSIVE); me->setRegeneratingHealth(false); + me->SetSpeedRate(MOVE_RUN, 2.5f); } void JustDied(Unit* /*killer*/) override @@ -353,7 +350,7 @@ class npc_grauf : public CreatureScript if (Creature* skadi = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SKADI_THE_RUTHLESS))) skadi->AI()->DoAction(ACTION_GAUNTLET_END); - me->DespawnOrUnsummon(6000); + me->DespawnOrUnsummon(Seconds(6)); } void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override @@ -373,50 +370,45 @@ class npc_grauf : public CreatureScript _scheduler.Schedule(Seconds(2), [this](TaskContext /*context*/) { - me->GetMotionMaster()->MovePath(GRAUF_PATH_INITIAL, false); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BREACH, SPLINE_CHAIN_INITIAL, false); }); } void MovementInform(uint32 type, uint32 pointId) override { - if (type != POINT_MOTION_TYPE && type != WAYPOINT_MOTION_TYPE) + if (type != SPLINE_CHAIN_MOTION_TYPE) return; switch (pointId) { - case POINT_9: - if (!_isFirstFly) - break; - _isFirstFly = false; - // no break - case POINT_11: + case POINT_BREACH: _scheduler .Schedule(Milliseconds(1), [this](TaskContext /*context*/) { - me->SetFacingTo(BreachPoint.GetOrientation()); + me->SetFacingTo(BreachPoint); Talk(EMOTE_ON_RANGE); }) .Schedule(Seconds(10), [this](TaskContext /*context*/) { - if (RAND(POINT_LEFT,POINT_RIGHT) == POINT_LEFT) - me->GetMotionMaster()->MovePoint(POINT_LEFT, BreathPointLeft); + if (RAND(POINT_LEFT, POINT_RIGHT) == POINT_LEFT) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_LEFT, SPLINE_CHAIN_BREACH_LEFT, false); else - me->GetMotionMaster()->MovePoint(POINT_RIGHT, BreathPointRight); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_RIGHT, SPLINE_CHAIN_BREACH_RIGHT, false); }); break; case POINT_LEFT: _scheduler .Schedule(Milliseconds(1), [this](TaskContext /*context*/) { - me->SetFacingTo(BreathPointLeft.GetOrientation()); + me->SetFacingTo(BreathPointLeft); Talk(EMOTE_BREATH); }) .Schedule(Seconds(2), [this](TaskContext /*context*/) { - me->GetMotionMaster()->MovePath(GRAUF_PATH_LEFT, false); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BREACH, SPLINE_CHAIN_LEFT, false); DoCast(SPELL_FREEZING_CLOUD_LEFT_PERIODIC); - if (Creature* skadi = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SKADI_THE_RUTHLESS))) - skadi->AI()->DoAction(ACTION_FLAME); + if (Creature* skadi = _instance->GetCreature(DATA_SKADI_THE_RUTHLESS)) + skadi->AI()->DoAction(ACTION_DRAKE_BREATH); }) .Schedule(Seconds(10), [this](TaskContext /*context*/) { @@ -427,23 +419,23 @@ class npc_grauf : public CreatureScript _scheduler .Schedule(Milliseconds(1), [this](TaskContext /*context*/) { - me->SetFacingTo(BreathPointRight.GetOrientation()); + me->SetFacingTo(BreathPointRight); Talk(EMOTE_BREATH); }) .Schedule(Seconds(2), [this](TaskContext /*context*/) { - me->GetMotionMaster()->MovePath(GRAUF_PATH_RIGHT, false); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BREACH, SPLINE_CHAIN_RIGHT, false); DoCast(SPELL_FREEZING_CLOUD_RIGHT_PERIODIC); - if (Creature* skadi = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SKADI_THE_RUTHLESS))) - skadi->AI()->DoAction(ACTION_FLAME); + if (Creature* skadi = _instance->GetCreature(DATA_SKADI_THE_RUTHLESS)) + skadi->AI()->DoAction(ACTION_DRAKE_BREATH); }) .Schedule(Seconds(10), [this](TaskContext /*context*/) { me->RemoveAurasDueToSpell(SPELL_FREEZING_CLOUD_RIGHT_PERIODIC); }); break; - default: - break; + default: + break; } } @@ -462,7 +454,6 @@ class npc_grauf : public CreatureScript private: TaskScheduler _scheduler; InstanceScript* _instance; - bool _isFirstFly; }; CreatureAI* GetAI(Creature* creature) const override @@ -508,11 +499,11 @@ struct npc_skadi_trashAI : public ScriptedAI case POINT_1: _scheduler.Schedule(Seconds(1), [this](TaskContext /*context*/) { - me->GetMotionMaster()->MovePoint(POINT_9, SecondaryWavesFinalPoint); + me->GetMotionMaster()->MovePoint(POINT_2, SecondaryWavesFinalPoint); }); break; - case POINT_9: - DoZoneInCombat(me, 200); + case POINT_2: + DoZoneInCombat(); break; default: break; @@ -637,76 +628,76 @@ class npc_ymirjar_harpooner : public CreatureScript class spell_freezing_cloud_area_right : public SpellScriptLoader { -public: - spell_freezing_cloud_area_right() : SpellScriptLoader("spell_freezing_cloud_area_right") { } - - class spell_freezing_cloud_area_right_SpellScript : public SpellScript - { - PrepareSpellScript(spell_freezing_cloud_area_right_SpellScript); + public: + spell_freezing_cloud_area_right() : SpellScriptLoader("spell_freezing_cloud_area_right") { } - bool Validate(SpellInfo const* /*spell*/) override + class spell_freezing_cloud_area_right_SpellScript : public SpellScript { - return ValidateSpellInfo({ SPELL_FREEZING_CLOUD }); - } + PrepareSpellScript(spell_freezing_cloud_area_right_SpellScript); - void FilterTargets(std::list& targets) - { - targets.remove_if([](WorldObject* obj) { return obj->GetPositionY() > -511.0f; }); - } + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_FREEZING_CLOUD }); + } - void HandleScript(SpellEffIndex /*effIndex*/) - { - GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FREEZING_CLOUD, true); - } + void FilterTargets(std::list& targets) + { + targets.remove_if([](WorldObject* obj) { return obj->GetPositionY() > -511.0f; }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FREEZING_CLOUD, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_freezing_cloud_area_right_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_freezing_cloud_area_right_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; - void Register() override + SpellScript* GetSpellScript() const override { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_freezing_cloud_area_right_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - OnEffectHitTarget += SpellEffectFn(spell_freezing_cloud_area_right_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + return new spell_freezing_cloud_area_right_SpellScript(); } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_freezing_cloud_area_right_SpellScript(); - } }; class spell_freezing_cloud_area_left : public SpellScriptLoader { -public: - spell_freezing_cloud_area_left() : SpellScriptLoader("spell_freezing_cloud_area_left") { } - - class spell_freezing_cloud_area_left_SpellScript : public SpellScript - { - PrepareSpellScript(spell_freezing_cloud_area_left_SpellScript); + public: + spell_freezing_cloud_area_left() : SpellScriptLoader("spell_freezing_cloud_area_left") { } - bool Validate(SpellInfo const* /*spell*/) override + class spell_freezing_cloud_area_left_SpellScript : public SpellScript { - return ValidateSpellInfo({ SPELL_FREEZING_CLOUD }); - } + PrepareSpellScript(spell_freezing_cloud_area_left_SpellScript); - void FilterTargets(std::list& targets) - { - targets.remove_if([](WorldObject* obj) { return obj->GetPositionY() < -511.0f; }); - } + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_FREEZING_CLOUD }); + } - void HandleScript(SpellEffIndex /*effIndex*/) - { - GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FREEZING_CLOUD, true); - } + void FilterTargets(std::list& targets) + { + targets.remove_if([](WorldObject* obj) { return obj->GetPositionY() < -511.0f; }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FREEZING_CLOUD, true); + } - void Register() override + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_freezing_cloud_area_left_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_freezing_cloud_area_left_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_freezing_cloud_area_left_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - OnEffectHitTarget += SpellEffectFn(spell_freezing_cloud_area_left_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + return new spell_freezing_cloud_area_left_SpellScript(); } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_freezing_cloud_area_left_SpellScript(); - } }; class spell_freezing_cloud_damage : public SpellScriptLoader @@ -917,20 +908,20 @@ class spell_summon_gauntlet_mobs_periodic : public SpellScriptLoader class achievement_girl_love_to_skadi : public AchievementCriteriaScript { -public: - achievement_girl_love_to_skadi() : AchievementCriteriaScript("achievement_girl_love_to_skadi") { } + public: + achievement_girl_love_to_skadi() : AchievementCriteriaScript("achievement_girl_love_to_skadi") { } - bool OnCheck(Player* /*player*/, Unit* target) override - { - if (!target) - return false; + bool OnCheck(Player* /*player*/, Unit* target) override + { + if (!target) + return false; - if (Creature* skadi = target->ToCreature()) - if (skadi->AI()->GetData(DATA_LOVE_TO_SKADI) == 1) - return true; + if (Creature* skadi = target->ToCreature()) + if (skadi->AI()->GetData(DATA_LOVE_TO_SKADI) == 1) + return true; - return false; - } + return false; + } }; class at_skadi_gaunlet : public AreaTriggerScript @@ -940,18 +931,19 @@ class at_skadi_gaunlet : public AreaTriggerScript bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/, bool entered) override { + InstanceScript* instance = player->GetInstanceScript(); + if (!instance || player->IsGameMaster()) + return true; + if (!entered) return true; - if (InstanceScript* instance = player->GetInstanceScript()) - { - if (instance->GetBossState(DATA_SKADI_THE_RUTHLESS) == NOT_STARTED) - if (Creature* skadi = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SKADI_THE_RUTHLESS))) - { - skadi->AI()->DoAction(ACTION_START_ENCOUNTER); - return true; - } - } + if (instance->GetBossState(DATA_SKADI_THE_RUTHLESS) == NOT_STARTED) + if (Creature* skadi = instance->GetCreature(DATA_SKADI_THE_RUTHLESS)) + { + skadi->AI()->DoAction(ACTION_START_ENCOUNTER); + return true; + } return true; } From ab050e74fae0d74a8cf3e142e0ea381517360228 Mon Sep 17 00:00:00 2001 From: TheGhost Date: Sun, 26 Oct 2025 14:05:35 +1300 Subject: [PATCH 18/49] Core/Misc: Remove world chat to discord relay * Is not needed for this project as we will not support it --- cmake/options.cmake | 3 +- contrib/ServerRelay/.gitignore | 1 - contrib/ServerRelay/README.md | 82 - contrib/ServerRelay/config.json | 15 - contrib/ServerRelay/linux.sh | 1 - contrib/ServerRelay/package-lock.json | 2766 ------- contrib/ServerRelay/package.json | 23 - .../run-server-scripts/windows.bat | 2 - contrib/ServerRelay/server.js | 244 - contrib/ServerRelay/windows.vbs | 3 - dep/CMakeLists.txt | 4 - dep/cpr/.clang-format | 59 - dep/cpr/.gitignore | 45 - dep/cpr/.travis.yml | 125 - dep/cpr/AUTHORS | 32 - dep/cpr/CMakeLists.txt | 73 - dep/cpr/CONTRIBUTING.md | 27 - dep/cpr/LICENSE | 21 - dep/cpr/README.md | 96 - dep/cpr/VERSION | 1 - dep/cpr/appveyor.yml | 16 - dep/cpr/cpr-config.cmake | 26 - dep/cpr/cpr/CMakeLists.txt | 56 - dep/cpr/cpr/auth.cpp | 9 - dep/cpr/cpr/cookies.cpp | 30 - dep/cpr/cpr/cprtypes.cpp | 14 - dep/cpr/cpr/digest.cpp | 9 - dep/cpr/cpr/error.cpp | 62 - dep/cpr/cpr/multipart.cpp | 7 - dep/cpr/cpr/parameters.cpp | 30 - dep/cpr/cpr/payload.cpp | 20 - dep/cpr/cpr/proxies.cpp | 21 - dep/cpr/cpr/session.cpp | 477 -- dep/cpr/cpr/ssl_options.cpp | 11 - dep/cpr/cpr/timeout.cpp | 26 - dep/cpr/cpr/util.cpp | 81 - dep/cpr/format-check.sh | 37 - dep/cpr/include/cpr/api.h | 200 - dep/cpr/include/cpr/auth.h | 27 - dep/cpr/include/cpr/body.h | 35 - dep/cpr/include/cpr/cookies.h | 26 - dep/cpr/include/cpr/cpr.h | 10 - dep/cpr/include/cpr/cprtypes.h | 18 - dep/cpr/include/cpr/curlholder.h | 19 - dep/cpr/include/cpr/defines.h | 8 - dep/cpr/include/cpr/digest.h | 20 - dep/cpr/include/cpr/error.h | 53 - dep/cpr/include/cpr/low_speed.h | 18 - dep/cpr/include/cpr/max_redirects.h | 18 - dep/cpr/include/cpr/multipart.h | 75 - dep/cpr/include/cpr/parameters.h | 33 - dep/cpr/include/cpr/payload.h | 43 - dep/cpr/include/cpr/proxies.h | 25 - dep/cpr/include/cpr/response.h | 38 - dep/cpr/include/cpr/session.h | 87 - dep/cpr/include/cpr/ssl_options.h | 19 - dep/cpr/include/cpr/timeout.h | 21 - dep/cpr/include/cpr/util.h | 20 - dep/cpr/opt/CMakeLists.txt | 118 - dep/cpr/opt/curl/.dir-locals.el | 10 - dep/cpr/opt/curl/.gitattributes | 7 - dep/cpr/opt/curl/.github/CONTRIBUTING.md | 23 - dep/cpr/opt/curl/.github/ISSUE_TEMPLATE | 16 - dep/cpr/opt/curl/.github/stale.yml | 17 - dep/cpr/opt/curl/.gitignore | 58 - dep/cpr/opt/curl/CHANGES | 7 - .../opt/curl/CMake/CMakeConfigurableFile.in | 2 - dep/cpr/opt/curl/CMake/CurlSymbolHiding.cmake | 61 - dep/cpr/opt/curl/CMake/CurlTests.c | 551 -- dep/cpr/opt/curl/CMake/FindCARES.cmake | 42 - dep/cpr/opt/curl/CMake/FindGSS.cmake | 289 - dep/cpr/opt/curl/CMake/FindLibSSH2.cmake | 35 - dep/cpr/opt/curl/CMake/FindMbedTLS.cmake | 13 - dep/cpr/opt/curl/CMake/FindNGHTTP2.cmake | 18 - dep/cpr/opt/curl/CMake/Macros.cmake | 124 - dep/cpr/opt/curl/CMake/OtherTests.cmake | 232 - .../curl/CMake/Platforms/WindowsCache.cmake | 125 - dep/cpr/opt/curl/CMake/Utilities.cmake | 44 - .../opt/curl/CMake/cmake_uninstall.cmake.in | 26 - dep/cpr/opt/curl/CMakeLists.txt | 1295 --- dep/cpr/opt/curl/COPYING | 22 - dep/cpr/opt/curl/GIT-INFO | 44 - dep/cpr/opt/curl/README | 49 - dep/cpr/opt/curl/README.md | 50 - dep/cpr/opt/curl/RELEASE-NOTES | 201 - dep/cpr/opt/curl/buildconf | 448 - dep/cpr/opt/curl/buildconf.bat | 317 - dep/cpr/opt/curl/curl-config.in | 178 - dep/cpr/opt/curl/include/Makefile.am | 5 - dep/cpr/opt/curl/include/README | 33 - dep/cpr/opt/curl/include/curl/.gitignore | 3 - dep/cpr/opt/curl/include/curl/Makefile.am | 34 - dep/cpr/opt/curl/include/curl/curl.h | 2740 ------- dep/cpr/opt/curl/include/curl/curlver.h | 77 - dep/cpr/opt/curl/include/curl/easy.h | 102 - dep/cpr/opt/curl/include/curl/mprintf.h | 50 - dep/cpr/opt/curl/include/curl/multi.h | 439 - dep/cpr/opt/curl/include/curl/stdcheaders.h | 33 - dep/cpr/opt/curl/include/curl/system.h | 471 -- dep/cpr/opt/curl/include/curl/typecheck-gcc.h | 683 -- dep/cpr/opt/curl/lib/.gitattributes | 1 - dep/cpr/opt/curl/lib/.gitignore | 12 - dep/cpr/opt/curl/lib/CMakeLists.txt | 114 - dep/cpr/opt/curl/lib/Makefile.Watcom | 275 - dep/cpr/opt/curl/lib/Makefile.am | 141 - dep/cpr/opt/curl/lib/Makefile.b32 | 185 - dep/cpr/opt/curl/lib/Makefile.inc | 81 - dep/cpr/opt/curl/lib/Makefile.m32 | 355 - dep/cpr/opt/curl/lib/Makefile.netware | 761 -- dep/cpr/opt/curl/lib/Makefile.vxworks | 177 - dep/cpr/opt/curl/lib/amigaos.c | 77 - dep/cpr/opt/curl/lib/amigaos.h | 39 - dep/cpr/opt/curl/lib/arpa_telnet.h | 104 - dep/cpr/opt/curl/lib/asyn-ares.c | 700 -- dep/cpr/opt/curl/lib/asyn-thread.c | 718 -- dep/cpr/opt/curl/lib/asyn.h | 168 - dep/cpr/opt/curl/lib/base64.c | 320 - dep/cpr/opt/curl/lib/checksrc.pl | 605 -- dep/cpr/opt/curl/lib/config-amigaos.h | 166 - dep/cpr/opt/curl/lib/config-dos.h | 185 - dep/cpr/opt/curl/lib/config-mac.h | 125 - dep/cpr/opt/curl/lib/config-os400.h | 563 -- dep/cpr/opt/curl/lib/config-riscos.h | 513 -- dep/cpr/opt/curl/lib/config-symbian.h | 811 -- dep/cpr/opt/curl/lib/config-tpf.h | 775 -- dep/cpr/opt/curl/lib/config-vxworks.h | 928 --- dep/cpr/opt/curl/lib/config-win32.h | 742 -- dep/cpr/opt/curl/lib/config-win32ce.h | 451 -- dep/cpr/opt/curl/lib/conncache.c | 360 - dep/cpr/opt/curl/lib/conncache.h | 68 - dep/cpr/opt/curl/lib/connect.c | 1410 ---- dep/cpr/opt/curl/lib/connect.h | 147 - dep/cpr/opt/curl/lib/content_encoding.c | 431 - dep/cpr/opt/curl/lib/content_encoding.h | 48 - dep/cpr/opt/curl/lib/cookie.c | 1479 ---- dep/cpr/opt/curl/lib/cookie.h | 107 - dep/cpr/opt/curl/lib/curl_addrinfo.c | 616 -- dep/cpr/opt/curl/lib/curl_addrinfo.h | 110 - dep/cpr/opt/curl/lib/curl_base64.h | 35 - dep/cpr/opt/curl/lib/curl_config.h.cmake | 1002 --- dep/cpr/opt/curl/lib/curl_des.c | 63 - dep/cpr/opt/curl/lib/curl_des.h | 34 - dep/cpr/opt/curl/lib/curl_endian.c | 124 - dep/cpr/opt/curl/lib/curl_endian.h | 46 - dep/cpr/opt/curl/lib/curl_fnmatch.c | 424 - dep/cpr/opt/curl/lib/curl_fnmatch.h | 44 - dep/cpr/opt/curl/lib/curl_gethostname.c | 100 - dep/cpr/opt/curl/lib/curl_gethostname.h | 31 - dep/cpr/opt/curl/lib/curl_gssapi.c | 131 - dep/cpr/opt/curl/lib/curl_gssapi.h | 75 - dep/cpr/opt/curl/lib/curl_hmac.h | 67 - dep/cpr/opt/curl/lib/curl_ldap.h | 35 - dep/cpr/opt/curl/lib/curl_md4.h | 35 - dep/cpr/opt/curl/lib/curl_md5.h | 63 - dep/cpr/opt/curl/lib/curl_memory.h | 156 - dep/cpr/opt/curl/lib/curl_memrchr.c | 61 - dep/cpr/opt/curl/lib/curl_memrchr.h | 44 - dep/cpr/opt/curl/lib/curl_multibyte.c | 84 - dep/cpr/opt/curl/lib/curl_multibyte.h | 92 - dep/cpr/opt/curl/lib/curl_ntlm_core.c | 818 -- dep/cpr/opt/curl/lib/curl_ntlm_core.h | 107 - dep/cpr/opt/curl/lib/curl_ntlm_wb.c | 425 - dep/cpr/opt/curl/lib/curl_ntlm_wb.h | 38 - dep/cpr/opt/curl/lib/curl_printf.h | 56 - dep/cpr/opt/curl/lib/curl_rtmp.c | 313 - dep/cpr/opt/curl/lib/curl_rtmp.h | 33 - dep/cpr/opt/curl/lib/curl_sasl.c | 628 -- dep/cpr/opt/curl/lib/curl_sasl.h | 143 - dep/cpr/opt/curl/lib/curl_sec.h | 51 - dep/cpr/opt/curl/lib/curl_setup.h | 762 -- dep/cpr/opt/curl/lib/curl_setup_once.h | 537 -- dep/cpr/opt/curl/lib/curl_sspi.c | 235 - dep/cpr/opt/curl/lib/curl_sspi.h | 350 - dep/cpr/opt/curl/lib/curl_threads.c | 146 - dep/cpr/opt/curl/lib/curl_threads.h | 63 - dep/cpr/opt/curl/lib/curlx.h | 115 - dep/cpr/opt/curl/lib/dict.c | 279 - dep/cpr/opt/curl/lib/dict.h | 29 - dep/cpr/opt/curl/lib/dotdot.c | 180 - dep/cpr/opt/curl/lib/dotdot.h | 25 - dep/cpr/opt/curl/lib/easy.c | 1141 --- dep/cpr/opt/curl/lib/easyif.h | 33 - dep/cpr/opt/curl/lib/escape.c | 242 - dep/cpr/opt/curl/lib/escape.h | 33 - dep/cpr/opt/curl/lib/file.c | 600 -- dep/cpr/opt/curl/lib/file.h | 41 - dep/cpr/opt/curl/lib/fileinfo.c | 46 - dep/cpr/opt/curl/lib/fileinfo.h | 37 - dep/cpr/opt/curl/lib/firefox-db2pem.sh | 54 - dep/cpr/opt/curl/lib/formdata.c | 1000 --- dep/cpr/opt/curl/lib/formdata.h | 51 - dep/cpr/opt/curl/lib/ftp.c | 4481 ---------- dep/cpr/opt/curl/lib/ftp.h | 161 - dep/cpr/opt/curl/lib/ftplistparser.c | 1016 --- dep/cpr/opt/curl/lib/ftplistparser.h | 41 - dep/cpr/opt/curl/lib/getenv.c | 54 - dep/cpr/opt/curl/lib/getinfo.c | 461 -- dep/cpr/opt/curl/lib/getinfo.h | 27 - dep/cpr/opt/curl/lib/gopher.c | 167 - dep/cpr/opt/curl/lib/gopher.h | 29 - dep/cpr/opt/curl/lib/hash.c | 354 - dep/cpr/opt/curl/lib/hash.h | 100 - dep/cpr/opt/curl/lib/hmac.c | 132 - dep/cpr/opt/curl/lib/hostasyn.c | 153 - dep/cpr/opt/curl/lib/hostcheck.c | 150 - dep/cpr/opt/curl/lib/hostcheck.h | 32 - dep/cpr/opt/curl/lib/hostip.c | 884 -- dep/cpr/opt/curl/lib/hostip.h | 250 - dep/cpr/opt/curl/lib/hostip4.c | 307 - dep/cpr/opt/curl/lib/hostip6.c | 234 - dep/cpr/opt/curl/lib/hostsyn.c | 107 - dep/cpr/opt/curl/lib/http.c | 3820 --------- dep/cpr/opt/curl/lib/http.h | 261 - dep/cpr/opt/curl/lib/http2.c | 2287 ------ dep/cpr/opt/curl/lib/http2.h | 80 - dep/cpr/opt/curl/lib/http_chunks.c | 379 - dep/cpr/opt/curl/lib/http_chunks.h | 91 - dep/cpr/opt/curl/lib/http_digest.c | 180 - dep/cpr/opt/curl/lib/http_digest.h | 42 - dep/cpr/opt/curl/lib/http_negotiate.c | 138 - dep/cpr/opt/curl/lib/http_negotiate.h | 38 - dep/cpr/opt/curl/lib/http_ntlm.c | 241 - dep/cpr/opt/curl/lib/http_ntlm.h | 40 - dep/cpr/opt/curl/lib/http_proxy.c | 686 -- dep/cpr/opt/curl/lib/http_proxy.h | 51 - dep/cpr/opt/curl/lib/idn_win32.c | 111 - dep/cpr/opt/curl/lib/if2ip.c | 274 - dep/cpr/opt/curl/lib/if2ip.h | 84 - dep/cpr/opt/curl/lib/imap.c | 2093 ----- dep/cpr/opt/curl/lib/imap.h | 97 - dep/cpr/opt/curl/lib/inet_ntop.c | 197 - dep/cpr/opt/curl/lib/inet_ntop.h | 38 - dep/cpr/opt/curl/lib/inet_pton.c | 236 - dep/cpr/opt/curl/lib/inet_pton.h | 40 - dep/cpr/opt/curl/lib/krb5.c | 342 - dep/cpr/opt/curl/lib/ldap.c | 1085 --- dep/cpr/opt/curl/lib/libcurl.plist | 35 - dep/cpr/opt/curl/lib/libcurl.rc | 63 - dep/cpr/opt/curl/lib/libcurl.vers.in | 13 - dep/cpr/opt/curl/lib/llist.c | 193 - dep/cpr/opt/curl/lib/llist.h | 54 - dep/cpr/opt/curl/lib/makefile.amiga | 21 - dep/cpr/opt/curl/lib/makefile.dj | 72 - dep/cpr/opt/curl/lib/md4.c | 307 - dep/cpr/opt/curl/lib/md5.c | 563 -- dep/cpr/opt/curl/lib/memdebug.c | 485 -- dep/cpr/opt/curl/lib/memdebug.h | 173 - dep/cpr/opt/curl/lib/mime.c | 1860 ----- dep/cpr/opt/curl/lib/mime.h | 135 - dep/cpr/opt/curl/lib/mk-ca-bundle.pl | 554 -- dep/cpr/opt/curl/lib/mk-ca-bundle.vbs | 431 - dep/cpr/opt/curl/lib/mprintf.c | 1173 --- dep/cpr/opt/curl/lib/multi.c | 3142 ------- dep/cpr/opt/curl/lib/multihandle.h | 155 - dep/cpr/opt/curl/lib/multiif.h | 99 - dep/cpr/opt/curl/lib/netrc.c | 205 - dep/cpr/opt/curl/lib/netrc.h | 36 - dep/cpr/opt/curl/lib/non-ascii.c | 322 - dep/cpr/opt/curl/lib/non-ascii.h | 61 - dep/cpr/opt/curl/lib/nonblock.c | 90 - dep/cpr/opt/curl/lib/nonblock.h | 31 - dep/cpr/opt/curl/lib/nwlib.c | 327 - dep/cpr/opt/curl/lib/nwos.c | 88 - dep/cpr/opt/curl/lib/objnames-test08.sh | 217 - dep/cpr/opt/curl/lib/objnames-test10.sh | 217 - dep/cpr/opt/curl/lib/objnames.inc | 107 - dep/cpr/opt/curl/lib/openldap.c | 713 -- dep/cpr/opt/curl/lib/parsedate.c | 585 -- dep/cpr/opt/curl/lib/parsedate.h | 31 - dep/cpr/opt/curl/lib/pingpong.c | 513 -- dep/cpr/opt/curl/lib/pingpong.h | 150 - dep/cpr/opt/curl/lib/pipeline.c | 403 - dep/cpr/opt/curl/lib/pipeline.h | 56 - dep/cpr/opt/curl/lib/pop3.c | 1537 ---- dep/cpr/opt/curl/lib/pop3.h | 95 - dep/cpr/opt/curl/lib/progress.c | 577 -- dep/cpr/opt/curl/lib/progress.h | 77 - dep/cpr/opt/curl/lib/rand.c | 179 - dep/cpr/opt/curl/lib/rand.h | 47 - dep/cpr/opt/curl/lib/rtsp.c | 850 -- dep/cpr/opt/curl/lib/rtsp.h | 67 - dep/cpr/opt/curl/lib/security.c | 588 -- dep/cpr/opt/curl/lib/select.c | 583 -- dep/cpr/opt/curl/lib/select.h | 116 - dep/cpr/opt/curl/lib/sendf.c | 855 -- dep/cpr/opt/curl/lib/sendf.h | 94 - dep/cpr/opt/curl/lib/setup-os400.h | 223 - dep/cpr/opt/curl/lib/setup-vms.h | 443 - dep/cpr/opt/curl/lib/share.c | 244 - dep/cpr/opt/curl/lib/share.h | 61 - dep/cpr/opt/curl/lib/sigpipe.h | 78 - dep/cpr/opt/curl/lib/slist.c | 145 - dep/cpr/opt/curl/lib/slist.h | 40 - dep/cpr/opt/curl/lib/smb.c | 1005 --- dep/cpr/opt/curl/lib/smb.h | 271 - dep/cpr/opt/curl/lib/smtp.c | 1633 ---- dep/cpr/opt/curl/lib/smtp.h | 91 - dep/cpr/opt/curl/lib/sockaddr.h | 43 - dep/cpr/opt/curl/lib/socks.c | 792 -- dep/cpr/opt/curl/lib/socks.h | 76 - dep/cpr/opt/curl/lib/socks_gssapi.c | 527 -- dep/cpr/opt/curl/lib/socks_sspi.c | 605 -- dep/cpr/opt/curl/lib/speedcheck.c | 73 - dep/cpr/opt/curl/lib/speedcheck.h | 33 - dep/cpr/opt/curl/lib/splay.c | 278 - dep/cpr/opt/curl/lib/splay.h | 68 - dep/cpr/opt/curl/lib/ssh.c | 3463 -------- dep/cpr/opt/curl/lib/ssh.h | 198 - dep/cpr/opt/curl/lib/strcase.c | 177 - dep/cpr/opt/curl/lib/strcase.h | 51 - dep/cpr/opt/curl/lib/strdup.c | 100 - dep/cpr/opt/curl/lib/strdup.h | 32 - dep/cpr/opt/curl/lib/strerror.c | 1103 --- dep/cpr/opt/curl/lib/strerror.h | 37 - dep/cpr/opt/curl/lib/strtok.c | 66 - dep/cpr/opt/curl/lib/strtok.h | 34 - dep/cpr/opt/curl/lib/strtoofft.c | 241 - dep/cpr/opt/curl/lib/strtoofft.h | 60 - dep/cpr/opt/curl/lib/system_win32.c | 329 - dep/cpr/opt/curl/lib/system_win32.h | 61 - dep/cpr/opt/curl/lib/telnet.c | 1700 ---- dep/cpr/opt/curl/lib/telnet.h | 29 - dep/cpr/opt/curl/lib/tftp.c | 1403 ---- dep/cpr/opt/curl/lib/tftp.h | 29 - dep/cpr/opt/curl/lib/timeval.c | 162 - dep/cpr/opt/curl/lib/timeval.h | 61 - dep/cpr/opt/curl/lib/transfer.c | 2070 ----- dep/cpr/opt/curl/lib/transfer.h | 71 - dep/cpr/opt/curl/lib/url.c | 7209 ----------------- dep/cpr/opt/curl/lib/url.h | 93 - dep/cpr/opt/curl/lib/urldata.h | 1785 ---- dep/cpr/opt/curl/lib/vauth/cleartext.c | 165 - dep/cpr/opt/curl/lib/vauth/cram.c | 138 - dep/cpr/opt/curl/lib/vauth/digest.c | 893 -- dep/cpr/opt/curl/lib/vauth/digest.h | 43 - dep/cpr/opt/curl/lib/vauth/digest_sspi.c | 669 -- dep/cpr/opt/curl/lib/vauth/krb5_gssapi.c | 401 - dep/cpr/opt/curl/lib/vauth/krb5_sspi.c | 518 -- dep/cpr/opt/curl/lib/vauth/ntlm.c | 860 -- dep/cpr/opt/curl/lib/vauth/ntlm.h | 143 - dep/cpr/opt/curl/lib/vauth/ntlm_sspi.c | 338 - dep/cpr/opt/curl/lib/vauth/oauth2.c | 86 - dep/cpr/opt/curl/lib/vauth/spnego_gssapi.c | 278 - dep/cpr/opt/curl/lib/vauth/spnego_sspi.c | 324 - dep/cpr/opt/curl/lib/vauth/vauth.c | 147 - dep/cpr/opt/curl/lib/vauth/vauth.h | 205 - dep/cpr/opt/curl/lib/version.c | 403 - dep/cpr/opt/curl/lib/vtls/axtls.c | 742 -- dep/cpr/opt/curl/lib/vtls/axtls.h | 34 - dep/cpr/opt/curl/lib/vtls/cyassl.c | 1017 --- dep/cpr/opt/curl/lib/vtls/cyassl.h | 31 - dep/cpr/opt/curl/lib/vtls/darwinssl.c | 2950 ------- dep/cpr/opt/curl/lib/vtls/darwinssl.h | 32 - dep/cpr/opt/curl/lib/vtls/gskit.c | 1390 ---- dep/cpr/opt/curl/lib/vtls/gskit.h | 38 - dep/cpr/opt/curl/lib/vtls/gtls.c | 1841 ----- dep/cpr/opt/curl/lib/vtls/gtls.h | 34 - dep/cpr/opt/curl/lib/vtls/mbedtls.c | 1075 --- dep/cpr/opt/curl/lib/vtls/mbedtls.h | 32 - dep/cpr/opt/curl/lib/vtls/nss.c | 2380 ------ dep/cpr/opt/curl/lib/vtls/nssg.h | 39 - dep/cpr/opt/curl/lib/vtls/openssl.c | 3654 --------- dep/cpr/opt/curl/lib/vtls/openssl.h | 37 - dep/cpr/opt/curl/lib/vtls/polarssl.c | 937 --- dep/cpr/opt/curl/lib/vtls/polarssl.h | 32 - .../opt/curl/lib/vtls/polarssl_threadlock.c | 153 - .../opt/curl/lib/vtls/polarssl_threadlock.h | 53 - dep/cpr/opt/curl/lib/vtls/schannel.c | 1852 ----- dep/cpr/opt/curl/lib/vtls/schannel.h | 34 - dep/cpr/opt/curl/lib/vtls/vtls.c | 1312 --- dep/cpr/opt/curl/lib/vtls/vtls.h | 274 - dep/cpr/opt/curl/lib/warnless.c | 546 -- dep/cpr/opt/curl/lib/warnless.h | 113 - dep/cpr/opt/curl/lib/wildcard.c | 63 - dep/cpr/opt/curl/lib/wildcard.h | 61 - dep/cpr/opt/curl/lib/x509asn1.c | 1200 --- dep/cpr/opt/curl/lib/x509asn1.h | 134 - dep/cpr/opt/curl/libcurl.pc.in | 39 - dep/cpr/opt/curl/src/.gitignore | 10 - dep/cpr/opt/curl/src/CMakeLists.txt | 79 - dep/cpr/opt/curl/src/Makefile.Watcom | 234 - dep/cpr/opt/curl/src/Makefile.am | 142 - dep/cpr/opt/curl/src/Makefile.b32 | 154 - dep/cpr/opt/curl/src/Makefile.inc | 109 - dep/cpr/opt/curl/src/Makefile.m32 | 377 - dep/cpr/opt/curl/src/Makefile.netware | 524 -- dep/cpr/opt/curl/src/curl.rc | 63 - dep/cpr/opt/curl/src/macos/MACINSTALL.TXT | 1 - .../opt/curl/src/macos/curl.mcp.xml.sit.hqx | 1 - .../curl/src/macos/src/curl_GUSIConfig.cpp | 1 - dep/cpr/opt/curl/src/macos/src/macos_main.cpp | 1 - dep/cpr/opt/curl/src/makefile.amiga | 30 - dep/cpr/opt/curl/src/makefile.dj | 94 - dep/cpr/opt/curl/src/mkhelp.pl | 258 - dep/cpr/opt/curl/src/slist_wc.c | 72 - dep/cpr/opt/curl/src/slist_wc.h | 56 - dep/cpr/opt/curl/src/tool_binmode.c | 52 - dep/cpr/opt/curl/src/tool_binmode.h | 37 - dep/cpr/opt/curl/src/tool_bname.c | 50 - dep/cpr/opt/curl/src/tool_bname.h | 35 - dep/cpr/opt/curl/src/tool_cb_dbg.c | 282 - dep/cpr/opt/curl/src/tool_cb_dbg.h | 35 - dep/cpr/opt/curl/src/tool_cb_hdr.c | 239 - dep/cpr/opt/curl/src/tool_cb_hdr.h | 54 - dep/cpr/opt/curl/src/tool_cb_prg.c | 150 - dep/cpr/opt/curl/src/tool_cb_prg.h | 50 - dep/cpr/opt/curl/src/tool_cb_rea.c | 55 - dep/cpr/opt/curl/src/tool_cb_rea.h | 33 - dep/cpr/opt/curl/src/tool_cb_see.c | 131 - dep/cpr/opt/curl/src/tool_cb_see.h | 46 - dep/cpr/opt/curl/src/tool_cb_wrt.c | 177 - dep/cpr/opt/curl/src/tool_cb_wrt.h | 36 - dep/cpr/opt/curl/src/tool_cfgable.c | 174 - dep/cpr/opt/curl/src/tool_cfgable.h | 282 - dep/cpr/opt/curl/src/tool_convert.c | 150 - dep/cpr/opt/curl/src/tool_convert.h | 45 - dep/cpr/opt/curl/src/tool_dirhie.c | 158 - dep/cpr/opt/curl/src/tool_dirhie.h | 29 - dep/cpr/opt/curl/src/tool_doswin.c | 668 -- dep/cpr/opt/curl/src/tool_doswin.h | 68 - dep/cpr/opt/curl/src/tool_easysrc.c | 236 - dep/cpr/opt/curl/src/tool_easysrc.h | 49 - dep/cpr/opt/curl/src/tool_formparse.c | 749 -- dep/cpr/opt/curl/src/tool_formparse.h | 33 - dep/cpr/opt/curl/src/tool_getparam.c | 2164 ----- dep/cpr/opt/curl/src/tool_getparam.h | 65 - dep/cpr/opt/curl/src/tool_getpass.c | 254 - dep/cpr/opt/curl/src/tool_getpass.h | 36 - dep/cpr/opt/curl/src/tool_help.c | 576 -- dep/cpr/opt/curl/src/tool_help.h | 31 - dep/cpr/opt/curl/src/tool_helpers.c | 120 - dep/cpr/opt/curl/src/tool_helpers.h | 35 - dep/cpr/opt/curl/src/tool_homedir.c | 95 - dep/cpr/opt/curl/src/tool_homedir.h | 28 - dep/cpr/opt/curl/src/tool_hugehelp.c.cvs | 29 - dep/cpr/opt/curl/src/tool_hugehelp.h | 28 - dep/cpr/opt/curl/src/tool_libinfo.c | 102 - dep/cpr/opt/curl/src/tool_libinfo.h | 34 - dep/cpr/opt/curl/src/tool_main.c | 284 - dep/cpr/opt/curl/src/tool_main.h | 44 - dep/cpr/opt/curl/src/tool_metalink.c | 981 --- dep/cpr/opt/curl/src/tool_metalink.h | 167 - dep/cpr/opt/curl/src/tool_msgs.c | 121 - dep/cpr/opt/curl/src/tool_msgs.h | 32 - dep/cpr/opt/curl/src/tool_operate.c | 2090 ----- dep/cpr/opt/curl/src/tool_operate.h | 29 - dep/cpr/opt/curl/src/tool_operhlp.c | 190 - dep/cpr/opt/curl/src/tool_operhlp.h | 39 - dep/cpr/opt/curl/src/tool_panykey.c | 48 - dep/cpr/opt/curl/src/tool_panykey.h | 37 - dep/cpr/opt/curl/src/tool_paramhlp.c | 610 -- dep/cpr/opt/curl/src/tool_paramhlp.h | 56 - dep/cpr/opt/curl/src/tool_parsecfg.c | 361 - dep/cpr/opt/curl/src/tool_parsecfg.h | 29 - dep/cpr/opt/curl/src/tool_sdecls.h | 151 - dep/cpr/opt/curl/src/tool_setopt.c | 704 -- dep/cpr/opt/curl/src/tool_setopt.h | 153 - dep/cpr/opt/curl/src/tool_setup.h | 74 - dep/cpr/opt/curl/src/tool_sleep.c | 58 - dep/cpr/opt/curl/src/tool_sleep.h | 29 - dep/cpr/opt/curl/src/tool_strdup.c | 47 - dep/cpr/opt/curl/src/tool_strdup.h | 30 - dep/cpr/opt/curl/src/tool_urlglob.c | 711 -- dep/cpr/opt/curl/src/tool_urlglob.h | 77 - dep/cpr/opt/curl/src/tool_util.c | 126 - dep/cpr/opt/curl/src/tool_util.h | 37 - dep/cpr/opt/curl/src/tool_version.h | 34 - dep/cpr/opt/curl/src/tool_vms.c | 219 - dep/cpr/opt/curl/src/tool_vms.h | 47 - dep/cpr/opt/curl/src/tool_writeout.c | 369 - dep/cpr/opt/curl/src/tool_writeout.h | 28 - dep/cpr/opt/curl/src/tool_xattr.c | 90 - dep/cpr/opt/curl/src/tool_xattr.h | 28 - src/common/Common.cpp | 2 - src/server/game/Chat/Channels/Channel.cpp | 18 - src/server/game/Chat/Channels/Channel.h | 3 - src/server/scripts/World/chat_log.cpp | 17 - 477 files changed, 1 insertion(+), 155209 deletions(-) delete mode 100644 contrib/ServerRelay/.gitignore delete mode 100644 contrib/ServerRelay/README.md delete mode 100644 contrib/ServerRelay/config.json delete mode 100644 contrib/ServerRelay/linux.sh delete mode 100644 contrib/ServerRelay/package-lock.json delete mode 100644 contrib/ServerRelay/package.json delete mode 100644 contrib/ServerRelay/run-server-scripts/windows.bat delete mode 100644 contrib/ServerRelay/server.js delete mode 100644 contrib/ServerRelay/windows.vbs delete mode 100644 dep/cpr/.clang-format delete mode 100644 dep/cpr/.gitignore delete mode 100644 dep/cpr/.travis.yml delete mode 100644 dep/cpr/AUTHORS delete mode 100644 dep/cpr/CMakeLists.txt delete mode 100644 dep/cpr/CONTRIBUTING.md delete mode 100644 dep/cpr/LICENSE delete mode 100644 dep/cpr/README.md delete mode 100644 dep/cpr/VERSION delete mode 100644 dep/cpr/appveyor.yml delete mode 100644 dep/cpr/cpr-config.cmake delete mode 100644 dep/cpr/cpr/CMakeLists.txt delete mode 100644 dep/cpr/cpr/auth.cpp delete mode 100644 dep/cpr/cpr/cookies.cpp delete mode 100644 dep/cpr/cpr/cprtypes.cpp delete mode 100644 dep/cpr/cpr/digest.cpp delete mode 100644 dep/cpr/cpr/error.cpp delete mode 100644 dep/cpr/cpr/multipart.cpp delete mode 100644 dep/cpr/cpr/parameters.cpp delete mode 100644 dep/cpr/cpr/payload.cpp delete mode 100644 dep/cpr/cpr/proxies.cpp delete mode 100644 dep/cpr/cpr/session.cpp delete mode 100644 dep/cpr/cpr/ssl_options.cpp delete mode 100644 dep/cpr/cpr/timeout.cpp delete mode 100644 dep/cpr/cpr/util.cpp delete mode 100644 dep/cpr/format-check.sh delete mode 100644 dep/cpr/include/cpr/api.h delete mode 100644 dep/cpr/include/cpr/auth.h delete mode 100644 dep/cpr/include/cpr/body.h delete mode 100644 dep/cpr/include/cpr/cookies.h delete mode 100644 dep/cpr/include/cpr/cpr.h delete mode 100644 dep/cpr/include/cpr/cprtypes.h delete mode 100644 dep/cpr/include/cpr/curlholder.h delete mode 100644 dep/cpr/include/cpr/defines.h delete mode 100644 dep/cpr/include/cpr/digest.h delete mode 100644 dep/cpr/include/cpr/error.h delete mode 100644 dep/cpr/include/cpr/low_speed.h delete mode 100644 dep/cpr/include/cpr/max_redirects.h delete mode 100644 dep/cpr/include/cpr/multipart.h delete mode 100644 dep/cpr/include/cpr/parameters.h delete mode 100644 dep/cpr/include/cpr/payload.h delete mode 100644 dep/cpr/include/cpr/proxies.h delete mode 100644 dep/cpr/include/cpr/response.h delete mode 100644 dep/cpr/include/cpr/session.h delete mode 100644 dep/cpr/include/cpr/ssl_options.h delete mode 100644 dep/cpr/include/cpr/timeout.h delete mode 100644 dep/cpr/include/cpr/util.h delete mode 100644 dep/cpr/opt/CMakeLists.txt delete mode 100644 dep/cpr/opt/curl/.dir-locals.el delete mode 100644 dep/cpr/opt/curl/.gitattributes delete mode 100644 dep/cpr/opt/curl/.github/CONTRIBUTING.md delete mode 100644 dep/cpr/opt/curl/.github/ISSUE_TEMPLATE delete mode 100644 dep/cpr/opt/curl/.github/stale.yml delete mode 100644 dep/cpr/opt/curl/.gitignore delete mode 100644 dep/cpr/opt/curl/CHANGES delete mode 100644 dep/cpr/opt/curl/CMake/CMakeConfigurableFile.in delete mode 100644 dep/cpr/opt/curl/CMake/CurlSymbolHiding.cmake delete mode 100644 dep/cpr/opt/curl/CMake/CurlTests.c delete mode 100644 dep/cpr/opt/curl/CMake/FindCARES.cmake delete mode 100644 dep/cpr/opt/curl/CMake/FindGSS.cmake delete mode 100644 dep/cpr/opt/curl/CMake/FindLibSSH2.cmake delete mode 100644 dep/cpr/opt/curl/CMake/FindMbedTLS.cmake delete mode 100644 dep/cpr/opt/curl/CMake/FindNGHTTP2.cmake delete mode 100644 dep/cpr/opt/curl/CMake/Macros.cmake delete mode 100644 dep/cpr/opt/curl/CMake/OtherTests.cmake delete mode 100644 dep/cpr/opt/curl/CMake/Platforms/WindowsCache.cmake delete mode 100644 dep/cpr/opt/curl/CMake/Utilities.cmake delete mode 100644 dep/cpr/opt/curl/CMake/cmake_uninstall.cmake.in delete mode 100644 dep/cpr/opt/curl/CMakeLists.txt delete mode 100644 dep/cpr/opt/curl/COPYING delete mode 100644 dep/cpr/opt/curl/GIT-INFO delete mode 100644 dep/cpr/opt/curl/README delete mode 100644 dep/cpr/opt/curl/README.md delete mode 100644 dep/cpr/opt/curl/RELEASE-NOTES delete mode 100644 dep/cpr/opt/curl/buildconf delete mode 100644 dep/cpr/opt/curl/buildconf.bat delete mode 100644 dep/cpr/opt/curl/curl-config.in delete mode 100644 dep/cpr/opt/curl/include/Makefile.am delete mode 100644 dep/cpr/opt/curl/include/README delete mode 100644 dep/cpr/opt/curl/include/curl/.gitignore delete mode 100644 dep/cpr/opt/curl/include/curl/Makefile.am delete mode 100644 dep/cpr/opt/curl/include/curl/curl.h delete mode 100644 dep/cpr/opt/curl/include/curl/curlver.h delete mode 100644 dep/cpr/opt/curl/include/curl/easy.h delete mode 100644 dep/cpr/opt/curl/include/curl/mprintf.h delete mode 100644 dep/cpr/opt/curl/include/curl/multi.h delete mode 100644 dep/cpr/opt/curl/include/curl/stdcheaders.h delete mode 100644 dep/cpr/opt/curl/include/curl/system.h delete mode 100644 dep/cpr/opt/curl/include/curl/typecheck-gcc.h delete mode 100644 dep/cpr/opt/curl/lib/.gitattributes delete mode 100644 dep/cpr/opt/curl/lib/.gitignore delete mode 100644 dep/cpr/opt/curl/lib/CMakeLists.txt delete mode 100644 dep/cpr/opt/curl/lib/Makefile.Watcom delete mode 100644 dep/cpr/opt/curl/lib/Makefile.am delete mode 100644 dep/cpr/opt/curl/lib/Makefile.b32 delete mode 100644 dep/cpr/opt/curl/lib/Makefile.inc delete mode 100644 dep/cpr/opt/curl/lib/Makefile.m32 delete mode 100644 dep/cpr/opt/curl/lib/Makefile.netware delete mode 100644 dep/cpr/opt/curl/lib/Makefile.vxworks delete mode 100644 dep/cpr/opt/curl/lib/amigaos.c delete mode 100644 dep/cpr/opt/curl/lib/amigaos.h delete mode 100644 dep/cpr/opt/curl/lib/arpa_telnet.h delete mode 100644 dep/cpr/opt/curl/lib/asyn-ares.c delete mode 100644 dep/cpr/opt/curl/lib/asyn-thread.c delete mode 100644 dep/cpr/opt/curl/lib/asyn.h delete mode 100644 dep/cpr/opt/curl/lib/base64.c delete mode 100644 dep/cpr/opt/curl/lib/checksrc.pl delete mode 100644 dep/cpr/opt/curl/lib/config-amigaos.h delete mode 100644 dep/cpr/opt/curl/lib/config-dos.h delete mode 100644 dep/cpr/opt/curl/lib/config-mac.h delete mode 100644 dep/cpr/opt/curl/lib/config-os400.h delete mode 100644 dep/cpr/opt/curl/lib/config-riscos.h delete mode 100644 dep/cpr/opt/curl/lib/config-symbian.h delete mode 100644 dep/cpr/opt/curl/lib/config-tpf.h delete mode 100644 dep/cpr/opt/curl/lib/config-vxworks.h delete mode 100644 dep/cpr/opt/curl/lib/config-win32.h delete mode 100644 dep/cpr/opt/curl/lib/config-win32ce.h delete mode 100644 dep/cpr/opt/curl/lib/conncache.c delete mode 100644 dep/cpr/opt/curl/lib/conncache.h delete mode 100644 dep/cpr/opt/curl/lib/connect.c delete mode 100644 dep/cpr/opt/curl/lib/connect.h delete mode 100644 dep/cpr/opt/curl/lib/content_encoding.c delete mode 100644 dep/cpr/opt/curl/lib/content_encoding.h delete mode 100644 dep/cpr/opt/curl/lib/cookie.c delete mode 100644 dep/cpr/opt/curl/lib/cookie.h delete mode 100644 dep/cpr/opt/curl/lib/curl_addrinfo.c delete mode 100644 dep/cpr/opt/curl/lib/curl_addrinfo.h delete mode 100644 dep/cpr/opt/curl/lib/curl_base64.h delete mode 100644 dep/cpr/opt/curl/lib/curl_config.h.cmake delete mode 100644 dep/cpr/opt/curl/lib/curl_des.c delete mode 100644 dep/cpr/opt/curl/lib/curl_des.h delete mode 100644 dep/cpr/opt/curl/lib/curl_endian.c delete mode 100644 dep/cpr/opt/curl/lib/curl_endian.h delete mode 100644 dep/cpr/opt/curl/lib/curl_fnmatch.c delete mode 100644 dep/cpr/opt/curl/lib/curl_fnmatch.h delete mode 100644 dep/cpr/opt/curl/lib/curl_gethostname.c delete mode 100644 dep/cpr/opt/curl/lib/curl_gethostname.h delete mode 100644 dep/cpr/opt/curl/lib/curl_gssapi.c delete mode 100644 dep/cpr/opt/curl/lib/curl_gssapi.h delete mode 100644 dep/cpr/opt/curl/lib/curl_hmac.h delete mode 100644 dep/cpr/opt/curl/lib/curl_ldap.h delete mode 100644 dep/cpr/opt/curl/lib/curl_md4.h delete mode 100644 dep/cpr/opt/curl/lib/curl_md5.h delete mode 100644 dep/cpr/opt/curl/lib/curl_memory.h delete mode 100644 dep/cpr/opt/curl/lib/curl_memrchr.c delete mode 100644 dep/cpr/opt/curl/lib/curl_memrchr.h delete mode 100644 dep/cpr/opt/curl/lib/curl_multibyte.c delete mode 100644 dep/cpr/opt/curl/lib/curl_multibyte.h delete mode 100644 dep/cpr/opt/curl/lib/curl_ntlm_core.c delete mode 100644 dep/cpr/opt/curl/lib/curl_ntlm_core.h delete mode 100644 dep/cpr/opt/curl/lib/curl_ntlm_wb.c delete mode 100644 dep/cpr/opt/curl/lib/curl_ntlm_wb.h delete mode 100644 dep/cpr/opt/curl/lib/curl_printf.h delete mode 100644 dep/cpr/opt/curl/lib/curl_rtmp.c delete mode 100644 dep/cpr/opt/curl/lib/curl_rtmp.h delete mode 100644 dep/cpr/opt/curl/lib/curl_sasl.c delete mode 100644 dep/cpr/opt/curl/lib/curl_sasl.h delete mode 100644 dep/cpr/opt/curl/lib/curl_sec.h delete mode 100644 dep/cpr/opt/curl/lib/curl_setup.h delete mode 100644 dep/cpr/opt/curl/lib/curl_setup_once.h delete mode 100644 dep/cpr/opt/curl/lib/curl_sspi.c delete mode 100644 dep/cpr/opt/curl/lib/curl_sspi.h delete mode 100644 dep/cpr/opt/curl/lib/curl_threads.c delete mode 100644 dep/cpr/opt/curl/lib/curl_threads.h delete mode 100644 dep/cpr/opt/curl/lib/curlx.h delete mode 100644 dep/cpr/opt/curl/lib/dict.c delete mode 100644 dep/cpr/opt/curl/lib/dict.h delete mode 100644 dep/cpr/opt/curl/lib/dotdot.c delete mode 100644 dep/cpr/opt/curl/lib/dotdot.h delete mode 100644 dep/cpr/opt/curl/lib/easy.c delete mode 100644 dep/cpr/opt/curl/lib/easyif.h delete mode 100644 dep/cpr/opt/curl/lib/escape.c delete mode 100644 dep/cpr/opt/curl/lib/escape.h delete mode 100644 dep/cpr/opt/curl/lib/file.c delete mode 100644 dep/cpr/opt/curl/lib/file.h delete mode 100644 dep/cpr/opt/curl/lib/fileinfo.c delete mode 100644 dep/cpr/opt/curl/lib/fileinfo.h delete mode 100644 dep/cpr/opt/curl/lib/firefox-db2pem.sh delete mode 100644 dep/cpr/opt/curl/lib/formdata.c delete mode 100644 dep/cpr/opt/curl/lib/formdata.h delete mode 100644 dep/cpr/opt/curl/lib/ftp.c delete mode 100644 dep/cpr/opt/curl/lib/ftp.h delete mode 100644 dep/cpr/opt/curl/lib/ftplistparser.c delete mode 100644 dep/cpr/opt/curl/lib/ftplistparser.h delete mode 100644 dep/cpr/opt/curl/lib/getenv.c delete mode 100644 dep/cpr/opt/curl/lib/getinfo.c delete mode 100644 dep/cpr/opt/curl/lib/getinfo.h delete mode 100644 dep/cpr/opt/curl/lib/gopher.c delete mode 100644 dep/cpr/opt/curl/lib/gopher.h delete mode 100644 dep/cpr/opt/curl/lib/hash.c delete mode 100644 dep/cpr/opt/curl/lib/hash.h delete mode 100644 dep/cpr/opt/curl/lib/hmac.c delete mode 100644 dep/cpr/opt/curl/lib/hostasyn.c delete mode 100644 dep/cpr/opt/curl/lib/hostcheck.c delete mode 100644 dep/cpr/opt/curl/lib/hostcheck.h delete mode 100644 dep/cpr/opt/curl/lib/hostip.c delete mode 100644 dep/cpr/opt/curl/lib/hostip.h delete mode 100644 dep/cpr/opt/curl/lib/hostip4.c delete mode 100644 dep/cpr/opt/curl/lib/hostip6.c delete mode 100644 dep/cpr/opt/curl/lib/hostsyn.c delete mode 100644 dep/cpr/opt/curl/lib/http.c delete mode 100644 dep/cpr/opt/curl/lib/http.h delete mode 100644 dep/cpr/opt/curl/lib/http2.c delete mode 100644 dep/cpr/opt/curl/lib/http2.h delete mode 100644 dep/cpr/opt/curl/lib/http_chunks.c delete mode 100644 dep/cpr/opt/curl/lib/http_chunks.h delete mode 100644 dep/cpr/opt/curl/lib/http_digest.c delete mode 100644 dep/cpr/opt/curl/lib/http_digest.h delete mode 100644 dep/cpr/opt/curl/lib/http_negotiate.c delete mode 100644 dep/cpr/opt/curl/lib/http_negotiate.h delete mode 100644 dep/cpr/opt/curl/lib/http_ntlm.c delete mode 100644 dep/cpr/opt/curl/lib/http_ntlm.h delete mode 100644 dep/cpr/opt/curl/lib/http_proxy.c delete mode 100644 dep/cpr/opt/curl/lib/http_proxy.h delete mode 100644 dep/cpr/opt/curl/lib/idn_win32.c delete mode 100644 dep/cpr/opt/curl/lib/if2ip.c delete mode 100644 dep/cpr/opt/curl/lib/if2ip.h delete mode 100644 dep/cpr/opt/curl/lib/imap.c delete mode 100644 dep/cpr/opt/curl/lib/imap.h delete mode 100644 dep/cpr/opt/curl/lib/inet_ntop.c delete mode 100644 dep/cpr/opt/curl/lib/inet_ntop.h delete mode 100644 dep/cpr/opt/curl/lib/inet_pton.c delete mode 100644 dep/cpr/opt/curl/lib/inet_pton.h delete mode 100644 dep/cpr/opt/curl/lib/krb5.c delete mode 100644 dep/cpr/opt/curl/lib/ldap.c delete mode 100644 dep/cpr/opt/curl/lib/libcurl.plist delete mode 100644 dep/cpr/opt/curl/lib/libcurl.rc delete mode 100644 dep/cpr/opt/curl/lib/libcurl.vers.in delete mode 100644 dep/cpr/opt/curl/lib/llist.c delete mode 100644 dep/cpr/opt/curl/lib/llist.h delete mode 100644 dep/cpr/opt/curl/lib/makefile.amiga delete mode 100644 dep/cpr/opt/curl/lib/makefile.dj delete mode 100644 dep/cpr/opt/curl/lib/md4.c delete mode 100644 dep/cpr/opt/curl/lib/md5.c delete mode 100644 dep/cpr/opt/curl/lib/memdebug.c delete mode 100644 dep/cpr/opt/curl/lib/memdebug.h delete mode 100644 dep/cpr/opt/curl/lib/mime.c delete mode 100644 dep/cpr/opt/curl/lib/mime.h delete mode 100644 dep/cpr/opt/curl/lib/mk-ca-bundle.pl delete mode 100644 dep/cpr/opt/curl/lib/mk-ca-bundle.vbs delete mode 100644 dep/cpr/opt/curl/lib/mprintf.c delete mode 100644 dep/cpr/opt/curl/lib/multi.c delete mode 100644 dep/cpr/opt/curl/lib/multihandle.h delete mode 100644 dep/cpr/opt/curl/lib/multiif.h delete mode 100644 dep/cpr/opt/curl/lib/netrc.c delete mode 100644 dep/cpr/opt/curl/lib/netrc.h delete mode 100644 dep/cpr/opt/curl/lib/non-ascii.c delete mode 100644 dep/cpr/opt/curl/lib/non-ascii.h delete mode 100644 dep/cpr/opt/curl/lib/nonblock.c delete mode 100644 dep/cpr/opt/curl/lib/nonblock.h delete mode 100644 dep/cpr/opt/curl/lib/nwlib.c delete mode 100644 dep/cpr/opt/curl/lib/nwos.c delete mode 100644 dep/cpr/opt/curl/lib/objnames-test08.sh delete mode 100644 dep/cpr/opt/curl/lib/objnames-test10.sh delete mode 100644 dep/cpr/opt/curl/lib/objnames.inc delete mode 100644 dep/cpr/opt/curl/lib/openldap.c delete mode 100644 dep/cpr/opt/curl/lib/parsedate.c delete mode 100644 dep/cpr/opt/curl/lib/parsedate.h delete mode 100644 dep/cpr/opt/curl/lib/pingpong.c delete mode 100644 dep/cpr/opt/curl/lib/pingpong.h delete mode 100644 dep/cpr/opt/curl/lib/pipeline.c delete mode 100644 dep/cpr/opt/curl/lib/pipeline.h delete mode 100644 dep/cpr/opt/curl/lib/pop3.c delete mode 100644 dep/cpr/opt/curl/lib/pop3.h delete mode 100644 dep/cpr/opt/curl/lib/progress.c delete mode 100644 dep/cpr/opt/curl/lib/progress.h delete mode 100644 dep/cpr/opt/curl/lib/rand.c delete mode 100644 dep/cpr/opt/curl/lib/rand.h delete mode 100644 dep/cpr/opt/curl/lib/rtsp.c delete mode 100644 dep/cpr/opt/curl/lib/rtsp.h delete mode 100644 dep/cpr/opt/curl/lib/security.c delete mode 100644 dep/cpr/opt/curl/lib/select.c delete mode 100644 dep/cpr/opt/curl/lib/select.h delete mode 100644 dep/cpr/opt/curl/lib/sendf.c delete mode 100644 dep/cpr/opt/curl/lib/sendf.h delete mode 100644 dep/cpr/opt/curl/lib/setup-os400.h delete mode 100644 dep/cpr/opt/curl/lib/setup-vms.h delete mode 100644 dep/cpr/opt/curl/lib/share.c delete mode 100644 dep/cpr/opt/curl/lib/share.h delete mode 100644 dep/cpr/opt/curl/lib/sigpipe.h delete mode 100644 dep/cpr/opt/curl/lib/slist.c delete mode 100644 dep/cpr/opt/curl/lib/slist.h delete mode 100644 dep/cpr/opt/curl/lib/smb.c delete mode 100644 dep/cpr/opt/curl/lib/smb.h delete mode 100644 dep/cpr/opt/curl/lib/smtp.c delete mode 100644 dep/cpr/opt/curl/lib/smtp.h delete mode 100644 dep/cpr/opt/curl/lib/sockaddr.h delete mode 100644 dep/cpr/opt/curl/lib/socks.c delete mode 100644 dep/cpr/opt/curl/lib/socks.h delete mode 100644 dep/cpr/opt/curl/lib/socks_gssapi.c delete mode 100644 dep/cpr/opt/curl/lib/socks_sspi.c delete mode 100644 dep/cpr/opt/curl/lib/speedcheck.c delete mode 100644 dep/cpr/opt/curl/lib/speedcheck.h delete mode 100644 dep/cpr/opt/curl/lib/splay.c delete mode 100644 dep/cpr/opt/curl/lib/splay.h delete mode 100644 dep/cpr/opt/curl/lib/ssh.c delete mode 100644 dep/cpr/opt/curl/lib/ssh.h delete mode 100644 dep/cpr/opt/curl/lib/strcase.c delete mode 100644 dep/cpr/opt/curl/lib/strcase.h delete mode 100644 dep/cpr/opt/curl/lib/strdup.c delete mode 100644 dep/cpr/opt/curl/lib/strdup.h delete mode 100644 dep/cpr/opt/curl/lib/strerror.c delete mode 100644 dep/cpr/opt/curl/lib/strerror.h delete mode 100644 dep/cpr/opt/curl/lib/strtok.c delete mode 100644 dep/cpr/opt/curl/lib/strtok.h delete mode 100644 dep/cpr/opt/curl/lib/strtoofft.c delete mode 100644 dep/cpr/opt/curl/lib/strtoofft.h delete mode 100644 dep/cpr/opt/curl/lib/system_win32.c delete mode 100644 dep/cpr/opt/curl/lib/system_win32.h delete mode 100644 dep/cpr/opt/curl/lib/telnet.c delete mode 100644 dep/cpr/opt/curl/lib/telnet.h delete mode 100644 dep/cpr/opt/curl/lib/tftp.c delete mode 100644 dep/cpr/opt/curl/lib/tftp.h delete mode 100644 dep/cpr/opt/curl/lib/timeval.c delete mode 100644 dep/cpr/opt/curl/lib/timeval.h delete mode 100644 dep/cpr/opt/curl/lib/transfer.c delete mode 100644 dep/cpr/opt/curl/lib/transfer.h delete mode 100644 dep/cpr/opt/curl/lib/url.c delete mode 100644 dep/cpr/opt/curl/lib/url.h delete mode 100644 dep/cpr/opt/curl/lib/urldata.h delete mode 100644 dep/cpr/opt/curl/lib/vauth/cleartext.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/cram.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/digest.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/digest.h delete mode 100644 dep/cpr/opt/curl/lib/vauth/digest_sspi.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/krb5_gssapi.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/krb5_sspi.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/ntlm.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/ntlm.h delete mode 100644 dep/cpr/opt/curl/lib/vauth/ntlm_sspi.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/oauth2.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/spnego_gssapi.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/spnego_sspi.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/vauth.c delete mode 100644 dep/cpr/opt/curl/lib/vauth/vauth.h delete mode 100644 dep/cpr/opt/curl/lib/version.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/axtls.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/axtls.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/cyassl.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/cyassl.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/darwinssl.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/darwinssl.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/gskit.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/gskit.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/gtls.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/gtls.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/mbedtls.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/mbedtls.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/nss.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/nssg.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/openssl.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/openssl.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/polarssl.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/polarssl.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/polarssl_threadlock.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/polarssl_threadlock.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/schannel.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/schannel.h delete mode 100644 dep/cpr/opt/curl/lib/vtls/vtls.c delete mode 100644 dep/cpr/opt/curl/lib/vtls/vtls.h delete mode 100644 dep/cpr/opt/curl/lib/warnless.c delete mode 100644 dep/cpr/opt/curl/lib/warnless.h delete mode 100644 dep/cpr/opt/curl/lib/wildcard.c delete mode 100644 dep/cpr/opt/curl/lib/wildcard.h delete mode 100644 dep/cpr/opt/curl/lib/x509asn1.c delete mode 100644 dep/cpr/opt/curl/lib/x509asn1.h delete mode 100644 dep/cpr/opt/curl/libcurl.pc.in delete mode 100644 dep/cpr/opt/curl/src/.gitignore delete mode 100644 dep/cpr/opt/curl/src/CMakeLists.txt delete mode 100644 dep/cpr/opt/curl/src/Makefile.Watcom delete mode 100644 dep/cpr/opt/curl/src/Makefile.am delete mode 100644 dep/cpr/opt/curl/src/Makefile.b32 delete mode 100644 dep/cpr/opt/curl/src/Makefile.inc delete mode 100644 dep/cpr/opt/curl/src/Makefile.m32 delete mode 100644 dep/cpr/opt/curl/src/Makefile.netware delete mode 100644 dep/cpr/opt/curl/src/curl.rc delete mode 100644 dep/cpr/opt/curl/src/macos/MACINSTALL.TXT delete mode 100644 dep/cpr/opt/curl/src/macos/curl.mcp.xml.sit.hqx delete mode 100644 dep/cpr/opt/curl/src/macos/src/curl_GUSIConfig.cpp delete mode 100644 dep/cpr/opt/curl/src/macos/src/macos_main.cpp delete mode 100644 dep/cpr/opt/curl/src/makefile.amiga delete mode 100644 dep/cpr/opt/curl/src/makefile.dj delete mode 100644 dep/cpr/opt/curl/src/mkhelp.pl delete mode 100644 dep/cpr/opt/curl/src/slist_wc.c delete mode 100644 dep/cpr/opt/curl/src/slist_wc.h delete mode 100644 dep/cpr/opt/curl/src/tool_binmode.c delete mode 100644 dep/cpr/opt/curl/src/tool_binmode.h delete mode 100644 dep/cpr/opt/curl/src/tool_bname.c delete mode 100644 dep/cpr/opt/curl/src/tool_bname.h delete mode 100644 dep/cpr/opt/curl/src/tool_cb_dbg.c delete mode 100644 dep/cpr/opt/curl/src/tool_cb_dbg.h delete mode 100644 dep/cpr/opt/curl/src/tool_cb_hdr.c delete mode 100644 dep/cpr/opt/curl/src/tool_cb_hdr.h delete mode 100644 dep/cpr/opt/curl/src/tool_cb_prg.c delete mode 100644 dep/cpr/opt/curl/src/tool_cb_prg.h delete mode 100644 dep/cpr/opt/curl/src/tool_cb_rea.c delete mode 100644 dep/cpr/opt/curl/src/tool_cb_rea.h delete mode 100644 dep/cpr/opt/curl/src/tool_cb_see.c delete mode 100644 dep/cpr/opt/curl/src/tool_cb_see.h delete mode 100644 dep/cpr/opt/curl/src/tool_cb_wrt.c delete mode 100644 dep/cpr/opt/curl/src/tool_cb_wrt.h delete mode 100644 dep/cpr/opt/curl/src/tool_cfgable.c delete mode 100644 dep/cpr/opt/curl/src/tool_cfgable.h delete mode 100644 dep/cpr/opt/curl/src/tool_convert.c delete mode 100644 dep/cpr/opt/curl/src/tool_convert.h delete mode 100644 dep/cpr/opt/curl/src/tool_dirhie.c delete mode 100644 dep/cpr/opt/curl/src/tool_dirhie.h delete mode 100644 dep/cpr/opt/curl/src/tool_doswin.c delete mode 100644 dep/cpr/opt/curl/src/tool_doswin.h delete mode 100644 dep/cpr/opt/curl/src/tool_easysrc.c delete mode 100644 dep/cpr/opt/curl/src/tool_easysrc.h delete mode 100644 dep/cpr/opt/curl/src/tool_formparse.c delete mode 100644 dep/cpr/opt/curl/src/tool_formparse.h delete mode 100644 dep/cpr/opt/curl/src/tool_getparam.c delete mode 100644 dep/cpr/opt/curl/src/tool_getparam.h delete mode 100644 dep/cpr/opt/curl/src/tool_getpass.c delete mode 100644 dep/cpr/opt/curl/src/tool_getpass.h delete mode 100644 dep/cpr/opt/curl/src/tool_help.c delete mode 100644 dep/cpr/opt/curl/src/tool_help.h delete mode 100644 dep/cpr/opt/curl/src/tool_helpers.c delete mode 100644 dep/cpr/opt/curl/src/tool_helpers.h delete mode 100644 dep/cpr/opt/curl/src/tool_homedir.c delete mode 100644 dep/cpr/opt/curl/src/tool_homedir.h delete mode 100644 dep/cpr/opt/curl/src/tool_hugehelp.c.cvs delete mode 100644 dep/cpr/opt/curl/src/tool_hugehelp.h delete mode 100644 dep/cpr/opt/curl/src/tool_libinfo.c delete mode 100644 dep/cpr/opt/curl/src/tool_libinfo.h delete mode 100644 dep/cpr/opt/curl/src/tool_main.c delete mode 100644 dep/cpr/opt/curl/src/tool_main.h delete mode 100644 dep/cpr/opt/curl/src/tool_metalink.c delete mode 100644 dep/cpr/opt/curl/src/tool_metalink.h delete mode 100644 dep/cpr/opt/curl/src/tool_msgs.c delete mode 100644 dep/cpr/opt/curl/src/tool_msgs.h delete mode 100644 dep/cpr/opt/curl/src/tool_operate.c delete mode 100644 dep/cpr/opt/curl/src/tool_operate.h delete mode 100644 dep/cpr/opt/curl/src/tool_operhlp.c delete mode 100644 dep/cpr/opt/curl/src/tool_operhlp.h delete mode 100644 dep/cpr/opt/curl/src/tool_panykey.c delete mode 100644 dep/cpr/opt/curl/src/tool_panykey.h delete mode 100644 dep/cpr/opt/curl/src/tool_paramhlp.c delete mode 100644 dep/cpr/opt/curl/src/tool_paramhlp.h delete mode 100644 dep/cpr/opt/curl/src/tool_parsecfg.c delete mode 100644 dep/cpr/opt/curl/src/tool_parsecfg.h delete mode 100644 dep/cpr/opt/curl/src/tool_sdecls.h delete mode 100644 dep/cpr/opt/curl/src/tool_setopt.c delete mode 100644 dep/cpr/opt/curl/src/tool_setopt.h delete mode 100644 dep/cpr/opt/curl/src/tool_setup.h delete mode 100644 dep/cpr/opt/curl/src/tool_sleep.c delete mode 100644 dep/cpr/opt/curl/src/tool_sleep.h delete mode 100644 dep/cpr/opt/curl/src/tool_strdup.c delete mode 100644 dep/cpr/opt/curl/src/tool_strdup.h delete mode 100644 dep/cpr/opt/curl/src/tool_urlglob.c delete mode 100644 dep/cpr/opt/curl/src/tool_urlglob.h delete mode 100644 dep/cpr/opt/curl/src/tool_util.c delete mode 100644 dep/cpr/opt/curl/src/tool_util.h delete mode 100644 dep/cpr/opt/curl/src/tool_version.h delete mode 100644 dep/cpr/opt/curl/src/tool_vms.c delete mode 100644 dep/cpr/opt/curl/src/tool_vms.h delete mode 100644 dep/cpr/opt/curl/src/tool_writeout.c delete mode 100644 dep/cpr/opt/curl/src/tool_writeout.h delete mode 100644 dep/cpr/opt/curl/src/tool_xattr.c delete mode 100644 dep/cpr/opt/curl/src/tool_xattr.h diff --git a/cmake/options.cmake b/cmake/options.cmake index 437c21294f8..12f3594cb0d 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -50,5 +50,4 @@ option(WITH_WARNINGS "Show all warnings during compile" option(WITH_COREDEBUG "Include additional debug-code in core" 0) set(WITH_SOURCE_TREE "hierarchical" CACHE STRING "Build the source tree for IDE's.") set_property(CACHE WITH_SOURCE_TREE PROPERTY STRINGS no flat hierarchical hierarchical-folders) -option(WITHOUT_GIT "Disable the GIT testing routines" 0) -option(WITH_CPR "Enable CPR dep (curl wrapper)" 0) +option(WITHOUT_GIT "Disable the GIT testing routines" 0) \ No newline at end of file diff --git a/contrib/ServerRelay/.gitignore b/contrib/ServerRelay/.gitignore deleted file mode 100644 index a313c84bd43..00000000000 --- a/contrib/ServerRelay/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules*/ \ No newline at end of file diff --git a/contrib/ServerRelay/README.md b/contrib/ServerRelay/README.md deleted file mode 100644 index ad598f998c3..00000000000 --- a/contrib/ServerRelay/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# ServerRelay - -Server Relay between world of warcraft world channel(AshamaneCore) and Discord. - -### CREDITS -* Made by : __DEVIL1234__ -* E-mail : __ingerasu1234@yahoo.com__. -* Credits for helping me : __Traesh__ from AshamaneProject -* Credits to guys with exceptional packages that simplified the process of making this project to happen - -### Installation - -To install this ServerRelay on your server(is more securely to run in same host with worldserver or internal on lan) you need to install Node.JS package and have setup a discord server and bot for it. Is already many tutorials how to setup this already on internet (google it bro). Tip : set the discordapp on developer mode, for id's right-click on channel's and select copy id. - -SPECIAL REQUIREMENT : compile the worldserver with -DCPR=1 argument on cmake. ( will take a longer time to configure) - -Recommended version of Node.JS : __v8.11.3__. Upper version is your risk to use. -1. Commands: - ```javascript - //That will install all packages needed from package.json and will be ready to use - npm install - ``` -2. Configure the config.json file with your channels id and token from bot. The rest is preferable to not edit exception is the prefix for send command. Like this : - ```javascript - { - "token": "BOT-TOKEN", - "channel_id": "RELAY-CHAT-ID", - "staff_channel_ID" : "STAFF-CHANNEL-ID", - "post_url_server_message_world": "http://127.0.0.1:8082/sendChannelMessage/", - "post_url_server_message_alliance" : "http://127.0.0.1:8082/sendChannelMessage/0", - "post_url_server_message_horde" : "http://127.0.0.1:8082/sendChannelMessage/1", - "post_url_server_command": "http://127.0.0.1:8082/command", - "post_port": "8082", - "post_token": "TOKEN FROM WORLDSERVER.CONF ON WorldREST.AuthToken, THIS ONE NEED TO MATCH HERE", - "channel_horde" : "world_h", // I RECOMMEND TO NOT CHANGE IT - "channel_alliance": "world_a", // I RECOMMEND TO NOT CHANGE IT - "allow_interactions" : "0", // IF YOU SET TO 1, YOU NEED TO ENABLE IN WORLDSERVER.CONF THIS ONE : AllowTwoSide.Interaction.Channel. - "channel_world" : "world", // I RECOMMEND TO NOT CHANGE IT - "command_prefix" : "." // IS USED ON staff channel for purge command(delete the message on channels) and send command for ingame commands(is same one from console) - } - ``` -3. Configure the roles: - ```javascript - Open the server.js file with txt editor and read the comments line numbers : 13 -> 16 - ``` -4. Running the server : - * Windows : -
WARNING: WILL RUN WITHOUT CMD PROMPT TO BE SHOWN - ```javascript - Run the file windows.vbs - ``` - * Linux : - ```javascript - chmod +x run.sh - ./linux.sh & - - // OPTIONALY CAND SET A CRONTAB WITH run.sh. THE SERVER IF IS WILL CRASH, THE NODEMON WILL TAKE OF SERVER.JS. IF YOU WANT TO SETUP CRONTAB ON THE END NOT SPECIFY `` BECAUSE IS ALREADY SPECIFIED ON linux.sh - ``` - -### Commands accessible on this discord bot -* Send - ```javascript - (prefix)send argument(commands accessible on worldserver console) - ``` - * EXAMPLE : - ```javascript - .send help // will return all commands available - ``` - -* Purge - ```javascript - (prefix)purge <1-100> (will delete the message on channel(can be used on any channel) - ``` - * EXAMPLE - * EXAMPLE : - ```javascript - .purge 10 // delete 10 messages from channel - ``` - -### Support -If you need support for this relay contact me on discord server Ashamane under the username : __devil1234__. -If you want to support with donations contact me same like up but on direct message/private message. \ No newline at end of file diff --git a/contrib/ServerRelay/config.json b/contrib/ServerRelay/config.json deleted file mode 100644 index 0f2de15fa69..00000000000 --- a/contrib/ServerRelay/config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "token": "", - "channel_id": "", - "staff_channel_ID" : "", - "post_url_server_message_world": "http://127.0.0.1:8082/sendChannelMessage/", - "post_url_server_message_alliance" : "http://127.0.0.1:8082/sendChannelMessage/0", - "post_url_server_message_horde" : "http://127.0.0.1:8082/sendChannelMessage/1", - "post_url_server_command": "http://127.0.0.1:8082/command", - "post_token": "", - "channel_horde" : "world_h", - "channel_alliance": "world_a", - "allow_interactions" : "0", - "channel_world" : "world", - "command_prefix" : "." -} \ No newline at end of file diff --git a/contrib/ServerRelay/linux.sh b/contrib/ServerRelay/linux.sh deleted file mode 100644 index fa37637a303..00000000000 --- a/contrib/ServerRelay/linux.sh +++ /dev/null @@ -1 +0,0 @@ -nodemon > /dev/null \ No newline at end of file diff --git a/contrib/ServerRelay/package-lock.json b/contrib/ServerRelay/package-lock.json deleted file mode 100644 index 25720e942c0..00000000000 --- a/contrib/ServerRelay/package-lock.json +++ /dev/null @@ -1,2766 +0,0 @@ -{ - "name": "server-relay", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", - "requires": { - "string-width": "^2.0.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" - }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - }, - "dependencies": { - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - } - } - }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=" - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" - } - }, - "ci-info": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz", - "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==" - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", - "requires": { - "color-name": "1.1.1" - } - }, - "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "discord.js": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.3.2.tgz", - "integrity": "sha512-Abw9CTMX3Jb47IeRffqx2VNSnXl/OsTdQzhvbw/JnqCyqc2imAocc7pX2HoRmgKd8CgSqsjBFBneusz/E16e6A==", - "requires": { - "long": "^4.0.0", - "prism-media": "^0.0.2", - "snekfetch": "^3.6.4", - "tweetnacl": "^1.0.0", - "ws": "^4.0.0" - } - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "requires": { - "is-obj": "^1.0.0" - } - }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "optional": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "event-stream": { - "version": "3.3.4", - "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "requires": { - "map-cache": "^0.2.2" - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" - }, - "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", - "optional": true, - "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.5.1", - "bundled": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.21", - "bundled": true, - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "minipass": { - "version": "2.2.4", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.1.0", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "needle": { - "version": "2.2.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.10.0", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "npm-packlist": { - "version": "1.1.10", - "bundled": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.7", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "optional": true - }, - "semver": { - "version": "5.5.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "4.4.1", - "bundled": true, - "optional": true, - "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "yallist": { - "version": "3.0.2", - "bundled": true - } - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "requires": { - "ini": "^1.3.4" - } - }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "http": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/http/-/http-0.0.0.tgz", - "integrity": "sha1-huYybSnF0Dnen6xYSkVon5KfT3I=" - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-ci": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz", - "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==", - "requires": { - "ci-info": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "is-empty": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-empty/-/is-empty-1.2.0.tgz", - "integrity": "sha1-3pu1snhzigWgsJpX4ftNSjQan2s=" - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - } - }, - "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "requires": { - "path-is-inside": "^1.0.1" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" - }, - "is-retry-allowed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - }, - "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", - "requires": { - "package-json": "^4.0.0" - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, - "lodash.toarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", - "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "mime-db": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" - }, - "mime-types": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", - "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", - "requires": { - "mime-db": "~1.35.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "node-emoji": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", - "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", - "requires": { - "lodash.toarray": "^4.4.0" - } - }, - "nodemon": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.3.tgz", - "integrity": "sha512-XdVfAjGlDKU2nqoGgycxTndkJ5fdwvWJ/tlMGk2vHxMZBrSPVh86OM6z7viAv8BBJWjMgeuYQBofzr6LUoi+7g==", - "requires": { - "chokidar": "^2.0.2", - "debug": "^3.1.0", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.0", - "semver": "^5.5.0", - "supports-color": "^5.2.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^2.3.0" - } - }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "requires": { - "abbrev": "1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "requires": { - "through": "~2.3" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" - }, - "prism-media": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.2.tgz", - "integrity": "sha512-L6yc8P5NVG35ivzvfI7bcTYzqFV+K8gTfX9YaJbmIFfMXTs71RMnAupvTQPTCteGsiOy9QcNLkQyWjAafY/hCQ==" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "ps-tree": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", - "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", - "requires": { - "event-stream": "~3.3.0" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "pstree.remy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.0.tgz", - "integrity": "sha512-q5I5vLRMVtdWa8n/3UEzZX7Lfghzrg9eG2IKk2ENLSofKRCXVqMvMUHxCKgXNaqH/8ebhBxrqftHWnyTFweJ5Q==", - "requires": { - "ps-tree": "^1.1.0" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", - "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "registry-auth-token": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "requires": { - "rc": "^1.0.1" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "request": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" - } - }, - "request-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", - "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", - "requires": { - "bluebird": "^3.5.0", - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" - } - }, - "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", - "requires": { - "lodash": "^4.13.1" - } - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, - "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "requires": { - "semver": "^5.0.3" - } - }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" - }, - "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "snekfetch": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", - "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" - }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "requires": { - "through": "2" - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sshpk": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "dependencies": { - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - } - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" - }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "requires": { - "duplexer": "~0.1.1" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", - "requires": { - "execa": "^0.7.0" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "requires": { - "nopt": "~1.0.10" - } - }, - "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "requires": { - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", - "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" - }, - "undefsafe": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", - "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", - "requires": { - "debug": "^2.2.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "requires": { - "crypto-random-string": "^1.0.0" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" - }, - "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==" - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "requires": { - "prepend-http": "^1.0.1" - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "widest-line": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.0.tgz", - "integrity": "sha1-AUKk6KJD+IgsAjOqDgKBqnYVInM=", - "requires": { - "string-width": "^2.1.1" - } - }, - "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "ws": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", - "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0" - } - }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } -} diff --git a/contrib/ServerRelay/package.json b/contrib/ServerRelay/package.json deleted file mode 100644 index 98368b0a832..00000000000 --- a/contrib/ServerRelay/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "server-relay", - "version": "1.0.0", - "description": "Server Relay between world of warcraft channel(AshamaneCore) and Discord", - "main": "server.js", - "author": { - "name": "DEVIL1234" - }, - "nodemonConfig":{ - "ignore": ["config.json", "node_modules/*"] - }, - - "dependencies": { - "discord.js": "^11.3.2", - "http": "0.0.0", - "is-empty": "^1.2.0", - "node-emoji": "^1.8.1", - "nodemon": "^1.18.3", - "parse-json": "^4.0.0", - "request": "^2.87.0", - "request-promise": "^4.2.2" - } -} diff --git a/contrib/ServerRelay/run-server-scripts/windows.bat b/contrib/ServerRelay/run-server-scripts/windows.bat deleted file mode 100644 index 5f85a5cf892..00000000000 --- a/contrib/ServerRelay/run-server-scripts/windows.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -nodemon > NUL \ No newline at end of file diff --git a/contrib/ServerRelay/server.js b/contrib/ServerRelay/server.js deleted file mode 100644 index 50df211767b..00000000000 --- a/contrib/ServerRelay/server.js +++ /dev/null @@ -1,244 +0,0 @@ - -/* requirements */ -var Discord = require("discord.js"); -var config = require("./config.json") -var client = new Discord.Client(); -const request = require('request'); -const http = require('http'); -var rp = require('request-promise'); -const parseJson = require('parse-json'); -var emoji = require('node-emoji'); -var empty = require('is-empty'); - -// CONFIGURE THE ROLES NEEDED FOR GM Logo -// If you want more roles added just do like this (append to original one on line 95 and 195(optionaly, for send command) with -// || message.member.roles.find("name", role_3+) and add const role_number here. -// If you want just to change role name, modify the attribute below . Example : Admin -> Your role name -role_1 = "Owner"; -role_2 = "GameMasters"; - -/* Ready the client */ -client.on('ready', () => { - console.log('I am ready!'); - - client.user.setPresence({game: {name: "WORD PORN", type: 0}}); - client.user.setStatus('dnd'); - //console.log(`Logged in as ${client.user.tag}!`); - - var server = http.createServer(OnWorldMessage); - OnDiscordMessage(); - Commands(); - server.listen(8083); -}); - -client.on("disconnected", function () { process.exit(1); }); -/* - * Handle message in the way "World => Discord" - */ -function OnWorldMessage(request, response) { - if (request.method != "POST") { - response.writeHead(404); - response.end(); - return; - } - - try { - let body = []; - request.on('data', (chunk) => { - body.push(chunk); - }).on('end', () => { - body = Buffer.concat(body).toString(); - //console.log(body); - - /*Send the message to discord*/ - - // Parse the json message to can return part from it - var myJSON = JSON.parse(body); - //console.log(string); - - // send to discord channel id and the json text - switch(config.allow_interactions) - { - case "1": - client.channels.get(config.channel_id).send(myJSON.text); - break; - case "0": - var string = "[" + myJSON.channel + "]" + " " + myJSON.text; - client.channels.get(config.channel_id).send(string); - break; - } - - response.writeHead(200); - response.end(); - }); - } - catch (e) { - console.log(e); - response.writeHead(500); - response.end(); - } -} - -/* - * Handle message in the way "Discord => World" - */ - -function OnDiscordMessage() { - - client.on('message', async message => { - if (message.author.bot) return; - if (message.channel.type === "dm") return; - - // SEND TO WORLD CHANNEL - // showGMlogo bollean - if(message.channel.id === config.channel_id){ - if(message.member.roles.find("name", role_1) || message.member.roles.find("name", role_2)) {var gmLOGO = '1'} else { gmLOGO = "0"}; - - const messageArray = message.content; - const author = message.member.user.username; - - const message_emoji_replace = emoji.replace(messageArray, (emoji) => `${emoji.key}`); - - // world channel - let json_world = JSON.stringify({"senderName":author,"channelName":config.channel_world,"message": message_emoji_replace, "showGMLogo": gmLOGO}); - // world_a channel - let json_world_a = JSON.stringify({"senderName":author,"channelName":config.channel_alliance,"message": message_emoji_replace, "showGMLogo": gmLOGO}); - // world_h channel - let json_world_h = JSON.stringify({"senderName":author,"channelName":config.channel_horde,"message": message_emoji_replace, "showGMLogo": gmLOGO}); - - // allow interactions between horde and alliance on world channel's - - switch (config.allow_interactions){ - case "1": - var url_0 = config.post_url_server_message_world + "0"; - var url_1 = config.post_url_server_message_world + "1"; - - console.log(url_0); - - var auth = { 'Authorization': config.post_token}; - request.post({url:url_0, form: json_world, headers: auth}, function(err, httpResponse,body) - { - if(err) { - return console.log(err); - } - //console.log('post Suceess the response is:', body); - }); - - var auth = { 'Authorization': config.post_token}; - request.post({url:url_1, form: json_world, headers: auth}, function(err, httpResponse,body) - { - if(err) { - return console.log(err); - } - //console.log('post Suceess the response is:', body); - }); - break; - case "0": - var auth = { 'Authorization': config.post_token}; - - request.post({url:config.post_url_server_message_alliance, form: json_world_a, headers: auth}, function(err, httpResponse,body) - { - if(err) { - return console.log(err); - } - console.log('post Suceess the response is:', body); - }); - - request.post({url:config.post_url_server_message_horde, form: json_world_h, headers: auth}, function(err, httpResponse,body) - { - if(err) { - return console.log(err); - } - //console.log('post Suceess the response is:', body); - }); - break; -// default: - - }; - }; - }); -}; - -/* - * Handle the commands - */ -function Commands() { - - client.on('message', async message => { - if (message.author.bot) return; - if (message.channel.type === "dm") return; - - const args = message.content.slice(config.command_prefix.length).trim().split(/ +/g); - const command = args.shift().toLowerCase(); - - if(message.content.indexOf(config.command_prefix) !== 0) return; - - // COMMAND POST COMMANDS - if(command === "purge") { - - // This command removes all messages from all users in the channel, up to 100. - - // get the delete count, as an actual number. - const deleteCount = parseInt(args[0], 10); - - // Ooooh nice, combined conditions. <3 - if(!deleteCount || deleteCount < 2 || deleteCount > 1000) - return message.reply("Please provide a number between 2 and 100 for the number of messages to delete"); - - // So we get our messages, and delete them. Simple enough, right? - const fetched = await message.channel.fetchMessages({limit: deleteCount}); - message.channel.bulkDelete(fetched) - .catch(error => message.reply(`Couldn't delete messages because of: ${error}`)); - }; - - if(message.channel.id === config.staff_channel_ID){ - if(message.member.roles.find("name", role_1) || message.member.roles.find("name", role_2)) - { - if(command === "send") { - const sendCommand = args.join(" "); - - message.delete().catch(O_o=>{}); - - //let json = {"command":sendCommand} - - //console.log(args.length); - if (args != null && args.length > 0) - { - - //let json_string = JSON.stringify(json) - var auth = { 'Authorization': config.post_token} - - var options = {method: 'POST', uri: config.post_url_server_command, body: {"command":sendCommand} ,headers: auth, json: true, resolveWithFullResponse: true, needReadable: true}; - - rp(options).then(function (response) { - //console.log(response); - var myJSONString = JSON.stringify(response.body); - //console.log(myJSONString); - var myEscapedJSONString = myJSONString.replace(/\\r/g, "").replace(/\\n/g, "").replace(/\s\s+/g, " "); - if (myEscapedJSONString === myJSONString) - { - var b = JSON.parse(myEscapedJSONString); - //console.log("this is b:", b); - //console.log(b.message); - message.channel.send("The command was sent to worldserver."); - } else { - var a = JSON.parse(JSON.parse(myEscapedJSONString)); - //console.log("this is a :" ,a) - //console.log(a.message); - message.channel.send("Your command response is: " + a.message); - } - - }).catch(function (err) { - console.log(err) - }) - } - else { - message.channel.send("You can't send emty command"); - }; - }; - } else { message.channel.send("Not enough permission to use this command. Contact Admin or Gamemaster to ban you :smile:"); }; - }; - }); -} - -client.login(config.token); diff --git a/contrib/ServerRelay/windows.vbs b/contrib/ServerRelay/windows.vbs deleted file mode 100644 index e6c791d0441..00000000000 --- a/contrib/ServerRelay/windows.vbs +++ /dev/null @@ -1,3 +0,0 @@ -Set WshShell = CreateObject("WScript.Shell") -WshShell.Run chr(34) & ".\run-server-scripts\windows.bat" & Chr(34), 0 -Set WshShell = Nothing diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt index 02a742169be..db0f3df8450 100644 --- a/dep/CMakeLists.txt +++ b/dep/CMakeLists.txt @@ -31,10 +31,6 @@ if(SERVERS) add_subdirectory(rapidjson) add_subdirectory(efsw) add_subdirectory(protobuf) - - if (WITH_CPR) - add_subdirectory(cpr) - endif(WITH_CPR) endif() if(TOOLS) diff --git a/dep/cpr/.clang-format b/dep/cpr/.clang-format deleted file mode 100644 index 2dda09e912d..00000000000 --- a/dep/cpr/.clang-format +++ /dev/null @@ -1,59 +0,0 @@ ---- -Language: Cpp -# BasedOnStyle: Google -AccessModifierOffset: -2 -AlignAfterOpenBracket: true -AlignEscapedNewlinesLeft: true -AlignOperands: true -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Empty -AlwaysBreakAfterDefinitionReturnType: false -AlwaysBreakTemplateDeclarations: true -AlwaysBreakBeforeMultilineStrings: true -BreakBeforeBinaryOperators: None -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BinPackParameters: true -BinPackArguments: true -ColumnLimit: 100 -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 8 -DerivePointerAlignment: false -ExperimentalAutoDetectBinPacking: false -IndentCaseLabels: true -IndentWrappedFunctionNames: false -IndentFunctionDeclarationAfterType: false -MaxEmptyLinesToKeep: 2 -KeepEmptyLinesAtTheStartOfBlocks: false -NamespaceIndentation: None -PenaltyBreakBeforeFirstCallParameter: 1 -PenaltyBreakComment: 300 -PenaltyBreakString: 1000 -PenaltyBreakFirstLessLess: 120 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Left -SpacesBeforeTrailingComments: 1 -Cpp11BracedListStyle: true -Standard: Auto -IndentWidth: 4 -TabWidth: 8 -UseTab: Never -BreakBeforeBraces: Attach -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpacesInAngles: false -SpaceInEmptyParentheses: false -SpacesInCStyleCastParentheses: false -SpaceAfterCStyleCast: true -SpacesInContainerLiterals: true -SpaceBeforeAssignmentOperators: true -ContinuationIndentWidth: 8 -CommentPragmas: '^ IWYU pragma:' -SpaceBeforeParens: ControlStatements -... diff --git a/dep/cpr/.gitignore b/dep/cpr/.gitignore deleted file mode 100644 index bedd5ade4e5..00000000000 --- a/dep/cpr/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# CMake -CMakeCache.txt -CMakeFiles -Makefile -cmake_install.cmake -install_manifest.txt - -# Custom -build/ - -# Jekyll stuff -_includes/ -_site/ - -# Vim -.ycm_extra_conf.py* diff --git a/dep/cpr/.travis.yml b/dep/cpr/.travis.yml deleted file mode 100644 index 93d471f89ae..00000000000 --- a/dep/cpr/.travis.yml +++ /dev/null @@ -1,125 +0,0 @@ -language: cpp - -sudo: false -cache: ccache - -compiler: clang - -# gcc 4.9 default -addons: &addons - apt: - packages: &packages - - g++-4.9 - - clang-format-3.8 - - python-pip - sources: &sources - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.5 - - llvm-toolchain-precise-3.6 - - llvm-toolchain-precise-3.7 - - llvm-toolchain-precise-3.8 - -env: - global: - - BUILD_CPR_TESTS=ON - - GTEST_SHUFFLE=1 - - USE_SYSTEM_CURL=ON - matrix: - - COMPILER=g++-4.9 CCOMPILER=gcc-4.9 GENERATE_COVERAGE=ON FORMAT_CHECK=ON - -matrix: - include: - # gcc 4.6 - - env: COMPILER=g++-4.6 CCOMPILER=gcc-4.6 - addons: - apt: - packages: g++-4.6 - sources: *sources - - # gcc 4.7 - - env: COMPILER=g++-4.7 CCOMPILER=gcc-4.7 EXTRA_CXXFLAGS=-D_GLIBCXX_USE_NANOSLEEP - addons: - apt: - packages: g++-4.7 - sources: *sources - - # gcc 4.8 - - env: COMPILER=g++-4.8 CCOMPILER=gcc-4.8 - addons: - apt: - packages: g++-4.8 - sources: *sources - - # gcc 5 - - env: COMPILER=g++-5 CCOMPILER=gcc-5 - addons: - apt: - packages: g++-5 - sources: *sources - - # Clang 3.4 - - env: COMPILER=clang++ CCOMPILER=clang LINUX_CLANG=1 - addons: - apt: - packages: clang-3.4 - sources: *sources - - # Clang 3.5 - - env: COMPILER=clang++-3.5 CCOMPILER=clang-3.5 - addons: - apt: - packages: clang-3.5 - sources: *sources - - # Clang 3.6 - - env: COMPILER=clang++-3.6 CCOMPILER=clang-3.6 - addons: - apt: - packages: clang-3.6 - sources: *sources - - # Clang 3.7 - - env: COMPILER=clang++-3.7 CCOMPILER=clang-3.7 - addons: - apt: - packages: clang-3.7 - sources: *sources - - # Clang 3.8 - - env: COMPILER=clang++-3.8 CCOMPILER=clang-3.8 - addons: - apt: - packages: clang-3.8 - sources: *sources - - # Xcode 6.4 - - os: osx - env: COMPILER=clang++ CCOMPILER=clang - osx_image: xcode6.4 - - # Xcode 7 - - os: osx - env: COMPILER=clang++ CCOMPILER=clang - osx_image: xcode7 - allow_failures: - - env: COMPILER=g++-4.6 CCOMPILER=gcc-4.6 - - env: COMPILER=clang++ CCOMPILER=clang LINUX_CLANG=1 - -install: - - if [ "$GENERATE_COVERAGE" == "ON" ]; then pip install --user git+git://github.com/eddyxu/cpp-coveralls.git; fi - -before_script: - - export CXX=$COMPILER CC=$CCOMPILER - - export CXXFLAGS=$EXTRA_CXXFLAGS - - cmake --version - - mkdir build - - cd build - - cmake -LAH .. - -script: - - make -j2 VERBOSE=1 - - ctest -V - - if [ "$FORMAT_CHECK" == "ON" ]; then cd ${TRAVIS_BUILD_DIR} && ./format-check.sh; fi - -after_success: - - if [ "$GENERATE_COVERAGE" == "ON" ]; then cd ${TRAVIS_BUILD_DIR}/build && coveralls -i 'cpr' -i 'include' -e '../include/cpr.h' --root '../' --verbose --gcov-options '\-lp' --gcov 'gcov-4.9'; fi diff --git a/dep/cpr/AUTHORS b/dep/cpr/AUTHORS deleted file mode 100644 index 32eac49266d..00000000000 --- a/dep/cpr/AUTHORS +++ /dev/null @@ -1,32 +0,0 @@ -Adam Nielsen -Andreas Gerstmayr -Anton Lindström -bandzaw -Bob Jansen -Chase Geigle -Danilo Spinella -David E -Don Goodman-Wilson -Eren Okka -Felix Vanorder -Florian Dang -fuchs -Guo Xiao -Himanshu Shekhar -Huu Nguyen -Ivan Smirnov -Josh Leeb-du Toit -Klaus Silveira -Mexus -nabijaczleweli -noh4h_ss -Omer Katz -pravic -Sam Bristow -Sean Chittenden -Shuyu Liang -Simon Ninon -Smiley Barry -Vittorio Romeo -Vladimir Gamalian -xpol diff --git a/dep/cpr/CMakeLists.txt b/dep/cpr/CMakeLists.txt deleted file mode 100644 index ddb107d5e1c..00000000000 --- a/dep/cpr/CMakeLists.txt +++ /dev/null @@ -1,73 +0,0 @@ -cmake_minimum_required(VERSION 2.8.7) - -if(POLICY CMP0048) - # cmake warns if loaded from a min-3.0-required parent dir, so silence the warning: - cmake_policy(SET CMP0048 NEW) -endif() - -# Allow use of project folders for IDEs like Visual Studio, so we -# could organize projects into relevant folders: "cpr", "tests" & "external (libraries)". -# set_property(GLOBAL PROPERTY USE_FOLDERS ON) -# set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake") - -project(cpr CXX) - -if(NOT ${CMAKE_VERSION} LESS 3.2) - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_STANDARD_REQUIRED ON) -else() - message(STATUS "Checking compiler flags for C++11 support.") - # Set C++11 support flags for various compilers - include(CheckCXXCompilerFlag) - check_cxx_compiler_flag("-std=c++11" COMPILER_SUPPORTS_CXX11) - check_cxx_compiler_flag("-std=c++0x" COMPILER_SUPPORTS_CXX0X) - if(COMPILER_SUPPORTS_CXX11) - message(STATUS "C++11 is supported.") - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - endif() - elseif(COMPILER_SUPPORTS_CXX0X) - message(STATUS "C++0x is supported.") - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") - endif() - else() - message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") - endif() -endif() - -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) -set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) - -set(CPR_LIBRARIES cpr CACHE INTERNAL "") -set(CPR_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "") - -macro(cpr_option OPTION_NAME OPTION_TEXT OPTION_DEFAULT) - option(${OPTION_NAME} ${OPTION_TEXT} ${OPTION_DEFAULT}) - if(DEFINED ENV{${OPTION_NAME}}) - # Allow setting the option through an environment variable - set(${OPTION_NAME} $ENV{${OPTION_NAME}}) - endif() - if(${OPTION_NAME}) - add_definitions(-D${OPTION_NAME}) - endif() - message(STATUS " ${OPTION_NAME}: ${${OPTION_NAME}}") -endmacro() - -message(STATUS "C++ Requests CMake Options") -message(STATUS "=======================================================") -cpr_option(USE_SYSTEM_CURL - "If ON, this project will look in the system paths for an installed curl library" OFF) -set(GENERATE_COVERAGE OFF) -cpr_option(CPR_CURL_NOSIGNAL "Set to ON to disable use of signals in libcurl." OFF) -cpr_option(USE_SYSTEM_GTEST - "If ON, this project will look in the system paths for an installed gtest library" OFF) -cpr_option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" OFF) -message(STATUS "=======================================================") - -add_subdirectory(opt) -add_subdirectory(cpr) diff --git a/dep/cpr/CONTRIBUTING.md b/dep/cpr/CONTRIBUTING.md deleted file mode 100644 index abfb97c346e..00000000000 --- a/dep/cpr/CONTRIBUTING.md +++ /dev/null @@ -1,27 +0,0 @@ -# Contributing to C++ Requests - -Please fork this repository and contribute back using [pull requests](https://github.com/whoshuu/cpr/pulls). Features can be requested using [issues](https://github.com/whoshuu/cpr/issues). All code, comments, and critiques are greatly appreciated. - -## Formatting - -To avoid unproductive debates on formatting, this project uses `clang-format` to ensure a consistent style across all source files. Currently, `clang-format` 3.8 is the version of `clang-format` we use. The format file can be found [here](https://github.com/whoshuu/cpr/blob/master/.clang-format). To install `clang-format` on Ubuntu, run this: - -``` -apt-get install clang-format-3.8 -``` - -To install `clang-format` on OS X, run this: - -``` -brew install clang-format -``` - -Note that `brew` might install a later version of `clang-format`, but it should be mostly compatible with what's run on the Travis servers. - -To run `clang-format` on every source file, run this in the root directory: - -``` -./format-check.sh -``` - -This should indicate which files need formatting and also show a diff of the requested changes. More specific usage instructions can be found on the official [LLVM website](http://releases.llvm.org/3.8.0/tools/clang/docs/ClangFormat.html). diff --git a/dep/cpr/LICENSE b/dep/cpr/LICENSE deleted file mode 100644 index d173854dcf9..00000000000 --- a/dep/cpr/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Huu Nguyen - -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. diff --git a/dep/cpr/README.md b/dep/cpr/README.md deleted file mode 100644 index 65ed0214df4..00000000000 --- a/dep/cpr/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# C++ Requests: Curl for People - -[![Build Status](https://travis-ci.org/whoshuu/cpr.svg?branch=master)](https://travis-ci.org/whoshuu/cpr) [![Build status](https://ci.appveyor.com/api/projects/status/imalkp3a6hblpj5y/branch/master?svg=true)](https://ci.appveyor.com/project/whoshuu/cpr/branch/master) [![Coverage Status](https://coveralls.io/repos/whoshuu/cpr/badge.svg?branch=master&service=github)](https://coveralls.io/github/whoshuu/cpr) [![Documentation](https://img.shields.io/badge/documentation-master-brightgreen.svg)](https://whoshuu.github.io/cpr/) - -C++ Requests is a simple wrapper around [libcurl](http://curl.haxx.se/libcurl) inspired by the excellent [Python Requests](https://github.com/kennethreitz/requests) project. - -Despite its name, libcurl's easy interface is anything but, and making mistakes misusing it is a common source of error and frustration. Using the more expressive language facilities of C++11, this library captures the essence of making network calls into a few concise idioms. - -Here's a quick GET request: - -```c++ -#include - -int main(int argc, char** argv) { - auto r = cpr::Get(cpr::Url{"https://api.github.com/repos/whoshuu/cpr/contributors"}, - cpr::Authentication{"user", "pass"}, - cpr::Parameters{{"anon", "true"}, {"key", "value"}}); - r.status_code; // 200 - r.header["content-type"]; // application/json; charset=utf-8 - r.text; // JSON text string -} -``` - -And here's [less functional, more complicated code, without cpr](https://gist.github.com/whoshuu/2dc858b8730079602044). - -## Documentation - -You can find the latest documentation [here](https://whoshuu.github.io/cpr). It's a work in progress, but it should give you a better idea of how to use the library than the [tests](https://github.com/whoshuu/cpr/tree/master/test) currently do. - -## Features - -C++ Requests currently supports: - -* Custom headers -* Url encoded parameters -* Url encoded POST values -* Multipart form POST upload -* File POST upload -* Basic authentication -* Digest authentication -* Timeout specification -* Timeout for low speed connection -* Asynchronous requests -* :cookie: support! -* Proxy support -* Callback interface -* PUT methods -* DELETE methods -* HEAD methods -* OPTIONS methods -* PATCH methods - -## Planned - -Support for the following will be forthcoming (in rough order of implementation priority): - -* [Streamed requests](https://github.com/whoshuu/cpr/issues/25) -* [OpenSSL support](https://github.com/whoshuu/cpr/issues/31) - -and much more! - -## Usage - -For just getting this library up and running, I highly recommend forking the [example project](https://github.com/whoshuu/cpr-example). It's configured with the minimum CMake magic and boilerplate needed to start playing around with networked applications. - -If you already have a project you need to integrate C++ Requests with, the primary way is to use git submodules. Add this repository as a submodule of your root repository: - -```shell -git submodule add git@github.com:whoshuu/cpr.git -OR -git submodule add https://github.com/whoshuu/cpr.git - -git submodule update --init --recursive -``` - -Next, add this subdirectory to your CMakeLists.txt before declaring any targets that might use it: - -```cmake -add_subdirectory(cpr) -``` - -This will produce two important CMake variables, `CPR_INCLUDE_DIRS` and `CPR_LIBRARIES`, which you'll use in the typical way: - -```cmake -include_directories(${CPR_INCLUDE_DIRS}) -target_link_libraries(your_target_name ${CPR_LIBRARIES}) -``` - -and that should do it! Using the submodule method of integrating C++ Requests, there's no need to handle libcurl yourself, all of those dependencies are taken care of for you. - -## Requirements - -The only explicit requirements are: - -* a C++11 compatible compiler such as Clang or GCC. The minimum required version of GCC is unknown, so if anyone has trouble building this library with a specific version of GCC, do let me know -* curl and its development libraries diff --git a/dep/cpr/VERSION b/dep/cpr/VERSION deleted file mode 100644 index f0bb29e7638..00000000000 --- a/dep/cpr/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.3.0 diff --git a/dep/cpr/appveyor.yml b/dep/cpr/appveyor.yml deleted file mode 100644 index 2f88cebe805..00000000000 --- a/dep/cpr/appveyor.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: '1.1.{build}' -configuration: - - RELEASE - - DEBUG -os: Visual Studio 2015 -before_build: - - git submodule update --init --recursive - - set CMAKE_USE_OPENSSL=OFF - - mkdir build - - cd build - - cmake -DCMAKE_BUILD_TYPE=%Configuration% .. -G "Visual Studio 14 2015" -build: - project: C:\projects\cpr\build\cpr.sln -test_script: - - cd C:\projects\cpr\build - - ctest -VV -C %Configuration% diff --git a/dep/cpr/cpr-config.cmake b/dep/cpr/cpr-config.cmake deleted file mode 100644 index 58ab48320bb..00000000000 --- a/dep/cpr/cpr-config.cmake +++ /dev/null @@ -1,26 +0,0 @@ -# - C++ Requests, Curl for People -# This module is a libcurl wrapper written in modern C++. -# It provides an easy, intuitive, and efficient interface to -# a host of networking methods. -# -# Finding this module will define the following variables: -# CPR_FOUND - True if the core library has been found -# CPR_LIBRARIES - Path to the core library archive -# CPR_INCLUDE_DIRS - Path to the include directories. Gives access -# to cpr.h, which must be included in every -# file that uses this interface - -find_path(CPR_INCLUDE_DIR - NAMES cpr.h) - -find_library(CPR_LIBRARY - NAMES cpr - HINTS ${CPR_LIBRARY_ROOT}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(CPR REQUIRED_VARS CPR_LIBRARY CPR_INCLUDE_DIR) - -if(CPR_FOUND) - set(CPR_LIBRARIES ${CPR_LIBRARY}) - set(CPR_INCLUDE_DIRS ${CPR_INCLUDE_DIR}) -endif() diff --git a/dep/cpr/cpr/CMakeLists.txt b/dep/cpr/cpr/CMakeLists.txt deleted file mode 100644 index 9e15255e46a..00000000000 --- a/dep/cpr/cpr/CMakeLists.txt +++ /dev/null @@ -1,56 +0,0 @@ -message(STATUS "Using CURL_INCLUDE_DIRS: ${CURL_INCLUDE_DIRS}.") - -add_library(${CPR_LIBRARIES} STATIC - - # Source files - auth.cpp - cookies.cpp - cprtypes.cpp - digest.cpp - error.cpp - multipart.cpp - parameters.cpp - payload.cpp - proxies.cpp - session.cpp - timeout.cpp - util.cpp - ssl_options.cpp - - # Header files (useful in IDEs) - "${CPR_INCLUDE_DIRS}/cpr/api.h" - "${CPR_INCLUDE_DIRS}/cpr/auth.h" - "${CPR_INCLUDE_DIRS}/cpr/body.h" - "${CPR_INCLUDE_DIRS}/cpr/cookies.h" - "${CPR_INCLUDE_DIRS}/cpr/cpr.h" - "${CPR_INCLUDE_DIRS}/cpr/cprtypes.h" - "${CPR_INCLUDE_DIRS}/cpr/curlholder.h" - "${CPR_INCLUDE_DIRS}/cpr/defines.h" - "${CPR_INCLUDE_DIRS}/cpr/digest.h" - "${CPR_INCLUDE_DIRS}/cpr/error.h" - "${CPR_INCLUDE_DIRS}/cpr/max_redirects.h" - "${CPR_INCLUDE_DIRS}/cpr/multipart.h" - "${CPR_INCLUDE_DIRS}/cpr/parameters.h" - "${CPR_INCLUDE_DIRS}/cpr/payload.h" - "${CPR_INCLUDE_DIRS}/cpr/proxies.h" - "${CPR_INCLUDE_DIRS}/cpr/response.h" - "${CPR_INCLUDE_DIRS}/cpr/session.h" - "${CPR_INCLUDE_DIRS}/cpr/timeout.h" - "${CPR_INCLUDE_DIRS}/cpr/util.h" - "${CPR_INCLUDE_DIRS}/cpr/ssl_options.h") - -message(STATUS "Using CURL_LIBRARIES: ${CURL_LIBRARIES}.") -set_property(TARGET ${CPR_LIBRARIES} PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_libraries(${CPR_LIBRARIES} - ${CURL_LIBRARIES}) - -if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) - target_include_directories(${CPR_LIBRARIES} - PUBLIC - ${CPR_INCLUDE_DIRS} - ${CURL_INCLUDE_DIRS}) -else() - include_directories( - ${CPR_INCLUDE_DIRS} - ${CURL_INCLUDE_DIRS}) -endif() diff --git a/dep/cpr/cpr/auth.cpp b/dep/cpr/cpr/auth.cpp deleted file mode 100644 index ff7c3a9c5b2..00000000000 --- a/dep/cpr/cpr/auth.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "cpr/auth.h" - -namespace cpr { - -const char* Authentication::GetAuthString() const noexcept { - return auth_string_.data(); -} - -} // namespace cpr diff --git a/dep/cpr/cpr/cookies.cpp b/dep/cpr/cpr/cookies.cpp deleted file mode 100644 index 21decd39f4d..00000000000 --- a/dep/cpr/cpr/cookies.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "cpr/cookies.h" - -#include "cpr/util.h" - -namespace cpr { - -Cookies::Cookies(const std::initializer_list>& pairs) - : map_{pairs} {} - -std::string Cookies::GetEncoded() const { - std::stringstream stream; - for (const auto& item : map_) { - stream << cpr::util::urlEncode(item.first) << "="; - // special case version 1 cookies, which can be distinguished by - // beginning and trailing quotes - if (!item.second.empty() && item.second.front() == '"' && item.second.back() == '"') { - stream << item.second; - } else { - stream << cpr::util::urlEncode(item.second); - } - stream << "; "; - } - return stream.str(); -} - -std::string& Cookies::operator[](const std::string& key) { - return map_[key]; -} - -} // namespace cpr diff --git a/dep/cpr/cpr/cprtypes.cpp b/dep/cpr/cpr/cprtypes.cpp deleted file mode 100644 index 4daf6de754e..00000000000 --- a/dep/cpr/cpr/cprtypes.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "cpr/cprtypes.h" - -#include -#include - -namespace cpr { - -bool CaseInsensitiveCompare::operator()(const std::string& a, const std::string& b) const noexcept { - return std::lexicographical_compare( - a.begin(), a.end(), b.begin(), b.end(), - [](unsigned char ac, unsigned char bc) { return std::tolower(ac) < std::tolower(bc); }); -} - -} // namespace cpr diff --git a/dep/cpr/cpr/digest.cpp b/dep/cpr/cpr/digest.cpp deleted file mode 100644 index 252c5d20997..00000000000 --- a/dep/cpr/cpr/digest.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "cpr/digest.h" - -namespace cpr { - -const char* Digest::GetAuthString() const noexcept { - return Authentication::GetAuthString(); -} - -} // namespace cpr diff --git a/dep/cpr/cpr/error.cpp b/dep/cpr/cpr/error.cpp deleted file mode 100644 index 713cb10c113..00000000000 --- a/dep/cpr/cpr/error.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "cpr/error.h" - -#include - -namespace cpr { - -ErrorCode Error::getErrorCodeForCurlError(std::int32_t curl_code) { - switch (curl_code) { - case CURLE_OK: - return ErrorCode::OK; - case CURLE_UNSUPPORTED_PROTOCOL: - return ErrorCode::UNSUPPORTED_PROTOCOL; - case CURLE_URL_MALFORMAT: - return ErrorCode::INVALID_URL_FORMAT; - case CURLE_COULDNT_RESOLVE_PROXY: - return ErrorCode::PROXY_RESOLUTION_FAILURE; - case CURLE_COULDNT_RESOLVE_HOST: - return ErrorCode::HOST_RESOLUTION_FAILURE; - case CURLE_COULDNT_CONNECT: - return ErrorCode::CONNECTION_FAILURE; - case CURLE_OPERATION_TIMEDOUT: - return ErrorCode::OPERATION_TIMEDOUT; - case CURLE_SSL_CONNECT_ERROR: - return ErrorCode::SSL_CONNECT_ERROR; - case CURLE_PEER_FAILED_VERIFICATION: - return ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR; - case CURLE_GOT_NOTHING: - return ErrorCode::EMPTY_RESPONSE; - case CURLE_SSL_ENGINE_NOTFOUND: - return ErrorCode::GENERIC_SSL_ERROR; - case CURLE_SSL_ENGINE_SETFAILED: - return ErrorCode::GENERIC_SSL_ERROR; - case CURLE_SEND_ERROR: - return ErrorCode::NETWORK_SEND_FAILURE; - case CURLE_RECV_ERROR: - return ErrorCode::NETWORK_RECEIVE_ERROR; - case CURLE_SSL_CERTPROBLEM: - return ErrorCode::SSL_LOCAL_CERTIFICATE_ERROR; - case CURLE_SSL_CIPHER: - return ErrorCode::GENERIC_SSL_ERROR; - case CURLE_SSL_CACERT: - return ErrorCode::SSL_CACERT_ERROR; - case CURLE_USE_SSL_FAILED: - return ErrorCode::GENERIC_SSL_ERROR; - case CURLE_SSL_ENGINE_INITFAILED: - return ErrorCode::GENERIC_SSL_ERROR; - case CURLE_SSL_CACERT_BADFILE: - return ErrorCode::SSL_CACERT_ERROR; - case CURLE_SSL_SHUTDOWN_FAILED: - return ErrorCode::GENERIC_SSL_ERROR; - case CURLE_SSL_CRL_BADFILE: - return ErrorCode::SSL_CACERT_ERROR; - case CURLE_SSL_ISSUER_ERROR: - return ErrorCode::SSL_CACERT_ERROR; - case CURLE_TOO_MANY_REDIRECTS: - return ErrorCode::OK; - default: - return ErrorCode::INTERNAL_ERROR; - } -} - -} // namespace cpr diff --git a/dep/cpr/cpr/multipart.cpp b/dep/cpr/cpr/multipart.cpp deleted file mode 100644 index c2e030add22..00000000000 --- a/dep/cpr/cpr/multipart.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "cpr/multipart.h" - -namespace cpr { - -Multipart::Multipart(const std::initializer_list& parts) : parts{parts} {} - -} // namespace cpr diff --git a/dep/cpr/cpr/parameters.cpp b/dep/cpr/cpr/parameters.cpp deleted file mode 100644 index 1adb5100810..00000000000 --- a/dep/cpr/cpr/parameters.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "cpr/parameters.h" - -#include -#include - -#include "cpr/util.h" - -namespace cpr { - -Parameters::Parameters(const std::initializer_list& parameters) { - for (const auto& parameter : parameters) { - AddParameter(parameter); - } -} - -void Parameters::AddParameter(const Parameter& parameter) { - if (!content.empty()) { - content += "&"; - } - - auto escapedKey = cpr::util::urlEncode(parameter.key); - if (parameter.value.empty()) { - content += escapedKey; - } else { - auto escapedValue = cpr::util::urlEncode(parameter.value); - content += escapedKey + "=" + escapedValue; - } -} - -} // namespace cpr diff --git a/dep/cpr/cpr/payload.cpp b/dep/cpr/cpr/payload.cpp deleted file mode 100644 index de7e8cc4e75..00000000000 --- a/dep/cpr/cpr/payload.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "cpr/payload.h" - -#include -#include - -#include "cpr/util.h" - -namespace cpr { - -Payload::Payload(const std::initializer_list& pairs) : Payload(begin(pairs), end(pairs)) {} - -void Payload::AddPair(const Pair& pair) { - if (!content.empty()) { - content += "&"; - } - auto escaped = cpr::util::urlEncode(pair.value); - content += pair.key + "=" + escaped; -} - -} // namespace cpr diff --git a/dep/cpr/cpr/proxies.cpp b/dep/cpr/cpr/proxies.cpp deleted file mode 100644 index 446f7d7659a..00000000000 --- a/dep/cpr/cpr/proxies.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "cpr/proxies.h" - -#include -#include -#include -#include - -namespace cpr { - -Proxies::Proxies(const std::initializer_list>& hosts) - : hosts_{hosts} {} - -bool Proxies::has(const std::string& protocol) const { - return hosts_.count(protocol) > 0; -} - -const std::string& Proxies::operator[](const std::string& protocol) { - return hosts_[protocol]; -} - -} // namespace cpr diff --git a/dep/cpr/cpr/session.cpp b/dep/cpr/cpr/session.cpp deleted file mode 100644 index bb53280bf6c..00000000000 --- a/dep/cpr/cpr/session.cpp +++ /dev/null @@ -1,477 +0,0 @@ -#include "cpr/session.h" - -#include -#include -#include -#define CURL_STATICLIB -#include - -#include "cpr/curlholder.h" -#include "cpr/util.h" - -namespace cpr { - -class Session::Impl { - public: - Impl(); - - void SetUrl(const Url& url); - void SetParameters(const Parameters& parameters); - void SetParameters(Parameters&& parameters); - void SetHeader(const Header& header); - void SetTimeout(const Timeout& timeout); - void SetAuth(const Authentication& auth); - void SetDigest(const Digest& auth); - void SetPayload(Payload&& payload); - void SetPayload(const Payload& payload); - void SetProxies(Proxies&& proxies); - void SetProxies(const Proxies& proxies); - void SetMultipart(Multipart&& multipart); - void SetMultipart(const Multipart& multipart); - void SetRedirect(const bool& redirect); - void SetMaxRedirects(const MaxRedirects& max_redirects); - void SetCookies(const Cookies& cookies); - void SetBody(Body&& body); - void SetBody(const Body& body); - void SetLowSpeed(const LowSpeed& low_speed); - void SetVerifySsl(const VerifySsl& verify); - - Response Delete(); - Response Get(); - Response Head(); - Response Options(); - Response Patch(); - Response Post(); - Response Put(); - - private: - std::unique_ptr> curl_; - Url url_; - Parameters parameters_; - Proxies proxies_; - - Response makeRequest(CURL* curl); - static void freeHolder(CurlHolder* holder); - static CurlHolder* newHolder(); -}; - -Session::Impl::Impl() { - curl_ = std::unique_ptr>(newHolder(), - &Impl::freeHolder); - auto curl = curl_->handle; - if (curl) { - // Set up some sensible defaults - auto version_info = curl_version_info(CURLVERSION_NOW); - auto version = std::string{"curl/"} + std::string{version_info->version}; - curl_easy_setopt(curl, CURLOPT_USERAGENT, version.data()); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_->error); - curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); -#ifdef CPR_CURL_NOSIGNAL - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); -#endif -#if LIBCURL_VERSION_MAJOR >= 7 -#if LIBCURL_VERSION_MINOR >= 25 -#if LIBCURL_VERSION_PATCH >= 0 - curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); -#endif -#endif -#endif - } -} - -void Session::Impl::freeHolder(CurlHolder* holder) { - curl_easy_cleanup(holder->handle); - curl_slist_free_all(holder->chunk); - curl_formfree(holder->formpost); - delete holder; -} - -CurlHolder* Session::Impl::newHolder() { - CurlHolder* holder = new CurlHolder(); - holder->handle = curl_easy_init(); - holder->chunk = NULL; - holder->formpost = NULL; - return holder; -} - -void Session::Impl::SetUrl(const Url& url) { - url_ = url; -} - -void Session::Impl::SetParameters(const Parameters& parameters) { - parameters_ = parameters; -} - -void Session::Impl::SetParameters(Parameters&& parameters) { - parameters_ = std::move(parameters); -} - -void Session::Impl::SetHeader(const Header& header) { - auto curl = curl_->handle; - if (curl) { - struct curl_slist* chunk = NULL; - for (auto item = header.cbegin(); item != header.cend(); ++item) { - auto header_string = std::string{item->first}; - if (item->second.empty()) { - header_string += ";"; - } else { - header_string += ": " + item->second; - } - - auto temp = curl_slist_append(chunk, header_string.data()); - if (temp) { - chunk = temp; - } - } - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); - - curl_slist_free_all(curl_->chunk); - curl_->chunk = chunk; - } -} - -void Session::Impl::SetTimeout(const Timeout& timeout) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout.Milliseconds()); - } -} - -void Session::Impl::SetAuth(const Authentication& auth) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - curl_easy_setopt(curl, CURLOPT_USERPWD, auth.GetAuthString()); - } -} - -void Session::Impl::SetDigest(const Digest& auth) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); - curl_easy_setopt(curl, CURLOPT_USERPWD, auth.GetAuthString()); - } -} - -void Session::Impl::SetPayload(Payload&& payload) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, payload.content.length()); - curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, payload.content.data()); - } -} - -void Session::Impl::SetPayload(const Payload& payload) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, payload.content.length()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.content.data()); - } -} - -void Session::Impl::SetProxies(const Proxies& proxies) { - proxies_ = proxies; -} - -void Session::Impl::SetProxies(Proxies&& proxies) { - proxies_ = std::move(proxies); -} - -void Session::Impl::SetMultipart(Multipart&& multipart) { - auto curl = curl_->handle; - if (curl) { - struct curl_httppost* formpost = NULL; - struct curl_httppost* lastptr = NULL; - - for (auto& part : multipart.parts) { - std::vector formdata; - formdata.push_back({CURLFORM_COPYNAME, part.name.data()}); - if (part.is_buffer) { - formdata.push_back({CURLFORM_BUFFER, part.value.data()}); - formdata.push_back( - {CURLFORM_COPYCONTENTS, reinterpret_cast(part.data)}); - formdata.push_back( - {CURLFORM_CONTENTSLENGTH, reinterpret_cast(part.datalen)}); - } else if (part.is_file) { - formdata.push_back({CURLFORM_FILE, part.value.data()}); - } else { - formdata.push_back({CURLFORM_COPYCONTENTS, part.value.data()}); - } - if (!part.content_type.empty()) { - formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.data()}); - } - formdata.push_back({CURLFORM_END, nullptr}); - curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END); - } - curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); - - curl_formfree(curl_->formpost); - curl_->formpost = formpost; - } -} - -void Session::Impl::SetMultipart(const Multipart& multipart) { - auto curl = curl_->handle; - if (curl) { - struct curl_httppost* formpost = NULL; - struct curl_httppost* lastptr = NULL; - - for (auto& part : multipart.parts) { - std::vector formdata; - formdata.push_back({CURLFORM_PTRNAME, part.name.data()}); - if (part.is_buffer) { - formdata.push_back({CURLFORM_BUFFER, part.value.data()}); - formdata.push_back({CURLFORM_BUFFERPTR, reinterpret_cast(part.data)}); - formdata.push_back( - {CURLFORM_BUFFERLENGTH, reinterpret_cast(part.datalen)}); - } else if (part.is_file) { - formdata.push_back({CURLFORM_FILE, part.value.data()}); - } else { - formdata.push_back({CURLFORM_PTRCONTENTS, part.value.data()}); - } - if (!part.content_type.empty()) { - formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.data()}); - } - formdata.push_back({CURLFORM_END, nullptr}); - curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END); - } - curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); - - curl_formfree(curl_->formpost); - curl_->formpost = formpost; - } -} - -void Session::Impl::SetRedirect(const bool& redirect) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, std::int32_t(redirect)); - } -} - -void Session::Impl::SetMaxRedirects(const MaxRedirects& max_redirects) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_redirects.number_of_redirects); - } -} - -void Session::Impl::SetCookies(const Cookies& cookies) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_COOKIELIST, "ALL"); - curl_easy_setopt(curl, CURLOPT_COOKIE, cookies.GetEncoded().data()); - } -} - -void Session::Impl::SetBody(Body&& body) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length()); - curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, body.data()); - } -} - -void Session::Impl::SetBody(const Body& body) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.data()); - } -} - -void Session::Impl::SetLowSpeed(const LowSpeed& low_speed) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, low_speed.limit); - curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, low_speed.time); - } -} - -void Session::Impl::SetVerifySsl(const VerifySsl& verify) { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, verify ? 1L : 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, verify ? 2L : 0L); - } -} - -Response Session::Impl::Delete() { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_HTTPGET, 0L); - curl_easy_setopt(curl, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); - } - - return makeRequest(curl); -} - -Response Session::Impl::Get() { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); - } - - return makeRequest(curl); -} - -Response Session::Impl::Head() { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL); - curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); - } - - return makeRequest(curl); -} - -Response Session::Impl::Options() { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "OPTIONS"); - } - - return makeRequest(curl); -} - -Response Session::Impl::Patch() { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH"); - } - - return makeRequest(curl); -} - -Response Session::Impl::Post() { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); - } - - return makeRequest(curl); -} - -Response Session::Impl::Put() { - auto curl = curl_->handle; - if (curl) { - curl_easy_setopt(curl, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); - } - - return makeRequest(curl); -} - -Response Session::Impl::makeRequest(CURL* curl) { - if (!parameters_.content.empty()) { - Url new_url{url_ + "?" + parameters_.content}; - curl_easy_setopt(curl, CURLOPT_URL, new_url.data()); - } else { - curl_easy_setopt(curl, CURLOPT_URL, url_.data()); - } - - auto protocol = url_.substr(0, url_.find(':')); - if (proxies_.has(protocol)) { - curl_easy_setopt(curl, CURLOPT_PROXY, proxies_[protocol].data()); - } else { - curl_easy_setopt(curl, CURLOPT_PROXY, ""); - } - - curl_->error[0] = '\0'; - - std::string response_string; - std::string header_string; - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cpr::util::writeFunction); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string); - curl_easy_setopt(curl, CURLOPT_HEADERDATA, &header_string); - - auto curl_error = curl_easy_perform(curl); - - char* raw_url; - long response_code; - double elapsed; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &elapsed); - curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &raw_url); - - Cookies cookies; - struct curl_slist* raw_cookies; - curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &raw_cookies); - for (struct curl_slist* nc = raw_cookies; nc; nc = nc->next) { - auto tokens = cpr::util::split(nc->data, '\t'); - auto value = tokens.back(); - tokens.pop_back(); - cookies[tokens.back()] = value; - } - curl_slist_free_all(raw_cookies); - - return Response{static_cast(response_code), - std::move(response_string), - cpr::util::parseHeader(header_string), - std::move(raw_url), - elapsed, - std::move(cookies), - Error(curl_error, curl_->error)}; -} - -// clang-format off -Session::Session() : pimpl_{ new Impl{} } {} -Session::~Session() {} -void Session::SetUrl(const Url& url) { pimpl_->SetUrl(url); } -void Session::SetParameters(const Parameters& parameters) { pimpl_->SetParameters(parameters); } -void Session::SetParameters(Parameters&& parameters) { pimpl_->SetParameters(std::move(parameters)); } -void Session::SetHeader(const Header& header) { pimpl_->SetHeader(header); } -void Session::SetTimeout(const Timeout& timeout) { pimpl_->SetTimeout(timeout); } -void Session::SetAuth(const Authentication& auth) { pimpl_->SetAuth(auth); } -void Session::SetDigest(const Digest& auth) { pimpl_->SetDigest(auth); } -void Session::SetPayload(const Payload& payload) { pimpl_->SetPayload(payload); } -void Session::SetPayload(Payload&& payload) { pimpl_->SetPayload(std::move(payload)); } -void Session::SetProxies(const Proxies& proxies) { pimpl_->SetProxies(proxies); } -void Session::SetProxies(Proxies&& proxies) { pimpl_->SetProxies(std::move(proxies)); } -void Session::SetMultipart(const Multipart& multipart) { pimpl_->SetMultipart(multipart); } -void Session::SetMultipart(Multipart&& multipart) { pimpl_->SetMultipart(std::move(multipart)); } -void Session::SetRedirect(const bool& redirect) { pimpl_->SetRedirect(redirect); } -void Session::SetMaxRedirects(const MaxRedirects& max_redirects) { pimpl_->SetMaxRedirects(max_redirects); } -void Session::SetCookies(const Cookies& cookies) { pimpl_->SetCookies(cookies); } -void Session::SetBody(const Body& body) { pimpl_->SetBody(body); } -void Session::SetBody(Body&& body) { pimpl_->SetBody(std::move(body)); } -void Session::SetLowSpeed(const LowSpeed& low_speed) { pimpl_->SetLowSpeed(low_speed); } -void Session::SetVerifySsl(const VerifySsl& verify) { pimpl_->SetVerifySsl(verify); } -void Session::SetOption(const Url& url) { pimpl_->SetUrl(url); } -void Session::SetOption(const Parameters& parameters) { pimpl_->SetParameters(parameters); } -void Session::SetOption(Parameters&& parameters) { pimpl_->SetParameters(std::move(parameters)); } -void Session::SetOption(const Header& header) { pimpl_->SetHeader(header); } -void Session::SetOption(const Timeout& timeout) { pimpl_->SetTimeout(timeout); } -void Session::SetOption(const Authentication& auth) { pimpl_->SetAuth(auth); } -void Session::SetOption(const Digest& auth) { pimpl_->SetDigest(auth); } -void Session::SetOption(const Payload& payload) { pimpl_->SetPayload(payload); } -void Session::SetOption(Payload&& payload) { pimpl_->SetPayload(std::move(payload)); } -void Session::SetOption(const Proxies& proxies) { pimpl_->SetProxies(proxies); } -void Session::SetOption(Proxies&& proxies) { pimpl_->SetProxies(std::move(proxies)); } -void Session::SetOption(const Multipart& multipart) { pimpl_->SetMultipart(multipart); } -void Session::SetOption(Multipart&& multipart) { pimpl_->SetMultipart(std::move(multipart)); } -void Session::SetOption(const bool& redirect) { pimpl_->SetRedirect(redirect); } -void Session::SetOption(const MaxRedirects& max_redirects) { pimpl_->SetMaxRedirects(max_redirects); } -void Session::SetOption(const Cookies& cookies) { pimpl_->SetCookies(cookies); } -void Session::SetOption(const Body& body) { pimpl_->SetBody(body); } -void Session::SetOption(Body&& body) { pimpl_->SetBody(std::move(body)); } -void Session::SetOption(const LowSpeed& low_speed) { pimpl_->SetLowSpeed(low_speed); } -void Session::SetOption(const VerifySsl& verify) { pimpl_->SetVerifySsl(verify); } -Response Session::Delete() { return pimpl_->Delete(); } -Response Session::Get() { return pimpl_->Get(); } -Response Session::Head() { return pimpl_->Head(); } -Response Session::Options() { return pimpl_->Options(); } -Response Session::Patch() { return pimpl_->Patch(); } -Response Session::Post() { return pimpl_->Post(); } -Response Session::Put() { return pimpl_->Put(); } -// clang-format on - -} // namespace cpr diff --git a/dep/cpr/cpr/ssl_options.cpp b/dep/cpr/cpr/ssl_options.cpp deleted file mode 100644 index 79d77f75b21..00000000000 --- a/dep/cpr/cpr/ssl_options.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "cpr/ssl_options.h" - -namespace cpr { - -VerifySsl::VerifySsl(bool verify) : verify_{verify} {} - -VerifySsl::operator bool() const { - return verify_; -} - -} // namespace cpr diff --git a/dep/cpr/cpr/timeout.cpp b/dep/cpr/cpr/timeout.cpp deleted file mode 100644 index 259eb96c979..00000000000 --- a/dep/cpr/cpr/timeout.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "cpr/timeout.h" - -#include -#include -#include -#include - -namespace cpr { - -long Timeout::Milliseconds() const { - static_assert(std::is_same::value, - "Following casting expects milliseconds."); - - if (ms.count() > std::numeric_limits::max()) { - throw std::overflow_error("cpr::Timeout: timeout value overflow: " + - std::to_string(ms.count()) + " ms."); - } - if (ms.count() < std::numeric_limits::min()) { - throw std::underflow_error("cpr::Timeout: timeout value underflow: " + - std::to_string(ms.count()) + " ms."); - } - - return static_cast(ms.count()); -} - -} // namespace cpr diff --git a/dep/cpr/cpr/util.cpp b/dep/cpr/cpr/util.cpp deleted file mode 100644 index 683295331de..00000000000 --- a/dep/cpr/cpr/util.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "cpr/util.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace cpr { -namespace util { - -Header parseHeader(const std::string& headers) { - Header header; - std::vector lines; - std::istringstream stream(headers); - { - std::string line; - while (std::getline(stream, line, '\n')) { - lines.push_back(line); - } - } - - for (auto& line : lines) { - if (line.substr(0, 5) == "HTTP/") { - header.clear(); - } - - if (line.length() > 0) { - auto found = line.find(":"); - if (found != std::string::npos) { - auto value = line.substr(found + 1); - value.erase(0, value.find_first_not_of("\t ")); - value.resize(std::min(value.size(), value.find_last_not_of("\t\n\r ") + 1)); - header[line.substr(0, found)] = value; - } - } - } - - return header; -} - -std::vector split(const std::string& to_split, char delimiter) { - std::vector tokens; - - std::stringstream stream(to_split); - std::string item; - while (std::getline(stream, item, delimiter)) { - tokens.push_back(item); - } - - return tokens; -} - -size_t writeFunction(void* ptr, size_t size, size_t nmemb, std::string* data) { - data->append(static_cast(ptr), size * nmemb); - return size * nmemb; -} - -std::string urlEncode(const std::string& value) { - std::ostringstream escaped; - escaped.fill('0'); - escaped << std::hex; - - for (auto i = value.cbegin(), n = value.cend(); i != n; ++i) { - std::string::value_type c = (*i); - // Keep alphanumeric and other accepted characters intact - if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { - escaped << c; - continue; - } - // Any other characters are percent-encoded - escaped << '%' << std::setw(2) << std::int32_t(static_cast(c)); - } - - return escaped.str(); -} - -} // namespace util -} // namespace cpr diff --git a/dep/cpr/format-check.sh b/dep/cpr/format-check.sh deleted file mode 100644 index 45a6ca14134..00000000000 --- a/dep/cpr/format-check.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - - -which clang-format-3.8 -if [ $? -eq 0 ] -then - format_command=clang-format-3.8 -else - format_command=clang-format -fi - -format_error_exists=0 - -for DIRECTORY in include cpr -do - for FILE in $DIRECTORY/*.h $DIRECTORY/*.cpp - do - if [ -e $FILE ] - then - $format_command -style=file -output-replacements-xml $FILE | grep -c "/dev/null - if [ $? -ne 1 ] - then - echo "Please run clang-format on $FILE:" - $format_command -style=file $FILE | diff - $FILE - format_error_exists=1 - fi - fi - done -done - -if [ $format_error_exists -ne 0 ] -then - echo "Some files require formatting" - exit 1 -fi - -exit 0 diff --git a/dep/cpr/include/cpr/api.h b/dep/cpr/include/cpr/api.h deleted file mode 100644 index 43699d93184..00000000000 --- a/dep/cpr/include/cpr/api.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef CPR_API_H -#define CPR_API_H - -#include -#include -#include - -#include "cpr/auth.h" -#include "cpr/cprtypes.h" -#include "cpr/defines.h" -#include "cpr/digest.h" -#include "cpr/multipart.h" -#include "cpr/payload.h" -#include "cpr/response.h" -#include "cpr/session.h" - -namespace cpr { - -using AsyncResponse = std::future; - -namespace priv { - -template -void set_option(Session& session, T&& t) { - session.SetOption(CPR_FWD(t)); -} - -template -void set_option(Session& session, T&& t, Ts&&... ts) { - set_option(session, CPR_FWD(t)); - set_option(session, CPR_FWD(ts)...); -} - -} // namespace priv - -// Get methods -template -Response Get(Ts&&... ts) { - Session session; - priv::set_option(session, CPR_FWD(ts)...); - return session.Get(); -} - -// Get async methods -template -AsyncResponse GetAsync(Ts... ts) { - return std::async(std::launch::async, [](Ts... ts) { return Get(std::move(ts)...); }, - std::move(ts)...); -} - -// Get callback methods -template -auto GetCallback(Then then, Ts... ts) -> std::future { - return std::async(std::launch::async, [](Then then, Ts... ts) { - return then(Get(std::move(ts)...)); - }, std::move(then), std::move(ts)...); -} - -// Post methods -template -Response Post(Ts&&... ts) { - Session session; - priv::set_option(session, CPR_FWD(ts)...); - return session.Post(); -} - -// Post async methods -template -AsyncResponse PostAsync(Ts... ts) { - return std::async(std::launch::async, [](Ts... ts) { return Post(std::move(ts)...); }, - std::move(ts)...); -} - -// Post callback methods -template -auto PostCallback(Then then, Ts... ts) -> std::future { - return std::async(std::launch::async, [](Then then, Ts... ts) { - return then(Post(std::move(ts)...)); - }, std::move(then), std::move(ts)...); -} - -// Put methods -template -Response Put(Ts&&... ts) { - Session session; - priv::set_option(session, CPR_FWD(ts)...); - return session.Put(); -} - -// Put async methods -template -AsyncResponse PutAsync(Ts... ts) { - return std::async(std::launch::async, [](Ts... ts) { return Put(std::move(ts)...); }, - std::move(ts)...); -} - -// Put callback methods -template -auto PutCallback(Then then, Ts... ts) -> std::future { - return std::async(std::launch::async, [](Then then, Ts... ts) { - return then(Put(std::move(ts)...)); - }, std::move(then), std::move(ts)...); -} - -// Head methods -template -Response Head(Ts&&... ts) { - Session session; - priv::set_option(session, CPR_FWD(ts)...); - return session.Head(); -} - -// Head async methods -template -AsyncResponse HeadAsync(Ts... ts) { - return std::async(std::launch::async, [](Ts... ts) { return Head(std::move(ts)...); }, - std::move(ts)...); -} - -// Head callback methods -template -auto HeadCallback(Then then, Ts... ts) -> std::future { - return std::async(std::launch::async, [](Then then, Ts... ts) { - return then(Head(std::move(ts)...)); - }, std::move(then), std::move(ts)...); -} - -// Delete methods -template -Response Delete(Ts&&... ts) { - Session session; - priv::set_option(session, CPR_FWD(ts)...); - return session.Delete(); -} - -// Delete async methods -template -AsyncResponse DeleteAsync(Ts... ts) { - return std::async(std::launch::async, [](Ts... ts) { return Delete(std::move(ts)...); }, - std::move(ts)...); -} - -// Delete callback methods -template -auto DeleteCallback(Then then, Ts... ts) -> std::future { - return std::async(std::launch::async, [](Then then, Ts... ts) { - return then(Delete(std::move(ts)...)); - }, std::move(then), std::move(ts)...); -} - -// Options methods -template -Response Options(Ts&&... ts) { - Session session; - priv::set_option(session, CPR_FWD(ts)...); - return session.Options(); -} - -// Options async methods -template -AsyncResponse OptionsAsync(Ts... ts) { - return std::async(std::launch::async, [](Ts... ts) { return Options(std::move(ts)...); }, - std::move(ts)...); -} - -// Options callback methods -template -auto OptionsCallback(Then then, Ts... ts) - -> std::future { - return std::async(std::launch::async, [](Then then, Ts... ts) { - return then(Options(std::move(ts)...)); - }, std::move(then), std::move(ts)...); -} - -// Patch methods -template -Response Patch(Ts&&... ts) { - Session session; - priv::set_option(session, CPR_FWD(ts)...); - return session.Patch(); -} - -// Patch async methods -template -AsyncResponse PatchAsync(Ts... ts) { - return std::async(std::launch::async, [](Ts... ts) { return Patch(std::move(ts)...); }, - std::move(ts)...); -} - -// Patch callback methods -template -auto PatchCallback(Then then, Ts... ts) -> std::future { - return std::async(std::launch::async, [](Then then, Ts... ts) { - return then(Patch(std::move(ts)...)); - }, std::move(then), std::move(ts)...); -} - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/auth.h b/dep/cpr/include/cpr/auth.h deleted file mode 100644 index 9673164cacb..00000000000 --- a/dep/cpr/include/cpr/auth.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CPR_AUTH_H -#define CPR_AUTH_H - -#include - -#include "cpr/defines.h" - -namespace cpr { - -class Authentication { - public: - template - Authentication(UserType&& username, PassType&& password) - : username_{CPR_FWD(username)}, password_{CPR_FWD(password)}, - auth_string_{username_ + ":" + password_} {} - - const char* GetAuthString() const noexcept; - - private: - std::string username_; - std::string password_; - std::string auth_string_; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/body.h b/dep/cpr/include/cpr/body.h deleted file mode 100644 index 34c5b367880..00000000000 --- a/dep/cpr/include/cpr/body.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef CPR_BODY_H -#define CPR_BODY_H - -#include - -#include -#include - -#include "cpr/defines.h" - -namespace cpr { - -class Body : public std::string { - public: - Body() = default; - Body(const Body& rhs) = default; - Body(Body&& rhs) = default; - Body& operator=(const Body& rhs) = default; - Body& operator=(Body&& rhs) = default; - explicit Body(const char* raw_string) : std::string(raw_string) {} - explicit Body(const char* raw_string, size_t length) : std::string(raw_string, length) {} - explicit Body(size_t to_fill, char character) : std::string(to_fill, character) {} - explicit Body(const std::string& std_string) : std::string(std_string) {} - explicit Body(const std::string& std_string, size_t position, size_t length = std::string::npos) - : std::string(std_string, position, length) {} - explicit Body(std::string&& std_string) : std::string(std::move(std_string)) {} - explicit Body(std::initializer_list il) : std::string(il) {} - template - explicit Body(InputIterator first, InputIterator last) - : std::string(first, last) {} -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/cookies.h b/dep/cpr/include/cpr/cookies.h deleted file mode 100644 index c0c32510670..00000000000 --- a/dep/cpr/include/cpr/cookies.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CPR_COOKIES_H -#define CPR_COOKIES_H - -#include -#include -#include -#include - -namespace cpr { - -class Cookies { - public: - Cookies() {} - Cookies(const std::initializer_list>& pairs); - Cookies(const std::map& map) : map_{map} {} - - std::string& operator[](const std::string& key); - std::string GetEncoded() const; - - private: - std::map map_; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/cpr.h b/dep/cpr/include/cpr/cpr.h deleted file mode 100644 index 9fcc3fd2a90..00000000000 --- a/dep/cpr/include/cpr/cpr.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CPR_CPR_H -#define CPR_CPR_H - -#include "cpr/api.h" -#include "cpr/auth.h" -#include "cpr/cprtypes.h" -#include "cpr/response.h" -#include "cpr/session.h" - -#endif diff --git a/dep/cpr/include/cpr/cprtypes.h b/dep/cpr/include/cpr/cprtypes.h deleted file mode 100644 index 37e6ff4d563..00000000000 --- a/dep/cpr/include/cpr/cprtypes.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CPR_CPR_TYPES_H -#define CPR_CPR_TYPES_H - -#include -#include - -namespace cpr { - -struct CaseInsensitiveCompare { - bool operator()(const std::string& a, const std::string& b) const noexcept; -}; - -using Header = std::map; -using Url = std::string; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/curlholder.h b/dep/cpr/include/cpr/curlholder.h deleted file mode 100644 index 2f9825e4568..00000000000 --- a/dep/cpr/include/cpr/curlholder.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CPR_CURL_HOLDER_H -#define CPR_CURL_HOLDER_H - -#include - -#include - -namespace cpr { - -struct CurlHolder { - CURL* handle; - struct curl_slist* chunk; - struct curl_httppost* formpost; - char error[CURL_ERROR_SIZE]; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/defines.h b/dep/cpr/include/cpr/defines.h deleted file mode 100644 index b08575c264a..00000000000 --- a/dep/cpr/include/cpr/defines.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CPR_DEFINES_H -#define CPR_DEFINES_H - -#include - -#define CPR_FWD(...) ::std::forward(__VA_ARGS__) - -#endif diff --git a/dep/cpr/include/cpr/digest.h b/dep/cpr/include/cpr/digest.h deleted file mode 100644 index 0a8e68a0491..00000000000 --- a/dep/cpr/include/cpr/digest.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CPR_DIGEST_H -#define CPR_DIGEST_H - -#include "cpr/auth.h" -#include "cpr/defines.h" - -namespace cpr { - -class Digest : public Authentication { - public: - template - Digest(UserType&& username, PassType&& password) - : Authentication{CPR_FWD(username), CPR_FWD(password)} {} - - const char* GetAuthString() const noexcept; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/error.h b/dep/cpr/include/cpr/error.h deleted file mode 100644 index 7cf8d99b527..00000000000 --- a/dep/cpr/include/cpr/error.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef CPR_ERROR_H -#define CPR_ERROR_H - -#include -#include - -#include "cpr/cprtypes.h" -#include "cpr/defines.h" - -namespace cpr { - -enum class ErrorCode { - OK = 0, - CONNECTION_FAILURE, - EMPTY_RESPONSE, - HOST_RESOLUTION_FAILURE, - INTERNAL_ERROR, - INVALID_URL_FORMAT, - NETWORK_RECEIVE_ERROR, - NETWORK_SEND_FAILURE, - OPERATION_TIMEDOUT, - PROXY_RESOLUTION_FAILURE, - SSL_CONNECT_ERROR, - SSL_LOCAL_CERTIFICATE_ERROR, - SSL_REMOTE_CERTIFICATE_ERROR, - SSL_CACERT_ERROR, - GENERIC_SSL_ERROR, - UNSUPPORTED_PROTOCOL, - UNKNOWN_ERROR = 1000, -}; - -class Error { - public: - Error() : code{ErrorCode::OK} {} - - template - Error(const std::int32_t& curl_code, TextType&& p_error_message) - : code{getErrorCodeForCurlError(curl_code)}, message{CPR_FWD(p_error_message)} {} - - explicit operator bool() const { - return code != ErrorCode::OK; - } - - ErrorCode code; - std::string message; - - private: - static ErrorCode getErrorCodeForCurlError(std::int32_t curl_code); -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/low_speed.h b/dep/cpr/include/cpr/low_speed.h deleted file mode 100644 index 394a43825ee..00000000000 --- a/dep/cpr/include/cpr/low_speed.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CPR_LOW_SPEED_H -#define CPR_LOW_SPEED_H - -#include - -namespace cpr { - -class LowSpeed { - public: - LowSpeed(const std::int32_t limit, const std::int32_t time) : limit(limit), time(time) {} - - std::int32_t limit; - std::int32_t time; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/max_redirects.h b/dep/cpr/include/cpr/max_redirects.h deleted file mode 100644 index 4d3dea4d38e..00000000000 --- a/dep/cpr/include/cpr/max_redirects.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CPR_MAX_REDIRECTS_H -#define CPR_MAX_REDIRECTS_H - -#include - -namespace cpr { - -class MaxRedirects { - public: - explicit MaxRedirects(const std::int32_t number_of_redirects) - : number_of_redirects(number_of_redirects) {} - - std::int32_t number_of_redirects; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/multipart.h b/dep/cpr/include/cpr/multipart.h deleted file mode 100644 index ba2c9ab7987..00000000000 --- a/dep/cpr/include/cpr/multipart.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef CPR_MULTIPART_H -#define CPR_MULTIPART_H - -#include -#include -#include -#include -#include - -#include "cpr/defines.h" - -namespace cpr { - -struct File { - template - explicit File(StringType&& filepath) - : filepath{CPR_FWD(filepath)} {} - std::string filepath; -}; - -struct Buffer { - typedef const unsigned char* data_t; - - template - explicit Buffer(Iterator begin, Iterator end, StringType&& filename) - : data{reinterpret_cast(&(*begin))}, - datalen{static_cast(std::distance(begin, end))}, - filename{CPR_FWD(filename)} { - is_random_access_iterator(begin, end); - static_assert(sizeof(*begin) == 1, "only byte buffers can be used"); - } - - template - typename std::enable_if::iterator_category, - std::random_access_iterator_tag>::value>::type - is_random_access_iterator(Iterator /* begin */, Iterator /* end */ ) {} - - data_t data; - unsigned long datalen; - std::string filename; -}; - -struct Part { - Part(const std::string& name, const std::string& value, const std::string& content_type = {}) - : name{name}, value{value}, content_type{content_type}, is_file{false}, - is_buffer{false} {} - Part(const std::string& name, const std::int32_t& value, const std::string& content_type = {}) - : name{name}, value{std::to_string(value)}, content_type{content_type}, is_file{false}, - is_buffer{false} {} - Part(const std::string& name, const File& file, const std::string& content_type = {}) - : name{name}, value{file.filepath}, content_type{content_type}, is_file{true}, - is_buffer{false} {} - Part(const std::string& name, const Buffer& buffer, const std::string& content_type = {}) - : name{name}, value{buffer.filename}, content_type{content_type}, data{buffer.data}, - datalen{buffer.datalen}, is_file{false}, is_buffer{true} {} - - std::string name; - std::string value; - std::string content_type; - Buffer::data_t data; - unsigned long datalen; - bool is_file; - bool is_buffer; -}; - -class Multipart { - public: - Multipart(const std::initializer_list& parts); - - std::vector parts; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/parameters.h b/dep/cpr/include/cpr/parameters.h deleted file mode 100644 index 4e36685fd75..00000000000 --- a/dep/cpr/include/cpr/parameters.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef CPR_PARAMETERS_H -#define CPR_PARAMETERS_H - -#include -#include -#include - -#include "cpr/defines.h" - -namespace cpr { - -struct Parameter { - template - Parameter(KeyType&& key, ValueType&& value) - : key{CPR_FWD(key)}, value{CPR_FWD(value)} {} - - std::string key; - std::string value; -}; - -class Parameters { - public: - Parameters() = default; - Parameters(const std::initializer_list& parameters); - - void AddParameter(const Parameter& parameter); - - std::string content; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/payload.h b/dep/cpr/include/cpr/payload.h deleted file mode 100644 index a183a618888..00000000000 --- a/dep/cpr/include/cpr/payload.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CPR_PAYLOAD_H -#define CPR_PAYLOAD_H - -#include -#include -#include -#include - -#include "cpr/defines.h" - -namespace cpr { - -struct Pair { - template ::value, bool>::type = true> - Pair(KeyType&& p_key, ValueType&& p_value) - : key{CPR_FWD(p_key)}, value{CPR_FWD(p_value)} {} - template - Pair(KeyType&& p_key, const std::int32_t& p_value) - : key{CPR_FWD(p_key)}, value{std::to_string(p_value)} {} - - std::string key; - std::string value; -}; - -class Payload { - public: - template - Payload(const It begin, const It end) { - for (It pair = begin; pair != end; ++pair) { - AddPair(*pair); - } - } - Payload(const std::initializer_list& pairs); - - void AddPair(const Pair& pair); - - std::string content; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/proxies.h b/dep/cpr/include/cpr/proxies.h deleted file mode 100644 index ba68fa5ca93..00000000000 --- a/dep/cpr/include/cpr/proxies.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CPR_PROXIES_H -#define CPR_PROXIES_H - -#include -#include -#include -#include - -namespace cpr { - -class Proxies { - public: - Proxies() {} - Proxies(const std::initializer_list>& hosts); - - bool has(const std::string& protocol) const; - const std::string& operator[](const std::string& protocol); - - private: - std::map hosts_; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/response.h b/dep/cpr/include/cpr/response.h deleted file mode 100644 index c3b0c3c81ec..00000000000 --- a/dep/cpr/include/cpr/response.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CPR_RESPONSE_H -#define CPR_RESPONSE_H - -#include -#include - -#include "cpr/cookies.h" -#include "cpr/cprtypes.h" -#include "cpr/defines.h" -#include "cpr/error.h" - -namespace cpr { - -class Response { - public: - Response() = default; - - template - Response(const std::int32_t& p_status_code, TextType&& p_text, HeaderType&& p_header, UrlType&& p_url, - const double& p_elapsed, CookiesType&& p_cookies = Cookies{}, - ErrorType&& p_error = Error{}) - : status_code{p_status_code}, text{CPR_FWD(p_text)}, header{CPR_FWD(p_header)}, - url{CPR_FWD(p_url)}, elapsed{p_elapsed}, cookies{CPR_FWD(p_cookies)}, - error{CPR_FWD(p_error)} {} - - std::int32_t status_code; - std::string text; - Header header; - Url url; - double elapsed; - Cookies cookies; - Error error; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/session.h b/dep/cpr/include/cpr/session.h deleted file mode 100644 index bf6b67171d9..00000000000 --- a/dep/cpr/include/cpr/session.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef CPR_SESSION_H -#define CPR_SESSION_H - -#include -#include - -#include "cpr/auth.h" -#include "cpr/body.h" -#include "cpr/cookies.h" -#include "cpr/cprtypes.h" -#include "cpr/digest.h" -#include "cpr/max_redirects.h" -#include "cpr/multipart.h" -#include "cpr/parameters.h" -#include "cpr/payload.h" -#include "cpr/proxies.h" -#include "cpr/response.h" -#include "cpr/timeout.h" -#include "cpr/low_speed.h" -#include "cpr/ssl_options.h" - -namespace cpr { - -class Session { - public: - Session(); - ~Session(); - - void SetUrl(const Url& url); - void SetParameters(const Parameters& parameters); - void SetParameters(Parameters&& parameters); - void SetHeader(const Header& header); - void SetTimeout(const Timeout& timeout); - void SetAuth(const Authentication& auth); - void SetDigest(const Digest& auth); - void SetPayload(Payload&& payload); - void SetPayload(const Payload& payload); - void SetProxies(Proxies&& proxies); - void SetProxies(const Proxies& proxies); - void SetMultipart(Multipart&& multipart); - void SetMultipart(const Multipart& multipart); - void SetRedirect(const bool& redirect); - void SetMaxRedirects(const MaxRedirects& max_redirects); - void SetCookies(const Cookies& cookies); - void SetBody(Body&& body); - void SetBody(const Body& body); - void SetLowSpeed(const LowSpeed& low_speed); - void SetVerifySsl(const VerifySsl& verify); - - // Used in templated functions - void SetOption(const Url& url); - void SetOption(const Parameters& parameters); - void SetOption(Parameters&& parameters); - void SetOption(const Header& header); - void SetOption(const Timeout& timeout); - void SetOption(const Authentication& auth); - void SetOption(const Digest& auth); - void SetOption(Payload&& payload); - void SetOption(const Payload& payload); - void SetOption(Proxies&& proxies); - void SetOption(const Proxies& proxies); - void SetOption(Multipart&& multipart); - void SetOption(const Multipart& multipart); - void SetOption(const bool& redirect); - void SetOption(const MaxRedirects& max_redirects); - void SetOption(const Cookies& cookies); - void SetOption(Body&& body); - void SetOption(const Body& body); - void SetOption(const LowSpeed& low_speed); - void SetOption(const VerifySsl& verify); - - Response Delete(); - Response Get(); - Response Head(); - Response Options(); - Response Patch(); - Response Post(); - Response Put(); - - private: - class Impl; - std::unique_ptr pimpl_; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/ssl_options.h b/dep/cpr/include/cpr/ssl_options.h deleted file mode 100644 index ebee0dff573..00000000000 --- a/dep/cpr/include/cpr/ssl_options.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CPR_SSLOPTIONS_H -#define CPR_SSLOPTIONS_H - -namespace cpr { - -class VerifySsl { - public: - VerifySsl() {} - VerifySsl(bool verify); - - operator bool() const; - - private: - bool verify_ = true; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/timeout.h b/dep/cpr/include/cpr/timeout.h deleted file mode 100644 index 6e6fb79381e..00000000000 --- a/dep/cpr/include/cpr/timeout.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CPR_TIMEOUT_H -#define CPR_TIMEOUT_H - -#include -#include - -namespace cpr { - -class Timeout { - public: - Timeout(const std::chrono::milliseconds& duration) : ms{duration} {} - Timeout(const std::int32_t& milliseconds) : Timeout{std::chrono::milliseconds(milliseconds)} {} - - long Milliseconds() const; - - std::chrono::milliseconds ms; -}; - -} // namespace cpr - -#endif diff --git a/dep/cpr/include/cpr/util.h b/dep/cpr/include/cpr/util.h deleted file mode 100644 index 7660d383819..00000000000 --- a/dep/cpr/include/cpr/util.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CPR_UTIL_H -#define CPR_UTIL_H - -#include -#include - -#include "cpr/cprtypes.h" - -namespace cpr { -namespace util { - -Header parseHeader(const std::string& headers); -size_t writeFunction(void* ptr, size_t size, size_t nmemb, std::string* data); -std::vector split(const std::string& to_split, char delimiter); -std::string urlEncode(const std::string& response); - -} // namespace util -} // namespace cpr - -#endif diff --git a/dep/cpr/opt/CMakeLists.txt b/dep/cpr/opt/CMakeLists.txt deleted file mode 100644 index 130532f1a4a..00000000000 --- a/dep/cpr/opt/CMakeLists.txt +++ /dev/null @@ -1,118 +0,0 @@ -macro(set_cache_variable VAR_NAME VAR_DESCRIPTION) - set(${VAR_NAME} ${${VAR_NAME}} CACHE INTERNAL ${VAR_DESCRIPTION}) - message(STATUS "Set ${VAR_NAME} to ${${VAR_NAME}}.") -endmacro() - - -# Code coverage - -if(BUILD_CPR_TESTS AND GENERATE_COVERAGE) - set(CMAKE_BUILD_TYPE COVERAGE CACHE INTERNAL "Coverage enabled build") - message(STATUS "Enabling gcov support") - if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(COVERAGE_FLAG "--coverage") - endif() - set(CMAKE_CXX_FLAGS_COVERAGE - "-g -O0 ${COVERAGE_FLAG} -fprofile-arcs -ftest-coverage" - CACHE STRING "Flags used by the C++ compiler during coverage builds." - FORCE) - set(CMAKE_C_FLAGS_COVERAGE - "-g -O0 ${COVERAGE_FLAG} -fprofile-arcs -ftest-coverage" - CACHE STRING "Flags used by the C compiler during coverage builds." - FORCE) - set(CMAKE_EXE_LINKER_FLAGS_COVERAGE - "" - CACHE STRING "Flags used for linking binaries during coverage builds." - FORCE) - set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE - "" - CACHE STRING "Flags used by the shared libraries linker during coverage builds." - FORCE) - mark_as_advanced( - CMAKE_CXX_FLAGS_COVERAGE - CMAKE_C_FLAGS_COVERAGE - CMAKE_EXE_LINKER_FLAGS_COVERAGE - CMAKE_SHARED_LINKER_FLAGS_COVERAGE) -endif() - - -# Curl configuration - -if(USE_SYSTEM_CURL) - find_package(CURL) -endif() -if(NOT USE_SYSTEM_CURL OR NOT CURL_FOUND) - message(STATUS "Not using system Curl, using built-in curl project instead.") - set(BUILD_TESTING OFF) - set(BUILD_CURL_EXE OFF) - add_subdirectory(curl) - set(CURL_FOUND TRUE) - set(CURL_LIBRARIES libcurl) - set(CURL_INCLUDE_DIRS - ${CURL_SOURCE_DIR}/include - ${CURL_BINARY_DIR}/include/curl) - - # Group under the "external" project folder in IDEs such as Visual Studio. - if(BUILD_CURL_EXE) - set_property(TARGET curl PROPERTY FOLDER "external") - endif() - - set_property(TARGET libcurl PROPERTY FOLDER "external") - set_property(TARGET libcurl PROPERTY POSITION_INDEPENDENT_CODE ON) -endif() - -set_cache_variable(CURL_FOUND "Set if libcurl is found or built") -set_cache_variable(CURL_LIBRARIES "Location of libcurl") -set_cache_variable(CURL_INCLUDE_DIRS "Location of curl include files") - - -# GTest configuration - -if(BUILD_CPR_TESTS) - if(USE_SYSTEM_GTEST) - find_package(GTest) - endif() - if(NOT USE_SYSTEM_GTEST OR NOT GTEST_FOUND) - message(STATUS "Not using system gtest, using built-in googletest project instead.") - if(MSVC) - # By default, GTest compiles on Windows in CRT static linkage mode. We use this - # variable to force it into using the CRT in dynamic linkage (DLL), just as CPR - # does. - set(gtest_force_shared_crt ON CACHE BOOL "Force gtest to use the shared c runtime") - endif() - add_subdirectory(googletest) - set(GTEST_FOUND TRUE) - set(GTEST_LIBRARIES gtest) - set(GTEST_MAIN_LIBRARIES gtest_main) - set(GTEST_BOTH_LIBRARIES gtest gtest_main) - set(GTEST_INCLUDE_DIRS ${gtest_SOURCE_DIR}/include) - - # Group under the "tests/gtest" project folder in IDEs such as Visual Studio. - set_property(TARGET gtest PROPERTY FOLDER "tests/gtest") - set_property(TARGET gtest_main PROPERTY FOLDER "tests/gtest") - endif() - - set_cache_variable(GTEST_FOUND "Set if libgtest was found or built") - set_cache_variable(GTEST_LIBRARIES "Location of libgtest") - set_cache_variable(GTEST_MAIN_LIBRARIES "Location of libgtest-main") - set_cache_variable(GTEST_BOTH_LIBRARIES "Location of both gtest libraries") - set_cache_variable(GTEST_INCLUDE_DIRS "Location of gtest include files") -endif() - - -# Mongoose configuration - -if(BUILD_CPR_TESTS) - message(STATUS "Building mongoose project for test support.") - add_subdirectory(mongoose) - set(MONGOOSE_FOUND TRUE) - set(MONGOOSE_LIBRARIES mongoose) - set(MONGOOSE_INCLUDE_DIRS ${mongoose_SOURCE_DIR}) - - set_cache_variable(MONGOOSE_FOUND "Set if libmongoose was found or built") - set_cache_variable(MONGOOSE_LIBRARIES "Location of libmongoose") - set_cache_variable(MONGOOSE_INCLUDE_DIRS "Location of mongoose include files") - - # Group under the "external" project folder in IDEs such as Visual Studio. - set_property(TARGET mongoose PROPERTY FOLDER "external") -endif() diff --git a/dep/cpr/opt/curl/.dir-locals.el b/dep/cpr/opt/curl/.dir-locals.el deleted file mode 100644 index ed91b128c55..00000000000 --- a/dep/cpr/opt/curl/.dir-locals.el +++ /dev/null @@ -1,10 +0,0 @@ -;;; Directory Local Variables -;;; See Info node `(emacs) Directory Variables' for more information. - -((nil . ((indent-tabs-mode . nil) - (show-trailing-whitespace . t))) - (c-mode . ((c-basic-offset . 2) - )) - (c++-mode . ((c-basic-offset . 2) - )) - ) diff --git a/dep/cpr/opt/curl/.gitattributes b/dep/cpr/opt/curl/.gitattributes deleted file mode 100644 index 429f8cde05a..00000000000 --- a/dep/cpr/opt/curl/.gitattributes +++ /dev/null @@ -1,7 +0,0 @@ -*.dsw -crlf -buildconf eol=lf -configure.ac eol=lf -*.m4 eol=lf -*.in eol=lf -*.am eol=lf -*.sh eol=lf diff --git a/dep/cpr/opt/curl/.github/CONTRIBUTING.md b/dep/cpr/opt/curl/.github/CONTRIBUTING.md deleted file mode 100644 index bce89b4442a..00000000000 --- a/dep/cpr/opt/curl/.github/CONTRIBUTING.md +++ /dev/null @@ -1,23 +0,0 @@ -How to contribute to curl -========================= - -Join the community ------------------- - - 1. Click 'watch' on the github repo - - 2. Subscribe to the suitable [mailing lists](https://curl.haxx.se/mail/) - -Read [CONTRIBUTE](../docs/CONTRIBUTE.md) ---------------------------------------- - -Send your suggestions using one of these methods: -------------------------------------------------- - - 1. in a mail to the mailing list - - 2. as a [pull request](https://github.com/curl/curl/pulls) - - 3. as an [issue](https://github.com/curl/curl/issues) - -/ The curl team! diff --git a/dep/cpr/opt/curl/.github/ISSUE_TEMPLATE b/dep/cpr/opt/curl/.github/ISSUE_TEMPLATE deleted file mode 100644 index a705e79e518..00000000000 --- a/dep/cpr/opt/curl/.github/ISSUE_TEMPLATE +++ /dev/null @@ -1,16 +0,0 @@ - - -### I did this - -### I expected the following - -### curl/libcurl version - -[curl -V output] - -### operating system diff --git a/dep/cpr/opt/curl/.github/stale.yml b/dep/cpr/opt/curl/.github/stale.yml deleted file mode 100644 index 9bcd4eb1d59..00000000000 --- a/dep/cpr/opt/curl/.github/stale.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 180 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 14 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security -# Label to use when marking an issue as stale -staleLabel: stale -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/dep/cpr/opt/curl/.gitignore b/dep/cpr/opt/curl/.gitignore deleted file mode 100644 index e567b38c475..00000000000 --- a/dep/cpr/opt/curl/.gitignore +++ /dev/null @@ -1,58 +0,0 @@ -*.asc -*.dll -*.exe -*.exp -*.la -*.lib -*.lo -*.o -*.obj -*.pdb -*.pyc -*~ -.*.sw? -.cproject -.deps -.dirstamp -.libs -.project -.settings -/.vs -/build/ -/builds/ -__pycache__ -CHANGES.dist -Debug -INSTALL -Makefile -Makefile.in -Release -TAGS -aclocal.m4 -aclocal.m4.bak -autom4te.cache -compile -config.cache -config.guess -config.log -config.status -config.sub -configure -curl-*.tar.bz2 -curl-*.tar.gz -curl-*.tar.xz -curl-*.zip -curl-config -depcomp -install-sh -libcurl.pc -libtool -ltmain.sh -missing -mkinstalldirs -tags -test-driver -scripts/_curl -curl_fuzzer -curl_fuzzer_seed_corpus.zip -libstandaloneengine.a diff --git a/dep/cpr/opt/curl/CHANGES b/dep/cpr/opt/curl/CHANGES deleted file mode 100644 index 4d13ef69635..00000000000 --- a/dep/cpr/opt/curl/CHANGES +++ /dev/null @@ -1,7 +0,0 @@ -See https://curl.haxx.se/changes.html for the edited and human readable online -version of what has changed over the years in different curl releases. - -Generate a CHANGES file like the one present in every release like this: - -$ git log --pretty=fuller --no-color --date=short --decorate=full | \ - ./scripts/log2changes.pl diff --git a/dep/cpr/opt/curl/CMake/CMakeConfigurableFile.in b/dep/cpr/opt/curl/CMake/CMakeConfigurableFile.in deleted file mode 100644 index 4cf74a12bb7..00000000000 --- a/dep/cpr/opt/curl/CMake/CMakeConfigurableFile.in +++ /dev/null @@ -1,2 +0,0 @@ -@CMAKE_CONFIGURABLE_FILE_CONTENT@ - diff --git a/dep/cpr/opt/curl/CMake/CurlSymbolHiding.cmake b/dep/cpr/opt/curl/CMake/CurlSymbolHiding.cmake deleted file mode 100644 index 9f7d2963384..00000000000 --- a/dep/cpr/opt/curl/CMake/CurlSymbolHiding.cmake +++ /dev/null @@ -1,61 +0,0 @@ -include(CheckCSourceCompiles) - -option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) -mark_as_advanced(CURL_HIDDEN_SYMBOLS) - -if(CURL_HIDDEN_SYMBOLS) - set(SUPPORTS_SYMBOL_HIDING FALSE) - - if(CMAKE_C_COMPILER_ID MATCHES "Clang") - set(SUPPORTS_SYMBOL_HIDING TRUE) - set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") - set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") - elseif(CMAKE_COMPILER_IS_GNUCC) - if(NOT CMAKE_VERSION VERSION_LESS 2.8.10) - set(GCC_VERSION ${CMAKE_C_COMPILER_VERSION}) - else() - execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion - OUTPUT_VARIABLE GCC_VERSION) - endif() - if(NOT GCC_VERSION VERSION_LESS 3.4) - # note: this is considered buggy prior to 4.0 but the autotools don't care, so let's ignore that fact - set(SUPPORTS_SYMBOL_HIDING TRUE) - set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") - set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") - endif() - elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0) - set(SUPPORTS_SYMBOL_HIDING TRUE) - set(_SYMBOL_EXTERN "__global") - set(_CFLAG_SYMBOLS_HIDE "-xldscope=hidden") - elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0) - # note: this should probably just check for version 9.1.045 but I'm not 100% sure - # so let's to it the same way autotools do. - set(SUPPORTS_SYMBOL_HIDING TRUE) - set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") - set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") - check_c_source_compiles("#include - int main (void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug) - if(NOT _no_bug) - set(SUPPORTS_SYMBOL_HIDING FALSE) - set(_SYMBOL_EXTERN "") - set(_CFLAG_SYMBOLS_HIDE "") - endif() - elseif(MSVC) - set(SUPPORTS_SYMBOL_HIDING TRUE) - endif() - - set(HIDES_CURL_PRIVATE_SYMBOLS ${SUPPORTS_SYMBOL_HIDING}) -elseif(MSVC) - if(NOT CMAKE_VERSION VERSION_LESS 3.7) - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) #present since 3.4.3 but broken - set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) - else() - message(WARNING "Hiding private symbols regardless CURL_HIDDEN_SYMBOLS being disabled.") - set(HIDES_CURL_PRIVATE_SYMBOLS TRUE) - endif() -elseif() - set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) -endif() - -set(CURL_CFLAG_SYMBOLS_HIDE ${_CFLAG_SYMBOLS_HIDE}) -set(CURL_EXTERN_SYMBOL ${_SYMBOL_EXTERN}) diff --git a/dep/cpr/opt/curl/CMake/CurlTests.c b/dep/cpr/opt/curl/CMake/CurlTests.c deleted file mode 100644 index bc36c8ef7dd..00000000000 --- a/dep/cpr/opt/curl/CMake/CurlTests.c +++ /dev/null @@ -1,551 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#ifdef TIME_WITH_SYS_TIME -/* Time with sys/time test */ - -#include -#include -#include - -int -main () -{ -if ((struct tm *) 0) -return 0; - ; - return 0; -} - -#endif - -#ifdef HAVE_FCNTL_O_NONBLOCK - -/* headers for FCNTL_O_NONBLOCK test */ -#include -#include -#include -/* */ -#if defined(sun) || defined(__sun__) || \ - defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# if defined(__SVR4) || defined(__srv4__) -# define PLATFORM_SOLARIS -# else -# define PLATFORM_SUNOS4 -# endif -#endif -#if (defined(_AIX) || defined(__xlC__)) && !defined(_AIX41) -# define PLATFORM_AIX_V3 -#endif -/* */ -#if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3) || defined(__BEOS__) -#error "O_NONBLOCK does not work on this platform" -#endif - -int -main () -{ - /* O_NONBLOCK source test */ - int flags = 0; - if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK)) - return 1; - return 0; -} -#endif - -/* tests for gethostbyaddr_r or gethostbyname_r */ -#if defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \ - defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \ - defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \ - defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \ - defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \ - defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) -# define _REENTRANT - /* no idea whether _REENTRANT is always set, just invent a new flag */ -# define TEST_GETHOSTBYFOO_REENTRANT -#endif -#if defined(HAVE_GETHOSTBYADDR_R_5) || \ - defined(HAVE_GETHOSTBYADDR_R_7) || \ - defined(HAVE_GETHOSTBYADDR_R_8) || \ - defined(HAVE_GETHOSTBYNAME_R_3) || \ - defined(HAVE_GETHOSTBYNAME_R_5) || \ - defined(HAVE_GETHOSTBYNAME_R_6) || \ - defined(TEST_GETHOSTBYFOO_REENTRANT) -#include -#include -int main(void) -{ - char *address = "example.com"; - int length = 0; - int type = 0; - struct hostent h; - int rc = 0; -#if defined(HAVE_GETHOSTBYADDR_R_5) || \ - defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \ - \ - defined(HAVE_GETHOSTBYNAME_R_3) || \ - defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) - struct hostent_data hdata; -#elif defined(HAVE_GETHOSTBYADDR_R_7) || \ - defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \ - defined(HAVE_GETHOSTBYADDR_R_8) || \ - defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \ - \ - defined(HAVE_GETHOSTBYNAME_R_5) || \ - defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \ - defined(HAVE_GETHOSTBYNAME_R_6) || \ - defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) - char buffer[8192]; - int h_errnop; - struct hostent *hp; -#endif - -#ifndef gethostbyaddr_r - (void)gethostbyaddr_r; -#endif - -#if defined(HAVE_GETHOSTBYADDR_R_5) || \ - defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) - rc = gethostbyaddr_r(address, length, type, &h, &hdata); -#elif defined(HAVE_GETHOSTBYADDR_R_7) || \ - defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) - hp = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &h_errnop); - (void)hp; -#elif defined(HAVE_GETHOSTBYADDR_R_8) || \ - defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) - rc = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &hp, &h_errnop); -#endif - -#if defined(HAVE_GETHOSTBYNAME_R_3) || \ - defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) - rc = gethostbyname_r(address, &h, &hdata); -#elif defined(HAVE_GETHOSTBYNAME_R_5) || \ - defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) - rc = gethostbyname_r(address, &h, buffer, 8192, &h_errnop); - (void)hp; /* not used for test */ -#elif defined(HAVE_GETHOSTBYNAME_R_6) || \ - defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) - rc = gethostbyname_r(address, &h, buffer, 8192, &hp, &h_errnop); -#endif - - (void)length; - (void)type; - (void)rc; - return 0; -} -#endif - -#ifdef HAVE_SOCKLEN_T -#ifdef _WIN32 -#include -#else -#include -#include -#endif -int -main () -{ -if ((socklen_t *) 0) - return 0; -if (sizeof (socklen_t)) - return 0; - ; - return 0; -} -#endif -#ifdef HAVE_IN_ADDR_T -#include -#include -#include - -int -main () -{ -if ((in_addr_t *) 0) - return 0; -if (sizeof (in_addr_t)) - return 0; - ; - return 0; -} -#endif - -#ifdef HAVE_BOOL_T -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_STDBOOL_H -#include -#endif -int -main () -{ -if (sizeof (bool *) ) - return 0; - ; - return 0; -} -#endif - -#ifdef STDC_HEADERS -#include -#include -#include -#include -int main() { return 0; } -#endif -#ifdef RETSIGTYPE_TEST -#include -#include -#ifdef signal -# undef signal -#endif -#ifdef __cplusplus -extern "C" void (*signal (int, void (*)(int)))(int); -#else -void (*signal ()) (); -#endif - -int -main () -{ - return 0; -} -#endif -#ifdef HAVE_INET_NTOA_R_DECL -#include - -typedef void (*func_type)(); - -int main() -{ -#ifndef inet_ntoa_r - func_type func; - func = (func_type)inet_ntoa_r; -#endif - return 0; -} -#endif -#ifdef HAVE_INET_NTOA_R_DECL_REENTRANT -#define _REENTRANT -#include - -typedef void (*func_type)(); - -int main() -{ -#ifndef inet_ntoa_r - func_type func; - func = (func_type)&inet_ntoa_r; -#endif - return 0; -} -#endif -#ifdef HAVE_GETADDRINFO -#include -#include -#include - -int main(void) { - struct addrinfo hints, *ai; - int error; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; -#ifndef getaddrinfo - (void)getaddrinfo; -#endif - error = getaddrinfo("127.0.0.1", "8080", &hints, &ai); - if (error) { - return 1; - } - return 0; -} -#endif -#ifdef HAVE_FILE_OFFSET_BITS -#ifdef _FILE_OFFSET_BITS -#undef _FILE_OFFSET_BITS -#endif -#define _FILE_OFFSET_BITS 64 -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int main () { ; return 0; } -#endif -#ifdef HAVE_IOCTLSOCKET -/* includes start */ -#ifdef HAVE_WINDOWS_H -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# ifdef HAVE_WINSOCK2_H -# include -# else -# ifdef HAVE_WINSOCK_H -# include -# endif -# endif -#endif - -int -main () -{ - -/* ioctlsocket source code */ - int socket; - unsigned long flags = ioctlsocket(socket, FIONBIO, &flags); - - ; - return 0; -} - -#endif -#ifdef HAVE_IOCTLSOCKET_CAMEL -/* includes start */ -#ifdef HAVE_WINDOWS_H -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# ifdef HAVE_WINSOCK2_H -# include -# else -# ifdef HAVE_WINSOCK_H -# include -# endif -# endif -#endif - -int -main () -{ - -/* IoctlSocket source code */ - if(0 != IoctlSocket(0, 0, 0)) - return 1; - ; - return 0; -} -#endif -#ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO -/* includes start */ -#ifdef HAVE_WINDOWS_H -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# ifdef HAVE_WINSOCK2_H -# include -# else -# ifdef HAVE_WINSOCK_H -# include -# endif -# endif -#endif - -int -main () -{ - -/* IoctlSocket source code */ - long flags = 0; - if(0 != ioctlsocket(0, FIONBIO, &flags)) - return 1; - ; - return 0; -} -#endif -#ifdef HAVE_IOCTLSOCKET_FIONBIO -/* includes start */ -#ifdef HAVE_WINDOWS_H -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# ifdef HAVE_WINSOCK2_H -# include -# else -# ifdef HAVE_WINSOCK_H -# include -# endif -# endif -#endif - -int -main () -{ - - int flags = 0; - if(0 != ioctlsocket(0, FIONBIO, &flags)) - return 1; - - ; - return 0; -} -#endif -#ifdef HAVE_IOCTL_FIONBIO -/* headers for FIONBIO test */ -/* includes start */ -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#ifdef HAVE_STROPTS_H -# include -#endif - -int -main () -{ - - int flags = 0; - if(0 != ioctl(0, FIONBIO, &flags)) - return 1; - - ; - return 0; -} -#endif -#ifdef HAVE_IOCTL_SIOCGIFADDR -/* headers for FIONBIO test */ -/* includes start */ -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#ifdef HAVE_STROPTS_H -# include -#endif -#include - -int -main () -{ - struct ifreq ifr; - if(0 != ioctl(0, SIOCGIFADDR, &ifr)) - return 1; - - ; - return 0; -} -#endif -#ifdef HAVE_SETSOCKOPT_SO_NONBLOCK -/* includes start */ -#ifdef HAVE_WINDOWS_H -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# ifdef HAVE_WINSOCK2_H -# include -# else -# ifdef HAVE_WINSOCK_H -# include -# endif -# endif -#endif -/* includes start */ -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -/* includes end */ - -int -main () -{ - if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0)) - return 1; - ; - return 0; -} -#endif -#ifdef HAVE_GLIBC_STRERROR_R -#include -#include -int -main () { - char buffer[1024]; /* big enough to play with */ - char *string = - strerror_r(EACCES, buffer, sizeof(buffer)); - /* this should've returned a string */ - if(!string || !string[0]) - return 99; - return 0; -} -#endif -#ifdef HAVE_POSIX_STRERROR_R -#include -#include -int -main () { - char buffer[1024]; /* big enough to play with */ - int error = - strerror_r(EACCES, buffer, sizeof(buffer)); - /* This should've returned zero, and written an error string in the - buffer.*/ - if(!buffer[0] || error) - return 99; - return 0; -} -#endif -#ifdef HAVE_FSETXATTR_6 -#include /* header from libc, not from libattr */ -int -main() { - fsetxattr(0, 0, 0, 0, 0, 0); - return 0; -} -#endif -#ifdef HAVE_FSETXATTR_5 -#include /* header from libc, not from libattr */ -int -main() { - fsetxattr(0, 0, 0, 0, 0); - return 0; -} -#endif diff --git a/dep/cpr/opt/curl/CMake/FindCARES.cmake b/dep/cpr/opt/curl/CMake/FindCARES.cmake deleted file mode 100644 index c4ab5f13220..00000000000 --- a/dep/cpr/opt/curl/CMake/FindCARES.cmake +++ /dev/null @@ -1,42 +0,0 @@ -# - Find c-ares -# Find the c-ares includes and library -# This module defines -# CARES_INCLUDE_DIR, where to find ares.h, etc. -# CARES_LIBRARIES, the libraries needed to use c-ares. -# CARES_FOUND, If false, do not try to use c-ares. -# also defined, but not for general use are -# CARES_LIBRARY, where to find the c-ares library. - -FIND_PATH(CARES_INCLUDE_DIR ares.h - /usr/local/include - /usr/include - ) - -SET(CARES_NAMES ${CARES_NAMES} cares) -FIND_LIBRARY(CARES_LIBRARY - NAMES ${CARES_NAMES} - PATHS /usr/lib /usr/local/lib - ) - -IF (CARES_LIBRARY AND CARES_INCLUDE_DIR) - SET(CARES_LIBRARIES ${CARES_LIBRARY}) - SET(CARES_FOUND "YES") -ELSE (CARES_LIBRARY AND CARES_INCLUDE_DIR) - SET(CARES_FOUND "NO") -ENDIF (CARES_LIBRARY AND CARES_INCLUDE_DIR) - - -IF (CARES_FOUND) - IF (NOT CARES_FIND_QUIETLY) - MESSAGE(STATUS "Found c-ares: ${CARES_LIBRARIES}") - ENDIF (NOT CARES_FIND_QUIETLY) -ELSE (CARES_FOUND) - IF (CARES_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find c-ares library") - ENDIF (CARES_FIND_REQUIRED) -ENDIF (CARES_FOUND) - -MARK_AS_ADVANCED( - CARES_LIBRARY - CARES_INCLUDE_DIR - ) diff --git a/dep/cpr/opt/curl/CMake/FindGSS.cmake b/dep/cpr/opt/curl/CMake/FindGSS.cmake deleted file mode 100644 index 60dcb73c923..00000000000 --- a/dep/cpr/opt/curl/CMake/FindGSS.cmake +++ /dev/null @@ -1,289 +0,0 @@ -# - Try to find the GSS Kerberos library -# Once done this will define -# -# GSS_ROOT_DIR - Set this variable to the root installation of GSS -# -# Read-Only variables: -# GSS_FOUND - system has the Heimdal library -# GSS_FLAVOUR - "MIT" or "Heimdal" if anything found. -# GSS_INCLUDE_DIR - the Heimdal include directory -# GSS_LIBRARIES - The libraries needed to use GSS -# GSS_LINK_DIRECTORIES - Directories to add to linker search path -# GSS_LINKER_FLAGS - Additional linker flags -# GSS_COMPILER_FLAGS - Additional compiler flags -# GSS_VERSION - This is set to version advertised by pkg-config or read from manifest. -# In case the library is found but no version info available it'll be set to "unknown" - -set(_MIT_MODNAME mit-krb5-gssapi) -set(_HEIMDAL_MODNAME heimdal-gssapi) - -include(CheckIncludeFile) -include(CheckIncludeFiles) -include(CheckTypeSize) - -set(_GSS_ROOT_HINTS - "${GSS_ROOT_DIR}" - "$ENV{GSS_ROOT_DIR}" -) - -# try to find library using system pkg-config if user didn't specify root dir -if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}") - if(UNIX) - find_package(PkgConfig QUIET) - pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME}) - list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}") - elseif(WIN32) - list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]") - endif() -endif() - -if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach. - find_file(_GSS_CONFIGURE_SCRIPT - NAMES - "krb5-config" - HINTS - ${_GSS_ROOT_HINTS} - PATH_SUFFIXES - bin - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - ) - - # if not found in user-supplied directories, maybe system knows better - find_file(_GSS_CONFIGURE_SCRIPT - NAMES - "krb5-config" - PATH_SUFFIXES - bin - ) - - if(_GSS_CONFIGURE_SCRIPT) - execute_process( - COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi" - OUTPUT_VARIABLE _GSS_CFLAGS - RESULT_VARIABLE _GSS_CONFIGURE_FAILED - ) -message(STATUS "CFLAGS: ${_GSS_CFLAGS}") - if(NOT _GSS_CONFIGURE_FAILED) # 0 means success - # should also work in an odd case when multiple directories are given - string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS) - string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}") - string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1"_GSS_CFLAGS "${_GSS_CFLAGS}") - - foreach(_flag ${_GSS_CFLAGS}) - if(_flag MATCHES "^-I.*") - string(REGEX REPLACE "^-I" "" _val "${_flag}") - list(APPEND _GSS_INCLUDE_DIR "${_val}") - else() - list(APPEND _GSS_COMPILER_FLAGS "${_flag}") - endif() - endforeach() - endif() - - execute_process( - COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi" - OUTPUT_VARIABLE _GSS_LIB_FLAGS - RESULT_VARIABLE _GSS_CONFIGURE_FAILED - ) -message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}") - if(NOT _GSS_CONFIGURE_FAILED) # 0 means success - # this script gives us libraries and link directories. Blah. We have to deal with it. - string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS) - string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}") - string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1"_GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}") - - foreach(_flag ${_GSS_LIB_FLAGS}) - if(_flag MATCHES "^-l.*") - string(REGEX REPLACE "^-l" "" _val "${_flag}") - list(APPEND _GSS_LIBRARIES "${_val}") - elseif(_flag MATCHES "^-L.*") - string(REGEX REPLACE "^-L" "" _val "${_flag}") - list(APPEND _GSS_LINK_DIRECTORIES "${_val}") - else() - list(APPEND _GSS_LINKER_FLAGS "${_flag}") - endif() - endforeach() - endif() - - - execute_process( - COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version" - OUTPUT_VARIABLE _GSS_VERSION - RESULT_VARIABLE _GSS_CONFIGURE_FAILED - ) - - # older versions may not have the "--version" parameter. In this case we just don't care. - if(_GSS_CONFIGURE_FAILED) - set(_GSS_VERSION 0) - endif() - - - execute_process( - COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor" - OUTPUT_VARIABLE _GSS_VENDOR - RESULT_VARIABLE _GSS_CONFIGURE_FAILED - ) - - # older versions may not have the "--vendor" parameter. In this case we just don't care. - if(_GSS_CONFIGURE_FAILED) - set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter - else() - if(_GSS_VENDOR MATCHES ".*H|heimdal.*") - set(GSS_FLAVOUR "Heimdal") - else() - set(GSS_FLAVOUR "MIT") - endif() - endif() - - else() # either there is no config script or we are on platform that doesn't provide one (Windows?) - - find_path(_GSS_INCLUDE_DIR - NAMES - "gssapi/gssapi.h" - HINTS - ${_GSS_ROOT_HINTS} - PATH_SUFFIXES - include - inc - ) - - if(_GSS_INCLUDE_DIR) #jay, we've found something - set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}") - check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS) - - if(_GSS_HAVE_MIT_HEADERS) - set(GSS_FLAVOUR "MIT") - else() - # prevent compiling the header - just check if we can include it - set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D__ROKEN_H__") - check_include_file( "roken.h" _GSS_HAVE_ROKEN_H) - - check_include_file( "heimdal/roken.h" _GSS_HAVE_HEIMDAL_ROKEN_H) - if(_GSS_HAVE_ROKEN_H OR _GSS_HAVE_HEIMDAL_ROKEN_H) - set(GSS_FLAVOUR "Heimdal") - endif() - set(CMAKE_REQUIRED_DEFINITIONS "") - endif() - else() - # I'm not convienced if this is the right way but this is what autotools do at the moment - find_path(_GSS_INCLUDE_DIR - NAMES - "gssapi.h" - HINTS - ${_GSS_ROOT_HINTS} - PATH_SUFFIXES - include - inc - ) - - if(_GSS_INCLUDE_DIR) - set(GSS_FLAVOUR "Heimdal") - endif() - endif() - - # if we have headers, check if we can link libraries - if(GSS_FLAVOUR) - set(_GSS_LIBDIR_SUFFIXES "") - set(_GSS_LIBDIR_HINTS ${_GSS_ROOT_HINTS}) - get_filename_component(_GSS_CALCULATED_POTENTIAL_ROOT "${_GSS_INCLUDE_DIR}" PATH) - list(APPEND _GSS_LIBDIR_HINTS ${_GSS_CALCULATED_POTENTIAL_ROOT}) - - if(WIN32) - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - list(APPEND _GSS_LIBDIR_SUFFIXES "lib/AMD64") - if(GSS_FLAVOUR STREQUAL "MIT") - set(_GSS_LIBNAME "gssapi64") - else() - set(_GSS_LIBNAME "libgssapi") - endif() - else() - list(APPEND _GSS_LIBDIR_SUFFIXES "lib/i386") - if(GSS_FLAVOUR STREQUAL "MIT") - set(_GSS_LIBNAME "gssapi32") - else() - set(_GSS_LIBNAME "libgssapi") - endif() - endif() - else() - list(APPEND _GSS_LIBDIR_SUFFIXES "lib;lib64") # those suffixes are not checked for HINTS - if(GSS_FLAVOUR STREQUAL "MIT") - set(_GSS_LIBNAME "gssapi_krb5") - else() - set(_GSS_LIBNAME "gssapi") - endif() - endif() - - find_library(_GSS_LIBRARIES - NAMES - ${_GSS_LIBNAME} - HINTS - ${_GSS_LIBDIR_HINTS} - PATH_SUFFIXES - ${_GSS_LIBDIR_SUFFIXES} - ) - - endif() - - endif() -else() - if(_GSS_PKG_${_MIT_MODNAME}_VERSION) - set(GSS_FLAVOUR "MIT") - set(_GSS_VERSION _GSS_PKG_${_MIT_MODNAME}_VERSION) - else() - set(GSS_FLAVOUR "Heimdal") - set(_GSS_VERSION _GSS_PKG_${_MIT_HEIMDAL}_VERSION) - endif() -endif() - -set(GSS_INCLUDE_DIR ${_GSS_INCLUDE_DIR}) -set(GSS_LIBRARIES ${_GSS_LIBRARIES}) -set(GSS_LINK_DIRECTORIES ${_GSS_LINK_DIRECTORIES}) -set(GSS_LINKER_FLAGS ${_GSS_LINKER_FLAGS}) -set(GSS_COMPILER_FLAGS ${_GSS_COMPILER_FLAGS}) -set(GSS_VERSION ${_GSS_VERSION}) - -if(GSS_FLAVOUR) - - if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal") - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.amd64.manifest") - else() - set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.x86.manifest") - endif() - - if(EXISTS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}") - file(STRINGS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}" heimdal_version_str - REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$") - - string(REGEX MATCH "[0-9]\\.[^\"]+" - GSS_VERSION "${heimdal_version_str}") - endif() - - if(NOT GSS_VERSION) - set(GSS_VERSION "Heimdal Unknown") - endif() - elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT") - get_filename_component(_MIT_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE) - if(WIN32 AND _MIT_VERSION) - set(GSS_VERSION "${_MIT_VERSION}") - else() - set(GSS_VERSION "MIT Unknown") - endif() - endif() -endif() - - -include(FindPackageHandleStandardArgs) - -set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR) - -find_package_handle_standard_args(GSS - REQUIRED_VARS - ${_GSS_REQUIRED_VARS} - VERSION_VAR - GSS_VERSION - FAIL_MESSAGE - "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR" -) - -mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES) diff --git a/dep/cpr/opt/curl/CMake/FindLibSSH2.cmake b/dep/cpr/opt/curl/CMake/FindLibSSH2.cmake deleted file mode 100644 index 12a7c612b3f..00000000000 --- a/dep/cpr/opt/curl/CMake/FindLibSSH2.cmake +++ /dev/null @@ -1,35 +0,0 @@ -# - Try to find the libssh2 library -# Once done this will define -# -# LIBSSH2_FOUND - system has the libssh2 library -# LIBSSH2_INCLUDE_DIR - the libssh2 include directory -# LIBSSH2_LIBRARY - the libssh2 library name - -if (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) - set(LibSSH2_FIND_QUIETLY TRUE) -endif (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) - -FIND_PATH(LIBSSH2_INCLUDE_DIR libssh2.h -) - -FIND_LIBRARY(LIBSSH2_LIBRARY NAMES ssh2 -) - -if(LIBSSH2_INCLUDE_DIR) - file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9][0-9][0-9][0-9][0-9].*") - - string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_MAJOR "${libssh2_version_str}") - string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9]([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_MINOR "${libssh2_version_str}") - string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9][0-9][0-9]([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_PATCH "${libssh2_version_str}") - - string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_MAJOR "${LIBSSH2_VERSION_MAJOR}") - string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_MINOR "${LIBSSH2_VERSION_MINOR}") - string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_PATCH "${LIBSSH2_VERSION_PATCH}") - - set(LIBSSH2_VERSION "${LIBSSH2_VERSION_MAJOR}.${LIBSSH2_VERSION_MINOR}.${LIBSSH2_VERSION_PATCH}") -endif(LIBSSH2_INCLUDE_DIR) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSSH2 DEFAULT_MSG LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY ) - -MARK_AS_ADVANCED(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY LIBSSH2_VERSION_MAJOR LIBSSH2_VERSION_MINOR LIBSSH2_VERSION_PATCH LIBSSH2_VERSION) diff --git a/dep/cpr/opt/curl/CMake/FindMbedTLS.cmake b/dep/cpr/opt/curl/CMake/FindMbedTLS.cmake deleted file mode 100644 index a9163958921..00000000000 --- a/dep/cpr/opt/curl/CMake/FindMbedTLS.cmake +++ /dev/null @@ -1,13 +0,0 @@ -find_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h) - -find_library(MBEDTLS_LIBRARY mbedtls) -find_library(MBEDX509_LIBRARY mbedx509) -find_library(MBEDCRYPTO_LIBRARY mbedcrypto) - -set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(MBEDTLS DEFAULT_MSG - MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) - -mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) diff --git a/dep/cpr/opt/curl/CMake/FindNGHTTP2.cmake b/dep/cpr/opt/curl/CMake/FindNGHTTP2.cmake deleted file mode 100644 index 4e566cf0281..00000000000 --- a/dep/cpr/opt/curl/CMake/FindNGHTTP2.cmake +++ /dev/null @@ -1,18 +0,0 @@ -include(FindPackageHandleStandardArgs) - -find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h") - -find_library(NGHTTP2_LIBRARY NAMES nghttp2) - -find_package_handle_standard_args(NGHTTP2 - FOUND_VAR - NGHTTP2_FOUND - REQUIRED_VARS - NGHTTP2_LIBRARY - NGHTTP2_INCLUDE_DIR - FAIL_MESSAGE - "Could NOT find NGHTTP2" -) - -set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR} ) -set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY}) diff --git a/dep/cpr/opt/curl/CMake/Macros.cmake b/dep/cpr/opt/curl/CMake/Macros.cmake deleted file mode 100644 index 82aadca9d58..00000000000 --- a/dep/cpr/opt/curl/CMake/Macros.cmake +++ /dev/null @@ -1,124 +0,0 @@ -#File defines convenience macros for available feature testing - -# This macro checks if the symbol exists in the library and if it -# does, it prepends library to the list. It is intended to be called -# multiple times with a sequence of possibly dependent libraries in -# order of least-to-most-dependent. Some libraries depend on others -# to link correctly. -macro(CHECK_LIBRARY_EXISTS_CONCAT LIBRARY SYMBOL VARIABLE) - check_library_exists("${LIBRARY};${CURL_LIBS}" ${SYMBOL} "${CMAKE_LIBRARY_PATH}" - ${VARIABLE}) - if(${VARIABLE}) - set(CURL_LIBS ${LIBRARY} ${CURL_LIBS}) - endif(${VARIABLE}) -endmacro(CHECK_LIBRARY_EXISTS_CONCAT) - -# Check if header file exists and add it to the list. -# This macro is intended to be called multiple times with a sequence of -# possibly dependent header files. Some headers depend on others to be -# compiled correctly. -macro(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE) - check_include_files("${CURL_INCLUDES};${FILE}" ${VARIABLE}) - if(${VARIABLE}) - set(CURL_INCLUDES ${CURL_INCLUDES} ${FILE}) - set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${VARIABLE}") - endif(${VARIABLE}) -endmacro(CHECK_INCLUDE_FILE_CONCAT) - -# For other curl specific tests, use this macro. -macro(CURL_INTERNAL_TEST CURL_TEST) - if(NOT DEFINED "${CURL_TEST}") - set(MACRO_CHECK_FUNCTION_DEFINITIONS - "-D${CURL_TEST} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS}") - if(CMAKE_REQUIRED_LIBRARIES) - set(CURL_TEST_ADD_LIBRARIES - "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") - endif(CMAKE_REQUIRED_LIBRARIES) - - message(STATUS "Performing Curl Test ${CURL_TEST}") - try_compile(${CURL_TEST} - ${CMAKE_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - "${CURL_TEST_ADD_LIBRARIES}" - OUTPUT_VARIABLE OUTPUT) - if(${CURL_TEST}) - set(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}") - message(STATUS "Performing Curl Test ${CURL_TEST} - Success") - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing Curl Test ${CURL_TEST} passed with the following output:\n" - "${OUTPUT}\n") - else(${CURL_TEST}) - message(STATUS "Performing Curl Test ${CURL_TEST} - Failed") - set(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}") - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing Curl Test ${CURL_TEST} failed with the following output:\n" - "${OUTPUT}\n") - endif(${CURL_TEST}) - endif() -endmacro(CURL_INTERNAL_TEST) - -macro(CURL_INTERNAL_TEST_RUN CURL_TEST) - if(NOT DEFINED "${CURL_TEST}_COMPILE") - set(MACRO_CHECK_FUNCTION_DEFINITIONS - "-D${CURL_TEST} ${CMAKE_REQUIRED_FLAGS}") - if(CMAKE_REQUIRED_LIBRARIES) - set(CURL_TEST_ADD_LIBRARIES - "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") - endif(CMAKE_REQUIRED_LIBRARIES) - - message(STATUS "Performing Curl Test ${CURL_TEST}") - try_run(${CURL_TEST} ${CURL_TEST}_COMPILE - ${CMAKE_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - "${CURL_TEST_ADD_LIBRARIES}" - OUTPUT_VARIABLE OUTPUT) - if(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST}) - set(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}") - message(STATUS "Performing Curl Test ${CURL_TEST} - Success") - else(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST}) - message(STATUS "Performing Curl Test ${CURL_TEST} - Failed") - set(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}") - file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log" - "Performing Curl Test ${CURL_TEST} failed with the following output:\n" - "${OUTPUT}") - if(${CURL_TEST}_COMPILE) - file(APPEND - "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log" - "There was a problem running this test\n") - endif(${CURL_TEST}_COMPILE) - file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log" - "\n\n") - endif(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST}) - endif() -endmacro(CURL_INTERNAL_TEST_RUN) - -macro(CURL_NROFF_CHECK) - find_program(NROFF NAMES gnroff nroff) - if(NROFF) - # Need a way to write to stdin, this will do - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test") - # Tests for a valid nroff option to generate a manpage - foreach(_MANOPT "-man" "-mandoc") - execute_process(COMMAND "${NROFF}" ${_MANOPT} - OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT - INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" - ERROR_QUIET) - # Save the option if it was valid - if(NROFF_MANOPT_OUTPUT) - message("Found *nroff option: -- ${_MANOPT}") - set(NROFF_MANOPT ${_MANOPT}) - set(NROFF_USEFUL ON) - break() - endif() - endforeach() - # No need for the temporary file - file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt") - if(NOT NROFF_USEFUL) - message(WARNING "Found no *nroff option to get plaintext from man pages") - endif() - else() - message(WARNING "Found no *nroff program") - endif() -endmacro(CURL_NROFF_CHECK) diff --git a/dep/cpr/opt/curl/CMake/OtherTests.cmake b/dep/cpr/opt/curl/CMake/OtherTests.cmake deleted file mode 100644 index 989f04eb2dc..00000000000 --- a/dep/cpr/opt/curl/CMake/OtherTests.cmake +++ /dev/null @@ -1,232 +0,0 @@ -include(CheckCSourceCompiles) -# The begin of the sources (macros and includes) -set(_source_epilogue "#undef inline") - -macro(add_header_include check header) - if(${check}) - set(_source_epilogue "${_source_epilogue}\n#include <${header}>") - endif(${check}) -endmacro(add_header_include) - -set(signature_call_conv) -if(HAVE_WINDOWS_H) - add_header_include(HAVE_WINSOCK2_H "winsock2.h") - add_header_include(HAVE_WINDOWS_H "windows.h") - add_header_include(HAVE_WINSOCK_H "winsock.h") - set(_source_epilogue - "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif") - set(signature_call_conv "PASCAL") - if(HAVE_LIBWS2_32) - set(CMAKE_REQUIRED_LIBRARIES ws2_32) - endif() -else(HAVE_WINDOWS_H) - add_header_include(HAVE_SYS_TYPES_H "sys/types.h") - add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h") -endif(HAVE_WINDOWS_H) - -check_c_source_compiles("${_source_epilogue} -int main(void) { - recv(0, 0, 0, 0); - return 0; -}" curl_cv_recv) -if(curl_cv_recv) - if(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown") - foreach(recv_retv "int" "ssize_t" ) - foreach(recv_arg1 "SOCKET" "int" ) - foreach(recv_arg2 "char *" "void *" ) - foreach(recv_arg3 "int" "size_t" "socklen_t" "unsigned int") - foreach(recv_arg4 "int" "unsigned int") - if(NOT curl_cv_func_recv_done) - unset(curl_cv_func_recv_test CACHE) - check_c_source_compiles(" - ${_source_epilogue} - extern ${recv_retv} ${signature_call_conv} - recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4}); - int main(void) { - ${recv_arg1} s=0; - ${recv_arg2} buf=0; - ${recv_arg3} len=0; - ${recv_arg4} flags=0; - ${recv_retv} res = recv(s, buf, len, flags); - (void) res; - return 0; - }" - curl_cv_func_recv_test) - message(STATUS - "Tested: ${recv_retv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})") - if(curl_cv_func_recv_test) - set(curl_cv_func_recv_args - "${recv_arg1},${recv_arg2},${recv_arg3},${recv_arg4},${recv_retv}") - set(RECV_TYPE_ARG1 "${recv_arg1}") - set(RECV_TYPE_ARG2 "${recv_arg2}") - set(RECV_TYPE_ARG3 "${recv_arg3}") - set(RECV_TYPE_ARG4 "${recv_arg4}") - set(RECV_TYPE_RETV "${recv_retv}") - set(HAVE_RECV 1) - set(curl_cv_func_recv_done 1) - endif(curl_cv_func_recv_test) - endif(NOT curl_cv_func_recv_done) - endforeach(recv_arg4) - endforeach(recv_arg3) - endforeach(recv_arg2) - endforeach(recv_arg1) - endforeach(recv_retv) - else() - string(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG1 "${curl_cv_func_recv_args}") - string(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG2 "${curl_cv_func_recv_args}") - string(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG3 "${curl_cv_func_recv_args}") - string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" RECV_TYPE_ARG4 "${curl_cv_func_recv_args}") - string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" RECV_TYPE_RETV "${curl_cv_func_recv_args}") - endif() - - if("${curl_cv_func_recv_args}" STREQUAL "unknown") - message(FATAL_ERROR "Cannot find proper types to use for recv args") - endif("${curl_cv_func_recv_args}" STREQUAL "unknown") -else(curl_cv_recv) - message(FATAL_ERROR "Unable to link function recv") -endif(curl_cv_recv) -set(curl_cv_func_recv_args "${curl_cv_func_recv_args}" CACHE INTERNAL "Arguments for recv") -set(HAVE_RECV 1) - -check_c_source_compiles("${_source_epilogue} -int main(void) { - send(0, 0, 0, 0); - return 0; -}" curl_cv_send) -if(curl_cv_send) - if(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown") - foreach(send_retv "int" "ssize_t" ) - foreach(send_arg1 "SOCKET" "int" "ssize_t" ) - foreach(send_arg2 "const char *" "const void *" "void *" "char *") - foreach(send_arg3 "int" "size_t" "socklen_t" "unsigned int") - foreach(send_arg4 "int" "unsigned int") - if(NOT curl_cv_func_send_done) - unset(curl_cv_func_send_test CACHE) - check_c_source_compiles(" - ${_source_epilogue} - extern ${send_retv} ${signature_call_conv} - send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4}); - int main(void) { - ${send_arg1} s=0; - ${send_arg2} buf=0; - ${send_arg3} len=0; - ${send_arg4} flags=0; - ${send_retv} res = send(s, buf, len, flags); - (void) res; - return 0; - }" - curl_cv_func_send_test) - message(STATUS - "Tested: ${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})") - if(curl_cv_func_send_test) - string(REGEX REPLACE "(const) .*" "\\1" send_qual_arg2 "${send_arg2}") - string(REGEX REPLACE "const (.*)" "\\1" send_arg2 "${send_arg2}") - set(curl_cv_func_send_args - "${send_arg1},${send_arg2},${send_arg3},${send_arg4},${send_retv},${send_qual_arg2}") - set(SEND_TYPE_ARG1 "${send_arg1}") - set(SEND_TYPE_ARG2 "${send_arg2}") - set(SEND_TYPE_ARG3 "${send_arg3}") - set(SEND_TYPE_ARG4 "${send_arg4}") - set(SEND_TYPE_RETV "${send_retv}") - set(HAVE_SEND 1) - set(curl_cv_func_send_done 1) - endif(curl_cv_func_send_test) - endif(NOT curl_cv_func_send_done) - endforeach(send_arg4) - endforeach(send_arg3) - endforeach(send_arg2) - endforeach(send_arg1) - endforeach(send_retv) - else() - string(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG1 "${curl_cv_func_send_args}") - string(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG2 "${curl_cv_func_send_args}") - string(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG3 "${curl_cv_func_send_args}") - string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG4 "${curl_cv_func_send_args}") - string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" SEND_TYPE_RETV "${curl_cv_func_send_args}") - string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" SEND_QUAL_ARG2 "${curl_cv_func_send_args}") - endif() - - if("${curl_cv_func_send_args}" STREQUAL "unknown") - message(FATAL_ERROR "Cannot find proper types to use for send args") - endif("${curl_cv_func_send_args}" STREQUAL "unknown") - set(SEND_QUAL_ARG2 "const") -else(curl_cv_send) - message(FATAL_ERROR "Unable to link function send") -endif(curl_cv_send) -set(curl_cv_func_send_args "${curl_cv_func_send_args}" CACHE INTERNAL "Arguments for send") -set(HAVE_SEND 1) - -check_c_source_compiles("${_source_epilogue} - int main(void) { - int flag = MSG_NOSIGNAL; - (void)flag; - return 0; - }" HAVE_MSG_NOSIGNAL) - -if(NOT HAVE_WINDOWS_H) - add_header_include(HAVE_SYS_TIME_H "sys/time.h") - add_header_include(TIME_WITH_SYS_TIME "time.h") - add_header_include(HAVE_TIME_H "time.h") -endif() -check_c_source_compiles("${_source_epilogue} -int main(void) { - struct timeval ts; - ts.tv_sec = 0; - ts.tv_usec = 0; - (void)ts; - return 0; -}" HAVE_STRUCT_TIMEVAL) - - -include(CheckCSourceRuns) -# See HAVE_POLL in CMakeLists.txt for why poll is disabled on macOS -if(NOT APPLE) - set(CMAKE_REQUIRED_FLAGS) - if(HAVE_SYS_POLL_H) - set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H") - endif(HAVE_SYS_POLL_H) - check_c_source_runs(" - #ifdef HAVE_SYS_POLL_H - # include - #endif - int main(void) { - return poll((void *)0, 0, 10 /*ms*/); - }" HAVE_POLL_FINE) -endif() - -set(HAVE_SIG_ATOMIC_T 1) -set(CMAKE_REQUIRED_FLAGS) -if(HAVE_SIGNAL_H) - set(CMAKE_REQUIRED_FLAGS "-DHAVE_SIGNAL_H") - set(CMAKE_EXTRA_INCLUDE_FILES "signal.h") -endif(HAVE_SIGNAL_H) -check_type_size("sig_atomic_t" SIZEOF_SIG_ATOMIC_T) -if(HAVE_SIZEOF_SIG_ATOMIC_T) - check_c_source_compiles(" - #ifdef HAVE_SIGNAL_H - # include - #endif - int main(void) { - static volatile sig_atomic_t dummy = 0; - (void)dummy; - return 0; - }" HAVE_SIG_ATOMIC_T_NOT_VOLATILE) - if(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE) - set(HAVE_SIG_ATOMIC_T_VOLATILE 1) - endif(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE) -endif(HAVE_SIZEOF_SIG_ATOMIC_T) - -if(HAVE_WINDOWS_H) - set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h) -else() - set(CMAKE_EXTRA_INCLUDE_FILES) - if(HAVE_SYS_SOCKET_H) - set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) - endif(HAVE_SYS_SOCKET_H) -endif() - -check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE) -if(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE) - set(HAVE_STRUCT_SOCKADDR_STORAGE 1) -endif(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE) - diff --git a/dep/cpr/opt/curl/CMake/Platforms/WindowsCache.cmake b/dep/cpr/opt/curl/CMake/Platforms/WindowsCache.cmake deleted file mode 100644 index 6fc2991cd14..00000000000 --- a/dep/cpr/opt/curl/CMake/Platforms/WindowsCache.cmake +++ /dev/null @@ -1,125 +0,0 @@ -if(NOT UNIX) - if(WIN32) - set(HAVE_LIBDL 0) - set(HAVE_LIBUCB 0) - set(HAVE_LIBSOCKET 0) - set(NOT_NEED_LIBNSL 0) - set(HAVE_LIBNSL 0) - set(HAVE_GETHOSTNAME 1) - set(HAVE_LIBZ 0) - set(HAVE_LIBCRYPTO 0) - - set(HAVE_DLOPEN 0) - - set(HAVE_ALLOCA_H 0) - set(HAVE_ARPA_INET_H 0) - set(HAVE_DLFCN_H 0) - set(HAVE_FCNTL_H 1) - set(HAVE_INTTYPES_H 0) - set(HAVE_IO_H 1) - set(HAVE_MALLOC_H 1) - set(HAVE_MEMORY_H 1) - set(HAVE_NETDB_H 0) - set(HAVE_NETINET_IF_ETHER_H 0) - set(HAVE_NETINET_IN_H 0) - set(HAVE_NET_IF_H 0) - set(HAVE_PROCESS_H 1) - set(HAVE_PWD_H 0) - set(HAVE_SETJMP_H 1) - set(HAVE_SGTTY_H 0) - set(HAVE_SIGNAL_H 1) - set(HAVE_SOCKIO_H 0) - set(HAVE_STDINT_H 0) - set(HAVE_STDLIB_H 1) - set(HAVE_STRINGS_H 0) - set(HAVE_STRING_H 1) - set(HAVE_SYS_PARAM_H 0) - set(HAVE_SYS_POLL_H 0) - set(HAVE_SYS_SELECT_H 0) - set(HAVE_SYS_SOCKET_H 0) - set(HAVE_SYS_SOCKIO_H 0) - set(HAVE_SYS_STAT_H 1) - set(HAVE_SYS_TIME_H 0) - set(HAVE_SYS_TYPES_H 1) - set(HAVE_SYS_UTIME_H 1) - set(HAVE_TERMIOS_H 0) - set(HAVE_TERMIO_H 0) - set(HAVE_TIME_H 1) - set(HAVE_UNISTD_H 0) - set(HAVE_UTIME_H 0) - set(HAVE_X509_H 0) - set(HAVE_ZLIB_H 0) - - set(HAVE_SIZEOF_LONG_DOUBLE 1) - set(SIZEOF_LONG_DOUBLE 8) - - set(HAVE_SOCKET 1) - set(HAVE_POLL 0) - set(HAVE_SELECT 1) - set(HAVE_STRDUP 1) - set(HAVE_STRSTR 1) - set(HAVE_STRTOK_R 0) - set(HAVE_STRFTIME 1) - set(HAVE_UNAME 0) - set(HAVE_STRCASECMP 0) - set(HAVE_STRICMP 1) - set(HAVE_STRCMPI 1) - set(HAVE_GETHOSTBYADDR 1) - set(HAVE_GETTIMEOFDAY 0) - set(HAVE_INET_ADDR 1) - set(HAVE_INET_NTOA 1) - set(HAVE_INET_NTOA_R 0) - set(HAVE_TCGETATTR 0) - set(HAVE_TCSETATTR 0) - set(HAVE_PERROR 1) - set(HAVE_CLOSESOCKET 1) - set(HAVE_SETVBUF 0) - set(HAVE_SIGSETJMP 0) - set(HAVE_GETPASS_R 0) - set(HAVE_STRLCAT 0) - set(HAVE_GETPWUID 0) - set(HAVE_GETEUID 0) - set(HAVE_UTIME 1) - set(HAVE_RAND_EGD 0) - set(HAVE_RAND_SCREEN 0) - set(HAVE_RAND_STATUS 0) - set(HAVE_GMTIME_R 0) - set(HAVE_LOCALTIME_R 0) - set(HAVE_GETHOSTBYADDR_R 0) - set(HAVE_GETHOSTBYNAME_R 0) - set(HAVE_SIGNAL_FUNC 1) - set(HAVE_SIGNAL_MACRO 0) - - set(HAVE_GETHOSTBYADDR_R_5 0) - set(HAVE_GETHOSTBYADDR_R_5_REENTRANT 0) - set(HAVE_GETHOSTBYADDR_R_7 0) - set(HAVE_GETHOSTBYADDR_R_7_REENTRANT 0) - set(HAVE_GETHOSTBYADDR_R_8 0) - set(HAVE_GETHOSTBYADDR_R_8_REENTRANT 0) - set(HAVE_GETHOSTBYNAME_R_3 0) - set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0) - set(HAVE_GETHOSTBYNAME_R_5 0) - set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0) - set(HAVE_GETHOSTBYNAME_R_6 0) - set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0) - - set(TIME_WITH_SYS_TIME 0) - set(HAVE_O_NONBLOCK 0) - set(HAVE_IN_ADDR_T 0) - set(HAVE_INET_NTOA_R_DECL 0) - set(HAVE_INET_NTOA_R_DECL_REENTRANT 0) - if(ENABLE_IPV6) - set(HAVE_GETADDRINFO 1) - else() - set(HAVE_GETADDRINFO 0) - endif() - set(STDC_HEADERS 1) - set(RETSIGTYPE_TEST 1) - - set(HAVE_SIGACTION 0) - set(HAVE_MACRO_SIGSETJMP 0) - else(WIN32) - message("This file should be included on Windows platform only") - endif(WIN32) -endif(NOT UNIX) - diff --git a/dep/cpr/opt/curl/CMake/Utilities.cmake b/dep/cpr/opt/curl/CMake/Utilities.cmake deleted file mode 100644 index 8b6276df611..00000000000 --- a/dep/cpr/opt/curl/CMake/Utilities.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# File containing various utilities - -# Converts a CMake list to a string containing elements separated by spaces -function(TO_LIST_SPACES _LIST_NAME OUTPUT_VAR) - set(NEW_LIST_SPACE) - foreach(ITEM ${${_LIST_NAME}}) - set(NEW_LIST_SPACE "${NEW_LIST_SPACE} ${ITEM}") - endforeach() - string(STRIP ${NEW_LIST_SPACE} NEW_LIST_SPACE) - set(${OUTPUT_VAR} "${NEW_LIST_SPACE}" PARENT_SCOPE) -endfunction() - -# Appends a lis of item to a string which is a space-separated list, if they don't already exist. -function(LIST_SPACES_APPEND_ONCE LIST_NAME) - string(REPLACE " " ";" _LIST ${${LIST_NAME}}) - list(APPEND _LIST ${ARGN}) - list(REMOVE_DUPLICATES _LIST) - to_list_spaces(_LIST NEW_LIST_SPACE) - set(${LIST_NAME} "${NEW_LIST_SPACE}" PARENT_SCOPE) -endfunction() - -# Convinience function that does the same as LIST(FIND ...) but with a TRUE/FALSE return value. -# Ex: IN_STR_LIST(MY_LIST "Searched item" WAS_FOUND) -function(IN_STR_LIST LIST_NAME ITEM_SEARCHED RETVAL) - list(FIND ${LIST_NAME} ${ITEM_SEARCHED} FIND_POS) - if(${FIND_POS} EQUAL -1) - set(${RETVAL} FALSE PARENT_SCOPE) - else() - set(${RETVAL} TRUE PARENT_SCOPE) - endif() -endfunction() - -# Returns a list of arguments that evaluate to true -function(collect_true output_var output_count_var) - set(${output_var}) - foreach(option_var IN LISTS ARGN) - if(${option_var}) - list(APPEND ${output_var} ${option_var}) - endif() - endforeach() - set(${output_var} ${${output_var}} PARENT_SCOPE) - list(LENGTH ${output_var} ${output_count_var}) - set(${output_count_var} ${${output_count_var}} PARENT_SCOPE) -endfunction() diff --git a/dep/cpr/opt/curl/CMake/cmake_uninstall.cmake.in b/dep/cpr/opt/curl/CMake/cmake_uninstall.cmake.in deleted file mode 100644 index d00a5166581..00000000000 --- a/dep/cpr/opt/curl/CMake/cmake_uninstall.cmake.in +++ /dev/null @@ -1,26 +0,0 @@ -if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") -endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - -if (NOT DEFINED CMAKE_INSTALL_PREFIX) - set (CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") -endif () - message(${CMAKE_INSTALL_PREFIX}) - -file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -string(REGEX REPLACE "\n" ";" files "${files}") -foreach(file ${files}) - message(STATUS "Uninstalling $ENV{DESTDIR}${file}") - if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") - exec_program( - "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" - OUTPUT_VARIABLE rm_out - RETURN_VALUE rm_retval - ) - if(NOT "${rm_retval}" STREQUAL 0) - message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") - endif(NOT "${rm_retval}" STREQUAL 0) - else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") - message(STATUS "File $ENV{DESTDIR}${file} does not exist.") - endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") -endforeach(file) diff --git a/dep/cpr/opt/curl/CMakeLists.txt b/dep/cpr/opt/curl/CMakeLists.txt deleted file mode 100644 index e8b640c23e2..00000000000 --- a/dep/cpr/opt/curl/CMakeLists.txt +++ /dev/null @@ -1,1295 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### -# curl/libcurl CMake script -# by Tetetest and Sukender (Benoit Neil) - -# TODO: -# The output .so file lacks the soname number which we currently have within the lib/Makefile.am file -# Add full (4 or 5 libs) SSL support -# Add INSTALL target (EXTRA_DIST variables in Makefile.am may be moved to Makefile.inc so that CMake/CPack is aware of what's to include). -# Add CTests(?) -# Check on all possible platforms -# Test with as many configurations possible (With or without any option) -# Create scripts that help keeping the CMake build system up to date (to reduce maintenance). According to Tetetest: -# - lists of headers that 'configure' checks for; -# - curl-specific tests (the ones that are in m4/curl-*.m4 files); -# - (most obvious thing:) curl version numbers. -# Add documentation subproject -# -# To check: -# (From Daniel Stenberg) The cmake build selected to run gcc with -fPIC on my box while the plain configure script did not. -# (From Daniel Stenberg) The gcc command line use neither -g nor any -O options. As a developer, I also treasure our configure scripts's --enable-debug option that sets a long range of "picky" compiler options. -cmake_minimum_required(VERSION 2.8 FATAL_ERROR) -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") -include(Utilities) -include(Macros) -include(CMakeDependentOption) -include(CheckCCompilerFlag) - -project( CURL C ) - -message(WARNING "the curl cmake build system is poorly maintained. Be aware") - -file (READ ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS) -string (REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*" - CURL_VERSION ${CURL_VERSION_H_CONTENTS}) -string (REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION}) -string (REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+" - CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS}) -string (REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM}) - -include_regular_expression("^.*$") # Sukender: Is it necessary? - -# Setup package meta-data -# SET(PACKAGE "curl") -message(STATUS "curl version=[${CURL_VERSION}]") -# SET(PACKAGE_TARNAME "curl") -# SET(PACKAGE_NAME "curl") -# SET(PACKAGE_VERSION "-") -# SET(PACKAGE_STRING "curl-") -# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/") -set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}") -set(OS "\"${CMAKE_SYSTEM_NAME}\"") - -include_directories(${PROJECT_BINARY_DIR}/include/curl) -include_directories( ${CURL_SOURCE_DIR}/include ) - -option(CURL_WERROR "Turn compiler warnings into errors" OFF) -set(PICKY_COMPILER ON) -set(BUILD_CURL_EXE OFF) -option(CURL_STATICLIB "Set to ON to build libcurl with static linking." ON) -option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) -if(WIN32) - option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF) - option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON) -endif() - -CMAKE_DEPENDENT_OPTION(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup" - ON "NOT ENABLE_ARES" - OFF) - -option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF) -option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF) - -if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG) - if (PICKY_COMPILER) - foreach (_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers) - # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new - # test result in. - CHECK_C_COMPILER_FLAG(${_CCOPT} OPT${_CCOPT}) - if(OPT${_CCOPT}) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT}") - endif() - endforeach() - endif(PICKY_COMPILER) -endif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG) - -if (ENABLE_DEBUG) - # DEBUGBUILD will be defined only for Debug builds - if(NOT CMAKE_VERSION VERSION_LESS 3.0) - set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$:DEBUGBUILD>) - else() - set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUGBUILD) - endif() - set(ENABLE_CURLDEBUG ON) -endif() - -if (ENABLE_CURLDEBUG) - set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG) -endif() - -# For debug libs and exes, add "-d" postfix -#set(CMAKE_DEBUG_POSTFIX "-d" CACHE STRING "Set debug library postfix") - -# initialize CURL_LIBS -set(CURL_LIBS "") - -if(ENABLE_ARES) - set(USE_ARES 1) - find_package(CARES REQUIRED) - list(APPEND CURL_LIBS ${CARES_LIBRARY} ) - set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY}) -endif() - -include(CurlSymbolHiding) - -option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF) -mark_as_advanced(HTTP_ONLY) -option(CURL_DISABLE_FTP "disables FTP" OFF) -mark_as_advanced(CURL_DISABLE_FTP) -option(CURL_DISABLE_LDAP "disables LDAP" OFF) -mark_as_advanced(CURL_DISABLE_LDAP) -option(CURL_DISABLE_TELNET "disables Telnet" OFF) -mark_as_advanced(CURL_DISABLE_TELNET) -option(CURL_DISABLE_DICT "disables DICT" OFF) -mark_as_advanced(CURL_DISABLE_DICT) -option(CURL_DISABLE_FILE "disables FILE" OFF) -mark_as_advanced(CURL_DISABLE_FILE) -option(CURL_DISABLE_TFTP "disables TFTP" OFF) -mark_as_advanced(CURL_DISABLE_TFTP) -option(CURL_DISABLE_HTTP "disables HTTP" OFF) -mark_as_advanced(CURL_DISABLE_HTTP) - -option(CURL_DISABLE_LDAPS "to disable LDAPS" OFF) -mark_as_advanced(CURL_DISABLE_LDAPS) - -option(CURL_DISABLE_RTSP "to disable RTSP" OFF) -mark_as_advanced(CURL_DISABLE_RTSP) -option(CURL_DISABLE_PROXY "to disable proxy" OFF) -mark_as_advanced(CURL_DISABLE_PROXY) -option(CURL_DISABLE_POP3 "to disable POP3" OFF) -mark_as_advanced(CURL_DISABLE_POP3) -option(CURL_DISABLE_IMAP "to disable IMAP" OFF) -mark_as_advanced(CURL_DISABLE_IMAP) -option(CURL_DISABLE_SMTP "to disable SMTP" OFF) -mark_as_advanced(CURL_DISABLE_SMTP) -option(CURL_DISABLE_GOPHER "to disable Gopher" OFF) -mark_as_advanced(CURL_DISABLE_GOPHER) - -if(HTTP_ONLY) - set(CURL_DISABLE_FTP ON) - set(CURL_DISABLE_LDAP ON) - set(CURL_DISABLE_LDAPS ON) - set(CURL_DISABLE_TELNET ON) - set(CURL_DISABLE_DICT ON) - set(CURL_DISABLE_FILE ON) - set(CURL_DISABLE_TFTP ON) - set(CURL_DISABLE_RTSP ON) - set(CURL_DISABLE_POP3 ON) - set(CURL_DISABLE_IMAP ON) - set(CURL_DISABLE_SMTP ON) - set(CURL_DISABLE_GOPHER ON) -endif() - -option(CURL_DISABLE_COOKIES "to disable cookies support" OFF) -mark_as_advanced(CURL_DISABLE_COOKIES) - -option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF) -mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH) -option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF) -mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS) -option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON) -mark_as_advanced(ENABLE_IPV6) -if(ENABLE_IPV6 AND NOT WIN32) - include(CheckStructHasMember) - check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h" - HAVE_SOCKADDR_IN6_SIN6_ADDR) - check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h" - HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) - if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR) - message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support") - # Force the feature off as this name is used as guard macro... - set(ENABLE_IPV6 OFF - CACHE BOOL "Define if you want to enable IPv6 support" FORCE) - endif() -endif() - -CURL_NROFF_CHECK() -find_package(Perl) - -CMAKE_DEPENDENT_OPTION(ENABLE_MANUAL "to provide the built-in manual" - ON "NROFF_USEFUL;PERL_FOUND" - OFF) - -if(NOT PERL_FOUND) - message(STATUS "Perl not found, testing disabled.") - set(BUILD_TESTING OFF) -endif() -if(ENABLE_MANUAL) - set(USE_MANUAL ON) -endif() - -# We need ansi c-flags, especially on HP -set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}") -set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS}) - -if(CURL_STATIC_CRT) - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") -endif() - -# Disable warnings on Borland to avoid changing 3rd party code. -if(BORLAND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-") -endif(BORLAND) - -if(CURL_WERROR) - if(MSVC_VERSION) - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /WX") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /WX") - else() - # this assumes clang or gcc style options - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") - endif() -endif(CURL_WERROR) - -# If we are on AIX, do the _ALL_SOURCE magic -if(${CMAKE_SYSTEM_NAME} MATCHES AIX) - set(_ALL_SOURCE 1) -endif(${CMAKE_SYSTEM_NAME} MATCHES AIX) - -# Include all the necessary files for macros -include (CheckFunctionExists) -include (CheckIncludeFile) -include (CheckIncludeFiles) -include (CheckLibraryExists) -include (CheckSymbolExists) -include (CheckTypeSize) -include (CheckCSourceCompiles) -include (CMakeDependentOption) - -# On windows preload settings -if(WIN32) - set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WINSOCKAPI_=") - include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake) -endif(WIN32) - -if(ENABLE_THREADED_RESOLVER) - find_package(Threads REQUIRED) - if(WIN32) - set(USE_THREADS_WIN32 ON) - else() - set(USE_THREADS_POSIX ${CMAKE_USE_PTHREADS_INIT}) - set(HAVE_PTHREAD_H ${CMAKE_USE_PTHREADS_INIT}) - endif() - set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) -endif() - -# Check for all needed libraries -check_library_exists_concat("dl" dlopen HAVE_LIBDL) -check_library_exists_concat("socket" connect HAVE_LIBSOCKET) -check_library_exists("c" gethostbyname "" NOT_NEED_LIBNSL) - -# Yellowtab Zeta needs different libraries than BeOS 5. -if(BEOS) - set(NOT_NEED_LIBNSL 1) - check_library_exists_concat("bind" gethostbyname HAVE_LIBBIND) - check_library_exists_concat("bnetapi" closesocket HAVE_LIBBNETAPI) -endif(BEOS) - -if(NOT NOT_NEED_LIBNSL) - check_library_exists_concat("nsl" gethostbyname HAVE_LIBNSL) -endif(NOT NOT_NEED_LIBNSL) - -check_function_exists(gethostname HAVE_GETHOSTNAME) - -if(WIN32) - check_library_exists_concat("ws2_32" getch HAVE_LIBWS2_32) - check_library_exists_concat("winmm" getch HAVE_LIBWINMM) -endif() - -# check SSL libraries -# TODO support GNUTLS, NSS, POLARSSL, AXTLS, CYASSL - -if(APPLE) - option(CMAKE_USE_DARWINSSL "enable Apple OS native SSL/TLS" OFF) -endif() -if(WIN32) - option(CMAKE_USE_WINSSL "enable Windows native SSL/TLS" OFF) - cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON - CMAKE_USE_WINSSL OFF) -endif() -option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF) - -set(openssl_default ON) -if(WIN32 OR CMAKE_USE_DARWINSSL OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS) - set(openssl_default OFF) -endif() -option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ${openssl_default}) - -collect_true(enabled_ssl_options enabled_ssl_options_count - CMAKE_USE_WINSSL - CMAKE_USE_DARWINSSL - CMAKE_USE_OPENSSL - CMAKE_USE_MBEDTLS -) -if(enabled_ssl_options_count GREATER 1) - message(FATAL_ERROR "Multiple SSL options specified: ${enabled_ssl_options}. Please pick at most one and disable the rest.") -endif() - -if(CMAKE_USE_WINSSL) - set(SSL_ENABLED ON) - set(USE_SCHANNEL ON) # Windows native SSL/TLS support - set(USE_WINDOWS_SSPI ON) # CMAKE_USE_WINSSL implies CURL_WINDOWS_SSPI - list(APPEND CURL_LIBS "crypt32") -endif() -if(CURL_WINDOWS_SSPI) - set(USE_WINDOWS_SSPI ON) - set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32") -endif() - -if(CMAKE_USE_DARWINSSL) - find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation") - if(NOT COREFOUNDATION_FRAMEWORK) - message(FATAL_ERROR "CoreFoundation framework not found") - endif() - - find_library(SECURITY_FRAMEWORK "Security") - if(NOT SECURITY_FRAMEWORK) - message(FATAL_ERROR "Security framework not found") - endif() - - set(SSL_ENABLED ON) - set(USE_DARWINSSL ON) - list(APPEND CURL_LIBS "${COREFOUNDATION_FRAMEWORK}" "${SECURITY_FRAMEWORK}") -endif() - -if(CMAKE_USE_OPENSSL) - find_package(OpenSSL REQUIRED) - set(SSL_ENABLED ON) - set(USE_OPENSSL ON) - set(HAVE_LIBCRYPTO ON) - set(HAVE_LIBSSL ON) - list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES}) - include_directories(${OPENSSL_INCLUDE_DIR}) - set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) - check_include_file("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H) - check_include_file("openssl/engine.h" HAVE_OPENSSL_ENGINE_H) - check_include_file("openssl/err.h" HAVE_OPENSSL_ERR_H) - check_include_file("openssl/pem.h" HAVE_OPENSSL_PEM_H) - check_include_file("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H) - check_include_file("openssl/rsa.h" HAVE_OPENSSL_RSA_H) - check_include_file("openssl/ssl.h" HAVE_OPENSSL_SSL_H) - check_include_file("openssl/x509.h" HAVE_OPENSSL_X509_H) - check_include_file("openssl/rand.h" HAVE_OPENSSL_RAND_H) - check_symbol_exists(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS) - check_symbol_exists(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN) - check_symbol_exists(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD) -endif() - -if(CMAKE_USE_MBEDTLS) - find_package(MbedTLS REQUIRED) - set(SSL_ENABLED ON) - set(USE_MBEDTLS ON) - list(APPEND CURL_LIBS ${MBEDTLS_LIBRARIES}) - include_directories(${MBEDTLS_INCLUDE_DIRS}) -endif() - -option(USE_NGHTTP2 "Use Nghttp2 library" OFF) -if(USE_NGHTTP2) - find_package(NGHTTP2 REQUIRED) - include_directories(${NGHTTP2_INCLUDE_DIRS}) - list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES}) -endif() - -if(NOT CURL_DISABLE_LDAP) - if(WIN32) - option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON) - if(USE_WIN32_LDAP) - check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32) - if(NOT HAVE_WLDAP32) - set(USE_WIN32_LDAP OFF) - endif() - endif() - endif() - - option(CMAKE_USE_OPENLDAP "Use OpenLDAP code." OFF) - mark_as_advanced(CMAKE_USE_OPENLDAP) - set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library") - set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library") - - if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP) - message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time") - endif() - - # Now that we know, we're not using windows LDAP... - if(USE_WIN32_LDAP) - check_include_file_concat("winldap.h" HAVE_WINLDAP_H) - check_include_file_concat("winber.h" HAVE_WINBER_H) - else() - # Check for LDAP - set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) - check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP) - check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER) - - set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES}) - set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory") - if(CMAKE_LDAP_INCLUDE_DIR) - list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR}) - endif() - check_include_file_concat("ldap.h" HAVE_LDAP_H) - check_include_file_concat("lber.h" HAVE_LBER_H) - - if(NOT HAVE_LDAP_H) - message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON") - set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) - set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used - elseif(NOT HAVE_LIBLDAP) - message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON") - set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) - set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used - else() - if(CMAKE_USE_OPENLDAP) - set(USE_OPENLDAP ON) - endif() - if(CMAKE_LDAP_INCLUDE_DIR) - include_directories(${CMAKE_LDAP_INCLUDE_DIR}) - endif() - set(NEED_LBER_H ON) - set(_HEADER_LIST) - if(HAVE_WINDOWS_H) - list(APPEND _HEADER_LIST "windows.h") - endif() - if(HAVE_SYS_TYPES_H) - list(APPEND _HEADER_LIST "sys/types.h") - endif() - list(APPEND _HEADER_LIST "ldap.h") - - set(_SRC_STRING "") - foreach(_HEADER ${_HEADER_LIST}) - set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n") - endforeach() - - set(_SRC_STRING - " - ${_INCLUDE_STRING} - int main(int argc, char ** argv) - { - BerValue *bvp = NULL; - BerElement *bep = ber_init(bvp); - ber_free(bep, 1); - return 0; - }" - ) - set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1") - list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) - if(HAVE_LIBLBER) - list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB}) - endif() - check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H) - - if(NOT_NEED_LBER_H) - set(NEED_LBER_H OFF) - else() - set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H") - endif() - endif() - endif() - -endif() - -# No ldap, no ldaps. -if(CURL_DISABLE_LDAP) - if(NOT CURL_DISABLE_LDAPS) - message(STATUS "LDAP needs to be enabled to support LDAPS") - set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE) - endif() -endif() - -if(NOT CURL_DISABLE_LDAPS) - check_include_file_concat("ldap_ssl.h" HAVE_LDAP_SSL_H) - check_include_file_concat("ldapssl.h" HAVE_LDAPSSL_H) -endif() - -# Check for idn -check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2) - -# Check for symbol dlopen (same as HAVE_LIBDL) -check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN) - -option(CURL_ZLIB "Set to ON to enable building curl with zlib support." ON) -set(HAVE_LIBZ OFF) -set(HAVE_ZLIB_H OFF) -set(HAVE_ZLIB OFF) -if(CURL_ZLIB) - find_package(ZLIB QUIET) - if(ZLIB_FOUND) - set(HAVE_ZLIB_H ON) - set(HAVE_ZLIB ON) - set(HAVE_LIBZ ON) - list(APPEND CURL_LIBS ${ZLIB_LIBRARIES}) - include_directories(${ZLIB_INCLUDE_DIRS}) - list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS}) - endif() -endif() - -#libSSH2 -option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON) -mark_as_advanced(CMAKE_USE_LIBSSH2) -set(USE_LIBSSH2 OFF) -set(HAVE_LIBSSH2 OFF) -set(HAVE_LIBSSH2_H OFF) - -if(CMAKE_USE_LIBSSH2) - find_package(LibSSH2) - if(LIBSSH2_FOUND) - list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY}) - set(CMAKE_REQUIRED_LIBRARIES ${LIBSSH2_LIBRARY}) - list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}") - include_directories("${LIBSSH2_INCLUDE_DIR}") - set(HAVE_LIBSSH2 ON) - set(USE_LIBSSH2 ON) - - # find_package has already found the headers - set(HAVE_LIBSSH2_H ON) - set(CURL_INCLUDES ${CURL_INCLUDES} "${LIBSSH2_INCLUDE_DIR}/libssh2.h") - set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DHAVE_LIBSSH2_H") - - # now check for specific libssh2 symbols as they were added in different versions - set(CMAKE_EXTRA_INCLUDE_FILES "libssh2.h") - check_function_exists(libssh2_version HAVE_LIBSSH2_VERSION) - check_function_exists(libssh2_init HAVE_LIBSSH2_INIT) - check_function_exists(libssh2_exit HAVE_LIBSSH2_EXIT) - check_function_exists(libssh2_scp_send64 HAVE_LIBSSH2_SCP_SEND64) - check_function_exists(libssh2_session_handshake HAVE_LIBSSH2_SESSION_HANDSHAKE) - set(CMAKE_EXTRA_INCLUDE_FILES "") - - endif(LIBSSH2_FOUND) -endif(CMAKE_USE_LIBSSH2) - -option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF) -mark_as_advanced(CMAKE_USE_GSSAPI) - -if(CMAKE_USE_GSSAPI) - find_package(GSS) - - set(HAVE_GSSAPI ${GSS_FOUND}) - if(GSS_FOUND) - - message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"") - - list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRECTORIES}) - check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) - check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) - check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H) - - if(GSS_FLAVOUR STREQUAL "Heimdal") - set(HAVE_GSSHEIMDAL ON) - else() # MIT - set(HAVE_GSSMIT ON) - set(_INCLUDE_LIST "") - if(HAVE_GSSAPI_GSSAPI_H) - list(APPEND _INCLUDE_LIST "gssapi/gssapi.h") - endif() - if(HAVE_GSSAPI_GSSAPI_GENERIC_H) - list(APPEND _INCLUDE_LIST "gssapi/gssapi_generic.h") - endif() - if(HAVE_GSSAPI_GSSAPI_KRB5_H) - list(APPEND _INCLUDE_LIST "gssapi/gssapi_krb5.h") - endif() - - string(REPLACE ";" " " _COMPILER_FLAGS_STR "${GSS_COMPILER_FLAGS}") - string(REPLACE ";" " " _LINKER_FLAGS_STR "${GSS_LINKER_FLAGS}") - - foreach(_dir ${GSS_LINK_DIRECTORIES}) - set(_LINKER_FLAGS_STR "${_LINKER_FLAGS_STR} -L\"${_dir}\"") - endforeach() - - set(CMAKE_REQUIRED_FLAGS "${_COMPILER_FLAGS_STR} ${_LINKER_FLAGS_STR}") - set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES}) - check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_INCLUDE_LIST} HAVE_GSS_C_NT_HOSTBASED_SERVICE) - if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE) - set(HAVE_OLD_GSSMIT ON) - endif() - - endif() - - include_directories(${GSS_INCLUDE_DIRECTORIES}) - link_directories(${GSS_LINK_DIRECTORIES}) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") - list(APPEND CURL_LIBS ${GSS_LIBRARIES}) - - else() - message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.") - endif() -endif() - -option(ENABLE_UNIX_SOCKETS "Define if you want Unix domain sockets support" ON) -if(ENABLE_UNIX_SOCKETS) - include(CheckStructHasMember) - check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS) -else() - unset(USE_UNIX_SOCKETS CACHE) -endif() - - -# -# CA handling -# -set(CURL_CA_BUNDLE "auto" CACHE STRING - "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") -set(CURL_CA_FALLBACK OFF CACHE BOOL - "Set ON to use built-in CA store of TLS backend. Defaults to OFF") -set(CURL_CA_PATH "none" CACHE STRING - "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") - -if("${CURL_CA_BUNDLE}" STREQUAL "") - message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.") -elseif("${CURL_CA_BUNDLE}" STREQUAL "none") - unset(CURL_CA_BUNDLE CACHE) -elseif("${CURL_CA_BUNDLE}" STREQUAL "auto") - unset(CURL_CA_BUNDLE CACHE) - set(CURL_CA_BUNDLE_AUTODETECT TRUE) -else() - set(CURL_CA_BUNDLE_SET TRUE) -endif() - -if("${CURL_CA_PATH}" STREQUAL "") - message(FATAL_ERROR "Invalid value of CURL_CA_PATH. Use 'none', 'auto' or directory path.") -elseif("${CURL_CA_PATH}" STREQUAL "none") - unset(CURL_CA_PATH CACHE) -elseif("${CURL_CA_PATH}" STREQUAL "auto") - unset(CURL_CA_PATH CACHE) - set(CURL_CA_PATH_AUTODETECT TRUE) -else() - set(CURL_CA_PATH_SET TRUE) -endif() - -if(CURL_CA_BUNDLE_SET AND CURL_CA_PATH_AUTODETECT) - # Skip autodetection of unset CA path because CA bundle is set explicitly -elseif(CURL_CA_PATH_SET AND CURL_CA_BUNDLE_AUTODETECT) - # Skip autodetection of unset CA bundle because CA path is set explicitly -elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT) - # first try autodetecting a CA bundle, then a CA path - - if(CURL_CA_BUNDLE_AUTODETECT) - set(SEARCH_CA_BUNDLE_PATHS - /etc/ssl/certs/ca-certificates.crt - /etc/pki/tls/certs/ca-bundle.crt - /usr/share/ssl/certs/ca-bundle.crt - /usr/local/share/certs/ca-root-nss.crt - /etc/ssl/cert.pem) - - foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS}) - if(EXISTS "${SEARCH_CA_BUNDLE_PATH}") - message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}") - set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}") - set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set") - break() - endif() - endforeach() - endif() - - if(CURL_CA_PATH_AUTODETECT AND (NOT CURL_CA_PATH_SET)) - if(EXISTS "/etc/ssl/certs") - set(CURL_CA_PATH "/etc/ssl/certs") - set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set") - endif() - endif() -endif() - -if(CURL_CA_PATH_SET AND NOT USE_OPENSSL AND NOT USE_MBEDTLS) - message(FATAL_ERROR - "CA path only supported by OpenSSL, GnuTLS or mbed TLS. " - "Set CURL_CA_PATH=none or enable one of those TLS backends.") -endif() - - -# Check for header files -if(NOT UNIX) - check_include_file_concat("windows.h" HAVE_WINDOWS_H) - check_include_file_concat("winsock.h" HAVE_WINSOCK_H) - check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H) - check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H) - if(NOT CURL_WINDOWS_SSPI AND USE_OPENSSL) - set(CURL_LIBS ${CURL_LIBS} "crypt32") - endif() -endif(NOT UNIX) - -check_include_file_concat("stdio.h" HAVE_STDIO_H) -check_include_file_concat("inttypes.h" HAVE_INTTYPES_H) -check_include_file_concat("sys/filio.h" HAVE_SYS_FILIO_H) -check_include_file_concat("sys/ioctl.h" HAVE_SYS_IOCTL_H) -check_include_file_concat("sys/param.h" HAVE_SYS_PARAM_H) -check_include_file_concat("sys/poll.h" HAVE_SYS_POLL_H) -check_include_file_concat("sys/resource.h" HAVE_SYS_RESOURCE_H) -check_include_file_concat("sys/select.h" HAVE_SYS_SELECT_H) -check_include_file_concat("sys/socket.h" HAVE_SYS_SOCKET_H) -check_include_file_concat("sys/sockio.h" HAVE_SYS_SOCKIO_H) -check_include_file_concat("sys/stat.h" HAVE_SYS_STAT_H) -check_include_file_concat("sys/time.h" HAVE_SYS_TIME_H) -check_include_file_concat("sys/types.h" HAVE_SYS_TYPES_H) -check_include_file_concat("sys/uio.h" HAVE_SYS_UIO_H) -check_include_file_concat("sys/un.h" HAVE_SYS_UN_H) -check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H) -check_include_file_concat("sys/xattr.h" HAVE_SYS_XATTR_H) -check_include_file_concat("alloca.h" HAVE_ALLOCA_H) -check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H) -check_include_file_concat("arpa/tftp.h" HAVE_ARPA_TFTP_H) -check_include_file_concat("assert.h" HAVE_ASSERT_H) -check_include_file_concat("crypto.h" HAVE_CRYPTO_H) -check_include_file_concat("des.h" HAVE_DES_H) -check_include_file_concat("err.h" HAVE_ERR_H) -check_include_file_concat("errno.h" HAVE_ERRNO_H) -check_include_file_concat("fcntl.h" HAVE_FCNTL_H) -check_include_file_concat("idn2.h" HAVE_IDN2_H) -check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) -check_include_file_concat("io.h" HAVE_IO_H) -check_include_file_concat("krb.h" HAVE_KRB_H) -check_include_file_concat("libgen.h" HAVE_LIBGEN_H) -check_include_file_concat("limits.h" HAVE_LIMITS_H) -check_include_file_concat("locale.h" HAVE_LOCALE_H) -check_include_file_concat("net/if.h" HAVE_NET_IF_H) -check_include_file_concat("netdb.h" HAVE_NETDB_H) -check_include_file_concat("netinet/in.h" HAVE_NETINET_IN_H) -check_include_file_concat("netinet/tcp.h" HAVE_NETINET_TCP_H) - -check_include_file_concat("pem.h" HAVE_PEM_H) -check_include_file_concat("poll.h" HAVE_POLL_H) -check_include_file_concat("pwd.h" HAVE_PWD_H) -check_include_file_concat("rsa.h" HAVE_RSA_H) -check_include_file_concat("setjmp.h" HAVE_SETJMP_H) -check_include_file_concat("sgtty.h" HAVE_SGTTY_H) -check_include_file_concat("signal.h" HAVE_SIGNAL_H) -check_include_file_concat("ssl.h" HAVE_SSL_H) -check_include_file_concat("stdbool.h" HAVE_STDBOOL_H) -check_include_file_concat("stdint.h" HAVE_STDINT_H) -check_include_file_concat("stdio.h" HAVE_STDIO_H) -check_include_file_concat("stdlib.h" HAVE_STDLIB_H) -check_include_file_concat("string.h" HAVE_STRING_H) -check_include_file_concat("strings.h" HAVE_STRINGS_H) -check_include_file_concat("stropts.h" HAVE_STROPTS_H) -check_include_file_concat("termio.h" HAVE_TERMIO_H) -check_include_file_concat("termios.h" HAVE_TERMIOS_H) -check_include_file_concat("time.h" HAVE_TIME_H) -check_include_file_concat("unistd.h" HAVE_UNISTD_H) -check_include_file_concat("utime.h" HAVE_UTIME_H) -check_include_file_concat("x509.h" HAVE_X509_H) - -check_include_file_concat("process.h" HAVE_PROCESS_H) -check_include_file_concat("stddef.h" HAVE_STDDEF_H) -check_include_file_concat("dlfcn.h" HAVE_DLFCN_H) -check_include_file_concat("malloc.h" HAVE_MALLOC_H) -check_include_file_concat("memory.h" HAVE_MEMORY_H) -check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H) -check_include_file_concat("stdint.h" HAVE_STDINT_H) -check_include_file_concat("sockio.h" HAVE_SOCKIO_H) -check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H) - -check_type_size(size_t SIZEOF_SIZE_T) -check_type_size(ssize_t SIZEOF_SSIZE_T) -check_type_size("long long" SIZEOF_LONG_LONG) -check_type_size("long" SIZEOF_LONG) -check_type_size("short" SIZEOF_SHORT) -check_type_size("int" SIZEOF_INT) -check_type_size("__int64" SIZEOF___INT64) -check_type_size("long double" SIZEOF_LONG_DOUBLE) -check_type_size("time_t" SIZEOF_TIME_T) -if(NOT HAVE_SIZEOF_SSIZE_T) - if(SIZEOF_LONG EQUAL SIZEOF_SIZE_T) - set(ssize_t long) - endif(SIZEOF_LONG EQUAL SIZEOF_SIZE_T) - if(NOT ssize_t AND SIZEOF___INT64 EQUAL SIZEOF_SIZE_T) - set(ssize_t __int64) - endif(NOT ssize_t AND SIZEOF___INT64 EQUAL SIZEOF_SIZE_T) -endif(NOT HAVE_SIZEOF_SSIZE_T) -# off_t is sized later, after the HAVE_FILE_OFFSET_BITS test - -if(HAVE_SIZEOF_LONG_LONG) - set(HAVE_LONGLONG 1) - set(HAVE_LL 1) -endif(HAVE_SIZEOF_LONG_LONG) - -find_file(RANDOM_FILE urandom /dev) -mark_as_advanced(RANDOM_FILE) - -# Check for some functions that are used -if(HAVE_LIBWS2_32) - set(CMAKE_REQUIRED_LIBRARIES ws2_32) -elseif(HAVE_LIBSOCKET) - set(CMAKE_REQUIRED_LIBRARIES socket) -endif() - -check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME) -check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET) -# poll on macOS is unreliable, it first did not exist, then was broken until -# fixed in 10.9 only to break again in 10.12. -if(NOT APPLE) - check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL) -endif() -check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT) -check_symbol_exists(strdup "${CURL_INCLUDES}" HAVE_STRDUP) -check_symbol_exists(strstr "${CURL_INCLUDES}" HAVE_STRSTR) -check_symbol_exists(strtok_r "${CURL_INCLUDES}" HAVE_STRTOK_R) -check_symbol_exists(strftime "${CURL_INCLUDES}" HAVE_STRFTIME) -check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) -check_symbol_exists(strcasecmp "${CURL_INCLUDES}" HAVE_STRCASECMP) -check_symbol_exists(stricmp "${CURL_INCLUDES}" HAVE_STRICMP) -check_symbol_exists(strcmpi "${CURL_INCLUDES}" HAVE_STRCMPI) -check_symbol_exists(strncmpi "${CURL_INCLUDES}" HAVE_STRNCMPI) -check_symbol_exists(alarm "${CURL_INCLUDES}" HAVE_ALARM) -if(NOT HAVE_STRNCMPI) - set(HAVE_STRCMPI) -endif(NOT HAVE_STRNCMPI) -check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR) -check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R) -check_symbol_exists(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY) -check_symbol_exists(inet_addr "${CURL_INCLUDES}" HAVE_INET_ADDR) -check_symbol_exists(inet_ntoa "${CURL_INCLUDES}" HAVE_INET_NTOA) -check_symbol_exists(inet_ntoa_r "${CURL_INCLUDES}" HAVE_INET_NTOA_R) -check_symbol_exists(tcsetattr "${CURL_INCLUDES}" HAVE_TCSETATTR) -check_symbol_exists(tcgetattr "${CURL_INCLUDES}" HAVE_TCGETATTR) -check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) -check_symbol_exists(closesocket "${CURL_INCLUDES}" HAVE_CLOSESOCKET) -check_symbol_exists(setvbuf "${CURL_INCLUDES}" HAVE_SETVBUF) -check_symbol_exists(sigsetjmp "${CURL_INCLUDES}" HAVE_SIGSETJMP) -check_symbol_exists(getpass_r "${CURL_INCLUDES}" HAVE_GETPASS_R) -check_symbol_exists(strlcat "${CURL_INCLUDES}" HAVE_STRLCAT) -check_symbol_exists(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID) -check_symbol_exists(geteuid "${CURL_INCLUDES}" HAVE_GETEUID) -check_symbol_exists(utime "${CURL_INCLUDES}" HAVE_UTIME) -check_symbol_exists(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R) -check_symbol_exists(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R) - -check_symbol_exists(gethostbyname "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME) -check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R) - -check_symbol_exists(signal "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC) -check_symbol_exists(SIGALRM "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO) -if(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) - set(HAVE_SIGNAL 1) -endif(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) -check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) -check_symbol_exists(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL) -check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64) -check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R) -check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT) -check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) -check_symbol_exists(fork "${CURL_INCLUDES}" HAVE_FORK) -check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO) -check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO) -check_symbol_exists(freeifaddrs "${CURL_INCLUDES}" HAVE_FREEIFADDRS) -check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) -check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE) -check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME) -check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) -check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) -check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) -check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) -check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL) -check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT) - -# symbol exists in win32, but function does not. -if(WIN32) - if(ENABLE_INET_PTON) - check_function_exists(inet_pton HAVE_INET_PTON) - # _WIN32_WINNT_VISTA (0x0600) - add_definitions(-D_WIN32_WINNT=0x0600) - else() - # _WIN32_WINNT_WINXP (0x0501) - add_definitions(-D_WIN32_WINNT=0x0501) - endif() -else() - check_function_exists(inet_pton HAVE_INET_PTON) -endif() - -check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR) -if(HAVE_FSETXATTR) - foreach(CURL_TEST HAVE_FSETXATTR_5 HAVE_FSETXATTR_6) - curl_internal_test_run(${CURL_TEST}) - endforeach(CURL_TEST) -endif(HAVE_FSETXATTR) - -# sigaction and sigsetjmp are special. Use special mechanism for -# detecting those, but only if previous attempt failed. -if(HAVE_SIGNAL_H) - check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION) -endif(HAVE_SIGNAL_H) - -if(NOT HAVE_SIGSETJMP) - if(HAVE_SETJMP_H) - check_symbol_exists(sigsetjmp "setjmp.h" HAVE_MACRO_SIGSETJMP) - if(HAVE_MACRO_SIGSETJMP) - set(HAVE_SIGSETJMP 1) - endif(HAVE_MACRO_SIGSETJMP) - endif(HAVE_SETJMP_H) -endif(NOT HAVE_SIGSETJMP) - -# If there is no stricmp(), do not allow LDAP to parse URLs -if(NOT HAVE_STRICMP) - set(HAVE_LDAP_URL_PARSE 1) -endif(NOT HAVE_STRICMP) - -# Do curl specific tests -foreach(CURL_TEST - HAVE_FCNTL_O_NONBLOCK - HAVE_IOCTLSOCKET - HAVE_IOCTLSOCKET_CAMEL - HAVE_IOCTLSOCKET_CAMEL_FIONBIO - HAVE_IOCTLSOCKET_FIONBIO - HAVE_IOCTL_FIONBIO - HAVE_IOCTL_SIOCGIFADDR - HAVE_SETSOCKOPT_SO_NONBLOCK - HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID - TIME_WITH_SYS_TIME - HAVE_O_NONBLOCK - HAVE_GETHOSTBYADDR_R_5 - HAVE_GETHOSTBYADDR_R_7 - HAVE_GETHOSTBYADDR_R_8 - HAVE_GETHOSTBYADDR_R_5_REENTRANT - HAVE_GETHOSTBYADDR_R_7_REENTRANT - HAVE_GETHOSTBYADDR_R_8_REENTRANT - HAVE_GETHOSTBYNAME_R_3 - HAVE_GETHOSTBYNAME_R_5 - HAVE_GETHOSTBYNAME_R_6 - HAVE_GETHOSTBYNAME_R_3_REENTRANT - HAVE_GETHOSTBYNAME_R_5_REENTRANT - HAVE_GETHOSTBYNAME_R_6_REENTRANT - HAVE_SOCKLEN_T - HAVE_IN_ADDR_T - HAVE_BOOL_T - STDC_HEADERS - RETSIGTYPE_TEST - HAVE_INET_NTOA_R_DECL - HAVE_INET_NTOA_R_DECL_REENTRANT - HAVE_GETADDRINFO - HAVE_FILE_OFFSET_BITS - ) - curl_internal_test(${CURL_TEST}) -endforeach(CURL_TEST) - -if(HAVE_FILE_OFFSET_BITS) - set(_FILE_OFFSET_BITS 64) - set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") -endif(HAVE_FILE_OFFSET_BITS) -check_type_size("off_t" SIZEOF_OFF_T) - -# include this header to get the type -set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCE_DIR}/include") -set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h") -check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) -set(CMAKE_EXTRA_INCLUDE_FILES "") - -set(CMAKE_REQUIRED_FLAGS) - -foreach(CURL_TEST - HAVE_GLIBC_STRERROR_R - HAVE_POSIX_STRERROR_R - ) - curl_internal_test_run(${CURL_TEST}) -endforeach(CURL_TEST) - -# Check for reentrant -foreach(CURL_TEST - HAVE_GETHOSTBYADDR_R_5 - HAVE_GETHOSTBYADDR_R_7 - HAVE_GETHOSTBYADDR_R_8 - HAVE_GETHOSTBYNAME_R_3 - HAVE_GETHOSTBYNAME_R_5 - HAVE_GETHOSTBYNAME_R_6 - HAVE_INET_NTOA_R_DECL_REENTRANT) - if(NOT ${CURL_TEST}) - if(${CURL_TEST}_REENTRANT) - set(NEED_REENTRANT 1) - endif(${CURL_TEST}_REENTRANT) - endif(NOT ${CURL_TEST}) -endforeach(CURL_TEST) - -if(NEED_REENTRANT) - foreach(CURL_TEST - HAVE_GETHOSTBYADDR_R_5 - HAVE_GETHOSTBYADDR_R_7 - HAVE_GETHOSTBYADDR_R_8 - HAVE_GETHOSTBYNAME_R_3 - HAVE_GETHOSTBYNAME_R_5 - HAVE_GETHOSTBYNAME_R_6) - set(${CURL_TEST} 0) - if(${CURL_TEST}_REENTRANT) - set(${CURL_TEST} 1) - endif(${CURL_TEST}_REENTRANT) - endforeach(CURL_TEST) -endif(NEED_REENTRANT) - -if(HAVE_INET_NTOA_R_DECL_REENTRANT) - set(HAVE_INET_NTOA_R_DECL 1) - set(NEED_REENTRANT 1) -endif(HAVE_INET_NTOA_R_DECL_REENTRANT) - -# Some other minor tests - -if(NOT HAVE_IN_ADDR_T) - set(in_addr_t "unsigned long") -endif(NOT HAVE_IN_ADDR_T) - -# Fix libz / zlib.h - -if(NOT CURL_SPECIAL_LIBZ) - if(NOT HAVE_LIBZ) - set(HAVE_ZLIB_H 0) - endif(NOT HAVE_LIBZ) - - if(NOT HAVE_ZLIB_H) - set(HAVE_LIBZ 0) - endif(NOT HAVE_ZLIB_H) -endif(NOT CURL_SPECIAL_LIBZ) - -# Check for nonblocking -set(HAVE_DISABLED_NONBLOCKING 1) -if(HAVE_FIONBIO OR - HAVE_IOCTLSOCKET OR - HAVE_IOCTLSOCKET_CASE OR - HAVE_O_NONBLOCK) - set(HAVE_DISABLED_NONBLOCKING) -endif(HAVE_FIONBIO OR - HAVE_IOCTLSOCKET OR - HAVE_IOCTLSOCKET_CASE OR - HAVE_O_NONBLOCK) - -if(RETSIGTYPE_TEST) - set(RETSIGTYPE void) -else(RETSIGTYPE_TEST) - set(RETSIGTYPE int) -endif(RETSIGTYPE_TEST) - -if(CMAKE_COMPILER_IS_GNUCC AND APPLE) - include(CheckCCompilerFlag) - check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double) - if(HAVE_C_FLAG_Wno_long_double) - # The Mac version of GCC warns about use of long double. Disable it. - get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS) - if(MPRINTF_COMPILE_FLAGS) - set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double") - else(MPRINTF_COMPILE_FLAGS) - set(MPRINTF_COMPILE_FLAGS "-Wno-long-double") - endif(MPRINTF_COMPILE_FLAGS) - set_source_files_properties(mprintf.c PROPERTIES - COMPILE_FLAGS ${MPRINTF_COMPILE_FLAGS}) - endif(HAVE_C_FLAG_Wno_long_double) -endif(CMAKE_COMPILER_IS_GNUCC AND APPLE) - -if(HAVE_SOCKLEN_T) - set(CURL_TYPEOF_CURL_SOCKLEN_T "socklen_t") - if(WIN32) - set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h;ws2tcpip.h") - elseif(HAVE_SYS_SOCKET_H) - set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h") - endif() - check_type_size("socklen_t" CURL_SIZEOF_CURL_SOCKLEN_T) - set(CMAKE_EXTRA_INCLUDE_FILES) - if(NOT HAVE_CURL_SIZEOF_CURL_SOCKLEN_T) - message(FATAL_ERROR - "Check for sizeof socklen_t failed, see CMakeFiles/CMakerror.log") - endif() -else() - set(CURL_TYPEOF_CURL_SOCKLEN_T int) - set(CURL_SIZEOF_CURL_SOCKLEN_T ${SIZEOF_INT}) -endif() - -# TODO test which of these headers are required -if(WIN32) - set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H}) -else() - set(CURL_PULL_SYS_TYPES_H ${HAVE_SYS_TYPES_H}) - set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H}) - set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H}) -endif() -set(CURL_PULL_STDINT_H ${HAVE_STDINT_H}) -set(CURL_PULL_INTTYPES_H ${HAVE_INTTYPES_H}) - -include(CMake/OtherTests.cmake) - -add_definitions(-DHAVE_CONFIG_H) - -# For windows, all compilers used by cmake should support large files -if(WIN32) - set(USE_WIN32_LARGE_FILES ON) -endif(WIN32) - -if(MSVC) - add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) - if(CMAKE_C_FLAGS MATCHES "/W[0-4]") - string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - else(CMAKE_C_FLAGS MATCHES "/W[0-4]") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") - endif(CMAKE_C_FLAGS MATCHES "/W[0-4]") -endif(MSVC) - -# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it). -function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE) - file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT) - string(REPLACE "$(top_srcdir)" "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) - string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) - - string(REGEX REPLACE "\\\\\n" "!Ï€!α!" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) - string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) - string(REPLACE "!Ï€!α!" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) - - string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace $() with ${} - string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace @@ with ${}, even if that may not be read by CMake scripts. - file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT}) - -endfunction() - -add_subdirectory(lib) - -if(BUILD_CURL_EXE) - add_subdirectory(src) -endif() - -include(CTest) - -# Helper to populate a list (_items) with a label when conditions (the remaining -# args) are satisfied -function(_add_if label) - # TODO need to disable policy CMP0054 (CMake 3.1) to allow this indirection - if(${ARGN}) - set(_items ${_items} "${label}" PARENT_SCOPE) - endif() -endfunction() - -# Clear list and try to detect available features -set(_items) -_add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI) -_add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) -_add_if("DarwinSSL" SSL_ENABLED AND USE_DARWINSSL) -_add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS) -_add_if("IPv6" ENABLE_IPV6) -_add_if("unix-sockets" USE_UNIX_SOCKETS) -_add_if("libz" HAVE_LIBZ) -_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32) -_add_if("IDN" HAVE_LIBIDN2) -_add_if("Largefile" (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND - ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES)) -# TODO SSP1 (WinSSL) check is missing -_add_if("SSPI" USE_WINDOWS_SSPI) -_add_if("GSS-API" HAVE_GSSAPI) -# TODO SSP1 missing for SPNEGO -_add_if("SPNEGO" NOT CURL_DISABLE_CRYPTO_AUTH AND - (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) -_add_if("Kerberos" NOT CURL_DISABLE_CRYPTO_AUTH AND - (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) -# NTLM support requires crypto function adaptions from various SSL libs -# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS -if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_DARWINSSL OR USE_MBEDTLS)) - _add_if("NTLM" 1) - # TODO missing option (autoconf: --enable-ntlm-wb) - _add_if("NTLM_WB" NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED) -endif() -# TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP -_add_if("TLS-SRP" USE_TLS_SRP) -# TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header -_add_if("HTTP2" USE_NGHTTP2) -string(REPLACE ";" " " SUPPORT_FEATURES "${_items}") -message(STATUS "Enabled features: ${SUPPORT_FEATURES}") - -# Clear list and try to detect available protocols -set(_items) -_add_if("HTTP" NOT CURL_DISABLE_HTTP) -_add_if("HTTPS" NOT CURL_DISABLE_HTTP AND SSL_ENABLED) -_add_if("FTP" NOT CURL_DISABLE_FTP) -_add_if("FTPS" NOT CURL_DISABLE_FTP AND SSL_ENABLED) -_add_if("FILE" NOT CURL_DISABLE_FILE) -_add_if("TELNET" NOT CURL_DISABLE_TELNET) -_add_if("LDAP" NOT CURL_DISABLE_LDAP) -# CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS -# TODO check HAVE_LDAP_SSL (in autoconf this is enabled with --enable-ldaps) -_add_if("LDAPS" NOT CURL_DISABLE_LDAPS AND - ((USE_OPENLDAP AND SSL_ENABLED) OR - (NOT USE_OPENLDAP AND HAVE_LDAP_SSL))) -_add_if("DICT" NOT CURL_DISABLE_DICT) -_add_if("TFTP" NOT CURL_DISABLE_TFTP) -_add_if("GOPHER" NOT CURL_DISABLE_GOPHER) -_add_if("POP3" NOT CURL_DISABLE_POP3) -_add_if("POP3S" NOT CURL_DISABLE_POP3 AND SSL_ENABLED) -_add_if("IMAP" NOT CURL_DISABLE_IMAP) -_add_if("IMAPS" NOT CURL_DISABLE_IMAP AND SSL_ENABLED) -_add_if("SMTP" NOT CURL_DISABLE_SMTP) -_add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED) -_add_if("SCP" USE_LIBSSH2) -_add_if("SFTP" USE_LIBSSH2) -_add_if("RTSP" NOT CURL_DISABLE_RTSP) -_add_if("RTMP" USE_LIBRTMP) -list(SORT _items) -string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}") -message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}") - -# curl-config needs the following options to be set. -set(CC "${CMAKE_C_COMPILER}") -# TODO probably put a -D... options here? -set(CONFIGURE_OPTIONS "") -# TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB? -set(CPPFLAG_CURL_STATICLIB "") -set(CURLVERSION "${CURL_VERSION}") -set(ENABLE_SHARED "yes") -if(CURL_STATICLIB) - set(ENABLE_STATIC "yes") -else() - set(ENABLE_STATIC "no") -endif() -set(exec_prefix "\${prefix}") -set(includedir "\${prefix}/include") -set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") -set(LIBCURL_LIBS "") -set(libdir "${CMAKE_INSTALL_PREFIX}/lib") -foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS}) - if(_lib MATCHES ".*/.*" OR _lib MATCHES "^-") - set(LIBCURL_LIBS "${LIBCURL_LIBS} ${_lib}") - else() - set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") - endif() -endforeach() -# "a" (Linux) or "lib" (Windows) -string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") -set(prefix "${CMAKE_INSTALL_PREFIX}") -# Set this to "yes" to append all libraries on which -lcurl is dependent -set(REQUIRE_LIB_DEPS "no") -# SUPPORT_FEATURES -# SUPPORT_PROTOCOLS -set(VERSIONNUM "${CURL_VERSION_NUM}") - -# Finally generate a "curl-config" matching this config -configure_file("${CURL_SOURCE_DIR}/curl-config.in" - "${CURL_BINARY_DIR}/curl-config" @ONLY) -install(FILES "${CURL_BINARY_DIR}/curl-config" - DESTINATION bin - PERMISSIONS - OWNER_READ OWNER_WRITE OWNER_EXECUTE - GROUP_READ GROUP_EXECUTE - WORLD_READ WORLD_EXECUTE) - -# Finally generate a pkg-config file matching this config -configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in" - "${CURL_BINARY_DIR}/libcurl.pc" @ONLY) -install(FILES "${CURL_BINARY_DIR}/libcurl.pc" - DESTINATION lib/pkgconfig) - -# This needs to be run very last so other parts of the scripts can take advantage of this. -if(NOT CURL_CONFIG_HAS_BEEN_RUN_BEFORE) - set(CURL_CONFIG_HAS_BEEN_RUN_BEFORE 1 CACHE INTERNAL "Flag to track whether this is the first time running CMake or if CMake has been configured before") -endif() - -# install headers -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl" - DESTINATION include - FILES_MATCHING PATTERN "*.h") - -# Workaround for MSVS10 to avoid the Dialog Hell -# FIXME: This could be removed with future version of CMake. -if(MSVC_VERSION EQUAL 1600) - set(CURL_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/CURL.sln") - if(EXISTS "${CURL_SLN_FILENAME}") - file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n") - endif() -endif() - -if(NOT TARGET uninstall) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake - IMMEDIATE @ONLY) - - add_custom_target(uninstall - COMMAND ${CMAKE_COMMAND} -P - ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake) -endif() diff --git a/dep/cpr/opt/curl/COPYING b/dep/cpr/opt/curl/COPYING deleted file mode 100644 index 1e45a5e2cd9..00000000000 --- a/dep/cpr/opt/curl/COPYING +++ /dev/null @@ -1,22 +0,0 @@ -COPYRIGHT AND PERMISSION NOTICE - -Copyright (c) 1996 - 2017, Daniel Stenberg, , and many -contributors, see the THANKS file. - -All rights reserved. - -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", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 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. - -Except as contained in this notice, the name of a copyright holder shall not -be used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization of the copyright holder. diff --git a/dep/cpr/opt/curl/GIT-INFO b/dep/cpr/opt/curl/GIT-INFO deleted file mode 100644 index 51df76ab4fd..00000000000 --- a/dep/cpr/opt/curl/GIT-INFO +++ /dev/null @@ -1,44 +0,0 @@ - _ _ ____ _ - ___| | | | _ \| | - / __| | | | |_) | | - | (__| |_| | _ <| |___ - \___|\___/|_| \_\_____| - -GIT-INFO - -This file is only present in git - never in release archives. It contains -information about other files and things that the git repository keeps in its -inner sanctum. - -To build in environments that support configure, after having extracted -everything from git, do this: - -./buildconf -./configure -make - - Daniel uses a ./configure line similar to this for easier development: - - ./configure --disable-shared --enable-debug --enable-maintainer-mode - -In environments that don't support configure (i.e. Microsoft), do this: - -buildconf.bat - - -REQUIREMENTS - - For buildconf (not buildconf.bat) to work, you need the following software -installed: - - o autoconf 2.57 (or later) - o automake 1.7 (or later) - o libtool 1.4.2 (or later) - o GNU m4 (required by autoconf) - - o nroff + perl - - If you don't have nroff and perl and you for some reason don't want to - install them, you can rename the source file src/tool_hugehelp.c.cvs to - src/tool_hugehelp.c and avoid having to generate this file. This will - give you a stubbed version of the file that doesn't contain actual content. diff --git a/dep/cpr/opt/curl/README b/dep/cpr/opt/curl/README deleted file mode 100644 index f0b3b93932f..00000000000 --- a/dep/cpr/opt/curl/README +++ /dev/null @@ -1,49 +0,0 @@ - _ _ ____ _ - ___| | | | _ \| | - / __| | | | |_) | | - | (__| |_| | _ <| |___ - \___|\___/|_| \_\_____| - -README - - Curl is a command line tool for transferring data specified with URL - syntax. Find out how to use curl by reading the curl.1 man page or the - MANUAL document. Find out how to install Curl by reading the INSTALL - document. - - libcurl is the library curl is using to do its job. It is readily - available to be used by your software. Read the libcurl.3 man page to - learn how! - - You find answers to the most frequent questions we get in the FAQ document. - - Study the COPYING file for distribution terms and similar. If you distribute - curl binaries or other binaries that involve libcurl, you might enjoy the - LICENSE-MIXING document. - -CONTACT - - If you have problems, questions, ideas or suggestions, please contact us - by posting to a suitable mailing list. See https://curl.haxx.se/mail/ - - All contributors to the project are listed in the THANKS document. - -WEB SITE - - Visit the curl web site for the latest news and downloads: - - https://curl.haxx.se/ - -GIT - - To download the very latest source off the GIT server do this: - - git clone https://github.com/curl/curl.git - - (you'll get a directory named curl created, filled with the source code) - -NOTICE - - Curl contains pieces of source code that is Copyright (c) 1998, 1999 - Kungliga Tekniska Högskolan. This notice is included here to comply with the - distribution terms. diff --git a/dep/cpr/opt/curl/README.md b/dep/cpr/opt/curl/README.md deleted file mode 100644 index 4abb51bc2f0..00000000000 --- a/dep/cpr/opt/curl/README.md +++ /dev/null @@ -1,50 +0,0 @@ -![curl logo](https://cdn.rawgit.com/curl/curl-www/master/logo/curl-logo.svg) -[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/63/badge)](https://bestpractices.coreinfrastructure.org/projects/63) -[![Coverity passed](https://scan.coverity.com/projects/curl/badge.svg)](https://scan.coverity.com/projects/curl) -[![Build Status](https://travis-ci.org/curl/curl.svg?branch=master)](https://travis-ci.org/curl/curl) -[![Coverage Status](https://coveralls.io/repos/github/curl/curl/badge.svg)](https://coveralls.io/github/curl/curl) - -Curl is a command-line tool for transferring data specified with URL -syntax. Find out how to use curl by reading [the curl.1 man -page](https://curl.haxx.se/docs/manpage.html) or [the MANUAL -document](https://curl.haxx.se/docs/manual.html). Find out how to install Curl -by reading [the INSTALL document](https://curl.haxx.se/docs/install.html). - -libcurl is the library curl is using to do its job. It is readily available to -be used by your software. Read [the libcurl.3 man -page](https://curl.haxx.se/libcurl/c/libcurl.html) to learn how! - -You find answers to the most frequent questions we get in [the FAQ -document](https://curl.haxx.se/docs/faq.html). - -Study [the COPYING file](https://curl.haxx.se/docs/copyright.html) for -distribution terms and similar. If you distribute curl binaries or other -binaries that involve libcurl, you might enjoy [the LICENSE-MIXING -document](https://curl.haxx.se/legal/licmix.html). - -## Contact - -If you have problems, questions, ideas or suggestions, please contact us by -posting to a suitable [mailing list](https://curl.haxx.se/mail/). - -All contributors to the project are listed in [the THANKS -document](https://curl.haxx.se/docs/thanks.html). - -## Website - -Visit the [curl web site](https://curl.haxx.se/) for the latest news and -downloads. - -## Git - -To download the very latest source off the Git server do this: - - git clone https://github.com/curl/curl.git - -(you'll get a directory named curl created, filled with the source code) - -## Notice - -Curl contains pieces of source code that is Copyright (c) 1998, 1999 Kungliga -Tekniska Högskolan. This notice is included here to comply with the -distribution terms. diff --git a/dep/cpr/opt/curl/RELEASE-NOTES b/dep/cpr/opt/curl/RELEASE-NOTES deleted file mode 100644 index 971336faf97..00000000000 --- a/dep/cpr/opt/curl/RELEASE-NOTES +++ /dev/null @@ -1,201 +0,0 @@ -Curl and libcurl 7.56.0 - - Public curl releases: 169 - Command line options: 211 - curl_easy_setopt() options: 249 - Public functions in libcurl: 74 - Contributors: 1618 - -This release includes the following changes: - - o curl: enable compression for SCP/SFTP with --compressed-ssh [11] - o libcurl: enable compression for SCP/SFTP with CURLOPT_SSH_COMPRESSION [11] - o vtls: added dynamic changing SSL backend with curl_global_sslset() [28] - o new MIME API, curl_mime_init() and friends [32] - o openssl: initial SSLKEYLOGFILE implementation [36] - -This release includes the following bugfixes: - - o FTP: zero terminate the entry path even on bad input [67] - o examples/ftpuploadresume.c: use portable code - o runtests: match keywords case insensitively - o travis: build the examples too [1] - o strtoofft: reduce integer overflow risks globally [2] - o zsh.pl: produce a working completion script again [3] - o cmake: remove dead code for CURL_DISABLE_RTMP [4] - o progress: Track total times following redirects [5] - o configure: fix --disable-threaded-resolver [6] - o cmake: remove dead code for DISABLED_THREADSAFE [7] - o configure: fix clang version detection - o darwinssi: fix error: variable length array used - o travis: add metalink to some osx builds [8] - o configure: check for __builtin_available() availability [9] - o http_proxy: fix build error for CURL_DOES_CONVERSIONS [10] - o examples/ftpuploadresume: checksrc compliance - o ftp: fix CWD when doing multicwd then nocwd on same connection [12] - o system.h: remove all CURL_SIZEOF_* defines [13] - o http: Don't wait on CONNECT when there is no proxy [14] - o system.h: check for __ppc__ as well [15] - o http2_recv: return error better on fatal h2 errors [16] - o scripts/contri*sh: use "git log --use-mailmap" - o tftp: fix memory leak on too long filename [17] - o system.h: fix build for hppa [18] - o cmake: enable picky compiler options with clang and gcc [19] - o makefile.m32: add support for libidn2 [20] - o curl: turn off MinGW CRT's globbing [21] - o request-target.d: mention added in 7.55.0 - o curl: shorten and clean up CA cert verification error message [22] - o imap: support PREAUTH [23] - o CURLOPT_USERPWD.3: see also CURLOPT_PROXYUSERPWD - o examples/threaded-ssl: mention that this is for openssl before 1.1 - o winbuild: fix embedded manifest option [24] - o tests: Make sure libtests & unittests call curl_global_cleanup() - o system.h: include sys/poll.h for AIX [25] - o darwinssl: handle long strings in TLS certs [26] - o strtooff: fix build for systems with long long but no strtoll [27] - o asyn-thread: Improved cleanup after OOM situations - o HELP-US.md: "How to get started helping out in the curl project" [29] - o curl.h: CURLSSLBACKEND_WOLFSSL used wrong value [30] - o unit1301: fix error message on first test - o ossfuzz: moving towards the ideal integration [31] - o http: fix a memory leakage in checkrtspprefix() - o examples/post-callback: stop returning one byte at a time - o schannel: return CURLE_SSL_CACERT on failed verification [33] - o MAIL-ETIQUETTE: added "1.9 Your emails are public" - o http-proxy: treat all 2xx as CONNECT success [34] - o openssl: use OpenSSL's default ciphers by default [35] - o runtests.pl: support attribute "nonewline" in part verify/upload - o configure: remove --enable-soname-bump and SONAME_BUMP [37] - o travis: add c-ares enabled builds linux + osx [38] - o vtls: fix WolfSSL 3.12 build problems [39] - o http-proxy: when not doing CONNECT, that phase is done immediately [40] - o configure: fix curl_off_t check's include order [41] - o configure: use -Wno-varargs on clang 3.9[.X] debug builds - o rtsp: do not call fwrite() with NULL pointer FILE * [42] - o mbedtls: enable CA path processing [43] - o travis: add build without HTTP/SMTP/IMAP - o checksrc: verify more code style rules [44] - o HTTP proxy: on connection re-use, still use the new remote port [45] - o tests: add initial gssapi test using stub implementation [46] - o rtsp: Segfault when using WRITEDATA [47] - o docs: clarify the CURLOPT_INTERLEAVE* options behavior - o non-ascii: use iconv() with 'char **' argument [48] - o server/getpart: provide dummy function to build conversion enabled - o conversions: fix several compiler warnings - o openssl: add missing includes [49] - o schannel: Support partial send for when data is too large [50] - o socks: fix incorrect port number in SOCKS4 error message [51] - o curl: fix integer overflow in timeout options [52] - o travis: on mac, don't install openssl or libidn [53] - o cookies: reject oversized cookies instead of truncating [54] - o cookies: use lock when using CURLINFO_COOKIELIST [55] - o curl: check fseek() return code and bail on error - o examples/post-callback: use long for CURLOPT_POSTFIELDSIZE - o openssl: only verify RSA private key if supported [56] - o tests: make the imap server not verify user+password [57] - o imap: quote atoms properly when escaping characters [58] - o tests: fix a compiler warning in test 643 - o file_range: avoid integer overflow when figuring out byte range [59] - o curl.h: include on cygwin too [60] - o reuse_conn: don't copy flags that are known to be equal [61] - o http: fix adding custom empty headers to repeated requests [62] - o docs: clarify the use of environment variables for proxy [63] - o docs: link CURLOPT_CONNECTTIMEOUT and CURLOPT_CONNECTTIMEOUT_MS [64] - o connect: fix race condition with happy eyeballs timeout [65] - o cookie: fix memory leak if path was set twice in header [66] - o vtls: compare and clone ssl configs properly [68] - o proxy: read the "no_proxy" variable only if necessary [69] - -This release includes the following known bugs: - - o see docs/KNOWN_BUGS (https://curl.haxx.se/docs/knownbugs.html) - -This release would not have looked like this without help, code, reports and -advice from friends like these: - - Anders Bakken, Andrei Karas, Benbuck Nason, Ben Greear, Benjamin Sergeant, - Bill Pyne, Brian Carpenter, Dan Fandrich, Daniel Stenberg, David Benjamin, - Dirk Feytons, Even Rouault, Frank Denis, Gergely Nagy, Gisle Vanem, - Ian Fette, imilli on github, Isaac Boukris, Jackarain on github, - Jakub Zakrzewski, Jan Alexander Steffens, Johannes Schindelin, - John David Anglin, joshhe on github, Kamil Dudka, Kevin Smith, - Lawrence Wagerfield, Maksim Stsepanenka, Marc Aldorasi, Marcel Raad, - Max Dymond, Michael Kaufmann, Michael Smith, Nick Zitzmann, - Nicolas Morey-Chaisemartin, Oli Kingshott, Patrick Monnerat, Pavel P, - Peter Lamare, Peter Wu, Ray Satiro, Rich Gray, Ryan Schmidt, Ryan Winograd, - SBKarr on github, Tatsuhiro Tsujikawa, Viktor Szakáts, - (47 contributors) - - Thanks! (and sorry if I forgot to mention someone) - -References to bug reports and discussions on issues: - - [1] = https://curl.haxx.se/bug/?i=1777 - [2] = https://curl.haxx.se/bug/?i=1758 - [3] = https://curl.haxx.se/bug/?i=1779 - [4] = https://curl.haxx.se/bug/?i=1785 - [5] = https://curl.haxx.se/bug/?i=1602 - [6] = https://curl.haxx.se/bug/?i=1784 - [7] = https://curl.haxx.se/bug/?i=1786 - [8] = https://curl.haxx.se/bug/?i=1790 - [9] = https://curl.haxx.se/bug/?i=1788 - [10] = https://curl.haxx.se/bug/?i=1793 - [11] = https://curl.haxx.se/bug/?i=1735 - [12] = https://curl.haxx.se/bug/?i=1782 - [13] = https://curl.haxx.se/bug/?i=1767 - [14] = https://curl.haxx.se/bug/?i=1803 - [15] = https://curl.haxx.se/bug/?i=1797 - [16] = https://curl.haxx.se/bug/?i=1021 - [17] = https://curl.haxx.se/bug/?i=1808 - [18] = https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872502#10 - [19] = https://curl.haxx.se/bug/?i=1799 - [20] = https://curl.haxx.se/bug/?i=1815 - [21] = https://curl.haxx.se/bug/?i=1751 - [22] = https://curl.haxx.se/bug/?i=1810 - [23] = https://curl.haxx.se/bug/?i=1818 - [24] = https://curl.haxx.se/bug/?i=1832 - [25] = https://curl.haxx.se/bug/?i=1828 - [26] = https://curl.haxx.se/bug/?i=1823 - [27] = https://curl.haxx.se/bug/?i=1829 - [28] = https://curl.haxx.se/libcurl/c/curl_global_sslset.html - [29] = https://curl.haxx.se/bug/?i=1837 - [30] = https://curl.haxx.se/mail/lib-2017-08/0120.html - [31] = https://curl.haxx.se/bug/?i=1842 - [32] = https://curl.haxx.se/bug/?i=1839 - [33] = https://curl.haxx.se/bug/?i=1858 - [34] = https://curl.haxx.se/bug/?i=1859 - [35] = https://curl.haxx.se/bug/?i=1846 - [36] = https://curl.haxx.se/bug/?i=1866 - [37] = https://curl.haxx.se/bug/?i=1861 - [38] = https://curl.haxx.se/bug/?i=1868 - [39] = https://curl.haxx.se/bug/?i=1865 - [40] = https://curl.haxx.se/bug/?i=1853 - [41] = https://curl.haxx.se/bug/?i=1870 - [42] = https://curl.haxx.se/bug/?i=1874 - [43] = https://curl.haxx.se/bug/?i=1877 - [44] = https://curl.haxx.se/bug/?i=1878 - [45] = https://curl.haxx.se/bug/?i=1887 - [46] = https://curl.haxx.se/bug/?i=1687 - [47] = https://curl.haxx.se/bug/?i=1880 - [48] = https://curl.haxx.se/mail/lib-2017-09/0031.html - [49] = https://curl.haxx.se/bug/?i=1891 - [50] = https://curl.haxx.se/bug/?i=1890 - [51] = https://curl.haxx.se/bug/?i=1892 - [52] = https://curl.haxx.se/bug/?i=1893 - [53] = https://curl.haxx.se/bug/?i=1895 - [54] = https://curl.haxx.se/bug/?i=1894 - [55] = https://curl.haxx.se/bug/?i=1896 - [56] = https://curl.haxx.se/bug/?i=1904 - [57] = https://curl.haxx.se/bug/?i=1902 - [58] = https://curl.haxx.se/bug/?i=1902 - [59] = https://curl.haxx.se/bug/?i=1908 - [60] = https://curl.haxx.se/bug/?i=1925 - [61] = https://curl.haxx.se/bug/?i=1918 - [62] = https://curl.haxx.se/bug/?i=1920 - [63] = https://curl.haxx.se/bug/?i=1921 - [64] = https://curl.haxx.se/bug/?i=1922 - [65] = https://curl.haxx.se/bug/?i=1928 - [66] = https://curl.haxx.se/bug/?i=1932 - [67] = https://curl.haxx.se/docs/adv_20171004.html - [68] = https://curl.haxx.se/bug/?i=1917 - [69] = https://curl.haxx.se/bug/?i=1919 diff --git a/dep/cpr/opt/curl/buildconf b/dep/cpr/opt/curl/buildconf deleted file mode 100644 index 50957531295..00000000000 --- a/dep/cpr/opt/curl/buildconf +++ /dev/null @@ -1,448 +0,0 @@ -#!/bin/sh -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### - -#-------------------------------------------------------------------------- -# die prints argument string to stdout and exits this shell script. -# -die(){ - echo "buildconf: $@" - exit 1 -} - -#-------------------------------------------------------------------------- -# findtool works as 'which' but we use a different name to make it more -# obvious we aren't using 'which'! ;-) -# Unlike 'which' does, the current directory is ignored. -# -findtool(){ - file="$1" - - if { echo "$file" | grep "/" >/dev/null 2>&1; } then - # when file is given with a path check it first - if test -f "$file"; then - echo "$file" - return - fi - fi - - old_IFS=$IFS; IFS=':' - for path in $PATH - do - IFS=$old_IFS - # echo "checks for $file in $path" >&2 - if test "$path" -a "$path" != '.' -a -f "$path/$file"; then - echo "$path/$file" - return - fi - done - IFS=$old_IFS -} - -#-------------------------------------------------------------------------- -# removethis() removes all files and subdirectories with the given name, -# inside and below the current subdirectory at invocation time. -# -removethis(){ - if test "$#" = "1"; then - find . -depth -name $1 -print > buildconf.tmp.$$ - while read fdname - do - if test -f "$fdname"; then - rm -f "$fdname" - elif test -d "$fdname"; then - rm -f -r "$fdname" - fi - done < buildconf.tmp.$$ - rm -f buildconf.tmp.$$ - fi -} - -#-------------------------------------------------------------------------- -# Ensure that buildconf runs from the subdirectory where configure.ac lives -# -if test ! -f configure.ac || - test ! -f src/tool_main.c || - test ! -f lib/urldata.h || - test ! -f include/curl/curl.h || - test ! -f m4/curl-functions.m4; then - echo "Can not run buildconf from outside of curl's source subdirectory!" - echo "Change to the subdirectory where buildconf is found, and try again." - exit 1 -fi - -#-------------------------------------------------------------------------- -# autoconf 2.57 or newer. Unpatched version 2.67 does not generate proper -# configure script. Unpatched version 2.68 is simply unusable, we should -# disallow 2.68 usage. -# -need_autoconf="2.57" -ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|head -n 1| sed -e 's/^[^0-9]*//' -e 's/[a-z]* *$//'` -if test -z "$ac_version"; then - echo "buildconf: autoconf not found." - echo " You need autoconf version $need_autoconf or newer installed." - exit 1 -fi -old_IFS=$IFS; IFS='.'; set $ac_version; IFS=$old_IFS -if test "$1" = "2" -a "$2" -lt "57" || test "$1" -lt "2"; then - echo "buildconf: autoconf version $ac_version found." - echo " You need autoconf version $need_autoconf or newer installed." - echo " If you have a sufficient autoconf installed, but it" - echo " is not named 'autoconf', then try setting the" - echo " AUTOCONF environment variable." - exit 1 -fi - -if test "$1" = "2" -a "$2" -eq "67"; then - echo "buildconf: autoconf version $ac_version (BAD)" - echo " Unpatched version generates broken configure script." -elif test "$1" = "2" -a "$2" -eq "68"; then - echo "buildconf: autoconf version $ac_version (BAD)" - echo " Unpatched version generates unusable configure script." -else - echo "buildconf: autoconf version $ac_version (ok)" -fi - -am4te_version=`${AUTOM4TE:-autom4te} --version 2>/dev/null|head -n 1| sed -e 's/autom4te\(.*\)/\1/' -e 's/^[^0-9]*//' -e 's/[a-z]* *$//'` -if test -z "$am4te_version"; then - echo "buildconf: autom4te not found. Weird autoconf installation!" - exit 1 -fi -if test "$am4te_version" = "$ac_version"; then - echo "buildconf: autom4te version $am4te_version (ok)" -else - echo "buildconf: autom4te version $am4te_version (ERROR: does not match autoconf version)" - exit 1 -fi - -#-------------------------------------------------------------------------- -# autoheader 2.50 or newer -# -ah_version=`${AUTOHEADER:-autoheader} --version 2>/dev/null|head -n 1| sed -e 's/^[^0-9]*//' -e 's/[a-z]* *$//'` -if test -z "$ah_version"; then - echo "buildconf: autoheader not found." - echo " You need autoheader version 2.50 or newer installed." - exit 1 -fi -old_IFS=$IFS; IFS='.'; set $ah_version; IFS=$old_IFS -if test "$1" = "2" -a "$2" -lt "50" || test "$1" -lt "2"; then - echo "buildconf: autoheader version $ah_version found." - echo " You need autoheader version 2.50 or newer installed." - echo " If you have a sufficient autoheader installed, but it" - echo " is not named 'autoheader', then try setting the" - echo " AUTOHEADER environment variable." - exit 1 -fi - -echo "buildconf: autoheader version $ah_version (ok)" - -#-------------------------------------------------------------------------- -# automake 1.7 or newer -# -need_automake="1.7" -am_version=`${AUTOMAKE:-automake} --version 2>/dev/null|head -n 1| sed -e 's/^.* \([0-9]\)/\1/' -e 's/[a-z]* *$//' -e 's/\(.*\)\(-p.*\)/\1/'` -if test -z "$am_version"; then - echo "buildconf: automake not found." - echo " You need automake version $need_automake or newer installed." - exit 1 -fi -old_IFS=$IFS; IFS='.'; set $am_version; IFS=$old_IFS -if test "$1" = "1" -a "$2" -lt "7" || test "$1" -lt "1"; then - echo "buildconf: automake version $am_version found." - echo " You need automake version $need_automake or newer installed." - echo " If you have a sufficient automake installed, but it" - echo " is not named 'automake', then try setting the" - echo " AUTOMAKE environment variable." - exit 1 -fi - -echo "buildconf: automake version $am_version (ok)" - -acloc_version=`${ACLOCAL:-aclocal} --version 2>/dev/null|head -n 1| sed -e 's/^.* \([0-9]\)/\1/' -e 's/[a-z]* *$//' -e 's/\(.*\)\(-p.*\)/\1/'` -if test -z "$acloc_version"; then - echo "buildconf: aclocal not found. Weird automake installation!" - exit 1 -fi -if test "$acloc_version" = "$am_version"; then - echo "buildconf: aclocal version $acloc_version (ok)" -else - echo "buildconf: aclocal version $acloc_version (ERROR: does not match automake version)" - exit 1 -fi - -#-------------------------------------------------------------------------- -# GNU libtoolize preliminary check -# -want_lt_major=1 -want_lt_minor=4 -want_lt_patch=2 -want_lt_version=1.4.2 - -# This approach that tries 'glibtoolize' first is intended for systems that -# have GNU libtool named as 'glibtoolize' and libtoolize not being GNU's. - -libtoolize=`findtool glibtoolize 2>/dev/null` -if test ! -x "$libtoolize"; then - libtoolize=`findtool ${LIBTOOLIZE:-libtoolize}` -fi -if test -z "$libtoolize"; then - echo "buildconf: libtoolize not found." - echo " You need GNU libtoolize $want_lt_version or newer installed." - exit 1 -fi - -lt_pver=`$libtoolize --version 2>/dev/null|head -n 1` -lt_qver=`echo $lt_pver|sed -e "s/([^)]*)//g" -e "s/^[^0-9]*//g"` -lt_version=`echo $lt_qver|sed -e "s/[- ].*//" -e "s/\([a-z]*\)$//"` -if test -z "$lt_version"; then - echo "buildconf: libtoolize not found." - echo " You need GNU libtoolize $want_lt_version or newer installed." - exit 1 -fi -old_IFS=$IFS; IFS='.'; set $lt_version; IFS=$old_IFS -lt_major=$1 -lt_minor=$2 -lt_patch=$3 - -if test -z "$lt_major"; then - lt_status="bad" -elif test "$lt_major" -gt "$want_lt_major"; then - lt_status="good" -elif test "$lt_major" -lt "$want_lt_major"; then - lt_status="bad" -elif test -z "$lt_minor"; then - lt_status="bad" -elif test "$lt_minor" -gt "$want_lt_minor"; then - lt_status="good" -elif test "$lt_minor" -lt "$want_lt_minor"; then - lt_status="bad" -elif test -z "$lt_patch"; then - lt_status="bad" -elif test "$lt_patch" -gt "$want_lt_patch"; then - lt_status="good" -elif test "$lt_patch" -lt "$want_lt_patch"; then - lt_status="bad" -else - lt_status="good" -fi -if test "$lt_status" != "good"; then - echo "buildconf: libtoolize version $lt_version found." - echo " You need GNU libtoolize $want_lt_version or newer installed." - exit 1 -fi - -echo "buildconf: libtoolize version $lt_version (ok)" - -#-------------------------------------------------------------------------- -# m4 check -# -m4=`(${M4:-m4} --version 0<&- || ${M4:-gm4} --version) 2>/dev/null 0<&- | head -n 1`; -m4_version=`echo $m4 | sed -e 's/^.* \([0-9]\)/\1/' -e 's/[a-z]* *$//'` - -if { echo $m4 | grep "GNU" >/dev/null 2>&1; } then - echo "buildconf: GNU m4 version $m4_version (ok)" -else - if test -z "$m4"; then - echo "buildconf: m4 version not recognized. You need a GNU m4 installed!" - else - echo "buildconf: m4 version $m4 found. You need a GNU m4 installed!" - fi - exit 1 -fi - -#-------------------------------------------------------------------------- -# perl check -# -PERL=`findtool ${PERL:-perl}` -if test -z "$PERL"; then - echo "buildconf: perl not found" - exit 1 -fi - -#-------------------------------------------------------------------------- -# Remove files generated on previous buildconf/configure run. -# -for fname in .deps \ - .libs \ - *.la \ - *.lo \ - *.a \ - *.o \ - Makefile \ - Makefile.in \ - aclocal.m4 \ - aclocal.m4.bak \ - ares_build.h \ - ares_config.h \ - ares_config.h.in \ - autom4te.cache \ - compile \ - config.guess \ - curl_config.h \ - curl_config.h.in \ - config.log \ - config.lt \ - config.status \ - config.sub \ - configure \ - configurehelp.pm \ - curl-config \ - depcomp \ - libcares.pc \ - libcurl.pc \ - libtool \ - libtool.m4 \ - libtool.m4.tmp \ - ltmain.sh \ - ltoptions.m4 \ - ltsugar.m4 \ - ltversion.m4 \ - lt~obsolete.m4 \ - missing \ - install-sh \ - stamp-h1 \ - stamp-h2 \ - stamp-h3 ; do - removethis "$fname" -done - -#-------------------------------------------------------------------------- -# run the correct scripts now -# - -echo "buildconf: running libtoolize" -${libtoolize} --copy --force || die "libtoolize command failed" - -# When using libtool 1.5.X (X < 26) we copy libtool.m4 to our local m4 -# subdirectory and this local copy is patched to fix some warnings that -# are triggered when running aclocal and using autoconf 2.62 or later. - -if test "$lt_major" = "1" && test "$lt_minor" = "5"; then - if test -z "$lt_patch" || test "$lt_patch" -lt "26"; then - echo "buildconf: copying libtool.m4 to local m4 subdir" - ac_dir=`${ACLOCAL:-aclocal} --print-ac-dir` - if test -f $ac_dir/libtool.m4; then - cp -f $ac_dir/libtool.m4 m4/libtool.m4 - else - echo "buildconf: $ac_dir/libtool.m4 not found" - fi - if test -f m4/libtool.m4; then - echo "buildconf: renaming some variables in local m4/libtool.m4" - $PERL -i.tmp -pe \ - 's/lt_prog_compiler_pic_works/lt_cv_prog_compiler_pic_works/g; \ - s/lt_prog_compiler_static_works/lt_cv_prog_compiler_static_works/g;' \ - m4/libtool.m4 - rm -f m4/libtool.m4.tmp - fi - fi -fi - -if test -f m4/libtool.m4; then - echo "buildconf: converting all mv to mv -f in local m4/libtool.m4" - $PERL -i.tmp -pe 's/\bmv +([^-\s])/mv -f $1/g' m4/libtool.m4 - rm -f m4/libtool.m4.tmp -fi - -echo "buildconf: running aclocal" -${ACLOCAL:-aclocal} -I m4 $ACLOCAL_FLAGS || die "aclocal command failed" - -echo "buildconf: converting all mv to mv -f in local aclocal.m4" -$PERL -i.bak -pe 's/\bmv +([^-\s])/mv -f $1/g' aclocal.m4 - -echo "buildconf: running autoheader" -${AUTOHEADER:-autoheader} || die "autoheader command failed" - -echo "buildconf: running autoconf" -${AUTOCONF:-autoconf} || die "autoconf command failed" - -if test -d ares; then - cd ares - echo "buildconf: running in ares" - ./buildconf - cd .. -fi - -echo "buildconf: running automake" -${AUTOMAKE:-automake} --add-missing --copy || die "automake command failed" - -#-------------------------------------------------------------------------- -# GNU libtool complementary check -# -# Depending on the libtool and automake versions being used, config.guess -# might not be installed in the subdirectory until automake has finished. -# So we can not attempt to use it until this very last buildconf stage. -# -if test ! -f ./config.guess; then - echo "buildconf: config.guess not found" -else - buildhost=`./config.guess 2>/dev/null|head -n 1` - case $buildhost in - *-*-darwin*) - need_lt_major=1 - need_lt_minor=5 - need_lt_patch=26 - need_lt_check="yes" - ;; - *-*-hpux*) - need_lt_major=1 - need_lt_minor=5 - need_lt_patch=24 - need_lt_check="yes" - ;; - esac - if test ! -z "$need_lt_check"; then - if test -z "$lt_major"; then - lt_status="bad" - elif test "$lt_major" -gt "$need_lt_major"; then - lt_status="good" - elif test "$lt_major" -lt "$need_lt_major"; then - lt_status="bad" - elif test -z "$lt_minor"; then - lt_status="bad" - elif test "$lt_minor" -gt "$need_lt_minor"; then - lt_status="good" - elif test "$lt_minor" -lt "$need_lt_minor"; then - lt_status="bad" - elif test -z "$lt_patch"; then - lt_status="bad" - elif test "$lt_patch" -gt "$need_lt_patch"; then - lt_status="good" - elif test "$lt_patch" -lt "$need_lt_patch"; then - lt_status="bad" - else - lt_status="good" - fi - if test "$lt_status" != "good"; then - need_lt_version="$need_lt_major.$need_lt_minor.$need_lt_patch" - echo "buildconf: libtool version $lt_version found." - echo " $buildhost requires GNU libtool $need_lt_version or newer installed." - rm -f configure - exit 1 - fi - fi -fi - -#-------------------------------------------------------------------------- -# Finished successfully. -# -echo "buildconf: OK" -exit 0 diff --git a/dep/cpr/opt/curl/buildconf.bat b/dep/cpr/opt/curl/buildconf.bat deleted file mode 100644 index da5c0391af7..00000000000 --- a/dep/cpr/opt/curl/buildconf.bat +++ /dev/null @@ -1,317 +0,0 @@ -@echo off -rem *************************************************************************** -rem * _ _ ____ _ -rem * Project ___| | | | _ \| | -rem * / __| | | | |_) | | -rem * | (__| |_| | _ <| |___ -rem * \___|\___/|_| \_\_____| -rem * -rem * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. -rem * -rem * This software is licensed as described in the file COPYING, which -rem * you should have received as part of this distribution. The terms -rem * are also available at https://curl.haxx.se/docs/copyright.html. -rem * -rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell -rem * copies of the Software, and permit persons to whom the Software is -rem * furnished to do so, under the terms of the COPYING file. -rem * -rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -rem * KIND, either express or implied. -rem * -rem *************************************************************************** - -rem NOTES -rem -rem This batch file must be used to set up a git tree to build on systems where -rem there is no autotools support (i.e. DOS and Windows). -rem - -:begin - rem Set our variables - if "%OS%" == "Windows_NT" setlocal - set MODE=GENERATE - - rem Switch to this batch file's directory - cd /d "%~0\.." 1>NUL 2>&1 - - rem Check we are running from a curl git repository - if not exist GIT-INFO goto norepo - - rem Detect programs. HAVE_ - rem When not found the variable is set undefined. The undefined pattern - rem allows for statements like "if not defined HAVE_PERL (command)" - groff --version NUL 2>&1 - if errorlevel 1 (set HAVE_GROFF=) else (set HAVE_GROFF=Y) - nroff --version NUL 2>&1 - if errorlevel 1 (set HAVE_NROFF=) else (set HAVE_NROFF=Y) - perl --version NUL 2>&1 - if errorlevel 1 (set HAVE_PERL=) else (set HAVE_PERL=Y) - gzip --version NUL 2>&1 - if errorlevel 1 (set HAVE_GZIP=) else (set HAVE_GZIP=Y) - -:parseArgs - if "%~1" == "" goto start - - if /i "%~1" == "-clean" ( - set MODE=CLEAN - ) else if /i "%~1" == "-?" ( - goto syntax - ) else if /i "%~1" == "-h" ( - goto syntax - ) else if /i "%~1" == "-help" ( - goto syntax - ) else ( - goto unknown - ) - - shift & goto parseArgs - -:start - if "%MODE%" == "GENERATE" ( - echo. - echo Generating prerequisite files - - call :generate - if errorlevel 3 goto nogenhugehelp - if errorlevel 2 goto nogenmakefile - if errorlevel 1 goto warning - - ) else ( - echo. - echo Removing prerequisite files - - call :clean - if errorlevel 2 goto nocleanhugehelp - if errorlevel 1 goto nocleanmakefile - ) - - goto success - -rem Main generate function. -rem -rem Returns: -rem -rem 0 - success -rem 1 - success with simplified tool_hugehelp.c -rem 2 - failed to generate Makefile -rem 3 - failed to generate tool_hugehelp.c -rem -:generate - if "%OS%" == "Windows_NT" setlocal - set BASIC_HUGEHELP=0 - - rem Create Makefile - echo * %CD%\Makefile - if exist Makefile.dist ( - copy /Y Makefile.dist Makefile 1>NUL 2>&1 - if errorlevel 1 ( - if "%OS%" == "Windows_NT" endlocal - exit /B 2 - ) - ) - - rem Create tool_hugehelp.c - echo * %CD%\src\tool_hugehelp.c - call :genHugeHelp - if errorlevel 2 ( - if "%OS%" == "Windows_NT" endlocal - exit /B 3 - ) - if errorlevel 1 ( - set BASIC_HUGEHELP=1 - ) - cmd /c exit 0 - - rem Setup c-ares git tree - if exist ares\buildconf.bat ( - echo. - echo Configuring c-ares build environment - cd ares - call buildconf.bat - cd .. - ) - - if "%BASIC_HUGEHELP%" == "1" ( - if "%OS%" == "Windows_NT" endlocal - exit /B 1 - ) - - if "%OS%" == "Windows_NT" endlocal - exit /B 0 - -rem Main clean function. -rem -rem Returns: -rem -rem 0 - success -rem 1 - failed to clean Makefile -rem 2 - failed to clean tool_hugehelp.c -rem -:clean - rem Remove Makefile - echo * %CD%\Makefile - if exist Makefile ( - del Makefile 2>NUL - if exist Makefile ( - exit /B 1 - ) - ) - - rem Remove tool_hugehelp.c - echo * %CD%\src\tool_hugehelp.c - if exist src\tool_hugehelp.c ( - del src\tool_hugehelp.c 2>NUL - if exist src\tool_hugehelp.c ( - exit /B 2 - ) - ) - - exit /B - -rem Function to generate src\tool_hugehelp.c -rem -rem Returns: -rem -rem 0 - full tool_hugehelp.c generated -rem 1 - simplified tool_hugehelp.c -rem 2 - failure -rem -:genHugeHelp - if "%OS%" == "Windows_NT" setlocal - set LC_ALL=C - set ROFFCMD= - set BASIC=1 - - if defined HAVE_PERL ( - if defined HAVE_GROFF ( - set ROFFCMD=groff -mtty-char -Tascii -P-c -man - ) else if defined HAVE_NROFF ( - set ROFFCMD=nroff -c -Tascii -man - ) - ) - - if defined ROFFCMD ( - echo #include "tool_setup.h"> src\tool_hugehelp.c - echo #include "tool_hugehelp.h">> src\tool_hugehelp.c - - if defined HAVE_GZIP ( - echo #ifndef HAVE_LIBZ>> src\tool_hugehelp.c - ) - - %ROFFCMD% docs\curl.1 2>NUL | perl src\mkhelp.pl docs\MANUAL >> src\tool_hugehelp.c - if defined HAVE_GZIP ( - echo #else>> src\tool_hugehelp.c - %ROFFCMD% docs\curl.1 2>NUL | perl src\mkhelp.pl -c docs\MANUAL >> src\tool_hugehelp.c - echo #endif /^* HAVE_LIBZ ^*/>> src\tool_hugehelp.c - ) - - set BASIC=0 - ) else ( - if exist src\tool_hugehelp.c.cvs ( - copy /Y src\tool_hugehelp.c.cvs src\tool_hugehelp.c 1>NUL 2>&1 - ) else ( - echo #include "tool_setup.h"> src\tool_hugehelp.c - echo #include "tool_hugehelp.hd">> src\tool_hugehelp.c - echo.>> src\tool_hugehelp.c - echo void hugehelp(void^)>> src\tool_hugehelp.c - echo {>> src\tool_hugehelp.c - echo #ifdef USE_MANUAL>> src\tool_hugehelp.c - echo fputs("Built-in manual not included\n", stdout^);>> src\tool_hugehelp.c - echo #endif>> src\tool_hugehelp.c - echo }>> src\tool_hugehelp.c - ) - ) - - findstr "/C:void hugehelp(void)" src\tool_hugehelp.c 1>NUL 2>&1 - if errorlevel 1 ( - if "%OS%" == "Windows_NT" endlocal - exit /B 2 - ) - - if "%BASIC%" == "1" ( - if "%OS%" == "Windows_NT" endlocal - exit /B 1 - ) - - if "%OS%" == "Windows_NT" endlocal - exit /B 0 - -rem Function to clean-up local variables under DOS, Windows 3.x and -rem Windows 9x as setlocal isn't available until Windows NT -rem -:dosCleanup - set MODE= - set HAVE_GROFF= - set HAVE_NROFF= - set HAVE_PERL= - set HAVE_GZIP= - set BASIC_HUGEHELP= - set LC_ALL - set ROFFCMD= - set BASIC= - - exit /B - -:syntax - rem Display the help - echo. - echo Usage: buildconf [-clean] - echo. - echo -clean - Removes the files - goto error - -:unknown - echo. - echo Error: Unknown argument '%1' - goto error - -:norepo - echo. - echo Error: This batch file should only be used with a curl git repository - goto error - -:nogenmakefile - echo. - echo Error: Unable to generate Makefile - goto error - -:nogenhugehelp - echo. - echo Error: Unable to generate src\tool_hugehelp.c - goto error - -:nocleanmakefile - echo. - echo Error: Unable to clean Makefile - goto error - -:nocleanhugehelp - echo. - echo Error: Unable to clean src\tool_hugehelp.c - goto error - -:warning - echo. - echo Warning: The curl manual could not be integrated in the source. This means when - echo you build curl the manual will not be available (curl --man^). Integration of - echo the manual is not required and a summary of the options will still be available - echo (curl --help^). To integrate the manual your PATH is required to have - echo groff/nroff, perl and optionally gzip for compression. - goto success - -:error - if "%OS%" == "Windows_NT" ( - endlocal - ) else ( - call :dosCleanup - ) - exit /B 1 - -:success - if "%OS%" == "Windows_NT" ( - endlocal - ) else ( - call :dosCleanup - ) - exit /B 0 diff --git a/dep/cpr/opt/curl/curl-config.in b/dep/cpr/opt/curl/curl-config.in deleted file mode 100644 index af484b44575..00000000000 --- a/dep/cpr/opt/curl/curl-config.in +++ /dev/null @@ -1,178 +0,0 @@ -#! /bin/sh -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2001 - 2012, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -includedir=@includedir@ -cppflag_curl_staticlib=@CPPFLAG_CURL_STATICLIB@ - -usage() -{ - cat <&2 - exit 1 - fi - ;; - - --configure) - echo @CONFIGURE_OPTIONS@ - ;; - - *) - echo "unknown option: $1" - usage 1 - ;; - esac - shift -done - -exit 0 diff --git a/dep/cpr/opt/curl/include/Makefile.am b/dep/cpr/opt/curl/include/Makefile.am deleted file mode 100644 index 3b248602995..00000000000 --- a/dep/cpr/opt/curl/include/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -SUBDIRS = curl - -EXTRA_DIST = README - -AUTOMAKE_OPTIONS = foreign no-dependencies diff --git a/dep/cpr/opt/curl/include/README b/dep/cpr/opt/curl/include/README deleted file mode 100644 index c2589ec8c40..00000000000 --- a/dep/cpr/opt/curl/include/README +++ /dev/null @@ -1,33 +0,0 @@ - _ _ ____ _ - ___| | | | _ \| | - / __| | | | |_) | | - | (__| |_| | _ <| |___ - \___|\___/|_| \_\_____| - -Include files for libcurl, external users. - -They're all placed in the curl subdirectory here for better fit in any kind -of environment. You must include files from here using... - - #include - -... style and point the compiler's include path to the directory holding the -curl subdirectory. It makes it more likely to survive future modifications. - -NOTE FOR LIBCURL HACKERS - -* If you check out from git on a non-configure platform, you must run the - appropriate buildconf* script to set up files before being able of compiling - the library. - -* We cannot assume anything else but very basic compiler features being - present. While libcurl requires an ANSI C compiler to build, some of the - earlier ANSI compilers clearly can't deal with some preprocessor operators. - -* Newlines must remain unix-style for older compilers' sake. - -* Comments must be written in the old-style /* unnested C-fashion */ - -To figure out how to do good and portable checks for features, operating -systems or specific hardwarare, a very good resource is Bjorn Reese's -collection at https://sourceforge.net/p/predef/wiki/ diff --git a/dep/cpr/opt/curl/include/curl/.gitignore b/dep/cpr/opt/curl/include/curl/.gitignore deleted file mode 100644 index 555795fae21..00000000000 --- a/dep/cpr/opt/curl/include/curl/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -curlver.h.dist -stamp-h2 -stamp-h3 diff --git a/dep/cpr/opt/curl/include/curl/Makefile.am b/dep/cpr/opt/curl/include/curl/Makefile.am deleted file mode 100644 index 989d4a21811..00000000000 --- a/dep/cpr/opt/curl/include/curl/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### -pkginclude_HEADERS = \ - curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \ - typecheck-gcc.h system.h - -pkgincludedir= $(includedir)/curl - -checksrc: - @@PERL@ $(top_srcdir)/lib/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS) - -if CURLDEBUG -# for debug builds, we scan the sources on all regular make invokes -all-local: checksrc -endif diff --git a/dep/cpr/opt/curl/include/curl/curl.h b/dep/cpr/opt/curl/include/curl/curl.h deleted file mode 100644 index 7139a33110b..00000000000 --- a/dep/cpr/opt/curl/include/curl/curl.h +++ /dev/null @@ -1,2740 +0,0 @@ -#ifndef __CURL_CURL_H -#define __CURL_CURL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * If you have libcurl problems, all docs and details are found here: - * https://curl.haxx.se/libcurl/ - * - * curl-library mailing list subscription and unsubscription web interface: - * https://cool.haxx.se/mailman/listinfo/curl-library/ - */ - -#ifdef CURL_NO_OLDIES -#define CURL_STRICTER -#endif - -#include "curlver.h" /* libcurl version defines */ -#include "system.h" /* determine things run-time */ - -/* - * Define WIN32 when build target is Win32 API - */ - -#if (defined(_WIN32) || defined(__WIN32__)) && \ - !defined(WIN32) && !defined(__SYMBIAN32__) -#define WIN32 -#endif - -#include -#include - -#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) -/* Needed for __FreeBSD_version symbol definition */ -#include -#endif - -/* The include stuff here below is mainly for time_t! */ -#include -#include - -#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) -#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ - defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) -/* The check above prevents the winsock2 inclusion if winsock.h already was - included, since they can't co-exist without problems */ -#include -#include -#endif -#endif - -/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish - libc5-based Linux systems. Only include it on systems that are known to - require it! */ -#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ - defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ - defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ - defined(__CYGWIN__) || \ - (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) -#include -#endif - -#if !defined(WIN32) && !defined(_WIN32_WCE) -#include -#endif - -#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) -#include -#endif - -#ifdef __BEOS__ -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) -typedef struct Curl_easy CURL; -typedef struct Curl_share CURLSH; -#else -typedef void CURL; -typedef void CURLSH; -#endif - -/* - * libcurl external API function linkage decorations. - */ - -#ifdef CURL_STATICLIB -# define CURL_EXTERN -#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) -# if defined(BUILDING_LIBCURL) -# define CURL_EXTERN __declspec(dllexport) -# else -# define CURL_EXTERN __declspec(dllimport) -# endif -#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) -# define CURL_EXTERN CURL_EXTERN_SYMBOL -#else -# define CURL_EXTERN -#endif - -#ifndef curl_socket_typedef -/* socket typedef */ -#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) -typedef SOCKET curl_socket_t; -#define CURL_SOCKET_BAD INVALID_SOCKET -#else -typedef int curl_socket_t; -#define CURL_SOCKET_BAD -1 -#endif -#define curl_socket_typedef -#endif /* curl_socket_typedef */ - -/* enum for the different supported SSL backends */ -typedef enum { - CURLSSLBACKEND_NONE = 0, - CURLSSLBACKEND_OPENSSL = 1, - CURLSSLBACKEND_GNUTLS = 2, - CURLSSLBACKEND_NSS = 3, - CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ - CURLSSLBACKEND_GSKIT = 5, - CURLSSLBACKEND_POLARSSL = 6, - CURLSSLBACKEND_WOLFSSL = 7, - CURLSSLBACKEND_SCHANNEL = 8, - CURLSSLBACKEND_DARWINSSL = 9, - CURLSSLBACKEND_AXTLS = 10, - CURLSSLBACKEND_MBEDTLS = 11 -} curl_sslbackend; - -/* aliases for library clones and renames */ -#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL -#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL -#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL - -struct curl_httppost { - struct curl_httppost *next; /* next entry in the list */ - char *name; /* pointer to allocated name */ - long namelength; /* length of name length */ - char *contents; /* pointer to allocated data contents */ - long contentslength; /* length of contents field, see also - CURL_HTTPPOST_LARGE */ - char *buffer; /* pointer to allocated buffer contents */ - long bufferlength; /* length of buffer field */ - char *contenttype; /* Content-Type */ - struct curl_slist *contentheader; /* list of extra headers for this form */ - struct curl_httppost *more; /* if one field name has more than one - file, this link should link to following - files */ - long flags; /* as defined below */ - -/* specified content is a file name */ -#define CURL_HTTPPOST_FILENAME (1<<0) -/* specified content is a file name */ -#define CURL_HTTPPOST_READFILE (1<<1) -/* name is only stored pointer do not free in formfree */ -#define CURL_HTTPPOST_PTRNAME (1<<2) -/* contents is only stored pointer do not free in formfree */ -#define CURL_HTTPPOST_PTRCONTENTS (1<<3) -/* upload file from buffer */ -#define CURL_HTTPPOST_BUFFER (1<<4) -/* upload file from pointer contents */ -#define CURL_HTTPPOST_PTRBUFFER (1<<5) -/* upload file contents by using the regular read callback to get the data and - pass the given pointer as custom pointer */ -#define CURL_HTTPPOST_CALLBACK (1<<6) -/* use size in 'contentlen', added in 7.46.0 */ -#define CURL_HTTPPOST_LARGE (1<<7) - - char *showfilename; /* The file name to show. If not set, the - actual file name will be used (if this - is a file part) */ - void *userp; /* custom pointer used for - HTTPPOST_CALLBACK posts */ - curl_off_t contentlen; /* alternative length of contents - field. Used if CURL_HTTPPOST_LARGE is - set. Added in 7.46.0 */ -}; - -/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered - deprecated but was the only choice up until 7.31.0 */ -typedef int (*curl_progress_callback)(void *clientp, - double dltotal, - double dlnow, - double ultotal, - double ulnow); - -/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in - 7.32.0, it avoids floating point and provides more detailed information. */ -typedef int (*curl_xferinfo_callback)(void *clientp, - curl_off_t dltotal, - curl_off_t dlnow, - curl_off_t ultotal, - curl_off_t ulnow); - -#ifndef CURL_MAX_READ_SIZE - /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ -#define CURL_MAX_READ_SIZE 524288 -#endif - -#ifndef CURL_MAX_WRITE_SIZE - /* Tests have proven that 20K is a very bad buffer size for uploads on - Windows, while 16K for some odd reason performed a lot better. - We do the ifndef check to allow this value to easier be changed at build - time for those who feel adventurous. The practical minimum is about - 400 bytes since libcurl uses a buffer of this size as a scratch area - (unrelated to network send operations). */ -#define CURL_MAX_WRITE_SIZE 16384 -#endif - -#ifndef CURL_MAX_HTTP_HEADER -/* The only reason to have a max limit for this is to avoid the risk of a bad - server feeding libcurl with a never-ending header that will cause reallocs - infinitely */ -#define CURL_MAX_HTTP_HEADER (100*1024) -#endif - -/* This is a magic return code for the write callback that, when returned, - will signal libcurl to pause receiving on the current transfer. */ -#define CURL_WRITEFUNC_PAUSE 0x10000001 - -typedef size_t (*curl_write_callback)(char *buffer, - size_t size, - size_t nitems, - void *outstream); - - - -/* enumeration of file types */ -typedef enum { - CURLFILETYPE_FILE = 0, - CURLFILETYPE_DIRECTORY, - CURLFILETYPE_SYMLINK, - CURLFILETYPE_DEVICE_BLOCK, - CURLFILETYPE_DEVICE_CHAR, - CURLFILETYPE_NAMEDPIPE, - CURLFILETYPE_SOCKET, - CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ - - CURLFILETYPE_UNKNOWN /* should never occur */ -} curlfiletype; - -#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) -#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) -#define CURLFINFOFLAG_KNOWN_TIME (1<<2) -#define CURLFINFOFLAG_KNOWN_PERM (1<<3) -#define CURLFINFOFLAG_KNOWN_UID (1<<4) -#define CURLFINFOFLAG_KNOWN_GID (1<<5) -#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) -#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) - -/* Content of this structure depends on information which is known and is - achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man - page for callbacks returning this structure -- some fields are mandatory, - some others are optional. The FLAG field has special meaning. */ -struct curl_fileinfo { - char *filename; - curlfiletype filetype; - time_t time; - unsigned int perm; - int uid; - int gid; - curl_off_t size; - long int hardlinks; - - struct { - /* If some of these fields is not NULL, it is a pointer to b_data. */ - char *time; - char *perm; - char *user; - char *group; - char *target; /* pointer to the target filename of a symlink */ - } strings; - - unsigned int flags; - - /* used internally */ - char *b_data; - size_t b_size; - size_t b_used; -}; - -/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ -#define CURL_CHUNK_BGN_FUNC_OK 0 -#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ -#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ - -/* if splitting of data transfer is enabled, this callback is called before - download of an individual chunk started. Note that parameter "remains" works - only for FTP wildcard downloading (for now), otherwise is not used */ -typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, - void *ptr, - int remains); - -/* return codes for CURLOPT_CHUNK_END_FUNCTION */ -#define CURL_CHUNK_END_FUNC_OK 0 -#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ - -/* If splitting of data transfer is enabled this callback is called after - download of an individual chunk finished. - Note! After this callback was set then it have to be called FOR ALL chunks. - Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. - This is the reason why we don't need "transfer_info" parameter in this - callback and we are not interested in "remains" parameter too. */ -typedef long (*curl_chunk_end_callback)(void *ptr); - -/* return codes for FNMATCHFUNCTION */ -#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ -#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ -#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ - -/* callback type for wildcard downloading pattern matching. If the - string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ -typedef int (*curl_fnmatch_callback)(void *ptr, - const char *pattern, - const char *string); - -/* These are the return codes for the seek callbacks */ -#define CURL_SEEKFUNC_OK 0 -#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ -#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so - libcurl might try other means instead */ -typedef int (*curl_seek_callback)(void *instream, - curl_off_t offset, - int origin); /* 'whence' */ - -/* This is a return code for the read callback that, when returned, will - signal libcurl to immediately abort the current transfer. */ -#define CURL_READFUNC_ABORT 0x10000000 -/* This is a return code for the read callback that, when returned, will - signal libcurl to pause sending data on the current transfer. */ -#define CURL_READFUNC_PAUSE 0x10000001 - -typedef size_t (*curl_read_callback)(char *buffer, - size_t size, - size_t nitems, - void *instream); - -typedef enum { - CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ - CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ - CURLSOCKTYPE_LAST /* never use */ -} curlsocktype; - -/* The return code from the sockopt_callback can signal information back - to libcurl: */ -#define CURL_SOCKOPT_OK 0 -#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return - CURLE_ABORTED_BY_CALLBACK */ -#define CURL_SOCKOPT_ALREADY_CONNECTED 2 - -typedef int (*curl_sockopt_callback)(void *clientp, - curl_socket_t curlfd, - curlsocktype purpose); - -struct curl_sockaddr { - int family; - int socktype; - int protocol; - unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it - turned really ugly and painful on the systems that - lack this type */ - struct sockaddr addr; -}; - -typedef curl_socket_t -(*curl_opensocket_callback)(void *clientp, - curlsocktype purpose, - struct curl_sockaddr *address); - -typedef int -(*curl_closesocket_callback)(void *clientp, curl_socket_t item); - -typedef enum { - CURLIOE_OK, /* I/O operation successful */ - CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ - CURLIOE_FAILRESTART, /* failed to restart the read */ - CURLIOE_LAST /* never use */ -} curlioerr; - -typedef enum { - CURLIOCMD_NOP, /* no operation */ - CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ - CURLIOCMD_LAST /* never use */ -} curliocmd; - -typedef curlioerr (*curl_ioctl_callback)(CURL *handle, - int cmd, - void *clientp); - -#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS -/* - * The following typedef's are signatures of malloc, free, realloc, strdup and - * calloc respectively. Function pointers of these types can be passed to the - * curl_global_init_mem() function to set user defined memory management - * callback routines. - */ -typedef void *(*curl_malloc_callback)(size_t size); -typedef void (*curl_free_callback)(void *ptr); -typedef void *(*curl_realloc_callback)(void *ptr, size_t size); -typedef char *(*curl_strdup_callback)(const char *str); -typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); - -#define CURL_DID_MEMORY_FUNC_TYPEDEFS -#endif - -/* the kind of data that is passed to information_callback*/ -typedef enum { - CURLINFO_TEXT = 0, - CURLINFO_HEADER_IN, /* 1 */ - CURLINFO_HEADER_OUT, /* 2 */ - CURLINFO_DATA_IN, /* 3 */ - CURLINFO_DATA_OUT, /* 4 */ - CURLINFO_SSL_DATA_IN, /* 5 */ - CURLINFO_SSL_DATA_OUT, /* 6 */ - CURLINFO_END -} curl_infotype; - -typedef int (*curl_debug_callback) - (CURL *handle, /* the handle/transfer this concerns */ - curl_infotype type, /* what kind of data */ - char *data, /* points to the data */ - size_t size, /* size of the data pointed to */ - void *userptr); /* whatever the user please */ - -/* All possible error codes from all sorts of curl functions. Future versions - may return other values, stay prepared. - - Always add new return codes last. Never *EVER* remove any. The return - codes must remain the same! - */ - -typedef enum { - CURLE_OK = 0, - CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ - CURLE_FAILED_INIT, /* 2 */ - CURLE_URL_MALFORMAT, /* 3 */ - CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for - 7.17.0, reused in April 2011 for 7.21.5] */ - CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ - CURLE_COULDNT_RESOLVE_HOST, /* 6 */ - CURLE_COULDNT_CONNECT, /* 7 */ - CURLE_WEIRD_SERVER_REPLY, /* 8 */ - CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server - due to lack of access - when login fails - this is not returned. */ - CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for - 7.15.4, reused in Dec 2011 for 7.24.0]*/ - CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ - CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server - [was obsoleted in August 2007 for 7.17.0, - reused in Dec 2011 for 7.24.0]*/ - CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ - CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ - CURLE_FTP_CANT_GET_HOST, /* 15 */ - CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. - [was obsoleted in August 2007 for 7.17.0, - reused in July 2014 for 7.38.0] */ - CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ - CURLE_PARTIAL_FILE, /* 18 */ - CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ - CURLE_OBSOLETE20, /* 20 - NOT USED */ - CURLE_QUOTE_ERROR, /* 21 - quote command failure */ - CURLE_HTTP_RETURNED_ERROR, /* 22 */ - CURLE_WRITE_ERROR, /* 23 */ - CURLE_OBSOLETE24, /* 24 - NOT USED */ - CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ - CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ - CURLE_OUT_OF_MEMORY, /* 27 */ - /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error - instead of a memory allocation error if CURL_DOES_CONVERSIONS - is defined - */ - CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ - CURLE_OBSOLETE29, /* 29 - NOT USED */ - CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ - CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ - CURLE_OBSOLETE32, /* 32 - NOT USED */ - CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ - CURLE_HTTP_POST_ERROR, /* 34 */ - CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ - CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ - CURLE_FILE_COULDNT_READ_FILE, /* 37 */ - CURLE_LDAP_CANNOT_BIND, /* 38 */ - CURLE_LDAP_SEARCH_FAILED, /* 39 */ - CURLE_OBSOLETE40, /* 40 - NOT USED */ - CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ - CURLE_ABORTED_BY_CALLBACK, /* 42 */ - CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ - CURLE_OBSOLETE44, /* 44 - NOT USED */ - CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ - CURLE_OBSOLETE46, /* 46 - NOT USED */ - CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ - CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ - CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ - CURLE_OBSOLETE50, /* 50 - NOT USED */ - CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint - wasn't verified fine */ - CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ - CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ - CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as - default */ - CURLE_SEND_ERROR, /* 55 - failed sending network data */ - CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ - CURLE_OBSOLETE57, /* 57 - NOT IN USE */ - CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ - CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ - CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ - CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ - CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ - CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ - CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ - CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind - that failed */ - CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ - CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not - accepted and we failed to login */ - CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ - CURLE_TFTP_PERM, /* 69 - permission problem on server */ - CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ - CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ - CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ - CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ - CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ - CURLE_CONV_FAILED, /* 75 - conversion failed */ - CURLE_CONV_REQD, /* 76 - caller must register conversion - callbacks using curl_easy_setopt options - CURLOPT_CONV_FROM_NETWORK_FUNCTION, - CURLOPT_CONV_TO_NETWORK_FUNCTION, and - CURLOPT_CONV_FROM_UTF8_FUNCTION */ - CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing - or wrong format */ - CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ - CURLE_SSH, /* 79 - error from the SSH layer, somewhat - generic so the error message will be of - interest when this has happened */ - - CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL - connection */ - CURLE_AGAIN, /* 81 - socket is not ready for send/recv, - wait till it's ready and try again (Added - in 7.18.2) */ - CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or - wrong format (Added in 7.19.0) */ - CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in - 7.19.0) */ - CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ - CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ - CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ - CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ - CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ - CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the - session will be queued */ - CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not - match */ - CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ - CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer - */ - CURL_LAST /* never use! */ -} CURLcode; - -#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all - the obsolete stuff removed! */ - -/* Previously obsolete error code re-used in 7.38.0 */ -#define CURLE_OBSOLETE16 CURLE_HTTP2 - -/* Previously obsolete error codes re-used in 7.24.0 */ -#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED -#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT - -/* compatibility with older names */ -#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING -#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY - -/* The following were added in 7.21.5, April 2011 */ -#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION - -/* The following were added in 7.17.1 */ -/* These are scheduled to disappear by 2009 */ -#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION - -/* The following were added in 7.17.0 */ -/* These are scheduled to disappear by 2009 */ -#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ -#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 -#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 -#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 -#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 -#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 -#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 -#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 -#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 -#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 -#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 -#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 -#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN - -#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED -#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE -#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR -#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL -#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS -#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR -#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED - -/* The following were added earlier */ - -#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT - -#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR -#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED -#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED - -#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE -#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME - -/* This was the error code 50 in 7.7.3 and a few earlier versions, this - is no longer used by libcurl but is instead #defined here only to not - make programs break */ -#define CURLE_ALREADY_COMPLETE 99999 - -/* Provide defines for really old option names */ -#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ -#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ -#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA - -/* Since long deprecated options with no code in the lib that does anything - with them. */ -#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 -#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 - -#endif /*!CURL_NO_OLDIES*/ - -/* This prototype applies to all conversion callbacks */ -typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); - -typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ - void *ssl_ctx, /* actually an - OpenSSL SSL_CTX */ - void *userptr); - -typedef enum { - CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use - CONNECT HTTP/1.1 */ - CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT - HTTP/1.0 */ - CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ - CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already - in 7.10 */ - CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ - CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ - CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the - host name rather than the IP address. added - in 7.18.0 */ -} curl_proxytype; /* this enum was added in 7.10 */ - -/* - * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: - * - * CURLAUTH_NONE - No HTTP authentication - * CURLAUTH_BASIC - HTTP Basic authentication (default) - * CURLAUTH_DIGEST - HTTP Digest authentication - * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication - * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) - * CURLAUTH_NTLM - HTTP NTLM authentication - * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour - * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper - * CURLAUTH_ONLY - Use together with a single other type to force no - * authentication or just that single type - * CURLAUTH_ANY - All fine types set - * CURLAUTH_ANYSAFE - All fine types except Basic - */ - -#define CURLAUTH_NONE ((unsigned long)0) -#define CURLAUTH_BASIC (((unsigned long)1)<<0) -#define CURLAUTH_DIGEST (((unsigned long)1)<<1) -#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) -/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ -#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE -/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ -#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE -#define CURLAUTH_NTLM (((unsigned long)1)<<3) -#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) -#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) -#define CURLAUTH_ONLY (((unsigned long)1)<<31) -#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) -#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) - -#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ -#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ -#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ -#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ -#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ -#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ -#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ -#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY - -#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ -#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ -#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ - -#define CURL_ERROR_SIZE 256 - -enum curl_khtype { - CURLKHTYPE_UNKNOWN, - CURLKHTYPE_RSA1, - CURLKHTYPE_RSA, - CURLKHTYPE_DSS -}; - -struct curl_khkey { - const char *key; /* points to a zero-terminated string encoded with base64 - if len is zero, otherwise to the "raw" data */ - size_t len; - enum curl_khtype keytype; -}; - -/* this is the set of return values expected from the curl_sshkeycallback - callback */ -enum curl_khstat { - CURLKHSTAT_FINE_ADD_TO_FILE, - CURLKHSTAT_FINE, - CURLKHSTAT_REJECT, /* reject the connection, return an error */ - CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so - this causes a CURLE_DEFER error but otherwise the - connection will be left intact etc */ - CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ -}; - -/* this is the set of status codes pass in to the callback */ -enum curl_khmatch { - CURLKHMATCH_OK, /* match */ - CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ - CURLKHMATCH_MISSING, /* no matching host/key found */ - CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ -}; - -typedef int - (*curl_sshkeycallback) (CURL *easy, /* easy handle */ - const struct curl_khkey *knownkey, /* known */ - const struct curl_khkey *foundkey, /* found */ - enum curl_khmatch, /* libcurl's view on the keys */ - void *clientp); /* custom pointer passed from app */ - -/* parameter for the CURLOPT_USE_SSL option */ -typedef enum { - CURLUSESSL_NONE, /* do not attempt to use SSL */ - CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ - CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ - CURLUSESSL_ALL, /* SSL for all communication or fail */ - CURLUSESSL_LAST /* not an option, never use */ -} curl_usessl; - -/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ - -/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the - name of improving interoperability with older servers. Some SSL libraries - have introduced work-arounds for this flaw but those work-arounds sometimes - make the SSL communication fail. To regain functionality with those broken - servers, a user can this way allow the vulnerability back. */ -#define CURLSSLOPT_ALLOW_BEAST (1<<0) - -/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those - SSL backends where such behavior is present. */ -#define CURLSSLOPT_NO_REVOKE (1<<1) - -#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all - the obsolete stuff removed! */ - -/* Backwards compatibility with older names */ -/* These are scheduled to disappear by 2009 */ - -#define CURLFTPSSL_NONE CURLUSESSL_NONE -#define CURLFTPSSL_TRY CURLUSESSL_TRY -#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL -#define CURLFTPSSL_ALL CURLUSESSL_ALL -#define CURLFTPSSL_LAST CURLUSESSL_LAST -#define curl_ftpssl curl_usessl -#endif /*!CURL_NO_OLDIES*/ - -/* parameter for the CURLOPT_FTP_SSL_CCC option */ -typedef enum { - CURLFTPSSL_CCC_NONE, /* do not send CCC */ - CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ - CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ - CURLFTPSSL_CCC_LAST /* not an option, never use */ -} curl_ftpccc; - -/* parameter for the CURLOPT_FTPSSLAUTH option */ -typedef enum { - CURLFTPAUTH_DEFAULT, /* let libcurl decide */ - CURLFTPAUTH_SSL, /* use "AUTH SSL" */ - CURLFTPAUTH_TLS, /* use "AUTH TLS" */ - CURLFTPAUTH_LAST /* not an option, never use */ -} curl_ftpauth; - -/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ -typedef enum { - CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ - CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD - again if MKD succeeded, for SFTP this does - similar magic */ - CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD - again even if MKD failed! */ - CURLFTP_CREATE_DIR_LAST /* not an option, never use */ -} curl_ftpcreatedir; - -/* parameter for the CURLOPT_FTP_FILEMETHOD option */ -typedef enum { - CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ - CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ - CURLFTPMETHOD_NOCWD, /* no CWD at all */ - CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ - CURLFTPMETHOD_LAST /* not an option, never use */ -} curl_ftpmethod; - -/* bitmask defines for CURLOPT_HEADEROPT */ -#define CURLHEADER_UNIFIED 0 -#define CURLHEADER_SEPARATE (1<<0) - -/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ -#define CURLPROTO_HTTP (1<<0) -#define CURLPROTO_HTTPS (1<<1) -#define CURLPROTO_FTP (1<<2) -#define CURLPROTO_FTPS (1<<3) -#define CURLPROTO_SCP (1<<4) -#define CURLPROTO_SFTP (1<<5) -#define CURLPROTO_TELNET (1<<6) -#define CURLPROTO_LDAP (1<<7) -#define CURLPROTO_LDAPS (1<<8) -#define CURLPROTO_DICT (1<<9) -#define CURLPROTO_FILE (1<<10) -#define CURLPROTO_TFTP (1<<11) -#define CURLPROTO_IMAP (1<<12) -#define CURLPROTO_IMAPS (1<<13) -#define CURLPROTO_POP3 (1<<14) -#define CURLPROTO_POP3S (1<<15) -#define CURLPROTO_SMTP (1<<16) -#define CURLPROTO_SMTPS (1<<17) -#define CURLPROTO_RTSP (1<<18) -#define CURLPROTO_RTMP (1<<19) -#define CURLPROTO_RTMPT (1<<20) -#define CURLPROTO_RTMPE (1<<21) -#define CURLPROTO_RTMPTE (1<<22) -#define CURLPROTO_RTMPS (1<<23) -#define CURLPROTO_RTMPTS (1<<24) -#define CURLPROTO_GOPHER (1<<25) -#define CURLPROTO_SMB (1<<26) -#define CURLPROTO_SMBS (1<<27) -#define CURLPROTO_ALL (~0) /* enable everything */ - -/* long may be 32 or 64 bits, but we should never depend on anything else - but 32 */ -#define CURLOPTTYPE_LONG 0 -#define CURLOPTTYPE_OBJECTPOINT 10000 -#define CURLOPTTYPE_STRINGPOINT 10000 -#define CURLOPTTYPE_FUNCTIONPOINT 20000 -#define CURLOPTTYPE_OFF_T 30000 - -/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the - string options from the header file */ - -/* name is uppercase CURLOPT_, - type is one of the defined CURLOPTTYPE_ - number is unique identifier */ -#ifdef CINIT -#undef CINIT -#endif - -#ifdef CURL_ISOCPP -#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define LONG CURLOPTTYPE_LONG -#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT -#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT -#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT -#define OFF_T CURLOPTTYPE_OFF_T -#define CINIT(name,type,number) CURLOPT_/**/name = type + number -#endif - -/* - * This macro-mania below setups the CURLOPT_[what] enum, to be used with - * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] - * word. - */ - -typedef enum { - /* This is the FILE * or void * the regular output should be written to. */ - CINIT(WRITEDATA, OBJECTPOINT, 1), - - /* The full URL to get/put */ - CINIT(URL, STRINGPOINT, 2), - - /* Port number to connect to, if other than default. */ - CINIT(PORT, LONG, 3), - - /* Name of proxy to use. */ - CINIT(PROXY, STRINGPOINT, 4), - - /* "user:password;options" to use when fetching. */ - CINIT(USERPWD, STRINGPOINT, 5), - - /* "user:password" to use with proxy. */ - CINIT(PROXYUSERPWD, STRINGPOINT, 6), - - /* Range to get, specified as an ASCII string. */ - CINIT(RANGE, STRINGPOINT, 7), - - /* not used */ - - /* Specified file stream to upload from (use as input): */ - CINIT(READDATA, OBJECTPOINT, 9), - - /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE - * bytes big. If this is not used, error messages go to stderr instead: */ - CINIT(ERRORBUFFER, OBJECTPOINT, 10), - - /* Function that will be called to store the output (instead of fwrite). The - * parameters will use fwrite() syntax, make sure to follow them. */ - CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), - - /* Function that will be called to read the input (instead of fread). The - * parameters will use fread() syntax, make sure to follow them. */ - CINIT(READFUNCTION, FUNCTIONPOINT, 12), - - /* Time-out the read operation after this amount of seconds */ - CINIT(TIMEOUT, LONG, 13), - - /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about - * how large the file being sent really is. That allows better error - * checking and better verifies that the upload was successful. -1 means - * unknown size. - * - * For large file support, there is also a _LARGE version of the key - * which takes an off_t type, allowing platforms with larger off_t - * sizes to handle larger files. See below for INFILESIZE_LARGE. - */ - CINIT(INFILESIZE, LONG, 14), - - /* POST static input fields. */ - CINIT(POSTFIELDS, OBJECTPOINT, 15), - - /* Set the referrer page (needed by some CGIs) */ - CINIT(REFERER, STRINGPOINT, 16), - - /* Set the FTP PORT string (interface name, named or numerical IP address) - Use i.e '-' to use default address. */ - CINIT(FTPPORT, STRINGPOINT, 17), - - /* Set the User-Agent string (examined by some CGIs) */ - CINIT(USERAGENT, STRINGPOINT, 18), - - /* If the download receives less than "low speed limit" bytes/second - * during "low speed time" seconds, the operations is aborted. - * You could i.e if you have a pretty high speed connection, abort if - * it is less than 2000 bytes/sec during 20 seconds. - */ - - /* Set the "low speed limit" */ - CINIT(LOW_SPEED_LIMIT, LONG, 19), - - /* Set the "low speed time" */ - CINIT(LOW_SPEED_TIME, LONG, 20), - - /* Set the continuation offset. - * - * Note there is also a _LARGE version of this key which uses - * off_t types, allowing for large file offsets on platforms which - * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. - */ - CINIT(RESUME_FROM, LONG, 21), - - /* Set cookie in request: */ - CINIT(COOKIE, STRINGPOINT, 22), - - /* This points to a linked list of headers, struct curl_slist kind. This - list is also used for RTSP (in spite of its name) */ - CINIT(HTTPHEADER, OBJECTPOINT, 23), - - /* This points to a linked list of post entries, struct curl_httppost */ - CINIT(HTTPPOST, OBJECTPOINT, 24), - - /* name of the file keeping your private SSL-certificate */ - CINIT(SSLCERT, STRINGPOINT, 25), - - /* password for the SSL or SSH private key */ - CINIT(KEYPASSWD, STRINGPOINT, 26), - - /* send TYPE parameter? */ - CINIT(CRLF, LONG, 27), - - /* send linked-list of QUOTE commands */ - CINIT(QUOTE, OBJECTPOINT, 28), - - /* send FILE * or void * to store headers to, if you use a callback it - is simply passed to the callback unmodified */ - CINIT(HEADERDATA, OBJECTPOINT, 29), - - /* point to a file to read the initial cookies from, also enables - "cookie awareness" */ - CINIT(COOKIEFILE, STRINGPOINT, 31), - - /* What version to specifically try to use. - See CURL_SSLVERSION defines below. */ - CINIT(SSLVERSION, LONG, 32), - - /* What kind of HTTP time condition to use, see defines */ - CINIT(TIMECONDITION, LONG, 33), - - /* Time to use with the above condition. Specified in number of seconds - since 1 Jan 1970 */ - CINIT(TIMEVALUE, LONG, 34), - - /* 35 = OBSOLETE */ - - /* Custom request, for customizing the get command like - HTTP: DELETE, TRACE and others - FTP: to use a different list command - */ - CINIT(CUSTOMREQUEST, STRINGPOINT, 36), - - /* FILE handle to use instead of stderr */ - CINIT(STDERR, OBJECTPOINT, 37), - - /* 38 is not used */ - - /* send linked-list of post-transfer QUOTE commands */ - CINIT(POSTQUOTE, OBJECTPOINT, 39), - - CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ - - CINIT(VERBOSE, LONG, 41), /* talk a lot */ - CINIT(HEADER, LONG, 42), /* throw the header out too */ - CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ - CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ - CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ - CINIT(UPLOAD, LONG, 46), /* this is an upload */ - CINIT(POST, LONG, 47), /* HTTP POST method */ - CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ - - CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ - - /* Specify whether to read the user+password from the .netrc or the URL. - * This must be one of the CURL_NETRC_* enums below. */ - CINIT(NETRC, LONG, 51), - - CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ - - CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ - CINIT(PUT, LONG, 54), /* HTTP PUT */ - - /* 55 = OBSOLETE */ - - /* DEPRECATED - * Function that will be called instead of the internal progress display - * function. This function should be defined as the curl_progress_callback - * prototype defines. */ - CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), - - /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION - callbacks */ - CINIT(PROGRESSDATA, OBJECTPOINT, 57), -#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA - - /* We want the referrer field set automatically when following locations */ - CINIT(AUTOREFERER, LONG, 58), - - /* Port of the proxy, can be set in the proxy string as well with: - "[host]:[port]" */ - CINIT(PROXYPORT, LONG, 59), - - /* size of the POST input data, if strlen() is not good to use */ - CINIT(POSTFIELDSIZE, LONG, 60), - - /* tunnel non-http operations through a HTTP proxy */ - CINIT(HTTPPROXYTUNNEL, LONG, 61), - - /* Set the interface string to use as outgoing network interface */ - CINIT(INTERFACE, STRINGPOINT, 62), - - /* Set the krb4/5 security level, this also enables krb4/5 awareness. This - * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string - * is set but doesn't match one of these, 'private' will be used. */ - CINIT(KRBLEVEL, STRINGPOINT, 63), - - /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ - CINIT(SSL_VERIFYPEER, LONG, 64), - - /* The CApath or CAfile used to validate the peer certificate - this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAINFO, STRINGPOINT, 65), - - /* 66 = OBSOLETE */ - /* 67 = OBSOLETE */ - - /* Maximum number of http redirects to follow */ - CINIT(MAXREDIRS, LONG, 68), - - /* Pass a long set to 1 to get the date of the requested document (if - possible)! Pass a zero to shut it off. */ - CINIT(FILETIME, LONG, 69), - - /* This points to a linked list of telnet options */ - CINIT(TELNETOPTIONS, OBJECTPOINT, 70), - - /* Max amount of cached alive connections */ - CINIT(MAXCONNECTS, LONG, 71), - - CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ - - /* 73 = OBSOLETE */ - - /* Set to explicitly use a new connection for the upcoming transfer. - Do not use this unless you're absolutely sure of this, as it makes the - operation slower and is less friendly for the network. */ - CINIT(FRESH_CONNECT, LONG, 74), - - /* Set to explicitly forbid the upcoming transfer's connection to be re-used - when done. Do not use this unless you're absolutely sure of this, as it - makes the operation slower and is less friendly for the network. */ - CINIT(FORBID_REUSE, LONG, 75), - - /* Set to a file name that contains random data for libcurl to use to - seed the random engine when doing SSL connects. */ - CINIT(RANDOM_FILE, STRINGPOINT, 76), - - /* Set to the Entropy Gathering Daemon socket pathname */ - CINIT(EGDSOCKET, STRINGPOINT, 77), - - /* Time-out connect operations after this amount of seconds, if connects are - OK within this time, then fine... This only aborts the connect phase. */ - CINIT(CONNECTTIMEOUT, LONG, 78), - - /* Function that will be called to store headers (instead of fwrite). The - * parameters will use fwrite() syntax, make sure to follow them. */ - CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), - - /* Set this to force the HTTP request to get back to GET. Only really usable - if POST, PUT or a custom request have been used first. - */ - CINIT(HTTPGET, LONG, 80), - - /* Set if we should verify the Common name from the peer certificate in ssl - * handshake, set 1 to check existence, 2 to ensure that it matches the - * provided hostname. */ - CINIT(SSL_VERIFYHOST, LONG, 81), - - /* Specify which file name to write all known cookies in after completed - operation. Set file name to "-" (dash) to make it go to stdout. */ - CINIT(COOKIEJAR, STRINGPOINT, 82), - - /* Specify which SSL ciphers to use */ - CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), - - /* Specify which HTTP version to use! This must be set to one of the - CURL_HTTP_VERSION* enums set below. */ - CINIT(HTTP_VERSION, LONG, 84), - - /* Specifically switch on or off the FTP engine's use of the EPSV command. By - default, that one will always be attempted before the more traditional - PASV command. */ - CINIT(FTP_USE_EPSV, LONG, 85), - - /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ - CINIT(SSLCERTTYPE, STRINGPOINT, 86), - - /* name of the file keeping your private SSL-key */ - CINIT(SSLKEY, STRINGPOINT, 87), - - /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ - CINIT(SSLKEYTYPE, STRINGPOINT, 88), - - /* crypto engine for the SSL-sub system */ - CINIT(SSLENGINE, STRINGPOINT, 89), - - /* set the crypto engine for the SSL-sub system as default - the param has no meaning... - */ - CINIT(SSLENGINE_DEFAULT, LONG, 90), - - /* Non-zero value means to use the global dns cache */ - CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ - - /* DNS cache timeout */ - CINIT(DNS_CACHE_TIMEOUT, LONG, 92), - - /* send linked-list of pre-transfer QUOTE commands */ - CINIT(PREQUOTE, OBJECTPOINT, 93), - - /* set the debug function */ - CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), - - /* set the data for the debug function */ - CINIT(DEBUGDATA, OBJECTPOINT, 95), - - /* mark this as start of a cookie session */ - CINIT(COOKIESESSION, LONG, 96), - - /* The CApath directory used to validate the peer certificate - this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAPATH, STRINGPOINT, 97), - - /* Instruct libcurl to use a smaller receive buffer */ - CINIT(BUFFERSIZE, LONG, 98), - - /* Instruct libcurl to not use any signal/alarm handlers, even when using - timeouts. This option is useful for multi-threaded applications. - See libcurl-the-guide for more background information. */ - CINIT(NOSIGNAL, LONG, 99), - - /* Provide a CURLShare for mutexing non-ts data */ - CINIT(SHARE, OBJECTPOINT, 100), - - /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), - CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and - CURLPROXY_SOCKS5. */ - CINIT(PROXYTYPE, LONG, 101), - - /* Set the Accept-Encoding string. Use this to tell a server you would like - the response to be compressed. Before 7.21.6, this was known as - CURLOPT_ENCODING */ - CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), - - /* Set pointer to private data */ - CINIT(PRIVATE, OBJECTPOINT, 103), - - /* Set aliases for HTTP 200 in the HTTP Response header */ - CINIT(HTTP200ALIASES, OBJECTPOINT, 104), - - /* Continue to send authentication (user+password) when following locations, - even when hostname changed. This can potentially send off the name - and password to whatever host the server decides. */ - CINIT(UNRESTRICTED_AUTH, LONG, 105), - - /* Specifically switch on or off the FTP engine's use of the EPRT command ( - it also disables the LPRT attempt). By default, those ones will always be - attempted before the good old traditional PORT command. */ - CINIT(FTP_USE_EPRT, LONG, 106), - - /* Set this to a bitmask value to enable the particular authentications - methods you like. Use this in combination with CURLOPT_USERPWD. - Note that setting multiple bits may cause extra network round-trips. */ - CINIT(HTTPAUTH, LONG, 107), - - /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx - in second argument. The function must be matching the - curl_ssl_ctx_callback proto. */ - CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), - - /* Set the userdata for the ssl context callback function's third - argument */ - CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), - - /* FTP Option that causes missing dirs to be created on the remote server. - In 7.19.4 we introduced the convenience enums for this option using the - CURLFTP_CREATE_DIR prefix. - */ - CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), - - /* Set this to a bitmask value to enable the particular authentications - methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. - Note that setting multiple bits may cause extra network round-trips. */ - CINIT(PROXYAUTH, LONG, 111), - - /* FTP option that changes the timeout, in seconds, associated with - getting a response. This is different from transfer timeout time and - essentially places a demand on the FTP server to acknowledge commands - in a timely manner. */ - CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), -#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT - - /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to - tell libcurl to resolve names to those IP versions only. This only has - affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ - CINIT(IPRESOLVE, LONG, 113), - - /* Set this option to limit the size of a file that will be downloaded from - an HTTP or FTP server. - - Note there is also _LARGE version which adds large file support for - platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ - CINIT(MAXFILESIZE, LONG, 114), - - /* See the comment for INFILESIZE above, but in short, specifies - * the size of the file being uploaded. -1 means unknown. - */ - CINIT(INFILESIZE_LARGE, OFF_T, 115), - - /* Sets the continuation offset. There is also a LONG version of this; - * look above for RESUME_FROM. - */ - CINIT(RESUME_FROM_LARGE, OFF_T, 116), - - /* Sets the maximum size of data that will be downloaded from - * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. - */ - CINIT(MAXFILESIZE_LARGE, OFF_T, 117), - - /* Set this option to the file name of your .netrc file you want libcurl - to parse (using the CURLOPT_NETRC option). If not set, libcurl will do - a poor attempt to find the user's home directory and check for a .netrc - file in there. */ - CINIT(NETRC_FILE, STRINGPOINT, 118), - - /* Enable SSL/TLS for FTP, pick one of: - CURLUSESSL_TRY - try using SSL, proceed anyway otherwise - CURLUSESSL_CONTROL - SSL for the control connection or fail - CURLUSESSL_ALL - SSL for all communication or fail - */ - CINIT(USE_SSL, LONG, 119), - - /* The _LARGE version of the standard POSTFIELDSIZE option */ - CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), - - /* Enable/disable the TCP Nagle algorithm */ - CINIT(TCP_NODELAY, LONG, 121), - - /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ - /* 123 OBSOLETE. Gone in 7.16.0 */ - /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ - /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ - /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ - /* 127 OBSOLETE. Gone in 7.16.0 */ - /* 128 OBSOLETE. Gone in 7.16.0 */ - - /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option - can be used to change libcurl's default action which is to first try - "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK - response has been received. - - Available parameters are: - CURLFTPAUTH_DEFAULT - let libcurl decide - CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS - CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL - */ - CINIT(FTPSSLAUTH, LONG, 129), - - CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), - CINIT(IOCTLDATA, OBJECTPOINT, 131), - - /* 132 OBSOLETE. Gone in 7.16.0 */ - /* 133 OBSOLETE. Gone in 7.16.0 */ - - /* zero terminated string for pass on to the FTP server when asked for - "account" info */ - CINIT(FTP_ACCOUNT, STRINGPOINT, 134), - - /* feed cookie into cookie engine */ - CINIT(COOKIELIST, STRINGPOINT, 135), - - /* ignore Content-Length */ - CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), - - /* Set to non-zero to skip the IP address received in a 227 PASV FTP server - response. Typically used for FTP-SSL purposes but is not restricted to - that. libcurl will then instead use the same IP address it used for the - control connection. */ - CINIT(FTP_SKIP_PASV_IP, LONG, 137), - - /* Select "file method" to use when doing FTP, see the curl_ftpmethod - above. */ - CINIT(FTP_FILEMETHOD, LONG, 138), - - /* Local port number to bind the socket to */ - CINIT(LOCALPORT, LONG, 139), - - /* Number of ports to try, including the first one set with LOCALPORT. - Thus, setting it to 1 will make no additional attempts but the first. - */ - CINIT(LOCALPORTRANGE, LONG, 140), - - /* no transfer, set up connection and let application use the socket by - extracting it with CURLINFO_LASTSOCKET */ - CINIT(CONNECT_ONLY, LONG, 141), - - /* Function that will be called to convert from the - network encoding (instead of using the iconv calls in libcurl) */ - CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), - - /* Function that will be called to convert to the - network encoding (instead of using the iconv calls in libcurl) */ - CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), - - /* Function that will be called to convert from UTF8 - (instead of using the iconv calls in libcurl) - Note that this is used only for SSL certificate processing */ - CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), - - /* if the connection proceeds too quickly then need to slow it down */ - /* limit-rate: maximum number of bytes per second to send or receive */ - CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), - CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), - - /* Pointer to command string to send if USER/PASS fails. */ - CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), - - /* callback function for setting socket options */ - CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), - CINIT(SOCKOPTDATA, OBJECTPOINT, 149), - - /* set to 0 to disable session ID re-use for this transfer, default is - enabled (== 1) */ - CINIT(SSL_SESSIONID_CACHE, LONG, 150), - - /* allowed SSH authentication methods */ - CINIT(SSH_AUTH_TYPES, LONG, 151), - - /* Used by scp/sftp to do public/private key authentication */ - CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), - CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), - - /* Send CCC (Clear Command Channel) after authentication */ - CINIT(FTP_SSL_CCC, LONG, 154), - - /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ - CINIT(TIMEOUT_MS, LONG, 155), - CINIT(CONNECTTIMEOUT_MS, LONG, 156), - - /* set to zero to disable the libcurl's decoding and thus pass the raw body - data to the application even when it is encoded/compressed */ - CINIT(HTTP_TRANSFER_DECODING, LONG, 157), - CINIT(HTTP_CONTENT_DECODING, LONG, 158), - - /* Permission used when creating new files and directories on the remote - server for protocols that support it, SFTP/SCP/FILE */ - CINIT(NEW_FILE_PERMS, LONG, 159), - CINIT(NEW_DIRECTORY_PERMS, LONG, 160), - - /* Set the behaviour of POST when redirecting. Values must be set to one - of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ - CINIT(POSTREDIR, LONG, 161), - - /* used by scp/sftp to verify the host's public key */ - CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), - - /* Callback function for opening socket (instead of socket(2)). Optionally, - callback is able change the address or refuse to connect returning - CURL_SOCKET_BAD. The callback should have type - curl_opensocket_callback */ - CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), - CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), - - /* POST volatile input fields. */ - CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), - - /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ - CINIT(PROXY_TRANSFER_MODE, LONG, 166), - - /* Callback function for seeking in the input stream */ - CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), - CINIT(SEEKDATA, OBJECTPOINT, 168), - - /* CRL file */ - CINIT(CRLFILE, STRINGPOINT, 169), - - /* Issuer certificate */ - CINIT(ISSUERCERT, STRINGPOINT, 170), - - /* (IPv6) Address scope */ - CINIT(ADDRESS_SCOPE, LONG, 171), - - /* Collect certificate chain info and allow it to get retrievable with - CURLINFO_CERTINFO after the transfer is complete. */ - CINIT(CERTINFO, LONG, 172), - - /* "name" and "pwd" to use when fetching. */ - CINIT(USERNAME, STRINGPOINT, 173), - CINIT(PASSWORD, STRINGPOINT, 174), - - /* "name" and "pwd" to use with Proxy when fetching. */ - CINIT(PROXYUSERNAME, STRINGPOINT, 175), - CINIT(PROXYPASSWORD, STRINGPOINT, 176), - - /* Comma separated list of hostnames defining no-proxy zones. These should - match both hostnames directly, and hostnames within a domain. For - example, local.com will match local.com and www.local.com, but NOT - notlocal.com or www.notlocal.com. For compatibility with other - implementations of this, .local.com will be considered to be the same as - local.com. A single * is the only valid wildcard, and effectively - disables the use of proxy. */ - CINIT(NOPROXY, STRINGPOINT, 177), - - /* block size for TFTP transfers */ - CINIT(TFTP_BLKSIZE, LONG, 178), - - /* Socks Service */ - CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ - - /* Socks Service */ - CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), - - /* set the bitmask for the protocols that are allowed to be used for the - transfer, which thus helps the app which takes URLs from users or other - external inputs and want to restrict what protocol(s) to deal - with. Defaults to CURLPROTO_ALL. */ - CINIT(PROTOCOLS, LONG, 181), - - /* set the bitmask for the protocols that libcurl is allowed to follow to, - as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs - to be set in both bitmasks to be allowed to get redirected to. Defaults - to all protocols except FILE and SCP. */ - CINIT(REDIR_PROTOCOLS, LONG, 182), - - /* set the SSH knownhost file name to use */ - CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), - - /* set the SSH host key callback, must point to a curl_sshkeycallback - function */ - CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), - - /* set the SSH host key callback custom pointer */ - CINIT(SSH_KEYDATA, OBJECTPOINT, 185), - - /* set the SMTP mail originator */ - CINIT(MAIL_FROM, STRINGPOINT, 186), - - /* set the list of SMTP mail receiver(s) */ - CINIT(MAIL_RCPT, OBJECTPOINT, 187), - - /* FTP: send PRET before PASV */ - CINIT(FTP_USE_PRET, LONG, 188), - - /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ - CINIT(RTSP_REQUEST, LONG, 189), - - /* The RTSP session identifier */ - CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), - - /* The RTSP stream URI */ - CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), - - /* The Transport: header to use in RTSP requests */ - CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), - - /* Manually initialize the client RTSP CSeq for this handle */ - CINIT(RTSP_CLIENT_CSEQ, LONG, 193), - - /* Manually initialize the server RTSP CSeq for this handle */ - CINIT(RTSP_SERVER_CSEQ, LONG, 194), - - /* The stream to pass to INTERLEAVEFUNCTION. */ - CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), - - /* Let the application define a custom write method for RTP data */ - CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), - - /* Turn on wildcard matching */ - CINIT(WILDCARDMATCH, LONG, 197), - - /* Directory matching callback called before downloading of an - individual file (chunk) started */ - CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), - - /* Directory matching callback called after the file (chunk) - was downloaded, or skipped */ - CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), - - /* Change match (fnmatch-like) callback for wildcard matching */ - CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), - - /* Let the application define custom chunk data pointer */ - CINIT(CHUNK_DATA, OBJECTPOINT, 201), - - /* FNMATCH_FUNCTION user pointer */ - CINIT(FNMATCH_DATA, OBJECTPOINT, 202), - - /* send linked-list of name:port:address sets */ - CINIT(RESOLVE, OBJECTPOINT, 203), - - /* Set a username for authenticated TLS */ - CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), - - /* Set a password for authenticated TLS */ - CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), - - /* Set authentication type for authenticated TLS */ - CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), - - /* Set to 1 to enable the "TE:" header in HTTP requests to ask for - compressed transfer-encoded responses. Set to 0 to disable the use of TE: - in outgoing requests. The current default is 0, but it might change in a - future libcurl release. - - libcurl will ask for the compressed methods it knows of, and if that - isn't any, it will not ask for transfer-encoding at all even if this - option is set to 1. - - */ - CINIT(TRANSFER_ENCODING, LONG, 207), - - /* Callback function for closing socket (instead of close(2)). The callback - should have type curl_closesocket_callback */ - CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), - CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), - - /* allow GSSAPI credential delegation */ - CINIT(GSSAPI_DELEGATION, LONG, 210), - - /* Set the name servers to use for DNS resolution */ - CINIT(DNS_SERVERS, STRINGPOINT, 211), - - /* Time-out accept operations (currently for FTP only) after this amount - of milliseconds. */ - CINIT(ACCEPTTIMEOUT_MS, LONG, 212), - - /* Set TCP keepalive */ - CINIT(TCP_KEEPALIVE, LONG, 213), - - /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ - CINIT(TCP_KEEPIDLE, LONG, 214), - CINIT(TCP_KEEPINTVL, LONG, 215), - - /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ - CINIT(SSL_OPTIONS, LONG, 216), - - /* Set the SMTP auth originator */ - CINIT(MAIL_AUTH, STRINGPOINT, 217), - - /* Enable/disable SASL initial response */ - CINIT(SASL_IR, LONG, 218), - - /* Function that will be called instead of the internal progress display - * function. This function should be defined as the curl_xferinfo_callback - * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ - CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), - - /* The XOAUTH2 bearer token */ - CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), - - /* Set the interface string to use as outgoing network - * interface for DNS requests. - * Only supported by the c-ares DNS backend */ - CINIT(DNS_INTERFACE, STRINGPOINT, 221), - - /* Set the local IPv4 address to use for outgoing DNS requests. - * Only supported by the c-ares DNS backend */ - CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), - - /* Set the local IPv4 address to use for outgoing DNS requests. - * Only supported by the c-ares DNS backend */ - CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), - - /* Set authentication options directly */ - CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), - - /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ - CINIT(SSL_ENABLE_NPN, LONG, 225), - - /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ - CINIT(SSL_ENABLE_ALPN, LONG, 226), - - /* Time to wait for a response to a HTTP request containing an - * Expect: 100-continue header before sending the data anyway. */ - CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), - - /* This points to a linked list of headers used for proxy requests only, - struct curl_slist kind */ - CINIT(PROXYHEADER, OBJECTPOINT, 228), - - /* Pass in a bitmask of "header options" */ - CINIT(HEADEROPT, LONG, 229), - - /* The public key in DER form used to validate the peer public key - this option is used only if SSL_VERIFYPEER is true */ - CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), - - /* Path to Unix domain socket */ - CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), - - /* Set if we should verify the certificate status. */ - CINIT(SSL_VERIFYSTATUS, LONG, 232), - - /* Set if we should enable TLS false start. */ - CINIT(SSL_FALSESTART, LONG, 233), - - /* Do not squash dot-dot sequences */ - CINIT(PATH_AS_IS, LONG, 234), - - /* Proxy Service Name */ - CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), - - /* Service Name */ - CINIT(SERVICE_NAME, STRINGPOINT, 236), - - /* Wait/don't wait for pipe/mutex to clarify */ - CINIT(PIPEWAIT, LONG, 237), - - /* Set the protocol used when curl is given a URL without a protocol */ - CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), - - /* Set stream weight, 1 - 256 (default is 16) */ - CINIT(STREAM_WEIGHT, LONG, 239), - - /* Set stream dependency on another CURL handle */ - CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), - - /* Set E-xclusive stream dependency on another CURL handle */ - CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), - - /* Do not send any tftp option requests to the server */ - CINIT(TFTP_NO_OPTIONS, LONG, 242), - - /* Linked-list of host:port:connect-to-host:connect-to-port, - overrides the URL's host:port (only for the network layer) */ - CINIT(CONNECT_TO, OBJECTPOINT, 243), - - /* Set TCP Fast Open */ - CINIT(TCP_FASTOPEN, LONG, 244), - - /* Continue to send data if the server responds early with an - * HTTP status code >= 300 */ - CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), - - /* The CApath or CAfile used to validate the proxy certificate - this option is used only if PROXY_SSL_VERIFYPEER is true */ - CINIT(PROXY_CAINFO, STRINGPOINT, 246), - - /* The CApath directory used to validate the proxy certificate - this option is used only if PROXY_SSL_VERIFYPEER is true */ - CINIT(PROXY_CAPATH, STRINGPOINT, 247), - - /* Set if we should verify the proxy in ssl handshake, - set 1 to verify. */ - CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), - - /* Set if we should verify the Common name from the proxy certificate in ssl - * handshake, set 1 to check existence, 2 to ensure that it matches - * the provided hostname. */ - CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), - - /* What version to specifically try to use for proxy. - See CURL_SSLVERSION defines below. */ - CINIT(PROXY_SSLVERSION, LONG, 250), - - /* Set a username for authenticated TLS for proxy */ - CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), - - /* Set a password for authenticated TLS for proxy */ - CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), - - /* Set authentication type for authenticated TLS for proxy */ - CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), - - /* name of the file keeping your private SSL-certificate for proxy */ - CINIT(PROXY_SSLCERT, STRINGPOINT, 254), - - /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for - proxy */ - CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), - - /* name of the file keeping your private SSL-key for proxy */ - CINIT(PROXY_SSLKEY, STRINGPOINT, 256), - - /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for - proxy */ - CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), - - /* password for the SSL private key for proxy */ - CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), - - /* Specify which SSL ciphers to use for proxy */ - CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), - - /* CRL file for proxy */ - CINIT(PROXY_CRLFILE, STRINGPOINT, 260), - - /* Enable/disable specific SSL features with a bitmask for proxy, see - CURLSSLOPT_* */ - CINIT(PROXY_SSL_OPTIONS, LONG, 261), - - /* Name of pre proxy to use. */ - CINIT(PRE_PROXY, STRINGPOINT, 262), - - /* The public key in DER form used to validate the proxy public key - this option is used only if PROXY_SSL_VERIFYPEER is true */ - CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), - - /* Path to an abstract Unix domain socket */ - CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), - - /* Suppress proxy CONNECT response headers from user callbacks */ - CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), - - /* The request target, instead of extracted from the URL */ - CINIT(REQUEST_TARGET, STRINGPOINT, 266), - - /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ - CINIT(SOCKS5_AUTH, LONG, 267), - - /* Enable/disable SSH compression */ - CINIT(SSH_COMPRESSION, LONG, 268), - - /* Post MIME data. */ - CINIT(MIMEPOST, OBJECTPOINT, 269), - - CURLOPT_LASTENTRY /* the last unused */ -} CURLoption; - -#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all - the obsolete stuff removed! */ - -/* Backwards compatibility with older names */ -/* These are scheduled to disappear by 2011 */ - -/* This was added in version 7.19.1 */ -#define CURLOPT_POST301 CURLOPT_POSTREDIR - -/* These are scheduled to disappear by 2009 */ - -/* The following were added in 7.17.0 */ -#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD -#define CURLOPT_FTPAPPEND CURLOPT_APPEND -#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY -#define CURLOPT_FTP_SSL CURLOPT_USE_SSL - -/* The following were added earlier */ - -#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD -#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL - -#else -/* This is set if CURL_NO_OLDIES is defined at compile-time */ -#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ -#endif - - - /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host - name resolves addresses using more than one IP protocol version, this - option might be handy to force libcurl to use a specific IP version. */ -#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP - versions that your system allows */ -#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ -#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ - - /* three convenient "aliases" that follow the name scheme better */ -#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER - - /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ -enum { - CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd - like the library to choose the best possible - for us! */ - CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ - CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ - CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ - CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ - CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 - Upgrade */ - - CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ -}; - -/* Convenience definition simple because the name of the version is HTTP/2 and - not 2.0. The 2_0 version of the enum name was set while the version was - still planned to be 2.0 and we stick to it for compatibility. */ -#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 - -/* - * Public API enums for RTSP requests - */ -enum { - CURL_RTSPREQ_NONE, /* first in list */ - CURL_RTSPREQ_OPTIONS, - CURL_RTSPREQ_DESCRIBE, - CURL_RTSPREQ_ANNOUNCE, - CURL_RTSPREQ_SETUP, - CURL_RTSPREQ_PLAY, - CURL_RTSPREQ_PAUSE, - CURL_RTSPREQ_TEARDOWN, - CURL_RTSPREQ_GET_PARAMETER, - CURL_RTSPREQ_SET_PARAMETER, - CURL_RTSPREQ_RECORD, - CURL_RTSPREQ_RECEIVE, - CURL_RTSPREQ_LAST /* last in list */ -}; - - /* These enums are for use with the CURLOPT_NETRC option. */ -enum CURL_NETRC_OPTION { - CURL_NETRC_IGNORED, /* The .netrc will never be read. - * This is the default. */ - CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred - * to one in the .netrc. */ - CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. - * Unless one is set programmatically, the .netrc - * will be queried. */ - CURL_NETRC_LAST -}; - -enum { - CURL_SSLVERSION_DEFAULT, - CURL_SSLVERSION_TLSv1, /* TLS 1.x */ - CURL_SSLVERSION_SSLv2, - CURL_SSLVERSION_SSLv3, - CURL_SSLVERSION_TLSv1_0, - CURL_SSLVERSION_TLSv1_1, - CURL_SSLVERSION_TLSv1_2, - CURL_SSLVERSION_TLSv1_3, - - CURL_SSLVERSION_LAST /* never use, keep last */ -}; - -enum { - CURL_SSLVERSION_MAX_NONE = 0, - CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), - CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), - CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), - CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), - CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), - - /* never use, keep last */ - CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) -}; - -enum CURL_TLSAUTH { - CURL_TLSAUTH_NONE, - CURL_TLSAUTH_SRP, - CURL_TLSAUTH_LAST /* never use, keep last */ -}; - -/* symbols to use with CURLOPT_POSTREDIR. - CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 - can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 - | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ - -#define CURL_REDIR_GET_ALL 0 -#define CURL_REDIR_POST_301 1 -#define CURL_REDIR_POST_302 2 -#define CURL_REDIR_POST_303 4 -#define CURL_REDIR_POST_ALL \ - (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) - -typedef enum { - CURL_TIMECOND_NONE, - - CURL_TIMECOND_IFMODSINCE, - CURL_TIMECOND_IFUNMODSINCE, - CURL_TIMECOND_LASTMOD, - - CURL_TIMECOND_LAST -} curl_TimeCond; - -/* Special size_t value signaling a zero-terminated string. */ -#define CURL_ZERO_TERMINATED ((size_t) -1) - -/* curl_strequal() and curl_strnequal() are subject for removal in a future - release */ -CURL_EXTERN int curl_strequal(const char *s1, const char *s2); -CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); - -/* Mime/form handling support. */ -typedef struct curl_mime_s curl_mime; /* Mime context. */ -typedef struct curl_mimepart_s curl_mimepart; /* Mime part context. */ - -/* - * NAME curl_mime_init() - * - * DESCRIPTION - * - * Create a mime context and return its handle. The easy parameter is the - * target handle. - */ -CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); - -/* - * NAME curl_mime_free() - * - * DESCRIPTION - * - * release a mime handle and its substructures. - */ -CURL_EXTERN void curl_mime_free(curl_mime *mime); - -/* - * NAME curl_mime_addpart() - * - * DESCRIPTION - * - * Append a new empty part to the given mime context and return a handle to - * the created part. - */ -CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); - -/* - * NAME curl_mime_name() - * - * DESCRIPTION - * - * Set mime/form part name. - */ -CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); - -/* - * NAME curl_mime_filename() - * - * DESCRIPTION - * - * Set mime part remote file name. - */ -CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, - const char *filename); - -/* - * NAME curl_mime_type() - * - * DESCRIPTION - * - * Set mime part type. - */ -CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); - -/* - * NAME curl_mime_encoder() - * - * DESCRIPTION - * - * Set mime data transfer encoder. - */ -CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, - const char *encoding); - -/* - * NAME curl_mime_data() - * - * DESCRIPTION - * - * Set mime part data source from memory data, - */ -CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, - const char *data, size_t datasize); - -/* - * NAME curl_mime_filedata() - * - * DESCRIPTION - * - * Set mime part data source from named file. - */ -CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, - const char *filename); - -/* - * NAME curl_mime_data_cb() - * - * DESCRIPTION - * - * Set mime part data source from callback function. - */ -CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, - curl_off_t datasize, - curl_read_callback readfunc, - curl_seek_callback seekfunc, - curl_free_callback freefunc, - void *arg); - -/* - * NAME curl_mime_subparts() - * - * DESCRIPTION - * - * Set mime part data source from subparts. - */ -CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, - curl_mime *subparts); -/* - * NAME curl_mime_headers() - * - * DESCRIPTION - * - * Set mime part headers. - */ -CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, - struct curl_slist *headers, - int take_ownership); - -/* Old form API. */ -/* name is uppercase CURLFORM_ */ -#ifdef CFINIT -#undef CFINIT -#endif - -#ifdef CURL_ISOCPP -#define CFINIT(name) CURLFORM_ ## name -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define CFINIT(name) CURLFORM_/**/name -#endif - -typedef enum { - CFINIT(NOTHING), /********* the first one is unused ************/ - - /* */ - CFINIT(COPYNAME), - CFINIT(PTRNAME), - CFINIT(NAMELENGTH), - CFINIT(COPYCONTENTS), - CFINIT(PTRCONTENTS), - CFINIT(CONTENTSLENGTH), - CFINIT(FILECONTENT), - CFINIT(ARRAY), - CFINIT(OBSOLETE), - CFINIT(FILE), - - CFINIT(BUFFER), - CFINIT(BUFFERPTR), - CFINIT(BUFFERLENGTH), - - CFINIT(CONTENTTYPE), - CFINIT(CONTENTHEADER), - CFINIT(FILENAME), - CFINIT(END), - CFINIT(OBSOLETE2), - - CFINIT(STREAM), - CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ - - CURLFORM_LASTENTRY /* the last unused */ -} CURLformoption; - -#undef CFINIT /* done */ - -/* structure to be used as parameter for CURLFORM_ARRAY */ -struct curl_forms { - CURLformoption option; - const char *value; -}; - -/* use this for multipart formpost building */ -/* Returns code for curl_formadd() - * - * Returns: - * CURL_FORMADD_OK on success - * CURL_FORMADD_MEMORY if the FormInfo allocation fails - * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form - * CURL_FORMADD_NULL if a null pointer was given for a char - * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed - * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used - * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) - * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated - * CURL_FORMADD_MEMORY if some allocation for string copying failed. - * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array - * - ***************************************************************************/ -typedef enum { - CURL_FORMADD_OK, /* first, no error */ - - CURL_FORMADD_MEMORY, - CURL_FORMADD_OPTION_TWICE, - CURL_FORMADD_NULL, - CURL_FORMADD_UNKNOWN_OPTION, - CURL_FORMADD_INCOMPLETE, - CURL_FORMADD_ILLEGAL_ARRAY, - CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ - - CURL_FORMADD_LAST /* last */ -} CURLFORMcode; - -/* - * NAME curl_formadd() - * - * DESCRIPTION - * - * Pretty advanced function for building multi-part formposts. Each invoke - * adds one part that together construct a full post. Then use - * CURLOPT_HTTPPOST to send it off to libcurl. - */ -CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...); - -/* - * callback function for curl_formget() - * The void *arg pointer will be the one passed as second argument to - * curl_formget(). - * The character buffer passed to it must not be freed. - * Should return the buffer length passed to it as the argument "len" on - * success. - */ -typedef size_t (*curl_formget_callback)(void *arg, const char *buf, - size_t len); - -/* - * NAME curl_formget() - * - * DESCRIPTION - * - * Serialize a curl_httppost struct built with curl_formadd(). - * Accepts a void pointer as second argument which will be passed to - * the curl_formget_callback function. - * Returns 0 on success. - */ -CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, - curl_formget_callback append); -/* - * NAME curl_formfree() - * - * DESCRIPTION - * - * Free a multipart formpost previously built with curl_formadd(). - */ -CURL_EXTERN void curl_formfree(struct curl_httppost *form); - -/* - * NAME curl_getenv() - * - * DESCRIPTION - * - * Returns a malloc()'ed string that MUST be curl_free()ed after usage is - * complete. DEPRECATED - see lib/README.curlx - */ -CURL_EXTERN char *curl_getenv(const char *variable); - -/* - * NAME curl_version() - * - * DESCRIPTION - * - * Returns a static ascii string of the libcurl version. - */ -CURL_EXTERN char *curl_version(void); - -/* - * NAME curl_easy_escape() - * - * DESCRIPTION - * - * Escapes URL strings (converts all letters consider illegal in URLs to their - * %XX versions). This function returns a new allocated string or NULL if an - * error occurred. - */ -CURL_EXTERN char *curl_easy_escape(CURL *handle, - const char *string, - int length); - -/* the previous version: */ -CURL_EXTERN char *curl_escape(const char *string, - int length); - - -/* - * NAME curl_easy_unescape() - * - * DESCRIPTION - * - * Unescapes URL encoding in strings (converts all %XX codes to their 8bit - * versions). This function returns a new allocated string or NULL if an error - * occurred. - * Conversion Note: On non-ASCII platforms the ASCII %XX codes are - * converted into the host encoding. - */ -CURL_EXTERN char *curl_easy_unescape(CURL *handle, - const char *string, - int length, - int *outlength); - -/* the previous version */ -CURL_EXTERN char *curl_unescape(const char *string, - int length); - -/* - * NAME curl_free() - * - * DESCRIPTION - * - * Provided for de-allocation in the same translation unit that did the - * allocation. Added in libcurl 7.10 - */ -CURL_EXTERN void curl_free(void *p); - -/* - * NAME curl_global_init() - * - * DESCRIPTION - * - * curl_global_init() should be invoked exactly once for each application that - * uses libcurl and before any call of other libcurl functions. - * - * This function is not thread-safe! - */ -CURL_EXTERN CURLcode curl_global_init(long flags); - -/* - * NAME curl_global_init_mem() - * - * DESCRIPTION - * - * curl_global_init() or curl_global_init_mem() should be invoked exactly once - * for each application that uses libcurl. This function can be used to - * initialize libcurl and set user defined memory management callback - * functions. Users can implement memory management routines to check for - * memory leaks, check for mis-use of the curl library etc. User registered - * callback routines with be invoked by this library instead of the system - * memory management routines like malloc, free etc. - */ -CURL_EXTERN CURLcode curl_global_init_mem(long flags, - curl_malloc_callback m, - curl_free_callback f, - curl_realloc_callback r, - curl_strdup_callback s, - curl_calloc_callback c); - -/* - * NAME curl_global_cleanup() - * - * DESCRIPTION - * - * curl_global_cleanup() should be invoked exactly once for each application - * that uses libcurl - */ -CURL_EXTERN void curl_global_cleanup(void); - -/* linked-list structure for the CURLOPT_QUOTE option (and other) */ -struct curl_slist { - char *data; - struct curl_slist *next; -}; - -/* - * NAME curl_global_sslset() - * - * DESCRIPTION - * - * When built with multiple SSL backends, curl_global_sslset() allows to - * choose one. This function can only be called once, and it must be called - * *before* curl_global_init(). - * - * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The - * backend can also be specified via the name parameter (passing -1 as id). - * If both id and name are specified, the name will be ignored. If neither id - * nor name are specified, the function will fail with - * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the - * NULL-terminated list of available backends. - * - * Upon success, the function returns CURLSSLSET_OK. - * - * If the specified SSL backend is not available, the function returns - * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated - * list of available SSL backends. - * - * The SSL backend can be set only once. If it has already been set, a - * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. - */ - -typedef struct { - curl_sslbackend id; - const char *name; -} curl_ssl_backend; - -typedef enum { - CURLSSLSET_OK = 0, - CURLSSLSET_UNKNOWN_BACKEND, - CURLSSLSET_TOO_LATE, - CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ -} CURLsslset; - -CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, - const curl_ssl_backend ***avail); - -/* - * NAME curl_slist_append() - * - * DESCRIPTION - * - * Appends a string to a linked list. If no list exists, it will be created - * first. Returns the new list, after appending. - */ -CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, - const char *); - -/* - * NAME curl_slist_free_all() - * - * DESCRIPTION - * - * free a previously built curl_slist. - */ -CURL_EXTERN void curl_slist_free_all(struct curl_slist *); - -/* - * NAME curl_getdate() - * - * DESCRIPTION - * - * Returns the time, in seconds since 1 Jan 1970 of the time string given in - * the first argument. The time argument in the second parameter is unused - * and should be set to NULL. - */ -CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); - -/* info about the certificate chain, only for OpenSSL builds. Asked - for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ -struct curl_certinfo { - int num_of_certs; /* number of certificates with information */ - struct curl_slist **certinfo; /* for each index in this array, there's a - linked list with textual information in the - format "name: value" */ -}; - -/* Information about the SSL library used and the respective internal SSL - handle, which can be used to obtain further information regarding the - connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ -struct curl_tlssessioninfo { - curl_sslbackend backend; - void *internals; -}; - -#define CURLINFO_STRING 0x100000 -#define CURLINFO_LONG 0x200000 -#define CURLINFO_DOUBLE 0x300000 -#define CURLINFO_SLIST 0x400000 -#define CURLINFO_PTR 0x400000 /* same as SLIST */ -#define CURLINFO_SOCKET 0x500000 -#define CURLINFO_OFF_T 0x600000 -#define CURLINFO_MASK 0x0fffff -#define CURLINFO_TYPEMASK 0xf00000 - -typedef enum { - CURLINFO_NONE, /* first, never use this */ - CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, - CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, - CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, - CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, - CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, - CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, - CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, - CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, - CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, - CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, - CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, - CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, - CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, - CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, - CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, - CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, - CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, - CURLINFO_FILETIME = CURLINFO_LONG + 14, - CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, - CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, - CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, - CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, - CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, - CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, - CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, - CURLINFO_PRIVATE = CURLINFO_STRING + 21, - CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, - CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, - CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, - CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, - CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, - CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, - CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, - CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, - CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, - CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, - CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, - CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, - CURLINFO_CERTINFO = CURLINFO_PTR + 34, - CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, - CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, - CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, - CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, - CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, - CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, - CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, - CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, - CURLINFO_TLS_SESSION = CURLINFO_PTR + 43, - CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, - CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, - CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, - CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, - CURLINFO_PROTOCOL = CURLINFO_LONG + 48, - CURLINFO_SCHEME = CURLINFO_STRING + 49, - /* Fill in new entries below here! */ - - CURLINFO_LASTONE = 49 -} CURLINFO; - -/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as - CURLINFO_HTTP_CODE */ -#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE - -typedef enum { - CURLCLOSEPOLICY_NONE, /* first, never use this */ - - CURLCLOSEPOLICY_OLDEST, - CURLCLOSEPOLICY_LEAST_RECENTLY_USED, - CURLCLOSEPOLICY_LEAST_TRAFFIC, - CURLCLOSEPOLICY_SLOWEST, - CURLCLOSEPOLICY_CALLBACK, - - CURLCLOSEPOLICY_LAST /* last, never use this */ -} curl_closepolicy; - -#define CURL_GLOBAL_SSL (1<<0) -#define CURL_GLOBAL_WIN32 (1<<1) -#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) -#define CURL_GLOBAL_NOTHING 0 -#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL -#define CURL_GLOBAL_ACK_EINTR (1<<2) - - -/***************************************************************************** - * Setup defines, protos etc for the sharing stuff. - */ - -/* Different data locks for a single share */ -typedef enum { - CURL_LOCK_DATA_NONE = 0, - /* CURL_LOCK_DATA_SHARE is used internally to say that - * the locking is just made to change the internal state of the share - * itself. - */ - CURL_LOCK_DATA_SHARE, - CURL_LOCK_DATA_COOKIE, - CURL_LOCK_DATA_DNS, - CURL_LOCK_DATA_SSL_SESSION, - CURL_LOCK_DATA_CONNECT, - CURL_LOCK_DATA_LAST -} curl_lock_data; - -/* Different lock access types */ -typedef enum { - CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ - CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ - CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ - CURL_LOCK_ACCESS_LAST /* never use */ -} curl_lock_access; - -typedef void (*curl_lock_function)(CURL *handle, - curl_lock_data data, - curl_lock_access locktype, - void *userptr); -typedef void (*curl_unlock_function)(CURL *handle, - curl_lock_data data, - void *userptr); - - -typedef enum { - CURLSHE_OK, /* all is fine */ - CURLSHE_BAD_OPTION, /* 1 */ - CURLSHE_IN_USE, /* 2 */ - CURLSHE_INVALID, /* 3 */ - CURLSHE_NOMEM, /* 4 out of memory */ - CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ - CURLSHE_LAST /* never use */ -} CURLSHcode; - -typedef enum { - CURLSHOPT_NONE, /* don't use */ - CURLSHOPT_SHARE, /* specify a data type to share */ - CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ - CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ - CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ - CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock - callback functions */ - CURLSHOPT_LAST /* never use */ -} CURLSHoption; - -CURL_EXTERN CURLSH *curl_share_init(void); -CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); -CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); - -/**************************************************************************** - * Structures for querying information about the curl library at runtime. - */ - -typedef enum { - CURLVERSION_FIRST, - CURLVERSION_SECOND, - CURLVERSION_THIRD, - CURLVERSION_FOURTH, - CURLVERSION_LAST /* never actually use this */ -} CURLversion; - -/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by - basically all programs ever that want to get version information. It is - meant to be a built-in version number for what kind of struct the caller - expects. If the struct ever changes, we redefine the NOW to another enum - from above. */ -#define CURLVERSION_NOW CURLVERSION_FOURTH - -typedef struct { - CURLversion age; /* age of the returned struct */ - const char *version; /* LIBCURL_VERSION */ - unsigned int version_num; /* LIBCURL_VERSION_NUM */ - const char *host; /* OS/host/cpu/machine when configured */ - int features; /* bitmask, see defines below */ - const char *ssl_version; /* human readable string */ - long ssl_version_num; /* not used anymore, always 0 */ - const char *libz_version; /* human readable string */ - /* protocols is terminated by an entry with a NULL protoname */ - const char * const *protocols; - - /* The fields below this were added in CURLVERSION_SECOND */ - const char *ares; - int ares_num; - - /* This field was added in CURLVERSION_THIRD */ - const char *libidn; - - /* These field were added in CURLVERSION_FOURTH */ - - /* Same as '_libiconv_version' if built with HAVE_ICONV */ - int iconv_ver_num; - - const char *libssh_version; /* human readable string */ - -} curl_version_info_data; - -#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ -#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported - (deprecated) */ -#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ -#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ -#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ -#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported - (deprecated) */ -#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ -#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ -#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ -#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ -#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are - supported */ -#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ -#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ -#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ -#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ -#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper - is supported */ -#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ -#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ -#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ -#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ -#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used - for cookie domain verification */ -#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ -#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ - - /* - * NAME curl_version_info() - * - * DESCRIPTION - * - * This function returns a pointer to a static copy of the version info - * struct. See above. - */ -CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); - -/* - * NAME curl_easy_strerror() - * - * DESCRIPTION - * - * The curl_easy_strerror function may be used to turn a CURLcode value - * into the equivalent human readable error string. This is useful - * for printing meaningful error messages. - */ -CURL_EXTERN const char *curl_easy_strerror(CURLcode); - -/* - * NAME curl_share_strerror() - * - * DESCRIPTION - * - * The curl_share_strerror function may be used to turn a CURLSHcode value - * into the equivalent human readable error string. This is useful - * for printing meaningful error messages. - */ -CURL_EXTERN const char *curl_share_strerror(CURLSHcode); - -/* - * NAME curl_easy_pause() - * - * DESCRIPTION - * - * The curl_easy_pause function pauses or unpauses transfers. Select the new - * state by setting the bitmask, use the convenience defines below. - * - */ -CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); - -#define CURLPAUSE_RECV (1<<0) -#define CURLPAUSE_RECV_CONT (0) - -#define CURLPAUSE_SEND (1<<2) -#define CURLPAUSE_SEND_CONT (0) - -#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) -#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) - -#ifdef __cplusplus -} -#endif - -/* unfortunately, the easy.h and multi.h include files need options and info - stuff before they can be included! */ -#include "easy.h" /* nothing in curl is fun without the easy stuff */ -#include "multi.h" - -/* the typechecker doesn't work in C++ (yet) */ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ - ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ - !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) -#include "typecheck-gcc.h" -#else -#if defined(__STDC__) && (__STDC__ >= 1) -/* This preprocessor magic that replaces a call with the exact same call is - only done to make sure application authors pass exactly three arguments - to these functions. */ -#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) -#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) -#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) -#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) -#endif /* __STDC__ >= 1 */ -#endif /* gcc >= 4.3 && !__cplusplus */ - -#endif /* __CURL_CURL_H */ diff --git a/dep/cpr/opt/curl/include/curl/curlver.h b/dep/cpr/opt/curl/include/curl/curlver.h deleted file mode 100644 index 8c9fb5e3ae4..00000000000 --- a/dep/cpr/opt/curl/include/curl/curlver.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef __CURL_CURLVER_H -#define __CURL_CURLVER_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* This header file contains nothing but libcurl version info, generated by - a script at release-time. This was made its own header file in 7.11.2 */ - -/* This is the global package copyright */ -#define LIBCURL_COPYRIGHT "1996 - 2017 Daniel Stenberg, ." - -/* This is the version number of the libcurl package from which this header - file origins: */ -#define LIBCURL_VERSION "7.56.0-DEV" - -/* The numeric version number is also available "in parts" by using these - defines: */ -#define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 56 -#define LIBCURL_VERSION_PATCH 0 - -/* This is the numeric version of the libcurl version number, meant for easier - parsing and comparions by programs. The LIBCURL_VERSION_NUM define will - always follow this syntax: - - 0xXXYYZZ - - Where XX, YY and ZZ are the main version, release and patch numbers in - hexadecimal (using 8 bits each). All three numbers are always represented - using two digits. 1.2 would appear as "0x010200" while version 9.11.7 - appears as "0x090b07". - - This 6-digit (24 bits) hexadecimal number does not show pre-release number, - and it is always a greater number in a more recent release. It makes - comparisons with greater than and less than work. - - Note: This define is the full hex number and _does not_ use the - CURL_VERSION_BITS() macro since curl's own configure script greps for it - and needs it to contain the full number. -*/ -#define LIBCURL_VERSION_NUM 0x073800 - -/* - * This is the date and time when the full source package was created. The - * timestamp is not stored in git, as the timestamp is properly set in the - * tarballs by the maketgz script. - * - * The format of the date follows this template: - * - * "2007-11-23" - */ -#define LIBCURL_TIMESTAMP "[unreleased]" - -#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) -#define CURL_AT_LEAST_VERSION(x,y,z) \ - (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) - -#endif /* __CURL_CURLVER_H */ diff --git a/dep/cpr/opt/curl/include/curl/easy.h b/dep/cpr/opt/curl/include/curl/easy.h deleted file mode 100644 index 752c5049f87..00000000000 --- a/dep/cpr/opt/curl/include/curl/easy.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef __CURL_EASY_H -#define __CURL_EASY_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#ifdef __cplusplus -extern "C" { -#endif - -CURL_EXTERN CURL *curl_easy_init(void); -CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); -CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); -CURL_EXTERN void curl_easy_cleanup(CURL *curl); - -/* - * NAME curl_easy_getinfo() - * - * DESCRIPTION - * - * Request internal information from the curl session with this function. The - * third argument MUST be a pointer to a long, a pointer to a char * or a - * pointer to a double (as the documentation describes elsewhere). The data - * pointed to will be filled in accordingly and can be relied upon only if the - * function returns CURLE_OK. This function is intended to get used *AFTER* a - * performed transfer, all results from this function are undefined until the - * transfer is completed. - */ -CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); - - -/* - * NAME curl_easy_duphandle() - * - * DESCRIPTION - * - * Creates a new curl session handle with the same options set for the handle - * passed in. Duplicating a handle could only be a matter of cloning data and - * options, internal state info and things like persistent connections cannot - * be transferred. It is useful in multithreaded applications when you can run - * curl_easy_duphandle() for each new thread to avoid a series of identical - * curl_easy_setopt() invokes in every thread. - */ -CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); - -/* - * NAME curl_easy_reset() - * - * DESCRIPTION - * - * Re-initializes a CURL handle to the default values. This puts back the - * handle to the same state as it was in when it was just created. - * - * It does keep: live connections, the Session ID cache, the DNS cache and the - * cookies. - */ -CURL_EXTERN void curl_easy_reset(CURL *curl); - -/* - * NAME curl_easy_recv() - * - * DESCRIPTION - * - * Receives data from the connected socket. Use after successful - * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. - */ -CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, - size_t *n); - -/* - * NAME curl_easy_send() - * - * DESCRIPTION - * - * Sends data over the connected socket. Use after successful - * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. - */ -CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, - size_t buflen, size_t *n); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/dep/cpr/opt/curl/include/curl/mprintf.h b/dep/cpr/opt/curl/include/curl/mprintf.h deleted file mode 100644 index e20f546e199..00000000000 --- a/dep/cpr/opt/curl/include/curl/mprintf.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef __CURL_MPRINTF_H -#define __CURL_MPRINTF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include -#include /* needed for FILE */ -#include "curl.h" /* for CURL_EXTERN */ - -#ifdef __cplusplus -extern "C" { -#endif - -CURL_EXTERN int curl_mprintf(const char *format, ...); -CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); -CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); -CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, - const char *format, ...); -CURL_EXTERN int curl_mvprintf(const char *format, va_list args); -CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); -CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); -CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, - const char *format, va_list args); -CURL_EXTERN char *curl_maprintf(const char *format, ...); -CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); - -#ifdef __cplusplus -} -#endif - -#endif /* __CURL_MPRINTF_H */ diff --git a/dep/cpr/opt/curl/include/curl/multi.h b/dep/cpr/opt/curl/include/curl/multi.h deleted file mode 100644 index 911c91dd1a6..00000000000 --- a/dep/cpr/opt/curl/include/curl/multi.h +++ /dev/null @@ -1,439 +0,0 @@ -#ifndef __CURL_MULTI_H -#define __CURL_MULTI_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -/* - This is an "external" header file. Don't give away any internals here! - - GOALS - - o Enable a "pull" interface. The application that uses libcurl decides where - and when to ask libcurl to get/send data. - - o Enable multiple simultaneous transfers in the same thread without making it - complicated for the application. - - o Enable the application to select() on its own file descriptors and curl's - file descriptors simultaneous easily. - -*/ - -/* - * This header file should not really need to include "curl.h" since curl.h - * itself includes this file and we expect user applications to do #include - * without the need for especially including multi.h. - * - * For some reason we added this include here at one point, and rather than to - * break existing (wrongly written) libcurl applications, we leave it as-is - * but with this warning attached. - */ -#include "curl.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) -typedef struct Curl_multi CURLM; -#else -typedef void CURLM; -#endif - -typedef enum { - CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or - curl_multi_socket*() soon */ - CURLM_OK, - CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ - CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ - CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ - CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ - CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ - CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ - CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was - attempted to get added - again */ - CURLM_LAST -} CURLMcode; - -/* just to make code nicer when using curl_multi_socket() you can now check - for CURLM_CALL_MULTI_SOCKET too in the same style it works for - curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ -#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM - -/* bitmask bits for CURLMOPT_PIPELINING */ -#define CURLPIPE_NOTHING 0L -#define CURLPIPE_HTTP1 1L -#define CURLPIPE_MULTIPLEX 2L - -typedef enum { - CURLMSG_NONE, /* first, not used */ - CURLMSG_DONE, /* This easy handle has completed. 'result' contains - the CURLcode of the transfer */ - CURLMSG_LAST /* last, not used */ -} CURLMSG; - -struct CURLMsg { - CURLMSG msg; /* what this message means */ - CURL *easy_handle; /* the handle it concerns */ - union { - void *whatever; /* message-specific data */ - CURLcode result; /* return code for transfer */ - } data; -}; -typedef struct CURLMsg CURLMsg; - -/* Based on poll(2) structure and values. - * We don't use pollfd and POLL* constants explicitly - * to cover platforms without poll(). */ -#define CURL_WAIT_POLLIN 0x0001 -#define CURL_WAIT_POLLPRI 0x0002 -#define CURL_WAIT_POLLOUT 0x0004 - -struct curl_waitfd { - curl_socket_t fd; - short events; - short revents; /* not supported yet */ -}; - -/* - * Name: curl_multi_init() - * - * Desc: inititalize multi-style curl usage - * - * Returns: a new CURLM handle to use in all 'curl_multi' functions. - */ -CURL_EXTERN CURLM *curl_multi_init(void); - -/* - * Name: curl_multi_add_handle() - * - * Desc: add a standard curl handle to the multi stack - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, - CURL *curl_handle); - - /* - * Name: curl_multi_remove_handle() - * - * Desc: removes a curl handle from the multi stack again - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, - CURL *curl_handle); - - /* - * Name: curl_multi_fdset() - * - * Desc: Ask curl for its fd_set sets. The app can use these to select() or - * poll() on. We want curl_multi_perform() called as soon as one of - * them are ready. - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, - fd_set *read_fd_set, - fd_set *write_fd_set, - fd_set *exc_fd_set, - int *max_fd); - -/* - * Name: curl_multi_wait() - * - * Desc: Poll on all fds within a CURLM set as well as any - * additional fds passed to the function. - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, - struct curl_waitfd extra_fds[], - unsigned int extra_nfds, - int timeout_ms, - int *ret); - - /* - * Name: curl_multi_perform() - * - * Desc: When the app thinks there's data available for curl it calls this - * function to read/write whatever there is right now. This returns - * as soon as the reads and writes are done. This function does not - * require that there actually is data available for reading or that - * data can be written, it can be called just in case. It returns - * the number of handles that still transfer data in the second - * argument's integer-pointer. - * - * Returns: CURLMcode type, general multi error code. *NOTE* that this only - * returns errors etc regarding the whole multi stack. There might - * still have occurred problems on invidual transfers even when this - * returns OK. - */ -CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, - int *running_handles); - - /* - * Name: curl_multi_cleanup() - * - * Desc: Cleans up and removes a whole multi stack. It does not free or - * touch any individual easy handles in any way. We need to define - * in what state those handles will be if this function is called - * in the middle of a transfer. - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); - -/* - * Name: curl_multi_info_read() - * - * Desc: Ask the multi handle if there's any messages/informationals from - * the individual transfers. Messages include informationals such as - * error code from the transfer or just the fact that a transfer is - * completed. More details on these should be written down as well. - * - * Repeated calls to this function will return a new struct each - * time, until a special "end of msgs" struct is returned as a signal - * that there is no more to get at this point. - * - * The data the returned pointer points to will not survive calling - * curl_multi_cleanup(). - * - * The 'CURLMsg' struct is meant to be very simple and only contain - * very basic information. If more involved information is wanted, - * we will provide the particular "transfer handle" in that struct - * and that should/could/would be used in subsequent - * curl_easy_getinfo() calls (or similar). The point being that we - * must never expose complex structs to applications, as then we'll - * undoubtably get backwards compatibility problems in the future. - * - * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out - * of structs. It also writes the number of messages left in the - * queue (after this read) in the integer the second argument points - * to. - */ -CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, - int *msgs_in_queue); - -/* - * Name: curl_multi_strerror() - * - * Desc: The curl_multi_strerror function may be used to turn a CURLMcode - * value into the equivalent human readable error string. This is - * useful for printing meaningful error messages. - * - * Returns: A pointer to a zero-terminated error message. - */ -CURL_EXTERN const char *curl_multi_strerror(CURLMcode); - -/* - * Name: curl_multi_socket() and - * curl_multi_socket_all() - * - * Desc: An alternative version of curl_multi_perform() that allows the - * application to pass in one of the file descriptors that have been - * detected to have "action" on them and let libcurl perform. - * See man page for details. - */ -#define CURL_POLL_NONE 0 -#define CURL_POLL_IN 1 -#define CURL_POLL_OUT 2 -#define CURL_POLL_INOUT 3 -#define CURL_POLL_REMOVE 4 - -#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD - -#define CURL_CSELECT_IN 0x01 -#define CURL_CSELECT_OUT 0x02 -#define CURL_CSELECT_ERR 0x04 - -typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ - curl_socket_t s, /* socket */ - int what, /* see above */ - void *userp, /* private callback - pointer */ - void *socketp); /* private socket - pointer */ -/* - * Name: curl_multi_timer_callback - * - * Desc: Called by libcurl whenever the library detects a change in the - * maximum number of milliseconds the app is allowed to wait before - * curl_multi_socket() or curl_multi_perform() must be called - * (to allow libcurl's timed events to take place). - * - * Returns: The callback should return zero. - */ -typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ - long timeout_ms, /* see above */ - void *userp); /* private callback - pointer */ - -CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, - int *running_handles); - -CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, - curl_socket_t s, - int ev_bitmask, - int *running_handles); - -CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, - int *running_handles); - -#ifndef CURL_ALLOW_OLD_MULTI_SOCKET -/* This macro below was added in 7.16.3 to push users who recompile to use - the new curl_multi_socket_action() instead of the old curl_multi_socket() -*/ -#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) -#endif - -/* - * Name: curl_multi_timeout() - * - * Desc: Returns the maximum number of milliseconds the app is allowed to - * wait before curl_multi_socket() or curl_multi_perform() must be - * called (to allow libcurl's timed events to take place). - * - * Returns: CURLM error code. - */ -CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, - long *milliseconds); - -#undef CINIT /* re-using the same name as in curl.h */ - -#ifdef CURL_ISOCPP -#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define LONG CURLOPTTYPE_LONG -#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT -#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT -#define OFF_T CURLOPTTYPE_OFF_T -#define CINIT(name,type,number) CURLMOPT_/**/name = type + number -#endif - -typedef enum { - /* This is the socket callback function pointer */ - CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), - - /* This is the argument passed to the socket callback */ - CINIT(SOCKETDATA, OBJECTPOINT, 2), - - /* set to 1 to enable pipelining for this multi handle */ - CINIT(PIPELINING, LONG, 3), - - /* This is the timer callback function pointer */ - CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), - - /* This is the argument passed to the timer callback */ - CINIT(TIMERDATA, OBJECTPOINT, 5), - - /* maximum number of entries in the connection cache */ - CINIT(MAXCONNECTS, LONG, 6), - - /* maximum number of (pipelining) connections to one host */ - CINIT(MAX_HOST_CONNECTIONS, LONG, 7), - - /* maximum number of requests in a pipeline */ - CINIT(MAX_PIPELINE_LENGTH, LONG, 8), - - /* a connection with a content-length longer than this - will not be considered for pipelining */ - CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), - - /* a connection with a chunk length longer than this - will not be considered for pipelining */ - CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), - - /* a list of site names(+port) that are blacklisted from - pipelining */ - CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), - - /* a list of server types that are blacklisted from - pipelining */ - CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), - - /* maximum number of open connections in total */ - CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), - - /* This is the server push callback function pointer */ - CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), - - /* This is the argument passed to the server push callback */ - CINIT(PUSHDATA, OBJECTPOINT, 15), - - CURLMOPT_LASTENTRY /* the last unused */ -} CURLMoption; - - -/* - * Name: curl_multi_setopt() - * - * Desc: Sets options for the multi handle. - * - * Returns: CURLM error code. - */ -CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, - CURLMoption option, ...); - - -/* - * Name: curl_multi_assign() - * - * Desc: This function sets an association in the multi handle between the - * given socket and a private pointer of the application. This is - * (only) useful for curl_multi_socket uses. - * - * Returns: CURLM error code. - */ -CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, - curl_socket_t sockfd, void *sockp); - - -/* - * Name: curl_push_callback - * - * Desc: This callback gets called when a new stream is being pushed by the - * server. It approves or denies the new stream. - * - * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. - */ -#define CURL_PUSH_OK 0 -#define CURL_PUSH_DENY 1 - -struct curl_pushheaders; /* forward declaration only */ - -CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, - size_t num); -CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, - const char *name); - -typedef int (*curl_push_callback)(CURL *parent, - CURL *easy, - size_t num_headers, - struct curl_pushheaders *headers, - void *userp); - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif - -#endif diff --git a/dep/cpr/opt/curl/include/curl/stdcheaders.h b/dep/cpr/opt/curl/include/curl/stdcheaders.h deleted file mode 100644 index 027b6f42117..00000000000 --- a/dep/cpr/opt/curl/include/curl/stdcheaders.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __STDC_HEADERS_H -#define __STDC_HEADERS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -size_t fread(void *, size_t, size_t, FILE *); -size_t fwrite(const void *, size_t, size_t, FILE *); - -int strcasecmp(const char *, const char *); -int strncasecmp(const char *, const char *, size_t); - -#endif /* __STDC_HEADERS_H */ diff --git a/dep/cpr/opt/curl/include/curl/system.h b/dep/cpr/opt/curl/include/curl/system.h deleted file mode 100644 index 39dae754cdb..00000000000 --- a/dep/cpr/opt/curl/include/curl/system.h +++ /dev/null @@ -1,471 +0,0 @@ -#ifndef __CURL_SYSTEM_H -#define __CURL_SYSTEM_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Try to keep one section per platform, compiler and architecture, otherwise, - * if an existing section is reused for a different one and later on the - * original is adjusted, probably the piggybacking one can be adversely - * changed. - * - * In order to differentiate between platforms/compilers/architectures use - * only compiler built in predefined preprocessor symbols. - * - * curl_off_t - * ---------- - * - * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit - * wide signed integral data type. The width of this data type must remain - * constant and independent of any possible large file support settings. - * - * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit - * wide signed integral data type if there is no 64-bit type. - * - * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall - * only be violated if off_t is the only 64-bit data type available and the - * size of off_t is independent of large file support settings. Keep your - * build on the safe side avoiding an off_t gating. If you have a 64-bit - * off_t then take for sure that another 64-bit data type exists, dig deeper - * and you will find it. - * - */ - -#if defined(__DJGPP__) || defined(__GO32__) -# if defined(__DJGPP__) && (__DJGPP__ > 1) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# else -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__SALFORDC__) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__BORLANDC__) -# if (__BORLANDC__ < 0x520) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# else -# define CURL_TYPEOF_CURL_OFF_T __int64 -# define CURL_FORMAT_CURL_OFF_T "I64d" -# define CURL_FORMAT_CURL_OFF_TU "I64u" -# define CURL_SUFFIX_CURL_OFF_T i64 -# define CURL_SUFFIX_CURL_OFF_TU ui64 -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__TURBOC__) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__WATCOMC__) -# if defined(__386__) -# define CURL_TYPEOF_CURL_OFF_T __int64 -# define CURL_FORMAT_CURL_OFF_T "I64d" -# define CURL_FORMAT_CURL_OFF_TU "I64u" -# define CURL_SUFFIX_CURL_OFF_T i64 -# define CURL_SUFFIX_CURL_OFF_TU ui64 -# else -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__POCC__) -# if (__POCC__ < 280) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# elif defined(_MSC_VER) -# define CURL_TYPEOF_CURL_OFF_T __int64 -# define CURL_FORMAT_CURL_OFF_T "I64d" -# define CURL_FORMAT_CURL_OFF_TU "I64u" -# define CURL_SUFFIX_CURL_OFF_T i64 -# define CURL_SUFFIX_CURL_OFF_TU ui64 -# else -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__LCC__) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__SYMBIAN32__) -# if defined(__EABI__) /* Treat all ARM compilers equally */ -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# elif defined(__CW32__) -# pragma longlong on -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# elif defined(__VC32__) -# define CURL_TYPEOF_CURL_OFF_T __int64 -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int - -#elif defined(__MWERKS__) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(_WIN32_WCE) -# define CURL_TYPEOF_CURL_OFF_T __int64 -# define CURL_FORMAT_CURL_OFF_T "I64d" -# define CURL_FORMAT_CURL_OFF_TU "I64u" -# define CURL_SUFFIX_CURL_OFF_T i64 -# define CURL_SUFFIX_CURL_OFF_TU ui64 -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__MINGW32__) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "I64d" -# define CURL_FORMAT_CURL_OFF_TU "I64u" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_WS2TCPIP_H 1 - -#elif defined(__VMS) -# if defined(__VAX) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# else -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int - -#elif defined(__OS400__) -# if defined(__ILEC400__) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_SYS_SOCKET_H 1 -# endif - -#elif defined(__MVS__) -# if defined(__IBMC__) || defined(__IBMCPP__) -# if defined(_ILP32) -# elif defined(_LP64) -# endif -# if defined(_LONG_LONG) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# elif defined(_LP64) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# else -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_SYS_SOCKET_H 1 -# endif - -#elif defined(__370__) -# if defined(__IBMC__) || defined(__IBMCPP__) -# if defined(_ILP32) -# elif defined(_LP64) -# endif -# if defined(_LONG_LONG) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# elif defined(_LP64) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# else -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_SYS_SOCKET_H 1 -# endif - -#elif defined(TPF) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -#elif defined(__TINYC__) /* also known as tcc */ - -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_SYS_SOCKET_H 1 - -#elif defined(__SUNPRO_C) /* Oracle Solaris Studio */ -# if !defined(__LP64) && (defined(__ILP32) || \ - defined(__i386) || defined(__sparcv8)) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# elif defined(__LP64) || \ - defined(__amd64) || defined(__sparcv9) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_SYS_SOCKET_H 1 - -/* ===================================== */ -/* KEEP MSVC THE PENULTIMATE ENTRY */ -/* ===================================== */ - -#elif defined(_MSC_VER) -# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) -# define CURL_TYPEOF_CURL_OFF_T __int64 -# define CURL_FORMAT_CURL_OFF_T "I64d" -# define CURL_FORMAT_CURL_OFF_TU "I64u" -# define CURL_SUFFIX_CURL_OFF_T i64 -# define CURL_SUFFIX_CURL_OFF_TU ui64 -# else -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T int - -/* ===================================== */ -/* KEEP GENERIC GCC THE LAST ENTRY */ -/* ===================================== */ - -#elif defined(__GNUC__) -# if !defined(__LP64__) && \ - (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ - defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ - defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ - defined(__XTENSA__) || \ - (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4)) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# elif defined(__LP64__) || \ - defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ - (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_SYS_SOCKET_H 1 - -#else -/* generic "safe guess" on old 32 bit style */ -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# define CURL_TYPEOF_CURL_SOCKLEN_T int -#endif - -#ifdef _AIX -/* AIX needs */ -#define CURL_PULL_SYS_POLL_H -#endif - - -/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ -/* ws2tcpip.h is required here to properly make type definitions below. */ -#ifdef CURL_PULL_WS2TCPIP_H -# include -# include -# include -#endif - -/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ -/* sys/types.h is required here to properly make type definitions below. */ -#ifdef CURL_PULL_SYS_TYPES_H -# include -#endif - -/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ -/* sys/socket.h is required here to properly make type definitions below. */ -#ifdef CURL_PULL_SYS_SOCKET_H -# include -#endif - -/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ -/* sys/poll.h is required here to properly make type definitions below. */ -#ifdef CURL_PULL_SYS_POLL_H -# include -#endif - -/* Data type definition of curl_socklen_t. */ -#ifdef CURL_TYPEOF_CURL_SOCKLEN_T - typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; -#endif - -/* Data type definition of curl_off_t. */ - -#ifdef CURL_TYPEOF_CURL_OFF_T - typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; -#endif - -/* - * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow - * these to be visible and exported by the external libcurl interface API, - * while also making them visible to the library internals, simply including - * curl_setup.h, without actually needing to include curl.h internally. - * If some day this section would grow big enough, all this should be moved - * to its own header file. - */ - -/* - * Figure out if we can use the ## preprocessor operator, which is supported - * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ - * or __cplusplus so we need to carefully check for them too. - */ - -#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ - defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ - defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ - defined(__ILEC400__) - /* This compiler is believed to have an ISO compatible preprocessor */ -#define CURL_ISOCPP -#else - /* This compiler is believed NOT to have an ISO compatible preprocessor */ -#undef CURL_ISOCPP -#endif - -/* - * Macros for minimum-width signed and unsigned curl_off_t integer constants. - */ - -#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) -# define __CURL_OFF_T_C_HLPR2(x) x -# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) -# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ - __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) -# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ - __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) -#else -# ifdef CURL_ISOCPP -# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix -# else -# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix -# endif -# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) -# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) -# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) -#endif - -#endif /* __CURL_SYSTEM_H */ diff --git a/dep/cpr/opt/curl/include/curl/typecheck-gcc.h b/dep/cpr/opt/curl/include/curl/typecheck-gcc.h deleted file mode 100644 index 10c74c764ca..00000000000 --- a/dep/cpr/opt/curl/include/curl/typecheck-gcc.h +++ /dev/null @@ -1,683 +0,0 @@ -#ifndef __CURL_TYPECHECK_GCC_H -#define __CURL_TYPECHECK_GCC_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* wraps curl_easy_setopt() with typechecking */ - -/* To add a new kind of warning, add an - * if(_curl_is_sometype_option(_curl_opt)) - * if(!_curl_is_sometype(value)) - * _curl_easy_setopt_err_sometype(); - * block and define _curl_is_sometype_option, _curl_is_sometype and - * _curl_easy_setopt_err_sometype below - * - * NOTE: We use two nested 'if' statements here instead of the && operator, in - * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x - * when compiling with -Wlogical-op. - * - * To add an option that uses the same type as an existing option, you'll just - * need to extend the appropriate _curl_*_option macro - */ -#define curl_easy_setopt(handle, option, value) \ -__extension__ ({ \ - __typeof__(option) _curl_opt = option; \ - if(__builtin_constant_p(_curl_opt)) { \ - if(_curl_is_long_option(_curl_opt)) \ - if(!_curl_is_long(value)) \ - _curl_easy_setopt_err_long(); \ - if(_curl_is_off_t_option(_curl_opt)) \ - if(!_curl_is_off_t(value)) \ - _curl_easy_setopt_err_curl_off_t(); \ - if(_curl_is_string_option(_curl_opt)) \ - if(!_curl_is_string(value)) \ - _curl_easy_setopt_err_string(); \ - if(_curl_is_write_cb_option(_curl_opt)) \ - if(!_curl_is_write_cb(value)) \ - _curl_easy_setopt_err_write_callback(); \ - if((_curl_opt) == CURLOPT_READFUNCTION) \ - if(!_curl_is_read_cb(value)) \ - _curl_easy_setopt_err_read_cb(); \ - if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ - if(!_curl_is_ioctl_cb(value)) \ - _curl_easy_setopt_err_ioctl_cb(); \ - if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ - if(!_curl_is_sockopt_cb(value)) \ - _curl_easy_setopt_err_sockopt_cb(); \ - if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ - if(!_curl_is_opensocket_cb(value)) \ - _curl_easy_setopt_err_opensocket_cb(); \ - if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ - if(!_curl_is_progress_cb(value)) \ - _curl_easy_setopt_err_progress_cb(); \ - if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ - if(!_curl_is_debug_cb(value)) \ - _curl_easy_setopt_err_debug_cb(); \ - if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ - if(!_curl_is_ssl_ctx_cb(value)) \ - _curl_easy_setopt_err_ssl_ctx_cb(); \ - if(_curl_is_conv_cb_option(_curl_opt)) \ - if(!_curl_is_conv_cb(value)) \ - _curl_easy_setopt_err_conv_cb(); \ - if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ - if(!_curl_is_seek_cb(value)) \ - _curl_easy_setopt_err_seek_cb(); \ - if(_curl_is_cb_data_option(_curl_opt)) \ - if(!_curl_is_cb_data(value)) \ - _curl_easy_setopt_err_cb_data(); \ - if((_curl_opt) == CURLOPT_ERRORBUFFER) \ - if(!_curl_is_error_buffer(value)) \ - _curl_easy_setopt_err_error_buffer(); \ - if((_curl_opt) == CURLOPT_STDERR) \ - if(!_curl_is_FILE(value)) \ - _curl_easy_setopt_err_FILE(); \ - if(_curl_is_postfields_option(_curl_opt)) \ - if(!_curl_is_postfields(value)) \ - _curl_easy_setopt_err_postfields(); \ - if((_curl_opt) == CURLOPT_HTTPPOST) \ - if(!_curl_is_arr((value), struct curl_httppost)) \ - _curl_easy_setopt_err_curl_httpost(); \ - if((_curl_opt) == CURLOPT_MIMEPOST) \ - if(!_curl_is_ptr((value), curl_mime)) \ - _curl_easy_setopt_err_curl_mimepost(); \ - if(_curl_is_slist_option(_curl_opt)) \ - if(!_curl_is_arr((value), struct curl_slist)) \ - _curl_easy_setopt_err_curl_slist(); \ - if((_curl_opt) == CURLOPT_SHARE) \ - if(!_curl_is_ptr((value), CURLSH)) \ - _curl_easy_setopt_err_CURLSH(); \ - } \ - curl_easy_setopt(handle, _curl_opt, value); \ -}) - -/* wraps curl_easy_getinfo() with typechecking */ -/* FIXME: don't allow const pointers */ -#define curl_easy_getinfo(handle, info, arg) \ -__extension__ ({ \ - __typeof__(info) _curl_info = info; \ - if(__builtin_constant_p(_curl_info)) { \ - if(_curl_is_string_info(_curl_info)) \ - if(!_curl_is_arr((arg), char *)) \ - _curl_easy_getinfo_err_string(); \ - if(_curl_is_long_info(_curl_info)) \ - if(!_curl_is_arr((arg), long)) \ - _curl_easy_getinfo_err_long(); \ - if(_curl_is_double_info(_curl_info)) \ - if(!_curl_is_arr((arg), double)) \ - _curl_easy_getinfo_err_double(); \ - if(_curl_is_slist_info(_curl_info)) \ - if(!_curl_is_arr((arg), struct curl_slist *)) \ - _curl_easy_getinfo_err_curl_slist(); \ - if(_curl_is_tlssessioninfo_info(_curl_info)) \ - if(!_curl_is_arr((arg), struct curl_tlssessioninfo *)) \ - _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ - if(_curl_is_certinfo_info(_curl_info)) \ - if(!_curl_is_arr((arg), struct curl_certinfo *)) \ - _curl_easy_getinfo_err_curl_certinfo(); \ - if(_curl_is_socket_info(_curl_info)) \ - if(!_curl_is_arr((arg), curl_socket_t)) \ - _curl_easy_getinfo_err_curl_socket(); \ - if(_curl_is_off_t_info(_curl_info)) \ - if(!_curl_is_arr((arg), curl_off_t)) \ - _curl_easy_getinfo_err_curl_off_t(); \ - } \ - curl_easy_getinfo(handle, _curl_info, arg); \ -}) - -/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), - * for now just make sure that the functions are called with three - * arguments - */ -#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) -#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) - - -/* the actual warnings, triggered by calling the _curl_easy_setopt_err* - * functions */ - -/* To define a new warning, use _CURL_WARNING(identifier, "message") */ -#define _CURL_WARNING(id, message) \ - static void __attribute__((__warning__(message))) \ - __attribute__((__unused__)) __attribute__((__noinline__)) \ - id(void) { __asm__(""); } - -_CURL_WARNING(_curl_easy_setopt_err_long, - "curl_easy_setopt expects a long argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, - "curl_easy_setopt expects a curl_off_t argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_string, - "curl_easy_setopt expects a " - "string ('char *' or char[]) argument for this option" - ) -_CURL_WARNING(_curl_easy_setopt_err_write_callback, - "curl_easy_setopt expects a curl_write_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_read_cb, - "curl_easy_setopt expects a curl_read_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, - "curl_easy_setopt expects a curl_ioctl_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, - "curl_easy_setopt expects a curl_sockopt_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, - "curl_easy_setopt expects a " - "curl_opensocket_callback argument for this option" - ) -_CURL_WARNING(_curl_easy_setopt_err_progress_cb, - "curl_easy_setopt expects a curl_progress_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_debug_cb, - "curl_easy_setopt expects a curl_debug_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, - "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_conv_cb, - "curl_easy_setopt expects a curl_conv_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_seek_cb, - "curl_easy_setopt expects a curl_seek_callback argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_cb_data, - "curl_easy_setopt expects a " - "private data pointer as argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_error_buffer, - "curl_easy_setopt expects a " - "char buffer of CURL_ERROR_SIZE as argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_FILE, - "curl_easy_setopt expects a 'FILE *' argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_postfields, - "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, - "curl_easy_setopt expects a 'struct curl_httppost *' " - "argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost, - "curl_easy_setopt expects a 'curl_mime *' " - "argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_curl_slist, - "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") -_CURL_WARNING(_curl_easy_setopt_err_CURLSH, - "curl_easy_setopt expects a CURLSH* argument for this option") - -_CURL_WARNING(_curl_easy_getinfo_err_string, - "curl_easy_getinfo expects a pointer to 'char *' for this info") -_CURL_WARNING(_curl_easy_getinfo_err_long, - "curl_easy_getinfo expects a pointer to long for this info") -_CURL_WARNING(_curl_easy_getinfo_err_double, - "curl_easy_getinfo expects a pointer to double for this info") -_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, - "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") -_CURL_WARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, - "curl_easy_getinfo expects a pointer to " - "'struct curl_tlssessioninfo *' for this info") -_CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo, - "curl_easy_getinfo expects a pointer to " - "'struct curl_certinfo *' for this info") -_CURL_WARNING(_curl_easy_getinfo_err_curl_socket, - "curl_easy_getinfo expects a pointer to curl_socket_t for this info") -_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t, - "curl_easy_getinfo expects a pointer to curl_off_t for this info") - -/* groups of curl_easy_setops options that take the same type of argument */ - -/* To add a new option to one of the groups, just add - * (option) == CURLOPT_SOMETHING - * to the or-expression. If the option takes a long or curl_off_t, you don't - * have to do anything - */ - -/* evaluates to true if option takes a long argument */ -#define _curl_is_long_option(option) \ - (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) - -#define _curl_is_off_t_option(option) \ - ((option) > CURLOPTTYPE_OFF_T) - -/* evaluates to true if option takes a char* argument */ -#define _curl_is_string_option(option) \ - ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ - (option) == CURLOPT_ACCEPT_ENCODING || \ - (option) == CURLOPT_CAINFO || \ - (option) == CURLOPT_CAPATH || \ - (option) == CURLOPT_COOKIE || \ - (option) == CURLOPT_COOKIEFILE || \ - (option) == CURLOPT_COOKIEJAR || \ - (option) == CURLOPT_COOKIELIST || \ - (option) == CURLOPT_CRLFILE || \ - (option) == CURLOPT_CUSTOMREQUEST || \ - (option) == CURLOPT_DEFAULT_PROTOCOL || \ - (option) == CURLOPT_DNS_INTERFACE || \ - (option) == CURLOPT_DNS_LOCAL_IP4 || \ - (option) == CURLOPT_DNS_LOCAL_IP6 || \ - (option) == CURLOPT_DNS_SERVERS || \ - (option) == CURLOPT_EGDSOCKET || \ - (option) == CURLOPT_FTPPORT || \ - (option) == CURLOPT_FTP_ACCOUNT || \ - (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ - (option) == CURLOPT_INTERFACE || \ - (option) == CURLOPT_ISSUERCERT || \ - (option) == CURLOPT_KEYPASSWD || \ - (option) == CURLOPT_KRBLEVEL || \ - (option) == CURLOPT_LOGIN_OPTIONS || \ - (option) == CURLOPT_MAIL_AUTH || \ - (option) == CURLOPT_MAIL_FROM || \ - (option) == CURLOPT_NETRC_FILE || \ - (option) == CURLOPT_NOPROXY || \ - (option) == CURLOPT_PASSWORD || \ - (option) == CURLOPT_PINNEDPUBLICKEY || \ - (option) == CURLOPT_PRE_PROXY || \ - (option) == CURLOPT_PROXY || \ - (option) == CURLOPT_PROXYPASSWORD || \ - (option) == CURLOPT_PROXYUSERNAME || \ - (option) == CURLOPT_PROXYUSERPWD || \ - (option) == CURLOPT_PROXY_CAINFO || \ - (option) == CURLOPT_PROXY_CAPATH || \ - (option) == CURLOPT_PROXY_CRLFILE || \ - (option) == CURLOPT_PROXY_KEYPASSWD || \ - (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ - (option) == CURLOPT_PROXY_SERVICE_NAME || \ - (option) == CURLOPT_PROXY_SSLCERT || \ - (option) == CURLOPT_PROXY_SSLCERTTYPE || \ - (option) == CURLOPT_PROXY_SSLKEY || \ - (option) == CURLOPT_PROXY_SSLKEYTYPE || \ - (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ - (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ - (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ - (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ - (option) == CURLOPT_RANDOM_FILE || \ - (option) == CURLOPT_RANGE || \ - (option) == CURLOPT_REFERER || \ - (option) == CURLOPT_RTSP_SESSION_ID || \ - (option) == CURLOPT_RTSP_STREAM_URI || \ - (option) == CURLOPT_RTSP_TRANSPORT || \ - (option) == CURLOPT_SERVICE_NAME || \ - (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ - (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ - (option) == CURLOPT_SSH_KNOWNHOSTS || \ - (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ - (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ - (option) == CURLOPT_SSLCERT || \ - (option) == CURLOPT_SSLCERTTYPE || \ - (option) == CURLOPT_SSLENGINE || \ - (option) == CURLOPT_SSLKEY || \ - (option) == CURLOPT_SSLKEYTYPE || \ - (option) == CURLOPT_SSL_CIPHER_LIST || \ - (option) == CURLOPT_TLSAUTH_PASSWORD || \ - (option) == CURLOPT_TLSAUTH_TYPE || \ - (option) == CURLOPT_TLSAUTH_USERNAME || \ - (option) == CURLOPT_UNIX_SOCKET_PATH || \ - (option) == CURLOPT_URL || \ - (option) == CURLOPT_USERAGENT || \ - (option) == CURLOPT_USERNAME || \ - (option) == CURLOPT_USERPWD || \ - (option) == CURLOPT_XOAUTH2_BEARER || \ - 0) - -/* evaluates to true if option takes a curl_write_callback argument */ -#define _curl_is_write_cb_option(option) \ - ((option) == CURLOPT_HEADERFUNCTION || \ - (option) == CURLOPT_WRITEFUNCTION) - -/* evaluates to true if option takes a curl_conv_callback argument */ -#define _curl_is_conv_cb_option(option) \ - ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ - (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ - (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) - -/* evaluates to true if option takes a data argument to pass to a callback */ -#define _curl_is_cb_data_option(option) \ - ((option) == CURLOPT_CHUNK_DATA || \ - (option) == CURLOPT_CLOSESOCKETDATA || \ - (option) == CURLOPT_DEBUGDATA || \ - (option) == CURLOPT_FNMATCH_DATA || \ - (option) == CURLOPT_HEADERDATA || \ - (option) == CURLOPT_INTERLEAVEDATA || \ - (option) == CURLOPT_IOCTLDATA || \ - (option) == CURLOPT_OPENSOCKETDATA || \ - (option) == CURLOPT_PRIVATE || \ - (option) == CURLOPT_PROGRESSDATA || \ - (option) == CURLOPT_READDATA || \ - (option) == CURLOPT_SEEKDATA || \ - (option) == CURLOPT_SOCKOPTDATA || \ - (option) == CURLOPT_SSH_KEYDATA || \ - (option) == CURLOPT_SSL_CTX_DATA || \ - (option) == CURLOPT_WRITEDATA || \ - 0) - -/* evaluates to true if option takes a POST data argument (void* or char*) */ -#define _curl_is_postfields_option(option) \ - ((option) == CURLOPT_POSTFIELDS || \ - (option) == CURLOPT_COPYPOSTFIELDS || \ - 0) - -/* evaluates to true if option takes a struct curl_slist * argument */ -#define _curl_is_slist_option(option) \ - ((option) == CURLOPT_HTTP200ALIASES || \ - (option) == CURLOPT_HTTPHEADER || \ - (option) == CURLOPT_MAIL_RCPT || \ - (option) == CURLOPT_POSTQUOTE || \ - (option) == CURLOPT_PREQUOTE || \ - (option) == CURLOPT_PROXYHEADER || \ - (option) == CURLOPT_QUOTE || \ - (option) == CURLOPT_RESOLVE || \ - (option) == CURLOPT_TELNETOPTIONS || \ - 0) - -/* groups of curl_easy_getinfo infos that take the same type of argument */ - -/* evaluates to true if info expects a pointer to char * argument */ -#define _curl_is_string_info(info) \ - (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) - -/* evaluates to true if info expects a pointer to long argument */ -#define _curl_is_long_info(info) \ - (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) - -/* evaluates to true if info expects a pointer to double argument */ -#define _curl_is_double_info(info) \ - (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) - -/* true if info expects a pointer to struct curl_slist * argument */ -#define _curl_is_slist_info(info) \ - (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) - -/* true if info expects a pointer to struct curl_tlssessioninfo * argument */ -#define _curl_is_tlssessioninfo_info(info) \ - (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) - -/* true if info expects a pointer to struct curl_certinfo * argument */ -#define _curl_is_certinfo_info(info) ((info) == CURLINFO_CERTINFO) - -/* true if info expects a pointer to struct curl_socket_t argument */ -#define _curl_is_socket_info(info) \ - (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) - -/* true if info expects a pointer to curl_off_t argument */ -#define _curl_is_off_t_info(info) \ - (CURLINFO_OFF_T < (info)) - - -/* typecheck helpers -- check whether given expression has requested type*/ - -/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, - * otherwise define a new macro. Search for __builtin_types_compatible_p - * in the GCC manual. - * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is - * the actual expression passed to the curl_easy_setopt macro. This - * means that you can only apply the sizeof and __typeof__ operators, no - * == or whatsoever. - */ - -/* XXX: should evaluate to true iff expr is a pointer */ -#define _curl_is_any_ptr(expr) \ - (sizeof(expr) == sizeof(void *)) - -/* evaluates to true if expr is NULL */ -/* XXX: must not evaluate expr, so this check is not accurate */ -#define _curl_is_NULL(expr) \ - (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) - -/* evaluates to true if expr is type*, const type* or NULL */ -#define _curl_is_ptr(expr, type) \ - (_curl_is_NULL(expr) || \ - __builtin_types_compatible_p(__typeof__(expr), type *) || \ - __builtin_types_compatible_p(__typeof__(expr), const type *)) - -/* evaluates to true if expr is one of type[], type*, NULL or const type* */ -#define _curl_is_arr(expr, type) \ - (_curl_is_ptr((expr), type) || \ - __builtin_types_compatible_p(__typeof__(expr), type [])) - -/* evaluates to true if expr is a string */ -#define _curl_is_string(expr) \ - (_curl_is_arr((expr), char) || \ - _curl_is_arr((expr), signed char) || \ - _curl_is_arr((expr), unsigned char)) - -/* evaluates to true if expr is a long (no matter the signedness) - * XXX: for now, int is also accepted (and therefore short and char, which - * are promoted to int when passed to a variadic function) */ -#define _curl_is_long(expr) \ - (__builtin_types_compatible_p(__typeof__(expr), long) || \ - __builtin_types_compatible_p(__typeof__(expr), signed long) || \ - __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ - __builtin_types_compatible_p(__typeof__(expr), int) || \ - __builtin_types_compatible_p(__typeof__(expr), signed int) || \ - __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ - __builtin_types_compatible_p(__typeof__(expr), short) || \ - __builtin_types_compatible_p(__typeof__(expr), signed short) || \ - __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ - __builtin_types_compatible_p(__typeof__(expr), char) || \ - __builtin_types_compatible_p(__typeof__(expr), signed char) || \ - __builtin_types_compatible_p(__typeof__(expr), unsigned char)) - -/* evaluates to true if expr is of type curl_off_t */ -#define _curl_is_off_t(expr) \ - (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) - -/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ -/* XXX: also check size of an char[] array? */ -#define _curl_is_error_buffer(expr) \ - (_curl_is_NULL(expr) || \ - __builtin_types_compatible_p(__typeof__(expr), char *) || \ - __builtin_types_compatible_p(__typeof__(expr), char[])) - -/* evaluates to true if expr is of type (const) void* or (const) FILE* */ -#if 0 -#define _curl_is_cb_data(expr) \ - (_curl_is_ptr((expr), void) || \ - _curl_is_ptr((expr), FILE)) -#else /* be less strict */ -#define _curl_is_cb_data(expr) \ - _curl_is_any_ptr(expr) -#endif - -/* evaluates to true if expr is of type FILE* */ -#define _curl_is_FILE(expr) \ - (_curl_is_NULL(expr) || \ - (__builtin_types_compatible_p(__typeof__(expr), FILE *))) - -/* evaluates to true if expr can be passed as POST data (void* or char*) */ -#define _curl_is_postfields(expr) \ - (_curl_is_ptr((expr), void) || \ - _curl_is_arr((expr), char)) - -/* FIXME: the whole callback checking is messy... - * The idea is to tolerate char vs. void and const vs. not const - * pointers in arguments at least - */ -/* helper: __builtin_types_compatible_p distinguishes between functions and - * function pointers, hide it */ -#define _curl_callback_compatible(func, type) \ - (__builtin_types_compatible_p(__typeof__(func), type) || \ - __builtin_types_compatible_p(__typeof__(func) *, type)) - -/* evaluates to true if expr is of type curl_read_callback or "similar" */ -#define _curl_is_read_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), __typeof__(fread) *) || \ - _curl_callback_compatible((expr), curl_read_callback) || \ - _curl_callback_compatible((expr), _curl_read_callback1) || \ - _curl_callback_compatible((expr), _curl_read_callback2) || \ - _curl_callback_compatible((expr), _curl_read_callback3) || \ - _curl_callback_compatible((expr), _curl_read_callback4) || \ - _curl_callback_compatible((expr), _curl_read_callback5) || \ - _curl_callback_compatible((expr), _curl_read_callback6)) -typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); -typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); -typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); -typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); -typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); -typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); - -/* evaluates to true if expr is of type curl_write_callback or "similar" */ -#define _curl_is_write_cb(expr) \ - (_curl_is_read_cb(expr) || \ - _curl_callback_compatible((expr), __typeof__(fwrite) *) || \ - _curl_callback_compatible((expr), curl_write_callback) || \ - _curl_callback_compatible((expr), _curl_write_callback1) || \ - _curl_callback_compatible((expr), _curl_write_callback2) || \ - _curl_callback_compatible((expr), _curl_write_callback3) || \ - _curl_callback_compatible((expr), _curl_write_callback4) || \ - _curl_callback_compatible((expr), _curl_write_callback5) || \ - _curl_callback_compatible((expr), _curl_write_callback6)) -typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); -typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, - const void *); -typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); -typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); -typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, - const void *); -typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); - -/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ -#define _curl_is_ioctl_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), curl_ioctl_callback) || \ - _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ - _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ - _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ - _curl_callback_compatible((expr), _curl_ioctl_callback4)) -typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); -typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); -typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); -typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); - -/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ -#define _curl_is_sockopt_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), curl_sockopt_callback) || \ - _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ - _curl_callback_compatible((expr), _curl_sockopt_callback2)) -typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); -typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, - curlsocktype); - -/* evaluates to true if expr is of type curl_opensocket_callback or - "similar" */ -#define _curl_is_opensocket_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), curl_opensocket_callback) || \ - _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ - _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ - _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ - _curl_callback_compatible((expr), _curl_opensocket_callback4)) -typedef curl_socket_t (*_curl_opensocket_callback1) - (void *, curlsocktype, struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback2) - (void *, curlsocktype, const struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback3) - (const void *, curlsocktype, struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback4) - (const void *, curlsocktype, const struct curl_sockaddr *); - -/* evaluates to true if expr is of type curl_progress_callback or "similar" */ -#define _curl_is_progress_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), curl_progress_callback) || \ - _curl_callback_compatible((expr), _curl_progress_callback1) || \ - _curl_callback_compatible((expr), _curl_progress_callback2)) -typedef int (*_curl_progress_callback1)(void *, - double, double, double, double); -typedef int (*_curl_progress_callback2)(const void *, - double, double, double, double); - -/* evaluates to true if expr is of type curl_debug_callback or "similar" */ -#define _curl_is_debug_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), curl_debug_callback) || \ - _curl_callback_compatible((expr), _curl_debug_callback1) || \ - _curl_callback_compatible((expr), _curl_debug_callback2) || \ - _curl_callback_compatible((expr), _curl_debug_callback3) || \ - _curl_callback_compatible((expr), _curl_debug_callback4) || \ - _curl_callback_compatible((expr), _curl_debug_callback5) || \ - _curl_callback_compatible((expr), _curl_debug_callback6) || \ - _curl_callback_compatible((expr), _curl_debug_callback7) || \ - _curl_callback_compatible((expr), _curl_debug_callback8)) -typedef int (*_curl_debug_callback1) (CURL *, - curl_infotype, char *, size_t, void *); -typedef int (*_curl_debug_callback2) (CURL *, - curl_infotype, char *, size_t, const void *); -typedef int (*_curl_debug_callback3) (CURL *, - curl_infotype, const char *, size_t, void *); -typedef int (*_curl_debug_callback4) (CURL *, - curl_infotype, const char *, size_t, const void *); -typedef int (*_curl_debug_callback5) (CURL *, - curl_infotype, unsigned char *, size_t, void *); -typedef int (*_curl_debug_callback6) (CURL *, - curl_infotype, unsigned char *, size_t, const void *); -typedef int (*_curl_debug_callback7) (CURL *, - curl_infotype, const unsigned char *, size_t, void *); -typedef int (*_curl_debug_callback8) (CURL *, - curl_infotype, const unsigned char *, size_t, const void *); - -/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ -/* this is getting even messier... */ -#define _curl_is_ssl_ctx_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), curl_ssl_ctx_callback) || \ - _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ - _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ - _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ - _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ - _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ - _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ - _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ - _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) -typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); -typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, - const void *); -#ifdef HEADER_SSL_H -/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX - * this will of course break if we're included before OpenSSL headers... - */ -typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); -typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); -typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); -typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, - const void *); -#else -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; -#endif - -/* evaluates to true if expr is of type curl_conv_callback or "similar" */ -#define _curl_is_conv_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), curl_conv_callback) || \ - _curl_callback_compatible((expr), _curl_conv_callback1) || \ - _curl_callback_compatible((expr), _curl_conv_callback2) || \ - _curl_callback_compatible((expr), _curl_conv_callback3) || \ - _curl_callback_compatible((expr), _curl_conv_callback4)) -typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); -typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); -typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); -typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); - -/* evaluates to true if expr is of type curl_seek_callback or "similar" */ -#define _curl_is_seek_cb(expr) \ - (_curl_is_NULL(expr) || \ - _curl_callback_compatible((expr), curl_seek_callback) || \ - _curl_callback_compatible((expr), _curl_seek_callback1) || \ - _curl_callback_compatible((expr), _curl_seek_callback2)) -typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); -typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); - - -#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/dep/cpr/opt/curl/lib/.gitattributes b/dep/cpr/opt/curl/lib/.gitattributes deleted file mode 100644 index 563eba7fd95..00000000000 --- a/dep/cpr/opt/curl/lib/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -objnames.inc eol=lf diff --git a/dep/cpr/opt/curl/lib/.gitignore b/dep/cpr/opt/curl/lib/.gitignore deleted file mode 100644 index 719fc977f3c..00000000000 --- a/dep/cpr/opt/curl/lib/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -*.a -*.imp -*.nlm -*.orig -*.rej -*.res -TAGS -curl_config.h -curl_config.h.in -libcurl.plist.dist -libcurl.vers -stamp-h1 diff --git a/dep/cpr/opt/curl/lib/CMakeLists.txt b/dep/cpr/opt/curl/lib/CMakeLists.txt deleted file mode 100644 index 0c0c4566f63..00000000000 --- a/dep/cpr/opt/curl/lib/CMakeLists.txt +++ /dev/null @@ -1,114 +0,0 @@ -set(LIB_NAME libcurl) - -configure_file(curl_config.h.cmake - ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h) - -transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) - -list(APPEND HHEADERS - ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h - ) - -if(MSVC) - list(APPEND CSOURCES libcurl.rc) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4127") -endif() - -# SET(CSOURCES -# # memdebug.c -not used -# # nwlib.c - Not used -# # strtok.c - specify later -# # strtoofft.c - specify later -# ) - -# # if we have Kerberos 4, right now this is never on -# #OPTION(CURL_KRB4 "Use Kerberos 4" OFF) -# IF(CURL_KRB4) -# SET(CSOURCES ${CSOURCES} -# krb4.c -# security.c -# ) -# ENDIF(CURL_KRB4) - -# #OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF) -# MARK_AS_ADVANCED(CURL_MALLOC_DEBUG) -# IF(CURL_MALLOC_DEBUG) -# SET(CSOURCES ${CSOURCES} -# memdebug.c -# ) -# ENDIF(CURL_MALLOC_DEBUG) - -# # only build compat strtoofft if we need to -# IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) -# SET(CSOURCES ${CSOURCES} -# strtoofft.c -# ) -# ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) - - -# The rest of the build - -include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) -if(USE_ARES) - include_directories(${CARES_INCLUDE_DIR}) -endif() - -if(CURL_STATICLIB) - # Static lib - set(CURL_USER_DEFINED_DYNAMIC_OR_STATIC STATIC) -else() - # DLL / so dynamic lib - set(CURL_USER_DEFINED_DYNAMIC_OR_STATIC SHARED) -endif() - -add_library( - ${LIB_NAME} - ${CURL_USER_DEFINED_DYNAMIC_OR_STATIC} - ${HHEADERS} ${CSOURCES} - ) - -if(MSVC AND CURL_STATICLIB) - set_target_properties(${LIB_NAME} PROPERTIES STATIC_LIBRARY_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) -endif() - -target_link_libraries(${LIB_NAME} ${CURL_LIBS}) - -if(WIN32) - add_definitions( -D_USRDLL ) -endif() - -set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL) - -if(HIDES_CURL_PRIVATE_SYMBOLS) - set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") - set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE}) -endif() - -# Remove the "lib" prefix since the library is already named "libcurl". -set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") -set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "") - -if(WIN32) - if(NOT CURL_STATICLIB) - # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib" - set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib") - - # set_target_properties (${LIB_NAME} PROPERTIES - # DEBUG_POSTFIX "-d" - # Note: no postfix for release variants, let user choose what style of release he wants - # MINSIZEREL_POSTFIX "-z" - # RELWITHDEBINFO_POSTFIX "-g" - # ) - endif() -endif() - -install(TARGETS ${LIB_NAME} - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin) diff --git a/dep/cpr/opt/curl/lib/Makefile.Watcom b/dep/cpr/opt/curl/lib/Makefile.Watcom deleted file mode 100644 index 77e5a6e0a17..00000000000 --- a/dep/cpr/opt/curl/lib/Makefile.Watcom +++ /dev/null @@ -1,275 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2005 - 2009, Gisle Vanem . -# Copyright (C) 2005 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -# -# Watcom / OpenWatcom / Win32 makefile for libcurl. -# - -.ERASE - -!if $(__VERSION__) < 1280 -!message !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!message ! This Open Watcom version is too old and is no longer supported ! -!message ! Please download latest version from www.openwatcom.org ! -!message !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!error Unsupported version of Open Watcom -!endif - -!ifndef %watcom -!error WATCOM environment variable not set! -!endif - -# In order to process Makefile.inc wmake must be called with -u switch! -!ifndef %MAKEFLAGS -!error You MUST call wmake with the -u switch! -!endif - -!ifdef %libname -LIBNAME = $(%libname) -!else -LIBNAME = libcurl -!endif -TARGETS = $(LIBNAME).dll $(LIBNAME).lib - -CC = wcc386 -LD = wlink -AR = wlib -RC = wrc - -!ifdef __LOADDLL__ -! loaddll wcc386 wccd386 -! loaddll wpp386 wppd386 -! loaddll wlib wlibd -! loaddll wlink wlinkd -!endif - -!ifdef __LINUX__ -CP = cp -MD = mkdir -p -!else -CP = copy 2>NUL -MD = mkdir -!endif -!if $(__VERSION__) > 1290 -RD = rm -rf -!else ifdef __UNIX__ -RD = rm -rf -!else -RD = rmdir /q /s 2>NUL -!endif - -SYS_INCL = -I"$(%watcom)/h/nt" -I"$(%watcom)/h" - -CFLAGS = -3r -mf -hc -zff -zgf -zq -zm -zc -s -fr=con -w2 -fpi -oilrtfm & - -wcd=201 -bt=nt -d+ -dWIN32 & - -dBUILDING_LIBCURL -I. -I"../include" $(SYS_INCL) - -!ifdef %debug -DEBUG = -dDEBUG=1 -dDEBUGBUILD -CFLAGS += -d3 $(DEBUG) -!else -CFLAGS += -d0 -!endif - -!ifdef %use_ipv6 -CFLAGS += -d_WIN32_WINNT=0x0501 -dENABLE_IPV6 -!endif - -!ifdef %use_sspi -CFLAGS += -dUSE_WINDOWS_SSPI -!endif - -!ifdef %use_winssl -CFLAGS += -dUSE_WINDOWS_SSPI -CFLAGS += -DUSE_SCHANNEL -!endif - -!ifdef %use_winidn -CFLAGS += -dWINVER=0x0600 -dUSE_WIN32_IDN -! if $(__VERSION__) <= 1290 -CFLAGS += -dWANT_IDN_PROTOTYPES -! endif -!endif - -# -# Change to suite. -# -!ifdef %zlib_root -ZLIB_ROOT = $(%zlib_root) -!else -ZLIB_ROOT = ../../zlib-1.2.8 -!endif - -!ifdef %libssh2_root -LIBSSH2_ROOT = $(%libssh2_root) -!else -LIBSSH2_ROOT = ../../libssh2-1.5.0 -!endif - -!ifdef %librtmp_root -LIBRTMP_ROOT = $(%librtmp_root) -!else -LIBRTMP_ROOT = ../../rtmpdump-2.3 -!endif - -!ifdef %openssl_root -OPENSSL_ROOT = $(%openssl_root) -!else -OPENSSL_ROOT = ../../openssl-1.0.2a -!endif - -!ifdef %ares_root -ARES_ROOT = $(%ares_root) -!else -ARES_ROOT = ../ares -!endif - -!ifdef %use_zlib -CFLAGS += -dHAVE_ZLIB_H -dHAVE_LIBZ -I"$(ZLIB_ROOT)" -!endif - -!ifdef %use_rtmp -CFLAGS += -dUSE_LIBRTMP -I"$(LIBRTMP_ROOT)" -!endif - -!ifdef %use_ssh2 -CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H -I"$(LIBSSH2_ROOT)/include" -I"$(LIBSSH2_ROOT)/win32" -!endif - -!ifdef %use_ssl -CFLAGS += -wcd=138 -dUSE_OPENSSL -dUSE_SSLEAY -I"$(OPENSSL_ROOT)/inc32" -!endif - -!ifdef %use_ares -CFLAGS += -dUSE_ARES -I"$(ARES_ROOT)" -!endif - -!ifdef %use_watt32 -CFLAGS += -dUSE_WATT32 -I"$(%watt_root)/inc" -!endif - -OBJ_BASE = WC_Win32.obj -!if $(__VERSION__) > 1290 -OBJ_STAT = $(OBJ_BASE)/stat -OBJ_DYN = $(OBJ_BASE)/dyn -!else ifdef __UNIX__ -OBJ_STAT = $(OBJ_BASE)/stat -OBJ_DYN = $(OBJ_BASE)/dyn -!else -OBJ_STAT = $(OBJ_BASE)\stat -OBJ_DYN = $(OBJ_BASE)\dyn -!endif - -LINK_ARG = $(OBJ_DYN)/wlink.arg -LIB_ARG = $(OBJ_STAT)/wlib.arg - -!include Makefile.inc - -OBJS1 = ./$(CSOURCES:.c=.obj) -OBJS2 = $(OBJS1:vtls/=) -OBJS3 = $(OBJS2:vauth/=) -OBJS4 = $(OBJS3: = ./) -OBJS_STAT = $(OBJS4:./=$(OBJ_STAT)/) -OBJS_DYN = $(OBJS4:./=$(OBJ_DYN)/) - -RESOURCE = $(OBJ_DYN)/libcurl.res - -DIRS = $(OBJ_BASE) $(OBJ_BASE)/stat $(OBJ_BASE)/dyn - -.c : vauth vtls - -all: $(DIRS) $(TARGETS) .SYMBOLIC - @echo Welcome to libcurl - -clean: .SYMBOLIC - -rm -f $(OBJS_STAT) - -rm -f $(OBJS_DYN) - -rm -f $(RESOURCE) $(LINK_ARG) $(LIB_ARG) - -vclean distclean: clean .SYMBOLIC - -rm -f $(TARGETS) $(LIBNAME).map $(LIBNAME).sym - -$(RD) $(OBJ_STAT) - -$(RD) $(OBJ_DYN) - -$(RD) $(OBJ_BASE) - -$(DIRS): - -$(MD) $^@ - -$(LIBNAME).dll: $(OBJS_DYN) $(RESOURCE) $(__MAKEFILES__) - %create $(LINK_ARG) - @%append $(LINK_ARG) system nt dll -!ifdef %debug - @%append $(LINK_ARG) debug all - @%append $(LINK_ARG) option symfile -!endif - @%append $(LINK_ARG) option quiet, caseexact, eliminate - @%append $(LINK_ARG) option map=$(OBJ_DYN)/$(LIBNAME).map - @%append $(LINK_ARG) option implib=$(LIBNAME)_imp.lib - @%append $(LINK_ARG) option res=$(RESOURCE) - @for %f in ($(OBJS_DYN)) do @%append $(LINK_ARG) file %f - @%append $(LINK_ARG) library wldap32.lib -!ifdef %use_watt32 - @%append $(LINK_ARG) library '$(%watt_root)/lib/wattcpw_imp.lib' -!else - @%append $(LINK_ARG) library ws2_32.lib -!endif -!ifdef %use_zlib - @%append $(LINK_ARG) library '$(ZLIB_ROOT)/zlib.lib' -!endif -!ifdef %use_rtmp - @%append $(LINK_ARG) library '$(LIBRTMP_ROOT)/librtmp/librtmp.lib' -!endif -!ifdef %use_ssh2 - @%append $(LINK_ARG) library '$(LIBSSH2_ROOT)/win32/libssh2.lib' -!endif -!ifdef %use_ssl - @%append $(LINK_ARG) library '$(OPENSSL_ROOT)/out32/libeay32.lib' - @%append $(LINK_ARG) library '$(OPENSSL_ROOT)/out32/ssleay32.lib' -!endif -!ifdef %use_ares - @%append $(LINK_ARG) library '$(ARES_ROOT)/cares.lib' -!endif -!ifdef %use_winidn -! if $(__VERSION__) > 1290 - @%append $(LINK_ARG) library normaliz.lib -! else - @%append $(LINK_ARG) import '_IdnToAscii@20' 'NORMALIZ.DLL'.'IdnToAscii' - @%append $(LINK_ARG) import '_IdnToUnicode@20' 'NORMALIZ.DLL'.'IdnToUnicode' -! endif -!endif - $(LD) name $^@ @$(LINK_ARG) - -$(LIBNAME).lib: $(OBJS_STAT) - %create $(LIB_ARG) - @for %f in ($<) do @%append $(LIB_ARG) +- %f - $(AR) -q -b -c -pa $^@ @$(LIB_ARG) - -$(RESOURCE): libcurl.rc - $(RC) $(DEBUG) -q -r -zm -bt=nt -I"../include" $(SYS_INCL) $[@ -fo=$^@ - -.c{$(OBJ_DYN)}.obj: - $(CC) $(CFLAGS) -bd -br $[@ -fo=$^@ - -.c{$(OBJ_STAT)}.obj: - $(CC) $(CFLAGS) -DCURL_STATICLIB $[@ -fo=$^@ - diff --git a/dep/cpr/opt/curl/lib/Makefile.am b/dep/cpr/opt/curl/lib/Makefile.am deleted file mode 100644 index 151c2615e5c..00000000000 --- a/dep/cpr/opt/curl/lib/Makefile.am +++ /dev/null @@ -1,141 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### -AUTOMAKE_OPTIONS = foreign nostdinc - -CMAKE_DIST = CMakeLists.txt curl_config.h.cmake - -EXTRA_DIST = Makefile.b32 Makefile.m32 config-win32.h \ - config-win32ce.h config-riscos.h config-mac.h curl_config.h.in \ - makefile.dj config-dos.h libcurl.plist libcurl.rc config-amigaos.h \ - makefile.amiga Makefile.netware nwlib.c nwos.c config-win32ce.h \ - config-os400.h setup-os400.h config-symbian.h Makefile.Watcom \ - config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ - firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl \ - objnames-test08.sh objnames-test10.sh objnames.inc - -lib_LTLIBRARIES = libcurl.la - -if BUILD_UNITTESTS -noinst_LTLIBRARIES = libcurlu.la -else -noinst_LTLIBRARIES = -endif - -# This might hold -Werror -CFLAGS += @CURL_CFLAG_EXTRAS@ - -# Specify our include paths here, and do it relative to $(top_srcdir) and -# $(top_builddir), to ensure that these paths which belong to the library -# being currently built and tested are searched before the library which -# might possibly already be installed in the system. -# -# $(top_srcdir)/include is for libcurl's external include files -# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file -# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "private" files -# $(top_builddir)/ares is for in-tree c-ares's generated ares_build.h file -# $(top_srcdir)/ares is for in-tree c-ares's external include files - -AM_CPPFLAGS = -I$(top_srcdir)/include \ - -I$(top_builddir)/lib \ - -I$(top_srcdir)/lib - -if USE_EMBEDDED_ARES -AM_CPPFLAGS += -I$(top_builddir)/ares \ - -I$(top_srcdir)/ares -endif - -# Prevent LIBS from being used for all link targets -LIBS = $(BLANK_AT_MAKETIME) - -VERSIONINFO=-version-info 9:0:5 -# This flag accepts an argument of the form current[:revision[:age]]. So, -# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to -# 1. -# -# Here's the simplified rule guide on how to change -version-info: -# (current version is C:R:A) -# -# 1. if there are only source changes, use C:R+1:A -# 2. if interfaces were added use C+1:0:A+1 -# 3. if interfaces were removed, then use C+1:0:0 -# -# For the full guide on libcurl ABI rules, see docs/libcurl/ABI - -AM_CPPFLAGS += -DBUILDING_LIBCURL -AM_LDFLAGS = -AM_CFLAGS = - -libcurl_la_CPPFLAGS_EXTRA = -libcurl_la_LDFLAGS_EXTRA = -libcurl_la_CFLAGS_EXTRA = - -@CODE_COVERAGE_RULES@ -libcurl_la_LDFLAGS_EXTRA += $(CODE_COVERAGE_LDFLAGS) -libcurl_la_CFLAGS_EXTRA += $(CODE_COVERAGE_CFLAGS) - -if CURL_LT_SHLIB_USE_VERSION_INFO -libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO) -endif - -if CURL_LT_SHLIB_USE_NO_UNDEFINED -libcurl_la_LDFLAGS_EXTRA += -no-undefined -endif - -if CURL_LT_SHLIB_USE_MIMPURE_TEXT -libcurl_la_LDFLAGS_EXTRA += -mimpure-text -endif - -if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS -libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers -endif - -if USE_CPPFLAG_CURL_STATICLIB -libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB -endif - -if DOING_CURL_SYMBOL_HIDING -libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS -libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) -endif - -libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) -libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) -libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) - -libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS -libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) -libcurlu_la_CFLAGS = $(AM_CFLAGS) - -# Makefile.inc provides the CSOURCES and HHEADERS defines -include Makefile.inc - -libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) -libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) - -checksrc: - @PERL@ $(srcdir)/checksrc.pl -D$(srcdir) -W$(srcdir)/curl_config.h \ - $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch] $(srcdir)/vtls/*.[ch] - -if CURLDEBUG -# for debug builds, we scan the sources on all regular make invokes -all-local: checksrc -endif diff --git a/dep/cpr/opt/curl/lib/Makefile.b32 b/dep/cpr/opt/curl/lib/Makefile.b32 deleted file mode 100644 index 5b5b5fa9fc2..00000000000 --- a/dep/cpr/opt/curl/lib/Makefile.b32 +++ /dev/null @@ -1,185 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2000, Jaepil Kim, . -# Copyright (C) 2001 - 2015, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -############################################################ -# -# Makefile.b32 - Borland's C++ Compiler 5.X -# -# 'BCCDIR' has to be set up to point to the base directory -# of the compiler, i.e. SET BCCDIR = c:\Borland\BCC55 -# -############################################################ - -!if "$(__MAKE__)" == "" -!error __MAKE__ not defined. Use Borlands's MAKE to process this makefile. -!endif - -# Borland's $(MAKEDIR) expands to the path where make.exe is located, -# use this feature to define BCCDIR when user has not defined BCCDIR. -!ifndef BCCDIR -BCCDIR = $(MAKEDIR)\.. -!endif - -# Edit the path below to point to the base of your Zlib sources. -!ifndef ZLIB_PATH -ZLIB_PATH = ..\..\zlib-1.2.8 -!endif - -# Edit the path below to point to the base of your OpenSSL package. -!ifndef OPENSSL_PATH -OPENSSL_PATH = ..\..\openssl-1.0.2a -!endif - -# Set libcurl static lib, dll and import lib -LIBCURL_LIB = libcurl.lib -LIBCURL_DLL = libcurl.dll -LIBCURL_IMPLIB = libcurl_imp.lib - -# Setup environment -PP_CMD = cpp32 -q -P- -CC_CMD = bcc32 -q -c -LD = bcc32 -RM = del 2>NUL -MKDIR = md -RMDIR = rd /q -LIB = tlib -IMPLIB = implib - -CC_FLAGS = -5 -O2 -tWM -w -w-aus -w-ccc -w-dup -w-prc -w-pro -w-rch -w-sig -w-spa -w-inl -w-pia -w-pin -Dinline=__inline -LIBFLAGS = /C /P32 -LDFLAGS = -q -lq -laa -tWD - -SRCDIR = .;.\vauth;.\vtls -OBJDIR = .\BCC_objs -INCDIRS = -I.;.\lib;..\include -LINKLIB = $(BCCDIR)\lib\cw32mt.lib $(BCCDIR)\lib\ws2_32.lib -DEFINES = -DNDEBUG -DWIN32 -DBUILDING_LIBCURL - -# By default SSPI support is enabled for BCC -!ifndef DISABLE_SSPI -DEFINES = $(DEFINES) -DUSE_WINDOWS_SSPI -!endif - -# By default LDAP support is disabled for BCC -!ifndef WITH_LDAP -DEFINES = $(DEFINES) -DCURL_DISABLE_LDAP -!endif - -# ZLIB support is enabled setting WITH_ZLIB=1 -!ifdef WITH_ZLIB -DEFINES = $(DEFINES) -DHAVE_LIBZ -DHAVE_ZLIB_H -INCDIRS = $(INCDIRS);$(ZLIB_PATH) -LINKLIB = $(LINKLIB) $(ZLIB_PATH)\zlib.lib -!endif - -# SSL support is enabled setting WITH_SSL=1 -!ifdef WITH_SSL -DEFINES = $(DEFINES) -DUSE_OPENSSL -INCDIRS = $(INCDIRS);$(OPENSSL_PATH)\inc32;$(OPENSSL_PATH)\inc32\openssl -LINKLIB = $(LINKLIB) $(OPENSSL_PATH)\out32\ssleay32.lib $(OPENSSL_PATH)\out32\libeay32.lib -!endif - -.autodepend - -.path.c = $(SRCDIR) -.path.obj = $(OBJDIR) -.path.int = $(OBJDIR) - -# Makefile.inc provides the CSOURCES and HHEADERS defines -!include Makefile.inc - -# Borland's command line librarian program TLIB version 4.5 is not capable -# of building a library when any of its objects contains an hyphen in its -# name, due to a command line parsing bug. In order to workaround this, we -# build source files with hyphens in their name as objects with underscores -# using explicit compilation build rules instead of implicit ones. - -NOHYPHEN1 = $(CSOURCES:-=_) -NOHYPHEN2 = $(NOHYPHEN1:vauth/=) -NOHYPHEN3 = $(NOHYPHEN2:vtls/=) - -OBJECTS = $(NOHYPHEN3:.c=.obj) -PREPROCESSED = $(NOHYPHEN3:.c=.int) - -# Borland's command line compiler (BCC32) version 5.5.1 integrated -# preprocessor has a bug which results in silently generating wrong -# definitions for libcurl macros such as CURL_OFF_T_C, on the other -# hand Borland's command line preprocessor (CPP32) version 5.5.1 does -# not have the bug and achieves proper results. In order to avoid the -# silent bug we first preprocess source files and later compile the -# preprocessed result. - -.c.obj: - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(<) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -all: $(OBJDIR) $(LIBCURL_LIB) $(LIBCURL_DLL) - -asyn_ares.obj: asyn-ares.c - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -asyn_thread.obj: asyn-thread.c - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -non_ascii.obj: non-ascii.c - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -clean: - cd $(OBJDIR) - @-$(RM) $(OBJECTS) - @-$(RM) $(PREPROCESSED) - cd .. - @-$(RMDIR) $(OBJDIR) - @-$(RM) $(LIBCURL_LIB) - @-$(RM) $(LIBCURL_IMPLIB) - @-$(RM) libcurl.tds - -$(OBJDIR): - @-$(RMDIR) $(OBJDIR) - @-$(MKDIR) $(OBJDIR) - -$(LIBCURL_LIB): $(OBJECTS) - @-$(RM) $(LIBCURL_LIB) - $(LIB) $(LIBFLAGS) $@ @&&! -+$(**: = &^ -+) -! - -$(LIBCURL_DLL) $(LIBCURL_IMPLIB): $(OBJECTS) $(LINKLIB) - @-$(RM) $(LIBCURL_DLL) - @-$(RM) $(LIBCURL_IMPLIB) - $(LD) $(LDFLAGS) -e$(LIBCURL_DLL) @&&! -$(**: = ^ -) -! - $(IMPLIB) $(LIBCURL_IMPLIB) $(LIBCURL_DLL) - - -# End of Makefile.b32 diff --git a/dep/cpr/opt/curl/lib/Makefile.inc b/dep/cpr/opt/curl/lib/Makefile.inc deleted file mode 100644 index 5c0b930cf86..00000000000 --- a/dep/cpr/opt/curl/lib/Makefile.inc +++ /dev/null @@ -1,81 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### - -LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ - vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \ - vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c \ - vauth/spnego_gssapi.c vauth/spnego_sspi.c - -LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h - -LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \ - vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c \ - vtls/mbedtls.c - -LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ - vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \ - vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \ - vtls/mbedtls.h - -LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ - cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ - ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ - getinfo.c transfer.c strcase.c easy.c security.c curl_fnmatch.c \ - fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ - strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ - http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ - strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ - inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ - ssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ - curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ - pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ - openldap.c curl_gethostname.c gopher.c idn_win32.c \ - http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ - http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \ - curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \ - x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ - mime.c - -LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ - formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ - speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ - strcase.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ - wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ - hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ - http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ - inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ - easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ - socks.h ssh.h curl_base64.h curl_addrinfo.h curl_sspi.h \ - slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ - rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ - curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ - http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ - curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ - curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \ - x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ - curl_printf.h system_win32.h rand.h mime.h - -LIB_RCFILES = libcurl.rc - -CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) -HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) diff --git a/dep/cpr/opt/curl/lib/Makefile.m32 b/dep/cpr/opt/curl/lib/Makefile.m32 deleted file mode 100644 index 22efbdee041..00000000000 --- a/dep/cpr/opt/curl/lib/Makefile.m32 +++ /dev/null @@ -1,355 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1999 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -########################################################################### -# -## Makefile for building libcurl.a with MingW (GCC-3.2 or later) -## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4) -## -## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...] -## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn -## -## Hint: you can also set environment vars to control the build, f.e.: -## set ZLIB_PATH=c:/zlib-1.2.8 -## set ZLIB=1 -# -########################################################################### - -# Edit the path below to point to the base of your Zlib sources. -ifndef ZLIB_PATH -ZLIB_PATH = ../../zlib-1.2.8 -endif -# Edit the path below to point to the base of your OpenSSL package. -ifndef OPENSSL_PATH -OPENSSL_PATH = ../../openssl-1.0.2a -endif -# Edit the path below to point to the base of your LibSSH2 package. -ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.5.0 -endif -# Edit the path below to point to the base of your librtmp package. -ifndef LIBRTMP_PATH -LIBRTMP_PATH = ../../librtmp-2.4 -endif -# Edit the path below to point to the base of your libidn2 package. -ifndef LIBIDN2_PATH -LIBIDN2_PATH = ../../libidn2-2.0.3 -endif -# Edit the path below to point to the base of your MS IDN package. -# Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1 -# https://www.microsoft.com/en-us/download/details.aspx?id=734 -ifndef WINIDN_PATH -WINIDN_PATH = ../../Microsoft IDN Mitigation APIs -endif -# Edit the path below to point to the base of your Novell LDAP NDK. -ifndef LDAP_SDK -LDAP_SDK = c:/novell/ndk/cldapsdk/win32 -endif -# Edit the path below to point to the base of your nghttp2 package. -ifndef NGHTTP2_PATH -NGHTTP2_PATH = ../../nghttp2-1.0.0 -endif - -PROOT = .. - -# Edit the path below to point to the base of your c-ares package. -ifndef LIBCARES_PATH -LIBCARES_PATH = $(PROOT)/ares -endif - -CC = $(CROSSPREFIX)gcc -CFLAGS = $(CURL_CFLAG_EXTRAS) -g -O2 -Wall -W -CFLAGS += -fno-strict-aliasing -# comment LDFLAGS below to keep debug info -LDFLAGS = $(CURL_LDFLAG_EXTRAS) $(CURL_LDFLAG_EXTRAS_DLL) -s -AR = $(CROSSPREFIX)ar -RANLIB = $(CROSSPREFIX)ranlib -RC = $(CROSSPREFIX)windres -RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O COFF -STRIP = $(CROSSPREFIX)strip -g - -# Set environment var ARCH to your architecture to override autodetection. -ifndef ARCH -ifeq ($(findstring x86_64,$(shell $(CC) -dumpmachine)),x86_64) -ARCH = w64 -else -ARCH = w32 -endif -endif - -ifeq ($(ARCH),w64) -CFLAGS += -m64 -D_AMD64_ -LDFLAGS += -m64 -RCFLAGS += -F pe-x86-64 -else -CFLAGS += -m32 -LDFLAGS += -m32 -RCFLAGS += -F pe-i386 -endif - -# Platform-dependent helper tool macros -ifeq ($(findstring /sh,$(SHELL)),/sh) -DEL = rm -f $1 -RMDIR = rm -fr $1 -MKDIR = mkdir -p $1 -COPY = -cp -afv $1 $2 -#COPYR = -cp -afr $1/* $2 -COPYR = -rsync -aC $1/* $2 -TOUCH = touch $1 -CAT = cat -ECHONL = echo "" -DL = ' -else -ifeq "$(OS)" "Windows_NT" -DEL = -del 2>NUL /q /f $(subst /,\,$1) -RMDIR = -rd 2>NUL /q /s $(subst /,\,$1) -else -DEL = -del 2>NUL $(subst /,\,$1) -RMDIR = -deltree 2>NUL /y $(subst /,\,$1) -endif -MKDIR = -md 2>NUL $(subst /,\,$1) -COPY = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2) -COPYR = -xcopy 2>NUL /q /y /e $(subst /,\,$1) $(subst /,\,$2) -TOUCH = copy 2>&1>NUL /b $(subst /,\,$1) +,, -CAT = type -ECHONL = $(ComSpec) /c echo. -endif - -######################################################## -## Nothing more to do below this line! - -ifeq ($(findstring -dyn,$(CFG)),-dyn) -DYN = 1 -endif -ifeq ($(findstring -ares,$(CFG)),-ares) -ARES = 1 -endif -ifeq ($(findstring -sync,$(CFG)),-sync) -SYNC = 1 -endif -ifeq ($(findstring -rtmp,$(CFG)),-rtmp) -RTMP = 1 -SSL = 1 -ZLIB = 1 -endif -ifeq ($(findstring -ssh2,$(CFG)),-ssh2) -SSH2 = 1 -SSL = 1 -ZLIB = 1 -endif -ifeq ($(findstring -ssl,$(CFG)),-ssl) -SSL = 1 -endif -ifeq ($(findstring -srp,$(CFG)),-srp) -SRP = 1 -endif -ifeq ($(findstring -zlib,$(CFG)),-zlib) -ZLIB = 1 -endif -ifeq ($(findstring -idn2,$(CFG)),-idn2) -IDN2 = 1 -endif -ifeq ($(findstring -winidn,$(CFG)),-winidn) -WINIDN = 1 -endif -ifeq ($(findstring -sspi,$(CFG)),-sspi) -SSPI = 1 -endif -ifeq ($(findstring -ldaps,$(CFG)),-ldaps) -LDAPS = 1 -endif -ifeq ($(findstring -ipv6,$(CFG)),-ipv6) -IPV6 = 1 -endif -ifeq ($(findstring -winssl,$(CFG)),-winssl) -WINSSL = 1 -SSPI = 1 -endif -ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) -NGHTTP2 = 1 -endif - -INCLUDES = -I. -I../include -CFLAGS += -DBUILDING_LIBCURL -ifdef SSL - ifdef WINSSL - CFLAGS += -DCURL_WITH_MULTI_SSL - endif -endif - -ifdef SYNC - CFLAGS += -DUSE_SYNC_DNS -else - ifdef ARES - INCLUDES += -I"$(LIBCARES_PATH)" - CFLAGS += -DUSE_ARES -DCARES_STATICLIB - DLL_LIBS += -L"$(LIBCARES_PATH)" -lcares - libcurl_dll_DEPENDENCIES = $(LIBCARES_PATH)/libcares.a - endif -endif -ifdef RTMP - INCLUDES += -I"$(LIBRTMP_PATH)" - CFLAGS += -DUSE_LIBRTMP - DLL_LIBS += -L"$(LIBRTMP_PATH)/librtmp" -lrtmp -lwinmm -endif -ifdef NGHTTP2 - INCLUDES += -I"$(NGHTTP2_PATH)/include" - CFLAGS += -DUSE_NGHTTP2 - DLL_LIBS += -L"$(NGHTTP2_PATH)/lib" -lnghttp2 -endif -ifdef SSH2 - INCLUDES += -I"$(LIBSSH2_PATH)/include" -I"$(LIBSSH2_PATH)/win32" - CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H - DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2 - ifdef WINSSL - ifndef DYN - DLL_LIBS += -lbcrypt -lcrypt32 - endif - endif -endif -ifdef SSL - ifndef OPENSSL_INCLUDE - ifeq "$(wildcard $(OPENSSL_PATH)/outinc)" "$(OPENSSL_PATH)/outinc" - OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc - endif - ifeq "$(wildcard $(OPENSSL_PATH)/include)" "$(OPENSSL_PATH)/include" - OPENSSL_INCLUDE = $(OPENSSL_PATH)/include - endif - endif - ifneq "$(wildcard $(OPENSSL_INCLUDE)/openssl/opensslv.h)" "$(OPENSSL_INCLUDE)/openssl/opensslv.h" - $(error Invalid path to OpenSSL package: $(OPENSSL_PATH)) - endif - ifndef OPENSSL_LIBPATH - ifeq "$(wildcard $(OPENSSL_PATH)/out)" "$(OPENSSL_PATH)/out" - OPENSSL_LIBPATH = $(OPENSSL_PATH)/out - OPENSSL_LIBS = -leay32 -lssl32 - endif - ifeq "$(wildcard $(OPENSSL_PATH)/lib)" "$(OPENSSL_PATH)/lib" - OPENSSL_LIBPATH = $(OPENSSL_PATH)/lib - OPENSSL_LIBS = -lcrypto -lssl - endif - endif - ifndef DYN - OPENSSL_LIBS += -lgdi32 -lcrypt32 - endif - INCLUDES += -I"$(OPENSSL_INCLUDE)" - CFLAGS += -DUSE_OPENSSL -DHAVE_OPENSSL_ENGINE_H -DHAVE_OPENSSL_PKCS12_H \ - -DHAVE_ENGINE_LOAD_BUILTIN_ENGINES -DOPENSSL_NO_KRB5 - DLL_LIBS += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) - ifdef SRP - ifeq "$(wildcard $(OPENSSL_INCLUDE)/openssl/srp.h)" "$(OPENSSL_INCLUDE)/openssl/srp.h" - CFLAGS += -DHAVE_OPENSSL_SRP -DUSE_TLS_SRP - endif - endif -endif -ifdef WINSSL - CFLAGS += -DUSE_SCHANNEL - DLL_LIBS += -lcrypt32 -endif -ifdef ZLIB - INCLUDES += -I"$(ZLIB_PATH)" - CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H - DLL_LIBS += -L"$(ZLIB_PATH)" -lz -endif -ifdef IDN2 - INCLUDES += -I"$(LIBIDN2_PATH)/include" - CFLAGS += -DUSE_LIBIDN2 - DLL_LIBS += -L"$(LIBIDN2_PATH)/lib" -lidn2 -else -ifdef WINIDN - CFLAGS += -DUSE_WIN32_IDN - CFLAGS += -DWANT_IDN_PROTOTYPES - DLL_LIBS += -L"$(WINIDN_PATH)" -lnormaliz -endif -endif -ifdef SSPI - CFLAGS += -DUSE_WINDOWS_SSPI -endif -ifdef SPNEGO - CFLAGS += -DHAVE_SPNEGO -endif -ifdef IPV6 - CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501 -endif -ifdef LDAPS - CFLAGS += -DHAVE_LDAP_SSL -endif -ifdef USE_LDAP_NOVELL - INCLUDES += -I"$(LDAP_SDK)/inc" - CFLAGS += -DCURL_HAS_NOVELL_LDAPSDK - DLL_LIBS += -L"$(LDAP_SDK)/lib/mscvc" -lldapsdk -lldapssl -lldapx -endif -ifdef USE_LDAP_OPENLDAP - INCLUDES += -I"$(LDAP_SDK)/include" - CFLAGS += -DCURL_HAS_OPENLDAP_LDAPSDK - DLL_LIBS += -L"$(LDAP_SDK)/lib" -lldap -llber -endif -ifndef USE_LDAP_NOVELL -ifndef USE_LDAP_OPENLDAP - DLL_LIBS += -lwldap32 -endif -endif -DLL_LIBS += -lws2_32 - -# Makefile.inc provides the CSOURCES and HHEADERS defines -include Makefile.inc - -libcurl_dll_LIBRARY = libcurl.dll -libcurl_dll_a_LIBRARY = libcurldll.a -libcurl_a_LIBRARY = libcurl.a - -libcurl_a_OBJECTS := $(patsubst %.c,%.o,$(strip $(CSOURCES))) -libcurl_a_DEPENDENCIES := $(strip $(CSOURCES) $(HHEADERS)) - -RESOURCE = libcurl.res - - -all: $(libcurl_a_LIBRARY) $(libcurl_dll_LIBRARY) - -$(libcurl_a_LIBRARY): $(libcurl_a_OBJECTS) $(libcurl_a_DEPENDENCIES) - @$(call DEL, $@) - $(AR) cru $@ $(libcurl_a_OBJECTS) - $(RANLIB) $@ - $(STRIP) $@ - -# remove the last line above to keep debug info - -$(libcurl_dll_LIBRARY): $(libcurl_a_OBJECTS) $(RESOURCE) $(libcurl_dll_DEPENDENCIES) - @$(call DEL, $@) - $(CC) $(LDFLAGS) -shared -o $@ \ - -Wl,--output-def,$(@:.dll=.def),--out-implib,$(libcurl_dll_a_LIBRARY) \ - $(libcurl_a_OBJECTS) $(RESOURCE) $(DLL_LIBS) - -%.o: %.c - $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@ - -%.res: %.rc - $(RC) $(RCFLAGS) -i $< -o $@ - -clean: - @$(call DEL, $(libcurl_a_OBJECTS) $(RESOURCE)) - -distclean vclean: clean - @$(call DEL, $(libcurl_a_LIBRARY) $(libcurl_dll_LIBRARY) $(libcurl_dll_LIBRARY:.dll=.def) $(libcurl_dll_a_LIBRARY)) - -$(LIBCARES_PATH)/libcares.a: - $(MAKE) -C $(LIBCARES_PATH) -f Makefile.m32 diff --git a/dep/cpr/opt/curl/lib/Makefile.netware b/dep/cpr/opt/curl/lib/Makefile.netware deleted file mode 100644 index a4ec4c8f381..00000000000 --- a/dep/cpr/opt/curl/lib/Makefile.netware +++ /dev/null @@ -1,761 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2004 - 2015, Guenter Knauf, . -# Copyright (C) 2001 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -################################################################# -# -## Makefile for building libcurl.nlm (NetWare version - gnu make) -## -## Use: make -f Makefile.netware -# -################################################################# - -# Edit the path below to point to the base of your Novell NDK. -ifndef NDKBASE -NDKBASE = c:/novell -endif - -# Edit the path below to point to the base of your Zlib sources. -ifndef ZLIB_PATH -ZLIB_PATH = ../../zlib-1.2.8 -endif - -# Edit the path below to point to the base of your OpenSSL package. -ifndef OPENSSL_PATH -OPENSSL_PATH = ../../openssl-1.0.2a -endif - -# Edit the path below to point to the base of your LibSSH2 package. -ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.5.0 -endif - -# Edit the path below to point to the base of your axTLS package. -ifndef AXTLS_PATH -AXTLS_PATH = ../../axTLS-1.2.7 -endif - -# Edit the path below to point to the base of your libidn package. -ifndef LIBIDN_PATH -LIBIDN_PATH = ../../libidn-1.18 -endif - -# Edit the path below to point to the base of your librtmp package. -ifndef LIBRTMP_PATH -LIBRTMP_PATH = ../../librtmp-2.3 -endif - -# Edit the path below to point to the base of your nghttp2 package. -ifndef NGHTTP2_PATH -NGHTTP2_PATH = ../../nghttp2-0.6.7 -endif - -# Edit the path below to point to the base of your fbopenssl package. -ifndef FBOPENSSL_PATH -FBOPENSSL_PATH = ../../fbopenssl-0.4 -endif - -# Edit the path below to point to the base of your c-ares package. -ifndef LIBCARES_PATH -LIBCARES_PATH = ../ares -endif - -ifndef INSTDIR -INSTDIR = ..$(DS)curl-$(LIBCURL_VERSION_STR)-bin-nw -endif - -# Edit the vars below to change NLM target settings. -TARGET = libcurl -VERSION = $(LIBCURL_VERSION) -COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR) -DESCR = curl libcurl $(LIBCURL_VERSION_STR) ($(LIBARCH)) - https://curl.haxx.se -MTSAFE = YES -STACK = 64000 -SCREEN = none -EXPORTF = $(TARGET).imp -EXPORTS = @$(EXPORTF) - -# Uncomment the next line to enable linking with POSIX semantics. -# POSIXFL = 1 - -# Edit the var below to point to your lib architecture. -ifndef LIBARCH -LIBARCH = LIBC -endif - -# must be equal to NDEBUG or DEBUG, CURLDEBUG -ifndef DB -DB = NDEBUG -endif -# Optimization: -O or debugging: -g -ifeq ($(DB),NDEBUG) - OPT = -O2 - OBJDIR = release -else - OPT = -g - OBJDIR = debug -endif - -# The following lines defines your compiler. -ifdef CWFolder - METROWERKS = $(CWFolder) -endif -ifdef METROWERKS - # MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support - MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support/Metrowerks Support - CC = mwccnlm -else - CC = gcc -endif -PERL = perl -# Here you can find a native Win32 binary of the original awk: -# http://www.gknw.net/development/prgtools/awk-20100523.zip -AWK = awk -CP = cp -afv -MKDIR = mkdir -# RM = rm -f -# If you want to mark the target as MTSAFE you will need a tool for -# generating the xdc data for the linker; here's a minimal tool: -# http://www.gknw.net/development/prgtools/mkxdc.zip -MPKXDC = mkxdc - -# LIBARCH_U = $(shell $(AWK) 'BEGIN {print toupper(ARGV[1])}' $(LIBARCH)) -LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH)) - -# Include the version info retrieved from curlver.h --include $(OBJDIR)/version.inc - -# Global flags for all compilers -CFLAGS += $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc - -ifeq ($(CC),mwccnlm) -LD = mwldnlm -LDFLAGS = -nostdlib $(PRELUDE) $(OBJL) -o $@ -commandfile -AR = mwldnlm -ARFLAGS = -nostdlib -type library -o -LIBEXT = lib -#RANLIB = -CFLAGS += -msgstyle gcc -gccinc -inline off -opt nointrinsics -proc 586 -CFLAGS += -relax_pointers -#CFLAGS += -w on -ifeq ($(LIBARCH),LIBC) -ifeq ($(POSIXFL),1) - PRELUDE = $(NDK_LIBC)/imports/posixpre.o -else - PRELUDE = $(NDK_LIBC)/imports/libcpre.o -endif - CFLAGS += -align 4 -else - # PRELUDE = $(NDK_CLIB)/imports/clibpre.o - # to avoid the __init_* / __deinit_* whoes don't use prelude from NDK - PRELUDE = "$(MWCW_PATH)/libraries/runtime/prelude.obj" - # CFLAGS += -include "$(MWCW_PATH)/headers/nlm_clib_prefix.h" - CFLAGS += -align 1 -endif -else -LD = nlmconv -LDFLAGS = -T -AR = ar -ARFLAGS = -cq -LIBEXT = a -RANLIB = ranlib -CFLAGS += -m32 -CFLAGS += -fno-builtin -fno-strict-aliasing -ifeq ($(findstring gcc,$(CC)),gcc) -CFLAGS += -fpcc-struct-return -endif -CFLAGS += -Wall # -pedantic -ifeq ($(LIBARCH),LIBC) -ifeq ($(POSIXFL),1) - PRELUDE = $(NDK_LIBC)/imports/posixpre.gcc.o -else - PRELUDE = $(NDK_LIBC)/imports/libcpre.gcc.o -endif -else - PRELUDE = $(NDK_CLIB)/imports/clibpre.gcc.o - # to avoid the __init_* / __deinit_* whoes don't use prelude from NDK - # http://www.gknw.net/development/mk_nlm/gcc_pre.zip - # PRELUDE = $(NDK_ROOT)/pre/prelude.o - CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h -endif -endif - -NDK_ROOT = $(NDKBASE)/ndk -ifndef NDK_CLIB -NDK_CLIB = $(NDK_ROOT)/nwsdk -endif -ifndef NDK_LIBC -NDK_LIBC = $(NDK_ROOT)/libc -endif -ifndef NDK_LDAP -NDK_LDAP = $(NDK_ROOT)/cldapsdk/netware -endif -CURL_INC = ../include -CURL_LIB = ../lib - -INCLUDES = -I$(CURL_INC) -I$(CURL_LIB) - -ifeq ($(findstring -static,$(CFG)),-static) -LINK_STATIC = 1 -endif -ifeq ($(findstring -ares,$(CFG)),-ares) -WITH_ARES = 1 -endif -ifeq ($(findstring -rtmp,$(CFG)),-rtmp) -WITH_RTMP = 1 -WITH_SSL = 1 -WITH_ZLIB = 1 -endif -ifeq ($(findstring -ssh2,$(CFG)),-ssh2) -WITH_SSH2 = 1 -WITH_SSL = 1 -WITH_ZLIB = 1 -endif -ifeq ($(findstring -axtls,$(CFG)),-axtls) -WITH_AXTLS = 1 -WITH_SSL = -else -ifeq ($(findstring -ssl,$(CFG)),-ssl) -WITH_SSL = 1 -ifeq ($(findstring -srp,$(CFG)),-srp) -ifeq "$(wildcard $(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)/openssl/srp.h)" "$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)/openssl/srp.h" -WITH_SRP = 1 -endif -endif -endif -endif -ifeq ($(findstring -zlib,$(CFG)),-zlib) -WITH_ZLIB = 1 -endif -ifeq ($(findstring -idn,$(CFG)),-idn) -WITH_IDN = 1 -endif -ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) -WITH_NGHTTP2 = 1 -endif -ifeq ($(findstring -ipv6,$(CFG)),-ipv6) -ENABLE_IPV6 = 1 -endif - -ifdef WITH_ARES - INCLUDES += -I$(LIBCARES_PATH) - LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT) -endif -ifdef WITH_SSH2 - INCLUDES += -I$(LIBSSH2_PATH)/include -ifdef LINK_STATIC - LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT) -else - MODULES += libssh2.nlm - IMPORTS += @$(LIBSSH2_PATH)/nw/libssh2.imp -endif -endif -ifdef WITH_RTMP - INCLUDES += -I$(LIBRTMP_PATH) - LDLIBS += $(LIBRTMP_PATH)/librtmp/librtmp.$(LIBEXT) -endif -ifdef WITH_SSL - INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) - LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT) - LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT) - IMPORTS += GetProcessSwitchCount RunningProcess - INSTDEP += ca-bundle.crt -else -ifdef WITH_AXTLS - INCLUDES += -I$(AXTLS_PATH)/inc -ifdef LINK_STATIC - LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT) -else - MODULES += libaxtls.nlm - IMPORTS += $(AXTLS_PATH)/lib/libaxtls.imp -endif - INSTDEP += ca-bundle.crt -endif -endif -ifdef WITH_ZLIB - INCLUDES += -I$(ZLIB_PATH) -ifdef LINK_STATIC - LDLIBS += $(ZLIB_PATH)/nw/$(LIBARCH)/libz.$(LIBEXT) -else - MODULES += libz.nlm - IMPORTS += @$(ZLIB_PATH)/nw/$(LIBARCH)/libz.imp -endif -endif -ifdef WITH_IDN - INCLUDES += -I$(LIBIDN_PATH)/include - LDLIBS += $(LIBIDN_PATH)/lib/libidn.$(LIBEXT) -endif -ifdef WITH_NGHTTP2 - INCLUDES += -I$(NGHTTP2_PATH)/include - LDLIBS += $(NGHTTP2_PATH)/lib/libnghttp2.$(LIBEXT) -endif - -ifeq ($(LIBARCH),LIBC) - INCLUDES += -I$(NDK_LIBC)/include - # INCLUDES += -I$(NDK_LIBC)/include/nks - # INCLUDES += -I$(NDK_LIBC)/include/winsock - CFLAGS += -D_POSIX_SOURCE -else - INCLUDES += -I$(NDK_CLIB)/include/nlm - # INCLUDES += -I$(NDK_CLIB)/include/nlm/obsolete - # INCLUDES += -I$(NDK_CLIB)/include -endif -ifndef DISABLE_LDAP - INCLUDES += -I$(NDK_LDAP)/$(LIBARCH_L)/inc -endif -CFLAGS += $(INCLUDES) - -ifeq ($(MTSAFE),YES) - XDCOPT = -n -endif -ifeq ($(MTSAFE),NO) - XDCOPT = -u -endif -ifdef XDCOPT - XDCDATA = $(OBJDIR)/$(TARGET).xdc -endif - -ifeq ($(findstring /sh,$(SHELL)),/sh) -DL = ' -DS = / -PCT = % -#-include $(NDKBASE)/nlmconv/ncpfs.inc -else -DS = \\ -PCT = %% -endif - -# Makefile.inc provides the CSOURCES and HHEADERS defines -include Makefile.inc - -OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(strip $(notdir $(CSOURCES)))) $(OBJDIR)/nwos.o - -OBJL = $(OBJS) $(OBJDIR)/nwlib.o $(LDLIBS) - -vpath %.c . vauth vtls - -all: lib nlm - -nlm: prebuild $(TARGET).nlm - -lib: prebuild $(TARGET).$(LIBEXT) - -prebuild: $(OBJDIR) $(OBJDIR)/version.inc curl_config.h - -$(OBJDIR)/%.o: %.c -# @echo Compiling $< - $(CC) $(CFLAGS) -c $< -o $@ - -$(OBJDIR)/version.inc: $(CURL_INC)/curl/curlver.h $(OBJDIR) - @echo Creating $@ - @$(AWK) -f ../packages/NetWare/get_ver.awk $< > $@ - -install: $(INSTDIR) all $(INSTDEP) - @$(CP) $(TARGET).nlm $(INSTDIR) - @$(CP) $(TARGET).$(LIBEXT) $(INSTDIR) - @$(CP) ../CHANGES $(INSTDIR) - @$(CP) ../COPYING $(INSTDIR) - @$(CP) ../README $(INSTDIR) - @$(CP) ../RELEASE-NOTES $(INSTDIR) -ifdef WITH_SSL - @-$(CP) ca-bundle.crt $(INSTDIR)/ca-bundle.crt -endif - -clean: - -$(RM) curl_config.h - -$(RM) -r $(OBJDIR) - -distclean vclean: clean - -$(RM) $(TARGET).$(LIBEXT) $(TARGET).nlm $(TARGET).imp - -$(RM) certdata.txt ca-bundle.crt - -$(OBJDIR) $(INSTDIR): - @$(MKDIR) $@ - -$(TARGET).$(LIBEXT): $(OBJS) - @echo Creating $@ - @-$(RM) $@ - @$(AR) $(ARFLAGS) $@ $^ -ifdef RANLIB - @$(RANLIB) $@ -endif - -$(TARGET).nlm: $(OBJDIR)/$(TARGET).def $(OBJL) $(EXPORTF) $(XDCDATA) - @echo Linking $@ - @-$(RM) $@ - @$(LD) $(LDFLAGS) $< - -$(OBJDIR)/%.xdc: Makefile.netware - @echo Creating $@ - @$(MPKXDC) $(XDCOPT) $@ - -$(OBJDIR)/%.def: Makefile.netware - @echo $(DL)# DEF file for linking with $(LD)$(DL) > $@ - @echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@ - @echo $(DL)# All your changes will be lost!!$(DL) >> $@ - @echo $(DL)#$(DL) >> $@ - @echo $(DL)copyright "$(COPYR)"$(DL) >> $@ - @echo $(DL)description "$(DESCR)"$(DL) >> $@ - @echo $(DL)version $(VERSION)$(DL) >> $@ -ifdef NLMTYPE - @echo $(DL)type $(NLMTYPE)$(DL) >> $@ -endif -ifdef STACK - @echo $(DL)stack $(STACK)$(DL) >> $@ -endif -ifdef SCREEN - @echo $(DL)screenname "$(SCREEN)"$(DL) >> $@ -else - @echo $(DL)screenname "DEFAULT"$(DL) >> $@ -endif -ifneq ($(DB),NDEBUG) - @echo $(DL)debug$(DL) >> $@ -endif - @echo $(DL)threadname "$(TARGET)"$(DL) >> $@ -ifdef XDCDATA - @echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@ -endif - @echo $(DL)flag_on 64$(DL) >> $@ -ifeq ($(LIBARCH),CLIB) - @echo $(DL)start _Prelude$(DL) >> $@ - @echo $(DL)exit _Stop$(DL) >> $@ - @echo $(DL)import @$(NDK_CLIB)/imports/clib.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_CLIB)/imports/threads.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_CLIB)/imports/nlmlib.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_CLIB)/imports/socklib.imp$(DL) >> $@ - @echo $(DL)module clib$(DL) >> $@ -ifndef DISABLE_LDAP - @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapsdk.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapssl.imp$(DL) >> $@ -# @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapx.imp$(DL) >> $@ - @echo $(DL)module ldapsdk ldapssl$(DL) >> $@ -endif -else -ifeq ($(POSIXFL),1) - @echo $(DL)flag_on 4194304$(DL) >> $@ -endif - @echo $(DL)pseudopreemption$(DL) >> $@ -ifeq ($(findstring posixpre,$(PRELUDE)),posixpre) - @echo $(DL)start POSIX_Start$(DL) >> $@ - @echo $(DL)exit POSIX_Stop$(DL) >> $@ - @echo $(DL)check POSIX_CheckUnload$(DL) >> $@ -else - @echo $(DL)start _LibCPrelude$(DL) >> $@ - @echo $(DL)exit _LibCPostlude$(DL) >> $@ - @echo $(DL)check _LibCCheckUnload$(DL) >> $@ -endif - @echo $(DL)import @$(NDK_LIBC)/imports/libc.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_LIBC)/imports/netware.imp$(DL) >> $@ - @echo $(DL)module libc$(DL) >> $@ -ifndef DISABLE_LDAP - @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapsdk.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapssl.imp$(DL) >> $@ -# @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapx.imp$(DL) >> $@ - @echo $(DL)module lldapsdk lldapssl$(DL) >> $@ -endif -endif -ifdef MODULES - @echo $(DL)module $(MODULES)$(DL) >> $@ -endif -ifdef EXPORTS - @echo $(DL)export $(EXPORTS)$(DL) >> $@ -endif -ifdef IMPORTS - @echo $(DL)import $(IMPORTS)$(DL) >> $@ -endif -ifeq ($(findstring nlmconv,$(LD)),nlmconv) - @echo $(DL)input $(PRELUDE)$(DL) >> $@ - @echo $(DL)input $(OBJL)$(DL) >> $@ -#ifdef LDLIBS -# @echo $(DL)input $(LDLIBS)$(DL) >> $@ -#endif - @echo $(DL)output $(TARGET).nlm$(DL) >> $@ -endif - -curl_config.h: Makefile.netware - @echo Creating $@ - @echo $(DL)/* $@ for NetWare target.$(DL) > $@ - @echo $(DL)** Do not edit this file - it is created by make!$(DL) >> $@ - @echo $(DL)** All your changes will be lost!!$(DL) >> $@ - @echo $(DL)*/$(DL) >> $@ - @echo $(DL)#ifndef NETWARE$(DL) >> $@ - @echo $(DL)#error This $(notdir $@) is created for NetWare platform!$(DL) >> $@ - @echo $(DL)#endif$(DL) >> $@ - @echo $(DL)#define VERSION "$(LIBCURL_VERSION_STR)"$(DL) >> $@ - @echo $(DL)#define PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/"$(DL) >> $@ -ifeq ($(LIBARCH),CLIB) - @echo $(DL)#define OS "i586-pc-clib-NetWare"$(DL) >> $@ - @echo $(DL)#define NETDB_USE_INTERNET 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRICMP 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRNICMP 1$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_ARG1 int$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_ARG2 char *$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_ARG3 int$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_ARG4 int$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_RETV int$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG1 int$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG2 char$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG3 int$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG4 int$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG5 struct sockaddr$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG6 int$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_RETV int$(DL) >> $@ - @echo $(DL)#define SEND_QUAL_ARG2$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_ARG1 int$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_ARG2 char *$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_ARG3 int$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_ARG4 int$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_RETV int$(DL) >> $@ - @echo $(DL)#define SIZEOF_SIZE_T 4$(DL) >> $@ - @echo $(DL)#define pressanykey PressAnyKeyToContinue$(DL) >> $@ -else - @echo $(DL)#define OS "i586-pc-libc-NetWare"$(DL) >> $@ - @echo $(DL)#define HAVE_FTRUNCATE 1$(DL) >> $@ - @echo $(DL)#define HAVE_GETTIMEOFDAY 1$(DL) >> $@ - @echo $(DL)#define HAVE_INTTYPES_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_LONGLONG 1$(DL) >> $@ - @echo $(DL)#define HAVE_STDINT_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRCASECMP 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRLCAT 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRLCPY 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRTOLL 1$(DL) >> $@ - @echo $(DL)#define HAVE_SYS_PARAM_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_SYS_SELECT_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_TERMIOS_H 1$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_ARG1 int$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_ARG2 void *$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_ARG3 size_t$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_ARG4 int$(DL) >> $@ - @echo $(DL)#define RECV_TYPE_RETV ssize_t$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG1 int$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG2 void$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG3 size_t$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG4 int$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG5 struct sockaddr$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG6 size_t$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_RETV ssize_t$(DL) >> $@ - @echo $(DL)#define RECVFROM_TYPE_ARG2_IS_VOID 1$(DL) >> $@ - @echo $(DL)#define SEND_QUAL_ARG2$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_ARG1 int$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_ARG2 void *$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_ARG3 size_t$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_ARG4 int$(DL) >> $@ - @echo $(DL)#define SEND_TYPE_RETV ssize_t$(DL) >> $@ - @echo $(DL)#define SIZEOF_OFF_T 8$(DL) >> $@ - @echo $(DL)#define SIZEOF_SIZE_T 8$(DL) >> $@ - @echo $(DL)#define _LARGEFILE 1$(DL) >> $@ -ifdef ENABLE_IPV6 - @echo $(DL)#define ENABLE_IPV6 1$(DL) >> $@ - @echo $(DL)#define HAVE_AF_INET6 1$(DL) >> $@ - @echo $(DL)#define HAVE_PF_INET6 1$(DL) >> $@ - @echo $(DL)#define HAVE_FREEADDRINFO 1$(DL) >> $@ - @echo $(DL)#define HAVE_GETADDRINFO 1$(DL) >> $@ - @echo $(DL)#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRUCT_ADDRINFO 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRUCT_IN6_ADDR 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRUCT_SOCKADDR_IN6 1$(DL) >> $@ - @echo $(DL)#define SIZEOF_STRUCT_IN6_ADDR 16$(DL) >> $@ -endif -endif - @echo $(DL)#define USE_MANUAL 1$(DL) >> $@ - @echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_ERRNO_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_ERR_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_GETHOSTBYADDR 1$(DL) >> $@ - @echo $(DL)#define HAVE_GETHOSTBYNAME 1$(DL) >> $@ - @echo $(DL)#define HAVE_GETPROTOBYNAME 1$(DL) >> $@ - @echo $(DL)#define HAVE_GMTIME_R 1$(DL) >> $@ - @echo $(DL)#define HAVE_INET_ADDR 1$(DL) >> $@ - @echo $(DL)#define HAVE_IOCTL 1$(DL) >> $@ - @echo $(DL)#define HAVE_IOCTL_FIONBIO 1$(DL) >> $@ - @echo $(DL)#define HAVE_LIMITS_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_LL 1$(DL) >> $@ - @echo $(DL)#define HAVE_LOCALE_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_LOCALTIME_R 1$(DL) >> $@ - @echo $(DL)#define HAVE_MALLOC_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_NETINET_IN_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_RECV 1$(DL) >> $@ - @echo $(DL)#define HAVE_RECVFROM 1$(DL) >> $@ - @echo $(DL)#define HAVE_SELECT 1$(DL) >> $@ - @echo $(DL)#define HAVE_SEND 1$(DL) >> $@ - @echo $(DL)#define HAVE_SETJMP_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_SETLOCALE 1$(DL) >> $@ - @echo $(DL)#define HAVE_SIGNAL 1$(DL) >> $@ - @echo $(DL)#define HAVE_SIGNAL_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_SIG_ATOMIC_T 1$(DL) >> $@ - @echo $(DL)#define HAVE_SOCKET 1$(DL) >> $@ - @echo $(DL)#define HAVE_STDLIB_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRDUP 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRFTIME 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRING_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRSTR 1$(DL) >> $@ - @echo $(DL)#define HAVE_STRUCT_TIMEVAL 1$(DL) >> $@ - @echo $(DL)#define HAVE_SYS_IOCTL_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_SYS_STAT_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_SYS_TIME_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_TIME_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_UNAME 1$(DL) >> $@ - @echo $(DL)#define HAVE_UNISTD_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_UTIME 1$(DL) >> $@ - @echo $(DL)#define HAVE_UTIME_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_WRITEV 1$(DL) >> $@ - @echo $(DL)#define RETSIGTYPE void$(DL) >> $@ - @echo $(DL)#define SIZEOF_INT 4$(DL) >> $@ - @echo $(DL)#define SIZEOF_SHORT 2$(DL) >> $@ - @echo $(DL)#define SIZEOF_STRUCT_IN_ADDR 4$(DL) >> $@ - @echo $(DL)#define STDC_HEADERS 1$(DL) >> $@ - @echo $(DL)#define TIME_WITH_SYS_TIME 1$(DL) >> $@ -ifdef DISABLE_LDAP - @echo $(DL)#define CURL_DISABLE_LDAP 1$(DL) >> $@ -else - @echo $(DL)#define CURL_HAS_NOVELL_LDAPSDK 1$(DL) >> $@ -ifndef DISABLE_LDAPS - @echo $(DL)#define HAVE_LDAP_SSL 1$(DL) >> $@ -endif - @echo $(DL)#define HAVE_LDAP_SSL_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_LDAP_URL_PARSE 1$(DL) >> $@ -endif -ifdef NW_WINSOCK - @echo $(DL)#define HAVE_CLOSESOCKET 1$(DL) >> $@ -else - @echo $(DL)#define USE_BSD_SOCKETS 1$(DL) >> $@ - @echo $(DL)#define HAVE_SYS_TYPES_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_SYS_SOCKET_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_SYS_SOCKIO_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_NETDB_H 1$(DL) >> $@ -endif -ifdef WITH_ARES - @echo $(DL)#define USE_ARES 1$(DL) >> $@ -endif -ifdef WITH_ZLIB - @echo $(DL)#define HAVE_ZLIB_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_LIBZ 1$(DL) >> $@ -endif -ifdef WITH_SSL - @echo $(DL)#define USE_SSLEAY 1$(DL) >> $@ - @echo $(DL)#define USE_OPENSSL 1$(DL) >> $@ - @echo $(DL)#define HAVE_OPENSSL_X509_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_OPENSSL_SSL_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_OPENSSL_RSA_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_OPENSSL_PEM_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_OPENSSL_ERR_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_OPENSSL_CRYPTO_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_OPENSSL_ENGINE_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_LIBSSL 1$(DL) >> $@ - @echo $(DL)#define HAVE_LIBCRYPTO 1$(DL) >> $@ - @echo $(DL)#define OPENSSL_NO_KRB5 1$(DL) >> $@ -ifdef WITH_SRP - @echo $(DL)#define HAVE_SSLEAY_SRP 1$(DL) >> $@ - @echo $(DL)#define USE_TLS_SRP 1$(DL) >> $@ -endif -ifdef WITH_SPNEGO - @echo $(DL)#define HAVE_SPNEGO 1$(DL) >> $@ -endif -else -ifdef WITH_AXTLS - @echo $(DL)#define USE_AXTLS 1$(DL) >> $@ -endif -endif -ifdef WITH_SSH2 - @echo $(DL)#define USE_LIBSSH2 1$(DL) >> $@ - @echo $(DL)#define HAVE_LIBSSH2_H 1$(DL) >> $@ -endif -ifdef WITH_IDN - @echo $(DL)#define HAVE_LIBIDN 1$(DL) >> $@ - @echo $(DL)#define HAVE_TLD_H 1$(DL) >> $@ -endif -ifdef WITH_RTMP - @echo $(DL)#define USE_LIBRTMP 1$(DL) >> $@ -endif -ifdef WITH_NGHTTP2 - @echo $(DL)#define USE_NGHTTP2 1$(DL) >> $@ -endif - @echo $(DL)#ifdef __GNUC__$(DL) >> $@ - @echo $(DL)#define HAVE_VARIADIC_MACROS_GCC 1$(DL) >> $@ - @echo $(DL)#else$(DL) >> $@ - @echo $(DL)#define HAVE_VARIADIC_MACROS_C99 1$(DL) >> $@ - @echo $(DL)#endif$(DL) >> $@ -ifdef CABUNDLE - @echo $(DL)#define CURL_CA_BUNDLE "$(CABUNDLE)"$(DL) >> $@ -else - @echo $(DL)#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")$(DL) >> $@ -endif - -$(EXPORTF): $(CURL_INC)/curl/curl.h $(CURL_INC)/curl/easy.h $(CURL_INC)/curl/multi.h $(CURL_INC)/curl/mprintf.h - @echo Creating $@ - @$(AWK) -f ../packages/NetWare/get_exp.awk $^ > $@ - -FORCE: ; - -info: $(OBJDIR)/version.inc - @echo Configured to build $(TARGET) with these options: - @echo libarchitecture: $(LIBARCH) - @echo curl version: $(LIBCURL_VERSION_STR) - @echo compiler/linker: $(CC) / $(LD) -ifdef CABUNDLE - @echo ca-bundle path: $(CABUNDLE) -endif -ifdef WITH_SSL - @echo SSL support: enabled (OpenSSL) -else - @echo SSL support: no -endif -ifdef WITH_SRP - @echo SRP support: enabled -else - @echo SRP support: no -endif -ifdef WITH_SSH2 - @echo SSH2 support: enabled (libssh2) -else - @echo SSH2 support: no -endif -ifdef WITH_ZLIB - @echo zlib support: enabled -else - @echo zlib support: no -endif -ifdef WITH_NGHTTP2 - @echo http2 support: enabled -else - @echo http2 support: no -endif -ifdef WITH_ARES - @echo c-ares support: enabled -else - @echo c-ares support: no -endif -ifdef ENABLE_IPV6 - @echo IPv6 support: enabled -else - @echo IPv6 support: no -endif - -$(LIBCARES_PATH)/libcares.$(LIBEXT): - $(MAKE) -C $(LIBCARES_PATH) -f Makefile.netware lib - -ca-bundle.crt: mk-ca-bundle.pl - @echo Creating $@ - @-$(PERL) $< -b -n $@ - diff --git a/dep/cpr/opt/curl/lib/Makefile.vxworks b/dep/cpr/opt/curl/lib/Makefile.vxworks deleted file mode 100644 index 7ff197f0334..00000000000 --- a/dep/cpr/opt/curl/lib/Makefile.vxworks +++ /dev/null @@ -1,177 +0,0 @@ -#***************************************************************************** -# -# -#Filename : Makefile.vxworks -#Description: makefile to be used in order to compile libcurl for VxWoorks 6.3. -# -#How to use: -# 1. Adjust environment variables at the file beginning -# 2. Open the Command Prompt window and change directory ('cd') -# into the 'lib' folder -# 3. Add /bin folder to the PATH environment variable -# For example type 'set PATH=C:/embedded/cygwin/bin;%PATH%' -# 4. Build the library by typing 'make -f ./Makefile.vxworks' -# As a result the libcurl.a should be created in the 'lib' folder. -# To clean package use 'make -f ./Makefile.vxworks clean' -#Requirements: -# 1. WinXP machine -# 2. Full CYGWIN installation (open source) with GNU make version -# v3.78 or higher -# 3. WindRiver Workbench with vxWorks 6.3 (commercial) -#***************************************************************************** - -# ---------------------------------------------------------------------- -# Environment -# ---------------------------------------------------------------------- - -export WIND_HOME := C:/embedded/Workbench2.5.0.1 -export WIND_BASE := $(WIND_HOME)/vxworks-6.3 -export WIND_HOST_TYPE := x86-win32 - -# BUILD_TYE:= | (build with debugging info or optimized) -BUILD_TYPE := debug -USER_CFLAGS:= - -# directories where to seek for includes and libraries -OPENSSL_INC := D:/libraries/openssl/openssl-0.9.8zc-vxWorks6.3/include -OPENSSL_LIB := D:/libraries/openssl/openssl-0.9.8zc-vxWorks6.3 -ZLIB_INC := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/zlib-1.2.8 -ZLIB_LIB := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/binaries/vxworks_3.1_gnu/Debug/lib -ARES_INC := -ARES_LIB := - - -# ---------------------------------------------------------------------- -# Compiler -# ---------------------------------------------------------------------- - -CC := ccppc -AR := arppc -LINK := ccppc -CFLAGS := -D__GNUC__ -D__ppc__ -msoft-float -fno-builtin -mcpu=604 -mlongcall -DCPU=PPC604 -D_GNU_TOOL -Wall -W -Winline $(USER_CFLAGS) -LDFLAGS := -nostdlib -Wl,-i -Wl,-X -INCLUDE_FLAG := -I -C_DEBUGFLAG := -g -C_OPTFLAG := -O2 -COMPILE_ONLY_FLAG := -c -OBJ_EXTENSION := .o -CC_OBJ_OUTPUT = -o $@ -ARFLAGS := -rc -LIBS_FLAG := -l -LIBS_DIRFLAG:= -L -LD_DEBUGFLAG := $(C_DEBUGFLAG) -EXECUTE_EXTENSION := .out -TOOL_CHAIN_BIN := $(WIND_HOME)/gnu/3.4.4-vxworks-6.3/$(WIND_HOST_TYPE)/bin/ - -# ---------------------------------------------------------------------- - -# Add -DINET6 if the OS kernel image was built with IPv6 support -# CFLAGS += -DINET6 - -# Set up compiler and linker flags for debug or optimization -ifeq ($(BUILD_TYPE), debug) -CFLAGS += $(C_DEBUGFLAG) -LDFLAGS += $(LD_DEBUGFLAG) -else -CFLAGS += $(C_OPTFLAG) -endif - -# ---------------------------------------------------------------------- - -# Main Makefile and possible sub-make files -MAKEFILES := Makefile.vxworks - -# List of external include directories -#----- -# IMPORTANT: include OPENSSL directories before system -# in order to prevent WindRiver OpenSSL to be used. -#----- -INCLUDE_DIRS := ../include $(OPENSSL_INC) $(ZLIB_INC) $(ARES_INC) $(WIND_BASE)/target/h $(WIND_BASE)/target/h/wrn/coreip - -# List of external libraries and their directories -LIBS_LIST := . -LIB_DIRS := . -ifneq ($(OPENSSL_LIB), ) -LIBS_LIST += crypto ssl -LIB_DIRS += $(OPENSSL_LIB) -endif -ifneq ($(ZLIB_LIB), ) -LIBS_LIST += z -LIB_DIRS += $(ZLIB_LIB) -endif -ifneq ($(ARES_LIB), ) -LIBS_LIST += ares -LIB_DIRS += $(ARES_LIB) -endif - -# Add include and library directories and libraries -CFLAGS += $(INCLUDE_DIRS:%=$(INCLUDE_FLAG)%) -LDFLAGS += $(LIB_DIRS:%=$(LIBS_DIRFLAG)%) - -# List of targets to make for libs target -LIBS_TARGET_LIST := libcurl.a - -# List of execuatble applications to make in addition to libs for all target -EXE_TARGET_LIST := - -# Support for echoing rules -# If ECHORULES variable was set (for example, using 'make' command line) -# some shell commands in the rules will be echoed -ifneq ($(strip $(findstring $(ECHORULES), yes YES 1 true TRUE)),) -_@_ := -else -_@_ := @ -endif - -# Directory to hold compilation intermediate files -TMP_DIR := tmp - -# Get sources and headers to be compiled -include Makefile.inc - -# List of headers -INCLUDE_FILES := $(HHEADERS) -INCLUDE_FILES += $(shell find ../include -name \*.h) - -# List of sources -OBJLIST := $(CSOURCES:%.c=$(TMP_DIR)/%$(OBJ_EXTENSION)) - - -# ---------------------------------------------------------------------- - -#### default rule -# It should be first rule in this file -.PHONY: default -default: libcurl.a - -#### Compiling C files -$(TMP_DIR)/%$(OBJ_EXTENSION): %.c $(MAKEFILES) - @echo Compiling C file $< $(ECHO_STDOUT) - @[ -d $(@D) ] || mkdir -p $(@D) - $(_@_) $(TOOL_CHAIN_BIN)$(CC) $(COMPILE_ONLY_FLAG) $(CFLAGS) $< $(CC_OBJ_OUTPUT) - -#### Creating library -$(LIBS_TARGET_LIST): $(INCLUDE_FILES) $(MAKEFILES) $(OBJLIST) - @echo Creating library $@ $(ECHO_STDOUT) - $(_@_) [ -d $(@D) ] || mkdir -p $(@D) - $(_@_) rm -f $@ - $(_@_) $(TOOL_CHAIN_BIN)$(AR) $(ARFLAGS) $@ $(filter %$(OBJ_EXTENSION), $^) - -#### Creating application -$(EXE_TARGET_LIST): $(INCLUDE_FILES) $(MAKEFILES) $(LIBS_TARGET_LIST) - @echo Creating application $@ - @[ -d $(@D) ] || mkdir -p $(@D) - $(_@_) $(TOOL_CHAIN_BIN)$(LINK) $(CC_OBJ_OUTPUT) $($(@)_EXE_OBJ_LIST) $(LDFLAGS) $($(@)_EXE_LIBS_NEEDED:%=$(LIBS_FLAG)%) $(LIBS_LIST:%=$(LIBS_FLAG)%) $(USER_LIBS_LIST) $(USER_LIBS_LIST) - -#### Master Targets -libs: $(LIBS_TARGET_LIST) - @echo All libs made. - -all: $(LIBS_TARGET_LIST) $(EXE_TARGET_LIST) $(INCLUDE_TARGET_LIST) - @echo All targets made. - -# Clean up -.PHONY: clean -clean: - $(_@_) rm -rf $(TMP_DIR) - @echo libcurl was cleaned. diff --git a/dep/cpr/opt/curl/lib/amigaos.c b/dep/cpr/opt/curl/lib/amigaos.c deleted file mode 100644 index 4f55b30e761..00000000000 --- a/dep/cpr/opt/curl/lib/amigaos.c +++ /dev/null @@ -1,77 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(__AMIGA__) && !defined(__ixemul__) - -#include - -#include "amigaos.h" - -struct Library *SocketBase = NULL; -extern int errno, h_errno; - -#ifdef __libnix__ -#include -void __request(const char *msg); -#else -# define __request(msg) Printf(msg "\n\a") -#endif - -void Curl_amiga_cleanup() -{ - if(SocketBase) { - CloseLibrary(SocketBase); - SocketBase = NULL; - } -} - -bool Curl_amiga_init() -{ - if(!SocketBase) - SocketBase = OpenLibrary("bsdsocket.library", 4); - - if(!SocketBase) { - __request("No TCP/IP Stack running!"); - return FALSE; - } - - if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, - SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", - TAG_DONE)) { - __request("SocketBaseTags ERROR"); - return FALSE; - } - -#ifndef __libnix__ - atexit(Curl_amiga_cleanup); -#endif - - return TRUE; -} - -#ifdef __libnix__ -ADD2EXIT(Curl_amiga_cleanup, -50); -#endif - -#endif /* __AMIGA__ && ! __ixemul__ */ diff --git a/dep/cpr/opt/curl/lib/amigaos.h b/dep/cpr/opt/curl/lib/amigaos.h deleted file mode 100644 index 02bee16107a..00000000000 --- a/dep/cpr/opt/curl/lib/amigaos.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef HEADER_CURL_AMIGAOS_H -#define HEADER_CURL_AMIGAOS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#if defined(__AMIGA__) && !defined(__ixemul__) - -bool Curl_amiga_init(); -void Curl_amiga_cleanup(); - -#else - -#define Curl_amiga_init() 1 -#define Curl_amiga_cleanup() Curl_nop_stmt - -#endif - -#endif /* HEADER_CURL_AMIGAOS_H */ - diff --git a/dep/cpr/opt/curl/lib/arpa_telnet.h b/dep/cpr/opt/curl/lib/arpa_telnet.h deleted file mode 100644 index ec238729dda..00000000000 --- a/dep/cpr/opt/curl/lib/arpa_telnet.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef HEADER_CURL_ARPA_TELNET_H -#define HEADER_CURL_ARPA_TELNET_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#ifndef CURL_DISABLE_TELNET -/* - * Telnet option defines. Add more here if in need. - */ -#define CURL_TELOPT_BINARY 0 /* binary 8bit data */ -#define CURL_TELOPT_ECHO 1 /* just echo! */ -#define CURL_TELOPT_SGA 3 /* Suppress Go Ahead */ -#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */ -#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */ -#define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */ -#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */ - -#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */ -#define CURL_NEW_ENV_VAR 0 -#define CURL_NEW_ENV_VALUE 1 - -/* - * The telnet options represented as strings - */ -static const char * const telnetoptions[]= -{ - "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", - "NAME", "STATUS", "TIMING MARK", "RCTE", - "NAOL", "NAOP", "NAOCRD", "NAOHTS", - "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", - "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", - "DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION", - "TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING", - "TTYLOC", "3270 REGIME", "X3 PAD", "NAWS", - "TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC", - "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON" -}; - -#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON - -#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM) -#define CURL_TELOPT(x) telnetoptions[x] - -#define CURL_NTELOPTS 40 - -/* - * First some defines - */ -#define CURL_xEOF 236 /* End Of File */ -#define CURL_SE 240 /* Sub negotiation End */ -#define CURL_NOP 241 /* No OPeration */ -#define CURL_DM 242 /* Data Mark */ -#define CURL_GA 249 /* Go Ahead, reverse the line */ -#define CURL_SB 250 /* SuBnegotiation */ -#define CURL_WILL 251 /* Our side WILL use this option */ -#define CURL_WONT 252 /* Our side WON'T use this option */ -#define CURL_DO 253 /* DO use this option! */ -#define CURL_DONT 254 /* DON'T use this option! */ -#define CURL_IAC 255 /* Interpret As Command */ - -/* - * Then those numbers represented as strings: - */ -static const char * const telnetcmds[]= -{ - "EOF", "SUSP", "ABORT", "EOR", "SE", - "NOP", "DMARK", "BRK", "IP", "AO", - "AYT", "EC", "EL", "GA", "SB", - "WILL", "WONT", "DO", "DONT", "IAC" -}; - -#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */ -#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */ - -#define CURL_TELQUAL_IS 0 -#define CURL_TELQUAL_SEND 1 -#define CURL_TELQUAL_INFO 2 -#define CURL_TELQUAL_NAME 3 - -#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \ - ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) ) -#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM] - -#endif /* CURL_DISABLE_TELNET */ - -#endif /* HEADER_CURL_ARPA_TELNET_H */ diff --git a/dep/cpr/opt/curl/lib/asyn-ares.c b/dep/cpr/opt/curl/lib/asyn-ares.c deleted file mode 100644 index 87e70b4d912..00000000000 --- a/dep/cpr/opt/curl/lib/asyn-ares.c +++ /dev/null @@ -1,700 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -/*********************************************************************** - * Only for ares-enabled builds - * And only for functions that fulfill the asynch resolver backend API - * as defined in asyn.h, nothing else belongs in this file! - **********************************************************************/ - -#ifdef CURLRES_ARES - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "multiif.h" -#include "inet_pton.h" -#include "connect.h" -#include "select.h" -#include "progress.h" - -# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ - (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) -# define CARES_STATICLIB -# endif -# include -# include /* really old c-ares didn't include this by - itself */ - -#if ARES_VERSION >= 0x010500 -/* c-ares 1.5.0 or later, the callback proto is modified */ -#define HAVE_CARES_CALLBACK_TIMEOUTS 1 -#endif - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -struct ResolverResults { - int num_pending; /* number of ares_gethostbyname() requests */ - Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ - int last_status; -}; - -/* - * Curl_resolver_global_init() - the generic low-level asynchronous name - * resolve API. Called from curl_global_init() to initialize global resolver - * environment. Initializes ares library. - */ -int Curl_resolver_global_init(void) -{ -#ifdef CARES_HAVE_ARES_LIBRARY_INIT - if(ares_library_init(ARES_LIB_INIT_ALL)) { - return CURLE_FAILED_INIT; - } -#endif - return CURLE_OK; -} - -/* - * Curl_resolver_global_cleanup() - * - * Called from curl_global_cleanup() to destroy global resolver environment. - * Deinitializes ares library. - */ -void Curl_resolver_global_cleanup(void) -{ -#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP - ares_library_cleanup(); -#endif -} - -/* - * Curl_resolver_init() - * - * Called from curl_easy_init() -> Curl_open() to initialize resolver - * URL-state specific environment ('resolver' member of the UrlState - * structure). Fills the passed pointer by the initialized ares_channel. - */ -CURLcode Curl_resolver_init(void **resolver) -{ - int status = ares_init((ares_channel*)resolver); - if(status != ARES_SUCCESS) { - if(status == ARES_ENOMEM) - return CURLE_OUT_OF_MEMORY; - else - return CURLE_FAILED_INIT; - } - return CURLE_OK; - /* make sure that all other returns from this function should destroy the - ares channel before returning error! */ -} - -/* - * Curl_resolver_cleanup() - * - * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver - * URL-state specific environment ('resolver' member of the UrlState - * structure). Destroys the ares channel. - */ -void Curl_resolver_cleanup(void *resolver) -{ - ares_destroy((ares_channel)resolver); -} - -/* - * Curl_resolver_duphandle() - * - * Called from curl_easy_duphandle() to duplicate resolver URL-state specific - * environment ('resolver' member of the UrlState structure). Duplicates the - * 'from' ares channel and passes the resulting channel to the 'to' pointer. - */ -int Curl_resolver_duphandle(void **to, void *from) -{ - /* Clone the ares channel for the new handle */ - if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from)) - return CURLE_FAILED_INIT; - return CURLE_OK; -} - -static void destroy_async_data(struct Curl_async *async); - -/* - * Cancel all possibly still on-going resolves for this connection. - */ -void Curl_resolver_cancel(struct connectdata *conn) -{ - if(conn->data && conn->data->state.resolver) - ares_cancel((ares_channel)conn->data->state.resolver); - destroy_async_data(&conn->async); -} - -/* - * destroy_async_data() cleans up async resolver data. - */ -static void destroy_async_data(struct Curl_async *async) -{ - free(async->hostname); - - if(async->os_specific) { - struct ResolverResults *res = (struct ResolverResults *)async->os_specific; - if(res) { - if(res->temp_ai) { - Curl_freeaddrinfo(res->temp_ai); - res->temp_ai = NULL; - } - free(res); - } - async->os_specific = NULL; - } - - async->hostname = NULL; -} - -/* - * Curl_resolver_getsock() is called when someone from the outside world - * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking - * with ares. The caller must make sure that this function is only called when - * we have a working ares channel. - * - * Returns: sockets-in-use-bitmap - */ - -int Curl_resolver_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) - -{ - struct timeval maxtime; - struct timeval timebuf; - struct timeval *timeout; - long milli; - int max = ares_getsock((ares_channel)conn->data->state.resolver, - (ares_socket_t *)socks, numsocks); - - maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; - maxtime.tv_usec = 0; - - timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime, - &timebuf); - milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000); - if(milli == 0) - milli += 10; - Curl_expire(conn->data, milli, EXPIRE_ASYNC_NAME); - - return max; -} - -/* - * waitperform() - * - * 1) Ask ares what sockets it currently plays with, then - * 2) wait for the timeout period to check for action on ares' sockets. - * 3) tell ares to act on all the sockets marked as "with action" - * - * return number of sockets it worked on - */ - -static int waitperform(struct connectdata *conn, int timeout_ms) -{ - struct Curl_easy *data = conn->data; - int nfds; - int bitmask; - ares_socket_t socks[ARES_GETSOCK_MAXNUM]; - struct pollfd pfd[ARES_GETSOCK_MAXNUM]; - int i; - int num = 0; - - bitmask = ares_getsock((ares_channel)data->state.resolver, socks, - ARES_GETSOCK_MAXNUM); - - for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { - pfd[i].events = 0; - pfd[i].revents = 0; - if(ARES_GETSOCK_READABLE(bitmask, i)) { - pfd[i].fd = socks[i]; - pfd[i].events |= POLLRDNORM|POLLIN; - } - if(ARES_GETSOCK_WRITABLE(bitmask, i)) { - pfd[i].fd = socks[i]; - pfd[i].events |= POLLWRNORM|POLLOUT; - } - if(pfd[i].events != 0) - num++; - else - break; - } - - if(num) - nfds = Curl_poll(pfd, num, timeout_ms); - else - nfds = 0; - - if(!nfds) - /* Call ares_process() unconditonally here, even if we simply timed out - above, as otherwise the ares name resolve won't timeout! */ - ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD, - ARES_SOCKET_BAD); - else { - /* move through the descriptors and ask for processing on them */ - for(i = 0; i < num; i++) - ares_process_fd((ares_channel)data->state.resolver, - pfd[i].revents & (POLLRDNORM|POLLIN)? - pfd[i].fd:ARES_SOCKET_BAD, - pfd[i].revents & (POLLWRNORM|POLLOUT)? - pfd[i].fd:ARES_SOCKET_BAD); - } - return nfds; -} - -/* - * Curl_resolver_is_resolved() is called repeatedly to check if a previous - * name resolve request has completed. It should also make sure to time-out if - * the operation seems to take too long. - * - * Returns normal CURLcode errors. - */ -CURLcode Curl_resolver_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dns) -{ - struct Curl_easy *data = conn->data; - struct ResolverResults *res = (struct ResolverResults *) - conn->async.os_specific; - CURLcode result = CURLE_OK; - - *dns = NULL; - - waitperform(conn, 0); - - if(res && !res->num_pending) { - (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai); - /* temp_ai ownership is moved to the connection, so we need not free-up - them */ - res->temp_ai = NULL; - if(!conn->async.dns) { - failf(data, "Could not resolve: %s (%s)", - conn->async.hostname, ares_strerror(conn->async.status)); - result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: - CURLE_COULDNT_RESOLVE_HOST; - } - else - *dns = conn->async.dns; - - destroy_async_data(&conn->async); - } - - return result; -} - -/* - * Curl_resolver_wait_resolv() - * - * waits for a resolve to finish. This function should be avoided since using - * this risk getting the multi interface to "hang". - * - * If 'entry' is non-NULL, make it point to the resolved dns entry - * - * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and - * CURLE_OPERATION_TIMEDOUT if a time-out occurred. - */ -CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, - struct Curl_dns_entry **entry) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - long timeout; - struct curltime now = Curl_tvnow(); - struct Curl_dns_entry *temp_entry; - - if(entry) - *entry = NULL; /* clear on entry */ - - timeout = Curl_timeleft(data, &now, TRUE); - if(timeout < 0) { - /* already expired! */ - connclose(conn, "Timed out before name resolve started"); - return CURLE_OPERATION_TIMEDOUT; - } - if(!timeout) - timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ - - /* Wait for the name resolve query to complete. */ - while(!result) { - struct timeval *tvp, tv, store; - int itimeout; - int timeout_ms; - - itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout; - - store.tv_sec = itimeout/1000; - store.tv_usec = (itimeout%1000)*1000; - - tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv); - - /* use the timeout period ares returned to us above if less than one - second is left, otherwise just use 1000ms to make sure the progress - callback gets called frequent enough */ - if(!tvp->tv_sec) - timeout_ms = (int)(tvp->tv_usec/1000); - else - timeout_ms = 1000; - - waitperform(conn, timeout_ms); - result = Curl_resolver_is_resolved(conn, &temp_entry); - - if(result || conn->async.done) - break; - - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else { - struct curltime now2 = Curl_tvnow(); - time_t timediff = Curl_tvdiff(now2, now); /* spent time */ - if(timediff <= 0) - timeout -= 1; /* always deduct at least 1 */ - else if(timediff > timeout) - timeout = -1; - else - timeout -= (long)timediff; - now = now2; /* for next loop */ - } - if(timeout < 0) - result = CURLE_OPERATION_TIMEDOUT; - } - if(result) - /* failure, so we cancel the ares operation */ - ares_cancel((ares_channel)data->state.resolver); - - /* Operation complete, if the lookup was successful we now have the entry - in the cache. */ - if(entry) - *entry = conn->async.dns; - - if(result) - /* close the connection, since we can't return failure here without - cleaning up this connection properly. - TODO: remove this action from here, it is not a name resolver decision. - */ - connclose(conn, "c-ares resolve failed"); - - return result; -} - -/* Connects results to the list */ -static void compound_results(struct ResolverResults *res, - Curl_addrinfo *ai) -{ - Curl_addrinfo *ai_tail; - if(!ai) - return; - ai_tail = ai; - - while(ai_tail->ai_next) - ai_tail = ai_tail->ai_next; - - /* Add the new results to the list of old results. */ - ai_tail->ai_next = res->temp_ai; - res->temp_ai = ai; -} - -/* - * ares_query_completed_cb() is the callback that ares will call when - * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), - * when using ares, is completed either successfully or with failure. - */ -static void query_completed_cb(void *arg, /* (struct connectdata *) */ - int status, -#ifdef HAVE_CARES_CALLBACK_TIMEOUTS - int timeouts, -#endif - struct hostent *hostent) -{ - struct connectdata *conn = (struct connectdata *)arg; - struct ResolverResults *res; - -#ifdef HAVE_CARES_CALLBACK_TIMEOUTS - (void)timeouts; /* ignored */ -#endif - - if(ARES_EDESTRUCTION == status) - /* when this ares handle is getting destroyed, the 'arg' pointer may not - be valid so only defer it when we know the 'status' says its fine! */ - return; - - res = (struct ResolverResults *)conn->async.os_specific; - res->num_pending--; - - if(CURL_ASYNC_SUCCESS == status) { - Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port); - if(ai) { - compound_results(res, ai); - } - } - /* A successful result overwrites any previous error */ - if(res->last_status != ARES_SUCCESS) - res->last_status = status; -} - -/* - * Curl_resolver_getaddrinfo() - when using ares - * - * Returns name information about the given hostname and port number. If - * successful, the 'hostent' is returned and the forth argument will point to - * memory we need to free after use. That memory *MUST* be freed with - * Curl_freeaddrinfo(), nothing else. - */ -Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - char *bufp; - struct Curl_easy *data = conn->data; - struct in_addr in; - int family = PF_INET; -#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ - struct in6_addr in6; -#endif /* CURLRES_IPV6 */ - - *waitp = 0; /* default to synchronous response */ - - /* First check if this is an IPv4 address string */ - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) { - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - } - -#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ - /* Otherwise, check if this is an IPv6 address string */ - if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) - /* This must be an IPv6 address literal. */ - return Curl_ip2addr(AF_INET6, &in6, hostname, port); - - switch(conn->ip_version) { - default: -#if ARES_VERSION >= 0x010601 - family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older - c-ares versions this just falls through and defaults - to PF_INET */ - break; -#endif - case CURL_IPRESOLVE_V4: - family = PF_INET; - break; - case CURL_IPRESOLVE_V6: - family = PF_INET6; - break; - } -#endif /* CURLRES_IPV6 */ - - bufp = strdup(hostname); - if(bufp) { - struct ResolverResults *res = NULL; - free(conn->async.hostname); - conn->async.hostname = bufp; - conn->async.port = port; - conn->async.done = FALSE; /* not done */ - conn->async.status = 0; /* clear */ - conn->async.dns = NULL; /* clear */ - res = calloc(sizeof(struct ResolverResults), 1); - if(!res) { - free(conn->async.hostname); - conn->async.hostname = NULL; - return NULL; - } - conn->async.os_specific = res; - - /* initial status - failed */ - res->last_status = ARES_ENOTFOUND; -#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ - if(family == PF_UNSPEC) { - if(Curl_ipv6works()) { - res->num_pending = 2; - - /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname((ares_channel)data->state.resolver, hostname, - PF_INET, query_completed_cb, conn); - ares_gethostbyname((ares_channel)data->state.resolver, hostname, - PF_INET6, query_completed_cb, conn); - } - else { - res->num_pending = 1; - - /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname((ares_channel)data->state.resolver, hostname, - PF_INET, query_completed_cb, conn); - } - } - else -#endif /* CURLRES_IPV6 */ - { - res->num_pending = 1; - - /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname((ares_channel)data->state.resolver, hostname, family, - query_completed_cb, conn); - } - - *waitp = 1; /* expect asynchronous response */ - } - return NULL; /* no struct yet */ -} - -CURLcode Curl_set_dns_servers(struct Curl_easy *data, - char *servers) -{ - CURLcode result = CURLE_NOT_BUILT_IN; - int ares_result; - - /* If server is NULL or empty, this would purge all DNS servers - * from ares library, which will cause any and all queries to fail. - * So, just return OK if none are configured and don't actually make - * any changes to c-ares. This lets c-ares use it's defaults, which - * it gets from the OS (for instance from /etc/resolv.conf on Linux). - */ - if(!(servers && servers[0])) - return CURLE_OK; - -#if (ARES_VERSION >= 0x010704) - ares_result = ares_set_servers_csv(data->state.resolver, servers); - switch(ares_result) { - case ARES_SUCCESS: - result = CURLE_OK; - break; - case ARES_ENOMEM: - result = CURLE_OUT_OF_MEMORY; - break; - case ARES_ENOTINITIALIZED: - case ARES_ENODATA: - case ARES_EBADSTR: - default: - result = CURLE_BAD_FUNCTION_ARGUMENT; - break; - } -#else /* too old c-ares version! */ - (void)data; - (void)(ares_result); -#endif - return result; -} - -CURLcode Curl_set_dns_interface(struct Curl_easy *data, - const char *interf) -{ -#if (ARES_VERSION >= 0x010704) - if(!interf) - interf = ""; - - ares_set_local_dev((ares_channel)data->state.resolver, interf); - - return CURLE_OK; -#else /* c-ares version too old! */ - (void)data; - (void)interf; - return CURLE_NOT_BUILT_IN; -#endif -} - -CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, - const char *local_ip4) -{ -#if (ARES_VERSION >= 0x010704) - struct in_addr a4; - - if((!local_ip4) || (local_ip4[0] == 0)) { - a4.s_addr = 0; /* disabled: do not bind to a specific address */ - } - else { - if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) { - return CURLE_BAD_FUNCTION_ARGUMENT; - } - } - - ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr)); - - return CURLE_OK; -#else /* c-ares version too old! */ - (void)data; - (void)local_ip4; - return CURLE_NOT_BUILT_IN; -#endif -} - -CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, - const char *local_ip6) -{ -#if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6) - unsigned char a6[INET6_ADDRSTRLEN]; - - if((!local_ip6) || (local_ip6[0] == 0)) { - /* disabled: do not bind to a specific address */ - memset(a6, 0, sizeof(a6)); - } - else { - if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) { - return CURLE_BAD_FUNCTION_ARGUMENT; - } - } - - ares_set_local_ip6((ares_channel)data->state.resolver, a6); - - return CURLE_OK; -#else /* c-ares version too old! */ - (void)data; - (void)local_ip6; - return CURLE_NOT_BUILT_IN; -#endif -} -#endif /* CURLRES_ARES */ diff --git a/dep/cpr/opt/curl/lib/asyn-thread.c b/dep/cpr/opt/curl/lib/asyn-thread.c deleted file mode 100644 index a8677296539..00000000000 --- a/dep/cpr/opt/curl/lib/asyn-thread.c +++ /dev/null @@ -1,718 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -/*********************************************************************** - * Only for threaded name resolves builds - **********************************************************************/ -#ifdef CURLRES_THREADED - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#if defined(USE_THREADS_POSIX) -# ifdef HAVE_PTHREAD_H -# include -# endif -#elif defined(USE_THREADS_WIN32) -# ifdef HAVE_PROCESS_H -# include -# endif -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#ifdef HAVE_GETADDRINFO -# define RESOLVER_ENOMEM EAI_MEMORY -#else -# define RESOLVER_ENOMEM ENOMEM -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "multiif.h" -#include "inet_pton.h" -#include "inet_ntop.h" -#include "curl_threads.h" -#include "connect.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_resolver_global_init() - * Called from curl_global_init() to initialize global resolver environment. - * Does nothing here. - */ -int Curl_resolver_global_init(void) -{ - return CURLE_OK; -} - -/* - * Curl_resolver_global_cleanup() - * Called from curl_global_cleanup() to destroy global resolver environment. - * Does nothing here. - */ -void Curl_resolver_global_cleanup(void) -{ -} - -/* - * Curl_resolver_init() - * Called from curl_easy_init() -> Curl_open() to initialize resolver - * URL-state specific environment ('resolver' member of the UrlState - * structure). Does nothing here. - */ -CURLcode Curl_resolver_init(void **resolver) -{ - (void)resolver; - return CURLE_OK; -} - -/* - * Curl_resolver_cleanup() - * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver - * URL-state specific environment ('resolver' member of the UrlState - * structure). Does nothing here. - */ -void Curl_resolver_cleanup(void *resolver) -{ - (void)resolver; -} - -/* - * Curl_resolver_duphandle() - * Called from curl_easy_duphandle() to duplicate resolver URL state-specific - * environment ('resolver' member of the UrlState structure). Does nothing - * here. - */ -int Curl_resolver_duphandle(void **to, void *from) -{ - (void)to; - (void)from; - return CURLE_OK; -} - -static void destroy_async_data(struct Curl_async *); - -/* - * Cancel all possibly still on-going resolves for this connection. - */ -void Curl_resolver_cancel(struct connectdata *conn) -{ - destroy_async_data(&conn->async); -} - -/* This function is used to init a threaded resolve */ -static bool init_resolve_thread(struct connectdata *conn, - const char *hostname, int port, - const struct addrinfo *hints); - - -/* Data for synchronization between resolver thread and its parent */ -struct thread_sync_data { - curl_mutex_t * mtx; - int done; - - char *hostname; /* hostname to resolve, Curl_async.hostname - duplicate */ - int port; - int sock_error; - Curl_addrinfo *res; -#ifdef HAVE_GETADDRINFO - struct addrinfo hints; -#endif - struct thread_data *td; /* for thread-self cleanup */ -}; - -struct thread_data { - curl_thread_t thread_hnd; - unsigned int poll_interval; - time_t interval_end; - struct thread_sync_data tsd; -}; - -static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn) -{ - return &(((struct thread_data *)conn->async.os_specific)->tsd); -} - -#define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd); - -/* Destroy resolver thread synchronization data */ -static -void destroy_thread_sync_data(struct thread_sync_data * tsd) -{ - if(tsd->mtx) { - Curl_mutex_destroy(tsd->mtx); - free(tsd->mtx); - } - - free(tsd->hostname); - - if(tsd->res) - Curl_freeaddrinfo(tsd->res); - - memset(tsd, 0, sizeof(*tsd)); -} - -/* Initialize resolver thread synchronization data */ -static -int init_thread_sync_data(struct thread_data * td, - const char *hostname, - int port, - const struct addrinfo *hints) -{ - struct thread_sync_data *tsd = &td->tsd; - - memset(tsd, 0, sizeof(*tsd)); - - tsd->td = td; - tsd->port = port; - /* Treat the request as done until the thread actually starts so any early - * cleanup gets done properly. - */ - tsd->done = 1; -#ifdef HAVE_GETADDRINFO - DEBUGASSERT(hints); - tsd->hints = *hints; -#else - (void) hints; -#endif - - tsd->mtx = malloc(sizeof(curl_mutex_t)); - if(tsd->mtx == NULL) - goto err_exit; - - Curl_mutex_init(tsd->mtx); - - tsd->sock_error = CURL_ASYNC_SUCCESS; - - /* Copying hostname string because original can be destroyed by parent - * thread during gethostbyname execution. - */ - tsd->hostname = strdup(hostname); - if(!tsd->hostname) - goto err_exit; - - return 1; - - err_exit: - /* Memory allocation failed */ - destroy_thread_sync_data(tsd); - return 0; -} - -static int getaddrinfo_complete(struct connectdata *conn) -{ - struct thread_sync_data *tsd = conn_thread_sync_data(conn); - int rc; - - rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res); - /* The tsd->res structure has been copied to async.dns and perhaps the DNS - cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it. - */ - tsd->res = NULL; - - return rc; -} - - -#ifdef HAVE_GETADDRINFO - -/* - * getaddrinfo_thread() resolves a name and then exits. - * - * For builds without ARES, but with ENABLE_IPV6, create a resolver thread - * and wait on it. - */ -static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg) -{ - struct thread_sync_data *tsd = (struct thread_sync_data*)arg; - struct thread_data *td = tsd->td; - char service[12]; - int rc; - - snprintf(service, sizeof(service), "%d", tsd->port); - - rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res); - - if(rc != 0) { - tsd->sock_error = SOCKERRNO?SOCKERRNO:rc; - if(tsd->sock_error == 0) - tsd->sock_error = RESOLVER_ENOMEM; - } - else { - Curl_addrinfo_set_port(tsd->res, tsd->port); - } - - Curl_mutex_acquire(tsd->mtx); - if(tsd->done) { - /* too late, gotta clean up the mess */ - Curl_mutex_release(tsd->mtx); - destroy_thread_sync_data(tsd); - free(td); - } - else { - tsd->done = 1; - Curl_mutex_release(tsd->mtx); - } - - return 0; -} - -#else /* HAVE_GETADDRINFO */ - -/* - * gethostbyname_thread() resolves a name and then exits. - */ -static unsigned int CURL_STDCALL gethostbyname_thread(void *arg) -{ - struct thread_sync_data *tsd = (struct thread_sync_data *)arg; - struct thread_data *td = tsd->td; - - tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port); - - if(!tsd->res) { - tsd->sock_error = SOCKERRNO; - if(tsd->sock_error == 0) - tsd->sock_error = RESOLVER_ENOMEM; - } - - Curl_mutex_acquire(tsd->mtx); - if(tsd->done) { - /* too late, gotta clean up the mess */ - Curl_mutex_release(tsd->mtx); - destroy_thread_sync_data(tsd); - free(td); - } - else { - tsd->done = 1; - Curl_mutex_release(tsd->mtx); - } - - return 0; -} - -#endif /* HAVE_GETADDRINFO */ - -/* - * destroy_async_data() cleans up async resolver data and thread handle. - */ -static void destroy_async_data(struct Curl_async *async) -{ - if(async->os_specific) { - struct thread_data *td = (struct thread_data*) async->os_specific; - int done; - - /* - * if the thread is still blocking in the resolve syscall, detach it and - * let the thread do the cleanup... - */ - Curl_mutex_acquire(td->tsd.mtx); - done = td->tsd.done; - td->tsd.done = 1; - Curl_mutex_release(td->tsd.mtx); - - if(!done) { - Curl_thread_destroy(td->thread_hnd); - } - else { - if(td->thread_hnd != curl_thread_t_null) - Curl_thread_join(&td->thread_hnd); - - destroy_thread_sync_data(&td->tsd); - - free(async->os_specific); - } - } - async->os_specific = NULL; - - free(async->hostname); - async->hostname = NULL; -} - -/* - * init_resolve_thread() starts a new thread that performs the actual - * resolve. This function returns before the resolve is done. - * - * Returns FALSE in case of failure, otherwise TRUE. - */ -static bool init_resolve_thread(struct connectdata *conn, - const char *hostname, int port, - const struct addrinfo *hints) -{ - struct thread_data *td = calloc(1, sizeof(struct thread_data)); - int err = ENOMEM; - - conn->async.os_specific = (void *)td; - if(!td) - goto errno_exit; - - conn->async.port = port; - conn->async.done = FALSE; - conn->async.status = 0; - conn->async.dns = NULL; - td->thread_hnd = curl_thread_t_null; - - if(!init_thread_sync_data(td, hostname, port, hints)) { - conn->async.os_specific = NULL; - free(td); - goto errno_exit; - } - - free(conn->async.hostname); - conn->async.hostname = strdup(hostname); - if(!conn->async.hostname) - goto err_exit; - - /* The thread will set this to 1 when complete. */ - td->tsd.done = 0; - -#ifdef HAVE_GETADDRINFO - td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); -#else - td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd); -#endif - - if(!td->thread_hnd) { - /* The thread never started, so mark it as done here for proper cleanup. */ - td->tsd.done = 1; - err = errno; - goto err_exit; - } - - return TRUE; - - err_exit: - destroy_async_data(&conn->async); - - errno_exit: - errno = err; - return FALSE; -} - -/* - * resolver_error() calls failf() with the appropriate message after a resolve - * error - */ - -static CURLcode resolver_error(struct connectdata *conn) -{ - const char *host_or_proxy; - CURLcode result; - - if(conn->bits.httpproxy) { - host_or_proxy = "proxy"; - result = CURLE_COULDNT_RESOLVE_PROXY; - } - else { - host_or_proxy = "host"; - result = CURLE_COULDNT_RESOLVE_HOST; - } - - failf(conn->data, "Could not resolve %s: %s", host_or_proxy, - conn->async.hostname); - - return result; -} - -/* - * Curl_resolver_wait_resolv() - * - * waits for a resolve to finish. This function should be avoided since using - * this risk getting the multi interface to "hang". - * - * If 'entry' is non-NULL, make it point to the resolved dns entry - * - * This is the version for resolves-in-a-thread. - */ -CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, - struct Curl_dns_entry **entry) -{ - struct thread_data *td = (struct thread_data*) conn->async.os_specific; - CURLcode result = CURLE_OK; - - DEBUGASSERT(conn && td); - - /* wait for the thread to resolve the name */ - if(Curl_thread_join(&td->thread_hnd)) - result = getaddrinfo_complete(conn); - else - DEBUGASSERT(0); - - conn->async.done = TRUE; - - if(entry) - *entry = conn->async.dns; - - if(!conn->async.dns) - /* a name was not resolved, report error */ - result = resolver_error(conn); - - destroy_async_data(&conn->async); - - if(!conn->async.dns) - connclose(conn, "asynch resolve failed"); - - return result; -} - -/* - * Curl_resolver_is_resolved() is called repeatedly to check if a previous - * name resolve request has completed. It should also make sure to time-out if - * the operation seems to take too long. - */ -CURLcode Curl_resolver_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **entry) -{ - struct Curl_easy *data = conn->data; - struct thread_data *td = (struct thread_data*) conn->async.os_specific; - int done = 0; - - *entry = NULL; - - if(!td) { - DEBUGASSERT(td); - return CURLE_COULDNT_RESOLVE_HOST; - } - - Curl_mutex_acquire(td->tsd.mtx); - done = td->tsd.done; - Curl_mutex_release(td->tsd.mtx); - - if(done) { - getaddrinfo_complete(conn); - - if(!conn->async.dns) { - CURLcode result = resolver_error(conn); - destroy_async_data(&conn->async); - return result; - } - destroy_async_data(&conn->async); - *entry = conn->async.dns; - } - else { - /* poll for name lookup done with exponential backoff up to 250ms */ - time_t elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - if(elapsed < 0) - elapsed = 0; - - if(td->poll_interval == 0) - /* Start at 1ms poll interval */ - td->poll_interval = 1; - else if(elapsed >= td->interval_end) - /* Back-off exponentially if last interval expired */ - td->poll_interval *= 2; - - if(td->poll_interval > 250) - td->poll_interval = 250; - - td->interval_end = elapsed + td->poll_interval; - Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME); - } - - return CURLE_OK; -} - -int Curl_resolver_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - (void)conn; - (void)socks; - (void)numsocks; - return 0; -} - -#ifndef HAVE_GETADDRINFO -/* - * Curl_getaddrinfo() - for platforms without getaddrinfo - */ -Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - struct in_addr in; - - *waitp = 0; /* default to synchronous response */ - - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - - /* fire up a new resolver thread! */ - if(init_resolve_thread(conn, hostname, port, NULL)) { - *waitp = 1; /* expect asynchronous response */ - return NULL; - } - - /* fall-back to blocking version */ - return Curl_ipv4_resolve_r(hostname, port); -} - -#else /* !HAVE_GETADDRINFO */ - -/* - * Curl_resolver_getaddrinfo() - for getaddrinfo - */ -Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - struct addrinfo hints; - Curl_addrinfo *res; - int error; - char sbuf[12]; - int pf = PF_INET; - - *waitp = 0; /* default to synchronous response */ - -#ifndef USE_RESOLVE_ON_IPS - { - struct in_addr in; - /* First check if this is an IPv4 address string */ - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - } -#ifdef CURLRES_IPV6 - { - struct in6_addr in6; - /* check if this is an IPv6 address string */ - if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) - /* This is an IPv6 address literal */ - return Curl_ip2addr(AF_INET6, &in6, hostname, port); - } -#endif /* CURLRES_IPV6 */ -#endif /* !USE_RESOLVE_ON_IPS */ - -#ifdef CURLRES_IPV6 - /* - * Check if a limited name resolve has been requested. - */ - switch(conn->ip_version) { - case CURL_IPRESOLVE_V4: - pf = PF_INET; - break; - case CURL_IPRESOLVE_V6: - pf = PF_INET6; - break; - default: - pf = PF_UNSPEC; - break; - } - - if((pf != PF_INET) && !Curl_ipv6works()) - /* The stack seems to be a non-IPv6 one */ - pf = PF_INET; -#endif /* CURLRES_IPV6 */ - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = pf; - hints.ai_socktype = conn->socktype; - - snprintf(sbuf, sizeof(sbuf), "%d", port); - - /* fire up a new resolver thread! */ - if(init_resolve_thread(conn, hostname, port, &hints)) { - *waitp = 1; /* expect asynchronous response */ - return NULL; - } - - /* fall-back to blocking version */ - infof(conn->data, "init_resolve_thread() failed for %s; %s\n", - hostname, Curl_strerror(conn, errno)); - - error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res); - if(error) { - infof(conn->data, "getaddrinfo() failed for %s:%d; %s\n", - hostname, port, Curl_strerror(conn, SOCKERRNO)); - return NULL; - } - else { - Curl_addrinfo_set_port(res, port); - } - - return res; -} - -#endif /* !HAVE_GETADDRINFO */ - -CURLcode Curl_set_dns_servers(struct Curl_easy *data, - char *servers) -{ - (void)data; - (void)servers; - return CURLE_NOT_BUILT_IN; - -} - -CURLcode Curl_set_dns_interface(struct Curl_easy *data, - const char *interf) -{ - (void)data; - (void)interf; - return CURLE_NOT_BUILT_IN; -} - -CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, - const char *local_ip4) -{ - (void)data; - (void)local_ip4; - return CURLE_NOT_BUILT_IN; -} - -CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, - const char *local_ip6) -{ - (void)data; - (void)local_ip6; - return CURLE_NOT_BUILT_IN; -} - -#endif /* CURLRES_THREADED */ diff --git a/dep/cpr/opt/curl/lib/asyn.h b/dep/cpr/opt/curl/lib/asyn.h deleted file mode 100644 index 3adc3664a29..00000000000 --- a/dep/cpr/opt/curl/lib/asyn.h +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef HEADER_CURL_ASYN_H -#define HEADER_CURL_ASYN_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" -#include "curl_addrinfo.h" - -struct addrinfo; -struct hostent; -struct Curl_easy; -struct connectdata; -struct Curl_dns_entry; - -/* - * This header defines all functions in the internal asynch resolver interface. - * All asynch resolvers need to provide these functions. - * asyn-ares.c and asyn-thread.c are the current implementations of asynch - * resolver backends. - */ - -/* - * Curl_resolver_global_init() - * - * Called from curl_global_init() to initialize global resolver environment. - * Returning anything else than CURLE_OK fails curl_global_init(). - */ -int Curl_resolver_global_init(void); - -/* - * Curl_resolver_global_cleanup() - * Called from curl_global_cleanup() to destroy global resolver environment. - */ -void Curl_resolver_global_cleanup(void); - -/* - * Curl_resolver_init() - * Called from curl_easy_init() -> Curl_open() to initialize resolver - * URL-state specific environment ('resolver' member of the UrlState - * structure). Should fill the passed pointer by the initialized handler. - * Returning anything else than CURLE_OK fails curl_easy_init() with the - * correspondent code. - */ -CURLcode Curl_resolver_init(void **resolver); - -/* - * Curl_resolver_cleanup() - * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver - * URL-state specific environment ('resolver' member of the UrlState - * structure). Should destroy the handler and free all resources connected to - * it. - */ -void Curl_resolver_cleanup(void *resolver); - -/* - * Curl_resolver_duphandle() - * Called from curl_easy_duphandle() to duplicate resolver URL-state specific - * environment ('resolver' member of the UrlState structure). Should - * duplicate the 'from' handle and pass the resulting handle to the 'to' - * pointer. Returning anything else than CURLE_OK causes failed - * curl_easy_duphandle() call. - */ -int Curl_resolver_duphandle(void **to, void *from); - -/* - * Curl_resolver_cancel(). - * - * It is called from inside other functions to cancel currently performing - * resolver request. Should also free any temporary resources allocated to - * perform a request. - */ -void Curl_resolver_cancel(struct connectdata *conn); - -/* Curl_resolver_getsock() - * - * This function is called from the multi_getsock() function. 'sock' is a - * pointer to an array to hold the file descriptors, with 'numsock' being the - * size of that array (in number of entries). This function is supposed to - * return bitmask indicating what file descriptors (referring to array indexes - * in the 'sock' array) to wait for, read/write. - */ -int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock, - int numsocks); - -/* - * Curl_resolver_is_resolved() - * - * Called repeatedly to check if a previous name resolve request has - * completed. It should also make sure to time-out if the operation seems to - * take too long. - * - * Returns normal CURLcode errors. - */ -CURLcode Curl_resolver_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dns); - -/* - * Curl_resolver_wait_resolv() - * - * waits for a resolve to finish. This function should be avoided since using - * this risk getting the multi interface to "hang". - * - * If 'entry' is non-NULL, make it point to the resolved dns entry - * - * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and - * CURLE_OPERATION_TIMEDOUT if a time-out occurred. - - */ -CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, - struct Curl_dns_entry **dnsentry); - -/* - * Curl_resolver_getaddrinfo() - when using this resolver - * - * Returns name information about the given hostname and port number. If - * successful, the 'hostent' is returned and the forth argument will point to - * memory we need to free after use. That memory *MUST* be freed with - * Curl_freeaddrinfo(), nothing else. - * - * Each resolver backend must of course make sure to return data in the - * correct format to comply with this. - */ -Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp); - -#ifndef CURLRES_ASYNCH -/* convert these functions if an asynch resolver isn't used */ -#define Curl_resolver_cancel(x) Curl_nop_stmt -#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST -#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST -#define Curl_resolver_getsock(x,y,z) 0 -#define Curl_resolver_duphandle(x,y) CURLE_OK -#define Curl_resolver_init(x) CURLE_OK -#define Curl_resolver_global_init() CURLE_OK -#define Curl_resolver_global_cleanup() Curl_nop_stmt -#define Curl_resolver_cleanup(x) Curl_nop_stmt -#endif - -#ifdef CURLRES_ASYNCH -#define Curl_resolver_asynch() 1 -#else -#define Curl_resolver_asynch() 0 -#endif - - -/********** end of generic resolver interface functions *****************/ -#endif /* HEADER_CURL_ASYN_H */ diff --git a/dep/cpr/opt/curl/lib/base64.c b/dep/cpr/opt/curl/lib/base64.c deleted file mode 100644 index 204a2273d19..00000000000 --- a/dep/cpr/opt/curl/lib/base64.c +++ /dev/null @@ -1,320 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* Base64 encoding/decoding */ - -#include "curl_setup.h" -#include "urldata.h" /* for the Curl_easy definition */ -#include "warnless.h" -#include "curl_base64.h" -#include "non-ascii.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* ---- Base64 Encoding/Decoding Table --- */ -static const char base64[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648 - section 5 */ -static const char base64url[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; - -static size_t decodeQuantum(unsigned char *dest, const char *src) -{ - size_t padding = 0; - const char *s, *p; - unsigned long i, x = 0; - - for(i = 0, s = src; i < 4; i++, s++) { - unsigned long v = 0; - - if(*s == '=') { - x = (x << 6); - padding++; - } - else { - p = base64; - - while(*p && (*p != *s)) { - v++; - p++; - } - - if(*p == *s) - x = (x << 6) + v; - else - return 0; - } - } - - if(padding < 1) - dest[2] = curlx_ultouc(x & 0xFFUL); - - x >>= 8; - if(padding < 2) - dest[1] = curlx_ultouc(x & 0xFFUL); - - x >>= 8; - dest[0] = curlx_ultouc(x & 0xFFUL); - - return 3 - padding; -} - -/* - * Curl_base64_decode() - * - * Given a base64 NUL-terminated string at src, decode it and return a - * pointer in *outptr to a newly allocated memory area holding decoded - * data. Size of decoded data is returned in variable pointed by outlen. - * - * Returns CURLE_OK on success, otherwise specific error code. Function - * output shall not be considered valid unless CURLE_OK is returned. - * - * When decoded data length is 0, returns NULL in *outptr. - * - * @unittest: 1302 - */ -CURLcode Curl_base64_decode(const char *src, - unsigned char **outptr, size_t *outlen) -{ - size_t srclen = 0; - size_t length = 0; - size_t padding = 0; - size_t i; - size_t numQuantums; - size_t rawlen = 0; - unsigned char *pos; - unsigned char *newstr; - - *outptr = NULL; - *outlen = 0; - srclen = strlen(src); - - /* Check the length of the input string is valid */ - if(!srclen || srclen % 4) - return CURLE_BAD_CONTENT_ENCODING; - - /* Find the position of any = padding characters */ - while((src[length] != '=') && src[length]) - length++; - - /* A maximum of two = padding characters is allowed */ - if(src[length] == '=') { - padding++; - if(src[length + 1] == '=') - padding++; - } - - /* Check the = padding characters weren't part way through the input */ - if(length + padding != srclen) - return CURLE_BAD_CONTENT_ENCODING; - - /* Calculate the number of quantums */ - numQuantums = srclen / 4; - - /* Calculate the size of the decoded string */ - rawlen = (numQuantums * 3) - padding; - - /* Allocate our buffer including room for a zero terminator */ - newstr = malloc(rawlen + 1); - if(!newstr) - return CURLE_OUT_OF_MEMORY; - - pos = newstr; - - /* Decode the quantums */ - for(i = 0; i < numQuantums; i++) { - size_t result = decodeQuantum(pos, src); - if(!result) { - free(newstr); - - return CURLE_BAD_CONTENT_ENCODING; - } - - pos += result; - src += 4; - } - - /* Zero terminate */ - *pos = '\0'; - - /* Return the decoded data */ - *outptr = newstr; - *outlen = rawlen; - - return CURLE_OK; -} - -static CURLcode base64_encode(const char *table64, - struct Curl_easy *data, - const char *inputbuff, size_t insize, - char **outptr, size_t *outlen) -{ - CURLcode result; - unsigned char ibuf[3]; - unsigned char obuf[4]; - int i; - int inputparts; - char *output; - char *base64data; - char *convbuf = NULL; - - const char *indata = inputbuff; - - *outptr = NULL; - *outlen = 0; - - if(!insize) - insize = strlen(indata); - -#if SIZEOF_SIZE_T == 4 - if(insize > UINT_MAX/4) - return CURLE_OUT_OF_MEMORY; -#endif - - base64data = output = malloc(insize * 4 / 3 + 4); - if(!output) - return CURLE_OUT_OF_MEMORY; - - /* - * The base64 data needs to be created using the network encoding - * not the host encoding. And we can't change the actual input - * so we copy it to a buffer, translate it, and use that instead. - */ - result = Curl_convert_clone(data, indata, insize, &convbuf); - if(result) { - free(output); - return result; - } - - if(convbuf) - indata = (char *)convbuf; - - while(insize > 0) { - for(i = inputparts = 0; i < 3; i++) { - if(insize > 0) { - inputparts++; - ibuf[i] = (unsigned char) *indata; - indata++; - insize--; - } - else - ibuf[i] = 0; - } - - obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); - obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ - ((ibuf[1] & 0xF0) >> 4)); - obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ - ((ibuf[2] & 0xC0) >> 6)); - obuf[3] = (unsigned char) (ibuf[2] & 0x3F); - - switch(inputparts) { - case 1: /* only one byte read */ - snprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); - break; - - case 2: /* two bytes read */ - snprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); - break; - - default: - snprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]]); - break; - } - output += 4; - } - - /* Zero terminate */ - *output = '\0'; - - /* Return the pointer to the new data (allocated memory) */ - *outptr = base64data; - - free(convbuf); - - /* Return the length of the new data */ - *outlen = strlen(base64data); - - return CURLE_OK; -} - -/* - * Curl_base64_encode() - * - * Given a pointer to an input buffer and an input size, encode it and - * return a pointer in *outptr to a newly allocated memory area holding - * encoded data. Size of encoded data is returned in variable pointed by - * outlen. - * - * Input length of 0 indicates input buffer holds a NUL-terminated string. - * - * Returns CURLE_OK on success, otherwise specific error code. Function - * output shall not be considered valid unless CURLE_OK is returned. - * - * When encoded data length is 0, returns NULL in *outptr. - * - * @unittest: 1302 - */ -CURLcode Curl_base64_encode(struct Curl_easy *data, - const char *inputbuff, size_t insize, - char **outptr, size_t *outlen) -{ - return base64_encode(base64, data, inputbuff, insize, outptr, outlen); -} - -/* - * Curl_base64url_encode() - * - * Given a pointer to an input buffer and an input size, encode it and - * return a pointer in *outptr to a newly allocated memory area holding - * encoded data. Size of encoded data is returned in variable pointed by - * outlen. - * - * Input length of 0 indicates input buffer holds a NUL-terminated string. - * - * Returns CURLE_OK on success, otherwise specific error code. Function - * output shall not be considered valid unless CURLE_OK is returned. - * - * When encoded data length is 0, returns NULL in *outptr. - * - * @unittest: 1302 - */ -CURLcode Curl_base64url_encode(struct Curl_easy *data, - const char *inputbuff, size_t insize, - char **outptr, size_t *outlen) -{ - return base64_encode(base64url, data, inputbuff, insize, outptr, outlen); -} diff --git a/dep/cpr/opt/curl/lib/checksrc.pl b/dep/cpr/opt/curl/lib/checksrc.pl deleted file mode 100644 index c1f74bebf32..00000000000 --- a/dep/cpr/opt/curl/lib/checksrc.pl +++ /dev/null @@ -1,605 +0,0 @@ -#!/usr/bin/perl -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2011 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### - -my $max_column = 79; -my $indent = 2; - -my $warnings; -my $errors; -my $supressed; # whitelisted problems -my $file; -my $dir="."; -my $wlist; -my $windows_os = $^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin'; -my $verbose; -my %whitelist; - -my %warnings = ( - 'LONGLINE' => "Line longer than $max_column", - 'TABS' => 'TAB characters not allowed', - 'TRAILINGSPACE' => 'Trailing white space on the line', - 'CPPCOMMENTS' => '// comment detected', - 'SPACEBEFOREPAREN' => 'space before an open parenthesis', - 'SPACEAFTERPAREN' => 'space after open parenthesis', - 'SPACEBEFORECLOSE' => 'space before a close parenthesis', - 'SPACEBEFORECOMMA' => 'space before a comma', - 'RETURNNOSPACE' => 'return without space', - 'COMMANOSPACE' => 'comma without following space', - 'BRACEELSE' => '} else on the same line', - 'PARENBRACE' => '){ without sufficient space', - 'SPACESEMILCOLON' => 'space before semicolon', - 'BANNEDFUNC' => 'a banned function was used', - 'FOPENMODE' => 'fopen needs a macro for the mode string', - 'BRACEPOS' => 'wrong position for an open brace', - 'INDENTATION' => 'wrong start column for code', - 'COPYRIGHT' => 'file missing a copyright statement', - 'BADCOMMAND' => 'bad !checksrc! instruction', - 'UNUSEDIGNORE' => 'a warning ignore was not used', - 'OPENCOMMENT' => 'file ended with a /* comment still "open"', - 'ASTERISKSPACE' => 'pointer declared with space after asterisk', - 'ASTERISKNOSPACE' => 'pointer declared without space before asterisk', - 'ASSIGNWITHINCONDITION' => 'assignment within conditional expression', - 'EQUALSNOSPACE' => 'equals sign without following space', - 'NOSPACEEQUALS' => 'equals sign without preceeding space', - 'SEMINOSPACE' => 'semicolon without following space', - 'MULTISPACE' => 'multiple spaces used when not suitable', - ); - -sub readwhitelist { - open(W, "<$dir/checksrc.whitelist"); - my @all=; - for(@all) { - $windows_os ? $_ =~ s/\r?\n$// : chomp; - $whitelist{$_}=1; - } - close(W); -} - -sub checkwarn { - my ($name, $num, $col, $file, $line, $msg, $error) = @_; - - my $w=$error?"error":"warning"; - my $nowarn=0; - - #if(!$warnings{$name}) { - # print STDERR "Dev! there's no description for $name!\n"; - #} - - # checksrc.whitelist - if($whitelist{$line}) { - $nowarn = 1; - } - # !checksrc! controlled - elsif($ignore{$name}) { - $ignore{$name}--; - $ignore_used{$name}++; - $nowarn = 1; - if(!$ignore{$name}) { - # reached zero, enable again - enable_warn($name, $line, $file, $l); - } - } - - if($nowarn) { - $supressed++; - if($w) { - $swarnings++; - } - else { - $serrors++; - } - return; - } - - if($w) { - $warnings++; - } - else { - $errors++; - } - - $col++; - print "$file:$num:$col: $w: $msg ($name)\n"; - print " $line\n"; - - if($col < 80) { - my $pref = (' ' x $col); - print "${pref}^\n"; - } -} - -$file = shift @ARGV; - -while(1) { - - if($file =~ /-D(.*)/) { - $dir = $1; - $file = shift @ARGV; - next; - } - elsif($file =~ /-W(.*)/) { - $wlist .= " $1 "; - $file = shift @ARGV; - next; - } - elsif($file =~ /^(-h|--help)/) { - undef $file; - last; - } - - last; -} - -if(!$file) { - print "checksrc.pl [option] [file2] ...\n"; - print " Options:\n"; - print " -D[DIR] Directory to prepend file names\n"; - print " -h Show help output\n"; - print " -W[file] Whitelist the given file - ignore all its flaws\n"; - print "\nDetects and warns for these problems:\n"; - for(sort keys %warnings) { - printf (" %-18s: %s\n", $_, $warnings{$_}); - } - exit; -} - -readwhitelist(); - -do { - if("$wlist" !~ / $file /) { - my $fullname = $file; - $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/'); - scanfile($fullname); - } - $file = shift @ARGV; - -} while($file); - -sub checksrc_clear { - undef %ignore; - undef %ignore_set; - undef @ignore_line; -} - -sub checksrc_endoffile { - my ($file) = @_; - for(keys %ignore_set) { - if($ignore_set{$_} && !$ignore_used{$_}) { - checkwarn("UNUSEDIGNORE", $ignore_set{$_}, - length($_)+11, $file, - $ignore_line[$ignore_set{$_}], - "Unused ignore: $_"); - } - } -} - -sub enable_warn { - my ($what, $line, $file, $l) = @_; - - # switch it back on, but warn if not triggered! - if(!$ignore_used{$what}) { - checkwarn("UNUSEDIGNORE", - $line, length($what) + 11, $file, $l, - "No warning was inhibited!"); - } - $ignore_set{$what}=0; - $ignore_used{$what}=0; - $ignore{$what}=0; -} -sub checksrc { - my ($cmd, $line, $file, $l) = @_; - if($cmd =~ / *([^ ]*) *(.*)/) { - my ($enable, $what) = ($1, $2); - $what =~ s: *\*/$::; # cut off end of C comment - # print "ENABLE $enable WHAT $what\n"; - if($enable eq "disable") { - my ($warn, $scope)=($1, $2); - if($what =~ /([^ ]*) +(.*)/) { - ($warn, $scope)=($1, $2); - } - else { - $warn = $what; - $scope = 1; - } - # print "IGNORE $warn for SCOPE $scope\n"; - if($scope eq "all") { - $scope=999999; - } - - if($ignore_set{$warn}) { - checkwarn("BADCOMMAND", - $line, 0, $file, $l, - "$warn already disabled from line $ignore_set{$warn}"); - } - else { - $ignore{$warn}=$scope; - $ignore_set{$warn}=$line; - $ignore_line[$line]=$l; - } - } - elsif($enable eq "enable") { - enable_warn($what, $line, $file, $l); - } - else { - checkwarn("BADCOMMAND", - $line, 0, $file, $l, - "Illegal !checksrc! command"); - } - } -} - -sub nostrings { - my ($str) = @_; - $str =~ s/\".*\"//g; - return $str; -} - -sub scanfile { - my ($file) = @_; - - my $line = 1; - my $prevl; - my $l; - open(R, "<$file") || die "failed to open $file"; - - my $incomment=0; - my $copyright=0; - checksrc_clear(); # for file based ignores - - while() { - $windows_os ? $_ =~ s/\r?\n$// : chomp; - my $l = $_; - my $ol = $l; # keep the unmodified line for error reporting - my $column = 0; - - # check for !checksrc! commands - if($l =~ /\!checksrc\! (.*)/) { - my $cmd = $1; - checksrc($cmd, $line, $file, $l) - } - - # check for a copyright statement - if(!$copyright && ($l =~ /copyright .* \d\d\d\d/i)) { - $copyright=1; - } - - # detect long lines - if(length($l) > $max_column) { - checkwarn("LONGLINE", $line, length($l), $file, $l, - "Longer than $max_column columns"); - } - # detect TAB characters - if($l =~ /^(.*)\t/) { - checkwarn("TABS", - $line, length($1), $file, $l, "Contains TAB character", 1); - } - # detect trailing white space - if($l =~ /^(.*)[ \t]+\z/) { - checkwarn("TRAILINGSPACE", - $line, length($1), $file, $l, "Trailing whitespace"); - } - - # ------------------------------------------------------------ - # Above this marker, the checks were done on lines *including* - # comments - # ------------------------------------------------------------ - - # strip off C89 comments - - comment: - if(!$incomment) { - if($l =~ s/\/\*.*\*\// /g) { - # full /* comments */ were removed! - } - if($l =~ s/\/\*.*//) { - # start of /* comment was removed - $incomment = 1; - } - } - else { - if($l =~ s/.*\*\///) { - # end of comment */ was removed - $incomment = 0; - goto comment; - } - else { - # still within a comment - $l=""; - } - } - - # ------------------------------------------------------------ - # Below this marker, the checks were done on lines *without* - # comments - # ------------------------------------------------------------ - - # crude attempt to detect // comments without too many false - # positives - if($l =~ /^([^"\*]*)[^:"]\/\//) { - checkwarn("CPPCOMMENTS", - $line, length($1), $file, $l, "\/\/ comment"); - } - - my $nostr = nostrings($l); - # check spaces after for/if/while/function call - if($nostr =~ /^(.*)(for|if|while| ([a-zA-Z0-9_]+)) \((.)/) { - if($1 =~ / *\#/) { - # this is a #if, treat it differently - } - elsif($3 eq "return") { - # return must have a space - } - elsif($3 eq "case") { - # case must have a space - } - elsif($4 eq "*") { - # (* beginning makes the space OK! - } - elsif($1 =~ / *typedef/) { - # typedefs can use space-paren - } - else { - checkwarn("SPACEBEFOREPAREN", $line, length($1)+length($2), $file, $l, - "$2 with space"); - } - } - - if($nostr =~ /^((.*)(if) *\()(.*)\)/) { - my $pos = length($1); - if($4 =~ / = /) { - checkwarn("ASSIGNWITHINCONDITION", - $line, $pos+1, $file, $l, - "assignment within conditional expression"); - } - } - # check spaces after open parentheses - if($l =~ /^(.*[a-z])\( /i) { - checkwarn("SPACEAFTERPAREN", - $line, length($1)+1, $file, $l, - "space after open parenthesis"); - } - - # check spaces before close parentheses, unless it was a space or a - # close parenthesis! - if($l =~ /(.*[^\) ]) \)/) { - checkwarn("SPACEBEFORECLOSE", - $line, length($1)+1, $file, $l, - "space before close parenthesis"); - } - - # check spaces before comma! - if($l =~ /(.*[^ ]) ,/) { - checkwarn("SPACEBEFORECOMMA", - $line, length($1)+1, $file, $l, - "space before comma"); - } - - # check for "return(" without space - if($l =~ /^(.*)return\(/) { - if($1 =~ / *\#/) { - # this is a #if, treat it differently - } - else { - checkwarn("RETURNNOSPACE", $line, length($1)+6, $file, $l, - "return without space before paren"); - } - } - - # check for comma without space - if($l =~ /^(.*),[^ \n]/) { - my $pref=$1; - my $ign=0; - if($pref =~ / *\#/) { - # this is a #if, treat it differently - $ign=1; - } - elsif($pref =~ /\/\*/) { - # this is a comment - $ign=1; - } - elsif($pref =~ /[\"\']/) { - $ign = 1; - # There is a quote here, figure out whether the comma is - # within a string or '' or not. - if($pref =~ /\"/) { - # withing a string - } - elsif($pref =~ /\'$/) { - # a single letter - } - else { - $ign = 0; - } - } - if(!$ign) { - checkwarn("COMMANOSPACE", $line, length($pref)+1, $file, $l, - "comma without following space"); - } - } - - # check for "} else" - if($l =~ /^(.*)\} *else/) { - checkwarn("BRACEELSE", - $line, length($1), $file, $l, "else after closing brace on same line"); - } - # check for "){" - if($l =~ /^(.*)\)\{/) { - checkwarn("PARENBRACE", - $line, length($1)+1, $file, $l, "missing space after close paren"); - } - - # check for space before the semicolon last in a line - if($l =~ /^(.*[^ ].*) ;$/) { - checkwarn("SPACESEMILCOLON", - $line, length($1), $file, $ol, "space before last semicolon"); - } - - # scan for use of banned functions - if($l =~ /^(.*\W) - (gets| - strtok| - v?sprintf| - (str|_mbs|_tcs|_wcs)n?cat| - LoadLibrary(Ex)?(A|W)?) - \s*\( - /x) { - checkwarn("BANNEDFUNC", - $line, length($1), $file, $ol, - "use of $2 is banned"); - } - - # scan for use of non-binary fopen without the macro - if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) { - my $mode = $2; - if($mode !~ /b/) { - checkwarn("FOPENMODE", - $line, length($1), $file, $ol, - "use of non-binary fopen without FOPEN_* macro: $mode"); - } - } - - # check for open brace first on line but not first column - # only alert if previous line ended with a close paren and wasn't a cpp - # line - if((($prevl =~ /\)\z/) && ($prevl !~ /^ *#/)) && ($l =~ /^( +)\{/)) { - checkwarn("BRACEPOS", - $line, length($1), $file, $ol, "badly placed open brace"); - } - - # if the previous line starts with if/while/for AND ends with an open - # brace, check that this line is indented $indent more steps, if not - # a cpp line - if($prevl =~ /^( *)(if|while|for)\(.*\{\z/) { - my $first = length($1); - - # this line has some character besides spaces - if(($l !~ /^ *#/) && ($l =~ /^( *)[^ ]/)) { - my $second = length($1); - my $expect = $first+$indent; - if($expect != $second) { - my $diff = $second - $first; - checkwarn("INDENTATION", $line, length($1), $file, $ol, - "not indented $indent steps, uses $diff)"); - - } - } - } - - # check for 'char * name' - if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost) *(\*+)) (\w+)/) && ($4 ne "const")) { - checkwarn("ASTERISKNOSPACE", - $line, length($1), $file, $ol, - "no space after declarative asterisk"); - } - # check for 'char*' - if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost|sockaddr_in|FILE)\*)/)) { - checkwarn("ASTERISKNOSPACE", - $line, length($1)-1, $file, $ol, - "no space before asterisk"); - } - - # check for 'void func() {', but avoid false positives by requiring - # both an open and closed parentheses before the open brace - if($l =~ /^((\w).*)\{\z/) { - my $k = $1; - $k =~ s/const *//; - $k =~ s/static *//; - if($k =~ /\(.*\)/) { - checkwarn("BRACEPOS", - $line, length($l)-1, $file, $ol, - "wrongly placed open brace"); - } - } - - # check for equals sign without spaces next to it - if($nostr =~ /(.*)\=[a-z0-9]/i) { - checkwarn("EQUALSNOSPACE", - $line, length($1)+1, $file, $ol, - "no space after equals sign"); - } - # check for equals sign without spaces before it - elsif($nostr =~ /(.*)[a-z0-9]\=/i) { - checkwarn("NOSPACEEQUALS", - $line, length($1)+1, $file, $ol, - "no space before equals sign"); - } - - # check for plus signs without spaces next to it - if($nostr =~ /(.*)[^+]\+[a-z0-9]/i) { - checkwarn("PLUSNOSPACE", - $line, length($1)+1, $file, $ol, - "no space after plus sign"); - } - # check for plus sign without spaces before it - elsif($nostr =~ /(.*)[a-z0-9]\+[^+]/i) { - checkwarn("NOSPACEPLUS", - $line, length($1)+1, $file, $ol, - "no space before plus sign"); - } - - # check for semicolons without space next to it - if($nostr =~ /(.*)\;[a-z0-9]/i) { - checkwarn("SEMINOSPACE", - $line, length($1)+1, $file, $ol, - "no space after semilcolon"); - } - - # check for more than one consecutive space before open brace or - # question mark. Skip lines containing strings since they make it hard - # due to artificially getting multiple spaces - if(($l eq $nostr) && - $nostr =~ /^(.*(\S)) + [{?]/i) { - checkwarn("MULTISPACE", - $line, length($1)+1, $file, $ol, - "multiple space"); - print STDERR "L: $l\n"; - print STDERR "nostr: $nostr\n"; - } - - $line++; - $prevl = $ol; - } - - if(!$copyright) { - checkwarn("COPYRIGHT", 1, 0, $file, "", "Missing copyright statement", 1); - } - if($incomment) { - checkwarn("OPENCOMMENT", 1, 0, $file, "", "Missing closing comment", 1); - } - - checksrc_endoffile($file); - - close(R); - -} - - -if($errors || $warnings || $verbose) { - printf "checksrc: %d errors and %d warnings\n", $errors, $warnings; - if($supressed) { - printf "checksrc: %d errors and %d warnings suppressed\n", - $serrors, - $swarnings; - } - exit 5; # return failure -} diff --git a/dep/cpr/opt/curl/lib/config-amigaos.h b/dep/cpr/opt/curl/lib/config-amigaos.h deleted file mode 100644 index 31cfc3afc21..00000000000 --- a/dep/cpr/opt/curl/lib/config-amigaos.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_AMIGAOS_H -#define HEADER_CURL_CONFIG_AMIGAOS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* ================================================================ */ -/* Hand crafted config file for AmigaOS */ -/* ================================================================ */ - -#ifdef __AMIGA__ /* Any AmigaOS flavour */ - -#define HAVE_ARPA_INET_H 1 -#define HAVE_CLOSESOCKET_CAMEL 1 -#define HAVE_ERRNO_H 1 -#define HAVE_GETHOSTBYADDR 1 -#define HAVE_INET_ADDR 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_IOCTLSOCKET_CAMEL 1 -#define HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1 -#define HAVE_LIBCRYPTO 1 -#define HAVE_LIBSSL 1 -#define HAVE_LIBZ 1 -#define HAVE_LONGLONG 1 -#define HAVE_MALLOC_H 1 -#define HAVE_MEMORY_H 1 -#define HAVE_NETDB_H 1 -#define HAVE_NETINET_IN_H 1 -#define HAVE_NET_IF_H 1 -#define HAVE_OPENSSL_CRYPTO_H 1 -#define HAVE_OPENSSL_ERR_H 1 -#define HAVE_OPENSSL_PEM_H 1 -#define HAVE_OPENSSL_RSA_H 1 -#define HAVE_OPENSSL_SSL_H 1 -#define HAVE_OPENSSL_X509_H 1 -#define HAVE_PERROR 1 -#define HAVE_PWD_H 1 -#define HAVE_RAND_EGD 1 -#define HAVE_RAND_STATUS 1 -#define HAVE_SELECT 1 -#define HAVE_SETJMP_H 1 -#define HAVE_SGTTY_H 1 -#define HAVE_SIGNAL 1 -#define HAVE_SIGNAL_H 1 -#define HAVE_SIG_ATOMIC_T 1 -#define HAVE_SOCKET 1 -#define HAVE_STRCASECMP 1 -#define HAVE_STRDUP 1 -#define HAVE_STRFTIME 1 -#define HAVE_STRICMP 1 -#define HAVE_STRINGS_H 1 -#define HAVE_STRING_H 1 -#define HAVE_STRSTR 1 -#define HAVE_STRUCT_TIMEVAL 1 -#define HAVE_SYS_PARAM_H 1 -#define HAVE_SYS_SOCKET_H 1 -#define HAVE_SYS_SOCKIO_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_SYS_TIME_H 1 -#define HAVE_SYS_TYPES_H 1 -#define HAVE_TIME_H 1 -#define HAVE_UNAME 1 -#define HAVE_UNISTD_H 1 -#define HAVE_UTIME 1 -#define HAVE_UTIME_H 1 -#define HAVE_WRITABLE_ARGV 1 -#define HAVE_ZLIB_H 1 -#define HAVE_SYS_IOCTL_H 1 - -#define NEED_MALLOC_H 1 - -#define SIZEOF_INT 4 -#define SIZEOF_SHORT 2 -#define SIZEOF_SIZE_T 4 - -#define USE_MANUAL 1 -#define USE_OPENSSL 1 -#define CURL_DISABLE_LDAP 1 - -#define OS "AmigaOS" - -#define PACKAGE "curl" -#define PACKAGE_BUGREPORT "a suitable mailing list: https://curl.haxx.se/mail/" -#define PACKAGE_NAME "curl" -#define PACKAGE_STRING "curl -" -#define PACKAGE_TARNAME "curl" -#define PACKAGE_VERSION "-" -#define CURL_CA_BUNDLE "s:curl-ca-bundle.crt" - -#define RETSIGTYPE void -#define SELECT_TYPE_ARG1 int -#define SELECT_TYPE_ARG234 (fd_set *) -#define SELECT_TYPE_ARG5 (struct timeval *) - -#define STDC_HEADERS 1 -#define TIME_WITH_SYS_TIME 1 - -#define in_addr_t int - -#ifndef F_OK -# define F_OK 0 -#endif - -#ifndef O_RDONLY -# define O_RDONLY 0x0000 -#endif - -#ifndef LONG_MAX -# define LONG_MAX 0x7fffffffL -#endif - -#ifndef LONG_MIN -# define LONG_MIN (-0x7fffffffL-1) -#endif - -#define HAVE_GETNAMEINFO 1 -#define GETNAMEINFO_QUAL_ARG1 const -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * -#define GETNAMEINFO_TYPE_ARG2 int -#define GETNAMEINFO_TYPE_ARG46 size_t -#define GETNAMEINFO_TYPE_ARG7 int - -#define HAVE_RECV 1 -#define RECV_TYPE_ARG1 long -#define RECV_TYPE_ARG2 char * -#define RECV_TYPE_ARG3 long -#define RECV_TYPE_ARG4 long -#define RECV_TYPE_RETV long - -#define HAVE_RECVFROM 1 -#define RECVFROM_TYPE_ARG1 long -#define RECVFROM_TYPE_ARG2 char -#define RECVFROM_TYPE_ARG3 long -#define RECVFROM_TYPE_ARG4 long -#define RECVFROM_TYPE_ARG5 struct sockaddr -#define RECVFROM_TYPE_ARG6 long -#define RECVFROM_TYPE_RETV long - -#define HAVE_SEND 1 -#define SEND_TYPE_ARG1 int -#define SEND_QUAL_ARG2 const -#define SEND_TYPE_ARG2 char * -#define SEND_TYPE_ARG3 int -#define SEND_TYPE_ARG4 int -#define SEND_TYPE_RETV int - -#endif /* __AMIGA__ */ -#endif /* HEADER_CURL_CONFIG_AMIGAOS_H */ diff --git a/dep/cpr/opt/curl/lib/config-dos.h b/dep/cpr/opt/curl/lib/config-dos.h deleted file mode 100644 index eec7af98881..00000000000 --- a/dep/cpr/opt/curl/lib/config-dos.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_DOS_H -#define HEADER_CURL_CONFIG_DOS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - - -/* ================================================================ */ -/* lib/config-dos.h - Hand crafted config file for DOS */ -/* ================================================================ */ - -#if defined(DJGPP) - #define OS "MSDOS/djgpp" -#elif defined(__HIGHC__) - #define OS "MSDOS/HighC" -#elif defined(__WATCOMC__) - #define OS "MSDOS/Watcom" -#else - #define OS "MSDOS/?" -#endif - -#define PACKAGE "curl" - -#define HAVE_ARPA_INET_H 1 -#define HAVE_ASSERT_H 1 -#define HAVE_ERRNO_H 1 -#define HAVE_FCNTL_H 1 -#define HAVE_FREEADDRINFO 1 -#define HAVE_GETADDRINFO 1 -#define HAVE_GETNAMEINFO 1 -#define HAVE_GETPROTOBYNAME 1 -#define HAVE_GETTIMEOFDAY 1 -#define HAVE_IO_H 1 -#define HAVE_IOCTL 1 -#define HAVE_IOCTL_FIONBIO 1 -#define HAVE_IOCTLSOCKET 1 -#define HAVE_IOCTLSOCKET_FIONBIO 1 -#define HAVE_LIMITS_H 1 -#define HAVE_LOCALE_H 1 -#define HAVE_LONGLONG 1 -#define HAVE_MEMORY_H 1 -#define HAVE_NETDB_H 1 -#define HAVE_NETINET_IN_H 1 -#define HAVE_NETINET_TCP_H 1 -#define HAVE_NET_IF_H 1 -#define HAVE_PROCESS_H 1 -#define HAVE_RECV 1 -#define HAVE_RECVFROM 1 -#define HAVE_SELECT 1 -#define HAVE_SEND 1 -#define HAVE_SETJMP_H 1 -#define HAVE_SETLOCALE 1 -#define HAVE_SETMODE 1 -#define HAVE_SIGNAL 1 -#define HAVE_SOCKET 1 -#define HAVE_STRDUP 1 -#define HAVE_STRICMP 1 -#define HAVE_STRTOLL 1 -#define HAVE_STRUCT_TIMEVAL 1 -#define HAVE_STRUCT_IN6_ADDR 1 -#define HAVE_SYS_IOCTL_H 1 -#define HAVE_SYS_SOCKET_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_SYS_TYPES_H 1 -#define HAVE_TIME_H 1 -#define HAVE_UNISTD_H 1 - -#define NEED_MALLOC_H 1 - -#define RETSIGTYPE void -#define SIZEOF_INT 4 -#define SIZEOF_LONG 4 -#define SIZEOF_LONG_DOUBLE 16 -#define SIZEOF_SHORT 2 -#define SIZEOF_SIZE_T 4 -#define SIZEOF_CURL_OFF_T 4 -#define STDC_HEADERS 1 -#define TIME_WITH_SYS_TIME 1 - -/* Qualifiers for send(), recv(), recvfrom() and getnameinfo(). */ - -#define SEND_TYPE_ARG1 int -#define SEND_QUAL_ARG2 const -#define SEND_TYPE_ARG2 void * -#define SEND_TYPE_ARG3 int -#define SEND_TYPE_ARG4 int -#define SEND_TYPE_RETV int - -#define RECV_TYPE_ARG1 int -#define RECV_TYPE_ARG2 void * -#define RECV_TYPE_ARG3 int -#define RECV_TYPE_ARG4 int -#define RECV_TYPE_RETV int - -#define RECVFROM_TYPE_ARG1 int -#define RECVFROM_TYPE_ARG2 void -#define RECVFROM_TYPE_ARG3 int -#define RECVFROM_TYPE_ARG4 int -#define RECVFROM_TYPE_ARG5 struct sockaddr -#define RECVFROM_TYPE_ARG6 int -#define RECVFROM_TYPE_RETV int -#define RECVFROM_TYPE_ARG2_IS_VOID 1 - -#define GETNAMEINFO_QUAL_ARG1 const -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * -#define GETNAMEINFO_TYPE_ARG2 int -#define GETNAMEINFO_TYPE_ARG46 int -#define GETNAMEINFO_TYPE_ARG7 int - -#define BSD - -/* CURLDEBUG definition enables memory tracking */ -/* #define CURLDEBUG */ - -/* USE_ZLIB on cmd-line */ -#ifdef USE_ZLIB - #define HAVE_ZLIB_H 1 - #define HAVE_LIBZ 1 -#endif - -/* USE_OPENSSL on cmd-line */ -#ifdef USE_OPENSSL - #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 - #define HAVE_OPENSSL_ENGINE_H 1 - #define OPENSSL_NO_KRB5 1 -#endif - -/* to disable LDAP */ -#define CURL_DISABLE_LDAP 1 - -#define in_addr_t u_long - -#if defined(__HIGHC__) || \ - (defined(__GNUC__) && (__GNUC__ < 4)) - #define ssize_t int -#endif - -#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") - -/* Target HAVE_x section */ - -#if defined(DJGPP) - #define HAVE_BASENAME 1 - #define HAVE_STRCASECMP 1 - #define HAVE_SIGACTION 1 - #define HAVE_SIGSETJMP 1 - #define HAVE_SYS_TIME_H 1 - #define HAVE_TERMIOS_H 1 - #define HAVE_VARIADIC_MACROS_GCC 1 - -#elif defined(__WATCOMC__) - #define HAVE_STRCASECMP 1 - -#elif defined(__HIGHC__) - #define HAVE_SYS_TIME_H 1 - #define strerror(e) strerror_s_((e)) -#endif - -#ifdef MSDOS /* Watt-32 */ - #define HAVE_CLOSE_S 1 -#endif - -#undef word -#undef byte - -#endif /* HEADER_CURL_CONFIG_DOS_H */ - diff --git a/dep/cpr/opt/curl/lib/config-mac.h b/dep/cpr/opt/curl/lib/config-mac.h deleted file mode 100644 index 3c12bdfacca..00000000000 --- a/dep/cpr/opt/curl/lib/config-mac.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_MAC_H -#define HEADER_CURL_CONFIG_MAC_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* =================================================================== */ -/* Hand crafted config file for Mac OS 9 */ -/* =================================================================== */ -/* On Mac OS X you must run configure to generate curl_config.h file */ -/* =================================================================== */ - -#define OS "mac" - -/* Define if you want the built-in manual */ -#define USE_MANUAL 1 - -#define HAVE_ERRNO_H 1 -#define HAVE_NETINET_IN_H 1 -#define HAVE_SYS_SOCKET_H 1 -#define HAVE_SYS_SELECT_H 1 -#define HAVE_NETDB_H 1 -#define HAVE_ARPA_INET_H 1 -#define HAVE_UNISTD_H 1 -#define HAVE_NET_IF_H 1 -#define HAVE_SYS_TYPES_H 1 -#define HAVE_GETTIMEOFDAY 1 -#define HAVE_FCNTL_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_ALLOCA_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_TIME_H 1 -#define HAVE_UTIME_H 1 -#define HAVE_SYS_TIME_H 1 -#define HAVE_SYS_UTIME_H 1 - -#define TIME_WITH_SYS_TIME 1 - -#define HAVE_ALARM 1 -#define HAVE_FTRUNCATE 1 -#define HAVE_UTIME 1 -#define HAVE_SETVBUF 1 -#define HAVE_STRFTIME 1 -#define HAVE_INET_ADDR 1 -#define HAVE_MEMCPY 1 -#define HAVE_SELECT 1 -#define HAVE_SOCKET 1 -#define HAVE_STRUCT_TIMEVAL 1 - -#define HAVE_SIGACTION 1 -#define HAVE_SIGNAL_H 1 -#define HAVE_SIG_ATOMIC_T 1 - -#ifdef MACOS_SSL_SUPPORT -# define USE_OPENSSL 1 -#endif - -#define CURL_DISABLE_LDAP 1 - -#define HAVE_RAND_STATUS 1 -#define HAVE_RAND_EGD 1 - -#define HAVE_IOCTL 1 -#define HAVE_IOCTL_FIONBIO 1 - -#define RETSIGTYPE void - -#define SIZEOF_INT 4 -#define SIZEOF_SHORT 2 -#define SIZEOF_SIZE_T 4 - -#define HAVE_GETNAMEINFO 1 -#define GETNAMEINFO_QUAL_ARG1 const -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * -#define GETNAMEINFO_TYPE_ARG2 socklen_t -#define GETNAMEINFO_TYPE_ARG46 size_t -#define GETNAMEINFO_TYPE_ARG7 int - -#define HAVE_RECV 1 -#define RECV_TYPE_ARG1 int -#define RECV_TYPE_ARG2 void * -#define RECV_TYPE_ARG3 size_t -#define RECV_TYPE_ARG4 int -#define RECV_TYPE_RETV ssize_t - -#define HAVE_RECVFROM 1 -#define RECVFROM_TYPE_ARG1 int -#define RECVFROM_TYPE_ARG2 void -#define RECVFROM_TYPE_ARG3 size_t -#define RECVFROM_TYPE_ARG4 int -#define RECVFROM_TYPE_ARG5 struct sockaddr -#define RECVFROM_TYPE_ARG6 int -#define RECVFROM_TYPE_RETV ssize_t -#define RECVFROM_TYPE_ARG2_IS_VOID 1 - -#define HAVE_SEND 1 -#define SEND_TYPE_ARG1 int -#define SEND_QUAL_ARG2 const -#define SEND_TYPE_ARG2 void * -#define SEND_TYPE_ARG3 size_T -#define SEND_TYPE_ARG4 int -#define SEND_TYPE_RETV ssize_t - -#define HAVE_EXTRA_STRICMP_H 1 -#define HAVE_EXTRA_STRDUP_H 1 - -#endif /* HEADER_CURL_CONFIG_MAC_H */ diff --git a/dep/cpr/opt/curl/lib/config-os400.h b/dep/cpr/opt/curl/lib/config-os400.h deleted file mode 100644 index fe5b864d649..00000000000 --- a/dep/cpr/opt/curl/lib/config-os400.h +++ /dev/null @@ -1,563 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_OS400_H -#define HEADER_CURL_CONFIG_OS400_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* ================================================================ */ -/* Hand crafted config file for OS/400 */ -/* ================================================================ */ - -#pragma enum(int) - -#undef PACKAGE - -/* Version number of this archive. */ -#undef VERSION - -/* Define if you have the getpass function. */ -#undef HAVE_GETPASS - -/* Define cpu-machine-OS */ -#define OS "OS/400" - -/* Define if you have the gethostbyaddr_r() function with 5 arguments */ -#define HAVE_GETHOSTBYADDR_R_5 - -/* Define if you have the gethostbyaddr_r() function with 7 arguments */ -#undef HAVE_GETHOSTBYADDR_R_7 - -/* Define if you have the gethostbyaddr_r() function with 8 arguments */ -#undef HAVE_GETHOSTBYADDR_R_8 - -/* OS400 supports a 3-argument ASCII version of gethostbyaddr_r(), but its - * prototype is incompatible with the "standard" one (1st argument is not - * const). However, getaddrinfo() is supported (ASCII version defined as - * a local wrapper in setup-os400.h) in a threadsafe way: we can then - * configure getaddrinfo() as such and get rid of gethostbyname_r() without - * loss of threadsafeness. */ -#undef HAVE_GETHOSTBYNAME_R -#undef HAVE_GETHOSTBYNAME_R_3 -#undef HAVE_GETHOSTBYNAME_R_5 -#undef HAVE_GETHOSTBYNAME_R_6 -#define HAVE_GETADDRINFO -#define HAVE_GETADDRINFO_THREADSAFE - -/* Define if you need the _REENTRANT define for some functions */ -#undef NEED_REENTRANT - -/* Define if you have the Kerberos4 libraries (including -ldes) */ -#undef HAVE_KRB4 - -/* Define if you want to enable IPv6 support */ -#define ENABLE_IPV6 - -/* Define if struct sockaddr_in6 has the sin6_scope_id member */ -#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 - -/* Define this to 'int' if ssize_t is not an available typedefed type */ -#undef ssize_t - -/* Define this as a suitable file to read random data from */ -#undef RANDOM_FILE - -/* Define this to your Entropy Gathering Daemon socket pathname */ -#undef EGD_SOCKET - -/* Define to 1 if you have the alarm function. */ -#define HAVE_ALARM 1 - -/* Define if you have the header file. */ -#undef HAVE_ALLOCA_H - -/* Define if you have the header file. */ -#define HAVE_ARPA_INET_H - -/* Define if you have the `closesocket' function. */ -#undef HAVE_CLOSESOCKET - -/* Define if you have the header file. */ -#undef HAVE_CRYPTO_H - -/* Define if you have the header file. */ -#undef HAVE_DES_H - -/* Define if you have the header file. */ -#define HAVE_ERRNO_H - -/* Define if you have the header file. */ -#undef HAVE_ERR_H - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H - -/* Define if you have the `geteuid' function. */ -#define HAVE_GETEUID - -/* Define if you have the `gethostbyaddr' function. */ -#define HAVE_GETHOSTBYADDR - -/* Define if you have the `gethostbyaddr_r' function. */ -#define HAVE_GETHOSTBYADDR_R - -/* Define if you have the `gethostname' function. */ -#define HAVE_GETHOSTNAME - -/* Define if you have the header file. */ -#undef HAVE_GETOPT_H - -/* Define if you have the `getpass_r' function. */ -#undef HAVE_GETPASS_R - -/* Define if you have the `getpwuid' function. */ -#define HAVE_GETPWUID - -/* Define if you have the `getservbyname' function. */ -#define HAVE_GETSERVBYNAME - -/* Define if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY - -/* Define if you have the `timeval' struct. */ -#define HAVE_STRUCT_TIMEVAL - -/* Define if you have the `inet_addr' function. */ -#define HAVE_INET_ADDR - -/* Define if you have the header file. */ -#define HAVE_INTTYPES_H - -/* Define if you have the header file. */ -#undef HAVE_IO_H - -/* Define if you have the `krb_get_our_ip_for_realm' function. */ -#undef HAVE_KRB_GET_OUR_IP_FOR_REALM - -/* Define if you have the header file. */ -#undef HAVE_KRB_H - -/* Define if you have the `crypto' library (-lcrypto). */ -#undef HAVE_LIBCRYPTO - -/* Define if you have the `nsl' library (-lnsl). */ -#undef HAVE_LIBNSL - -/* Define if you have the `resolv' library (-lresolv). */ -#undef HAVE_LIBRESOLV - -/* Define if you have the `resolve' library (-lresolve). */ -#undef HAVE_LIBRESOLVE - -/* Define if you have the `socket' library (-lsocket). */ -#undef HAVE_LIBSOCKET - -/* Define if you have the `ssl' library (-lssl). */ -#undef HAVE_LIBSSL - -/* Define if you have GSS API. */ -#define HAVE_GSSAPI - -/* Define if you have the GNU gssapi libraries */ -#undef HAVE_GSSGNU - -/* Define if you have the Heimdal gssapi libraries */ -#define HAVE_GSSHEIMDAL - -/* Define if you have the MIT gssapi libraries */ -#undef HAVE_GSSMIT - -/* Define if you have the `ucb' library (-lucb). */ -#undef HAVE_LIBUCB - -/* Define if you have the `localtime_r' function. */ -#define HAVE_LOCALTIME_R - -/* Define if you have the header file. */ -#define HAVE_MALLOC_H - -/* Define if you need the malloc.h header file even with stdlib.h */ -/* #define NEED_MALLOC_H 1 */ - -/* Define if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define if you have the header file. */ -#define HAVE_NETDB_H - -/* Define if you have the header file. */ -#undef HAVE_NETINET_IF_ETHER_H - -/* Define if you have the header file. */ -#define HAVE_NETINET_IN_H - -/* Define if you have the header file. */ -#define HAVE_NET_IF_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_CRYPTO_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_ERR_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_PEM_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_RSA_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_SSL_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_X509_H - -/* Define if you have the header file. */ -#undef HAVE_PEM_H - -/* Define if you have the `perror' function. */ -#define HAVE_PERROR - -/* Define if you have the header file. */ -#define HAVE_PWD_H - -/* Define if you have the `RAND_egd' function. */ -#undef HAVE_RAND_EGD - -/* Define if you have the `RAND_screen' function. */ -#undef HAVE_RAND_SCREEN - -/* Define if you have the `RAND_status' function. */ -#undef HAVE_RAND_STATUS - -/* Define if you have the header file. */ -#undef HAVE_RSA_H - -/* Define if you have the `select' function. */ -#define HAVE_SELECT - -/* Define if you have the `setvbuf' function. */ -#define HAVE_SETVBUF - -/* Define if you have the header file. */ -#undef HAVE_SGTTY_H - -/* Define if you have the `sigaction' function. */ -#define HAVE_SIGACTION - -/* Define if you have the `signal' function. */ -#undef HAVE_SIGNAL - -/* Define if you have the header file. */ -#define HAVE_SIGNAL_H - -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T - -/* Define if sig_atomic_t is already defined as volatile. */ -#undef HAVE_SIG_ATOMIC_T_VOLATILE - -/* Define if you have the `socket' function. */ -#define HAVE_SOCKET - -/* Define if you have the header file. */ -#undef HAVE_SSL_H - -/* Define if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define if you have the header file. */ -#define HAVE_STDLIB_H - - -/* The following define is needed on OS400 to enable strcmpi(), stricmp() and - strdup(). */ -#define __cplusplus__strings__ - -/* Define if you have the `strcasecmp' function. */ -#undef HAVE_STRCASECMP - -/* Define if you have the `strcmpi' function. */ -#define HAVE_STRCMPI - -/* Define if you have the `stricmp' function. */ -#define HAVE_STRICMP - -/* Define if you have the `strdup' function. */ -#define HAVE_STRDUP - - -/* Define if you have the `strftime' function. */ -#define HAVE_STRFTIME - -/* Define if you have the header file. */ -#define HAVE_STRINGS_H - -/* Define if you have the header file. */ -#define HAVE_STRING_H - -/* Define if you have the `strlcpy' function. */ -#undef HAVE_STRLCPY - -/* Define if you have the header file. */ -#undef HAVE_STROPTS_H - -/* Define if you have the `strstr' function. */ -#define HAVE_STRSTR - -/* Define if you have the `strtok_r' function. */ -#define HAVE_STRTOK_R - -/* Define if you have the `strtoll' function. */ -#undef HAVE_STRTOLL /* Allows ASCII compile on V5R1. */ - -/* Define if you have the header file. */ -#define HAVE_SYS_PARAM_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_SELECT_H - -/* Define if you have the header file. */ -#define HAVE_SYS_SOCKET_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_SOCKIO_H - -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H - -/* Define if you have the header file. */ -#define HAVE_SYS_TIME_H - -/* Define if you have the header file. */ -#define HAVE_SYS_TYPES_H - -/* Define if you have the header file. */ -#define HAVE_SYS_UN_H - -/* Define if you have the header file. */ -#define HAVE_SYS_IOCTL_H - -/* Define if you have the `tcgetattr' function. */ -#undef HAVE_TCGETATTR - -/* Define if you have the `tcsetattr' function. */ -#undef HAVE_TCSETATTR - -/* Define if you have the header file. */ -#undef HAVE_TERMIOS_H - -/* Define if you have the header file. */ -#undef HAVE_TERMIO_H - -/* Define if you have the header file. */ -#define HAVE_TIME_H - -/* Define if you have the `uname' function. */ -#undef HAVE_UNAME - -/* Define if you have the header file. */ -#define HAVE_UNISTD_H - -/* Define if you have the header file. */ -#undef HAVE_WINSOCK_H - -/* Define if you have the header file. */ -#undef HAVE_X509_H - -/* Name of package */ -#undef PACKAGE - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of a `long double', as computed by sizeof. */ -#define SIZEOF_LONG_DOUBLE 8 - -/* Define if the compiler supports the 'long long' data type. */ -#define HAVE_LONGLONG - -/* The size of a `long long', as computed by sizeof. */ -#define SIZEOF_LONG_LONG 8 - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* The size of `size_t', as computed by sizeof. */ -#define SIZEOF_SIZE_T 8 - -/* Whether long long constants must be suffixed by LL. */ - -#define HAVE_LL - -/* Define this if you have struct sockaddr_storage */ -#define HAVE_STRUCT_SOCKADDR_STORAGE - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS - -/* Define if you can safely include both and . */ -#define TIME_WITH_SYS_TIME - -/* Version number of package */ -#undef VERSION - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Define for large files, on AIX-style hosts. */ -#define _LARGE_FILES - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* type to use in place of in_addr_t if not defined */ -#define in_addr_t unsigned long - -/* Define to `unsigned' if does not define. */ -#undef size_t - -/* Define if you have the ioctl function. */ -#define HAVE_IOCTL - -/* Define if you have a working ioctl FIONBIO function. */ -#define HAVE_IOCTL_FIONBIO - -/* Define if you have a working ioctl SIOCGIFADDR function. */ -#define HAVE_IOCTL_SIOCGIFADDR - -/* To disable LDAP */ -#undef CURL_DISABLE_LDAP - -/* Definition to make a library symbol externally visible. */ -#define CURL_EXTERN_SYMBOL - -/* Define if you have the ldap_url_parse procedure. */ -/* #define HAVE_LDAP_URL_PARSE */ /* Disabled because of an IBM bug. */ - -/* Define if you have the getnameinfo function. */ -/* OS400 has no ASCII version of this procedure: wrapped in setup-os400.h. */ -#define HAVE_GETNAMEINFO - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -#define GETNAMEINFO_QUAL_ARG1 const - -/* Define to the type of arg 1 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * - -/* Define to the type of arg 2 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG2 socklen_t - -/* Define to the type of args 4 and 6 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG46 socklen_t - -/* Define to the type of arg 7 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG7 int - -/* Define if you have the recv function. */ -#define HAVE_RECV - -/* Define to the type of arg 1 for recv. */ -#define RECV_TYPE_ARG1 int - -/* Define to the type of arg 2 for recv. */ -#define RECV_TYPE_ARG2 char * - -/* Define to the type of arg 3 for recv. */ -#define RECV_TYPE_ARG3 int - -/* Define to the type of arg 4 for recv. */ -#define RECV_TYPE_ARG4 int - -/* Define to the function return type for recv. */ -#define RECV_TYPE_RETV int - -/* Define if you have the recvfrom function. */ -#define HAVE_RECVFROM - -/* Define to the type of arg 1 for recvfrom. */ -#define RECVFROM_TYPE_ARG1 int - -/* Define to the type pointed by arg 2 for recvfrom. */ -#define RECVFROM_TYPE_ARG2 char - -/* Define to the type of arg 3 for recvfrom. */ -#define RECVFROM_TYPE_ARG3 int - -/* Define to the type of arg 4 for recvfrom. */ -#define RECVFROM_TYPE_ARG4 int - -/* Define to the type pointed by arg 5 for recvfrom. */ -#define RECVFROM_TYPE_ARG5 struct sockaddr - -/* Define to the type pointed by arg 6 for recvfrom. */ -#define RECVFROM_TYPE_ARG6 int - -/* Define to the function return type for recvfrom. */ -#define RECVFROM_TYPE_RETV int - -/* Define if you have the send function. */ -#define HAVE_SEND - -/* Define to the type of arg 1 for send. */ -#define SEND_TYPE_ARG1 int - -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 - -/* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 char * - -/* Define to the type of arg 3 for send. */ -#define SEND_TYPE_ARG3 int - -/* Define to the type of arg 4 for send. */ -#define SEND_TYPE_ARG4 int - -/* Define to the function return type for send. */ -#define SEND_TYPE_RETV int - -/* Define to use the GSKit package. */ -#define USE_GSKIT - -/* Define to use the OS/400 crypto library. */ -#define USE_OS400CRYPTO - -/* Define to use Unix sockets. */ -#define USE_UNIX_SOCKETS - -/* Use the system keyring as the default CA bundle. */ -#define CURL_CA_BUNDLE "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB" - -/* ---------------------------------------------------------------- */ -/* ADDITIONAL DEFINITIONS */ -/* ---------------------------------------------------------------- */ - -/* The following must be defined BEFORE system header files inclusion. */ - -#define __ptr128 /* No teraspace. */ -#define qadrt_use_fputc_inline /* Generate fputc() wrapper inline. */ -#define qadrt_use_fread_inline /* Generate fread() wrapper inline. */ -#define qadrt_use_fwrite_inline /* Generate fwrite() wrapper inline. */ - -#endif /* HEADER_CURL_CONFIG_OS400_H */ diff --git a/dep/cpr/opt/curl/lib/config-riscos.h b/dep/cpr/opt/curl/lib/config-riscos.h deleted file mode 100644 index 0379524fb36..00000000000 --- a/dep/cpr/opt/curl/lib/config-riscos.h +++ /dev/null @@ -1,513 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_RISCOS_H -#define HEADER_CURL_CONFIG_RISCOS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* ================================================================ */ -/* Hand crafted config file for RISC OS */ -/* ================================================================ */ - -/* Name of this package! */ -#undef PACKAGE - -/* Version number of this archive. */ -#undef VERSION - -/* Define if you have the getpass function. */ -#undef HAVE_GETPASS - -/* Define cpu-machine-OS */ -#define OS "ARM-RISC OS" - -/* Define if you want the built-in manual */ -#define USE_MANUAL - -/* Define if you have the gethostbyaddr_r() function with 5 arguments */ -#undef HAVE_GETHOSTBYADDR_R_5 - -/* Define if you have the gethostbyaddr_r() function with 7 arguments */ -#undef HAVE_GETHOSTBYADDR_R_7 - -/* Define if you have the gethostbyaddr_r() function with 8 arguments */ -#undef HAVE_GETHOSTBYADDR_R_8 - -/* Define if you have the gethostbyname_r() function with 3 arguments */ -#undef HAVE_GETHOSTBYNAME_R_3 - -/* Define if you have the gethostbyname_r() function with 5 arguments */ -#undef HAVE_GETHOSTBYNAME_R_5 - -/* Define if you have the gethostbyname_r() function with 6 arguments */ -#undef HAVE_GETHOSTBYNAME_R_6 - -/* Define if you need the _REENTRANT define for some functions */ -#undef NEED_REENTRANT - -/* Define if you have the Kerberos4 libraries (including -ldes) */ -#undef HAVE_KRB4 - -/* Define if you want to enable IPv6 support */ -#undef ENABLE_IPV6 - -/* Define if struct sockaddr_in6 has the sin6_scope_id member */ -#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 - -/* Define this to 'int' if ssize_t is not an available typedefed type */ -#undef ssize_t - -/* Define this as a suitable file to read random data from */ -#undef RANDOM_FILE - -/* Define this to your Entropy Gathering Daemon socket pathname */ -#undef EGD_SOCKET - -/* Define if you want to enable IPv6 support */ -#undef ENABLE_IPV6 - -/* Define if you have the alarm function. */ -#define HAVE_ALARM - -/* Define if you have the header file. */ -#define HAVE_ALLOCA_H - -/* Define if you have the header file. */ -#define HAVE_ARPA_INET_H - -/* Define if you have the `closesocket' function. */ -#undef HAVE_CLOSESOCKET - -/* Define if you have the header file. */ -#undef HAVE_CRYPTO_H - -/* Define if you have the header file. */ -#undef HAVE_DES_H - -/* Define if you have the header file. */ -#define HAVE_ERRNO_H - -/* Define if you have the header file. */ -#undef HAVE_ERR_H - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H - -/* Define if you have the `ftruncate' function. */ -#define HAVE_FTRUNCATE - -/* Define if getaddrinfo exists and works */ -#define HAVE_GETADDRINFO - -/* Define if you have the `geteuid' function. */ -#undef HAVE_GETEUID - -/* Define if you have the `gethostbyaddr' function. */ -#define HAVE_GETHOSTBYADDR - -/* Define if you have the `gethostbyaddr_r' function. */ -#undef HAVE_GETHOSTBYADDR_R - -/* Define if you have the `gethostbyname_r' function. */ -#undef HAVE_GETHOSTBYNAME_R - -/* Define if you have the `gethostname' function. */ -#define HAVE_GETHOSTNAME - -/* Define if you have the header file. */ -#define HAVE_GETOPT_H - -/* Define if you have the `getpass_r' function. */ -#undef HAVE_GETPASS_R - -/* Define if you have the `getpwuid' function. */ -#undef HAVE_GETPWUID - -/* Define if you have the `getservbyname' function. */ -#undef HAVE_GETSERVBYNAME - -/* Define if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY - -/* Define if you have the `timeval' struct. */ -#define HAVE_STRUCT_TIMEVAL - -/* Define if you have the `inet_addr' function. */ -#undef HAVE_INET_ADDR - -/* Define if you have the header file. */ -#define HAVE_INTTYPES_H - -/* Define if you have the header file. */ -#undef HAVE_IO_H - -/* Define if you have the `krb_get_our_ip_for_realm' function. */ -#undef HAVE_KRB_GET_OUR_IP_FOR_REALM - -/* Define if you have the header file. */ -#undef HAVE_KRB_H - -/* Define if you have the `crypto' library (-lcrypto). */ -#undef HAVE_LIBCRYPTO - -/* Define if you have the `nsl' library (-lnsl). */ -#undef HAVE_LIBNSL - -/* Define if you have the `resolv' library (-lresolv). */ -#undef HAVE_LIBRESOLV - -/* Define if you have the `resolve' library (-lresolve). */ -#undef HAVE_LIBRESOLVE - -/* Define if you have the `socket' library (-lsocket). */ -#undef HAVE_LIBSOCKET - -/* Define if you have the `ssl' library (-lssl). */ -#undef HAVE_LIBSSL - -/* Define if you have the `ucb' library (-lucb). */ -#undef HAVE_LIBUCB - -/* Define if you have the `localtime_r' function. */ -#undef HAVE_LOCALTIME_R - -/* Define if you have the header file. */ -#define HAVE_MALLOC_H - -/* Define if you need the malloc.h header file even with stdlib.h */ -/* #define NEED_MALLOC_H 1 */ - -/* Define if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define if you have the header file. */ -#define HAVE_NETDB_H - -/* Define if you have the header file. */ -#undef HAVE_NETINET_IF_ETHER_H - -/* Define if you have the header file. */ -#define HAVE_NETINET_IN_H - -/* Define if you have the header file. */ -#define HAVE_NET_IF_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_CRYPTO_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_ERR_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_PEM_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_RSA_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_SSL_H - -/* Define if you have the header file. */ -#undef HAVE_OPENSSL_X509_H - -/* Define if you have the header file. */ -#undef HAVE_PEM_H - -/* Define if you have the `perror' function. */ -#undef HAVE_PERROR - -/* Define if you have the header file. */ -#undef HAVE_PWD_H - -/* Define if you have the `RAND_egd' function. */ -#undef HAVE_RAND_EGD - -/* Define if you have the `RAND_screen' function. */ -#undef HAVE_RAND_SCREEN - -/* Define if you have the `RAND_status' function. */ -#undef HAVE_RAND_STATUS - -/* Define if you have the header file. */ -#undef HAVE_RSA_H - -/* Define if you have the `select' function. */ -#define HAVE_SELECT - -/* Define if you have the `setvbuf' function. */ -#undef HAVE_SETVBUF - -/* Define if you have the header file. */ -#define HAVE_SGTTY_H - -/* Define if you have the `sigaction' function. */ -#undef HAVE_SIGACTION - -/* Define if you have the `signal' function. */ -#define HAVE_SIGNAL - -/* Define if you have the header file. */ -#define HAVE_SIGNAL_H - -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T - -/* Define if sig_atomic_t is already defined as volatile. */ -#undef HAVE_SIG_ATOMIC_T_VOLATILE - -/* Define if you have the `socket' function. */ -#define HAVE_SOCKET - -/* Define if you have the header file. */ -#undef HAVE_SSL_H - -/* Define if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define if you have the header file. */ -#define HAVE_STDLIB_H - -/* Define if you have the `strcasecmp' function. */ -#undef HAVE_STRCASECMP - -/* Define if you have the `strcmpi' function. */ -#undef HAVE_STRCMPI - -/* Define if you have the `strdup' function. */ -#define HAVE_STRDUP - -/* Define if you have the `strftime' function. */ -#define HAVE_STRFTIME - -/* Define if you have the `stricmp' function. */ -#define HAVE_STRICMP - -/* Define if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define if you have the header file. */ -#define HAVE_STRING_H - -/* Define if you have the `strlcpy' function. */ -#undef HAVE_STRLCPY - -/* Define if you have the `strstr' function. */ -#define HAVE_STRSTR - -/* Define if you have the `strtok_r' function. */ -#undef HAVE_STRTOK_R - -/* Define if you have the `strtoll' function. */ -#undef HAVE_STRTOLL - -/* Define if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_SELECT_H - -/* Define if you have the header file. */ -#define HAVE_SYS_SOCKET_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_SOCKIO_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define if you have the header file. */ -#define HAVE_SYS_TIME_H - -/* Define if you have the header file. */ -#define HAVE_SYS_TYPES_H - -/* Define if you have the `tcgetattr' function. */ -#define HAVE_TCGETATTR - -/* Define if you have the `tcsetattr' function. */ -#define HAVE_TCSETATTR - -/* Define if you have the header file. */ -#define HAVE_TERMIOS_H - -/* Define if you have the header file. */ -#undef HAVE_TERMIO_H - -/* Define if you have the header file. */ -#undef HAVE_TIME_H - -/* Define if you have the `uname' function. */ -#define HAVE_UNAME - -/* Define if you have the header file. */ -#define HAVE_UNISTD_H - -/* Define if you have the header file. */ -#undef HAVE_WINSOCK_H - -/* Define if you have the header file. */ -#undef HAVE_X509_H - -/* Name of package */ -#undef PACKAGE - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of `long double', as computed by sizeof. */ -#undef SIZEOF_LONG_DOUBLE - -/* The size of `long long', as computed by sizeof. */ -#undef SIZEOF_LONG_LONG - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* The size of `size_t', as computed by sizeof. */ -#define SIZEOF_SIZE_T 4 - -/* Define if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define if you can safely include both and . */ -#undef TIME_WITH_SYS_TIME - -/* Version number of package */ -#undef VERSION - -/* Define if on AIX 3. - System headers sometimes define this. - We just want to avoid a redefinition error message. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Define for large files, on AIX-style hosts. */ -#undef _LARGE_FILES - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `unsigned' if does not define. */ -#undef size_t - -/* Define to `int' if does not define. */ -#undef ssize_t - -/* Define if you have the ioctl function. */ -#define HAVE_IOCTL - -/* Define if you have a working ioctl FIONBIO function. */ -#define HAVE_IOCTL_FIONBIO - -/* to disable LDAP */ -#define CURL_DISABLE_LDAP - -/* Define if you have the getnameinfo function. */ -#define HAVE_GETNAMEINFO 1 - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -#define GETNAMEINFO_QUAL_ARG1 const - -/* Define to the type of arg 1 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * - -/* Define to the type of arg 2 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG2 socklen_t - -/* Define to the type of args 4 and 6 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG46 size_t - -/* Define to the type of arg 7 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG7 int - -/* Define if you have the recv function. */ -#define HAVE_RECV 1 - -/* Define to the type of arg 1 for recv. */ -#define RECV_TYPE_ARG1 int - -/* Define to the type of arg 2 for recv. */ -#define RECV_TYPE_ARG2 void * - -/* Define to the type of arg 3 for recv. */ -#define RECV_TYPE_ARG3 size_t - -/* Define to the type of arg 4 for recv. */ -#define RECV_TYPE_ARG4 int - -/* Define to the function return type for recv. */ -#define RECV_TYPE_RETV ssize_t - -/* Define 1 if you have the recvfrom function. */ -#define HAVE_RECVFROM 1 - -/* Define to the type of arg 1 for recvfrom. */ -#define RECVFROM_TYPE_ARG1 int - -/* Define to the type pointed by arg 2 for recvfrom. */ -#define RECVFROM_TYPE_ARG2 void - -/* Define if the type pointed by arg 2 for recvfrom is void. */ -#define RECVFROM_TYPE_ARG2_IS_VOID - -/* Define to the type of arg 3 for recvfrom. */ -#define RECVFROM_TYPE_ARG3 size_t - -/* Define to the type of arg 4 for recvfrom. */ -#define RECVFROM_TYPE_ARG4 int - -/* Define to the type pointed by arg 5 for recvfrom. */ -#define RECVFROM_TYPE_ARG5 struct sockaddr - -/* Define to the type pointed by arg 6 for recvfrom. */ -#define RECVFROM_TYPE_ARG6 int - -/* Define to the function return type for recvfrom. */ -#define RECVFROM_TYPE_RETV ssize_t - -/* Define if you have the send function. */ -#define HAVE_SEND 1 - -/* Define to the type of arg 1 for send. */ -#define SEND_TYPE_ARG1 int - -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 const - -/* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 void * - -/* Define to the type of arg 3 for send. */ -#define SEND_TYPE_ARG3 size_t - -/* Define to the type of arg 4 for send. */ -#define SEND_TYPE_ARG4 int - -/* Define to the function return type for send. */ -#define SEND_TYPE_RETV ssize_t - -#endif /* HEADER_CURL_CONFIG_RISCOS_H */ diff --git a/dep/cpr/opt/curl/lib/config-symbian.h b/dep/cpr/opt/curl/lib/config-symbian.h deleted file mode 100644 index 92983d24211..00000000000 --- a/dep/cpr/opt/curl/lib/config-symbian.h +++ /dev/null @@ -1,811 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_SYMBIAN_H -#define HEADER_CURL_CONFIG_SYMBIAN_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* ================================================================ */ -/* Hand crafted config file for Symbian */ -/* ================================================================ */ - -/* Location of default ca bundle */ -/* #define CURL_CA_BUNDLE "/etc/pki/tls/certs/ca-bundle.crt"*/ - -/* Location of default ca path */ -/* #undef CURL_CA_PATH */ - -/* to disable cookies support */ -/* #undef CURL_DISABLE_COOKIES */ - -/* to disable cryptographic authentication */ -/* #undef CURL_DISABLE_CRYPTO_AUTH */ - -/* to disable DICT */ -/* #undef CURL_DISABLE_DICT */ - -/* to disable FILE */ -/* #undef CURL_DISABLE_FILE */ - -/* to disable FTP */ -/* #undef CURL_DISABLE_FTP */ - -/* to disable HTTP */ -/* #undef CURL_DISABLE_HTTP */ - -/* to disable LDAP */ -#define CURL_DISABLE_LDAP 1 - -/* to disable LDAPS */ -#define CURL_DISABLE_LDAPS 1 - -/* to disable TELNET */ -/* #undef CURL_DISABLE_TELNET */ - -/* to disable TFTP */ -/* #undef CURL_DISABLE_TFTP */ - -/* to disable verbose strings */ -/* #define CURL_DISABLE_VERBOSE_STRINGS 1*/ - -/* Definition to make a library symbol externally visible. */ -/* #undef CURL_EXTERN_SYMBOL */ - -/* Use Windows LDAP implementation */ -/* #undef USE_WIN32_LDAP */ - -/* your Entropy Gathering Daemon socket pathname */ -/* #undef EGD_SOCKET */ - -/* Define if you want to enable IPv6 support */ -#define ENABLE_IPV6 1 - -/* Define if struct sockaddr_in6 has the sin6_scope_id member */ -#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -#define GETNAMEINFO_QUAL_ARG1 const - -/* Define to the type of arg 1 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * - -/* Define to the type of arg 2 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG2 socklen_t - -/* Define to the type of args 4 and 6 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG46 size_t - -/* Define to the type of arg 7 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG7 int - -/* Define to 1 if you have the header file. */ -/*#define HAVE_ALLOCA_H 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the header file. */ -/*#define HAVE_ARPA_TFTP_H 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the `basename' function. */ -/*#define HAVE_BASENAME 1*/ - -/* Define to 1 if bool is an available type. */ -/*#define HAVE_BOOL_T 1*/ - -/* Define to 1 if you have the `closesocket' function. */ -/* #undef HAVE_CLOSESOCKET */ - -/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ -/*#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1*/ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CRYPTO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DES_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */ -/*#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERR_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the fcntl function. */ -#define HAVE_FCNTL 1 - -/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ -#define HAVE_FCNTL_O_NONBLOCK 1 - -/* Define to 1 if you have the `fork' function. */ -/*#define HAVE_FORK 1*/ - -/* Define to 1 if you have the `ftruncate' function. */ -#define HAVE_FTRUNCATE 1 - -/* Define if getaddrinfo exists and works */ -#define HAVE_GETADDRINFO 1 - -/* Define to 1 if you have the `geteuid' function. */ -#define HAVE_GETEUID 1 - -/* Define to 1 if you have the `gethostbyaddr' function. */ -#define HAVE_GETHOSTBYADDR 1 - -/* If you have gethostbyname */ -#define HAVE_GETHOSTBYNAME 1 - -/* Define to 1 if you have the `gethostbyname_r' function. */ -/* #undef HAVE_GETHOSTBYNAME_R */ - -/* gethostbyname_r() takes 3 args */ -/* #undef HAVE_GETHOSTBYNAME_R_3 */ - -/* gethostbyname_r() takes 5 args */ -/* #undef HAVE_GETHOSTBYNAME_R_5 */ - -/* gethostbyname_r() takes 6 args */ -/* #undef HAVE_GETHOSTBYNAME_R_6 */ - -/* Define to 1 if you have the getnameinfo function. */ -#define HAVE_GETNAMEINFO 1 - -/* Define to 1 if you have the `getpass_r' function. */ -/* #undef HAVE_GETPASS_R */ - -/* Define to 1 if you have the `getppid' function. */ -#define HAVE_GETPPID 1 - -/* Define to 1 if you have the `getprotobyname' function. */ -#define HAVE_GETPROTOBYNAME 1 - -/* Define to 1 if you have the `getpwuid' function. */ -#define HAVE_GETPWUID 1 - -/* Define to 1 if you have the `getrlimit' function. */ -/*#define HAVE_GETRLIMIT 1*/ - -/* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* we have a glibc-style strerror_r() */ -/* #undef HAVE_GLIBC_STRERROR_R */ - -/* Define to 1 if you have the `gmtime_r' function. */ -#define HAVE_GMTIME_R 1 - -/* if you have the gssapi libraries */ -/* #undef HAVE_GSSAPI */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_GSSAPI_GSSAPI_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */ - -/* if you have the GNU gssapi libraries */ -/* #undef HAVE_GSSGNU */ - -/* if you have the Heimdal gssapi libraries */ -/* #undef HAVE_GSSHEIMDAL */ - -/* if you have the MIT gssapi libraries */ -/* #undef HAVE_GSSMIT */ - -/* Define to 1 if you have the `idna_strerror' function. */ -/*#define HAVE_IDNA_STRERROR 1*/ - -/* Define to 1 if you have the `idn_free' function. */ -/*#define HAVE_IDN_FREE 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_IDN_FREE_H 1*/ - -/* Define to 1 if you have the `inet_addr' function. */ -/*#define HAVE_INET_ADDR 1*/ - -/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ -/*#define HAVE_INET_NTOP 1*/ - -/* Define to 1 if you have a IPv6 capable working inet_pton function. */ -/*#define HAVE_INET_PTON 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the ioctl function. */ -#define HAVE_IOCTL 1 - -/* Define to 1 if you have a working ioctl FIONBIO function. */ -#define HAVE_IOCTL_FIONBIO 1 - -/* Define to 1 if you have the ioctlsocket function. */ -/* #undef HAVE_IOCTLSOCKET */ - -/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ -/* #undef HAVE_IOCTLSOCKET_FIONBIO */ - -/* Define to 1 if you have the IoctlSocket camel case function. */ -/* #undef HAVE_IOCTLSOCKET_CAMEL */ - -/* Define to 1 if you have a working IoctlSocket camel case FIONBIO - function. */ -/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IO_H */ - -/* if you have the Kerberos4 libraries (including -ldes) */ -/* #undef HAVE_KRB4 */ - -/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ -/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_KRB_H */ - -/* Define to 1 if you have the lber.h header file. */ -/*#define HAVE_LBER_H 1*/ - -/* Define to 1 if you have the ldapssl.h header file. */ -/* #undef HAVE_LDAPSSL_H */ - -/* Define to 1 if you have the ldap.h header file. */ -/*#define HAVE_LDAP_H 1*/ - -/* Use LDAPS implementation */ -/*#define HAVE_LDAP_SSL 1*/ - -/* Define to 1 if you have the ldap_ssl.h header file. */ -/* #undef HAVE_LDAP_SSL_H */ - -/* Define to 1 if you have the `ldap_url_parse' function. */ -/*#define HAVE_LDAP_URL_PARSE 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_LIBGEN_H 1*/ - -/* Define to 1 if you have the `idn' library (-lidn). */ -/*#define HAVE_LIBIDN 1*/ - -/* Define to 1 if you have the `resolv' library (-lresolv). */ -/* #undef HAVE_LIBRESOLV */ - -/* Define to 1 if you have the `resolve' library (-lresolve). */ -/* #undef HAVE_LIBRESOLVE */ - -/* Define to 1 if you have the `socket' library (-lsocket). */ -/* #undef HAVE_LIBSOCKET */ - -/* Define to 1 if you have the `ssh2' library (-lssh2). */ -/*#define HAVE_LIBSSH2 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_LIBSSH2_H 1*/ - -/* Define to 1 if you have the `ssl' library (-lssl). */ -/*#define HAVE_LIBSSL 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* if your compiler supports LL */ -#define HAVE_LL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if you have the `localtime_r' function. */ -#define HAVE_LOCALTIME_R 1 - -/* Define to 1 if the compiler supports the 'long long' data type. */ -#define HAVE_LONGLONG 1 - -/* Define to 1 if you have the malloc.h header file. */ -/*#define HAVE_MALLOC_H 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the MSG_NOSIGNAL flag. */ -/*#define HAVE_MSG_NOSIGNAL 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have the header file. */ -/*#define HAVE_NETINET_TCP_H 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_NET_IF_H 1 - -/* Define to 1 if NI_WITHSCOPEID exists and works. */ -/*#define HAVE_NI_WITHSCOPEID 1*/ - -/* we have no strerror_r() proto */ -/* #undef HAVE_NO_STRERROR_R_DECL */ - -/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE - */ -/* #undef HAVE_OLD_GSSMIT */ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_CRYPTO_H 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_ENGINE_H 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_ERR_H 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_PEM_H 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_PKCS12_H 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_RSA_H 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_SSL_H 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_X509_H 1*/ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PEM_H */ - -/* Define to 1 if you have the `perror' function. */ -#define HAVE_PERROR 1 - -/* Define to 1 if you have the `pipe' function. */ -#define HAVE_PIPE 1 - -/* Define to 1 if you have the `poll' function. */ -/*#define HAVE_POLL 1*/ - -/* If you have a fine poll */ -/*#define HAVE_POLL_FINE 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_POLL_H 1*/ - -/* we have a POSIX-style strerror_r() */ -#define HAVE_POSIX_STRERROR_R 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define to 1 if you have the `RAND_egd' function. */ -#define HAVE_RAND_EGD 1 - -/* Define to 1 if you have the `RAND_screen' function. */ -/* #undef HAVE_RAND_SCREEN */ - -/* Define to 1 if you have the `RAND_status' function. */ -/*#define HAVE_RAND_STATUS 1*/ - -/* Define to 1 if you have the recv function. */ -#define HAVE_RECV 1 - -/* Define to 1 if you have the recvfrom function. */ -#define HAVE_RECVFROM 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_RSA_H */ - -/* Define to 1 if you have the select function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the send function. */ -#define HAVE_SEND 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SETJMP_H 1 - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the `setmode' function. */ -/* #undef HAVE_SETMODE */ - -/* Define to 1 if you have the `setrlimit' function. */ -/*#define HAVE_SETRLIMIT 1*/ - -/* Define to 1 if you have the setsockopt function. */ -/* #undef HAVE_SETSOCKOPT */ - -/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ -/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_SGTTY_H 1*/ - -/* Define to 1 if you have the `sigaction' function. */ -/*#define HAVE_SIGACTION 1*/ - -/* Define to 1 if you have the `siginterrupt' function. */ -/*#define HAVE_SIGINTERRUPT 1*/ - -/* Define to 1 if you have the `signal' function. */ -/*#define HAVE_SIGNAL 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* If you have sigsetjmp */ -/*#define HAVE_SIGSETJMP 1*/ - -/* Define to 1 if sig_atomic_t is an available typedef. */ -/*#define HAVE_SIG_ATOMIC_T 1*/ - -/* Define to 1 if sig_atomic_t is already defined as volatile. */ -/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define to 1 if you have the `SSL_get_shutdown' function. */ -/*#define HAVE_SSL_GET_SHUTDOWN 1*/ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SSL_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDBOOL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strcasecmp' function. */ -#define HAVE_STRCASECMP 1 - -/* Define to 1 if you have the `strcmpi' function. */ -/* #undef HAVE_STRCMPI */ - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strerror_r' function. */ -#define HAVE_STRERROR_R 1 - -/* Define to 1 if you have the `stricmp' function. */ -/* #undef HAVE_STRICMP */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strlcpy' function. */ -#define HAVE_STRLCPY 1 - -/* Define to 1 if you have the `strstr' function. */ -#define HAVE_STRSTR 1 - -/* Define to 1 if you have the `strtok_r' function. */ -#define HAVE_STRTOK_R 1 - -/* Define to 1 if you have the `strtoll' function. */ -#define HAVE_STRTOLL 1 - -/* if struct sockaddr_storage is defined */ -#define HAVE_STRUCT_SOCKADDR_STORAGE 1 - -/* Define to 1 if you have the timeval struct. */ -#define HAVE_STRUCT_TIMEVAL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_FILIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -/*#define HAVE_SYS_POLL_H 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_RESOURCE_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UTIME_H */ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_TERMIOS_H 1*/ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_TERMIO_H 1*/ - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the header file. */ -/*#define HAVE_TLD_H 1*/ - -/* Define to 1 if you have the `tld_strerror' function. */ -/*#define HAVE_TLD_STRERROR 1*/ - -/* Define to 1 if you have the `uname' function. */ -#define HAVE_UNAME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UTIME_H 1 - -/* Define to 1 if compiler supports C99 variadic macro style. */ -#define HAVE_VARIADIC_MACROS_C99 1 - -/* Define to 1 if compiler supports old gcc variadic macro style. */ -/*#define HAVE_VARIADIC_MACROS_GCC 1*/ - -/* Define to 1 if you have the winber.h header file. */ -/* #undef HAVE_WINBER_H */ - -/* Define to 1 if you have the windows.h header file. */ -/* #undef HAVE_WINDOWS_H */ - -/* Define to 1 if you have the winldap.h header file. */ -/* #undef HAVE_WINLDAP_H */ - -/* Define to 1 if you have the winsock2.h header file. */ -/* #undef HAVE_WINSOCK2_H */ - -/* Define to 1 if you have the winsock.h header file. */ -/* #undef HAVE_WINSOCK_H */ - -/* Define this symbol if your OS supports changing the contents of argv */ -/*#define HAVE_WRITABLE_ARGV 1*/ - -/* Define to 1 if you have the ws2tcpip.h header file. */ -/* #undef HAVE_WS2TCPIP_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_X509_H */ - -/* Define to 1 if you need the lber.h header file even with ldap.h */ -/* #undef NEED_LBER_H */ - -/* Define to 1 if you need the malloc.h header file even with stdlib.h */ -/* #undef NEED_MALLOC_H */ - -/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ -/* #undef NEED_REENTRANT */ - -/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ -/* #undef NEED_THREAD_SAFE */ - -/* cpu-machine-OS */ -#ifdef __WINS__ -#define OS "i386-pc-epoc32" -#elif __MARM__ -#define OS "arm-unknown-epoc32" -#else -/* This won't happen on any current Symbian version */ -#define OS "unknown-unknown-epoc32" -#endif - -/* Name of package */ -/*#define PACKAGE "curl"*/ - -/* Define to the address where bug reports for this package should be sent. */ -/*#define PACKAGE_BUGREPORT \ - "a suitable curl mailing list => https://curl.haxx.se/mail/"*/ - -/* Define to the full name of this package. */ -/*#define PACKAGE_NAME "curl"*/ - -/* Define to the full name and version of this package. */ -/*#define PACKAGE_STRING "curl -"*/ - -/* Define to the one symbol short name of this package. */ -/*#define PACKAGE_TARNAME "curl"*/ - -/* Define to the version of this package. */ -/*#define PACKAGE_VERSION "-"*/ - -/* a suitable file to read random data from */ -/*#define RANDOM_FILE "/dev/urandom"*/ - -#define RECV_TYPE_ARG1 int -#define RECV_TYPE_ARG2 void * -#define RECV_TYPE_ARG3 size_t -#define RECV_TYPE_ARG4 int -#define RECV_TYPE_RETV ssize_t - -#define RECVFROM_TYPE_ARG1 int -#define RECVFROM_TYPE_ARG2 void -#define RECVFROM_TYPE_ARG3 size_t -#define RECVFROM_TYPE_ARG4 int -#define RECVFROM_TYPE_ARG5 struct sockaddr -#define RECVFROM_TYPE_ARG6 size_t -#define RECVFROM_TYPE_RETV ssize_t -#define RECVFROM_TYPE_ARG2_IS_VOID 1 - -#define SEND_TYPE_ARG1 int -#define SEND_QUAL_ARG2 const -#define SEND_TYPE_ARG2 void * -#define SEND_TYPE_ARG3 size_t -#define SEND_TYPE_ARG4 int -#define SEND_TYPE_RETV ssize_t - - -/* Define as the return type of signal handlers (`int' or `void'). */ -/*#define RETSIGTYPE void*/ - -/* Define to the type of arg 1 for `select'. */ -#define SELECT_TYPE_ARG1 int - -/* Define to the type of args 2, 3 and 4 for `select'. */ -#define SELECT_TYPE_ARG234 (fd_set *) - -/* Define to the type of arg 5 for `select'. */ -#define SELECT_TYPE_ARG5 (struct timeval *) - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of `off_t', as computed by sizeof. */ -#define SIZEOF_OFF_T 8 - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* The size of `size_t', as computed by sizeof. */ -#define SIZEOF_SIZE_T 4 - -/* The size of `time_t', as computed by sizeof. */ -#define SIZEOF_TIME_T 4 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Define if you want to enable c-ares support */ -/* #undef USE_ARES */ - -/* Define to disable non-blocking sockets */ -/* #undef USE_BLOCKING_SOCKETS */ - -/* if GnuTLS is enabled */ -/* #undef USE_GNUTLS */ - -/* if libSSH2 is in use */ -/*#define USE_LIBSSH2 1*/ - -/* If you want to build curl with the built-in manual */ -/*#define USE_MANUAL 1*/ - -/* if NSS is enabled */ -/* #undef USE_NSS */ - -/* to enable SSPI support */ -/* #undef USE_WINDOWS_SSPI */ - -/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ -/* #undef USE_YASSLEMUL */ - -/* Version number of package */ -/*#define VERSION "7.18.2-CVS"*/ - -/* Define to avoid automatic inclusion of winsock.h */ -/* #undef WIN32_LEAN_AND_MEAN */ - -/* Define to 1 if on AIX 3. - System headers sometimes define this. - We just want to avoid a redefinition error message. */ -#ifndef _ALL_SOURCE -/* # undef _ALL_SOURCE */ -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -#define _FILE_OFFSET_BITS 64 - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* type to use in place of in_addr_t if not defined */ -/* #undef in_addr_t */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* the signed version of size_t */ -/* #undef ssize_t */ - -/* Enabling curl debug mode when building in Symbian debug mode would work */ -/* except that debug mode introduces new exports that must be frozen. */ -#ifdef _DEBUG -/* #define CURLDEBUG */ -#endif - -/* sys/cdefs.h fails to define this for WINSCW prior to Symbian OS ver. 9.4 */ -#ifndef __LONG_LONG_SUPPORTED -#define __LONG_LONG_SUPPORTED -#endif - -/* Enable appropriate header only when zlib support is enabled */ -#ifdef HAVE_LIBZ -#define HAVE_ZLIB_H 1 -#endif - -#endif /* HEADER_CURL_CONFIG_SYMBIAN_H */ diff --git a/dep/cpr/opt/curl/lib/config-tpf.h b/dep/cpr/opt/curl/lib/config-tpf.h deleted file mode 100644 index d1eb3d90620..00000000000 --- a/dep/cpr/opt/curl/lib/config-tpf.h +++ /dev/null @@ -1,775 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_TPF_H -#define HEADER_CURL_CONFIG_TPF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* ================================================================ */ -/* Hand crafted config file for TPF */ -/* ================================================================ */ - -/* ---------------------------------------------------------------- */ -/* FEATURES, FUNCTIONS, and DEFINITIONS */ -/* ---------------------------------------------------------------- */ - -/* NOTE: Refer also to the .mak file for some of the flags below */ - -/* to disable cookies support */ -/* #undef CURL_DISABLE_COOKIES */ - -/* to disable cryptographic authentication */ -/* #undef CURL_DISABLE_CRYPTO_AUTH */ - -/* to disable DICT */ -/* #undef CURL_DISABLE_DICT */ - -/* to disable FILE */ -/* #undef CURL_DISABLE_FILE */ - -/* to disable FTP */ -/* #undef CURL_DISABLE_FTP */ - -/* to disable HTTP */ -/* #undef CURL_DISABLE_HTTP */ - -/* to disable LDAP */ -/* #undef CURL_DISABLE_LDAP */ - -/* to disable TELNET */ -/* #undef CURL_DISABLE_TELNET */ - -/* to disable TFTP */ -/* #undef CURL_DISABLE_TFTP */ - -/* to disable verbose strings */ -/* #undef CURL_DISABLE_VERBOSE_STRINGS */ - -/* lber dynamic library file */ -/* #undef DL_LBER_FILE */ - -/* ldap dynamic library file */ -/* #undef DL_LDAP_FILE */ - -/* your Entropy Gathering Daemon socket pathname */ -/* #undef EGD_SOCKET */ - -/* Define if you want to enable IPv6 support */ -/* #undef ENABLE_IPV6 */ - -/* Define if struct sockaddr_in6 has the sin6_scope_id member */ -/* #undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID */ - -/* Define to the type of arg 1 for getnameinfo. */ -/* #undef GETNAMEINFO_TYPE_ARG1 */ - -/* Define to the type of arg 2 for getnameinfo. */ -/* #undef GETNAMEINFO_TYPE_ARG2 */ - -/* Define to the type of args 4 and 6 for getnameinfo. */ -/* #undef GETNAMEINFO_TYPE_ARG46 */ - -/* Define to the type of arg 7 for getnameinfo. */ -/* #undef GETNAMEINFO_TYPE_ARG7 */ - -/* Define to 1 if you have the alarm function. */ -#define HAVE_ALARM 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ARPA_TFTP_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the `basename' function. */ -#define HAVE_BASENAME 1 - -/* Define to 1 if you have the `closesocket' function. */ -/* #undef HAVE_CLOSESOCKET */ - -/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ -/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */ -#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CRYPTO_H */ -#define HAVE_CRYPTO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DES_H */ -#define HAVE_DES_H 1 - -/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */ -/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */ -#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ERR_H */ -#define HAVE_ERR_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the fcntl function. */ -#define HAVE_FCNTL 1 - -/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ -#define HAVE_FCNTL_O_NONBLOCK 1 - -/* Define to 1 if you have the `fork' function. */ -/* #undef HAVE_FORK */ -#define HAVE_FORK 1 - -/* Define to 1 if you have the `ftruncate' function. */ -#define HAVE_FTRUNCATE 1 - -/* Define if getaddrinfo exists and works */ -/* #undef HAVE_GETADDRINFO */ - -/* Define to 1 if you have the `geteuid' function. */ -#define HAVE_GETEUID 1 - -/* Define to 1 if you have the `gethostbyaddr' function. */ -#define HAVE_GETHOSTBYADDR 1 - -/* If you have gethostbyname */ -#define HAVE_GETHOSTBYNAME 1 - -/* Define to 1 if you have the `gethostbyname_r' function. */ -/* #undef HAVE_GETHOSTBYNAME_R */ - -/* gethostbyname_r() takes 3 args */ -/* #undef HAVE_GETHOSTBYNAME_R_3 */ - -/* gethostbyname_r() takes 5 args */ -/* #undef HAVE_GETHOSTBYNAME_R_5 */ - -/* gethostbyname_r() takes 6 args */ -/* #undef HAVE_GETHOSTBYNAME_R_6 1 */ - -/* Define to 1 if you have the getnameinfo function. */ -/* #undef HAVE_GETNAMEINFO */ - -/* Define to 1 if you have the `getpass_r' function. */ -/* #undef HAVE_GETPASS_R */ - -/* Define to 1 if you have the `getprotobyname' function. */ -/* #undef HAVE_GETPROTOBYNAME */ - -/* Define to 1 if you have the `getpwuid' function. */ -#define HAVE_GETPWUID 1 - -/* Define to 1 if you have the `getrlimit' function. */ -/* #undef HAVE_GETRLIMIT */ - -/* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* we have a glibc-style strerror_r() */ -/* #undef HAVE_GLIBC_STRERROR_R */ -#define HAVE_GLIBC_STRERROR_R 1 - -/* Define to 1 if you have the `gmtime_r' function. */ -#define HAVE_GMTIME_R 1 - -/* if you have the gssapi libraries */ -/* #undef HAVE_GSSAPI */ - -/* if you have the GNU gssapi libraries */ -/* #undef HAVE_GSSGNU */ - -/* if you have the Heimdal gssapi libraries */ -/* #undef HAVE_GSSHEIMDAL */ - -/* if you have the MIT gssapi libraries */ -/* #undef HAVE_GSSMIT */ - -/* Define to 1 if you have the `iconv' functions. */ -#define HAVE_ICONV 1 - -/* Define to 1 if you have the `idna_strerror' function. */ -/* #undef HAVE_IDNA_STRERROR */ - -/* Define to 1 if you have the `idn_free' function. */ -/* #undef HAVE_IDN_FREE */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IDN_FREE_H */ - -/* Define to 1 if you have the `inet_addr' function. */ -#define HAVE_INET_ADDR 1 - -/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ -/* #undef HAVE_INET_NTOP */ - -/* Define to 1 if you have a IPv6 capable working inet_pton function. */ -/* #undef HAVE_INET_PTON */ - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the ioctl function. */ -#define HAVE_IOCTL 1 - -/* Define to 1 if you have a working ioctl FIONBIO function. */ -#define HAVE_IOCTL_FIONBIO 1 - -/* Define to 1 if you have the ioctlsocket function. */ -/* #undef HAVE_IOCTLSOCKET */ - -/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ -/* #undef HAVE_IOCTLSOCKET_FIONBIO */ - -/* Define to 1 if you have the IoctlSocket camel case function. */ -/* #undef HAVE_IOCTLSOCKET_CAMEL */ - -/* Define to 1 if you have a working IoctlSocket camel case FIONBIO - function. */ -/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IO_H */ - -/* if you have the Kerberos4 libraries (including -ldes) */ -/* #undef HAVE_KRB4 */ - -/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ -/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_KRB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBGEN_H 1 */ - -/* Define to 1 if you have the `idn' library (-lidn). */ -/* #undef HAVE_LIBIDN */ - -/* Define to 1 if you have the `resolv' library (-lresolv). */ -/* #undef HAVE_LIBRESOLV */ - -/* Define to 1 if you have the `resolve' library (-lresolve). */ -/* #undef HAVE_LIBRESOLVE */ - -/* Define to 1 if you have the `socket' library (-lsocket). */ -/* #undef HAVE_LIBSOCKET */ - -/* Define to 1 if you have the `ssl' library (-lssl). */ -/* #undef HAVE_LIBSSL */ -#define HAVE_LIBSSL 1 - -/* if zlib is available */ -/* #undef HAVE_LIBZ */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* if your compiler supports LL */ -#define HAVE_LL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if you have the `localtime_r' function. */ -#define HAVE_LOCALTIME_R 1 - -/* Define to 1 if the compiler supports the 'long long' data type. */ -#define HAVE_LONGLONG 1 - -/* Define to 1 if you need the malloc.h header file even with stdlib.h */ -/* #undef NEED_MALLOC_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have the header file. */ -/* undef HAVE_NETINET_TCP_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_NET_IF_H 1 - -/* Define if NI_WITHSCOPEID exists and works */ -/* #undef HAVE_NI_WITHSCOPEID */ - -/* we have no strerror_r() proto */ -/* #undef HAVE_NO_STRERROR_R_DECL */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_CRYPTO_H */ -#define HAVE_OPENSSL_CRYPTO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_ENGINE_H */ -#define HAVE_OPENSSL_ENGINE_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_ERR_H */ -#define HAVE_OPENSSL_ERR_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_PEM_H */ -#define HAVE_OPENSSL_PEM_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_PKCS12_H */ -#define HAVE_OPENSSL_PKCS12_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_RSA_H */ -#define HAVE_OPENSSL_RSA_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_SSL_H */ -#define HAVE_OPENSSL_SSL_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_X509_H */ -#define HAVE_OPENSSL_X509_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PEM_H */ -#define HAVE_PEM_H 1 - -/* Define to 1 if you have the `perror' function. */ -#define HAVE_PERROR 1 - -/* Define to 1 if you have the `pipe' function. */ -#define HAVE_PIPE 1 - -/* Define to 1 if you have the `poll' function. */ -/* #undef HAVE_POLL */ - -/* If you have a fine poll */ -/* #undef HAVE_POLL_FINE */ - -/* we have a POSIX-style strerror_r() */ -/* #undef HAVE_POSIX_STRERROR_R */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define to 1 if you have the `RAND_egd' function. */ -/* #undef HAVE_RAND_EGD */ -#define HAVE_RAND_EGD 1 - -/* Define to 1 if you have the `RAND_screen' function. */ -/* #undef HAVE_RAND_SCREEN */ - -/* Define to 1 if you have the `RAND_status' function. */ -/* #undef HAVE_RAND_STATUS */ -#define HAVE_RAND_STATUS 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_RSA_H */ -#define HAVE_RSA_H 1 - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SETJMP_H 1 - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the `setrlimit' function. */ -#define HAVE_SETRLIMIT 1 - -/* Define to 1 if you have the setsockopt function. */ -/* #undef HAVE_SETSOCKOPT */ - -/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ -/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SGTTY_H 1 */ - -/* Define to 1 if you have the `sigaction' function. */ -#define HAVE_SIGACTION 1 - -/* Define to 1 if you have the `siginterrupt' function. */ -/* #undef HAVE_SIGINTERRUPT */ - -/* Define to 1 if you have the `signal' function. */ -#define HAVE_SIGNAL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - -/* Define to 1 if sig_atomic_t is already defined as volatile. */ -/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ - -/* If you have sigsetjmp */ -/* #undef HAVE_SIGSETJMP */ - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SSL_H */ -#define HAVE_SSL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strcasecmp' function. */ -#define HAVE_STRCASECMP 1 - -/* Define to 1 if you have the `strcmpi' function. */ -/* #undef HAVE_STRCMPI */ - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strerror_r' function. */ -#define HAVE_STRERROR_R 1 - -/* Define to 1 if you have the `stricmp' function. */ -/* #undef HAVE_STRICMP */ -#define HAVE_STRICMP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strlcpy' function. */ -/* #undef HAVE_STRLCPY */ - -/* Define to 1 if you have the `strstr' function. */ -#define HAVE_STRSTR 1 - -/* Define to 1 if you have the `strtok_r' function. */ -#define HAVE_STRTOK_R 1 - -/* Define to 1 if you have the `strtoll' function. */ -#define HAVE_STRTOLL 1 - -/* if struct sockaddr_storage is defined */ -/* #undef HAVE_STRUCT_SOCKADDR_STORAGE */ - -/* Define this if you have struct timeval */ -#define HAVE_STRUCT_TIMEVAL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_FILIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_POLL_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_RESOURCE_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOCKIO_H */ -#define HAVE_SYS_SOCKIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UTIME_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TERMIOS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TERMIO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TLD_H */ - -/* Define to 1 if you have the `tld_strerror' function. */ -/* #undef HAVE_TLD_STRERROR */ - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UTIME_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINSOCK2_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINSOCK_H */ - -/* Define this symbol if your OS supports changing the contents of argv */ -/* #undef HAVE_WRITABLE_ARGV */ - -/* Define to 1 if you have the ws2tcpip.h header file. */ -/* #undef HAVE_WS2TCPIP_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_X509_H */ - -/* if you have the zlib.h header file */ -/* #undef HAVE_ZLIB_H */ - -/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ -/* #undef NEED_REENTRANT */ - -/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ -/* #undef NEED_THREAD_SAFE */ - -/* cpu-machine-OS */ -#define OS "s390x-ibm-tpf" - -/* Name of package */ -#define PACKAGE "curl" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT \ - "a suitable curl mailing list => https://curl.haxx.se/mail/" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "curl" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "curl -" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "curl" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "-" - -/* a suitable file to read random data from */ -/* #undef RANDOM_FILE */ - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* Define to the type of arg 1 for `select'. */ -#define SELECT_TYPE_ARG1 int - -/* Define to the type of args 2, 3 and 4 for `select'. */ -#define SELECT_TYPE_ARG234 (fd_set *) - -/* Define to the type of arg 5 for `select'. */ -#define SELECT_TYPE_ARG5 (struct timeval *) - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of `off_t', as computed by sizeof. */ -#define SIZEOF_OFF_T 8 - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* Define to the size of `long', as computed by sizeof. */ -#define SIZEOF_LONG 8 - -/* The size of `size_t', as computed by sizeof. */ -#define SIZEOF_SIZE_T 8 - -/* The size of `time_t', as computed by sizeof. */ -#define SIZEOF_TIME_T 8 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Define if you want to enable ares support */ -/* #undef USE_ARES */ - -/* Define to disable non-blocking sockets */ -/* #undef USE_BLOCKING_SOCKETS */ - -/* if GnuTLS is enabled */ -/* #undef USE_GNUTLS */ - -/* If you want to build curl with the built-in manual */ -/* #undef USE_MANUAL */ - -/* if OpenSSL is in use */ -/* #undef USE_OPENSSL */ - -/* if SSL is enabled */ -/* #undef USE_OPENSSL */ - -/* to enable SSPI support */ -/* #undef USE_WINDOWS_SSPI */ - -/* Version number of package */ -#define VERSION "not-used" - -/* Define to avoid automatic inclusion of winsock.h */ -/* #undef WIN32_LEAN_AND_MEAN */ - -/* Define to 1 if on AIX 3. - System headers sometimes define this. - We just want to avoid a redefinition error message. */ -#ifndef _ALL_SOURCE -/* # undef _ALL_SOURCE */ -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* type to use in place of in_addr_t if not defined */ -/* #undef in_addr_t */ - -/* Define to `unsigned' if does not define. */ -/* #undef size_t */ - -/* the signed version of size_t */ -/* #undef ssize_t */ - -/* Define to 1 if you have the getnameinfo function. */ -/* #undef HAVE_GETNAMEINFO 1 */ - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -/* #undef GETNAMEINFO_QUAL_ARG1 const */ - -/* Define to the type of arg 1 for getnameinfo. */ -/* #undef GETNAMEINFO_TYPE_ARG1 struct sockaddr * */ - -/* Define to the type of arg 2 for getnameinfo. */ -/* #undef GETNAMEINFO_TYPE_ARG2 socklen_t */ - -/* Define to the type of args 4 and 6 for getnameinfo. */ -/* #undef GETNAMEINFO_TYPE_ARG46 size_t */ - -/* Define to the type of arg 7 for getnameinfo. */ -/* #undef GETNAMEINFO_TYPE_ARG7 int */ - -/* Define to 1 if you have the recv function. */ -#define HAVE_RECV 1 - -/* Define to the type of arg 1 for recv. */ -#define RECV_TYPE_ARG1 int - -/* Define to the type of arg 2 for recv. */ -#define RECV_TYPE_ARG2 char * - -/* Define to the type of arg 3 for recv. */ -#define RECV_TYPE_ARG3 int - -/* Define to the type of arg 4 for recv. */ -#define RECV_TYPE_ARG4 int - -/* Define to the function return type for recv. */ -#define RECV_TYPE_RETV int - -/* Define to 1 if you have the recvfrom function. */ -#define HAVE_RECVFROM 1 - -/* Define to the type of arg 1 for recvfrom. */ -#define RECVFROM_TYPE_ARG1 int - -/* Define to the type pointed by arg 2 for recvfrom. */ -#define RECVFROM_TYPE_ARG2 char - -/* Define to the type of arg 3 for recvfrom. */ -#define RECVFROM_TYPE_ARG3 int - -/* Define to the type of arg 4 for recvfrom. */ -#define RECVFROM_TYPE_ARG4 int - -/* Define to the type pointed by arg 5 for recvfrom. */ -#define RECVFROM_TYPE_ARG5 struct sockaddr - -/* Define to the type pointed by arg 6 for recvfrom. */ -#define RECVFROM_TYPE_ARG6 int - -/* Define to the function return type for recvfrom. */ -#define RECVFROM_TYPE_RETV int - -/* Define to 1 if you have the send function. */ -#define HAVE_SEND 1 - -/* Define to the type of arg 1 for send. */ -#define SEND_TYPE_ARG1 int - -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 const - -/* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 char * - -/* Define to the type of arg 3 for send. */ -#define SEND_TYPE_ARG3 int - -/* Define to the type of arg 4 for send. */ -#define SEND_TYPE_ARG4 int - -/* Define to the function return type for send. */ -#define SEND_TYPE_RETV int - -#define CURL_DOES_CONVERSIONS -#ifndef CURL_ICONV_CODESET_OF_HOST -#define CURL_ICONV_CODESET_OF_HOST "IBM-1047" -#endif - - -#endif /* HEADER_CURL_CONFIG_TPF_H */ diff --git a/dep/cpr/opt/curl/lib/config-vxworks.h b/dep/cpr/opt/curl/lib/config-vxworks.h deleted file mode 100644 index 780a4a225f0..00000000000 --- a/dep/cpr/opt/curl/lib/config-vxworks.h +++ /dev/null @@ -1,928 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_VXWORKS_H -#define HEADER_CURL_CONFIG_VXWORKS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* =============================================================== */ -/* Hand crafted config file for VxWorks */ -/* =============================================================== */ - -/* Location of default ca bundle */ -/* #undef CURL_CA_BUNDLE */ - -/* Location of default ca path */ -/* #undef CURL_CA_PATH */ - -/* to disable cookies support */ -/* #undef CURL_DISABLE_COOKIES */ - -/* to disable cryptographic authentication */ -/* #undef CURL_DISABLE_CRYPTO_AUTH */ - -/* to disable DICT */ -/* #undef CURL_DISABLE_DICT */ - -/* to disable FILE */ -/* #undef CURL_DISABLE_FILE */ - -/* to disable FTP */ -#define CURL_DISABLE_FTP 1 - -/* to disable HTTP */ -/* #undef CURL_DISABLE_HTTP */ - -/* to disable LDAP */ -#define CURL_DISABLE_LDAP 1 - -/* to disable LDAPS */ -#define CURL_DISABLE_LDAPS 1 - -/* to disable NTLM authentication */ -#define CURL_DISABLE_NTLM 1 - -/* to disable proxies */ -/* #undef CURL_DISABLE_PROXY */ - -/* to disable TELNET */ -#define CURL_DISABLE_TELNET 1 - -/* to disable TFTP */ -#define CURL_DISABLE_TFTP 1 - -/* to disable verbose strings */ -/* #undef CURL_DISABLE_VERBOSE_STRINGS */ - -/* Definition to make a library symbol externally visible. */ -/* #undef CURL_EXTERN_SYMBOL */ - -/* Use Windows LDAP implementation */ -/* #undef USE_WIN32_LDAP */ - -/* your Entropy Gathering Daemon socket pathname */ -/* #undef EGD_SOCKET */ - -/* Define if you want to enable IPv6 support */ -#define ENABLE_IPV6 1 - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -#define GETNAMEINFO_QUAL_ARG1 const - -/* Define to the type of arg 1 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * - -/* Define to the type of arg 2 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG2 socklen_t - -/* Define to the type of args 4 and 6 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG46 size_t - -/* Define to the type of arg 7 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG7 unsigned int - -/* Specifies the number of arguments to getservbyport_r */ -#define GETSERVBYPORT_R_ARGS 6 - -/* Specifies the size of the buffer to pass to getservbyport_r */ -#define GETSERVBYPORT_R_BUFSIZE 4096 - -/* Define to 1 if you have the alarm function. */ -#define HAVE_ALARM 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ALLOCA_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ARPA_TFTP_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the `basename' function. */ -/* #undef HAVE_BASENAME */ - -/* Define to 1 if bool is an available type. */ -#define HAVE_BOOL_T 1 - -/* Define to 1 if you have the clock_gettime function and monotonic timer. */ -/* #undef HAVE_CLOCK_GETTIME_MONOTONIC */ - -/* Define to 1 if you have the `closesocket' function. */ -/* #undef HAVE_CLOSESOCKET */ - -/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ -#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CRYPTO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DES_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */ -#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ERR_H */ - -/* Define to 1 if you have the fcntl function. */ -#define HAVE_FCNTL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ -#define HAVE_FCNTL_O_NONBLOCK 1 - -/* Define to 1 if you have the fdopen function. */ -#define HAVE_FDOPEN 1 - -/* Define to 1 if you have the `fork' function. */ -#define HAVE_FORK 1 - -/* Define to 1 if you have the freeaddrinfo function. */ -#define HAVE_FREEADDRINFO 1 - -/* Define to 1 if you have the freeifaddrs function. */ -#define HAVE_FREEIFADDRS 1 - -/* Define to 1 if you have the ftruncate function. */ -#define HAVE_FTRUNCATE 1 - -/* Define to 1 if you have a working getaddrinfo function. */ -#define HAVE_GETADDRINFO 1 - -/* Define to 1 if you have the `geteuid' function. */ -/* #undef HAVE_GETEUID */ - -/* Define to 1 if you have the gethostbyaddr function. */ -#define HAVE_GETHOSTBYADDR 1 - -/* Define to 1 if you have the gethostbyaddr_r function. */ -#define HAVE_GETHOSTBYADDR_R 1 - -/* gethostbyaddr_r() takes 5 args */ -/* #undef HAVE_GETHOSTBYADDR_R_5 */ - -/* gethostbyaddr_r() takes 7 args */ -/* #undef HAVE_GETHOSTBYADDR_R_7 */ - -/* gethostbyaddr_r() takes 8 args */ -#define HAVE_GETHOSTBYADDR_R_8 1 - -/* Define to 1 if you have the gethostbyname function. */ -#define HAVE_GETHOSTBYNAME 1 - -/* Define to 1 if you have the gethostbyname_r function. */ -/* #undef HAVE_GETHOSTBYNAME_R */ - -/* gethostbyname_r() takes 3 args */ -/* #undef HAVE_GETHOSTBYNAME_R_3 */ - -/* gethostbyname_r() takes 5 args */ -/* #undef HAVE_GETHOSTBYNAME_R_5 */ - -/* gethostbyname_r() takes 6 args */ -/* #undef HAVE_GETHOSTBYNAME_R_6 */ - -/* Define to 1 if you have the gethostname function. */ -#define HAVE_GETHOSTNAME 1 - -/* Define to 1 if you have a working getifaddrs function. */ -/* #undef HAVE_GETIFADDRS */ - -/* Define to 1 if you have the getnameinfo function. */ -#define HAVE_GETNAMEINFO 1 - -/* Define to 1 if you have the `getpass_r' function. */ -/* #undef HAVE_GETPASS_R */ - -/* Define to 1 if you have the `getppid' function. */ -#define HAVE_GETPPID 1 - -/* Define to 1 if you have the `getprotobyname' function. */ -#define HAVE_GETPROTOBYNAME 1 - -/* Define to 1 if you have the `getpwuid' function. */ -/* #undef HAVE_GETPWUID */ - -/* Define to 1 if you have the `getrlimit' function. */ -#define HAVE_GETRLIMIT 1 - -/* Define to 1 if you have the getservbyport_r function. */ -/* #undef HAVE_GETSERVBYPORT_R */ - -/* Define to 1 if you have the `gettimeofday' function. */ -/* #undef HAVE_GETTIMEOFDAY */ - -/* Define to 1 if you have a working glibc-style strerror_r function. */ -/* #undef HAVE_GLIBC_STRERROR_R */ - -/* Define to 1 if you have a working gmtime_r function. */ -#define HAVE_GMTIME_R 1 - -/* if you have the gssapi libraries */ -/* #undef HAVE_GSSAPI */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_GSSAPI_GSSAPI_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */ - -/* if you have the GNU gssapi libraries */ -/* #undef HAVE_GSSGNU */ - -/* if you have the Heimdal gssapi libraries */ -/* #undef HAVE_GSSHEIMDAL */ - -/* if you have the MIT gssapi libraries */ -/* #undef HAVE_GSSMIT */ - -/* Define to 1 if you have the `idna_strerror' function. */ -/* #undef HAVE_IDNA_STRERROR */ - -/* Define to 1 if you have the `idn_free' function. */ -/* #undef HAVE_IDN_FREE */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IDN_FREE_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IFADDRS_H */ - -/* Define to 1 if you have the `inet_addr' function. */ -#define HAVE_INET_ADDR 1 - -/* Define to 1 if you have the inet_ntoa_r function. */ -/* #undef HAVE_INET_NTOA_R */ - -/* inet_ntoa_r() takes 2 args */ -/* #undef HAVE_INET_NTOA_R_2 */ - -/* inet_ntoa_r() takes 3 args */ -/* #undef HAVE_INET_NTOA_R_3 */ - -/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ -/* #undef HAVE_INET_NTOP */ - -/* Define to 1 if you have a IPv6 capable working inet_pton function. */ -/* #undef HAVE_INET_PTON */ - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the ioctl function. */ -#define HAVE_IOCTL 1 - -/* Define to 1 if you have the ioctlsocket function. */ -/* #undef HAVE_IOCTLSOCKET */ - -/* Define to 1 if you have the IoctlSocket camel case function. */ -/* #undef HAVE_IOCTLSOCKET_CAMEL */ - -/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. - */ -/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ - -/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ -/* #undef HAVE_IOCTLSOCKET_FIONBIO */ - -/* Define to 1 if you have a working ioctl FIONBIO function. */ -#define HAVE_IOCTL_FIONBIO 1 - -/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ -#define HAVE_IOCTL_SIOCGIFADDR 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_IO_H 1 - -/* if you have the Kerberos4 libraries (including -ldes) */ -/* #undef HAVE_KRB4 */ - -/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ -/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_KRB_H */ - -/* Define to 1 if you have the lber.h header file. */ -/* #undef HAVE_LBER_H */ - -/* Define to 1 if you have the ldapssl.h header file. */ -/* #undef HAVE_LDAPSSL_H */ - -/* Define to 1 if you have the ldap.h header file. */ -/* #undef HAVE_LDAP_H */ - -/* Use LDAPS implementation */ -/* #undef HAVE_LDAP_SSL */ - -/* Define to 1 if you have the ldap_ssl.h header file. */ -/* #undef HAVE_LDAP_SSL_H */ - -/* Define to 1 if you have the `ldap_url_parse' function. */ -/* #undef HAVE_LDAP_URL_PARSE */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBGEN_H */ - -/* Define to 1 if you have the `idn' library (-lidn). */ -/* #undef HAVE_LIBIDN */ - -/* Define to 1 if you have the `resolv' library (-lresolv). */ -/* #undef HAVE_LIBRESOLV */ - -/* Define to 1 if you have the `resolve' library (-lresolve). */ -/* #undef HAVE_LIBRESOLVE */ - -/* Define to 1 if you have the `socket' library (-lsocket). */ -/* #undef HAVE_LIBSOCKET */ - -/* Define to 1 if you have the `ssh2' library (-lssh2). */ -/* #undef HAVE_LIBSSH2 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBSSH2_H */ - -/* Define to 1 if you have the `libssh2_version' function. */ -/* #undef HAVE_LIBSSH2_VERSION */ - -/* Define to 1 if you have the `ssl' library (-lssl). */ -#define HAVE_LIBSSL 1 - -/* if zlib is available */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* if your compiler supports LL */ -#define HAVE_LL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if you have a working localtime_r function. */ -#define HAVE_LOCALTIME_R 1 - -/* Define to 1 if the compiler supports the 'long long' data type. */ -#define HAVE_LONGLONG 1 - -/* Define to 1 if you have the malloc.h header file. */ -#define HAVE_MALLOC_H 1 - -/* Define to 1 if you have the memory.h header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the MSG_NOSIGNAL flag. */ -/* #undef HAVE_MSG_NOSIGNAL */ - -/* Define to 1 if you have the header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_TCP_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NET_IF_H 1 - -/* Define to 1 if NI_WITHSCOPEID exists and works. */ -/* #undef HAVE_NI_WITHSCOPEID */ - -/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE - */ -/* #undef HAVE_OLD_GSSMIT */ - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_CRYPTO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_ENGINE_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_ERR_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_PEM_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_PKCS12_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_RSA_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_SSL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_X509_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PEM_H */ - -/* Define to 1 if you have the `perror' function. */ -#define HAVE_PERROR 1 - -/* Define to 1 if you have the `pipe' function. */ -#define HAVE_PIPE 1 - -/* Define to 1 if you have a working poll function. */ -/* #undef HAVE_POLL */ - -/* If you have a fine poll */ -/* #undef HAVE_POLL_FINE */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_POLL_H */ - -/* Define to 1 if you have a working POSIX-style strerror_r function. */ -/* #undef HAVE_POSIX_STRERROR_R */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PWD_H */ - -/* Define to 1 if you have the `RAND_egd' function. */ -#define HAVE_RAND_EGD 1 - -/* Define to 1 if you have the `RAND_screen' function. */ -/* #undef HAVE_RAND_SCREEN */ - -/* Define to 1 if you have the `RAND_status' function. */ -#define HAVE_RAND_STATUS 1 - -/* Define to 1 if you have the recv function. */ -#define HAVE_RECV 1 - -/* Define to 1 if you have the recvfrom function. */ -#define HAVE_RECVFROM 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_RSA_H */ - -/* Define to 1 if you have the select function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the send function. */ -#define HAVE_SEND 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SETJMP_H 1 - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the `setmode' function. */ -#define HAVE_SETMODE 1 - -/* Define to 1 if you have the `setrlimit' function. */ -#define HAVE_SETRLIMIT 1 - -/* Define to 1 if you have the setsockopt function. */ -#define HAVE_SETSOCKOPT 1 - -/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ -/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SGTTY_H */ - -/* Define to 1 if you have the sigaction function. */ -#define HAVE_SIGACTION 1 - -/* Define to 1 if you have the siginterrupt function. */ -#define HAVE_SIGINTERRUPT 1 - -/* Define to 1 if you have the signal function. */ -#define HAVE_SIGNAL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the sigsetjmp function or macro. */ -/* #undef HAVE_SIGSETJMP */ - -/* Define to 1 if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - -/* Define to 1 if sig_atomic_t is already defined as volatile. */ -/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ - -/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ -#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define to 1 if you have the `SSL_get_shutdown' function. */ -#define HAVE_SSL_GET_SHUTDOWN 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SSL_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDBOOL_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STDINT_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the strcasecmp function. */ -#define HAVE_STRCASECMP 1 - -/* Define to 1 if you have the strcmpi function. */ -/* #undef HAVE_STRCMPI */ - -/* Define to 1 if you have the strdup function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the strerror_r function. */ -#define HAVE_STRERROR_R 1 - -/* Define to 1 if you have the stricmp function. */ -/* #undef HAVE_STRICMP */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strlcpy' function. */ -/* #undef HAVE_STRLCPY */ - -/* Define to 1 if you have the strncasecmp function. */ -#define HAVE_STRNCASECMP 1 - -/* Define to 1 if you have the strncmpi function. */ -/* #undef HAVE_STRNCMPI */ - -/* Define to 1 if you have the strnicmp function. */ -/* #undef HAVE_STRNICMP */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STROPTS_H */ - -/* Define to 1 if you have the strstr function. */ -#define HAVE_STRSTR 1 - -/* Define to 1 if you have the strtok_r function. */ -#define HAVE_STRTOK_R 1 - -/* Define to 1 if you have the strtoll function. */ -/* #undef HAVE_STRTOLL */ - -/* if struct sockaddr_storage is defined */ -#define HAVE_STRUCT_SOCKADDR_STORAGE 1 - -/* Define to 1 if you have the timeval struct. */ -#define HAVE_STRUCT_TIMEVAL 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_FILIO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_PARAM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_POLL_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_RESOURCE_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SELECT_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOCKIO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_TIME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UTIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_TERMIOS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_TERMIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TLD_H */ - -/* Define to 1 if you have the `tld_strerror' function. */ -/* #undef HAVE_TLD_STRERROR */ - -/* Define to 1 if you have the `uname' function. */ -#define HAVE_UNAME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UTIME_H 1 - -/* Define to 1 if compiler supports C99 variadic macro style. */ -#define HAVE_VARIADIC_MACROS_C99 1 - -/* Define to 1 if compiler supports old gcc variadic macro style. */ -#define HAVE_VARIADIC_MACROS_GCC 1 - -/* Define to 1 if you have a working vxworks-style strerror_r function. */ -#define HAVE_VXWORKS_STRERROR_R 1 - -/* Define to 1 if you have the winber.h header file. */ -/* #undef HAVE_WINBER_H */ - -/* Define to 1 if you have the windows.h header file. */ -/* #undef HAVE_WINDOWS_H */ - -/* Define to 1 if you have the winldap.h header file. */ -/* #undef HAVE_WINLDAP_H */ - -/* Define to 1 if you have the winsock2.h header file. */ -/* #undef HAVE_WINSOCK2_H */ - -/* Define to 1 if you have the winsock.h header file. */ -/* #undef HAVE_WINSOCK_H */ - -/* Define this symbol if your OS supports changing the contents of argv */ -#define HAVE_WRITABLE_ARGV 1 - -/* Define to 1 if you have the writev function. */ -#define HAVE_WRITEV 1 - -/* Define to 1 if you have the ws2tcpip.h header file. */ -/* #undef HAVE_WS2TCPIP_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_X509_H */ - -/* if you have the zlib.h header file */ -#define HAVE_ZLIB_H 1 - -/* Define to 1 if you need the lber.h header file even with ldap.h */ -/* #undef NEED_LBER_H */ - -/* Define to 1 if you need the malloc.h header file even with stdlib.h */ -/* #undef NEED_MALLOC_H */ - -/* Define to 1 if you need the memory.h header file even with stdlib.h */ -/* #undef NEED_MEMORY_H */ - -/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ -/* #undef NEED_REENTRANT */ - -/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ -/* #undef NEED_THREAD_SAFE */ - -/* Define to 1 if the open function requires three arguments. */ -#define OPEN_NEEDS_ARG3 1 - -/* cpu-machine-OS */ -#define OS "unknown-unknown-vxworks" - -/* Name of package */ -#define PACKAGE "curl" - -/* a suitable file to read random data from */ -#define RANDOM_FILE "/dev/urandom" - -/* Define to the type of arg 1 for recvfrom. */ -#define RECVFROM_TYPE_ARG1 int - -/* Define to the type pointed by arg 2 for recvfrom. */ -#define RECVFROM_TYPE_ARG2 void - -/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ -#define RECVFROM_TYPE_ARG2_IS_VOID 1 - -/* Define to the type of arg 3 for recvfrom. */ -#define RECVFROM_TYPE_ARG3 size_t - -/* Define to the type of arg 4 for recvfrom. */ -#define RECVFROM_TYPE_ARG4 int - -/* Define to the type pointed by arg 5 for recvfrom. */ -#define RECVFROM_TYPE_ARG5 struct sockaddr - -/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ -/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ - -/* Define to the type pointed by arg 6 for recvfrom. */ -#define RECVFROM_TYPE_ARG6 socklen_t - -/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ -/* #undef RECVFROM_TYPE_ARG6_IS_VOID */ - -/* Define to the function return type for recvfrom. */ -#define RECVFROM_TYPE_RETV int - -/* Define to the type of arg 1 for recv. */ -#define RECV_TYPE_ARG1 int - -/* Define to the type of arg 2 for recv. */ -#define RECV_TYPE_ARG2 void * - -/* Define to the type of arg 3 for recv. */ -#define RECV_TYPE_ARG3 size_t - -/* Define to the type of arg 4 for recv. */ -#define RECV_TYPE_ARG4 int - -/* Define to the function return type for recv. */ -#define RECV_TYPE_RETV int - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* Define to the type qualifier of arg 5 for select. */ -#define SELECT_QUAL_ARG5 - -/* Define to the type of arg 1 for select. */ -#define SELECT_TYPE_ARG1 int - -/* Define to the type of args 2, 3 and 4 for select. */ -#define SELECT_TYPE_ARG234 fd_set * - -/* Define to the type of arg 5 for select. */ -#define SELECT_TYPE_ARG5 struct timeval * - -/* Define to the function return type for select. */ -#define SELECT_TYPE_RETV int - -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 const - -/* Define to the type of arg 1 for send. */ -#define SEND_TYPE_ARG1 int - -/* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 void * - -/* Define to the type of arg 3 for send. */ -#define SEND_TYPE_ARG3 size_t - -/* Define to the type of arg 4 for send. */ -#define SEND_TYPE_ARG4 int - -/* Define to the function return type for send. */ -#define SEND_TYPE_RETV int - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of `long', as computed by sizeof. */ -#define SIZEOF_LONG 4 - -/* The size of `off_t', as computed by sizeof. */ -#define SIZEOF_OFF_T 8 - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* The size of `size_t', as computed by sizeof. */ -#define SIZEOF_SIZE_T 4 - -/* The size of `time_t', as computed by sizeof. */ -#define SIZEOF_TIME_T 4 - -/* The size of `void*', as computed by sizeof. */ -#define SIZEOF_VOIDP 4 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to the type of arg 3 for strerror_r. */ -/* #undef STRERROR_R_TYPE_ARG3 */ - -/* Define to 1 if you can safely include both and . */ -/* #undef TIME_WITH_SYS_TIME */ - -/* Define if you want to enable c-ares support */ -/* #undef USE_ARES */ - -/* Define to disable non-blocking sockets. */ -/* #undef USE_BLOCKING_SOCKETS */ - -/* if GnuTLS is enabled */ -/* #undef USE_GNUTLS */ - -/* if libSSH2 is in use */ -/* #undef USE_LIBSSH2 */ - -/* If you want to build curl with the built-in manual */ -#define USE_MANUAL 1 - -/* if NSS is enabled */ -/* #undef USE_NSS */ - -/* if OpenSSL is in use */ -#define USE_OPENSSL 1 - -/* Define to 1 if you are building a Windows target without large file - support. */ -/* #undef USE_WIN32_LARGE_FILES */ - -/* to enable SSPI support */ -/* #undef USE_WINDOWS_SSPI */ - -/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ -/* #undef USE_YASSLEMUL */ - -/* Define to avoid automatic inclusion of winsock.h */ -/* #undef WIN32_LEAN_AND_MEAN */ - -/* Define to 1 if OS is AIX. */ -#ifndef _ALL_SOURCE -/* # undef _ALL_SOURCE */ -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Type to use in place of in_addr_t when system does not provide it. */ -/* #undef in_addr_t */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* the signed version of size_t */ -/* #undef ssize_t */ - -#endif /* HEADER_CURL_CONFIG_VXWORKS_H */ diff --git a/dep/cpr/opt/curl/lib/config-win32.h b/dep/cpr/opt/curl/lib/config-win32.h deleted file mode 100644 index 00191fe4c8f..00000000000 --- a/dep/cpr/opt/curl/lib/config-win32.h +++ /dev/null @@ -1,742 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_WIN32_H -#define HEADER_CURL_CONFIG_WIN32_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* ================================================================ */ -/* Hand crafted config file for Windows */ -/* ================================================================ */ - -/* ---------------------------------------------------------------- */ -/* HEADER FILES */ -/* ---------------------------------------------------------------- */ - -/* Define if you have the header file. */ -/* #define HAVE_ARPA_INET_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_ASSERT_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_CRYPTO_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_ERR_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the header file. */ -#if defined(__MINGW32__) || defined(__POCC__) -#define HAVE_GETOPT_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1800) -#define HAVE_INTTYPES_H 1 -#endif - -/* Define if you have the header file. */ -#define HAVE_IO_H 1 - -/* Define if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define if you need header even with header file. */ -#if !defined(__SALFORDC__) && !defined(__POCC__) -#define NEED_MALLOC_H 1 -#endif - -/* Define if you have the header file. */ -/* #define HAVE_NETDB_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_NETINET_IN_H 1 */ - -/* Define if you have the header file. */ -#ifndef __SALFORDC__ -#define HAVE_PROCESS_H 1 -#endif - -/* Define if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SGTTY_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SSL_H 1 */ - -/* Define to 1 if you have the header file. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1800) -#define HAVE_STDBOOL_H 1 -#endif - -/* Define if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SYS_PARAM_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_SELECT_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_SOCKET_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_SOCKIO_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SYS_TIME_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define if you have the header file. */ -#ifndef __BORLANDC__ -#define HAVE_SYS_UTIME_H 1 -#endif - -/* Define if you have the header file. */ -/* #define HAVE_TERMIO_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_TERMIOS_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define if you have the header file. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \ - defined(__POCC__) -#define HAVE_UNISTD_H 1 -#endif - -/* Define if you have the header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define if you have the header file. */ -#define HAVE_WINSOCK_H 1 - -/* Define if you have the header file. */ -#ifndef __SALFORDC__ -#define HAVE_WINSOCK2_H 1 -#endif - -/* Define if you have the header file. */ -#ifndef __SALFORDC__ -#define HAVE_WS2TCPIP_H 1 -#endif - -/* ---------------------------------------------------------------- */ -/* OTHER HEADER INFO */ -/* ---------------------------------------------------------------- */ - -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you can safely include both and . */ -/* #define TIME_WITH_SYS_TIME 1 */ - -/* Define to 1 if bool is an available type. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1800) -#define HAVE_BOOL_T 1 -#endif - -/* ---------------------------------------------------------------- */ -/* FUNCTIONS */ -/* ---------------------------------------------------------------- */ - -/* Define if you have the closesocket function. */ -#define HAVE_CLOSESOCKET 1 - -/* Define if you don't have vprintf but do have _doprnt. */ -/* #define HAVE_DOPRNT 1 */ - -/* Define if you have the ftruncate function. */ -#define HAVE_FTRUNCATE 1 - -/* Define if you have the gethostbyaddr function. */ -#define HAVE_GETHOSTBYADDR 1 - -/* Define if you have the gethostname function. */ -#define HAVE_GETHOSTNAME 1 - -/* Define if you have the getpass function. */ -/* #define HAVE_GETPASS 1 */ - -/* Define if you have the getservbyname function. */ -#define HAVE_GETSERVBYNAME 1 - -/* Define if you have the getprotobyname function. */ -#define HAVE_GETPROTOBYNAME - -/* Define if you have the gettimeofday function. */ -/* #define HAVE_GETTIMEOFDAY 1 */ - -/* Define if you have the inet_addr function. */ -#define HAVE_INET_ADDR 1 - -/* Define if you have the ioctlsocket function. */ -#define HAVE_IOCTLSOCKET 1 - -/* Define if you have a working ioctlsocket FIONBIO function. */ -#define HAVE_IOCTLSOCKET_FIONBIO 1 - -/* Define if you have the perror function. */ -#define HAVE_PERROR 1 - -/* Define if you have the RAND_screen function when using SSL. */ -#define HAVE_RAND_SCREEN 1 - -/* Define if you have the `RAND_status' function when using SSL. */ -#define HAVE_RAND_STATUS 1 - -/* Define if you have the `CRYPTO_cleanup_all_ex_data' function. - This is present in OpenSSL versions after 0.9.6b */ -#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 - -/* Define if you have the select function. */ -#define HAVE_SELECT 1 - -/* Define if you have the setlocale function. */ -#define HAVE_SETLOCALE 1 - -/* Define if you have the setmode function. */ -#define HAVE_SETMODE 1 - -/* Define if you have the setvbuf function. */ -#define HAVE_SETVBUF 1 - -/* Define if you have the socket function. */ -#define HAVE_SOCKET 1 - -/* Define if you have the strcasecmp function. */ -/* #define HAVE_STRCASECMP 1 */ - -/* Define if you have the strdup function. */ -#define HAVE_STRDUP 1 - -/* Define if you have the strftime function. */ -#define HAVE_STRFTIME 1 - -/* Define if you have the stricmp function. */ -#define HAVE_STRICMP 1 - -/* Define if you have the strncasecmp function. */ -/* #define HAVE_STRNCASECMP 1 */ - -/* Define if you have the strnicmp function. */ -#define HAVE_STRNICMP 1 - -/* Define if you have the strstr function. */ -#define HAVE_STRSTR 1 - -/* Define if you have the strtoll function. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__) || \ - (defined(_MSC_VER) && (_MSC_VER >= 1800)) -#define HAVE_STRTOLL 1 -#endif - -/* Define if you have the tcgetattr function. */ -/* #define HAVE_TCGETATTR 1 */ - -/* Define if you have the tcsetattr function. */ -/* #define HAVE_TCSETATTR 1 */ - -/* Define if you have the utime function. */ -#ifndef __BORLANDC__ -#define HAVE_UTIME 1 -#endif - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -#define GETNAMEINFO_QUAL_ARG1 const - -/* Define to the type of arg 1 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * - -/* Define to the type of arg 2 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG2 socklen_t - -/* Define to the type of args 4 and 6 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG46 DWORD - -/* Define to the type of arg 7 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG7 int - -/* Define if you have the recv function. */ -#define HAVE_RECV 1 - -/* Define to the type of arg 1 for recv. */ -#define RECV_TYPE_ARG1 SOCKET - -/* Define to the type of arg 2 for recv. */ -#define RECV_TYPE_ARG2 char * - -/* Define to the type of arg 3 for recv. */ -#define RECV_TYPE_ARG3 int - -/* Define to the type of arg 4 for recv. */ -#define RECV_TYPE_ARG4 int - -/* Define to the function return type for recv. */ -#define RECV_TYPE_RETV int - -/* Define if you have the recvfrom function. */ -#define HAVE_RECVFROM 1 - -/* Define to the type of arg 1 for recvfrom. */ -#define RECVFROM_TYPE_ARG1 SOCKET - -/* Define to the type pointed by arg 2 for recvfrom. */ -#define RECVFROM_TYPE_ARG2 char - -/* Define to the type of arg 3 for recvfrom. */ -#define RECVFROM_TYPE_ARG3 int - -/* Define to the type of arg 4 for recvfrom. */ -#define RECVFROM_TYPE_ARG4 int - -/* Define to the type pointed by arg 5 for recvfrom. */ -#define RECVFROM_TYPE_ARG5 struct sockaddr - -/* Define to the type pointed by arg 6 for recvfrom. */ -#define RECVFROM_TYPE_ARG6 int - -/* Define to the function return type for recvfrom. */ -#define RECVFROM_TYPE_RETV int - -/* Define if you have the send function. */ -#define HAVE_SEND 1 - -/* Define to the type of arg 1 for send. */ -#define SEND_TYPE_ARG1 SOCKET - -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 const - -/* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 char * - -/* Define to the type of arg 3 for send. */ -#define SEND_TYPE_ARG3 int - -/* Define to the type of arg 4 for send. */ -#define SEND_TYPE_ARG4 int - -/* Define to the function return type for send. */ -#define SEND_TYPE_RETV int - -/* ---------------------------------------------------------------- */ -/* TYPEDEF REPLACEMENTS */ -/* ---------------------------------------------------------------- */ - -/* Define if in_addr_t is not an available 'typedefed' type. */ -#define in_addr_t unsigned long - -/* Define to the return type of signal handlers (int or void). */ -#define RETSIGTYPE void - -/* Define if ssize_t is not an available 'typedefed' type. */ -#ifndef _SSIZE_T_DEFINED -# if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \ - defined(__POCC__) || \ - defined(__MINGW32__) -# elif defined(_WIN64) -# define _SSIZE_T_DEFINED -# define ssize_t __int64 -# else -# define _SSIZE_T_DEFINED -# define ssize_t int -# endif -#endif - -/* ---------------------------------------------------------------- */ -/* TYPE SIZES */ -/* ---------------------------------------------------------------- */ - -/* Define to the size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* Define to the size of `long double', as computed by sizeof. */ -#define SIZEOF_LONG_DOUBLE 16 - -/* Define to the size of `long long', as computed by sizeof. */ -/* #define SIZEOF_LONG_LONG 8 */ - -/* Define to the size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* Define to the size of `long', as computed by sizeof. */ -#define SIZEOF_LONG 4 - -/* Define to the size of `size_t', as computed by sizeof. */ -#if defined(_WIN64) -# define SIZEOF_SIZE_T 8 -#else -# define SIZEOF_SIZE_T 4 -#endif - -/* Define to the size of `curl_off_t', as computed by sizeof. */ -#define SIZEOF_CURL_OFF_T 8 - -/* ---------------------------------------------------------------- */ -/* BSD-style lwIP TCP/IP stack SPECIFIC */ -/* ---------------------------------------------------------------- */ - -/* Define to use BSD-style lwIP TCP/IP stack. */ -/* #define USE_LWIPSOCK 1 */ - -#ifdef USE_LWIPSOCK -# undef USE_WINSOCK -# undef HAVE_WINSOCK_H -# undef HAVE_WINSOCK2_H -# undef HAVE_WS2TCPIP_H -# undef HAVE_ERRNO_H -# undef HAVE_GETHOSTNAME -# undef HAVE_GETNAMEINFO -# undef LWIP_POSIX_SOCKETS_IO_NAMES -# undef RECV_TYPE_ARG1 -# undef RECV_TYPE_ARG3 -# undef SEND_TYPE_ARG1 -# undef SEND_TYPE_ARG3 -# define HAVE_FREEADDRINFO -# define HAVE_GETADDRINFO -# define HAVE_GETHOSTBYNAME -# define HAVE_GETHOSTBYNAME_R -# define HAVE_GETHOSTBYNAME_R_6 -# define LWIP_POSIX_SOCKETS_IO_NAMES 0 -# define RECV_TYPE_ARG1 int -# define RECV_TYPE_ARG3 size_t -# define SEND_TYPE_ARG1 int -# define SEND_TYPE_ARG3 size_t -#endif - -/* ---------------------------------------------------------------- */ -/* Watt-32 tcp/ip SPECIFIC */ -/* ---------------------------------------------------------------- */ - -#ifdef USE_WATT32 - #include - #undef byte - #undef word - #undef USE_WINSOCK - #undef HAVE_WINSOCK_H - #undef HAVE_WINSOCK2_H - #undef HAVE_WS2TCPIP_H - #define HAVE_GETADDRINFO - #define HAVE_GETNAMEINFO - #define HAVE_SYS_IOCTL_H - #define HAVE_SYS_SOCKET_H - #define HAVE_NETINET_IN_H - #define HAVE_NETDB_H - #define HAVE_ARPA_INET_H - #define HAVE_FREEADDRINFO - #define SOCKET int -#endif - - -/* ---------------------------------------------------------------- */ -/* COMPILER SPECIFIC */ -/* ---------------------------------------------------------------- */ - -/* Define to nothing if compiler does not support 'const' qualifier. */ -/* #define const */ - -/* Define to nothing if compiler does not support 'volatile' qualifier. */ -/* #define volatile */ - -/* Windows should not have HAVE_GMTIME_R defined */ -/* #undef HAVE_GMTIME_R */ - -/* Define if the compiler supports C99 variadic macro style. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define HAVE_VARIADIC_MACROS_C99 1 -#endif - -/* Define if the compiler supports the 'long long' data type. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) || \ - (defined(_MSC_VER) && (_MSC_VER >= 1310)) || \ - (defined(__BORLANDC__) && (__BORLANDC__ >= 0x561)) -#define HAVE_LONGLONG 1 -#endif - -/* Define to avoid VS2005 complaining about portable C functions. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define _CRT_SECURE_NO_DEPRECATE 1 -#define _CRT_NONSTDC_NO_DEPRECATE 1 -#endif - -/* VS2005 and later default size for time_t is 64-bit, unless - _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -# ifndef _USE_32BIT_TIME_T -# define SIZEOF_TIME_T 8 -# else -# define SIZEOF_TIME_T 4 -# endif -#endif - -/* Define some minimum and default build targets for Visual Studio */ -#if defined(_MSC_VER) - /* Officially, Microsoft's Windows SDK versions 6.X does not support Windows - 2000 as a supported build target. VS2008 default installations provides - an embedded Windows SDK v6.0A along with the claim that Windows 2000 is a - valid build target for VS2008. Popular belief is that binaries built with - VS2008 using Windows SDK versions v6.X and Windows 2000 as a build target - are functional. */ -# define VS2008_MIN_TARGET 0x0500 - - /* The minimum build target for VS2012 is Vista unless Update 1 is installed - and the v110_xp toolset is chosen. */ -# if defined(_USING_V110_SDK71_) -# define VS2012_MIN_TARGET 0x0501 -# else -# define VS2012_MIN_TARGET 0x0600 -# endif - - /* VS2008 default build target is Windows Vista. We override default target - to be Windows XP. */ -# define VS2008_DEF_TARGET 0x0501 - - /* VS2012 default build target is Windows Vista unless Update 1 is installed - and the v110_xp toolset is chosen. */ -# if defined(_USING_V110_SDK71_) -# define VS2012_DEF_TARGET 0x0501 -# else -# define VS2012_DEF_TARGET 0x0600 -# endif -#endif - -/* VS2008 default target settings and minimum build target check. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_MSC_VER <= 1600) -# ifndef _WIN32_WINNT -# define _WIN32_WINNT VS2008_DEF_TARGET -# endif -# ifndef WINVER -# define WINVER VS2008_DEF_TARGET -# endif -# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET) -# error VS2008 does not support Windows build targets prior to Windows 2000 -# endif -#endif - -/* VS2012 default target settings and minimum build target check. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1700) -# ifndef _WIN32_WINNT -# define _WIN32_WINNT VS2012_DEF_TARGET -# endif -# ifndef WINVER -# define WINVER VS2012_DEF_TARGET -# endif -# if (_WIN32_WINNT < VS2012_MIN_TARGET) || (WINVER < VS2012_MIN_TARGET) -# if defined(_USING_V110_SDK71_) -# error VS2012 does not support Windows build targets prior to Windows XP -# else -# error VS2012 does not support Windows build targets prior to Windows \ -Vista -# endif -# endif -#endif - -/* When no build target is specified Pelles C 5.00 and later default build - target is Windows Vista. We override default target to be Windows 2000. */ -#if defined(__POCC__) && (__POCC__ >= 500) -# ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0500 -# endif -# ifndef WINVER -# define WINVER 0x0500 -# endif -#endif - -/* Availability of freeaddrinfo, getaddrinfo and getnameinfo functions is - quite convoluted, compiler dependent and even build target dependent. */ -#if defined(HAVE_WS2TCPIP_H) -# if defined(__POCC__) -# define HAVE_FREEADDRINFO 1 -# define HAVE_GETADDRINFO 1 -# define HAVE_GETADDRINFO_THREADSAFE 1 -# define HAVE_GETNAMEINFO 1 -# elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) -# define HAVE_FREEADDRINFO 1 -# define HAVE_GETADDRINFO 1 -# define HAVE_GETADDRINFO_THREADSAFE 1 -# define HAVE_GETNAMEINFO 1 -# elif defined(_MSC_VER) && (_MSC_VER >= 1200) -# define HAVE_FREEADDRINFO 1 -# define HAVE_GETADDRINFO 1 -# define HAVE_GETADDRINFO_THREADSAFE 1 -# define HAVE_GETNAMEINFO 1 -# endif -#endif - -#if defined(__POCC__) -# ifndef _MSC_VER -# error Microsoft extensions /Ze compiler option is required -# endif -# ifndef __POCC__OLDNAMES -# error Compatibility names /Go compiler option is required -# endif -#endif - -/* ---------------------------------------------------------------- */ -/* STRUCT RELATED */ -/* ---------------------------------------------------------------- */ - -/* Define if you have struct sockaddr_storage. */ -#if !defined(__SALFORDC__) && !defined(__BORLANDC__) -#define HAVE_STRUCT_SOCKADDR_STORAGE 1 -#endif - -/* Define if you have struct timeval. */ -#define HAVE_STRUCT_TIMEVAL 1 - -/* Define if struct sockaddr_in6 has the sin6_scope_id member. */ -#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 - -#if defined(HAVE_WINSOCK2_H) && defined(_WIN32_WINNT) && \ - (_WIN32_WINNT >= 0x0600) -#define HAVE_STRUCT_POLLFD 1 -#endif - -/* ---------------------------------------------------------------- */ -/* LARGE FILE SUPPORT */ -/* ---------------------------------------------------------------- */ - -#if defined(_MSC_VER) && !defined(_WIN32_WCE) -# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) -# define USE_WIN32_LARGE_FILES -# else -# define USE_WIN32_SMALL_FILES -# endif -#endif - -#if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES) -# define USE_WIN32_LARGE_FILES -#endif - -#if defined(__WATCOMC__) && !defined(USE_WIN32_LARGE_FILES) -# define USE_WIN32_LARGE_FILES -#endif - -#if defined(__POCC__) -# undef USE_WIN32_LARGE_FILES -#endif - -#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES) -# define USE_WIN32_SMALL_FILES -#endif - -/* ---------------------------------------------------------------- */ -/* DNS RESOLVER SPECIALTY */ -/* ---------------------------------------------------------------- */ - -/* - * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS. - */ - -/* Define to enable c-ares asynchronous DNS lookups. */ -/* #define USE_ARES 1 */ - -/* Default define to enable threaded asynchronous DNS lookups. */ -#if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && \ - !defined(USE_THREADS_WIN32) -# define USE_THREADS_WIN32 1 -#endif - -#if defined(USE_ARES) && defined(USE_THREADS_WIN32) -# error "Only one DNS lookup specialty may be defined at most" -#endif - -/* ---------------------------------------------------------------- */ -/* LDAP SUPPORT */ -/* ---------------------------------------------------------------- */ - -#if defined(CURL_HAS_NOVELL_LDAPSDK) || defined(CURL_HAS_MOZILLA_LDAPSDK) -#undef USE_WIN32_LDAP -#define HAVE_LDAP_SSL_H 1 -#define HAVE_LDAP_URL_PARSE 1 -#elif defined(CURL_HAS_OPENLDAP_LDAPSDK) -#undef USE_WIN32_LDAP -#define HAVE_LDAP_URL_PARSE 1 -#else -#undef HAVE_LDAP_URL_PARSE -#define USE_WIN32_LDAP 1 -#endif - -#if defined(__WATCOMC__) && defined(USE_WIN32_LDAP) -#if __WATCOMC__ < 1280 -#define WINBERAPI __declspec(cdecl) -#define WINLDAPAPI __declspec(cdecl) -#endif -#endif - -#if defined(__POCC__) && defined(USE_WIN32_LDAP) -# define CURL_DISABLE_LDAP 1 -#endif - -/* Define to use the Windows crypto library. */ -#if !defined(USE_OPENSSL) && !defined(USE_NSS) -#define USE_WIN32_CRYPTO -#endif - -/* ---------------------------------------------------------------- */ -/* ADDITIONAL DEFINITIONS */ -/* ---------------------------------------------------------------- */ - -/* Define cpu-machine-OS */ -#undef OS -#if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */ -#define OS "i386-pc-win32" -#elif defined(_M_X64) || defined(__x86_64__) /* x86_64 (MSVC >=2005 or gcc) */ -#define OS "x86_64-pc-win32" -#elif defined(_M_IA64) /* Itanium */ -#define OS "ia64-pc-win32" -#else -#define OS "unknown-pc-win32" -#endif - -/* Name of package */ -#define PACKAGE "curl" - -/* If you want to build curl with the built-in manual */ -#define USE_MANUAL 1 - -#if defined(__POCC__) || defined(USE_IPV6) -# define ENABLE_IPV6 1 -#endif - -#endif /* HEADER_CURL_CONFIG_WIN32_H */ diff --git a/dep/cpr/opt/curl/lib/config-win32ce.h b/dep/cpr/opt/curl/lib/config-win32ce.h deleted file mode 100644 index 28a15f2a1bf..00000000000 --- a/dep/cpr/opt/curl/lib/config-win32ce.h +++ /dev/null @@ -1,451 +0,0 @@ -#ifndef HEADER_CURL_CONFIG_WIN32CE_H -#define HEADER_CURL_CONFIG_WIN32CE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* ================================================================ */ -/* lib/config-win32ce.h - Hand crafted config file for windows ce */ -/* ================================================================ */ - -/* ---------------------------------------------------------------- */ -/* HEADER FILES */ -/* ---------------------------------------------------------------- */ - -/* Define if you have the header file. */ -/* #define HAVE_ARPA_INET_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_ASSERT_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_CRYPTO_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_ERRNO_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_ERR_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_GETOPT_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_IO_H 1 - -/* Define if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define if you need the malloc.h header header file even with stdlib.h */ -#define NEED_MALLOC_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_NETDB_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_NETINET_IN_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SGTTY_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SSL_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_PROCESS_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_PARAM_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_SELECT_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_SOCKET_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_SOCKIO_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define if you have the header file */ -/* #define HAVE_SYS_TIME_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_TYPES_H 1 */ - -/* Define if you have the header file */ -#define HAVE_SYS_UTIME_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_TERMIO_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_TERMIOS_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define if you have the header file. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) -#define HAVE_UNISTD_H 1 -#endif - -/* Define if you have the header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define if you have the header file. */ -#define HAVE_WINSOCK_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_WINSOCK2_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_WS2TCPIP_H 1 */ - -/* ---------------------------------------------------------------- */ -/* OTHER HEADER INFO */ -/* ---------------------------------------------------------------- */ - -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you can safely include both and . */ -/* #define TIME_WITH_SYS_TIME 1 */ - -/* ---------------------------------------------------------------- */ -/* FUNCTIONS */ -/* ---------------------------------------------------------------- */ - -/* Define if you have the closesocket function. */ -#define HAVE_CLOSESOCKET 1 - -/* Define if you don't have vprintf but do have _doprnt. */ -/* #define HAVE_DOPRNT 1 */ - -/* Define if you have the gethostbyaddr function. */ -#define HAVE_GETHOSTBYADDR 1 - -/* Define if you have the gethostname function. */ -#define HAVE_GETHOSTNAME 1 - -/* Define if you have the getpass function. */ -/* #define HAVE_GETPASS 1 */ - -/* Define if you have the getservbyname function. */ -#define HAVE_GETSERVBYNAME 1 - -/* Define if you have the gettimeofday function. */ -/* #define HAVE_GETTIMEOFDAY 1 */ - -/* Define if you have the inet_addr function. */ -#define HAVE_INET_ADDR 1 - -/* Define if you have the ioctlsocket function. */ -#define HAVE_IOCTLSOCKET 1 - -/* Define if you have a working ioctlsocket FIONBIO function. */ -#define HAVE_IOCTLSOCKET_FIONBIO 1 - -/* Define if you have the perror function. */ -#define HAVE_PERROR 1 - -/* Define if you have the RAND_screen function when using SSL */ -#define HAVE_RAND_SCREEN 1 - -/* Define if you have the `RAND_status' function when using SSL. */ -#define HAVE_RAND_STATUS 1 - -/* Define if you have the select function. */ -#define HAVE_SELECT 1 - -/* Define if you have the setvbuf function. */ -#define HAVE_SETVBUF 1 - -/* Define if you have the socket function. */ -#define HAVE_SOCKET 1 - -/* Define if you have the strcasecmp function. */ -/* #define HAVE_STRCASECMP 1 */ - -/* Define if you have the strdup function. */ -/* #define HAVE_STRDUP 1 */ - -/* Define if you have the strftime function. */ -/* #define HAVE_STRFTIME 1 */ - -/* Define if you have the stricmp function. */ -/* #define HAVE_STRICMP 1 */ - -/* Define if you have the strncasecmp function. */ -/* #define HAVE_STRNCASECMP 1 */ - -/* Define if you have the strnicmp function. */ -/* #define HAVE_STRNICMP 1 */ - -/* Define if you have the strstr function. */ -#define HAVE_STRSTR 1 - -/* Define if you have the strtoll function. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) -#define HAVE_STRTOLL 1 -#endif - -/* Define if you have the tcgetattr function. */ -/* #define HAVE_TCGETATTR 1 */ - -/* Define if you have the tcsetattr function. */ -/* #define HAVE_TCSETATTR 1 */ - -/* Define if you have the utime function */ -#define HAVE_UTIME 1 - -/* Define if you have the getnameinfo function. */ -#define HAVE_GETNAMEINFO 1 - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -#define GETNAMEINFO_QUAL_ARG1 const - -/* Define to the type of arg 1 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * - -/* Define to the type of arg 2 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG2 socklen_t - -/* Define to the type of args 4 and 6 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG46 DWORD - -/* Define to the type of arg 7 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG7 int - -/* Define if you have the recv function. */ -#define HAVE_RECV 1 - -/* Define to the type of arg 1 for recv. */ -#define RECV_TYPE_ARG1 SOCKET - -/* Define to the type of arg 2 for recv. */ -#define RECV_TYPE_ARG2 char * - -/* Define to the type of arg 3 for recv. */ -#define RECV_TYPE_ARG3 int - -/* Define to the type of arg 4 for recv. */ -#define RECV_TYPE_ARG4 int - -/* Define to the function return type for recv. */ -#define RECV_TYPE_RETV int - -/* Define if you have the recvfrom function. */ -#define HAVE_RECVFROM 1 - -/* Define to the type of arg 1 for recvfrom. */ -#define RECVFROM_TYPE_ARG1 SOCKET - -/* Define to the type pointed by arg 2 for recvfrom. */ -#define RECVFROM_TYPE_ARG2 char - -/* Define to the type of arg 3 for recvfrom. */ -#define RECVFROM_TYPE_ARG3 int - -/* Define to the type of arg 4 for recvfrom. */ -#define RECVFROM_TYPE_ARG4 int - -/* Define to the type pointed by arg 5 for recvfrom. */ -#define RECVFROM_TYPE_ARG5 struct sockaddr - -/* Define to the type pointed by arg 6 for recvfrom. */ -#define RECVFROM_TYPE_ARG6 int - -/* Define to the function return type for recvfrom. */ -#define RECVFROM_TYPE_RETV int - -/* Define if you have the send function. */ -#define HAVE_SEND 1 - -/* Define to the type of arg 1 for send. */ -#define SEND_TYPE_ARG1 SOCKET - -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 const - -/* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 char * - -/* Define to the type of arg 3 for send. */ -#define SEND_TYPE_ARG3 int - -/* Define to the type of arg 4 for send. */ -#define SEND_TYPE_ARG4 int - -/* Define to the function return type for send. */ -#define SEND_TYPE_RETV int - -/* ---------------------------------------------------------------- */ -/* TYPEDEF REPLACEMENTS */ -/* ---------------------------------------------------------------- */ - -/* Define this if in_addr_t is not an available 'typedefed' type */ -#define in_addr_t unsigned long - -/* Define as the return type of signal handlers (int or void). */ -#define RETSIGTYPE void - -/* Define ssize_t if it is not an available 'typedefed' type */ -#if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || defined(__POCC__) -#elif defined(_WIN64) -#define ssize_t __int64 -#else -#define ssize_t int -#endif - -/* ---------------------------------------------------------------- */ -/* TYPE SIZES */ -/* ---------------------------------------------------------------- */ - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of `long double', as computed by sizeof. */ -#define SIZEOF_LONG_DOUBLE 16 - -/* The size of `long long', as computed by sizeof. */ -/* #define SIZEOF_LONG_LONG 8 */ - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* Define to the size of `long', as computed by sizeof. */ -#define SIZEOF_LONG 4 - -/* The size of `size_t', as computed by sizeof. */ -#if defined(_WIN64) -# define SIZEOF_SIZE_T 8 -#else -# define SIZEOF_SIZE_T 4 -#endif - -/* ---------------------------------------------------------------- */ -/* STRUCT RELATED */ -/* ---------------------------------------------------------------- */ - -/* Define this if you have struct sockaddr_storage */ -/* #define HAVE_STRUCT_SOCKADDR_STORAGE 1 */ - -/* Define this if you have struct timeval */ -#define HAVE_STRUCT_TIMEVAL 1 - -/* Define this if struct sockaddr_in6 has the sin6_scope_id member */ -#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 - -/* ---------------------------------------------------------------- */ -/* COMPILER SPECIFIC */ -/* ---------------------------------------------------------------- */ - -/* Undef keyword 'const' if it does not work. */ -/* #undef const */ - -/* Define to avoid VS2005 complaining about portable C functions */ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define _CRT_SECURE_NO_DEPRECATE 1 -#define _CRT_NONSTDC_NO_DEPRECATE 1 -#endif - -/* VS2005 and later default size for time_t is 64-bit, unless */ -/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -# ifndef _USE_32BIT_TIME_T -# define SIZEOF_TIME_T 8 -# else -# define SIZEOF_TIME_T 4 -# endif -#endif - -/* ---------------------------------------------------------------- */ -/* LARGE FILE SUPPORT */ -/* ---------------------------------------------------------------- */ - -#if defined(_MSC_VER) && !defined(_WIN32_WCE) -# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) -# define USE_WIN32_LARGE_FILES -# else -# define USE_WIN32_SMALL_FILES -# endif -#endif - -#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES) -# define USE_WIN32_SMALL_FILES -#endif - -/* ---------------------------------------------------------------- */ -/* LDAP SUPPORT */ -/* ---------------------------------------------------------------- */ - -#define USE_WIN32_LDAP 1 -#undef HAVE_LDAP_URL_PARSE - -/* ---------------------------------------------------------------- */ -/* ADDITIONAL DEFINITIONS */ -/* ---------------------------------------------------------------- */ - -/* Define cpu-machine-OS */ -#undef OS -#define OS "i386-pc-win32ce" - -/* Name of package */ -#define PACKAGE "curl" - -/* ---------------------------------------------------------------- */ -/* WinCE */ -/* ---------------------------------------------------------------- */ - -#ifndef UNICODE -# define UNICODE -#endif - -#ifndef _UNICODE -# define _UNICODE -#endif - -#define CURL_DISABLE_FILE 1 -#define CURL_DISABLE_TELNET 1 -#define CURL_DISABLE_LDAP 1 - -#define ENOSPC 1 -#define ENOMEM 2 -#define EAGAIN 3 - -extern int stat(const char *path, struct stat *buffer); - -#endif /* HEADER_CURL_CONFIG_WIN32CE_H */ diff --git a/dep/cpr/opt/curl/lib/conncache.c b/dep/cpr/opt/curl/lib/conncache.c deleted file mode 100644 index c79d227640c..00000000000 --- a/dep/cpr/opt/curl/lib/conncache.c +++ /dev/null @@ -1,360 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "urldata.h" -#include "url.h" -#include "progress.h" -#include "multiif.h" -#include "sendf.h" -#include "conncache.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -static void conn_llist_dtor(void *user, void *element) -{ - struct connectdata *data = element; - (void)user; - - data->bundle = NULL; -} - -static CURLcode bundle_create(struct Curl_easy *data, - struct connectbundle **cb_ptr) -{ - (void)data; - DEBUGASSERT(*cb_ptr == NULL); - *cb_ptr = malloc(sizeof(struct connectbundle)); - if(!*cb_ptr) - return CURLE_OUT_OF_MEMORY; - - (*cb_ptr)->num_connections = 0; - (*cb_ptr)->multiuse = BUNDLE_UNKNOWN; - - Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor); - return CURLE_OK; -} - -static void bundle_destroy(struct connectbundle *cb_ptr) -{ - if(!cb_ptr) - return; - - Curl_llist_destroy(&cb_ptr->conn_list, NULL); - - free(cb_ptr); -} - -/* Add a connection to a bundle */ -static CURLcode bundle_add_conn(struct connectbundle *cb_ptr, - struct connectdata *conn) -{ - Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn, - &conn->bundle_node); - conn->bundle = cb_ptr; - cb_ptr->num_connections++; - return CURLE_OK; -} - -/* Remove a connection from a bundle */ -static int bundle_remove_conn(struct connectbundle *cb_ptr, - struct connectdata *conn) -{ - struct curl_llist_element *curr; - - curr = cb_ptr->conn_list.head; - while(curr) { - if(curr->ptr == conn) { - Curl_llist_remove(&cb_ptr->conn_list, curr, NULL); - cb_ptr->num_connections--; - conn->bundle = NULL; - return 1; /* we removed a handle */ - } - curr = curr->next; - } - return 0; -} - -static void free_bundle_hash_entry(void *freethis) -{ - struct connectbundle *b = (struct connectbundle *) freethis; - - bundle_destroy(b); -} - -int Curl_conncache_init(struct conncache *connc, int size) -{ - return Curl_hash_init(&connc->hash, size, Curl_hash_str, - Curl_str_key_compare, free_bundle_hash_entry); -} - -void Curl_conncache_destroy(struct conncache *connc) -{ - if(connc) - Curl_hash_destroy(&connc->hash); -} - -/* creates a key to find a bundle for this connection */ -static void hashkey(struct connectdata *conn, char *buf, - size_t len) /* something like 128 is fine */ -{ - const char *hostname; - - if(conn->bits.socksproxy) - hostname = conn->socks_proxy.host.name; - else if(conn->bits.httpproxy) - hostname = conn->http_proxy.host.name; - else if(conn->bits.conn_to_host) - hostname = conn->conn_to_host.name; - else - hostname = conn->host.name; - - DEBUGASSERT(len > 32); - - /* put the number first so that the hostname gets cut off if too long */ - snprintf(buf, len, "%ld%s", conn->port, hostname); -} - -/* Look up the bundle with all the connections to the same host this - connectdata struct is setup to use. */ -struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, - struct conncache *connc) -{ - struct connectbundle *bundle = NULL; - if(connc) { - char key[128]; - hashkey(conn, key, sizeof(key)); - bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); - } - - return bundle; -} - -static bool conncache_add_bundle(struct conncache *connc, - char *key, - struct connectbundle *bundle) -{ - void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle); - - return p?TRUE:FALSE; -} - -static void conncache_remove_bundle(struct conncache *connc, - struct connectbundle *bundle) -{ - struct curl_hash_iterator iter; - struct curl_hash_element *he; - - if(!connc) - return; - - Curl_hash_start_iterate(&connc->hash, &iter); - - he = Curl_hash_next_element(&iter); - while(he) { - if(he->ptr == bundle) { - /* The bundle is destroyed by the hash destructor function, - free_bundle_hash_entry() */ - Curl_hash_delete(&connc->hash, he->key, he->key_len); - return; - } - - he = Curl_hash_next_element(&iter); - } -} - -CURLcode Curl_conncache_add_conn(struct conncache *connc, - struct connectdata *conn) -{ - CURLcode result; - struct connectbundle *bundle; - struct connectbundle *new_bundle = NULL; - struct Curl_easy *data = conn->data; - - bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); - if(!bundle) { - int rc; - char key[128]; - - result = bundle_create(data, &new_bundle); - if(result) - return result; - - hashkey(conn, key, sizeof(key)); - rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle); - - if(!rc) { - bundle_destroy(new_bundle); - return CURLE_OUT_OF_MEMORY; - } - bundle = new_bundle; - } - - result = bundle_add_conn(bundle, conn); - if(result) { - if(new_bundle) - conncache_remove_bundle(data->state.conn_cache, new_bundle); - return result; - } - - conn->connection_id = connc->next_connection_id++; - connc->num_connections++; - - DEBUGF(infof(conn->data, "Added connection %ld. " - "The cache now contains %" CURL_FORMAT_CURL_OFF_TU " members\n", - conn->connection_id, (curl_off_t) connc->num_connections)); - - return CURLE_OK; -} - -void Curl_conncache_remove_conn(struct conncache *connc, - struct connectdata *conn) -{ - struct connectbundle *bundle = conn->bundle; - - /* The bundle pointer can be NULL, since this function can be called - due to a failed connection attempt, before being added to a bundle */ - if(bundle) { - bundle_remove_conn(bundle, conn); - if(bundle->num_connections == 0) { - conncache_remove_bundle(connc, bundle); - } - - if(connc) { - connc->num_connections--; - - DEBUGF(infof(conn->data, "The cache now contains %" - CURL_FORMAT_CURL_OFF_TU " members\n", - (curl_off_t) connc->num_connections)); - } - } -} - -/* This function iterates the entire connection cache and calls the - function func() with the connection pointer as the first argument - and the supplied 'param' argument as the other, - - Return 0 from func() to continue the loop, return 1 to abort it. - */ -void Curl_conncache_foreach(struct conncache *connc, - void *param, - int (*func)(struct connectdata *conn, void *param)) -{ - struct curl_hash_iterator iter; - struct curl_llist_element *curr; - struct curl_hash_element *he; - - if(!connc) - return; - - Curl_hash_start_iterate(&connc->hash, &iter); - - he = Curl_hash_next_element(&iter); - while(he) { - struct connectbundle *bundle; - - bundle = he->ptr; - he = Curl_hash_next_element(&iter); - - curr = bundle->conn_list.head; - while(curr) { - /* Yes, we need to update curr before calling func(), because func() - might decide to remove the connection */ - struct connectdata *conn = curr->ptr; - curr = curr->next; - - if(1 == func(conn, param)) - return; - } - } -} - -/* Return the first connection found in the cache. Used when closing all - connections */ -struct connectdata * -Curl_conncache_find_first_connection(struct conncache *connc) -{ - struct curl_hash_iterator iter; - struct curl_hash_element *he; - struct connectbundle *bundle; - - Curl_hash_start_iterate(&connc->hash, &iter); - - he = Curl_hash_next_element(&iter); - while(he) { - struct curl_llist_element *curr; - bundle = he->ptr; - - curr = bundle->conn_list.head; - if(curr) { - return curr->ptr; - } - - he = Curl_hash_next_element(&iter); - } - - return NULL; -} - - -#if 0 -/* Useful for debugging the connection cache */ -void Curl_conncache_print(struct conncache *connc) -{ - struct curl_hash_iterator iter; - struct curl_llist_element *curr; - struct curl_hash_element *he; - - if(!connc) - return; - - fprintf(stderr, "=Bundle cache=\n"); - - Curl_hash_start_iterate(connc->hash, &iter); - - he = Curl_hash_next_element(&iter); - while(he) { - struct connectbundle *bundle; - struct connectdata *conn; - - bundle = he->ptr; - - fprintf(stderr, "%s -", he->key); - curr = bundle->conn_list->head; - while(curr) { - conn = curr->ptr; - - fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse); - curr = curr->next; - } - fprintf(stderr, "\n"); - - he = Curl_hash_next_element(&iter); - } -} -#endif diff --git a/dep/cpr/opt/curl/lib/conncache.h b/dep/cpr/opt/curl/lib/conncache.h deleted file mode 100644 index 14be4e8e734..00000000000 --- a/dep/cpr/opt/curl/lib/conncache.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef HEADER_CURL_CONNCACHE_H -#define HEADER_CURL_CONNCACHE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2015 - 2017, Daniel Stenberg, , et al. - * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -struct conncache { - struct curl_hash hash; - size_t num_connections; - long next_connection_id; - struct curltime last_cleanup; -}; - -#define BUNDLE_NO_MULTIUSE -1 -#define BUNDLE_UNKNOWN 0 /* initial value */ -#define BUNDLE_PIPELINING 1 -#define BUNDLE_MULTIPLEX 2 - -struct connectbundle { - int multiuse; /* supports multi-use */ - size_t num_connections; /* Number of connections in the bundle */ - struct curl_llist conn_list; /* The connectdata members of the bundle */ -}; - -int Curl_conncache_init(struct conncache *, int size); - -void Curl_conncache_destroy(struct conncache *connc); - -/* return the correct bundle, to a host or a proxy */ -struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, - struct conncache *connc); - -CURLcode Curl_conncache_add_conn(struct conncache *connc, - struct connectdata *conn); - -void Curl_conncache_remove_conn(struct conncache *connc, - struct connectdata *conn); - -void Curl_conncache_foreach(struct conncache *connc, - void *param, - int (*func)(struct connectdata *conn, - void *param)); - -struct connectdata * -Curl_conncache_find_first_connection(struct conncache *connc); - -void Curl_conncache_print(struct conncache *connc); - -#endif /* HEADER_CURL_CONNCACHE_H */ diff --git a/dep/cpr/opt/curl/lib/connect.c b/dep/cpr/opt/curl/lib/connect.c deleted file mode 100644 index b7d10af5536..00000000000 --- a/dep/cpr/opt/curl/lib/connect.c +++ /dev/null @@ -1,1410 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -#include /* may need it */ -#endif -#ifdef HAVE_SYS_UN_H -#include /* for sockaddr_un */ -#endif -#ifdef HAVE_NETINET_TCP_H -#include /* for TCP_NODELAY */ -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) -#include -#endif -#ifdef NETWARE -#undef in_addr_t -#define in_addr_t unsigned long -#endif -#ifdef __VMS -#include -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "if2ip.h" -#include "strerror.h" -#include "connect.h" -#include "select.h" -#include "url.h" /* for Curl_safefree() */ -#include "multiif.h" -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "inet_ntop.h" -#include "inet_pton.h" -#include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */ -#include "progress.h" -#include "warnless.h" -#include "conncache.h" -#include "multihandle.h" -#include "system_win32.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifdef __SYMBIAN32__ -/* This isn't actually supported under Symbian OS */ -#undef SO_NOSIGPIPE -#endif - -static bool verifyconnect(curl_socket_t sockfd, int *error); - -#if defined(__DragonFly__) || defined(HAVE_WINSOCK_H) -/* DragonFlyBSD and Windows use millisecond units */ -#define KEEPALIVE_FACTOR(x) (x *= 1000) -#else -#define KEEPALIVE_FACTOR(x) -#endif - -#if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS) -#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) - -struct tcp_keepalive { - u_long onoff; - u_long keepalivetime; - u_long keepaliveinterval; -}; -#endif - -static void -tcpkeepalive(struct Curl_easy *data, - curl_socket_t sockfd) -{ - int optval = data->set.tcp_keepalive?1:0; - - /* only set IDLE and INTVL if setting KEEPALIVE is successful */ - if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, - (void *)&optval, sizeof(optval)) < 0) { - infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd); - } - else { -#if defined(SIO_KEEPALIVE_VALS) - struct tcp_keepalive vals; - DWORD dummy; - vals.onoff = 1; - optval = curlx_sltosi(data->set.tcp_keepidle); - KEEPALIVE_FACTOR(optval); - vals.keepalivetime = optval; - optval = curlx_sltosi(data->set.tcp_keepintvl); - KEEPALIVE_FACTOR(optval); - vals.keepaliveinterval = optval; - if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals), - NULL, 0, &dummy, NULL, NULL) != 0) { - infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n", - (int)sockfd, WSAGetLastError()); - } -#else -#ifdef TCP_KEEPIDLE - optval = curlx_sltosi(data->set.tcp_keepidle); - KEEPALIVE_FACTOR(optval); - if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, - (void *)&optval, sizeof(optval)) < 0) { - infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd); - } -#endif -#ifdef TCP_KEEPINTVL - optval = curlx_sltosi(data->set.tcp_keepintvl); - KEEPALIVE_FACTOR(optval); - if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, - (void *)&optval, sizeof(optval)) < 0) { - infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd); - } -#endif -#ifdef TCP_KEEPALIVE - /* Mac OS X style */ - optval = curlx_sltosi(data->set.tcp_keepidle); - KEEPALIVE_FACTOR(optval); - if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, - (void *)&optval, sizeof(optval)) < 0) { - infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd); - } -#endif -#endif - } -} - -static CURLcode -singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, /* start connecting to this */ - curl_socket_t *sock); - -/* - * Curl_timeleft() returns the amount of milliseconds left allowed for the - * transfer/connection. If the value is negative, the timeout time has already - * elapsed. - * - * The start time is stored in progress.t_startsingle - as set with - * Curl_pgrsTime(..., TIMER_STARTSINGLE); - * - * If 'nowp' is non-NULL, it points to the current time. - * 'duringconnect' is FALSE if not during a connect, as then of course the - * connect timeout is not taken into account! - * - * @unittest: 1303 - */ -time_t Curl_timeleft(struct Curl_easy *data, - struct curltime *nowp, - bool duringconnect) -{ - int timeout_set = 0; - time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0; - struct curltime now; - - /* if a timeout is set, use the most restrictive one */ - - if(data->set.timeout > 0) - timeout_set |= 1; - if(duringconnect && (data->set.connecttimeout > 0)) - timeout_set |= 2; - - switch(timeout_set) { - case 1: - timeout_ms = data->set.timeout; - break; - case 2: - timeout_ms = data->set.connecttimeout; - break; - case 3: - if(data->set.timeout < data->set.connecttimeout) - timeout_ms = data->set.timeout; - else - timeout_ms = data->set.connecttimeout; - break; - default: - /* use the default */ - if(!duringconnect) - /* if we're not during connect, there's no default timeout so if we're - at zero we better just return zero and not make it a negative number - by the math below */ - return 0; - break; - } - - if(!nowp) { - now = Curl_tvnow(); - nowp = &now; - } - - /* subtract elapsed time */ - if(duringconnect) - /* since this most recent connect started */ - timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle); - else - /* since the entire operation started */ - timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop); - if(!timeout_ms) - /* avoid returning 0 as that means no timeout! */ - return -1; - - return timeout_ms; -} - -static CURLcode bindlocal(struct connectdata *conn, - curl_socket_t sockfd, int af, unsigned int scope) -{ - struct Curl_easy *data = conn->data; - - struct Curl_sockaddr_storage sa; - struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */ - curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */ - struct sockaddr_in *si4 = (struct sockaddr_in *)&sa; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa; -#endif - - struct Curl_dns_entry *h = NULL; - unsigned short port = data->set.localport; /* use this port number, 0 for - "random" */ - /* how many port numbers to try to bind to, increasing one at a time */ - int portnum = data->set.localportrange; - const char *dev = data->set.str[STRING_DEVICE]; - int error; - - /************************************************************* - * Select device to bind socket to - *************************************************************/ - if(!dev && !port) - /* no local kind of binding was requested */ - return CURLE_OK; - - memset(&sa, 0, sizeof(struct Curl_sockaddr_storage)); - - if(dev && (strlen(dev)<255) ) { - char myhost[256] = ""; - int done = 0; /* -1 for error, 1 for address found */ - bool is_interface = FALSE; - bool is_host = FALSE; - static const char *if_prefix = "if!"; - static const char *host_prefix = "host!"; - - if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) { - dev += strlen(if_prefix); - is_interface = TRUE; - } - else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) { - dev += strlen(host_prefix); - is_host = TRUE; - } - - /* interface */ - if(!is_host) { - switch(Curl_if2ip(af, scope, conn->scope_id, dev, - myhost, sizeof(myhost))) { - case IF2IP_NOT_FOUND: - if(is_interface) { - /* Do not fall back to treating it as a host name */ - failf(data, "Couldn't bind to interface '%s'", dev); - return CURLE_INTERFACE_FAILED; - } - break; - case IF2IP_AF_NOT_SUPPORTED: - /* Signal the caller to try another address family if available */ - return CURLE_UNSUPPORTED_PROTOCOL; - case IF2IP_FOUND: - is_interface = TRUE; - /* - * We now have the numerical IP address in the 'myhost' buffer - */ - infof(data, "Local Interface %s is ip %s using address family %i\n", - dev, myhost, af); - done = 1; - -#ifdef SO_BINDTODEVICE - /* I am not sure any other OSs than Linux that provide this feature, - * and at the least I cannot test. --Ben - * - * This feature allows one to tightly bind the local socket to a - * particular interface. This will force even requests to other - * local interfaces to go out the external interface. - * - * - * Only bind to the interface when specified as interface, not just - * as a hostname or ip address. - */ - if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, - dev, (curl_socklen_t)strlen(dev) + 1) != 0) { - error = SOCKERRNO; - infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;" - " will do regular bind\n", - dev, error, Curl_strerror(conn, error)); - /* This is typically "errno 1, error: Operation not permitted" if - you're not running as root or another suitable privileged - user */ - } -#endif - break; - } - } - if(!is_interface) { - /* - * This was not an interface, resolve the name as a host name - * or IP number - * - * Temporarily force name resolution to use only the address type - * of the connection. The resolve functions should really be changed - * to take a type parameter instead. - */ - long ipver = conn->ip_version; - int rc; - - if(af == AF_INET) - conn->ip_version = CURL_IPRESOLVE_V4; -#ifdef ENABLE_IPV6 - else if(af == AF_INET6) - conn->ip_version = CURL_IPRESOLVE_V6; -#endif - - rc = Curl_resolv(conn, dev, 0, &h); - if(rc == CURLRESOLV_PENDING) - (void)Curl_resolver_wait_resolv(conn, &h); - conn->ip_version = ipver; - - if(h) { - /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ - Curl_printable_address(h->addr, myhost, sizeof(myhost)); - infof(data, "Name '%s' family %i resolved to '%s' family %i\n", - dev, af, myhost, h->addr->ai_family); - Curl_resolv_unlock(data, h); - done = 1; - } - else { - /* - * provided dev was no interface (or interfaces are not supported - * e.g. solaris) no ip address and no domain we fail here - */ - done = -1; - } - } - - if(done > 0) { -#ifdef ENABLE_IPV6 - /* IPv6 address */ - if(af == AF_INET6) { -#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID - char *scope_ptr = strchr(myhost, '%'); - if(scope_ptr) - *(scope_ptr++) = 0; -#endif - if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) { - si6->sin6_family = AF_INET6; - si6->sin6_port = htons(port); -#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID - if(scope_ptr) - /* The "myhost" string either comes from Curl_if2ip or from - Curl_printable_address. The latter returns only numeric scope - IDs and the former returns none at all. So the scope ID, if - present, is known to be numeric */ - si6->sin6_scope_id = atoi(scope_ptr); -#endif - } - sizeof_sa = sizeof(struct sockaddr_in6); - } - else -#endif - /* IPv4 address */ - if((af == AF_INET) && - (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) { - si4->sin_family = AF_INET; - si4->sin_port = htons(port); - sizeof_sa = sizeof(struct sockaddr_in); - } - } - - if(done < 1) { - failf(data, "Couldn't bind to '%s'", dev); - return CURLE_INTERFACE_FAILED; - } - } - else { - /* no device was given, prepare sa to match af's needs */ -#ifdef ENABLE_IPV6 - if(af == AF_INET6) { - si6->sin6_family = AF_INET6; - si6->sin6_port = htons(port); - sizeof_sa = sizeof(struct sockaddr_in6); - } - else -#endif - if(af == AF_INET) { - si4->sin_family = AF_INET; - si4->sin_port = htons(port); - sizeof_sa = sizeof(struct sockaddr_in); - } - } - - for(;;) { - if(bind(sockfd, sock, sizeof_sa) >= 0) { - /* we succeeded to bind */ - struct Curl_sockaddr_storage add; - curl_socklen_t size = sizeof(add); - memset(&add, 0, sizeof(struct Curl_sockaddr_storage)); - if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) { - data->state.os_errno = error = SOCKERRNO; - failf(data, "getsockname() failed with errno %d: %s", - error, Curl_strerror(conn, error)); - return CURLE_INTERFACE_FAILED; - } - infof(data, "Local port: %hu\n", port); - conn->bits.bound = TRUE; - return CURLE_OK; - } - - if(--portnum > 0) { - infof(data, "Bind to local port %hu failed, trying next\n", port); - port++; /* try next port */ - /* We re-use/clobber the port variable here below */ - if(sock->sa_family == AF_INET) - si4->sin_port = ntohs(port); -#ifdef ENABLE_IPV6 - else - si6->sin6_port = ntohs(port); -#endif - } - else - break; - } - - data->state.os_errno = error = SOCKERRNO; - failf(data, "bind failed with errno %d: %s", - error, Curl_strerror(conn, error)); - - return CURLE_INTERFACE_FAILED; -} - -/* - * verifyconnect() returns TRUE if the connect really has happened. - */ -static bool verifyconnect(curl_socket_t sockfd, int *error) -{ - bool rc = TRUE; -#ifdef SO_ERROR - int err = 0; - curl_socklen_t errSize = sizeof(err); - -#ifdef WIN32 - /* - * In October 2003 we effectively nullified this function on Windows due to - * problems with it using all CPU in multi-threaded cases. - * - * In May 2004, we bring it back to offer more info back on connect failures. - * Gisle Vanem could reproduce the former problems with this function, but - * could avoid them by adding this SleepEx() call below: - * - * "I don't have Rational Quantify, but the hint from his post was - * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe - * just Sleep(0) would be enough?) would release whatever - * mutex/critical-section the ntdll call is waiting on. - * - * Someone got to verify this on Win-NT 4.0, 2000." - */ - -#ifdef _WIN32_WCE - Sleep(0); -#else - SleepEx(0, FALSE); -#endif - -#endif - - if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize)) - err = SOCKERRNO; -#ifdef _WIN32_WCE - /* Old WinCE versions don't support SO_ERROR */ - if(WSAENOPROTOOPT == err) { - SET_SOCKERRNO(0); - err = 0; - } -#endif -#ifdef __minix - /* Minix 3.1.x doesn't support getsockopt on UDP sockets */ - if(EBADIOCTL == err) { - SET_SOCKERRNO(0); - err = 0; - } -#endif - if((0 == err) || (EISCONN == err)) - /* we are connected, awesome! */ - rc = TRUE; - else - /* This wasn't a successful connect */ - rc = FALSE; - if(error) - *error = err; -#else - (void)sockfd; - if(error) - *error = SOCKERRNO; -#endif - return rc; -} - -/* Used within the multi interface. Try next IP address, return TRUE if no - more address exists or error */ -static CURLcode trynextip(struct connectdata *conn, - int sockindex, - int tempindex) -{ - const int other = tempindex ^ 1; - CURLcode result = CURLE_COULDNT_CONNECT; - - /* First clean up after the failed socket. - Don't close it yet to ensure that the next IP's socket gets a different - file descriptor, which can prevent bugs when the curl_multi_socket_action - interface is used with certain select() replacements such as kqueue. */ - curl_socket_t fd_to_close = conn->tempsock[tempindex]; - conn->tempsock[tempindex] = CURL_SOCKET_BAD; - - if(sockindex == FIRSTSOCKET) { - Curl_addrinfo *ai = NULL; - int family = AF_UNSPEC; - - if(conn->tempaddr[tempindex]) { - /* find next address in the same protocol family */ - family = conn->tempaddr[tempindex]->ai_family; - ai = conn->tempaddr[tempindex]->ai_next; - } -#ifdef ENABLE_IPV6 - else if(conn->tempaddr[0]) { - /* happy eyeballs - try the other protocol family */ - int firstfamily = conn->tempaddr[0]->ai_family; - family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; - ai = conn->tempaddr[0]->ai_next; - } -#endif - - while(ai) { - if(conn->tempaddr[other]) { - /* we can safely skip addresses of the other protocol family */ - while(ai && ai->ai_family != family) - ai = ai->ai_next; - } - - if(ai) { - result = singleipconnect(conn, ai, &conn->tempsock[tempindex]); - if(result == CURLE_COULDNT_CONNECT) { - ai = ai->ai_next; - continue; - } - - conn->tempaddr[tempindex] = ai; - } - break; - } - } - - if(fd_to_close != CURL_SOCKET_BAD) - Curl_closesocket(conn, fd_to_close); - - return result; -} - -/* Copies connection info into the session handle to make it available - when the session handle is no longer associated with a connection. */ -void Curl_persistconninfo(struct connectdata *conn) -{ - memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN); - memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN); - conn->data->info.conn_scheme = conn->handler->scheme; - conn->data->info.conn_protocol = conn->handler->protocol; - conn->data->info.conn_primary_port = conn->primary_port; - conn->data->info.conn_local_port = conn->local_port; -} - -/* retrieves ip address and port from a sockaddr structure. - note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */ -static bool getaddressinfo(struct sockaddr *sa, char *addr, - long *port) -{ - unsigned short us_port; - struct sockaddr_in *si = NULL; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 *si6 = NULL; -#endif -#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) - struct sockaddr_un *su = NULL; -#endif - - switch(sa->sa_family) { - case AF_INET: - si = (struct sockaddr_in *)(void *) sa; - if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, - addr, MAX_IPADR_LEN)) { - us_port = ntohs(si->sin_port); - *port = us_port; - return TRUE; - } - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - si6 = (struct sockaddr_in6 *)(void *) sa; - if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, - addr, MAX_IPADR_LEN)) { - us_port = ntohs(si6->sin6_port); - *port = us_port; - return TRUE; - } - break; -#endif -#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) - case AF_UNIX: - su = (struct sockaddr_un*)sa; - snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path); - *port = 0; - return TRUE; -#endif - default: - break; - } - - addr[0] = '\0'; - *port = 0; - errno = EAFNOSUPPORT; - return FALSE; -} - -/* retrieves the start/end point information of a socket of an established - connection */ -void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) -{ - curl_socklen_t len; - struct Curl_sockaddr_storage ssrem; - struct Curl_sockaddr_storage ssloc; - struct Curl_easy *data = conn->data; - - if(conn->socktype == SOCK_DGRAM) - /* there's no connection! */ - return; - - if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { - len = sizeof(struct Curl_sockaddr_storage); - if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) { - int error = SOCKERRNO; - failf(data, "getpeername() failed with errno %d: %s", - error, Curl_strerror(conn, error)); - return; - } - - len = sizeof(struct Curl_sockaddr_storage); - memset(&ssloc, 0, sizeof(ssloc)); - if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) { - int error = SOCKERRNO; - failf(data, "getsockname() failed with errno %d: %s", - error, Curl_strerror(conn, error)); - return; - } - - if(!getaddressinfo((struct sockaddr*)&ssrem, - conn->primary_ip, &conn->primary_port)) { - failf(data, "ssrem inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(conn, errno)); - return; - } - memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); - - if(!getaddressinfo((struct sockaddr*)&ssloc, - conn->local_ip, &conn->local_port)) { - failf(data, "ssloc inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(conn, errno)); - return; - } - - } - - /* persist connection info in session handle */ - Curl_persistconninfo(conn); -} - -/* - * Curl_is_connected() checks if the socket has connected. - */ - -CURLcode Curl_is_connected(struct connectdata *conn, - int sockindex, - bool *connected) -{ - struct Curl_easy *data = conn->data; - CURLcode result = CURLE_OK; - time_t allow; - int error = 0; - struct curltime now; - int rc; - int i; - - DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); - - *connected = FALSE; /* a very negative world view is best */ - - if(conn->bits.tcpconnect[sockindex]) { - /* we are connected already! */ - *connected = TRUE; - return CURLE_OK; - } - - now = Curl_tvnow(); - - /* figure out how long time we have left to connect */ - allow = Curl_timeleft(data, &now, TRUE); - - if(allow < 0) { - /* time-out, bail out, go home */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - for(i = 0; i<2; i++) { - const int other = i ^ 1; - if(conn->tempsock[i] == CURL_SOCKET_BAD) - continue; - -#ifdef mpeix - /* Call this function once now, and ignore the results. We do this to - "clear" the error state on the socket so that we can later read it - reliably. This is reported necessary on the MPE/iX operating system. */ - (void)verifyconnect(conn->tempsock[i], NULL); -#endif - - /* check socket for connect */ - rc = SOCKET_WRITABLE(conn->tempsock[i], 0); - - if(rc == 0) { /* no connection yet */ - error = 0; - if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) { - infof(data, "After %ldms connect time, move on!\n", - conn->timeoutms_per_addr); - error = ETIMEDOUT; - } - - /* should we try another protocol family? */ - if(i == 0 && conn->tempaddr[1] == NULL && - curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) { - trynextip(conn, sockindex, 1); - } - } - else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) { - if(verifyconnect(conn->tempsock[i], &error)) { - /* we are connected with TCP, awesome! */ - - /* use this socket from now on */ - conn->sock[sockindex] = conn->tempsock[i]; - conn->ip_addr = conn->tempaddr[i]; - conn->tempsock[i] = CURL_SOCKET_BAD; - - /* close the other socket, if open */ - if(conn->tempsock[other] != CURL_SOCKET_BAD) { - Curl_closesocket(conn, conn->tempsock[other]); - conn->tempsock[other] = CURL_SOCKET_BAD; - } - - /* see if we need to do any proxy magic first once we connected */ - result = Curl_connected_proxy(conn, sockindex); - if(result) - return result; - - conn->bits.tcpconnect[sockindex] = TRUE; - - *connected = TRUE; - if(sockindex == FIRSTSOCKET) - Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ - Curl_updateconninfo(conn, conn->sock[sockindex]); - Curl_verboseconnect(conn); - - return CURLE_OK; - } - infof(data, "Connection failed\n"); - } - else if(rc & CURL_CSELECT_ERR) - (void)verifyconnect(conn->tempsock[i], &error); - - /* - * The connection failed here, we should attempt to connect to the "next - * address" for the given host. But first remember the latest error. - */ - if(error) { - data->state.os_errno = error; - SET_SOCKERRNO(error); - if(conn->tempaddr[i]) { - CURLcode status; - char ipaddress[MAX_IPADR_LEN]; - Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN); - infof(data, "connect to %s port %ld failed: %s\n", - ipaddress, conn->port, Curl_strerror(conn, error)); - - conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? - allow : allow / 2; - - status = trynextip(conn, sockindex, i); - if(status != CURLE_COULDNT_CONNECT - || conn->tempsock[other] == CURL_SOCKET_BAD) - /* the last attempt failed and no other sockets remain open */ - result = status; - } - } - } - - if(result) { - /* no more addresses to try */ - - const char *hostname; - - /* if the first address family runs out of addresses to try before - the happy eyeball timeout, go ahead and try the next family now */ - if(conn->tempaddr[1] == NULL) { - result = trynextip(conn, sockindex, 1); - if(!result) - return result; - } - - if(conn->bits.socksproxy) - hostname = conn->socks_proxy.host.name; - else if(conn->bits.httpproxy) - hostname = conn->http_proxy.host.name; - else if(conn->bits.conn_to_host) - hostname = conn->conn_to_host.name; - else - hostname = conn->host.name; - - failf(data, "Failed to connect to %s port %ld: %s", - hostname, conn->port, Curl_strerror(conn, error)); - } - - return result; -} - -void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) -{ -#if defined(TCP_NODELAY) -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) - struct Curl_easy *data = conn->data; -#endif - curl_socklen_t onoff = (curl_socklen_t) 1; - int level = IPPROTO_TCP; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) conn; -#endif - - if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, - sizeof(onoff)) < 0) - infof(data, "Could not set TCP_NODELAY: %s\n", - Curl_strerror(conn, SOCKERRNO)); - else - infof(data, "TCP_NODELAY set\n"); -#else - (void)conn; - (void)sockfd; -#endif -} - -#ifdef SO_NOSIGPIPE -/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when - sending data to a dead peer (instead of relying on the 4th argument to send - being MSG_NOSIGNAL). Possibly also existing and in use on other BSD - systems? */ -static void nosigpipe(struct connectdata *conn, - curl_socket_t sockfd) -{ - struct Curl_easy *data = conn->data; - int onoff = 1; - if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, - sizeof(onoff)) < 0) - infof(data, "Could not set SO_NOSIGPIPE: %s\n", - Curl_strerror(conn, SOCKERRNO)); -} -#else -#define nosigpipe(x,y) Curl_nop_stmt -#endif - -#ifdef USE_WINSOCK -/* When you run a program that uses the Windows Sockets API, you may - experience slow performance when you copy data to a TCP server. - - https://support.microsoft.com/kb/823764 - - Work-around: Make the Socket Send Buffer Size Larger Than the Program Send - Buffer Size - - The problem described in this knowledge-base is applied only to pre-Vista - Windows. Following function trying to detect OS version and skips - SO_SNDBUF adjustment for Windows Vista and above. -*/ -#define DETECT_OS_NONE 0 -#define DETECT_OS_PREVISTA 1 -#define DETECT_OS_VISTA_OR_LATER 2 - -void Curl_sndbufset(curl_socket_t sockfd) -{ - int val = CURL_MAX_WRITE_SIZE + 32; - int curval = 0; - int curlen = sizeof(curval); - - static int detectOsState = DETECT_OS_NONE; - - if(detectOsState == DETECT_OS_NONE) { - if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT, - VERSION_GREATER_THAN_EQUAL)) - detectOsState = DETECT_OS_VISTA_OR_LATER; - else - detectOsState = DETECT_OS_PREVISTA; - } - - if(detectOsState == DETECT_OS_VISTA_OR_LATER) - return; - - if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0) - if(curval > val) - return; - - setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val)); -} -#endif - -/* - * singleipconnect() - * - * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to - * CURL_SOCKET_BAD. Other errors will however return proper errors. - * - * singleipconnect() connects to the given IP only, and it may return without - * having connected. - */ -static CURLcode singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, - curl_socket_t *sockp) -{ - struct Curl_sockaddr_ex addr; - int rc = -1; - int error = 0; - bool isconnected = FALSE; - struct Curl_easy *data = conn->data; - curl_socket_t sockfd; - CURLcode result; - char ipaddress[MAX_IPADR_LEN]; - long port; - bool is_tcp; - - *sockp = CURL_SOCKET_BAD; - - result = Curl_socket(conn, ai, &addr, &sockfd); - if(result) - /* Failed to create the socket, but still return OK since we signal the - lack of socket as well. This allows the parent function to keep looping - over alternative addresses/socket families etc. */ - return CURLE_OK; - - /* store remote address and port used in this connection attempt */ - if(!getaddressinfo((struct sockaddr*)&addr.sa_addr, - ipaddress, &port)) { - /* malformed address or bug in inet_ntop, try next address */ - failf(data, "sa_addr inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(conn, errno)); - Curl_closesocket(conn, sockfd); - return CURLE_OK; - } - infof(data, " Trying %s...\n", ipaddress); - -#ifdef ENABLE_IPV6 - is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) && - addr.socktype == SOCK_STREAM; -#else - is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM; -#endif - if(is_tcp && data->set.tcp_nodelay) - Curl_tcpnodelay(conn, sockfd); - - nosigpipe(conn, sockfd); - - Curl_sndbufset(sockfd); - - if(is_tcp && data->set.tcp_keepalive) - tcpkeepalive(data, sockfd); - - if(data->set.fsockopt) { - /* activate callback for setting socket options */ - error = data->set.fsockopt(data->set.sockopt_client, - sockfd, - CURLSOCKTYPE_IPCXN); - - if(error == CURL_SOCKOPT_ALREADY_CONNECTED) - isconnected = TRUE; - else if(error) { - Curl_closesocket(conn, sockfd); /* close the socket and bail out */ - return CURLE_ABORTED_BY_CALLBACK; - } - } - - /* possibly bind the local end to an IP, interface or port */ - if(addr.family == AF_INET -#ifdef ENABLE_IPV6 - || addr.family == AF_INET6 -#endif - ) { - result = bindlocal(conn, sockfd, addr.family, - Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr)); - if(result) { - Curl_closesocket(conn, sockfd); /* close socket and bail out */ - if(result == CURLE_UNSUPPORTED_PROTOCOL) { - /* The address family is not supported on this interface. - We can continue trying addresses */ - return CURLE_COULDNT_CONNECT; - } - return result; - } - } - - /* set socket non-blocking */ - (void)curlx_nonblock(sockfd, TRUE); - - conn->connecttime = Curl_tvnow(); - if(conn->num_addr > 1) - Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME); - - /* Connect TCP sockets, bind UDP */ - if(!isconnected && (conn->socktype == SOCK_STREAM)) { - if(conn->bits.tcp_fastopen) { -#if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */ -#ifdef HAVE_BUILTIN_AVAILABLE - if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) { -#endif /* HAVE_BUILTIN_AVAILABLE */ - sa_endpoints_t endpoints; - endpoints.sae_srcif = 0; - endpoints.sae_srcaddr = NULL; - endpoints.sae_srcaddrlen = 0; - endpoints.sae_dstaddr = &addr.sa_addr; - endpoints.sae_dstaddrlen = addr.addrlen; - - rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, - CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, - NULL, 0, NULL, NULL); -#ifdef HAVE_BUILTIN_AVAILABLE - } - else { - rc = connect(sockfd, &addr.sa_addr, addr.addrlen); - } -#endif /* HAVE_BUILTIN_AVAILABLE */ -#elif defined(MSG_FASTOPEN) /* Linux */ - if(conn->given->flags & PROTOPT_SSL) - rc = connect(sockfd, &addr.sa_addr, addr.addrlen); - else - rc = 0; /* Do nothing */ -#endif - } - else { - rc = connect(sockfd, &addr.sa_addr, addr.addrlen); - } - - if(-1 == rc) - error = SOCKERRNO; - } - else { - *sockp = sockfd; - return CURLE_OK; - } - -#ifdef ENABLE_IPV6 - conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE; -#endif - - if(-1 == rc) { - switch(error) { - case EINPROGRESS: - case EWOULDBLOCK: -#if defined(EAGAIN) -#if (EAGAIN) != (EWOULDBLOCK) - /* On some platforms EAGAIN and EWOULDBLOCK are the - * same value, and on others they are different, hence - * the odd #if - */ - case EAGAIN: -#endif -#endif - result = CURLE_OK; - break; - - default: - /* unknown error, fallthrough and try another address! */ - infof(data, "Immediate connect fail for %s: %s\n", - ipaddress, Curl_strerror(conn, error)); - data->state.os_errno = error; - - /* connect failed */ - Curl_closesocket(conn, sockfd); - result = CURLE_COULDNT_CONNECT; - } - } - - if(!result) - *sockp = sockfd; - - return result; -} - -/* - * TCP connect to the given host with timeout, proxy or remote doesn't matter. - * There might be more than one IP address to try out. Fill in the passed - * pointer with the connected socket. - */ - -CURLcode Curl_connecthost(struct connectdata *conn, /* context */ - const struct Curl_dns_entry *remotehost) -{ - struct Curl_easy *data = conn->data; - struct curltime before = Curl_tvnow(); - CURLcode result = CURLE_COULDNT_CONNECT; - - time_t timeout_ms = Curl_timeleft(data, &before, TRUE); - - if(timeout_ms < 0) { - /* a precaution, no need to continue if time already is up */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - conn->num_addr = Curl_num_addresses(remotehost->addr); - conn->tempaddr[0] = remotehost->addr; - conn->tempaddr[1] = NULL; - conn->tempsock[0] = CURL_SOCKET_BAD; - conn->tempsock[1] = CURL_SOCKET_BAD; - - /* Max time for the next connection attempt */ - conn->timeoutms_per_addr = - conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2; - - /* start connecting to first IP */ - while(conn->tempaddr[0]) { - result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0])); - if(!result) - break; - conn->tempaddr[0] = conn->tempaddr[0]->ai_next; - } - - if(conn->tempsock[0] == CURL_SOCKET_BAD) { - if(!result) - result = CURLE_COULDNT_CONNECT; - return result; - } - - data->info.numconnects++; /* to track the number of connections made */ - Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS); - - return CURLE_OK; -} - -struct connfind { - struct connectdata *tofind; - bool found; -}; - -static int conn_is_conn(struct connectdata *conn, void *param) -{ - struct connfind *f = (struct connfind *)param; - if(conn == f->tofind) { - f->found = TRUE; - return 1; - } - return 0; -} - -/* - * Used to extract socket and connectdata struct for the most recent - * transfer on the given Curl_easy. - * - * The returned socket will be CURL_SOCKET_BAD in case of failure! - */ -curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, - struct connectdata **connp) -{ - curl_socket_t sockfd; - - DEBUGASSERT(data); - - /* this works for an easy handle: - * - that has been used for curl_easy_perform() - * - that is associated with a multi handle, and whose connection - * was detached with CURLOPT_CONNECT_ONLY - */ - if(data->state.lastconnect && (data->multi_easy || data->multi)) { - struct connectdata *c = data->state.lastconnect; - struct connfind find; - find.tofind = data->state.lastconnect; - find.found = FALSE; - - Curl_conncache_foreach(data->multi_easy? - &data->multi_easy->conn_cache: - &data->multi->conn_cache, &find, conn_is_conn); - - if(!find.found) { - data->state.lastconnect = NULL; - return CURL_SOCKET_BAD; - } - - if(connp) - /* only store this if the caller cares for it */ - *connp = c; - sockfd = c->sock[FIRSTSOCKET]; - } - else - return CURL_SOCKET_BAD; - - return sockfd; -} - -/* - * Check if a connection seems to be alive. - */ -bool Curl_connalive(struct connectdata *conn) -{ - /* First determine if ssl */ - if(conn->ssl[FIRSTSOCKET].use) { - /* use the SSL context */ - if(!Curl_ssl_check_cxn(conn)) - return false; /* FIN received */ - } -/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ -#ifdef MSG_PEEK - else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) - return false; - else { - /* use the socket */ - char buf; - if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, - (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { - return false; /* FIN received */ - } - } -#endif - return true; -} - -/* - * Close a socket. - * - * 'conn' can be NULL, beware! - */ -int Curl_closesocket(struct connectdata *conn, - curl_socket_t sock) -{ - if(conn && conn->fclosesocket) { - if((sock == conn->sock[SECONDARYSOCKET]) && - conn->sock_accepted[SECONDARYSOCKET]) - /* if this socket matches the second socket, and that was created with - accept, then we MUST NOT call the callback but clear the accepted - status */ - conn->sock_accepted[SECONDARYSOCKET] = FALSE; - else { - Curl_multi_closed(conn, sock); - return conn->fclosesocket(conn->closesocket_client, sock); - } - } - - if(conn) - /* tell the multi-socket code about this */ - Curl_multi_closed(conn, sock); - - sclose(sock); - - return 0; -} - -/* - * Create a socket based on info from 'conn' and 'ai'. - * - * 'addr' should be a pointer to the correct struct to get data back, or NULL. - * 'sockfd' must be a pointer to a socket descriptor. - * - * If the open socket callback is set, used that! - * - */ -CURLcode Curl_socket(struct connectdata *conn, - const Curl_addrinfo *ai, - struct Curl_sockaddr_ex *addr, - curl_socket_t *sockfd) -{ - struct Curl_easy *data = conn->data; - struct Curl_sockaddr_ex dummy; - - if(!addr) - /* if the caller doesn't want info back, use a local temp copy */ - addr = &dummy; - - /* - * The Curl_sockaddr_ex structure is basically libcurl's external API - * curl_sockaddr structure with enough space available to directly hold - * any protocol-specific address structures. The variable declared here - * will be used to pass / receive data to/from the fopensocket callback - * if this has been set, before that, it is initialized from parameters. - */ - - addr->family = ai->ai_family; - addr->socktype = conn->socktype; - addr->protocol = conn->socktype == SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol; - addr->addrlen = ai->ai_addrlen; - - if(addr->addrlen > sizeof(struct Curl_sockaddr_storage)) - addr->addrlen = sizeof(struct Curl_sockaddr_storage); - memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen); - - if(data->set.fopensocket) - /* - * If the opensocket callback is set, all the destination address - * information is passed to the callback. Depending on this information the - * callback may opt to abort the connection, this is indicated returning - * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When - * the callback returns a valid socket the destination address information - * might have been changed and this 'new' address will actually be used - * here to connect. - */ - *sockfd = data->set.fopensocket(data->set.opensocket_client, - CURLSOCKTYPE_IPCXN, - (struct curl_sockaddr *)addr); - else - /* opensocket callback not set, so simply create the socket now */ - *sockfd = socket(addr->family, addr->socktype, addr->protocol); - - if(*sockfd == CURL_SOCKET_BAD) - /* no socket, no connection */ - return CURLE_COULDNT_CONNECT; - -#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) - if(conn->scope_id && (addr->family == AF_INET6)) { - struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr; - sa6->sin6_scope_id = conn->scope_id; - } -#endif - - return CURLE_OK; - -} - -/* - * Curl_conncontrol() marks streams or connection for closure. - */ -void Curl_conncontrol(struct connectdata *conn, - int ctrl /* see defines in header */ -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - , const char *reason -#endif - ) -{ - /* close if a connection, or a stream that isn't multiplexed */ - bool closeit = (ctrl == CONNCTRL_CONNECTION) || - ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM)); - if((ctrl == CONNCTRL_STREAM) && - (conn->handler->flags & PROTOPT_STREAM)) - DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); - else if(closeit != conn->bits.close) { - DEBUGF(infof(conn->data, "Marked for [%s]: %s\n", - closeit?"closure":"keep alive", reason)); - conn->bits.close = closeit; /* the only place in the source code that - should assign this bit */ - } -} - -/* Data received can be cached at various levels, so check them all here. */ -bool Curl_conn_data_pending(struct connectdata *conn, int sockindex) -{ - int readable; - - if(Curl_ssl_data_pending(conn, sockindex) || - Curl_recv_has_postponed_data(conn, sockindex)) - return true; - - readable = SOCKET_READABLE(conn->sock[sockindex], 0); - return (readable > 0 && (readable & CURL_CSELECT_IN)); -} diff --git a/dep/cpr/opt/curl/lib/connect.h b/dep/cpr/opt/curl/lib/connect.h deleted file mode 100644 index 3f05c397844..00000000000 --- a/dep/cpr/opt/curl/lib/connect.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef HEADER_CURL_CONNECT_H -#define HEADER_CURL_CONNECT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */ -#include "sockaddr.h" - -CURLcode Curl_is_connected(struct connectdata *conn, - int sockindex, - bool *connected); - -CURLcode Curl_connecthost(struct connectdata *conn, - const struct Curl_dns_entry *host); - -/* generic function that returns how much time there's left to run, according - to the timeouts set */ -time_t Curl_timeleft(struct Curl_easy *data, - struct curltime *nowp, - bool duringconnect); - -#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ -#define HAPPY_EYEBALLS_TIMEOUT 200 /* milliseconds to wait between - IPv4/IPv6 connection attempts */ - -/* - * Used to extract socket and connectdata struct for the most recent - * transfer on the given Curl_easy. - * - * The returned socket will be CURL_SOCKET_BAD in case of failure! - */ -curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, - struct connectdata **connp); - -/* - * Check if a connection seems to be alive. - */ -bool Curl_connalive(struct connectdata *conn); - -#ifdef USE_WINSOCK -/* When you run a program that uses the Windows Sockets API, you may - experience slow performance when you copy data to a TCP server. - - https://support.microsoft.com/kb/823764 - - Work-around: Make the Socket Send Buffer Size Larger Than the Program Send - Buffer Size - -*/ -void Curl_sndbufset(curl_socket_t sockfd); -#else -#define Curl_sndbufset(y) Curl_nop_stmt -#endif - -void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd); -void Curl_persistconninfo(struct connectdata *conn); -int Curl_closesocket(struct connectdata *conn, curl_socket_t sock); - -/* - * The Curl_sockaddr_ex structure is basically libcurl's external API - * curl_sockaddr structure with enough space available to directly hold any - * protocol-specific address structures. The variable declared here will be - * used to pass / receive data to/from the fopensocket callback if this has - * been set, before that, it is initialized from parameters. - */ -struct Curl_sockaddr_ex { - int family; - int socktype; - int protocol; - unsigned int addrlen; - union { - struct sockaddr addr; - struct Curl_sockaddr_storage buff; - } _sa_ex_u; -}; -#define sa_addr _sa_ex_u.addr - -/* - * Create a socket based on info from 'conn' and 'ai'. - * - * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open - * socket callback is set, used that! - * - */ -CURLcode Curl_socket(struct connectdata *conn, - const Curl_addrinfo *ai, - struct Curl_sockaddr_ex *addr, - curl_socket_t *sockfd); - -void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd); - -/* - * Curl_conncontrol() marks the end of a connection/stream. The 'closeit' - * argument specifies if it is the end of a connection or a stream. - * - * For stream-based protocols (such as HTTP/2), a stream close will not cause - * a connection close. Other protocols will close the connection for both - * cases. - * - * It sets the bit.close bit to TRUE (with an explanation for debug builds), - * when the connection will close. - */ - -#define CONNCTRL_KEEP 0 /* undo a marked closure */ -#define CONNCTRL_CONNECTION 1 -#define CONNCTRL_STREAM 2 - -void Curl_conncontrol(struct connectdata *conn, - int closeit -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - , const char *reason -#endif - ); - -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) -#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y) -#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y) -#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y) -#else /* if !DEBUGBUILD || CURL_DISABLE_VERBOSE_STRINGS */ -#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM) -#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION) -#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP) -#endif - -bool Curl_conn_data_pending(struct connectdata *conn, int sockindex); - -#endif /* HEADER_CURL_CONNECT_H */ diff --git a/dep/cpr/opt/curl/lib/content_encoding.c b/dep/cpr/opt/curl/lib/content_encoding.c deleted file mode 100644 index 110226034c6..00000000000 --- a/dep/cpr/opt/curl/lib/content_encoding.c +++ /dev/null @@ -1,431 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_LIBZ - -#include "urldata.h" -#include -#include "sendf.h" -#include "content_encoding.h" -#include "strdup.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Comment this out if zlib is always going to be at least ver. 1.2.0.4 - (doing so will reduce code size slightly). */ -#define OLD_ZLIB_SUPPORT 1 - -#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */ - -#define GZIP_MAGIC_0 0x1f -#define GZIP_MAGIC_1 0x8b - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -static voidpf -zalloc_cb(voidpf opaque, unsigned int items, unsigned int size) -{ - (void) opaque; - /* not a typo, keep it calloc() */ - return (voidpf) calloc(items, size); -} - -static void -zfree_cb(voidpf opaque, voidpf ptr) -{ - (void) opaque; - free(ptr); -} - -static CURLcode -process_zlib_error(struct connectdata *conn, z_stream *z) -{ - struct Curl_easy *data = conn->data; - if(z->msg) - failf(data, "Error while processing content unencoding: %s", - z->msg); - else - failf(data, "Error while processing content unencoding: " - "Unknown failure within decompression software."); - - return CURLE_BAD_CONTENT_ENCODING; -} - -static CURLcode -exit_zlib(z_stream *z, zlibInitState *zlib_init, CURLcode result) -{ - inflateEnd(z); - *zlib_init = ZLIB_UNINIT; - return result; -} - -static CURLcode -inflate_stream(struct connectdata *conn, - struct SingleRequest *k) -{ - int allow_restart = 1; - z_stream *z = &k->z; /* zlib state structure */ - uInt nread = z->avail_in; - Bytef *orig_in = z->next_in; - int status; /* zlib status */ - CURLcode result = CURLE_OK; /* Curl_client_write status */ - char *decomp; /* Put the decompressed data here. */ - - /* Dynamically allocate a buffer for decompression because it's uncommonly - large to hold on the stack */ - decomp = malloc(DSIZ); - if(decomp == NULL) { - return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); - } - - /* because the buffer size is fixed, iteratively decompress and transfer to - the client via client_write. */ - for(;;) { - /* (re)set buffer for decompressed output for every iteration */ - z->next_out = (Bytef *)decomp; - z->avail_out = DSIZ; - - status = inflate(z, Z_SYNC_FLUSH); - if(status == Z_OK || status == Z_STREAM_END) { - allow_restart = 0; - if((DSIZ - z->avail_out) && (!k->ignorebody)) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp, - DSIZ - z->avail_out); - /* if !CURLE_OK, clean up, return */ - if(result) { - free(decomp); - return exit_zlib(z, &k->zlib_init, result); - } - } - - /* Done? clean up, return */ - if(status == Z_STREAM_END) { - free(decomp); - if(inflateEnd(z) == Z_OK) - return exit_zlib(z, &k->zlib_init, result); - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - - /* Done with these bytes, exit */ - - /* status is always Z_OK at this point! */ - if(z->avail_in == 0) { - free(decomp); - return result; - } - } - else if(allow_restart && status == Z_DATA_ERROR) { - /* some servers seem to not generate zlib headers, so this is an attempt - to fix and continue anyway */ - - (void) inflateEnd(z); /* don't care about the return code */ - if(inflateInit2(z, -MAX_WBITS) != Z_OK) { - free(decomp); - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - z->next_in = orig_in; - z->avail_in = nread; - allow_restart = 0; - continue; - } - else { /* Error; exit loop, handle below */ - free(decomp); - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - } - /* Will never get here */ -} - -CURLcode -Curl_unencode_deflate_write(struct connectdata *conn, - struct SingleRequest *k, - ssize_t nread) -{ - z_stream *z = &k->z; /* zlib state structure */ - - /* Initialize zlib? */ - if(k->zlib_init == ZLIB_UNINIT) { - memset(z, 0, sizeof(z_stream)); - z->zalloc = (alloc_func)zalloc_cb; - z->zfree = (free_func)zfree_cb; - - if(inflateInit(z) != Z_OK) - return process_zlib_error(conn, z); - k->zlib_init = ZLIB_INIT; - } - - /* Set the compressed input when this function is called */ - z->next_in = (Bytef *)k->str; - z->avail_in = (uInt)nread; - - /* Now uncompress the data */ - return inflate_stream(conn, k); -} - -#ifdef OLD_ZLIB_SUPPORT -/* Skip over the gzip header */ -static enum { - GZIP_OK, - GZIP_BAD, - GZIP_UNDERFLOW -} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen) -{ - int method, flags; - const ssize_t totallen = len; - - /* The shortest header is 10 bytes */ - if(len < 10) - return GZIP_UNDERFLOW; - - if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1)) - return GZIP_BAD; - - method = data[2]; - flags = data[3]; - - if(method != Z_DEFLATED || (flags & RESERVED) != 0) { - /* Can't handle this compression method or unknown flag */ - return GZIP_BAD; - } - - /* Skip over time, xflags, OS code and all previous bytes */ - len -= 10; - data += 10; - - if(flags & EXTRA_FIELD) { - ssize_t extra_len; - - if(len < 2) - return GZIP_UNDERFLOW; - - extra_len = (data[1] << 8) | data[0]; - - if(len < (extra_len + 2)) - return GZIP_UNDERFLOW; - - len -= (extra_len + 2); - data += (extra_len + 2); - } - - if(flags & ORIG_NAME) { - /* Skip over NUL-terminated file name */ - while(len && *data) { - --len; - ++data; - } - if(!len || *data) - return GZIP_UNDERFLOW; - - /* Skip over the NUL */ - --len; - ++data; - } - - if(flags & COMMENT) { - /* Skip over NUL-terminated comment */ - while(len && *data) { - --len; - ++data; - } - if(!len || *data) - return GZIP_UNDERFLOW; - - /* Skip over the NUL */ - --len; - } - - if(flags & HEAD_CRC) { - if(len < 2) - return GZIP_UNDERFLOW; - - len -= 2; - } - - *headerlen = totallen - len; - return GZIP_OK; -} -#endif - -CURLcode -Curl_unencode_gzip_write(struct connectdata *conn, - struct SingleRequest *k, - ssize_t nread) -{ - z_stream *z = &k->z; /* zlib state structure */ - - /* Initialize zlib? */ - if(k->zlib_init == ZLIB_UNINIT) { - memset(z, 0, sizeof(z_stream)); - z->zalloc = (alloc_func)zalloc_cb; - z->zfree = (free_func)zfree_cb; - - if(strcmp(zlibVersion(), "1.2.0.4") >= 0) { - /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */ - if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) { - return process_zlib_error(conn, z); - } - k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */ - } - else { - /* we must parse the gzip header ourselves */ - if(inflateInit2(z, -MAX_WBITS) != Z_OK) { - return process_zlib_error(conn, z); - } - k->zlib_init = ZLIB_INIT; /* Initial call state */ - } - } - - if(k->zlib_init == ZLIB_INIT_GZIP) { - /* Let zlib handle the gzip decompression entirely */ - z->next_in = (Bytef *)k->str; - z->avail_in = (uInt)nread; - /* Now uncompress the data */ - return inflate_stream(conn, k); - } - -#ifndef OLD_ZLIB_SUPPORT - /* Support for old zlib versions is compiled away and we are running with - an old version, so return an error. */ - return exit_zlib(z, &k->zlib_init, CURLE_WRITE_ERROR); - -#else - /* This next mess is to get around the potential case where there isn't - * enough data passed in to skip over the gzip header. If that happens, we - * malloc a block and copy what we have then wait for the next call. If - * there still isn't enough (this is definitely a worst-case scenario), we - * make the block bigger, copy the next part in and keep waiting. - * - * This is only required with zlib versions < 1.2.0.4 as newer versions - * can handle the gzip header themselves. - */ - - switch(k->zlib_init) { - /* Skip over gzip header? */ - case ZLIB_INIT: - { - /* Initial call state */ - ssize_t hlen; - - switch(check_gzip_header((unsigned char *)k->str, nread, &hlen)) { - case GZIP_OK: - z->next_in = (Bytef *)k->str + hlen; - z->avail_in = (uInt)(nread - hlen); - k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ - break; - - case GZIP_UNDERFLOW: - /* We need more data so we can find the end of the gzip header. It's - * possible that the memory block we malloc here will never be freed if - * the transfer abruptly aborts after this point. Since it's unlikely - * that circumstances will be right for this code path to be followed in - * the first place, and it's even more unlikely for a transfer to fail - * immediately afterwards, it should seldom be a problem. - */ - z->avail_in = (uInt)nread; - z->next_in = malloc(z->avail_in); - if(z->next_in == NULL) { - return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); - } - memcpy(z->next_in, k->str, z->avail_in); - k->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */ - /* We don't have any data to inflate yet */ - return CURLE_OK; - - case GZIP_BAD: - default: - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - - } - break; - - case ZLIB_GZIP_HEADER: - { - /* Need more gzip header data state */ - ssize_t hlen; - z->avail_in += (uInt)nread; - z->next_in = Curl_saferealloc(z->next_in, z->avail_in); - if(z->next_in == NULL) { - return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); - } - /* Append the new block of data to the previous one */ - memcpy(z->next_in + z->avail_in - nread, k->str, nread); - - switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) { - case GZIP_OK: - /* This is the zlib stream data */ - free(z->next_in); - /* Don't point into the malloced block since we just freed it */ - z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in; - z->avail_in = (uInt)(z->avail_in - hlen); - k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ - break; - - case GZIP_UNDERFLOW: - /* We still don't have any data to inflate! */ - return CURLE_OK; - - case GZIP_BAD: - default: - free(z->next_in); - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - - } - break; - - case ZLIB_GZIP_INFLATING: - default: - /* Inflating stream state */ - z->next_in = (Bytef *)k->str; - z->avail_in = (uInt)nread; - break; - } - - if(z->avail_in == 0) { - /* We don't have any data to inflate; wait until next time */ - return CURLE_OK; - } - - /* We've parsed the header, now uncompress the data */ - return inflate_stream(conn, k); -#endif -} - -void Curl_unencode_cleanup(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - struct SingleRequest *k = &data->req; - z_stream *z = &k->z; - if(k->zlib_init != ZLIB_UNINIT) - (void) exit_zlib(z, &k->zlib_init, CURLE_OK); -} - -#endif /* HAVE_LIBZ */ diff --git a/dep/cpr/opt/curl/lib/content_encoding.h b/dep/cpr/opt/curl/lib/content_encoding.h deleted file mode 100644 index 3fadd28997e..00000000000 --- a/dep/cpr/opt/curl/lib/content_encoding.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef HEADER_CURL_CONTENT_ENCODING_H -#define HEADER_CURL_CONTENT_ENCODING_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -/* - * Comma-separated list all supported Content-Encodings ('identity' is implied) - */ -#ifdef HAVE_LIBZ -#define ALL_CONTENT_ENCODINGS "deflate, gzip" -/* force a cleanup */ -void Curl_unencode_cleanup(struct connectdata *conn); -#else -#define ALL_CONTENT_ENCODINGS "identity" -#define Curl_unencode_cleanup(x) Curl_nop_stmt -#endif - -CURLcode Curl_unencode_deflate_write(struct connectdata *conn, - struct SingleRequest *req, - ssize_t nread); - -CURLcode -Curl_unencode_gzip_write(struct connectdata *conn, - struct SingleRequest *k, - ssize_t nread); - - -#endif /* HEADER_CURL_CONTENT_ENCODING_H */ diff --git a/dep/cpr/opt/curl/lib/cookie.c b/dep/cpr/opt/curl/lib/cookie.c deleted file mode 100644 index 271f6d49d38..00000000000 --- a/dep/cpr/opt/curl/lib/cookie.c +++ /dev/null @@ -1,1479 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/*** - - -RECEIVING COOKIE INFORMATION -============================ - -struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, - const char *file, struct CookieInfo *inc, bool newsession); - - Inits a cookie struct to store data in a local file. This is always - called before any cookies are set. - -struct Cookie *Curl_cookie_add(struct Curl_easy *data, - struct CookieInfo *c, bool httpheader, char *lineptr, - const char *domain, const char *path); - - The 'lineptr' parameter is a full "Set-cookie:" line as - received from a server. - - The function need to replace previously stored lines that this new - line superceeds. - - It may remove lines that are expired. - - It should return an indication of success/error. - - -SENDING COOKIE INFORMATION -========================== - -struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie, - char *host, char *path, bool secure); - - For a given host and path, return a linked list of cookies that - the client should send to the server if used now. The secure - boolean informs the cookie if a secure connection is achieved or - not. - - It shall only return cookies that haven't expired. - - -Example set of cookies: - - Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure - Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/ftgw; secure - Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/; secure - Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/; secure - Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/; secure - Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/; secure - Set-cookie: - Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday, - 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure -****/ - - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - -#ifdef USE_LIBPSL -# include -#endif - -#include "urldata.h" -#include "cookie.h" -#include "strtok.h" -#include "sendf.h" -#include "slist.h" -#include "share.h" -#include "strtoofft.h" -#include "strcase.h" -#include "curl_memrchr.h" -#include "inet_pton.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -static void freecookie(struct Cookie *co) -{ - free(co->expirestr); - free(co->domain); - free(co->path); - free(co->spath); - free(co->name); - free(co->value); - free(co->maxage); - free(co->version); - free(co); -} - -static bool tailmatch(const char *cooke_domain, const char *hostname) -{ - size_t cookie_domain_len = strlen(cooke_domain); - size_t hostname_len = strlen(hostname); - - if(hostname_len < cookie_domain_len) - return FALSE; - - if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len)) - return FALSE; - - /* A lead char of cookie_domain is not '.'. - RFC6265 4.1.2.3. The Domain Attribute says: - For example, if the value of the Domain attribute is - "example.com", the user agent will include the cookie in the Cookie - header when making HTTP requests to example.com, www.example.com, and - www.corp.example.com. - */ - if(hostname_len == cookie_domain_len) - return TRUE; - if('.' == *(hostname + hostname_len - cookie_domain_len - 1)) - return TRUE; - return FALSE; -} - -/* - * matching cookie path and url path - * RFC6265 5.1.4 Paths and Path-Match - */ -static bool pathmatch(const char *cookie_path, const char *request_uri) -{ - size_t cookie_path_len; - size_t uri_path_len; - char *uri_path = NULL; - char *pos; - bool ret = FALSE; - - /* cookie_path must not have last '/' separator. ex: /sample */ - cookie_path_len = strlen(cookie_path); - if(1 == cookie_path_len) { - /* cookie_path must be '/' */ - return TRUE; - } - - uri_path = strdup(request_uri); - if(!uri_path) - return FALSE; - pos = strchr(uri_path, '?'); - if(pos) - *pos = 0x0; - - /* #-fragments are already cut off! */ - if(0 == strlen(uri_path) || uri_path[0] != '/') { - free(uri_path); - uri_path = strdup("/"); - if(!uri_path) - return FALSE; - } - - /* here, RFC6265 5.1.4 says - 4. Output the characters of the uri-path from the first character up - to, but not including, the right-most %x2F ("/"). - but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site - without redirect. - Ignore this algorithm because /hoge is uri path for this case - (uri path is not /). - */ - - uri_path_len = strlen(uri_path); - - if(uri_path_len < cookie_path_len) { - ret = FALSE; - goto pathmatched; - } - - /* not using checkprefix() because matching should be case-sensitive */ - if(strncmp(cookie_path, uri_path, cookie_path_len)) { - ret = FALSE; - goto pathmatched; - } - - /* The cookie-path and the uri-path are identical. */ - if(cookie_path_len == uri_path_len) { - ret = TRUE; - goto pathmatched; - } - - /* here, cookie_path_len < url_path_len */ - if(uri_path[cookie_path_len] == '/') { - ret = TRUE; - goto pathmatched; - } - - ret = FALSE; - -pathmatched: - free(uri_path); - return ret; -} - -/* - * cookie path sanitize - */ -static char *sanitize_cookie_path(const char *cookie_path) -{ - size_t len; - char *new_path = strdup(cookie_path); - if(!new_path) - return NULL; - - /* some stupid site sends path attribute with '"'. */ - len = strlen(new_path); - if(new_path[0] == '\"') { - memmove((void *)new_path, (const void *)(new_path + 1), len); - len--; - } - if(len && (new_path[len - 1] == '\"')) { - new_path[len - 1] = 0x0; - len--; - } - - /* RFC6265 5.2.4 The Path Attribute */ - if(new_path[0] != '/') { - /* Let cookie-path be the default-path. */ - free(new_path); - new_path = strdup("/"); - return new_path; - } - - /* convert /hoge/ to /hoge */ - if(len && new_path[len - 1] == '/') { - new_path[len - 1] = 0x0; - } - - return new_path; -} - -/* - * Load cookies from all given cookie files (CURLOPT_COOKIEFILE). - * - * NOTE: OOM or cookie parsing failures are ignored. - */ -void Curl_cookie_loadfiles(struct Curl_easy *data) -{ - struct curl_slist *list = data->change.cookielist; - if(list) { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - while(list) { - struct CookieInfo *newcookies = Curl_cookie_init(data, - list->data, - data->cookies, - data->set.cookiesession); - if(!newcookies) - /* Failure may be due to OOM or a bad cookie; both are ignored - * but only the first should be - */ - infof(data, "ignoring failed cookie_init for %s\n", list->data); - else - data->cookies = newcookies; - list = list->next; - } - curl_slist_free_all(data->change.cookielist); /* clean up list */ - data->change.cookielist = NULL; /* don't do this again! */ - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } -} - -/* - * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL - * that will be freed before the allocated string is stored there. - * - * It is meant to easily replace strdup() - */ -static void strstore(char **str, const char *newstr) -{ - free(*str); - *str = strdup(newstr); -} - -/* - * remove_expired() removes expired cookies. - */ -static void remove_expired(struct CookieInfo *cookies) -{ - struct Cookie *co, *nx, *pv; - curl_off_t now = (curl_off_t)time(NULL); - - co = cookies->cookies; - pv = NULL; - while(co) { - nx = co->next; - if(co->expires && co->expires < now) { - if(co == cookies->cookies) { - cookies->cookies = co->next; - } - else { - pv->next = co->next; - } - cookies->numcookies--; - freecookie(co); - } - else { - pv = co; - } - co = nx; - } -} - -/* - * Return true if the given string is an IP(v4|v6) address. - */ -static bool isip(const char *domain) -{ - struct in_addr addr; -#ifdef ENABLE_IPV6 - struct in6_addr addr6; -#endif - - if(Curl_inet_pton(AF_INET, domain, &addr) -#ifdef ENABLE_IPV6 - || Curl_inet_pton(AF_INET6, domain, &addr6) -#endif - ) { - /* domain name given as IP address */ - return TRUE; - } - - return FALSE; -} - -/**************************************************************************** - * - * Curl_cookie_add() - * - * Add a single cookie line to the cookie keeping object. - * - * Be aware that sometimes we get an IP-only host name, and that might also be - * a numerical IPv6 address. - * - * Returns NULL on out of memory or invalid cookie. This is suboptimal, - * as they should be treated separately. - ***************************************************************************/ - -struct Cookie * -Curl_cookie_add(struct Curl_easy *data, - /* The 'data' pointer here may be NULL at times, and thus - must only be used very carefully for things that can deal - with data being NULL. Such as infof() and similar */ - - struct CookieInfo *c, - bool httpheader, /* TRUE if HTTP header-style line */ - char *lineptr, /* first character of the line */ - const char *domain, /* default domain */ - const char *path) /* full path used when this cookie is set, - used to get default path for the cookie - unless set */ -{ - struct Cookie *clist; - struct Cookie *co; - struct Cookie *lastc = NULL; - time_t now = time(NULL); - bool replace_old = FALSE; - bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ - -#ifdef USE_LIBPSL - const psl_ctx_t *psl; -#endif - -#ifdef CURL_DISABLE_VERBOSE_STRINGS - (void)data; -#endif - - /* First, alloc and init a new struct for it */ - co = calloc(1, sizeof(struct Cookie)); - if(!co) - return NULL; /* bail out if we're this low on memory */ - - if(httpheader) { - /* This line was read off a HTTP-header */ - char name[MAX_NAME]; - char what[MAX_NAME]; - const char *ptr; - const char *semiptr; - - size_t linelength = strlen(lineptr); - if(linelength > MAX_COOKIE_LINE) { - /* discard overly long lines at once */ - free(co); - return NULL; - } - - semiptr = strchr(lineptr, ';'); /* first, find a semicolon */ - - while(*lineptr && ISBLANK(*lineptr)) - lineptr++; - - ptr = lineptr; - do { - /* we have a = pair or a stand-alone word here */ - name[0] = what[0] = 0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%" - MAX_NAME_TXT "[^;\r\n]", - name, what)) { - /* Use strstore() below to properly deal with received cookie - headers that have the same string property set more than once, - and then we use the last one. */ - const char *whatptr; - bool done = FALSE; - bool sep; - size_t len = strlen(what); - size_t nlen = strlen(name); - const char *endofn = &ptr[ nlen ]; - - infof(data, "cookie size: name/val %d + %d bytes\n", - nlen, len); - - if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) || - ((nlen + len) > MAX_NAME)) { - /* too long individual name or contents, or too long combination of - name + contents. Chrome and Firefox support 4095 or 4096 bytes - combo. */ - freecookie(co); - infof(data, "oversized cookie dropped, name/val %d + %d bytes\n", - nlen, len); - return NULL; - } - - /* name ends with a '=' ? */ - sep = (*endofn == '=')?TRUE:FALSE; - - if(nlen) { - endofn--; /* move to the last character */ - if(ISBLANK(*endofn)) { - /* skip trailing spaces in name */ - while(*endofn && ISBLANK(*endofn) && nlen) { - endofn--; - nlen--; - } - name[nlen] = 0; /* new end of name */ - } - } - - /* Strip off trailing whitespace from the 'what' */ - while(len && ISBLANK(what[len-1])) { - what[len-1] = 0; - len--; - } - - /* Skip leading whitespace from the 'what' */ - whatptr = what; - while(*whatptr && ISBLANK(*whatptr)) - whatptr++; - - if(!co->name && sep) { - /* The very first name/value pair is the actual cookie name */ - co->name = strdup(name); - co->value = strdup(whatptr); - if(!co->name || !co->value) { - badcookie = TRUE; - break; - } - } - else if(!len) { - /* this was a "=" with no content, and we must allow - 'secure' and 'httponly' specified this weirdly */ - done = TRUE; - if(strcasecompare("secure", name)) - co->secure = TRUE; - else if(strcasecompare("httponly", name)) - co->httponly = TRUE; - else if(sep) - /* there was a '=' so we're not done parsing this field */ - done = FALSE; - } - if(done) - ; - else if(strcasecompare("path", name)) { - strstore(&co->path, whatptr); - if(!co->path) { - badcookie = TRUE; /* out of memory bad */ - break; - } - free(co->spath); /* if this is set again */ - co->spath = sanitize_cookie_path(co->path); - if(!co->spath) { - badcookie = TRUE; /* out of memory bad */ - break; - } - } - else if(strcasecompare("domain", name)) { - bool is_ip; - - /* Now, we make sure that our host is within the given domain, - or the given domain is not valid and thus cannot be set. */ - - if('.' == whatptr[0]) - whatptr++; /* ignore preceding dot */ - -#ifndef USE_LIBPSL - /* - * Without PSL we don't know when the incoming cookie is set on a - * TLD or otherwise "protected" suffix. To reduce risk, we require a - * dot OR the exact host name being "localhost". - */ - { - const char *dotp; - /* check for more dots */ - dotp = strchr(whatptr, '.'); - if(!dotp && !strcasecompare("localhost", whatptr)) - domain = ":"; - } -#endif - - is_ip = isip(domain ? domain : whatptr); - - if(!domain - || (is_ip && !strcmp(whatptr, domain)) - || (!is_ip && tailmatch(whatptr, domain))) { - strstore(&co->domain, whatptr); - if(!co->domain) { - badcookie = TRUE; - break; - } - if(!is_ip) - co->tailmatch = TRUE; /* we always do that if the domain name was - given */ - } - else { - /* we did not get a tailmatch and then the attempted set domain - is not a domain to which the current host belongs. Mark as - bad. */ - badcookie = TRUE; - infof(data, "skipped cookie with bad tailmatch domain: %s\n", - whatptr); - } - } - else if(strcasecompare("version", name)) { - strstore(&co->version, whatptr); - if(!co->version) { - badcookie = TRUE; - break; - } - } - else if(strcasecompare("max-age", name)) { - /* Defined in RFC2109: - - Optional. The Max-Age attribute defines the lifetime of the - cookie, in seconds. The delta-seconds value is a decimal non- - negative integer. After delta-seconds seconds elapse, the - client should discard the cookie. A value of zero means the - cookie should be discarded immediately. - - */ - strstore(&co->maxage, whatptr); - if(!co->maxage) { - badcookie = TRUE; - break; - } - } - else if(strcasecompare("expires", name)) { - strstore(&co->expirestr, whatptr); - if(!co->expirestr) { - badcookie = TRUE; - break; - } - } - /* - else this is the second (or more) name we don't know - about! */ - } - else { - /* this is an "illegal" = pair */ - } - - if(!semiptr || !*semiptr) { - /* we already know there are no more cookies */ - semiptr = NULL; - continue; - } - - ptr = semiptr + 1; - while(*ptr && ISBLANK(*ptr)) - ptr++; - semiptr = strchr(ptr, ';'); /* now, find the next semicolon */ - - if(!semiptr && *ptr) - /* There are no more semicolons, but there's a final name=value pair - coming up */ - semiptr = strchr(ptr, '\0'); - } while(semiptr); - - if(co->maxage) { - CURLofft offt; - offt = curlx_strtoofft((*co->maxage == '\"')? - &co->maxage[1]:&co->maxage[0], NULL, 10, - &co->expires); - if(offt == CURL_OFFT_FLOW) - /* overflow, used max value */ - co->expires = CURL_OFF_T_MAX; - else if(!offt) { - if(CURL_OFF_T_MAX - now < co->expires) - /* would overflow */ - co->expires = CURL_OFF_T_MAX; - else - co->expires += now; - } - } - else if(co->expirestr) { - /* Note that if the date couldn't get parsed for whatever reason, - the cookie will be treated as a session cookie */ - co->expires = curl_getdate(co->expirestr, NULL); - - /* Session cookies have expires set to 0 so if we get that back - from the date parser let's add a second to make it a - non-session cookie */ - if(co->expires == 0) - co->expires = 1; - else if(co->expires < 0) - co->expires = 0; - } - - if(!badcookie && !co->domain) { - if(domain) { - /* no domain was given in the header line, set the default */ - co->domain = strdup(domain); - if(!co->domain) - badcookie = TRUE; - } - } - - if(!badcookie && !co->path && path) { - /* No path was given in the header line, set the default. - Note that the passed-in path to this function MAY have a '?' and - following part that MUST not be stored as part of the path. */ - char *queryp = strchr(path, '?'); - - /* queryp is where the interesting part of the path ends, so now we - want to the find the last */ - char *endslash; - if(!queryp) - endslash = strrchr(path, '/'); - else - endslash = memrchr(path, '/', (size_t)(queryp - path)); - if(endslash) { - size_t pathlen = (size_t)(endslash-path + 1); /* include end slash */ - co->path = malloc(pathlen + 1); /* one extra for the zero byte */ - if(co->path) { - memcpy(co->path, path, pathlen); - co->path[pathlen] = 0; /* zero terminate */ - co->spath = sanitize_cookie_path(co->path); - if(!co->spath) - badcookie = TRUE; /* out of memory bad */ - } - else - badcookie = TRUE; - } - } - - if(badcookie || !co->name) { - /* we didn't get a cookie name or a bad one, - this is an illegal line, bail out */ - freecookie(co); - return NULL; - } - - } - else { - /* This line is NOT a HTTP header style line, we do offer support for - reading the odd netscape cookies-file format here */ - char *ptr; - char *firstptr; - char *tok_buf = NULL; - int fields; - - /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies - marked with httpOnly after the domain name are not accessible - from javascripts, but since curl does not operate at javascript - level, we include them anyway. In Firefox's cookie files, these - lines are preceded with #HttpOnly_ and then everything is - as usual, so we skip 10 characters of the line.. - */ - if(strncmp(lineptr, "#HttpOnly_", 10) == 0) { - lineptr += 10; - co->httponly = TRUE; - } - - if(lineptr[0]=='#') { - /* don't even try the comments */ - free(co); - return NULL; - } - /* strip off the possible end-of-line characters */ - ptr = strchr(lineptr, '\r'); - if(ptr) - *ptr = 0; /* clear it */ - ptr = strchr(lineptr, '\n'); - if(ptr) - *ptr = 0; /* clear it */ - - firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ - - /* Now loop through the fields and init the struct we already have - allocated */ - for(ptr = firstptr, fields = 0; ptr && !badcookie; - ptr = strtok_r(NULL, "\t", &tok_buf), fields++) { - switch(fields) { - case 0: - if(ptr[0]=='.') /* skip preceding dots */ - ptr++; - co->domain = strdup(ptr); - if(!co->domain) - badcookie = TRUE; - break; - case 1: - /* This field got its explanation on the 23rd of May 2001 by - Andrés García: - - flag: A TRUE/FALSE value indicating if all machines within a given - domain can access the variable. This value is set automatically by - the browser, depending on the value you set for the domain. - - As far as I can see, it is set to true when the cookie says - .domain.com and to false when the domain is complete www.domain.com - */ - co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE; - break; - case 2: - /* It turns out, that sometimes the file format allows the path - field to remain not filled in, we try to detect this and work - around it! Andrés García made us aware of this... */ - if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) { - /* only if the path doesn't look like a boolean option! */ - co->path = strdup(ptr); - if(!co->path) - badcookie = TRUE; - else { - co->spath = sanitize_cookie_path(co->path); - if(!co->spath) { - badcookie = TRUE; /* out of memory bad */ - } - } - break; - } - /* this doesn't look like a path, make one up! */ - co->path = strdup("/"); - if(!co->path) - badcookie = TRUE; - co->spath = strdup("/"); - if(!co->spath) - badcookie = TRUE; - fields++; /* add a field and fall down to secure */ - /* FALLTHROUGH */ - case 3: - co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE; - break; - case 4: - if(curlx_strtoofft(ptr, NULL, 10, &co->expires)) - badcookie = TRUE; - break; - case 5: - co->name = strdup(ptr); - if(!co->name) - badcookie = TRUE; - break; - case 6: - co->value = strdup(ptr); - if(!co->value) - badcookie = TRUE; - break; - } - } - if(6 == fields) { - /* we got a cookie with blank contents, fix it */ - co->value = strdup(""); - if(!co->value) - badcookie = TRUE; - else - fields++; - } - - if(!badcookie && (7 != fields)) - /* we did not find the sufficient number of fields */ - badcookie = TRUE; - - if(badcookie) { - freecookie(co); - return NULL; - } - - } - - if(!c->running && /* read from a file */ - c->newsession && /* clean session cookies */ - !co->expires) { /* this is a session cookie since it doesn't expire! */ - freecookie(co); - return NULL; - } - - co->livecookie = c->running; - - /* now, we have parsed the incoming line, we must now check if this - superceeds an already existing cookie, which it may if the previous have - the same domain and path as this */ - - /* at first, remove expired cookies */ - remove_expired(c); - -#ifdef USE_LIBPSL - /* Check if the domain is a Public Suffix and if yes, ignore the cookie. - This needs a libpsl compiled with builtin data. */ - if(domain && co->domain && !isip(co->domain)) { - psl = psl_builtin(); - if(psl && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) { - infof(data, - "cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n", - co->name, domain, co->domain); - freecookie(co); - return NULL; - } - } -#endif - - clist = c->cookies; - replace_old = FALSE; - while(clist) { - if(strcasecompare(clist->name, co->name)) { - /* the names are identical */ - - if(clist->domain && co->domain) { - if(strcasecompare(clist->domain, co->domain) && - (clist->tailmatch == co->tailmatch)) - /* The domains are identical */ - replace_old = TRUE; - } - else if(!clist->domain && !co->domain) - replace_old = TRUE; - - if(replace_old) { - /* the domains were identical */ - - if(clist->spath && co->spath) { - if(strcasecompare(clist->spath, co->spath)) { - replace_old = TRUE; - } - else - replace_old = FALSE; - } - else if(!clist->spath && !co->spath) - replace_old = TRUE; - else - replace_old = FALSE; - - } - - if(replace_old && !co->livecookie && clist->livecookie) { - /* Both cookies matched fine, except that the already present - cookie is "live", which means it was set from a header, while - the new one isn't "live" and thus only read from a file. We let - live cookies stay alive */ - - /* Free the newcomer and get out of here! */ - freecookie(co); - return NULL; - } - - if(replace_old) { - co->next = clist->next; /* get the next-pointer first */ - - /* then free all the old pointers */ - free(clist->name); - free(clist->value); - free(clist->domain); - free(clist->path); - free(clist->spath); - free(clist->expirestr); - free(clist->version); - free(clist->maxage); - - *clist = *co; /* then store all the new data */ - - free(co); /* free the newly alloced memory */ - co = clist; /* point to the previous struct instead */ - - /* We have replaced a cookie, now skip the rest of the list but - make sure the 'lastc' pointer is properly set */ - do { - lastc = clist; - clist = clist->next; - } while(clist); - break; - } - } - lastc = clist; - clist = clist->next; - } - - if(c->running) - /* Only show this when NOT reading the cookies from a file */ - infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, " - "expire %" CURL_FORMAT_CURL_OFF_T "\n", - replace_old?"Replaced":"Added", co->name, co->value, - co->domain, co->path, co->expires); - - if(!replace_old) { - /* then make the last item point on this new one */ - if(lastc) - lastc->next = co; - else - c->cookies = co; - c->numcookies++; /* one more cookie in the jar */ - } - - return co; -} - -/* - * get_line() makes sure to only return complete whole lines that fit in 'len' - * bytes and end with a newline. - */ -static char *get_line(char *buf, int len, FILE *input) -{ - bool partial = FALSE; - while(1) { - char *b = fgets(buf, len, input); - if(b) { - size_t rlen = strlen(b); - if(rlen && (b[rlen-1] == '\n')) { - if(partial) { - partial = FALSE; - continue; - } - return b; - } - /* read a partial, discard the next piece that ends with newline */ - partial = TRUE; - } - else - break; - } - return NULL; -} - - -/***************************************************************************** - * - * Curl_cookie_init() - * - * Inits a cookie struct to read data from a local file. This is always - * called before any cookies are set. File may be NULL. - * - * If 'newsession' is TRUE, discard all "session cookies" on read from file. - * - * Returns NULL on out of memory. Invalid cookies are ignored. - ****************************************************************************/ -struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, - const char *file, - struct CookieInfo *inc, - bool newsession) -{ - struct CookieInfo *c; - FILE *fp = NULL; - bool fromfile = TRUE; - char *line = NULL; - - if(NULL == inc) { - /* we didn't get a struct, create one */ - c = calloc(1, sizeof(struct CookieInfo)); - if(!c) - return NULL; /* failed to get memory */ - c->filename = strdup(file?file:"none"); /* copy the name just in case */ - if(!c->filename) - goto fail; /* failed to get memory */ - } - else { - /* we got an already existing one, use that */ - c = inc; - } - c->running = FALSE; /* this is not running, this is init */ - - if(file && !strcmp(file, "-")) { - fp = stdin; - fromfile = FALSE; - } - else if(file && !*file) { - /* points to a "" string */ - fp = NULL; - } - else - fp = file?fopen(file, FOPEN_READTEXT):NULL; - - c->newsession = newsession; /* new session? */ - - if(fp) { - char *lineptr; - bool headerline; - - line = malloc(MAX_COOKIE_LINE); - if(!line) - goto fail; - while(get_line(line, MAX_COOKIE_LINE, fp)) { - if(checkprefix("Set-Cookie:", line)) { - /* This is a cookie line, get it! */ - lineptr = &line[11]; - headerline = TRUE; - } - else { - lineptr = line; - headerline = FALSE; - } - while(*lineptr && ISBLANK(*lineptr)) - lineptr++; - - Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL); - } - free(line); /* free the line buffer */ - - if(fromfile) - fclose(fp); - } - - c->running = TRUE; /* now, we're running */ - - return c; - -fail: - free(line); - if(!inc) - /* Only clean up if we allocated it here, as the original could still be in - * use by a share handle */ - Curl_cookie_cleanup(c); - if(fromfile && fp) - fclose(fp); - return NULL; /* out of memory */ -} - -/* sort this so that the longest path gets before the shorter path */ -static int cookie_sort(const void *p1, const void *p2) -{ - struct Cookie *c1 = *(struct Cookie **)p1; - struct Cookie *c2 = *(struct Cookie **)p2; - size_t l1, l2; - - /* 1 - compare cookie path lengths */ - l1 = c1->path ? strlen(c1->path) : 0; - l2 = c2->path ? strlen(c2->path) : 0; - - if(l1 != l2) - return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */ - - /* 2 - compare cookie domain lengths */ - l1 = c1->domain ? strlen(c1->domain) : 0; - l2 = c2->domain ? strlen(c2->domain) : 0; - - if(l1 != l2) - return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */ - - /* 3 - compare cookie names */ - if(c1->name && c2->name) - return strcmp(c1->name, c2->name); - - /* sorry, can't be more deterministic */ - return 0; -} - -#define CLONE(field) \ - do { \ - if(src->field) { \ - d->field = strdup(src->field); \ - if(!d->field) \ - goto fail; \ - } \ - } while(0) - -static struct Cookie *dup_cookie(struct Cookie *src) -{ - struct Cookie *d = calloc(sizeof(struct Cookie), 1); - if(d) { - CLONE(expirestr); - CLONE(domain); - CLONE(path); - CLONE(spath); - CLONE(name); - CLONE(value); - CLONE(maxage); - CLONE(version); - d->expires = src->expires; - d->tailmatch = src->tailmatch; - d->secure = src->secure; - d->livecookie = src->livecookie; - d->httponly = src->httponly; - } - return d; - - fail: - freecookie(d); - return NULL; -} - -/***************************************************************************** - * - * Curl_cookie_getlist() - * - * For a given host and path, return a linked list of cookies that the - * client should send to the server if used now. The secure boolean informs - * the cookie if a secure connection is achieved or not. - * - * It shall only return cookies that haven't expired. - * - ****************************************************************************/ - -struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, - const char *host, const char *path, - bool secure) -{ - struct Cookie *newco; - struct Cookie *co; - time_t now = time(NULL); - struct Cookie *mainco = NULL; - size_t matches = 0; - bool is_ip; - - if(!c || !c->cookies) - return NULL; /* no cookie struct or no cookies in the struct */ - - /* at first, remove expired cookies */ - remove_expired(c); - - /* check if host is an IP(v4|v6) address */ - is_ip = isip(host); - - co = c->cookies; - - while(co) { - /* only process this cookie if it is not expired or had no expire - date AND that if the cookie requires we're secure we must only - continue if we are! */ - if((!co->expires || (co->expires > now)) && - (co->secure?secure:TRUE)) { - - /* now check if the domain is correct */ - if(!co->domain || - (co->tailmatch && !is_ip && tailmatch(co->domain, host)) || - ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { - /* the right part of the host matches the domain stuff in the - cookie data */ - - /* now check the left part of the path with the cookies path - requirement */ - if(!co->spath || pathmatch(co->spath, path) ) { - - /* and now, we know this is a match and we should create an - entry for the return-linked-list */ - - newco = dup_cookie(co); - if(newco) { - /* then modify our next */ - newco->next = mainco; - - /* point the main to us */ - mainco = newco; - - matches++; - } - else { - fail: - /* failure, clear up the allocated chain and return NULL */ - Curl_cookie_freelist(mainco); - return NULL; - } - } - } - } - co = co->next; - } - - if(matches) { - /* Now we need to make sure that if there is a name appearing more than - once, the longest specified path version comes first. To make this - the swiftest way, we just sort them all based on path length. */ - struct Cookie **array; - size_t i; - - /* alloc an array and store all cookie pointers */ - array = malloc(sizeof(struct Cookie *) * matches); - if(!array) - goto fail; - - co = mainco; - - for(i = 0; co; co = co->next) - array[i++] = co; - - /* now sort the cookie pointers in path length order */ - qsort(array, matches, sizeof(struct Cookie *), cookie_sort); - - /* remake the linked list order according to the new order */ - - mainco = array[0]; /* start here */ - for(i = 0; inext = array[i + 1]; - array[matches-1]->next = NULL; /* terminate the list */ - - free(array); /* remove the temporary data again */ - } - - return mainco; /* return the new list */ -} - -/***************************************************************************** - * - * Curl_cookie_clearall() - * - * Clear all existing cookies and reset the counter. - * - ****************************************************************************/ -void Curl_cookie_clearall(struct CookieInfo *cookies) -{ - if(cookies) { - Curl_cookie_freelist(cookies->cookies); - cookies->cookies = NULL; - cookies->numcookies = 0; - } -} - -/***************************************************************************** - * - * Curl_cookie_freelist() - * - * Free a list of cookies previously returned by Curl_cookie_getlist(); - * - ****************************************************************************/ - -void Curl_cookie_freelist(struct Cookie *co) -{ - struct Cookie *next; - while(co) { - next = co->next; - freecookie(co); - co = next; - } -} - - -/***************************************************************************** - * - * Curl_cookie_clearsess() - * - * Free all session cookies in the cookies list. - * - ****************************************************************************/ -void Curl_cookie_clearsess(struct CookieInfo *cookies) -{ - struct Cookie *first, *curr, *next, *prev = NULL; - - if(!cookies || !cookies->cookies) - return; - - first = curr = prev = cookies->cookies; - - for(; curr; curr = next) { - next = curr->next; - if(!curr->expires) { - if(first == curr) - first = next; - - if(prev == curr) - prev = next; - else - prev->next = next; - - freecookie(curr); - cookies->numcookies--; - } - else - prev = curr; - } - - cookies->cookies = first; -} - - -/***************************************************************************** - * - * Curl_cookie_cleanup() - * - * Free a "cookie object" previous created with Curl_cookie_init(). - * - ****************************************************************************/ -void Curl_cookie_cleanup(struct CookieInfo *c) -{ - if(c) { - free(c->filename); - Curl_cookie_freelist(c->cookies); - free(c); /* free the base struct as well */ - } -} - -/* get_netscape_format() - * - * Formats a string for Netscape output file, w/o a newline at the end. - * - * Function returns a char * to a formatted line. Has to be free()d -*/ -static char *get_netscape_format(const struct Cookie *co) -{ - return aprintf( - "%s" /* httponly preamble */ - "%s%s\t" /* domain */ - "%s\t" /* tailmatch */ - "%s\t" /* path */ - "%s\t" /* secure */ - "%" CURL_FORMAT_CURL_OFF_T "\t" /* expires */ - "%s\t" /* name */ - "%s", /* value */ - co->httponly?"#HttpOnly_":"", - /* Make sure all domains are prefixed with a dot if they allow - tailmatching. This is Mozilla-style. */ - (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"", - co->domain?co->domain:"unknown", - co->tailmatch?"TRUE":"FALSE", - co->path?co->path:"/", - co->secure?"TRUE":"FALSE", - co->expires, - co->name, - co->value?co->value:""); -} - -/* - * cookie_output() - * - * Writes all internally known cookies to the specified file. Specify - * "-" as file name to write to stdout. - * - * The function returns non-zero on write failure. - */ -static int cookie_output(struct CookieInfo *c, const char *dumphere) -{ - struct Cookie *co; - FILE *out; - bool use_stdout = FALSE; - char *format_ptr; - - if((NULL == c) || (0 == c->numcookies)) - /* If there are no known cookies, we don't write or even create any - destination file */ - return 0; - - /* at first, remove expired cookies */ - remove_expired(c); - - if(!strcmp("-", dumphere)) { - /* use stdout */ - out = stdout; - use_stdout = TRUE; - } - else { - out = fopen(dumphere, FOPEN_WRITETEXT); - if(!out) - return 1; /* failure */ - } - - fputs("# Netscape HTTP Cookie File\n" - "# https://curl.haxx.se/docs/http-cookies.html\n" - "# This file was generated by libcurl! Edit at your own risk.\n\n", - out); - - for(co = c->cookies; co; co = co->next) { - if(!co->domain) - continue; - format_ptr = get_netscape_format(co); - if(format_ptr == NULL) { - fprintf(out, "#\n# Fatal libcurl error\n"); - if(!use_stdout) - fclose(out); - return 1; - } - fprintf(out, "%s\n", format_ptr); - free(format_ptr); - } - - if(!use_stdout) - fclose(out); - - return 0; -} - -static struct curl_slist *cookie_list(struct Curl_easy *data) -{ - struct curl_slist *list = NULL; - struct curl_slist *beg; - struct Cookie *c; - char *line; - - if((data->cookies == NULL) || - (data->cookies->numcookies == 0)) - return NULL; - - for(c = data->cookies->cookies; c; c = c->next) { - if(!c->domain) - continue; - line = get_netscape_format(c); - if(!line) { - curl_slist_free_all(list); - return NULL; - } - beg = Curl_slist_append_nodup(list, line); - if(!beg) { - free(line); - curl_slist_free_all(list); - return NULL; - } - list = beg; - } - - return list; -} - -struct curl_slist *Curl_cookie_list(struct Curl_easy *data) -{ - struct curl_slist *list; - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - list = cookie_list(data); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - return list; -} - -void Curl_flush_cookies(struct Curl_easy *data, int cleanup) -{ - if(data->set.str[STRING_COOKIEJAR]) { - if(data->change.cookielist) { - /* If there is a list of cookie files to read, do it first so that - we have all the told files read before we write the new jar. - Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */ - Curl_cookie_loadfiles(data); - } - - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - - /* if we have a destination file for all the cookies to get dumped to */ - if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR])) - infof(data, "WARNING: failed to save cookies in %s\n", - data->set.str[STRING_COOKIEJAR]); - } - else { - if(cleanup && data->change.cookielist) { - /* since nothing is written, we can just free the list of cookie file - names */ - curl_slist_free_all(data->change.cookielist); /* clean up list */ - data->change.cookielist = NULL; - } - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - } - - if(cleanup && (!data->share || (data->cookies != data->share->cookies))) { - Curl_cookie_cleanup(data->cookies); - } - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); -} - -#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */ diff --git a/dep/cpr/opt/curl/lib/cookie.h b/dep/cpr/opt/curl/lib/cookie.h deleted file mode 100644 index cb50b71c6a9..00000000000 --- a/dep/cpr/opt/curl/lib/cookie.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef HEADER_CURL_COOKIE_H -#define HEADER_CURL_COOKIE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#include - -struct Cookie { - struct Cookie *next; /* next in the chain */ - char *name; /* = value */ - char *value; /* name = */ - char *path; /* path = which is in Set-Cookie: */ - char *spath; /* sanitized cookie path */ - char *domain; /* domain = */ - curl_off_t expires; /* expires = */ - char *expirestr; /* the plain text version */ - bool tailmatch; /* weather we do tail-matchning of the domain name */ - - /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */ - char *version; /* Version = */ - char *maxage; /* Max-Age = */ - - bool secure; /* whether the 'secure' keyword was used */ - bool livecookie; /* updated from a server, not a stored file */ - bool httponly; /* true if the httponly directive is present */ -}; - -struct CookieInfo { - /* linked list of cookies we know of */ - struct Cookie *cookies; - - char *filename; /* file we read from/write to */ - bool running; /* state info, for cookie adding information */ - long numcookies; /* number of cookies in the "jar" */ - bool newsession; /* new session, discard session cookies on load */ -}; - -/* This is the maximum line length we accept for a cookie line. RFC 2109 - section 6.3 says: - - "at least 4096 bytes per cookie (as measured by the size of the characters - that comprise the cookie non-terminal in the syntax description of the - Set-Cookie header)" - - We allow max 5000 bytes cookie header. Max 4095 bytes length per cookie - name and value. Name + value may not exceed 4096 bytes. - -*/ -#define MAX_COOKIE_LINE 5000 -#define MAX_COOKIE_LINE_TXT "4999" - -/* This is the maximum length of a cookie name or content we deal with: */ -#define MAX_NAME 4096 -#define MAX_NAME_TXT "4095" - -struct Curl_easy; -/* - * Add a cookie to the internal list of cookies. The domain and path arguments - * are only used if the header boolean is TRUE. - */ - -struct Cookie *Curl_cookie_add(struct Curl_easy *data, - struct CookieInfo *, bool header, char *lineptr, - const char *domain, const char *path); - -struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *, - const char *, bool); -void Curl_cookie_freelist(struct Cookie *cookies); -void Curl_cookie_clearall(struct CookieInfo *cookies); -void Curl_cookie_clearsess(struct CookieInfo *cookies); - -#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) -#define Curl_cookie_list(x) NULL -#define Curl_cookie_loadfiles(x) Curl_nop_stmt -#define Curl_cookie_init(x,y,z,w) NULL -#define Curl_cookie_cleanup(x) Curl_nop_stmt -#define Curl_flush_cookies(x,y) Curl_nop_stmt -#else -void Curl_flush_cookies(struct Curl_easy *data, int cleanup); -void Curl_cookie_cleanup(struct CookieInfo *); -struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, - const char *, struct CookieInfo *, bool); -struct curl_slist *Curl_cookie_list(struct Curl_easy *data); -void Curl_cookie_loadfiles(struct Curl_easy *data); -#endif - -#endif /* HEADER_CURL_COOKIE_H */ diff --git a/dep/cpr/opt/curl/lib/curl_addrinfo.c b/dep/cpr/opt/curl/lib/curl_addrinfo.c deleted file mode 100644 index 6eb28bbcb6c..00000000000 --- a/dep/cpr/opt/curl/lib/curl_addrinfo.c +++ /dev/null @@ -1,616 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_NETDB_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif -#ifdef HAVE_SYS_UN_H -# include -#endif - -#ifdef __VMS -# include -# include -#endif - -#if defined(NETWARE) && defined(__NOVELL_LIBC__) -# undef in_addr_t -# define in_addr_t unsigned long -#endif - -#include - -#include "curl_addrinfo.h" -#include "inet_pton.h" -#include "warnless.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_freeaddrinfo() - * - * This is used to free a linked list of Curl_addrinfo structs along - * with all its associated allocated storage. This function should be - * called once for each successful call to Curl_getaddrinfo_ex() or to - * any function call which actually allocates a Curl_addrinfo struct. - */ - -#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ - defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) - /* workaround icc 9.1 optimizer issue */ -# define vqualifier volatile -#else -# define vqualifier -#endif - -void -Curl_freeaddrinfo(Curl_addrinfo *cahead) -{ - Curl_addrinfo *vqualifier canext; - Curl_addrinfo *ca; - - for(ca = cahead; ca != NULL; ca = canext) { - free(ca->ai_addr); - free(ca->ai_canonname); - canext = ca->ai_next; - - free(ca); - } -} - - -#ifdef HAVE_GETADDRINFO -/* - * Curl_getaddrinfo_ex() - * - * This is a wrapper function around system's getaddrinfo(), with - * the only difference that instead of returning a linked list of - * addrinfo structs this one returns a linked list of Curl_addrinfo - * ones. The memory allocated by this function *MUST* be free'd with - * Curl_freeaddrinfo(). For each successful call to this function - * there must be an associated call later to Curl_freeaddrinfo(). - * - * There should be no single call to system's getaddrinfo() in the - * whole library, any such call should be 'routed' through this one. - */ - -int -Curl_getaddrinfo_ex(const char *nodename, - const char *servname, - const struct addrinfo *hints, - Curl_addrinfo **result) -{ - const struct addrinfo *ai; - struct addrinfo *aihead; - Curl_addrinfo *cafirst = NULL; - Curl_addrinfo *calast = NULL; - Curl_addrinfo *ca; - size_t ss_size; - int error; - - *result = NULL; /* assume failure */ - - error = getaddrinfo(nodename, servname, hints, &aihead); - if(error) - return error; - - /* traverse the addrinfo list */ - - for(ai = aihead; ai != NULL; ai = ai->ai_next) { - - /* ignore elements with unsupported address family, */ - /* settle family-specific sockaddr structure size. */ - if(ai->ai_family == AF_INET) - ss_size = sizeof(struct sockaddr_in); -#ifdef ENABLE_IPV6 - else if(ai->ai_family == AF_INET6) - ss_size = sizeof(struct sockaddr_in6); -#endif - else - continue; - - /* ignore elements without required address info */ - if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0)) - continue; - - /* ignore elements with bogus address size */ - if((size_t)ai->ai_addrlen < ss_size) - continue; - - ca = malloc(sizeof(Curl_addrinfo)); - if(!ca) { - error = EAI_MEMORY; - break; - } - - /* copy each structure member individually, member ordering, */ - /* size, or padding might be different for each platform. */ - - ca->ai_flags = ai->ai_flags; - ca->ai_family = ai->ai_family; - ca->ai_socktype = ai->ai_socktype; - ca->ai_protocol = ai->ai_protocol; - ca->ai_addrlen = (curl_socklen_t)ss_size; - ca->ai_addr = NULL; - ca->ai_canonname = NULL; - ca->ai_next = NULL; - - ca->ai_addr = malloc(ss_size); - if(!ca->ai_addr) { - error = EAI_MEMORY; - free(ca); - break; - } - memcpy(ca->ai_addr, ai->ai_addr, ss_size); - - if(ai->ai_canonname != NULL) { - ca->ai_canonname = strdup(ai->ai_canonname); - if(!ca->ai_canonname) { - error = EAI_MEMORY; - free(ca->ai_addr); - free(ca); - break; - } - } - - /* if the return list is empty, this becomes the first element */ - if(!cafirst) - cafirst = ca; - - /* add this element last in the return list */ - if(calast) - calast->ai_next = ca; - calast = ca; - - } - - /* destroy the addrinfo list */ - if(aihead) - freeaddrinfo(aihead); - - /* if we failed, also destroy the Curl_addrinfo list */ - if(error) { - Curl_freeaddrinfo(cafirst); - cafirst = NULL; - } - else if(!cafirst) { -#ifdef EAI_NONAME - /* rfc3493 conformant */ - error = EAI_NONAME; -#else - /* rfc3493 obsoleted */ - error = EAI_NODATA; -#endif -#ifdef USE_WINSOCK - SET_SOCKERRNO(error); -#endif - } - - *result = cafirst; - - /* This is not a CURLcode */ - return error; -} -#endif /* HAVE_GETADDRINFO */ - - -/* - * Curl_he2ai() - * - * This function returns a pointer to the first element of a newly allocated - * Curl_addrinfo struct linked list filled with the data of a given hostent. - * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6 - * stack, but usable also for IPv4, all hosts and environments. - * - * The memory allocated by this function *MUST* be free'd later on calling - * Curl_freeaddrinfo(). For each successful call to this function there - * must be an associated call later to Curl_freeaddrinfo(). - * - * Curl_addrinfo defined in "lib/curl_addrinfo.h" - * - * struct Curl_addrinfo { - * int ai_flags; - * int ai_family; - * int ai_socktype; - * int ai_protocol; - * curl_socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo * - * char *ai_canonname; - * struct sockaddr *ai_addr; - * struct Curl_addrinfo *ai_next; - * }; - * typedef struct Curl_addrinfo Curl_addrinfo; - * - * hostent defined in - * - * struct hostent { - * char *h_name; - * char **h_aliases; - * int h_addrtype; - * int h_length; - * char **h_addr_list; - * }; - * - * for backward compatibility: - * - * #define h_addr h_addr_list[0] - */ - -Curl_addrinfo * -Curl_he2ai(const struct hostent *he, int port) -{ - Curl_addrinfo *ai; - Curl_addrinfo *prevai = NULL; - Curl_addrinfo *firstai = NULL; - struct sockaddr_in *addr; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 *addr6; -#endif - CURLcode result = CURLE_OK; - int i; - char *curr; - - if(!he) - /* no input == no output! */ - return NULL; - - DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL)); - - for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { - - size_t ss_size; -#ifdef ENABLE_IPV6 - if(he->h_addrtype == AF_INET6) - ss_size = sizeof(struct sockaddr_in6); - else -#endif - ss_size = sizeof(struct sockaddr_in); - - ai = calloc(1, sizeof(Curl_addrinfo)); - if(!ai) { - result = CURLE_OUT_OF_MEMORY; - break; - } - ai->ai_canonname = strdup(he->h_name); - if(!ai->ai_canonname) { - result = CURLE_OUT_OF_MEMORY; - free(ai); - break; - } - ai->ai_addr = calloc(1, ss_size); - if(!ai->ai_addr) { - result = CURLE_OUT_OF_MEMORY; - free(ai->ai_canonname); - free(ai); - break; - } - - if(!firstai) - /* store the pointer we want to return from this function */ - firstai = ai; - - if(prevai) - /* make the previous entry point to this */ - prevai->ai_next = ai; - - ai->ai_family = he->h_addrtype; - - /* we return all names as STREAM, so when using this address for TFTP - the type must be ignored and conn->socktype be used instead! */ - ai->ai_socktype = SOCK_STREAM; - - ai->ai_addrlen = (curl_socklen_t)ss_size; - - /* leave the rest of the struct filled with zero */ - - switch(ai->ai_family) { - case AF_INET: - addr = (void *)ai->ai_addr; /* storage area for this info */ - - memcpy(&addr->sin_addr, curr, sizeof(struct in_addr)); - addr->sin_family = (unsigned short)(he->h_addrtype); - addr->sin_port = htons((unsigned short)port); - break; - -#ifdef ENABLE_IPV6 - case AF_INET6: - addr6 = (void *)ai->ai_addr; /* storage area for this info */ - - memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr)); - addr6->sin6_family = (unsigned short)(he->h_addrtype); - addr6->sin6_port = htons((unsigned short)port); - break; -#endif - } - - prevai = ai; - } - - if(result) { - Curl_freeaddrinfo(firstai); - firstai = NULL; - } - - return firstai; -} - - -struct namebuff { - struct hostent hostentry; - union { - struct in_addr ina4; -#ifdef ENABLE_IPV6 - struct in6_addr ina6; -#endif - } addrentry; - char *h_addr_list[2]; -}; - - -/* - * Curl_ip2addr() - * - * This function takes an internet address, in binary form, as input parameter - * along with its address family and the string version of the address, and it - * returns a Curl_addrinfo chain filled in correctly with information for the - * given address/host - */ - -Curl_addrinfo * -Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) -{ - Curl_addrinfo *ai; - -#if defined(__VMS) && \ - defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) -#pragma pointer_size save -#pragma pointer_size short -#pragma message disable PTRMISMATCH -#endif - - struct hostent *h; - struct namebuff *buf; - char *addrentry; - char *hoststr; - size_t addrsize; - - DEBUGASSERT(inaddr && hostname); - - buf = malloc(sizeof(struct namebuff)); - if(!buf) - return NULL; - - hoststr = strdup(hostname); - if(!hoststr) { - free(buf); - return NULL; - } - - switch(af) { - case AF_INET: - addrsize = sizeof(struct in_addr); - addrentry = (void *)&buf->addrentry.ina4; - memcpy(addrentry, inaddr, sizeof(struct in_addr)); - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - addrsize = sizeof(struct in6_addr); - addrentry = (void *)&buf->addrentry.ina6; - memcpy(addrentry, inaddr, sizeof(struct in6_addr)); - break; -#endif - default: - free(hoststr); - free(buf); - return NULL; - } - - h = &buf->hostentry; - h->h_name = hoststr; - h->h_aliases = NULL; - h->h_addrtype = (short)af; - h->h_length = (short)addrsize; - h->h_addr_list = &buf->h_addr_list[0]; - h->h_addr_list[0] = addrentry; - h->h_addr_list[1] = NULL; /* terminate list of entries */ - -#if defined(__VMS) && \ - defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) -#pragma pointer_size restore -#pragma message enable PTRMISMATCH -#endif - - ai = Curl_he2ai(h, port); - - free(hoststr); - free(buf); - - return ai; -} - -/* - * Given an IPv4 or IPv6 dotted string address, this converts it to a proper - * allocated Curl_addrinfo struct and returns it. - */ -Curl_addrinfo *Curl_str2addr(char *address, int port) -{ - struct in_addr in; - if(Curl_inet_pton(AF_INET, address, &in) > 0) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, address, port); -#ifdef ENABLE_IPV6 - { - struct in6_addr in6; - if(Curl_inet_pton(AF_INET6, address, &in6) > 0) - /* This is a dotted IPv6 address ::1-style */ - return Curl_ip2addr(AF_INET6, &in6, address, port); - } -#endif - return NULL; /* bad input format */ -} - -#ifdef USE_UNIX_SOCKETS -/** - * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo - * struct initialized with this path. - * Set '*longpath' to TRUE if the error is a too long path. - */ -Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract) -{ - Curl_addrinfo *ai; - struct sockaddr_un *sa_un; - size_t path_len; - - *longpath = FALSE; - - ai = calloc(1, sizeof(Curl_addrinfo)); - if(!ai) - return NULL; - ai->ai_addr = calloc(1, sizeof(struct sockaddr_un)); - if(!ai->ai_addr) { - free(ai); - return NULL; - } - - sa_un = (void *) ai->ai_addr; - sa_un->sun_family = AF_UNIX; - - /* sun_path must be able to store the NUL-terminated path */ - path_len = strlen(path) + 1; - if(path_len > sizeof(sa_un->sun_path)) { - free(ai->ai_addr); - free(ai); - *longpath = TRUE; - return NULL; - } - - ai->ai_family = AF_UNIX; - ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ - ai->ai_addrlen = (curl_socklen_t) - ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF); - - /* Abstract Unix domain socket have NULL prefix instead of suffix */ - if(abstract) - memcpy(sa_un->sun_path + 1, path, path_len - 1); - else - memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */ - - return ai; -} -#endif - -#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) -/* - * curl_dofreeaddrinfo() - * - * This is strictly for memory tracing and are using the same style as the - * family otherwise present in memdebug.c. I put these ones here since they - * require a bunch of structs I didn't want to include in memdebug.c - */ - -void -curl_dofreeaddrinfo(struct addrinfo *freethis, - int line, const char *source) -{ -#ifdef USE_LWIPSOCK - lwip_freeaddrinfo(freethis); -#else - (freeaddrinfo)(freethis); -#endif - curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n", - source, line, (void *)freethis); -} -#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */ - - -#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) -/* - * curl_dogetaddrinfo() - * - * This is strictly for memory tracing and are using the same style as the - * family otherwise present in memdebug.c. I put these ones here since they - * require a bunch of structs I didn't want to include in memdebug.c - */ - -int -curl_dogetaddrinfo(const char *hostname, - const char *service, - const struct addrinfo *hints, - struct addrinfo **result, - int line, const char *source) -{ -#ifdef USE_LWIPSOCK - int res = lwip_getaddrinfo(hostname, service, hints, result); -#else - int res = (getaddrinfo)(hostname, service, hints, result); -#endif - if(0 == res) - /* success */ - curl_memlog("ADDR %s:%d getaddrinfo() = %p\n", - source, line, (void *)*result); - else - curl_memlog("ADDR %s:%d getaddrinfo() failed\n", - source, line); - return res; -} -#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */ - -#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS) -/* - * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X - * 10.11.5. - */ -void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port) -{ - Curl_addrinfo *ca; - struct sockaddr_in *addr; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 *addr6; -#endif - for(ca = addrinfo; ca != NULL; ca = ca->ai_next) { - switch(ca->ai_family) { - case AF_INET: - addr = (void *)ca->ai_addr; /* storage area for this info */ - addr->sin_port = htons((unsigned short)port); - break; - -#ifdef ENABLE_IPV6 - case AF_INET6: - addr6 = (void *)ca->ai_addr; /* storage area for this info */ - addr6->sin6_port = htons((unsigned short)port); - break; -#endif - } - } -} -#endif diff --git a/dep/cpr/opt/curl/lib/curl_addrinfo.h b/dep/cpr/opt/curl/lib/curl_addrinfo.h deleted file mode 100644 index 8f6f3d10647..00000000000 --- a/dep/cpr/opt/curl/lib/curl_addrinfo.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef HEADER_CURL_ADDRINFO_H -#define HEADER_CURL_ADDRINFO_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_NETDB_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif - -#ifdef __VMS -# include -# include -# include -#endif - - -/* - * Curl_addrinfo is our internal struct definition that we use to allow - * consistent internal handling of this data. We use this even when the - * system provides an addrinfo structure definition. And we use this for - * all sorts of IPv4 and IPV6 builds. - */ - -struct Curl_addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - curl_socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */ - char *ai_canonname; - struct sockaddr *ai_addr; - struct Curl_addrinfo *ai_next; -}; -typedef struct Curl_addrinfo Curl_addrinfo; - -void -Curl_freeaddrinfo(Curl_addrinfo *cahead); - -#ifdef HAVE_GETADDRINFO -int -Curl_getaddrinfo_ex(const char *nodename, - const char *servname, - const struct addrinfo *hints, - Curl_addrinfo **result); -#endif - -Curl_addrinfo * -Curl_he2ai(const struct hostent *he, int port); - -Curl_addrinfo * -Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); - -Curl_addrinfo *Curl_str2addr(char *dotted, int port); - -#ifdef USE_UNIX_SOCKETS -Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract); -#endif - -#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ - defined(HAVE_FREEADDRINFO) -void -curl_dofreeaddrinfo(struct addrinfo *freethis, - int line, const char *source); -#endif - -#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) -int -curl_dogetaddrinfo(const char *hostname, - const char *service, - const struct addrinfo *hints, - struct addrinfo **result, - int line, const char *source); -#endif - -#ifdef HAVE_GETADDRINFO -#ifdef USE_RESOLVE_ON_IPS -void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port); -#else -#define Curl_addrinfo_set_port(x,y) -#endif -#endif - -#endif /* HEADER_CURL_ADDRINFO_H */ diff --git a/dep/cpr/opt/curl/lib/curl_base64.h b/dep/cpr/opt/curl/lib/curl_base64.h deleted file mode 100644 index 7e9fc26062a..00000000000 --- a/dep/cpr/opt/curl/lib/curl_base64.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef HEADER_CURL_BASE64_H -#define HEADER_CURL_BASE64_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -CURLcode Curl_base64_encode(struct Curl_easy *data, - const char *inputbuff, size_t insize, - char **outptr, size_t *outlen); -CURLcode Curl_base64url_encode(struct Curl_easy *data, - const char *inputbuff, size_t insize, - char **outptr, size_t *outlen); - -CURLcode Curl_base64_decode(const char *src, - unsigned char **outptr, size_t *outlen); - -#endif /* HEADER_CURL_BASE64_H */ diff --git a/dep/cpr/opt/curl/lib/curl_config.h.cmake b/dep/cpr/opt/curl/lib/curl_config.h.cmake deleted file mode 100644 index c80484f6521..00000000000 --- a/dep/cpr/opt/curl/lib/curl_config.h.cmake +++ /dev/null @@ -1,1002 +0,0 @@ -/* lib/curl_config.h.in. Generated somehow by cmake. */ - -/* when building libcurl itself */ -#cmakedefine BUILDING_LIBCURL 1 - -/* Location of default ca bundle */ -#cmakedefine CURL_CA_BUNDLE "${CURL_CA_BUNDLE}" - -/* define "1" to use built-in ca store of TLS backend */ -#cmakedefine CURL_CA_FALLBACK 1 - -/* Location of default ca path */ -#cmakedefine CURL_CA_PATH "${CURL_CA_PATH}" - -/* to disable cookies support */ -#cmakedefine CURL_DISABLE_COOKIES 1 - -/* to disable cryptographic authentication */ -#cmakedefine CURL_DISABLE_CRYPTO_AUTH 1 - -/* to disable DICT */ -#cmakedefine CURL_DISABLE_DICT 1 - -/* to disable FILE */ -#cmakedefine CURL_DISABLE_FILE 1 - -/* to disable FTP */ -#cmakedefine CURL_DISABLE_FTP 1 - -/* to disable GOPHER */ -#cmakedefine CURL_DISABLE_GOPHER 1 - -/* to disable IMAP */ -#cmakedefine CURL_DISABLE_IMAP 1 - -/* to disable HTTP */ -#cmakedefine CURL_DISABLE_HTTP 1 - -/* to disable LDAP */ -#cmakedefine CURL_DISABLE_LDAP 1 - -/* to disable LDAPS */ -#cmakedefine CURL_DISABLE_LDAPS 1 - -/* to disable POP3 */ -#cmakedefine CURL_DISABLE_POP3 1 - -/* to disable proxies */ -#cmakedefine CURL_DISABLE_PROXY 1 - -/* to disable RTSP */ -#cmakedefine CURL_DISABLE_RTSP 1 - -/* to disable SMB */ -#cmakedefine CURL_DISABLE_SMB 1 - -/* to disable SMTP */ -#cmakedefine CURL_DISABLE_SMTP 1 - -/* to disable TELNET */ -#cmakedefine CURL_DISABLE_TELNET 1 - -/* to disable TFTP */ -#cmakedefine CURL_DISABLE_TFTP 1 - -/* to disable verbose strings */ -#cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1 - -/* to make a symbol visible */ -#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL} -/* Ensure using CURL_EXTERN_SYMBOL is possible */ -#ifndef CURL_EXTERN_SYMBOL -#define CURL_EXTERN_SYMBOL -#endif - -/* Use Windows LDAP implementation */ -#cmakedefine USE_WIN32_LDAP 1 - -/* when not building a shared library */ -#cmakedefine CURL_STATICLIB 1 - -/* your Entropy Gathering Daemon socket pathname */ -#cmakedefine EGD_SOCKET ${EGD_SOCKET} - -/* Define if you want to enable IPv6 support */ -#cmakedefine ENABLE_IPV6 1 - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -#cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1} - -/* Define to the type of arg 1 for getnameinfo. */ -#cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1} - -/* Define to the type of arg 2 for getnameinfo. */ -#cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2} - -/* Define to the type of args 4 and 6 for getnameinfo. */ -#cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46} - -/* Define to the type of arg 7 for getnameinfo. */ -#cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7} - -/* Specifies the number of arguments to getservbyport_r */ -#cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS} - -/* Specifies the size of the buffer to pass to getservbyport_r */ -#cmakedefine GETSERVBYPORT_R_BUFSIZE ${GETSERVBYPORT_R_BUFSIZE} - -/* Define to 1 if you have the alarm function. */ -#cmakedefine HAVE_ALARM 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_ALLOCA_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_ARPA_TFTP_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_ASSERT_H 1 - -/* Define to 1 if you have the `basename' function. */ -#cmakedefine HAVE_BASENAME 1 - -/* Define to 1 if bool is an available type. */ -#cmakedefine HAVE_BOOL_T 1 - -/* Define to 1 if you have the clock_gettime function and monotonic timer. */ -#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1 - -/* Define to 1 if you have the `closesocket' function. */ -#cmakedefine HAVE_CLOSESOCKET 1 - -/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ -#cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_CRYPTO_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_DES_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_DLFCN_H 1 - -/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */ -#cmakedefine HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_ERR_H 1 - -/* Define to 1 if you have the fcntl function. */ -#cmakedefine HAVE_FCNTL 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_FCNTL_H 1 - -/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ -#cmakedefine HAVE_FCNTL_O_NONBLOCK 1 - -/* Define to 1 if you have the fdopen function. */ -#cmakedefine HAVE_FDOPEN 1 - -/* Define to 1 if you have the `fork' function. */ -#cmakedefine HAVE_FORK 1 - -/* Define to 1 if you have the freeaddrinfo function. */ -#cmakedefine HAVE_FREEADDRINFO 1 - -/* Define to 1 if you have the freeifaddrs function. */ -#cmakedefine HAVE_FREEIFADDRS 1 - -/* Define to 1 if you have the ftruncate function. */ -#cmakedefine HAVE_FTRUNCATE 1 - -/* Define to 1 if you have a working getaddrinfo function. */ -#cmakedefine HAVE_GETADDRINFO 1 - -/* Define to 1 if you have the `geteuid' function. */ -#cmakedefine HAVE_GETEUID 1 - -/* Define to 1 if you have the gethostbyaddr function. */ -#cmakedefine HAVE_GETHOSTBYADDR 1 - -/* Define to 1 if you have the gethostbyaddr_r function. */ -#cmakedefine HAVE_GETHOSTBYADDR_R 1 - -/* gethostbyaddr_r() takes 5 args */ -#cmakedefine HAVE_GETHOSTBYADDR_R_5 1 - -/* gethostbyaddr_r() takes 7 args */ -#cmakedefine HAVE_GETHOSTBYADDR_R_7 1 - -/* gethostbyaddr_r() takes 8 args */ -#cmakedefine HAVE_GETHOSTBYADDR_R_8 1 - -/* Define to 1 if you have the gethostbyname function. */ -#cmakedefine HAVE_GETHOSTBYNAME 1 - -/* Define to 1 if you have the gethostbyname_r function. */ -#cmakedefine HAVE_GETHOSTBYNAME_R 1 - -/* gethostbyname_r() takes 3 args */ -#cmakedefine HAVE_GETHOSTBYNAME_R_3 1 - -/* gethostbyname_r() takes 5 args */ -#cmakedefine HAVE_GETHOSTBYNAME_R_5 1 - -/* gethostbyname_r() takes 6 args */ -#cmakedefine HAVE_GETHOSTBYNAME_R_6 1 - -/* Define to 1 if you have the gethostname function. */ -#cmakedefine HAVE_GETHOSTNAME 1 - -/* Define to 1 if you have a working getifaddrs function. */ -#cmakedefine HAVE_GETIFADDRS 1 - -/* Define to 1 if you have the getnameinfo function. */ -#cmakedefine HAVE_GETNAMEINFO 1 - -/* Define to 1 if you have the `getpass_r' function. */ -#cmakedefine HAVE_GETPASS_R 1 - -/* Define to 1 if you have the `getppid' function. */ -#cmakedefine HAVE_GETPPID 1 - -/* Define to 1 if you have the `getprotobyname' function. */ -#cmakedefine HAVE_GETPROTOBYNAME 1 - -/* Define to 1 if you have the `getpwuid' function. */ -#cmakedefine HAVE_GETPWUID 1 - -/* Define to 1 if you have the `getrlimit' function. */ -#cmakedefine HAVE_GETRLIMIT 1 - -/* Define to 1 if you have the getservbyport_r function. */ -#cmakedefine HAVE_GETSERVBYPORT_R 1 - -/* Define to 1 if you have the `gettimeofday' function. */ -#cmakedefine HAVE_GETTIMEOFDAY 1 - -/* Define to 1 if you have a working glibc-style strerror_r function. */ -#cmakedefine HAVE_GLIBC_STRERROR_R 1 - -/* Define to 1 if you have a working gmtime_r function. */ -#cmakedefine HAVE_GMTIME_R 1 - -/* if you have the gssapi libraries */ -#cmakedefine HAVE_GSSAPI 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_GSSAPI_GSSAPI_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H 1 - -/* if you have the GNU gssapi libraries */ -#cmakedefine HAVE_GSSGNU 1 - -/* if you have the Heimdal gssapi libraries */ -#cmakedefine HAVE_GSSHEIMDAL 1 - -/* if you have the MIT gssapi libraries */ -#cmakedefine HAVE_GSSMIT 1 - -/* Define to 1 if you have the `idna_strerror' function. */ -#cmakedefine HAVE_IDNA_STRERROR 1 - -/* Define to 1 if you have the `idn_free' function. */ -#cmakedefine HAVE_IDN_FREE 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_IDN_FREE_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_IFADDRS_H 1 - -/* Define to 1 if you have the `inet_addr' function. */ -#cmakedefine HAVE_INET_ADDR 1 - -/* Define to 1 if you have the inet_ntoa_r function. */ -#cmakedefine HAVE_INET_NTOA_R 1 - -/* inet_ntoa_r() takes 2 args */ -#cmakedefine HAVE_INET_NTOA_R_2 1 - -/* inet_ntoa_r() takes 3 args */ -#cmakedefine HAVE_INET_NTOA_R_3 1 - -/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ -#cmakedefine HAVE_INET_NTOP 1 - -/* Define to 1 if you have a IPv6 capable working inet_pton function. */ -#cmakedefine HAVE_INET_PTON 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the ioctl function. */ -#cmakedefine HAVE_IOCTL 1 - -/* Define to 1 if you have the ioctlsocket function. */ -#cmakedefine HAVE_IOCTLSOCKET 1 - -/* Define to 1 if you have the IoctlSocket camel case function. */ -#cmakedefine HAVE_IOCTLSOCKET_CAMEL 1 - -/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. - */ -#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1 - -/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ -#cmakedefine HAVE_IOCTLSOCKET_FIONBIO 1 - -/* Define to 1 if you have a working ioctl FIONBIO function. */ -#cmakedefine HAVE_IOCTL_FIONBIO 1 - -/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ -#cmakedefine HAVE_IOCTL_SIOCGIFADDR 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_IO_H 1 - -/* if you have the Kerberos4 libraries (including -ldes) */ -#cmakedefine HAVE_KRB4 1 - -/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ -#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_KRB_H 1 - -/* Define to 1 if you have the lber.h header file. */ -#cmakedefine HAVE_LBER_H 1 - -/* Define to 1 if you have the ldapssl.h header file. */ -#cmakedefine HAVE_LDAPSSL_H 1 - -/* Define to 1 if you have the ldap.h header file. */ -#cmakedefine HAVE_LDAP_H 1 - -/* Use LDAPS implementation */ -#cmakedefine HAVE_LDAP_SSL 1 - -/* Define to 1 if you have the ldap_ssl.h header file. */ -#cmakedefine HAVE_LDAP_SSL_H 1 - -/* Define to 1 if you have the `ldap_url_parse' function. */ -#cmakedefine HAVE_LDAP_URL_PARSE 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_LIBGEN_H 1 - -/* Define to 1 if you have the `idn' library (-lidn). */ -#cmakedefine HAVE_LIBIDN 1 - -/* Define to 1 if you have the `resolv' library (-lresolv). */ -#cmakedefine HAVE_LIBRESOLV 1 - -/* Define to 1 if you have the `resolve' library (-lresolve). */ -#cmakedefine HAVE_LIBRESOLVE 1 - -/* Define to 1 if you have the `socket' library (-lsocket). */ -#cmakedefine HAVE_LIBSOCKET 1 - -/* Define to 1 if you have the `ssh2' library (-lssh2). */ -#cmakedefine HAVE_LIBSSH2 1 - -/* Define to 1 if libssh2 provides `libssh2_version'. */ -#cmakedefine HAVE_LIBSSH2_VERSION 1 - -/* Define to 1 if libssh2 provides `libssh2_init'. */ -#cmakedefine HAVE_LIBSSH2_INIT 1 - -/* Define to 1 if libssh2 provides `libssh2_exit'. */ -#cmakedefine HAVE_LIBSSH2_EXIT 1 - -/* Define to 1 if libssh2 provides `libssh2_scp_send64'. */ -#cmakedefine HAVE_LIBSSH2_SCP_SEND64 1 - -/* Define to 1 if libssh2 provides `libssh2_session_handshake'. */ -#cmakedefine HAVE_LIBSSH2_SESSION_HANDSHAKE 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_LIBSSH2_H 1 - -/* Define to 1 if you have the `ssl' library (-lssl). */ -#cmakedefine HAVE_LIBSSL 1 - -/* if zlib is available */ -#cmakedefine HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_LIMITS_H 1 - -/* if your compiler supports LL */ -#cmakedefine HAVE_LL 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_LOCALE_H 1 - -/* Define to 1 if you have a working localtime_r function. */ -#cmakedefine HAVE_LOCALTIME_R 1 - -/* Define to 1 if the compiler supports the 'long long' data type. */ -#cmakedefine HAVE_LONGLONG 1 - -/* Define to 1 if you have the malloc.h header file. */ -#cmakedefine HAVE_MALLOC_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_MEMORY_H 1 - -/* Define to 1 if you have the MSG_NOSIGNAL flag. */ -#cmakedefine HAVE_MSG_NOSIGNAL 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_NETDB_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_NETINET_TCP_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_NET_IF_H 1 - -/* Define to 1 if NI_WITHSCOPEID exists and works. */ -#cmakedefine HAVE_NI_WITHSCOPEID 1 - -/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */ -#cmakedefine HAVE_OLD_GSSMIT 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_CRYPTO_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_ENGINE_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_ERR_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_PEM_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_PKCS12_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_RSA_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_SSL_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_X509_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_PEM_H 1 - -/* Define to 1 if you have the `perror' function. */ -#cmakedefine HAVE_PERROR 1 - -/* Define to 1 if you have the `pipe' function. */ -#cmakedefine HAVE_PIPE 1 - -/* Define to 1 if you have a working poll function. */ -#cmakedefine HAVE_POLL 1 - -/* If you have a fine poll */ -#cmakedefine HAVE_POLL_FINE 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_POLL_H 1 - -/* Define to 1 if you have a working POSIX-style strerror_r function. */ -#cmakedefine HAVE_POSIX_STRERROR_R 1 - -/* Define to 1 if you have the header file */ -#cmakedefine HAVE_PTHREAD_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_PWD_H 1 - -/* Define to 1 if you have the `RAND_egd' function. */ -#cmakedefine HAVE_RAND_EGD 1 - -/* Define to 1 if you have the `RAND_screen' function. */ -#cmakedefine HAVE_RAND_SCREEN 1 - -/* Define to 1 if you have the `RAND_status' function. */ -#cmakedefine HAVE_RAND_STATUS 1 - -/* Define to 1 if you have the recv function. */ -#cmakedefine HAVE_RECV 1 - -/* Define to 1 if you have the recvfrom function. */ -#cmakedefine HAVE_RECVFROM 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_RSA_H 1 - -/* Define to 1 if you have the select function. */ -#cmakedefine HAVE_SELECT 1 - -/* Define to 1 if you have the send function. */ -#cmakedefine HAVE_SEND 1 - -/* Define to 1 if you have the 'fsetxattr' function. */ -#cmakedefine HAVE_FSETXATTR 1 - -/* fsetxattr() takes 5 args */ -#cmakedefine HAVE_FSETXATTR_5 1 - -/* fsetxattr() takes 6 args */ -#cmakedefine HAVE_FSETXATTR_6 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SETJMP_H 1 - -/* Define to 1 if you have the `setlocale' function. */ -#cmakedefine HAVE_SETLOCALE 1 - -/* Define to 1 if you have the `setmode' function. */ -#cmakedefine HAVE_SETMODE 1 - -/* Define to 1 if you have the `setrlimit' function. */ -#cmakedefine HAVE_SETRLIMIT 1 - -/* Define to 1 if you have the setsockopt function. */ -#cmakedefine HAVE_SETSOCKOPT 1 - -/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ -#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SGTTY_H 1 - -/* Define to 1 if you have the sigaction function. */ -#cmakedefine HAVE_SIGACTION 1 - -/* Define to 1 if you have the siginterrupt function. */ -#cmakedefine HAVE_SIGINTERRUPT 1 - -/* Define to 1 if you have the signal function. */ -#cmakedefine HAVE_SIGNAL 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the sigsetjmp function or macro. */ -#cmakedefine HAVE_SIGSETJMP 1 - -/* Define to 1 if sig_atomic_t is an available typedef. */ -#cmakedefine HAVE_SIG_ATOMIC_T 1 - -/* Define to 1 if sig_atomic_t is already defined as volatile. */ -#cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE 1 - -/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ -#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 - -/* Define to 1 if you have the `socket' function. */ -#cmakedefine HAVE_SOCKET 1 - -/* Define to 1 if you have the `SSL_get_shutdown' function. */ -#cmakedefine HAVE_SSL_GET_SHUTDOWN 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SSL_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STDBOOL_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STDLIB_H 1 - -/* Define to 1 if you have the strcasecmp function. */ -#cmakedefine HAVE_STRCASECMP 1 - -/* Define to 1 if you have the strcasestr function. */ -#cmakedefine HAVE_STRCASESTR 1 - -/* Define to 1 if you have the strcmpi function. */ -#cmakedefine HAVE_STRCMPI 1 - -/* Define to 1 if you have the strdup function. */ -#cmakedefine HAVE_STRDUP 1 - -/* Define to 1 if you have the strerror_r function. */ -#cmakedefine HAVE_STRERROR_R 1 - -/* Define to 1 if you have the stricmp function. */ -#cmakedefine HAVE_STRICMP 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STRING_H 1 - -/* Define to 1 if you have the strlcat function. */ -#cmakedefine HAVE_STRLCAT 1 - -/* Define to 1 if you have the `strlcpy' function. */ -#cmakedefine HAVE_STRLCPY 1 - -/* Define to 1 if you have the strncasecmp function. */ -#cmakedefine HAVE_STRNCASECMP 1 - -/* Define to 1 if you have the strncmpi function. */ -#cmakedefine HAVE_STRNCMPI 1 - -/* Define to 1 if you have the strnicmp function. */ -#cmakedefine HAVE_STRNICMP 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STROPTS_H 1 - -/* Define to 1 if you have the strstr function. */ -#cmakedefine HAVE_STRSTR 1 - -/* Define to 1 if you have the strtok_r function. */ -#cmakedefine HAVE_STRTOK_R 1 - -/* Define to 1 if you have the strtoll function. */ -#cmakedefine HAVE_STRTOLL 1 - -/* if struct sockaddr_storage is defined */ -#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1 - -/* Define to 1 if you have the timeval struct. */ -#cmakedefine HAVE_STRUCT_TIMEVAL 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_FILIO_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_POLL_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_RESOURCE_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_SOCKIO_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_UIO_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_UN_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_UTIME_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_TERMIOS_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_TERMIO_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_TLD_H 1 - -/* Define to 1 if you have the `tld_strerror' function. */ -#cmakedefine HAVE_TLD_STRERROR 1 - -/* Define to 1 if you have the `uname' function. */ -#cmakedefine HAVE_UNAME 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `utime' function. */ -#cmakedefine HAVE_UTIME 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_UTIME_H 1 - -/* Define to 1 if compiler supports C99 variadic macro style. */ -#cmakedefine HAVE_VARIADIC_MACROS_C99 1 - -/* Define to 1 if compiler supports old gcc variadic macro style. */ -#cmakedefine HAVE_VARIADIC_MACROS_GCC 1 - -/* Define to 1 if you have the winber.h header file. */ -#cmakedefine HAVE_WINBER_H 1 - -/* Define to 1 if you have the windows.h header file. */ -#cmakedefine HAVE_WINDOWS_H 1 - -/* Define to 1 if you have the winldap.h header file. */ -#cmakedefine HAVE_WINLDAP_H 1 - -/* Define to 1 if you have the winsock2.h header file. */ -#cmakedefine HAVE_WINSOCK2_H 1 - -/* Define to 1 if you have the winsock.h header file. */ -#cmakedefine HAVE_WINSOCK_H 1 - -/* Define this symbol if your OS supports changing the contents of argv */ -#cmakedefine HAVE_WRITABLE_ARGV 1 - -/* Define to 1 if you have the writev function. */ -#cmakedefine HAVE_WRITEV 1 - -/* Define to 1 if you have the ws2tcpip.h header file. */ -#cmakedefine HAVE_WS2TCPIP_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_X509_H 1 - -/* Define if you have the header file. */ -#cmakedefine HAVE_PROCESS_H 1 - -/* if you have the zlib.h header file */ -#cmakedefine HAVE_ZLIB_H 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#cmakedefine LT_OBJDIR ${LT_OBJDIR} - -/* If you lack a fine basename() prototype */ -#cmakedefine NEED_BASENAME_PROTO 1 - -/* Define to 1 if you need the lber.h header file even with ldap.h */ -#cmakedefine NEED_LBER_H 1 - -/* Define to 1 if you need the malloc.h header file even with stdlib.h */ -#cmakedefine NEED_MALLOC_H 1 - -/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ -#cmakedefine NEED_REENTRANT 1 - -/* cpu-machine-OS */ -#cmakedefine OS ${OS} - -/* Name of package */ -#cmakedefine PACKAGE ${PACKAGE} - -/* Define to the address where bug reports for this package should be sent. */ -#cmakedefine PACKAGE_BUGREPORT ${PACKAGE_BUGREPORT} - -/* Define to the full name of this package. */ -#cmakedefine PACKAGE_NAME ${PACKAGE_NAME} - -/* Define to the full name and version of this package. */ -#cmakedefine PACKAGE_STRING ${PACKAGE_STRING} - -/* Define to the one symbol short name of this package. */ -#cmakedefine PACKAGE_TARNAME ${PACKAGE_TARNAME} - -/* Define to the version of this package. */ -#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION} - -/* a suitable file to read random data from */ -#cmakedefine RANDOM_FILE "${RANDOM_FILE}" - -/* Define to the type of arg 1 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG1 ${RECVFROM_TYPE_ARG1} - -/* Define to the type pointed by arg 2 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG2 ${RECVFROM_TYPE_ARG2} - -/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ -#cmakedefine RECVFROM_TYPE_ARG2_IS_VOID 1 - -/* Define to the type of arg 3 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG3 ${RECVFROM_TYPE_ARG3} - -/* Define to the type of arg 4 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG4 ${RECVFROM_TYPE_ARG4} - -/* Define to the type pointed by arg 5 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG5 ${RECVFROM_TYPE_ARG5} - -/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ -#cmakedefine RECVFROM_TYPE_ARG5_IS_VOID 1 - -/* Define to the type pointed by arg 6 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG6 ${RECVFROM_TYPE_ARG6} - -/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ -#cmakedefine RECVFROM_TYPE_ARG6_IS_VOID 1 - -/* Define to the function return type for recvfrom. */ -#cmakedefine RECVFROM_TYPE_RETV ${RECVFROM_TYPE_RETV} - -/* Define to the type of arg 1 for recv. */ -#cmakedefine RECV_TYPE_ARG1 ${RECV_TYPE_ARG1} - -/* Define to the type of arg 2 for recv. */ -#cmakedefine RECV_TYPE_ARG2 ${RECV_TYPE_ARG2} - -/* Define to the type of arg 3 for recv. */ -#cmakedefine RECV_TYPE_ARG3 ${RECV_TYPE_ARG3} - -/* Define to the type of arg 4 for recv. */ -#cmakedefine RECV_TYPE_ARG4 ${RECV_TYPE_ARG4} - -/* Define to the function return type for recv. */ -#cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV} - -/* Define as the return type of signal handlers (`int' or `void'). */ -#cmakedefine RETSIGTYPE ${RETSIGTYPE} - -/* Define to the type qualifier of arg 5 for select. */ -#cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5} - -/* Define to the type of arg 1 for select. */ -#cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1} - -/* Define to the type of args 2, 3 and 4 for select. */ -#cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234} - -/* Define to the type of arg 5 for select. */ -#cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5} - -/* Define to the function return type for select. */ -#cmakedefine SELECT_TYPE_RETV ${SELECT_TYPE_RETV} - -/* Define to the type qualifier of arg 2 for send. */ -#cmakedefine SEND_QUAL_ARG2 ${SEND_QUAL_ARG2} - -/* Define to the type of arg 1 for send. */ -#cmakedefine SEND_TYPE_ARG1 ${SEND_TYPE_ARG1} - -/* Define to the type of arg 2 for send. */ -#cmakedefine SEND_TYPE_ARG2 ${SEND_TYPE_ARG2} - -/* Define to the type of arg 3 for send. */ -#cmakedefine SEND_TYPE_ARG3 ${SEND_TYPE_ARG3} - -/* Define to the type of arg 4 for send. */ -#cmakedefine SEND_TYPE_ARG4 ${SEND_TYPE_ARG4} - -/* Define to the function return type for send. */ -#cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV} - -/* The size of `int', as computed by sizeof. */ -#cmakedefine SIZEOF_INT ${SIZEOF_INT} - -/* The size of `short', as computed by sizeof. */ -#cmakedefine SIZEOF_SHORT ${SIZEOF_SHORT} - -/* The size of `long', as computed by sizeof. */ -#cmakedefine SIZEOF_LONG ${SIZEOF_LONG} - -/* The size of `off_t', as computed by sizeof. */ -#cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T} - -/* The size of `curl_off_t', as computed by sizeof. */ -#cmakedefine SIZEOF_CURL_OFF_T ${SIZEOF_CURL_OFF_T} - -/* The size of `size_t', as computed by sizeof. */ -#cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T} - -/* The size of `time_t', as computed by sizeof. */ -#cmakedefine SIZEOF_TIME_T ${SIZEOF_TIME_T} - -/* The size of `void*', as computed by sizeof. */ -#cmakedefine SIZEOF_VOIDP ${SIZEOF_VOIDP} - -/* Define to 1 if you have the ANSI C header files. */ -#cmakedefine STDC_HEADERS 1 - -/* Define to the type of arg 3 for strerror_r. */ -#cmakedefine STRERROR_R_TYPE_ARG3 ${STRERROR_R_TYPE_ARG3} - -/* Define to 1 if you can safely include both and . */ -#cmakedefine TIME_WITH_SYS_TIME 1 - -/* Define if you want to enable c-ares support */ -#cmakedefine USE_ARES 1 - -/* Define if you want to enable POSIX threaded DNS lookup */ -#cmakedefine USE_THREADS_POSIX 1 - -/* Define if you want to enable WIN32 threaded DNS lookup */ -#cmakedefine USE_THREADS_WIN32 1 - -/* Define to disable non-blocking sockets. */ -#cmakedefine USE_BLOCKING_SOCKETS 1 - -/* if GnuTLS is enabled */ -#cmakedefine USE_GNUTLS 1 - -/* if PolarSSL is enabled */ -#cmakedefine USE_POLARSSL 1 - -/* if DarwinSSL is enabled */ -#cmakedefine USE_DARWINSSL 1 - -/* if mbedTLS is enabled */ -#cmakedefine USE_MBEDTLS 1 - -/* if libSSH2 is in use */ -#cmakedefine USE_LIBSSH2 1 - -/* If you want to build curl with the built-in manual */ -#cmakedefine USE_MANUAL 1 - -/* if NSS is enabled */ -#cmakedefine USE_NSS 1 - -/* if you want to use OpenLDAP code instead of legacy ldap implementation */ -#cmakedefine USE_OPENLDAP 1 - -/* if OpenSSL is in use */ -#cmakedefine USE_OPENSSL 1 - -/* to enable NGHTTP2 */ -#cmakedefine USE_NGHTTP2 1 - -/* if Unix domain sockets are enabled */ -#cmakedefine USE_UNIX_SOCKETS - -/* Define to 1 if you are building a Windows target with large file support. */ -#cmakedefine USE_WIN32_LARGE_FILES 1 - -/* to enable SSPI support */ -#cmakedefine USE_WINDOWS_SSPI 1 - -/* to enable Windows SSL */ -#cmakedefine USE_SCHANNEL 1 - -/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ -#cmakedefine USE_YASSLEMUL 1 - -/* Version number of package */ -#cmakedefine VERSION ${VERSION} - -/* Define to 1 if OS is AIX. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS} - -/* Define for large files, on AIX-style hosts. */ -#cmakedefine _LARGE_FILES ${_LARGE_FILES} - -/* define this if you need it to compile thread-safe code */ -#cmakedefine _THREAD_SAFE ${_THREAD_SAFE} - -/* Define to empty if `const' does not conform to ANSI C. */ -#cmakedefine const ${const} - -/* Type to use in place of in_addr_t when system does not provide it. */ -#cmakedefine in_addr_t ${in_addr_t} - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif - -/* Define to `unsigned int' if does not define. */ -#cmakedefine size_t ${size_t} - -/* the signed version of size_t */ -#cmakedefine ssize_t ${ssize_t} diff --git a/dep/cpr/opt/curl/lib/curl_des.c b/dep/cpr/opt/curl/lib/curl_des.c deleted file mode 100644 index b123a00f01e..00000000000 --- a/dep/cpr/opt/curl/lib/curl_des.c +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2015, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_NTLM) && !defined(USE_OPENSSL) - -#include "curl_des.h" - -/* - * Curl_des_set_odd_parity() - * - * This is used to apply odd parity to the given byte array. It is typically - * used by when a cryptography engines doesn't have it's own version. - * - * The function is a port of the Java based oddParity() function over at: - * - * https://davenport.sourceforge.io/ntlm.html - * - * Parameters: - * - * bytes [in/out] - The data whose parity bits are to be adjusted for - * odd parity. - * len [out] - The length of the data. - */ -void Curl_des_set_odd_parity(unsigned char *bytes, size_t len) -{ - size_t i; - - for(i = 0; i < len; i++) { - unsigned char b = bytes[i]; - - bool needs_parity = (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ - (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ - (b >> 1)) & 0x01) == 0; - - if(needs_parity) - bytes[i] |= 0x01; - else - bytes[i] &= 0xfe; - } -} - -#endif /* USE_NTLM && !USE_OPENSSL */ diff --git a/dep/cpr/opt/curl/lib/curl_des.h b/dep/cpr/opt/curl/lib/curl_des.h deleted file mode 100644 index 129060ff7de..00000000000 --- a/dep/cpr/opt/curl/lib/curl_des.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef HEADER_CURL_DES_H -#define HEADER_CURL_DES_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2015, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_NTLM) && !defined(USE_OPENSSL) - -/* Applies odd parity to the given byte array */ -void Curl_des_set_odd_parity(unsigned char *bytes, size_t length); - -#endif /* USE_NTLM && !USE_OPENSSL */ - -#endif /* HEADER_CURL_DES_H */ diff --git a/dep/cpr/opt/curl/lib/curl_endian.c b/dep/cpr/opt/curl/lib/curl_endian.c deleted file mode 100644 index c25db4956eb..00000000000 --- a/dep/cpr/opt/curl/lib/curl_endian.c +++ /dev/null @@ -1,124 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "curl_endian.h" - -/* - * Curl_read16_le() - * - * This function converts a 16-bit integer from the little endian format, as - * used in the incoming package to whatever endian format we're using - * natively. - * - * Parameters: - * - * buf [in] - A pointer to a 2 byte buffer. - * - * Returns the integer. - */ -unsigned short Curl_read16_le(const unsigned char *buf) -{ - return (unsigned short)(((unsigned short)buf[0]) | - ((unsigned short)buf[1] << 8)); -} - -/* - * Curl_read32_le() - * - * This function converts a 32-bit integer from the little endian format, as - * used in the incoming package to whatever endian format we're using - * natively. - * - * Parameters: - * - * buf [in] - A pointer to a 4 byte buffer. - * - * Returns the integer. - */ -unsigned int Curl_read32_le(const unsigned char *buf) -{ - return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | - ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); -} - -/* - * Curl_read16_be() - * - * This function converts a 16-bit integer from the big endian format, as - * used in the incoming package to whatever endian format we're using - * natively. - * - * Parameters: - * - * buf [in] - A pointer to a 2 byte buffer. - * - * Returns the integer. - */ -unsigned short Curl_read16_be(const unsigned char *buf) -{ - return (unsigned short)(((unsigned short)buf[0] << 8) | - ((unsigned short)buf[1])); -} - -/* - * Curl_write32_le() - * - * This function converts a 32-bit integer from the native endian format, - * to little endian format ready for sending down the wire. - * - * Parameters: - * - * value [in] - The 32-bit integer value. - * buffer [in] - A pointer to the output buffer. - */ -void Curl_write32_le(const int value, unsigned char *buffer) -{ - buffer[0] = (char)(value & 0x000000FF); - buffer[1] = (char)((value & 0x0000FF00) >> 8); - buffer[2] = (char)((value & 0x00FF0000) >> 16); - buffer[3] = (char)((value & 0xFF000000) >> 24); -} - -#if (CURL_SIZEOF_CURL_OFF_T > 4) -/* - * Curl_write64_le() - * - * This function converts a 64-bit integer from the native endian format, - * to little endian format ready for sending down the wire. - * - * Parameters: - * - * value [in] - The 64-bit integer value. - * buffer [in] - A pointer to the output buffer. - */ -#if defined(HAVE_LONGLONG) -void Curl_write64_le(const long long value, unsigned char *buffer) -#else -void Curl_write64_le(const __int64 value, unsigned char *buffer) -#endif -{ - Curl_write32_le((int)value, buffer); - Curl_write32_le((int)(value >> 32), buffer + 4); -} -#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */ diff --git a/dep/cpr/opt/curl/lib/curl_endian.h b/dep/cpr/opt/curl/lib/curl_endian.h deleted file mode 100644 index 4f345a6a22c..00000000000 --- a/dep/cpr/opt/curl/lib/curl_endian.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef HEADER_CURL_ENDIAN_H -#define HEADER_CURL_ENDIAN_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* Converts a 16-bit integer from little endian */ -unsigned short Curl_read16_le(const unsigned char *buf); - -/* Converts a 32-bit integer from little endian */ -unsigned int Curl_read32_le(const unsigned char *buf); - -/* Converts a 16-bit integer from big endian */ -unsigned short Curl_read16_be(const unsigned char *buf); - -/* Converts a 32-bit integer to little endian */ -void Curl_write32_le(const int value, unsigned char *buffer); - -#if (CURL_SIZEOF_CURL_OFF_T > 4) -/* Converts a 64-bit integer to little endian */ -#if defined(HAVE_LONGLONG) -void Curl_write64_le(const long long value, unsigned char *buffer); -#else -void Curl_write64_le(const __int64 value, unsigned char *buffer); -#endif -#endif - -#endif /* HEADER_CURL_ENDIAN_H */ diff --git a/dep/cpr/opt/curl/lib/curl_fnmatch.c b/dep/cpr/opt/curl/lib/curl_fnmatch.c deleted file mode 100644 index 631268bc178..00000000000 --- a/dep/cpr/opt/curl/lib/curl_fnmatch.c +++ /dev/null @@ -1,424 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "curl_fnmatch.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -#define CURLFNM_CHARSET_LEN (sizeof(char) * 256) -#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15) - -#define CURLFNM_NEGATE CURLFNM_CHARSET_LEN - -#define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1) -#define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2) -#define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3) -#define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4) -#define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5) -#define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6) -#define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7) -#define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8) -#define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9) -#define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10) - -typedef enum { - CURLFNM_LOOP_DEFAULT = 0, - CURLFNM_LOOP_BACKSLASH -} loop_state; - -typedef enum { - CURLFNM_SCHS_DEFAULT = 0, - CURLFNM_SCHS_MAYRANGE, - CURLFNM_SCHS_MAYRANGE2, - CURLFNM_SCHS_RIGHTBR, - CURLFNM_SCHS_RIGHTBRLEFTBR -} setcharset_state; - -typedef enum { - CURLFNM_PKW_INIT = 0, - CURLFNM_PKW_DDOT -} parsekey_state; - -#define SETCHARSET_OK 1 -#define SETCHARSET_FAIL 0 - -static int parsekeyword(unsigned char **pattern, unsigned char *charset) -{ - parsekey_state state = CURLFNM_PKW_INIT; -#define KEYLEN 10 - char keyword[KEYLEN] = { 0 }; - int found = FALSE; - int i; - unsigned char *p = *pattern; - for(i = 0; !found; i++) { - char c = *p++; - if(i >= KEYLEN) - return SETCHARSET_FAIL; - switch(state) { - case CURLFNM_PKW_INIT: - if(ISALPHA(c) && ISLOWER(c)) - keyword[i] = c; - else if(c == ':') - state = CURLFNM_PKW_DDOT; - else - return 0; - break; - case CURLFNM_PKW_DDOT: - if(c == ']') - found = TRUE; - else - return SETCHARSET_FAIL; - } - } -#undef KEYLEN - - *pattern = p; /* move caller's pattern pointer */ - if(strcmp(keyword, "digit") == 0) - charset[CURLFNM_DIGIT] = 1; - else if(strcmp(keyword, "alnum") == 0) - charset[CURLFNM_ALNUM] = 1; - else if(strcmp(keyword, "alpha") == 0) - charset[CURLFNM_ALPHA] = 1; - else if(strcmp(keyword, "xdigit") == 0) - charset[CURLFNM_XDIGIT] = 1; - else if(strcmp(keyword, "print") == 0) - charset[CURLFNM_PRINT] = 1; - else if(strcmp(keyword, "graph") == 0) - charset[CURLFNM_GRAPH] = 1; - else if(strcmp(keyword, "space") == 0) - charset[CURLFNM_SPACE] = 1; - else if(strcmp(keyword, "blank") == 0) - charset[CURLFNM_BLANK] = 1; - else if(strcmp(keyword, "upper") == 0) - charset[CURLFNM_UPPER] = 1; - else if(strcmp(keyword, "lower") == 0) - charset[CURLFNM_LOWER] = 1; - else - return SETCHARSET_FAIL; - return SETCHARSET_OK; -} - -/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */ -static int setcharset(unsigned char **p, unsigned char *charset) -{ - setcharset_state state = CURLFNM_SCHS_DEFAULT; - unsigned char rangestart = 0; - unsigned char lastchar = 0; - bool something_found = FALSE; - unsigned char c; - for(;;) { - c = **p; - switch(state) { - case CURLFNM_SCHS_DEFAULT: - if(ISALNUM(c)) { /* ASCII value */ - rangestart = c; - charset[c] = 1; - (*p)++; - state = CURLFNM_SCHS_MAYRANGE; - something_found = TRUE; - } - else if(c == ']') { - if(something_found) - return SETCHARSET_OK; - something_found = TRUE; - state = CURLFNM_SCHS_RIGHTBR; - charset[c] = 1; - (*p)++; - } - else if(c == '[') { - char c2 = *((*p) + 1); - if(c2 == ':') { /* there has to be a keyword */ - (*p) += 2; - if(parsekeyword(p, charset)) { - state = CURLFNM_SCHS_DEFAULT; - } - else - return SETCHARSET_FAIL; - } - else { - charset[c] = 1; - (*p)++; - } - something_found = TRUE; - } - else if(c == '?' || c == '*') { - something_found = TRUE; - charset[c] = 1; - (*p)++; - } - else if(c == '^' || c == '!') { - if(!something_found) { - if(charset[CURLFNM_NEGATE]) { - charset[c] = 1; - something_found = TRUE; - } - else - charset[CURLFNM_NEGATE] = 1; /* negate charset */ - } - else - charset[c] = 1; - (*p)++; - } - else if(c == '\\') { - c = *(++(*p)); - if(ISPRINT((c))) { - something_found = TRUE; - state = CURLFNM_SCHS_MAYRANGE; - charset[c] = 1; - rangestart = c; - (*p)++; - } - else - return SETCHARSET_FAIL; - } - else if(c == '\0') { - return SETCHARSET_FAIL; - } - else { - charset[c] = 1; - (*p)++; - something_found = TRUE; - } - break; - case CURLFNM_SCHS_MAYRANGE: - if(c == '-') { - charset[c] = 1; - (*p)++; - lastchar = '-'; - state = CURLFNM_SCHS_MAYRANGE2; - } - else if(c == '[') { - state = CURLFNM_SCHS_DEFAULT; - } - else if(ISALNUM(c)) { - charset[c] = 1; - (*p)++; - } - else if(c == '\\') { - c = *(++(*p)); - if(ISPRINT(c)) { - charset[c] = 1; - (*p)++; - } - else - return SETCHARSET_FAIL; - } - else if(c == ']') { - return SETCHARSET_OK; - } - else - return SETCHARSET_FAIL; - break; - case CURLFNM_SCHS_MAYRANGE2: - if(c == '\\') { - c = *(++(*p)); - if(!ISPRINT(c)) - return SETCHARSET_FAIL; - } - if(c == ']') { - return SETCHARSET_OK; - } - if(c == '\\') { - c = *(++(*p)); - if(ISPRINT(c)) { - charset[c] = 1; - state = CURLFNM_SCHS_DEFAULT; - (*p)++; - } - else - return SETCHARSET_FAIL; - } - if(c >= rangestart) { - if((ISLOWER(c) && ISLOWER(rangestart)) || - (ISDIGIT(c) && ISDIGIT(rangestart)) || - (ISUPPER(c) && ISUPPER(rangestart))) { - charset[lastchar] = 0; - rangestart++; - while(rangestart++ <= c) - charset[rangestart-1] = 1; - (*p)++; - state = CURLFNM_SCHS_DEFAULT; - } - else - return SETCHARSET_FAIL; - } - break; - case CURLFNM_SCHS_RIGHTBR: - if(c == '[') { - state = CURLFNM_SCHS_RIGHTBRLEFTBR; - charset[c] = 1; - (*p)++; - } - else if(c == ']') { - return SETCHARSET_OK; - } - else if(c == '\0') { - return SETCHARSET_FAIL; - } - else if(ISPRINT(c)) { - charset[c] = 1; - (*p)++; - state = CURLFNM_SCHS_DEFAULT; - } - else - /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a - * nonsense warning 'statement not reached' at end of the fnc when - * compiling on Solaris */ - goto fail; - break; - case CURLFNM_SCHS_RIGHTBRLEFTBR: - if(c == ']') { - return SETCHARSET_OK; - } - else { - state = CURLFNM_SCHS_DEFAULT; - charset[c] = 1; - (*p)++; - } - break; - } - } -fail: - return SETCHARSET_FAIL; -} - -static int loop(const unsigned char *pattern, const unsigned char *string) -{ - loop_state state = CURLFNM_LOOP_DEFAULT; - unsigned char *p = (unsigned char *)pattern; - unsigned char *s = (unsigned char *)string; - unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 }; - int rc = 0; - - for(;;) { - switch(state) { - case CURLFNM_LOOP_DEFAULT: - if(*p == '*') { - while(*(p + 1) == '*') /* eliminate multiple stars */ - p++; - if(*s == '\0' && *(p + 1) == '\0') - return CURL_FNMATCH_MATCH; - rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */ - if(rc == CURL_FNMATCH_MATCH) - return CURL_FNMATCH_MATCH; - if(*s) /* let the star eat up one character */ - s++; - else - return CURL_FNMATCH_NOMATCH; - } - else if(*p == '?') { - if(ISPRINT(*s)) { - s++; - p++; - } - else if(*s == '\0') - return CURL_FNMATCH_NOMATCH; - else - return CURL_FNMATCH_FAIL; /* cannot deal with other character */ - } - else if(*p == '\0') { - if(*s == '\0') - return CURL_FNMATCH_MATCH; - return CURL_FNMATCH_NOMATCH; - } - else if(*p == '\\') { - state = CURLFNM_LOOP_BACKSLASH; - p++; - } - else if(*p == '[') { - unsigned char *pp = p + 1; /* cannot handle with pointer to register */ - if(setcharset(&pp, charset)) { - int found = FALSE; - if(charset[(unsigned int)*s]) - found = TRUE; - else if(charset[CURLFNM_ALNUM]) - found = ISALNUM(*s); - else if(charset[CURLFNM_ALPHA]) - found = ISALPHA(*s); - else if(charset[CURLFNM_DIGIT]) - found = ISDIGIT(*s); - else if(charset[CURLFNM_XDIGIT]) - found = ISXDIGIT(*s); - else if(charset[CURLFNM_PRINT]) - found = ISPRINT(*s); - else if(charset[CURLFNM_SPACE]) - found = ISSPACE(*s); - else if(charset[CURLFNM_UPPER]) - found = ISUPPER(*s); - else if(charset[CURLFNM_LOWER]) - found = ISLOWER(*s); - else if(charset[CURLFNM_BLANK]) - found = ISBLANK(*s); - else if(charset[CURLFNM_GRAPH]) - found = ISGRAPH(*s); - - if(charset[CURLFNM_NEGATE]) - found = !found; - - if(found) { - p = pp + 1; - s++; - memset(charset, 0, CURLFNM_CHSET_SIZE); - } - else - return CURL_FNMATCH_NOMATCH; - } - else - return CURL_FNMATCH_FAIL; - } - else { - if(*p++ != *s++) - return CURL_FNMATCH_NOMATCH; - } - break; - case CURLFNM_LOOP_BACKSLASH: - if(ISPRINT(*p)) { - if(*p++ == *s++) - state = CURLFNM_LOOP_DEFAULT; - else - return CURL_FNMATCH_NOMATCH; - } - else - return CURL_FNMATCH_FAIL; - break; - } - } -} - -/* - * @unittest: 1307 - */ -int Curl_fnmatch(void *ptr, const char *pattern, const char *string) -{ - (void)ptr; /* the argument is specified by the curl_fnmatch_callback - prototype, but not used by Curl_fnmatch() */ - if(!pattern || !string) { - return CURL_FNMATCH_FAIL; - } - return loop((unsigned char *)pattern, (unsigned char *)string); -} diff --git a/dep/cpr/opt/curl/lib/curl_fnmatch.h b/dep/cpr/opt/curl/lib/curl_fnmatch.h deleted file mode 100644 index 69ffe392fdb..00000000000 --- a/dep/cpr/opt/curl/lib/curl_fnmatch.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef HEADER_CURL_FNMATCH_H -#define HEADER_CURL_FNMATCH_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#define CURL_FNMATCH_MATCH 0 -#define CURL_FNMATCH_NOMATCH 1 -#define CURL_FNMATCH_FAIL 2 - -/* default pattern matching function - * ================================= - * Implemented with recursive backtracking, if you want to use Curl_fnmatch, - * please note that there is not implemented UTF/UNICODE support. - * - * Implemented features: - * '?' notation, does not match UTF characters - * '*' can also work with UTF string - * [a-zA-Z0-9] enumeration support - * - * keywords: alnum, digit, xdigit, alpha, print, blank, lower, graph, space - * and upper (use as "[[:alnum:]]") - */ -int Curl_fnmatch(void *ptr, const char *pattern, const char *string); - -#endif /* HEADER_CURL_FNMATCH_H */ diff --git a/dep/cpr/opt/curl/lib/curl_gethostname.c b/dep/cpr/opt/curl/lib/curl_gethostname.c deleted file mode 100644 index 8337c72e81f..00000000000 --- a/dep/cpr/opt/curl/lib/curl_gethostname.c +++ /dev/null @@ -1,100 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "curl_gethostname.h" - -/* - * Curl_gethostname() is a wrapper around gethostname() which allows - * overriding the host name that the function would normally return. - * This capability is used by the test suite to verify exact matching - * of NTLM authentication, which exercises libcurl's MD4 and DES code - * as well as by the SMTP module when a hostname is not provided. - * - * For libcurl debug enabled builds host name overriding takes place - * when environment variable CURL_GETHOSTNAME is set, using the value - * held by the variable to override returned host name. - * - * Note: The function always returns the un-qualified hostname rather - * than being provider dependent. - * - * For libcurl shared library release builds the test suite preloads - * another shared library named libhostname using the LD_PRELOAD - * mechanism which intercepts, and might override, the gethostname() - * function call. In this case a given platform must support the - * LD_PRELOAD mechanism and additionally have environment variable - * CURL_GETHOSTNAME set in order to override the returned host name. - * - * For libcurl static library release builds no overriding takes place. - */ - -int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) -{ -#ifndef HAVE_GETHOSTNAME - - /* Allow compilation and return failure when unavailable */ - (void) name; - (void) namelen; - return -1; - -#else - int err; - char *dot; - -#ifdef DEBUGBUILD - - /* Override host name when environment variable CURL_GETHOSTNAME is set */ - const char *force_hostname = getenv("CURL_GETHOSTNAME"); - if(force_hostname) { - strncpy(name, force_hostname, namelen); - err = 0; - } - else { - name[0] = '\0'; - err = gethostname(name, namelen); - } - -#else /* DEBUGBUILD */ - - /* The call to system's gethostname() might get intercepted by the - libhostname library when libcurl is built as a non-debug shared - library when running the test suite. */ - name[0] = '\0'; - err = gethostname(name, namelen); - -#endif - - name[namelen - 1] = '\0'; - - if(err) - return err; - - /* Truncate domain, leave only machine name */ - dot = strchr(name, '.'); - if(dot) - *dot = '\0'; - - return 0; -#endif - -} diff --git a/dep/cpr/opt/curl/lib/curl_gethostname.h b/dep/cpr/opt/curl/lib/curl_gethostname.h deleted file mode 100644 index 07517c5359c..00000000000 --- a/dep/cpr/opt/curl/lib/curl_gethostname.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef HEADER_CURL_GETHOSTNAME_H -#define HEADER_CURL_GETHOSTNAME_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* Hostname buffer size */ -#define HOSTNAME_MAX 1024 - -/* This returns the local machine's un-qualified hostname */ -int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen); - -#endif /* HEADER_CURL_GETHOSTNAME_H */ diff --git a/dep/cpr/opt/curl/lib/curl_gssapi.c b/dep/cpr/opt/curl/lib/curl_gssapi.c deleted file mode 100644 index 83f3fa0c43a..00000000000 --- a/dep/cpr/opt/curl/lib/curl_gssapi.c +++ /dev/null @@ -1,131 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2011 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_GSSAPI - -#include "curl_gssapi.h" -#include "sendf.h" - -static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02"; -gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes }; -static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"; -gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes }; - -OM_uint32 Curl_gss_init_sec_context( - struct Curl_easy *data, - OM_uint32 *minor_status, - gss_ctx_id_t *context, - gss_name_t target_name, - gss_OID mech_type, - gss_channel_bindings_t input_chan_bindings, - gss_buffer_t input_token, - gss_buffer_t output_token, - const bool mutual_auth, - OM_uint32 *ret_flags) -{ - OM_uint32 req_flags = GSS_C_REPLAY_FLAG; - - if(mutual_auth) - req_flags |= GSS_C_MUTUAL_FLAG; - - if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { -#ifdef GSS_C_DELEG_POLICY_FLAG - req_flags |= GSS_C_DELEG_POLICY_FLAG; -#else - infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " - "compiled in\n"); -#endif - } - - if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG) - req_flags |= GSS_C_DELEG_FLAG; - - return gss_init_sec_context(minor_status, - GSS_C_NO_CREDENTIAL, /* cred_handle */ - context, - target_name, - mech_type, - req_flags, - 0, /* time_req */ - input_chan_bindings, - input_token, - NULL, /* actual_mech_type */ - output_token, - ret_flags, - NULL /* time_rec */); -} - -#define GSS_LOG_BUFFER_LEN 1024 -static size_t display_gss_error(OM_uint32 status, int type, - char *buf, size_t len) { - OM_uint32 maj_stat; - OM_uint32 min_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - - do { - maj_stat = gss_display_status(&min_stat, - status, - type, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { - len += snprintf(buf + len, GSS_LOG_BUFFER_LEN - len, - "%.*s. ", (int)status_string.length, - (char *)status_string.value); - } - gss_release_buffer(&min_stat, &status_string); - } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); - - return len; -} - -/* - * Curl_gss_log_error() - * - * This is used to log a GSS-API error status. - * - * Parameters: - * - * data [in] - The session handle. - * prefix [in] - The prefix of the log message. - * major [in] - The major status code. - * minor [in] - The minor status code. - */ -void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, - OM_uint32 major, OM_uint32 minor) -{ - char buf[GSS_LOG_BUFFER_LEN]; - size_t len = 0; - - if(major != GSS_S_FAILURE) - len = display_gss_error(major, GSS_C_GSS_CODE, buf, len); - - display_gss_error(minor, GSS_C_MECH_CODE, buf, len); - - infof(data, "%s%s\n", prefix, buf); -} - -#endif /* HAVE_GSSAPI */ diff --git a/dep/cpr/opt/curl/lib/curl_gssapi.h b/dep/cpr/opt/curl/lib/curl_gssapi.h deleted file mode 100644 index 9700a281740..00000000000 --- a/dep/cpr/opt/curl/lib/curl_gssapi.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef HEADER_CURL_GSSAPI_H -#define HEADER_CURL_GSSAPI_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" -#include "urldata.h" - -#ifdef HAVE_GSSAPI - -#ifdef HAVE_GSSGNU -# include -#elif defined HAVE_GSSMIT - /* MIT style */ -# include -# include -# include -#else - /* Heimdal-style */ -# include -#endif - -extern gss_OID_desc Curl_spnego_mech_oid; -extern gss_OID_desc Curl_krb5_mech_oid; - -/* Common method for using GSS-API */ -OM_uint32 Curl_gss_init_sec_context( - struct Curl_easy *data, - OM_uint32 *minor_status, - gss_ctx_id_t *context, - gss_name_t target_name, - gss_OID mech_type, - gss_channel_bindings_t input_chan_bindings, - gss_buffer_t input_token, - gss_buffer_t output_token, - const bool mutual_auth, - OM_uint32 *ret_flags); - -/* Helper to log a GSS-API error status */ -void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, - OM_uint32 major, OM_uint32 minor); - -/* Provide some definitions missing in old headers */ -#ifdef HAVE_OLD_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#define NCOMPAT 1 -#endif - -/* Define our privacy and integrity protection values */ -#define GSSAUTH_P_NONE 1 -#define GSSAUTH_P_INTEGRITY 2 -#define GSSAUTH_P_PRIVACY 4 - -#endif /* HAVE_GSSAPI */ - -#endif /* HEADER_CURL_GSSAPI_H */ diff --git a/dep/cpr/opt/curl/lib/curl_hmac.h b/dep/cpr/opt/curl/lib/curl_hmac.h deleted file mode 100644 index 756dc9e4cd2..00000000000 --- a/dep/cpr/opt/curl/lib/curl_hmac.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef HEADER_CURL_HMAC_H -#define HEADER_CURL_HMAC_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#ifndef CURL_DISABLE_CRYPTO_AUTH - -typedef void (* HMAC_hinit_func)(void *context); -typedef void (* HMAC_hupdate_func)(void *context, - const unsigned char *data, - unsigned int len); -typedef void (* HMAC_hfinal_func)(unsigned char *result, void *context); - - -/* Per-hash function HMAC parameters. */ - -typedef struct { - HMAC_hinit_func hmac_hinit; /* Initialize context procedure. */ - HMAC_hupdate_func hmac_hupdate; /* Update context with data. */ - HMAC_hfinal_func hmac_hfinal; /* Get final result procedure. */ - unsigned int hmac_ctxtsize; /* Context structure size. */ - unsigned int hmac_maxkeylen; /* Maximum key length (bytes). */ - unsigned int hmac_resultlen; /* Result length (bytes). */ -} HMAC_params; - - -/* HMAC computation context. */ - -typedef struct { - const HMAC_params *hmac_hash; /* Hash function definition. */ - void *hmac_hashctxt1; /* Hash function context 1. */ - void *hmac_hashctxt2; /* Hash function context 2. */ -} HMAC_context; - - -/* Prototypes. */ - -HMAC_context * Curl_HMAC_init(const HMAC_params *hashparams, - const unsigned char *key, - unsigned int keylen); -int Curl_HMAC_update(HMAC_context *context, - const unsigned char *data, - unsigned int len); -int Curl_HMAC_final(HMAC_context *context, unsigned char *result); - -#endif - -#endif /* HEADER_CURL_HMAC_H */ diff --git a/dep/cpr/opt/curl/lib/curl_ldap.h b/dep/cpr/opt/curl/lib/curl_ldap.h deleted file mode 100644 index 27d03810fb9..00000000000 --- a/dep/cpr/opt/curl/lib/curl_ldap.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef HEADER_CURL_LDAP_H -#define HEADER_CURL_LDAP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#ifndef CURL_DISABLE_LDAP -extern const struct Curl_handler Curl_handler_ldap; - -#if !defined(CURL_DISABLE_LDAPS) && \ - ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ - (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) -extern const struct Curl_handler Curl_handler_ldaps; -#endif - -#endif -#endif /* HEADER_CURL_LDAP_H */ - diff --git a/dep/cpr/opt/curl/lib/curl_md4.h b/dep/cpr/opt/curl/lib/curl_md4.h deleted file mode 100644 index e0690416dd0..00000000000 --- a/dep/cpr/opt/curl/lib/curl_md4.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef HEADER_CURL_MD4_H -#define HEADER_CURL_MD4_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_NSS) || defined(USE_OS400CRYPTO) || \ - (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) - -void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len); - -#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) || - (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) */ - -#endif /* HEADER_CURL_MD4_H */ diff --git a/dep/cpr/opt/curl/lib/curl_md5.h b/dep/cpr/opt/curl/lib/curl_md5.h deleted file mode 100644 index 5f70c96346b..00000000000 --- a/dep/cpr/opt/curl/lib/curl_md5.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef HEADER_CURL_MD5_H -#define HEADER_CURL_MD5_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#ifndef CURL_DISABLE_CRYPTO_AUTH -#include "curl_hmac.h" - -#define MD5_DIGEST_LEN 16 - -typedef void (* Curl_MD5_init_func)(void *context); -typedef void (* Curl_MD5_update_func)(void *context, - const unsigned char *data, - unsigned int len); -typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context); - -typedef struct { - Curl_MD5_init_func md5_init_func; /* Initialize context procedure */ - Curl_MD5_update_func md5_update_func; /* Update context with data */ - Curl_MD5_final_func md5_final_func; /* Get final result procedure */ - unsigned int md5_ctxtsize; /* Context structure size */ - unsigned int md5_resultlen; /* Result length (bytes) */ -} MD5_params; - -typedef struct { - const MD5_params *md5_hash; /* Hash function definition */ - void *md5_hashctx; /* Hash function context */ -} MD5_context; - -extern const MD5_params Curl_DIGEST_MD5[1]; -extern const HMAC_params Curl_HMAC_MD5[1]; - -void Curl_md5it(unsigned char *output, - const unsigned char *input); - -MD5_context * Curl_MD5_init(const MD5_params *md5params); -int Curl_MD5_update(MD5_context *context, - const unsigned char *data, - unsigned int len); -int Curl_MD5_final(MD5_context *context, unsigned char *result); - -#endif - -#endif /* HEADER_CURL_MD5_H */ diff --git a/dep/cpr/opt/curl/lib/curl_memory.h b/dep/cpr/opt/curl/lib/curl_memory.h deleted file mode 100644 index fccf46879a5..00000000000 --- a/dep/cpr/opt/curl/lib/curl_memory.h +++ /dev/null @@ -1,156 +0,0 @@ -#ifndef HEADER_CURL_MEMORY_H -#define HEADER_CURL_MEMORY_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Nasty internal details ahead... - * - * File curl_memory.h must be included by _all_ *.c source files - * that use memory related functions strdup, malloc, calloc, realloc - * or free, and given source file is used to build libcurl library. - * It should be included immediately before memdebug.h as the last files - * included to avoid undesired interaction with other memory function - * headers in dependent libraries. - * - * There is nearly no exception to above rule. All libcurl source - * files in 'lib' subdirectory as well as those living deep inside - * 'packages' subdirectories and linked together in order to build - * libcurl library shall follow it. - * - * File lib/strdup.c is an exception, given that it provides a strdup - * clone implementation while using malloc. Extra care needed inside - * this one. TODO: revisit this paragraph and related code. - * - * The need for curl_memory.h inclusion is due to libcurl's feature - * of allowing library user to provide memory replacement functions, - * memory callbacks, at runtime with curl_global_init_mem() - * - * Any *.c source file used to build libcurl library that does not - * include curl_memory.h and uses any memory function of the five - * mentioned above will compile without any indication, but it will - * trigger weird memory related issues at runtime. - * - * OTOH some source files from 'lib' subdirectory may additionally be - * used directly as source code when using some curlx_ functions by - * third party programs that don't even use libcurl at all. When using - * these source files in this way it is necessary these are compiled - * with CURLX_NO_MEMORY_CALLBACKS defined, in order to ensure that no - * attempt of calling libcurl's memory callbacks is done from code - * which can not use this machinery. - * - * Notice that libcurl's 'memory tracking' system works chaining into - * the memory callback machinery. This implies that when compiling - * 'lib' source files with CURLX_NO_MEMORY_CALLBACKS defined this file - * disengages usage of libcurl's 'memory tracking' system, defining - * MEMDEBUG_NODEFINES and overriding CURLDEBUG purpose. - * - * CURLX_NO_MEMORY_CALLBACKS takes precedence over CURLDEBUG. This is - * done in order to allow building a 'memory tracking' enabled libcurl - * and at the same time allow building programs which do not use it. - * - * Programs and libraries in 'tests' subdirectories have specific - * purposes and needs, and as such each one will use whatever fits - * best, depending additionally whether it links with libcurl or not. - * - * Caveat emptor. Proper curlx_* separation is a work in progress - * the same as CURLX_NO_MEMORY_CALLBACKS usage, some adjustments may - * still be required. IOW don't use them yet, there are sharp edges. - */ - -#ifdef HEADER_CURL_MEMDEBUG_H -#error "Header memdebug.h shall not be included before curl_memory.h" -#endif - -#ifndef CURLX_NO_MEMORY_CALLBACKS - -#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ -/* - * The following memory function replacement typedef's are COPIED from - * curl/curl.h and MUST match the originals. We copy them to avoid having to - * include curl/curl.h here. We avoid that include since it includes stdio.h - * and other headers that may get messed up with defines done here. - */ -typedef void *(*curl_malloc_callback)(size_t size); -typedef void (*curl_free_callback)(void *ptr); -typedef void *(*curl_realloc_callback)(void *ptr, size_t size); -typedef char *(*curl_strdup_callback)(const char *str); -typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); -#define CURL_DID_MEMORY_FUNC_TYPEDEFS -#endif - -extern curl_malloc_callback Curl_cmalloc; -extern curl_free_callback Curl_cfree; -extern curl_realloc_callback Curl_crealloc; -extern curl_strdup_callback Curl_cstrdup; -extern curl_calloc_callback Curl_ccalloc; -#if defined(WIN32) && defined(UNICODE) -extern curl_wcsdup_callback Curl_cwcsdup; -#endif - -#ifndef CURLDEBUG - -/* - * libcurl's 'memory tracking' system defines strdup, malloc, calloc, - * realloc and free, along with others, in memdebug.h in a different - * way although still using memory callbacks forward declared above. - * When using the 'memory tracking' system (CURLDEBUG defined) we do - * not define here the five memory functions given that definitions - * from memdebug.h are the ones that shall be used. - */ - -#undef strdup -#define strdup(ptr) Curl_cstrdup(ptr) -#undef malloc -#define malloc(size) Curl_cmalloc(size) -#undef calloc -#define calloc(nbelem,size) Curl_ccalloc(nbelem, size) -#undef realloc -#define realloc(ptr,size) Curl_crealloc(ptr, size) -#undef free -#define free(ptr) Curl_cfree(ptr) - -#ifdef WIN32 -# ifdef UNICODE -# undef wcsdup -# define wcsdup(ptr) Curl_cwcsdup(ptr) -# undef _wcsdup -# define _wcsdup(ptr) Curl_cwcsdup(ptr) -# undef _tcsdup -# define _tcsdup(ptr) Curl_cwcsdup(ptr) -# else -# undef _tcsdup -# define _tcsdup(ptr) Curl_cstrdup(ptr) -# endif -#endif - -#endif /* CURLDEBUG */ - -#else /* CURLX_NO_MEMORY_CALLBACKS */ - -#ifndef MEMDEBUG_NODEFINES -#define MEMDEBUG_NODEFINES -#endif - -#endif /* CURLX_NO_MEMORY_CALLBACKS */ - -#endif /* HEADER_CURL_MEMORY_H */ diff --git a/dep/cpr/opt/curl/lib/curl_memrchr.c b/dep/cpr/opt/curl/lib/curl_memrchr.c deleted file mode 100644 index c521497b21f..00000000000 --- a/dep/cpr/opt/curl/lib/curl_memrchr.c +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "curl_memrchr.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -#ifndef HAVE_MEMRCHR - -/* - * Curl_memrchr() - * - * Our memrchr() function clone for systems which lack this function. The - * memrchr() function is like the memchr() function, except that it searches - * backwards from the end of the n bytes pointed to by s instead of forward - * from the beginning. - */ - -void * -Curl_memrchr(const void *s, int c, size_t n) -{ - const unsigned char *p = s; - const unsigned char *q = s; - - p += n - 1; - - while(p >= q) { - if(*p == (unsigned char)c) - return (void *)p; - p--; - } - - return NULL; -} - -#endif /* HAVE_MEMRCHR */ diff --git a/dep/cpr/opt/curl/lib/curl_memrchr.h b/dep/cpr/opt/curl/lib/curl_memrchr.h deleted file mode 100644 index 747509c45af..00000000000 --- a/dep/cpr/opt/curl/lib/curl_memrchr.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef HEADER_CURL_MEMRCHR_H -#define HEADER_CURL_MEMRCHR_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_MEMRCHR - -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif - -#else /* HAVE_MEMRCHR */ - -void *Curl_memrchr(const void *s, int c, size_t n); - -#define memrchr(x,y,z) Curl_memrchr((x),(y),(z)) - -#endif /* HAVE_MEMRCHR */ - -#endif /* HEADER_CURL_MEMRCHR_H */ diff --git a/dep/cpr/opt/curl/lib/curl_multibyte.c b/dep/cpr/opt/curl/lib/curl_multibyte.c deleted file mode 100644 index e78bb5002e5..00000000000 --- a/dep/cpr/opt/curl/lib/curl_multibyte.c +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ - defined(USE_WIN32_LDAP)) && defined(UNICODE)) - - /* - * MultiByte conversions using Windows kernel32 library. - */ - -#include "curl_multibyte.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8) -{ - wchar_t *str_w = NULL; - - if(str_utf8) { - int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, - str_utf8, -1, NULL, 0); - if(str_w_len > 0) { - str_w = malloc(str_w_len * sizeof(wchar_t)); - if(str_w) { - if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w, - str_w_len) == 0) { - free(str_w); - return NULL; - } - } - } - } - - return str_w; -} - -char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w) -{ - char *str_utf8 = NULL; - - if(str_w) { - int str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL, - 0, NULL, NULL); - if(str_utf8_len > 0) { - str_utf8 = malloc(str_utf8_len * sizeof(wchar_t)); - if(str_utf8) { - if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len, - NULL, FALSE) == 0) { - free(str_utf8); - return NULL; - } - } - } - } - - return str_utf8; -} - -#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ diff --git a/dep/cpr/opt/curl/lib/curl_multibyte.h b/dep/cpr/opt/curl/lib/curl_multibyte.h deleted file mode 100644 index 615f5c086c0..00000000000 --- a/dep/cpr/opt/curl/lib/curl_multibyte.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef HEADER_CURL_MULTIBYTE_H -#define HEADER_CURL_MULTIBYTE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ - defined(USE_WIN32_LDAP)) && defined(UNICODE)) - - /* - * MultiByte conversions using Windows kernel32 library. - */ - -wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8); -char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w); - -#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ - - -#if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI) || \ - defined(USE_WIN32_LDAP) - -/* - * Macros Curl_convert_UTF8_to_tchar(), Curl_convert_tchar_to_UTF8() - * and Curl_unicodefree() main purpose is to minimize the number of - * preprocessor conditional directives needed by code using these - * to differentiate UNICODE from non-UNICODE builds. - * - * When building with UNICODE defined, this two macros - * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8() - * return a pointer to a newly allocated memory area holding result. - * When the result is no longer needed, allocated memory is intended - * to be free'ed with Curl_unicodefree(). - * - * When building without UNICODE defined, this macros - * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8() - * return the pointer received as argument. Curl_unicodefree() does - * no actual free'ing of this pointer it is simply set to NULL. - */ - -#ifdef UNICODE - -#define Curl_convert_UTF8_to_tchar(ptr) Curl_convert_UTF8_to_wchar((ptr)) -#define Curl_convert_tchar_to_UTF8(ptr) Curl_convert_wchar_to_UTF8((ptr)) -#define Curl_unicodefree(ptr) \ - do {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE - -typedef union { - unsigned short *tchar_ptr; - const unsigned short *const_tchar_ptr; - unsigned short *tbyte_ptr; - const unsigned short *const_tbyte_ptr; -} xcharp_u; - -#else - -#define Curl_convert_UTF8_to_tchar(ptr) (ptr) -#define Curl_convert_tchar_to_UTF8(ptr) (ptr) -#define Curl_unicodefree(ptr) \ - do {(ptr) = NULL;} WHILE_FALSE - -typedef union { - char *tchar_ptr; - const char *const_tchar_ptr; - unsigned char *tbyte_ptr; - const unsigned char *const_tbyte_ptr; -} xcharp_u; - -#endif /* UNICODE */ - -#endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI || USE_WIN32_LDAP */ - -#endif /* HEADER_CURL_MULTIBYTE_H */ diff --git a/dep/cpr/opt/curl/lib/curl_ntlm_core.c b/dep/cpr/opt/curl/lib/curl_ntlm_core.c deleted file mode 100644 index 5154949e6e7..00000000000 --- a/dep/cpr/opt/curl/lib/curl_ntlm_core.c +++ /dev/null @@ -1,818 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_NTLM) - -/* - * NTLM details: - * - * https://davenport.sourceforge.io/ntlm.html - * https://www.innovation.ch/java/ntlm.html - */ - -/* Please keep the SSL backend-specific #if branches in this order: - - 1. USE_OPENSSL - 2. USE_GNUTLS_NETTLE - 3. USE_GNUTLS - 4. USE_NSS - 5. USE_MBEDTLS - 6. USE_DARWINSSL - 7. USE_OS400CRYPTO - 8. USE_WIN32_CRYPTO - - This ensures that: - - the same SSL branch gets activated throughout this source - file even if multiple backends are enabled at the same time. - - OpenSSL and NSS have higher priority than Windows Crypt, due - to issues with the latter supporting NTLM2Session responses - in NTLM type-3 messages. - */ - -#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) - -#ifdef USE_OPENSSL - -# ifdef USE_OPENSSL -# include -# ifndef OPENSSL_NO_MD4 -# include -# endif -# include -# include -# include -# else -# include -# ifndef OPENSSL_NO_MD4 -# include -# endif -# include -# include -# include -# endif -# if (OPENSSL_VERSION_NUMBER < 0x00907001L) -# define DES_key_schedule des_key_schedule -# define DES_cblock des_cblock -# define DES_set_odd_parity des_set_odd_parity -# define DES_set_key des_set_key -# define DES_ecb_encrypt des_ecb_encrypt -# define DESKEY(x) x -# define DESKEYARG(x) x -# else -# define DESKEYARG(x) *x -# define DESKEY(x) &x -# endif - -#elif defined(USE_GNUTLS_NETTLE) - -# include -# include - -#elif defined(USE_GNUTLS) - -# include -# define MD5_DIGEST_LENGTH 16 -# define MD4_DIGEST_LENGTH 16 - -#elif defined(USE_NSS) - -# include -# include -# include -# include "curl_md4.h" -# define MD5_DIGEST_LENGTH MD5_LENGTH - -#elif defined(USE_MBEDTLS) - -# include -# include -# if !defined(MBEDTLS_MD4_C) -# include "curl_md4.h" -# endif - -#elif defined(USE_DARWINSSL) - -# include -# include - -#elif defined(USE_OS400CRYPTO) -# include "cipher.mih" /* mih/cipher */ -# include "curl_md4.h" -#elif defined(USE_WIN32_CRYPTO) -# include -#else -# error "Can't compile NTLM support without a crypto library." -#endif - -#include "urldata.h" -#include "non-ascii.h" -#include "strcase.h" -#include "curl_ntlm_core.h" -#include "curl_md5.h" -#include "curl_hmac.h" -#include "warnless.h" -#include "curl_endian.h" -#include "curl_des.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#define NTLM_HMAC_MD5_LEN (16) -#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00" -#define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4) - -/* -* Turns a 56-bit key into being 64-bit wide. -*/ -static void extend_key_56_to_64(const unsigned char *key_56, char *key) -{ - key[0] = key_56[0]; - key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); - key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); - key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); - key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); - key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); - key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); - key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); -} - -#ifdef USE_OPENSSL -/* - * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The - * key schedule ks is also set. - */ -static void setup_des_key(const unsigned char *key_56, - DES_key_schedule DESKEYARG(ks)) -{ - DES_cblock key; - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, (char *) &key); - - /* Set the key parity to odd */ - DES_set_odd_parity(&key); - - /* Set the key */ - DES_set_key(&key, ks); -} - -#elif defined(USE_GNUTLS_NETTLE) - -static void setup_des_key(const unsigned char *key_56, - struct des_ctx *des) -{ - char key[8]; - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, key); - - /* Set the key parity to odd */ - Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); - - /* Set the key */ - des_set_key(des, (const uint8_t *) key); -} - -#elif defined(USE_GNUTLS) - -/* - * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. - */ -static void setup_des_key(const unsigned char *key_56, - gcry_cipher_hd_t *des) -{ - char key[8]; - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, key); - - /* Set the key parity to odd */ - Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); - - /* Set the key */ - gcry_cipher_setkey(*des, key, sizeof(key)); -} - -#elif defined(USE_NSS) - -/* - * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using - * the expanded key. The caller is responsible for giving 64 bit of valid - * data is IN and (at least) 64 bit large buffer as OUT. - */ -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ - PK11SlotInfo *slot = NULL; - char key[8]; /* expanded 64 bit key */ - SECItem key_item; - PK11SymKey *symkey = NULL; - SECItem *param = NULL; - PK11Context *ctx = NULL; - int out_len; /* not used, required by NSS */ - bool rv = FALSE; - - /* use internal slot for DES encryption (requires NSS to be initialized) */ - slot = PK11_GetInternalKeySlot(); - if(!slot) - return FALSE; - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, key); - - /* Set the key parity to odd */ - Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); - - /* Import the key */ - key_item.data = (unsigned char *)key; - key_item.len = sizeof(key); - symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, - &key_item, NULL); - if(!symkey) - goto fail; - - /* Create the DES encryption context */ - param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); - if(!param) - goto fail; - ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); - if(!ctx) - goto fail; - - /* Perform the encryption */ - if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, - (unsigned char *)in, /* inbuflen */ 8) - && SECSuccess == PK11_Finalize(ctx)) - rv = /* all OK */ TRUE; - -fail: - /* cleanup */ - if(ctx) - PK11_DestroyContext(ctx, PR_TRUE); - if(symkey) - PK11_FreeSymKey(symkey); - if(param) - SECITEM_FreeItem(param, PR_TRUE); - PK11_FreeSlot(slot); - return rv; -} - -#elif defined(USE_MBEDTLS) - -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - mbedtls_des_context ctx; - char key[8]; - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, key); - - /* Set the key parity to odd */ - mbedtls_des_key_set_parity((unsigned char *) key); - - /* Perform the encryption */ - mbedtls_des_init(&ctx); - mbedtls_des_setkey_enc(&ctx, (unsigned char *) key); - return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; -} - -#elif defined(USE_DARWINSSL) - -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - char key[8]; - size_t out_len; - CCCryptorStatus err; - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, key); - - /* Set the key parity to odd */ - Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); - - /* Perform the encryption */ - err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, - kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out, - 8 /* outbuflen */, &out_len); - - return err == kCCSuccess; -} - -#elif defined(USE_OS400CRYPTO) - -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - char key[8]; - _CIPHER_Control_T ctl; - - /* Setup the cipher control structure */ - ctl.Func_ID = ENCRYPT_ONLY; - ctl.Data_Len = sizeof(key); - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, ctl.Crypto_Key); - - /* Set the key parity to odd */ - Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len); - - /* Perform the encryption */ - _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in); - - return TRUE; -} - -#elif defined(USE_WIN32_CRYPTO) - -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - HCRYPTPROV hprov; - HCRYPTKEY hkey; - struct { - BLOBHEADER hdr; - unsigned int len; - char key[8]; - } blob; - DWORD len = 8; - - /* Acquire the crypto provider */ - if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) - return FALSE; - - /* Setup the key blob structure */ - memset(&blob, 0, sizeof(blob)); - blob.hdr.bType = PLAINTEXTKEYBLOB; - blob.hdr.bVersion = 2; - blob.hdr.aiKeyAlg = CALG_DES; - blob.len = sizeof(blob.key); - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, blob.key); - - /* Set the key parity to odd */ - Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key)); - - /* Import the key */ - if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) { - CryptReleaseContext(hprov, 0); - - return FALSE; - } - - memcpy(out, in, 8); - - /* Perform the encryption */ - CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len); - - CryptDestroyKey(hkey); - CryptReleaseContext(hprov, 0); - - return TRUE; -} - -#endif /* defined(USE_WIN32_CRYPTO) */ - - /* - * takes a 21 byte array and treats it as 3 56-bit DES keys. The - * 8 byte plaintext is encrypted with each key and the resulting 24 - * bytes are stored in the results array. - */ -void Curl_ntlm_core_lm_resp(const unsigned char *keys, - const unsigned char *plaintext, - unsigned char *results) -{ -#ifdef USE_OPENSSL - DES_key_schedule ks; - - setup_des_key(keys, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys + 7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8), - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys + 14, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16), - DESKEY(ks), DES_ENCRYPT); -#elif defined(USE_GNUTLS_NETTLE) - struct des_ctx des; - setup_des_key(keys, &des); - des_encrypt(&des, 8, results, plaintext); - setup_des_key(keys + 7, &des); - des_encrypt(&des, 8, results + 8, plaintext); - setup_des_key(keys + 14, &des); - des_encrypt(&des, 8, results + 16, plaintext); -#elif defined(USE_GNUTLS) - gcry_cipher_hd_t des; - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys, &des); - gcry_cipher_encrypt(des, results, 8, plaintext, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys + 7, &des); - gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys + 14, &des); - gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); - gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \ - || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) - encrypt_des(plaintext, results, keys); - encrypt_des(plaintext, results + 8, keys + 7); - encrypt_des(plaintext, results + 16, keys + 14); -#endif -} - -/* - * Set up lanmanager hashed password - */ -CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, - const char *password, - unsigned char *lmbuffer /* 21 bytes */) -{ - CURLcode result; - unsigned char pw[14]; - static const unsigned char magic[] = { - 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ - }; - size_t len = CURLMIN(strlen(password), 14); - - Curl_strntoupper((char *)pw, password, len); - memset(&pw[len], 0, 14 - len); - - /* - * The LanManager hashed password needs to be created using the - * password in the network encoding not the host encoding. - */ - result = Curl_convert_to_network(data, (char *)pw, 14); - if(result) - return result; - - { - /* Create LanManager hashed password. */ - -#ifdef USE_OPENSSL - DES_key_schedule ks; - - setup_des_key(pw, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(pw + 7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8), - DESKEY(ks), DES_ENCRYPT); -#elif defined(USE_GNUTLS_NETTLE) - struct des_ctx des; - setup_des_key(pw, &des); - des_encrypt(&des, 8, lmbuffer, magic); - setup_des_key(pw + 7, &des); - des_encrypt(&des, 8, lmbuffer + 8, magic); -#elif defined(USE_GNUTLS) - gcry_cipher_hd_t des; - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(pw, &des); - gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(pw + 7, &des); - gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); - gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \ - || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) - encrypt_des(magic, lmbuffer, pw); - encrypt_des(magic, lmbuffer + 8, pw + 7); -#endif - - memset(lmbuffer + 16, 0, 21 - 16); - } - - return CURLE_OK; -} - -#ifdef USE_NTRESPONSES -static void ascii_to_unicode_le(unsigned char *dest, const char *src, - size_t srclen) -{ - size_t i; - for(i = 0; i < srclen; i++) { - dest[2 * i] = (unsigned char)src[i]; - dest[2 * i + 1] = '\0'; - } -} - -#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) - -static void ascii_uppercase_to_unicode_le(unsigned char *dest, - const char *src, size_t srclen) -{ - size_t i; - for(i = 0; i < srclen; i++) { - dest[2 * i] = (unsigned char)(Curl_raw_toupper(src[i])); - dest[2 * i + 1] = '\0'; - } -} - -#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ - -/* - * Set up nt hashed passwords - * @unittest: 1600 - */ -CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, - const char *password, - unsigned char *ntbuffer /* 21 bytes */) -{ - size_t len = strlen(password); - unsigned char *pw = malloc(len * 2); - CURLcode result; - if(!pw) - return CURLE_OUT_OF_MEMORY; - - ascii_to_unicode_le(pw, password, len); - - /* - * The NT hashed password needs to be created using the password in the - * network encoding not the host encoding. - */ - result = Curl_convert_to_network(data, (char *)pw, len * 2); - if(result) - return result; - - { - /* Create NT hashed password. */ -#ifdef USE_OPENSSL - MD4_CTX MD4pw; - MD4_Init(&MD4pw); - MD4_Update(&MD4pw, pw, 2 * len); - MD4_Final(ntbuffer, &MD4pw); -#elif defined(USE_GNUTLS_NETTLE) - struct md4_ctx MD4pw; - md4_init(&MD4pw); - md4_update(&MD4pw, (unsigned int)(2 * len), pw); - md4_digest(&MD4pw, MD4_DIGEST_SIZE, ntbuffer); -#elif defined(USE_GNUTLS) - gcry_md_hd_t MD4pw; - gcry_md_open(&MD4pw, GCRY_MD_MD4, 0); - gcry_md_write(MD4pw, pw, 2 * len); - memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH); - gcry_md_close(MD4pw); -#elif defined(USE_NSS) - Curl_md4it(ntbuffer, pw, 2 * len); -#elif defined(USE_MBEDTLS) -#if defined(MBEDTLS_MD4_C) - mbedtls_md4(pw, 2 * len, ntbuffer); -#else - Curl_md4it(ntbuffer, pw, 2 * len); -#endif -#elif defined(USE_DARWINSSL) - (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer); -#elif defined(USE_OS400CRYPTO) - Curl_md4it(ntbuffer, pw, 2 * len); -#elif defined(USE_WIN32_CRYPTO) - HCRYPTPROV hprov; - if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { - HCRYPTHASH hhash; - if(CryptCreateHash(hprov, CALG_MD4, 0, 0, &hhash)) { - DWORD length = 16; - CryptHashData(hhash, pw, (unsigned int)len * 2, 0); - CryptGetHashParam(hhash, HP_HASHVAL, ntbuffer, &length, 0); - CryptDestroyHash(hhash); - } - CryptReleaseContext(hprov, 0); - } -#endif - - memset(ntbuffer + 16, 0, 21 - 16); - } - - free(pw); - - return CURLE_OK; -} - -#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) - -/* This returns the HMAC MD5 digest */ -CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, - const unsigned char *data, unsigned int datalen, - unsigned char *output) -{ - HMAC_context *ctxt = Curl_HMAC_init(Curl_HMAC_MD5, key, keylen); - - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - /* Update the digest with the given challenge */ - Curl_HMAC_update(ctxt, data, datalen); - - /* Finalise the digest */ - Curl_HMAC_final(ctxt, output); - - return CURLE_OK; -} - -/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode - * (uppercase UserName + Domain) as the data - */ -CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, - const char *domain, size_t domlen, - unsigned char *ntlmhash, - unsigned char *ntlmv2hash) -{ - /* Unicode representation */ - size_t identity_len = (userlen + domlen) * 2; - unsigned char *identity = malloc(identity_len); - CURLcode result = CURLE_OK; - - if(!identity) - return CURLE_OUT_OF_MEMORY; - - ascii_uppercase_to_unicode_le(identity, user, userlen); - ascii_to_unicode_le(identity + (userlen << 1), domain, domlen); - - result = Curl_hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len), - ntlmv2hash); - - free(identity); - - return result; -} - -/* - * Curl_ntlm_core_mk_ntlmv2_resp() - * - * This creates the NTLMv2 response as set in the ntlm type-3 message. - * - * Parameters: - * - * ntlmv2hash [in] - The ntlmv2 hash (16 bytes) - * challenge_client [in] - The client nonce (8 bytes) - * ntlm [in] - The ntlm data struct being used to read TargetInfo - and Server challenge received in the type-2 message - * ntresp [out] - The address where a pointer to newly allocated - * memory holding the NTLMv2 response. - * ntresp_len [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, - unsigned char *challenge_client, - struct ntlmdata *ntlm, - unsigned char **ntresp, - unsigned int *ntresp_len) -{ -/* NTLMv2 response structure : ------------------------------------------------------------------------------- -0 HMAC MD5 16 bytes -------BLOB-------------------------------------------------------------------- -16 Signature 0x01010000 -20 Reserved long (0x00000000) -24 Timestamp LE, 64-bit signed value representing the number of - tenths of a microsecond since January 1, 1601. -32 Client Nonce 8 bytes -40 Unknown 4 bytes -44 Target Info N bytes (from the type-2 message) -44+N Unknown 4 bytes ------------------------------------------------------------------------------- -*/ - - unsigned int len = 0; - unsigned char *ptr = NULL; - unsigned char hmac_output[NTLM_HMAC_MD5_LEN]; - curl_off_t tw; - - CURLcode result = CURLE_OK; - -#if CURL_SIZEOF_CURL_OFF_T < 8 -#error "this section needs 64bit support to work" -#endif - - /* Calculate the timestamp */ -#ifdef DEBUGBUILD - char *force_timestamp = getenv("CURL_FORCETIME"); - if(force_timestamp) - tw = CURL_OFF_T_C(11644473600) * 10000000; - else -#endif - tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000; - - /* Calculate the response len */ - len = NTLM_HMAC_MD5_LEN + NTLMv2_BLOB_LEN; - - /* Allocate the response */ - ptr = malloc(len); - if(!ptr) - return CURLE_OUT_OF_MEMORY; - - memset(ptr, 0, len); - - /* Create the BLOB structure */ - snprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN, - "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ - "%c%c%c%c", /* Reserved = 0 */ - NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], - NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], - 0, 0, 0, 0); - - Curl_write64_le(tw, ptr + 24); - memcpy(ptr + 32, challenge_client, 8); - memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len); - - /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */ - memcpy(ptr + 8, &ntlm->nonce[0], 8); - result = Curl_hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8, - NTLMv2_BLOB_LEN + 8, hmac_output); - if(result) { - free(ptr); - return result; - } - - /* Concatenate the HMAC MD5 output with the BLOB */ - memcpy(ptr, hmac_output, NTLM_HMAC_MD5_LEN); - - /* Return the response */ - *ntresp = ptr; - *ntresp_len = len; - - return result; -} - -/* - * Curl_ntlm_core_mk_lmv2_resp() - * - * This creates the LMv2 response as used in the ntlm type-3 message. - * - * Parameters: - * - * ntlmv2hash [in] - The ntlmv2 hash (16 bytes) - * challenge_client [in] - The client nonce (8 bytes) - * challenge_client [in] - The server challenge (8 bytes) - * lmresp [out] - The LMv2 response (24 bytes) - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, - unsigned char *challenge_client, - unsigned char *challenge_server, - unsigned char *lmresp) -{ - unsigned char data[16]; - unsigned char hmac_output[16]; - CURLcode result = CURLE_OK; - - memcpy(&data[0], challenge_server, 8); - memcpy(&data[8], challenge_client, 8); - - result = Curl_hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output); - if(result) - return result; - - /* Concatenate the HMAC MD5 output with the client nonce */ - memcpy(lmresp, hmac_output, 16); - memcpy(lmresp + 16, challenge_client, 8); - - return result; -} - -#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ - -#endif /* USE_NTRESPONSES */ - -#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ - -#endif /* USE_NTLM */ diff --git a/dep/cpr/opt/curl/lib/curl_ntlm_core.h b/dep/cpr/opt/curl/lib/curl_ntlm_core.h deleted file mode 100644 index 07ef5deae9b..00000000000 --- a/dep/cpr/opt/curl/lib/curl_ntlm_core.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef HEADER_CURL_NTLM_CORE_H -#define HEADER_CURL_NTLM_CORE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_NTLM) - -/* If NSS is the first available SSL backend (see order in curl_ntlm_core.c) - then it must be initialized to be used by NTLM. */ -#if !defined(USE_OPENSSL) && \ - !defined(USE_GNUTLS_NETTLE) && \ - !defined(USE_GNUTLS) && \ - defined(USE_NSS) -#define NTLM_NEEDS_NSS_INIT -#endif - -#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) - -#ifdef USE_OPENSSL -# include -#endif - -/* Define USE_NTRESPONSES in order to make the type-3 message include - * the NT response message. */ -#if !defined(USE_OPENSSL) || !defined(OPENSSL_NO_MD4) -#define USE_NTRESPONSES -#endif - -/* Define USE_NTLM2SESSION in order to make the type-3 message include the - NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and a - Crypto engine that we have curl_ssl_md5sum() for. */ -#if defined(USE_NTRESPONSES) && !defined(USE_WIN32_CRYPTO) -#define USE_NTLM2SESSION -#endif - -/* Define USE_NTLM_V2 in order to allow the type-3 message to include the - LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1 - and support for 64-bit integers. */ -#if defined(USE_NTRESPONSES) && (CURL_SIZEOF_CURL_OFF_T > 4) -#define USE_NTLM_V2 -#endif - -void Curl_ntlm_core_lm_resp(const unsigned char *keys, - const unsigned char *plaintext, - unsigned char *results); - -CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, - const char *password, - unsigned char *lmbuffer /* 21 bytes */); - -#ifdef USE_NTRESPONSES -CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, - const char *password, - unsigned char *ntbuffer /* 21 bytes */); - -#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) - -CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, - const unsigned char *data, unsigned int datalen, - unsigned char *output); - -CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, - const char *domain, size_t domlen, - unsigned char *ntlmhash, - unsigned char *ntlmv2hash); - -CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, - unsigned char *challenge_client, - struct ntlmdata *ntlm, - unsigned char **ntresp, - unsigned int *ntresp_len); - -CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, - unsigned char *challenge_client, - unsigned char *challenge_server, - unsigned char *lmresp); - -#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ - -#endif /* USE_NTRESPONSES */ - -#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ - -#endif /* USE_NTLM */ - -#endif /* HEADER_CURL_NTLM_CORE_H */ diff --git a/dep/cpr/opt/curl/lib/curl_ntlm_wb.c b/dep/cpr/opt/curl/lib/curl_ntlm_wb.c deleted file mode 100644 index 03f47a3a52e..00000000000 --- a/dep/cpr/opt/curl/lib/curl_ntlm_wb.c +++ /dev/null @@ -1,425 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ - defined(NTLM_WB_ENABLED) - -/* - * NTLM details: - * - * https://davenport.sourceforge.io/ntlm.html - * https://www.innovation.ch/java/ntlm.html - */ - -#define DEBUG_ME 0 - -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SIGNAL_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "select.h" -#include "vauth/ntlm.h" -#include "curl_ntlm_core.h" -#include "curl_ntlm_wb.h" -#include "url.h" -#include "strerror.h" -#include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#if DEBUG_ME -# define DEBUG_OUT(x) x -#else -# define DEBUG_OUT(x) Curl_nop_stmt -#endif - -/* Portable 'sclose_nolog' used only in child process instead of 'sclose' - to avoid fooling the socket leak detector */ -#if defined(HAVE_CLOSESOCKET) -# define sclose_nolog(x) closesocket((x)) -#elif defined(HAVE_CLOSESOCKET_CAMEL) -# define sclose_nolog(x) CloseSocket((x)) -#else -# define sclose_nolog(x) close((x)) -#endif - -void Curl_ntlm_wb_cleanup(struct connectdata *conn) -{ - if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { - sclose(conn->ntlm_auth_hlpr_socket); - conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; - } - - if(conn->ntlm_auth_hlpr_pid) { - int i; - for(i = 0; i < 4; i++) { - pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG); - if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD) - break; - switch(i) { - case 0: - kill(conn->ntlm_auth_hlpr_pid, SIGTERM); - break; - case 1: - /* Give the process another moment to shut down cleanly before - bringing down the axe */ - Curl_wait_ms(1); - break; - case 2: - kill(conn->ntlm_auth_hlpr_pid, SIGKILL); - break; - case 3: - break; - } - } - conn->ntlm_auth_hlpr_pid = 0; - } - - free(conn->challenge_header); - conn->challenge_header = NULL; - free(conn->response_header); - conn->response_header = NULL; -} - -static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) -{ - curl_socket_t sockfds[2]; - pid_t child_pid; - const char *username; - char *slash, *domain = NULL; - const char *ntlm_auth = NULL; - char *ntlm_auth_alloc = NULL; -#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) - struct passwd pw, *pw_res; - char pwbuf[1024]; -#endif - - /* Return if communication with ntlm_auth already set up */ - if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || - conn->ntlm_auth_hlpr_pid) - return CURLE_OK; - - username = userp; - /* The real ntlm_auth really doesn't like being invoked with an - empty username. It won't make inferences for itself, and expects - the client to do so (mostly because it's really designed for - servers like squid to use for auth, and client support is an - afterthought for it). So try hard to provide a suitable username - if we don't already have one. But if we can't, provide the - empty one anyway. Perhaps they have an implementation of the - ntlm_auth helper which *doesn't* need it so we might as well try */ - if(!username || !username[0]) { - username = getenv("NTLMUSER"); - if(!username || !username[0]) - username = getenv("LOGNAME"); - if(!username || !username[0]) - username = getenv("USER"); -#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) - if((!username || !username[0]) && - !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) && - pw_res) { - username = pw.pw_name; - } -#endif - if(!username || !username[0]) - username = userp; - } - slash = strpbrk(username, "\\/"); - if(slash) { - domain = strdup(username); - if(!domain) - return CURLE_OUT_OF_MEMORY; - slash = domain + (slash - username); - *slash = '\0'; - username = username + (slash - domain) + 1; - } - - /* For testing purposes, when DEBUGBUILD is defined and environment - variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform - NTLM challenge/response which only accepts commands and output - strings pre-written in test case definitions */ -#ifdef DEBUGBUILD - ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE"); - if(ntlm_auth_alloc) - ntlm_auth = ntlm_auth_alloc; - else -#endif - ntlm_auth = NTLM_WB_FILE; - - if(access(ntlm_auth, X_OK) != 0) { - failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s", - ntlm_auth, errno, Curl_strerror(conn, errno)); - goto done; - } - - if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) { - failf(conn->data, "Could not open socket pair. errno %d: %s", - errno, Curl_strerror(conn, errno)); - goto done; - } - - child_pid = fork(); - if(child_pid == -1) { - sclose(sockfds[0]); - sclose(sockfds[1]); - failf(conn->data, "Could not fork. errno %d: %s", - errno, Curl_strerror(conn, errno)); - goto done; - } - else if(!child_pid) { - /* - * child process - */ - - /* Don't use sclose in the child since it fools the socket leak detector */ - sclose_nolog(sockfds[0]); - if(dup2(sockfds[1], STDIN_FILENO) == -1) { - failf(conn->data, "Could not redirect child stdin. errno %d: %s", - errno, Curl_strerror(conn, errno)); - exit(1); - } - - if(dup2(sockfds[1], STDOUT_FILENO) == -1) { - failf(conn->data, "Could not redirect child stdout. errno %d: %s", - errno, Curl_strerror(conn, errno)); - exit(1); - } - - if(domain) - execl(ntlm_auth, ntlm_auth, - "--helper-protocol", "ntlmssp-client-1", - "--use-cached-creds", - "--username", username, - "--domain", domain, - NULL); - else - execl(ntlm_auth, ntlm_auth, - "--helper-protocol", "ntlmssp-client-1", - "--use-cached-creds", - "--username", username, - NULL); - - sclose_nolog(sockfds[1]); - failf(conn->data, "Could not execl(). errno %d: %s", - errno, Curl_strerror(conn, errno)); - exit(1); - } - - sclose(sockfds[1]); - conn->ntlm_auth_hlpr_socket = sockfds[0]; - conn->ntlm_auth_hlpr_pid = child_pid; - free(domain); - free(ntlm_auth_alloc); - return CURLE_OK; - -done: - free(domain); - free(ntlm_auth_alloc); - return CURLE_REMOTE_ACCESS_DENIED; -} - -static CURLcode ntlm_wb_response(struct connectdata *conn, - const char *input, curlntlm state) -{ - char *buf = malloc(NTLM_BUFSIZE); - size_t len_in = strlen(input), len_out = 0; - - if(!buf) - return CURLE_OUT_OF_MEMORY; - - while(len_in > 0) { - ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in); - if(written == -1) { - /* Interrupted by a signal, retry it */ - if(errno == EINTR) - continue; - /* write failed if other errors happen */ - goto done; - } - input += written; - len_in -= written; - } - /* Read one line */ - while(1) { - ssize_t size; - char *newbuf; - - size = sread(conn->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE); - if(size == -1) { - if(errno == EINTR) - continue; - goto done; - } - else if(size == 0) - goto done; - - len_out += size; - if(buf[len_out - 1] == '\n') { - buf[len_out - 1] = '\0'; - break; - } - newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE); - if(!newbuf) - return CURLE_OUT_OF_MEMORY; - - buf = newbuf; - } - - /* Samba/winbind installed but not configured */ - if(state == NTLMSTATE_TYPE1 && - len_out == 3 && - buf[0] == 'P' && buf[1] == 'W') - goto done; - /* invalid response */ - if(len_out < 4) - goto done; - if(state == NTLMSTATE_TYPE1 && - (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' ')) - goto done; - if(state == NTLMSTATE_TYPE2 && - (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') && - (buf[0]!='A' || buf[1]!='F' || buf[2]!=' ')) - goto done; - - conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3); - free(buf); - return CURLE_OK; -done: - free(buf); - return CURLE_REMOTE_ACCESS_DENIED; -} - -/* - * This is for creating ntlm header output by delegating challenge/response - * to Samba's winbind daemon helper ntlm_auth. - */ -CURLcode Curl_output_ntlm_wb(struct connectdata *conn, - bool proxy) -{ - /* point to the address of the pointer that holds the string to send to the - server, which is for a plain host or for a HTTP proxy */ - char **allocuserpwd; - /* point to the name and password for this */ - const char *userp; - /* point to the correct struct with this */ - struct ntlmdata *ntlm; - struct auth *authp; - - CURLcode res = CURLE_OK; - char *input; - - DEBUGASSERT(conn); - DEBUGASSERT(conn->data); - - if(proxy) { - allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->http_proxy.user; - ntlm = &conn->proxyntlm; - authp = &conn->data->state.authproxy; - } - else { - allocuserpwd = &conn->allocptr.userpwd; - userp = conn->user; - ntlm = &conn->ntlm; - authp = &conn->data->state.authhost; - } - authp->done = FALSE; - - /* not set means empty */ - if(!userp) - userp = ""; - - switch(ntlm->state) { - case NTLMSTATE_TYPE1: - default: - /* Use Samba's 'winbind' daemon to support NTLM authentication, - * by delegating the NTLM challenge/response protocal to a helper - * in ntlm_auth. - * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html - * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html - * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html - * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this - * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute - * filename of ntlm_auth helper. - * If NTLM authentication using winbind fails, go back to original - * request handling process. - */ - /* Create communication with ntlm_auth */ - res = ntlm_wb_init(conn, userp); - if(res) - return res; - res = ntlm_wb_response(conn, "YR\n", ntlm->state); - if(res) - return res; - - free(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: %s\r\n", - proxy ? "Proxy-" : "", - conn->response_header); - DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); - free(conn->response_header); - conn->response_header = NULL; - break; - case NTLMSTATE_TYPE2: - input = aprintf("TT %s\n", conn->challenge_header); - if(!input) - return CURLE_OUT_OF_MEMORY; - res = ntlm_wb_response(conn, input, ntlm->state); - free(input); - input = NULL; - if(res) - return res; - - free(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: %s\r\n", - proxy ? "Proxy-" : "", - conn->response_header); - DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); - ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ - authp->done = TRUE; - Curl_ntlm_wb_cleanup(conn); - break; - case NTLMSTATE_TYPE3: - /* connection is already authenticated, - * don't send a header in future requests */ - free(*allocuserpwd); - *allocuserpwd = NULL; - authp->done = TRUE; - break; - } - - return CURLE_OK; -} - -#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ diff --git a/dep/cpr/opt/curl/lib/curl_ntlm_wb.h b/dep/cpr/opt/curl/lib/curl_ntlm_wb.h deleted file mode 100644 index aba3d469c39..00000000000 --- a/dep/cpr/opt/curl/lib/curl_ntlm_wb.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef HEADER_CURL_NTLM_WB_H -#define HEADER_CURL_NTLM_WB_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ - defined(NTLM_WB_ENABLED) - -/* this is for creating ntlm header output by delegating challenge/response - to Samba's winbind daemon helper ntlm_auth */ -CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy); - -void Curl_ntlm_wb_cleanup(struct connectdata *conn); - -#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ - -#endif /* HEADER_CURL_NTLM_WB_H */ diff --git a/dep/cpr/opt/curl/lib/curl_printf.h b/dep/cpr/opt/curl/lib/curl_printf.h deleted file mode 100644 index 49857cdb0db..00000000000 --- a/dep/cpr/opt/curl/lib/curl_printf.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef HEADER_CURL_PRINTF_H -#define HEADER_CURL_PRINTF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * This header should be included by ALL code in libcurl that uses any - * *rintf() functions. - */ - -#include - -# undef printf -# undef fprintf -# undef snprintf -# undef vprintf -# undef vfprintf -# undef vsnprintf -# undef aprintf -# undef vaprintf -# define printf curl_mprintf -# define fprintf curl_mfprintf -# define snprintf curl_msnprintf -# define vprintf curl_mvprintf -# define vfprintf curl_mvfprintf -# define vsnprintf curl_mvsnprintf -# define aprintf curl_maprintf -# define vaprintf curl_mvaprintf - -/* We define away the sprintf functions unconditonally since we don't want - internal code to be using them, intentionally or by mistake!*/ -# undef sprintf -# undef vsprintf -# define sprintf sprintf_was_used -# define vsprintf vsprintf_was_used - -#endif /* HEADER_CURL_PRINTF_H */ diff --git a/dep/cpr/opt/curl/lib/curl_rtmp.c b/dep/cpr/opt/curl/lib/curl_rtmp.c deleted file mode 100644 index 97430647bf6..00000000000 --- a/dep/cpr/opt/curl/lib/curl_rtmp.c +++ /dev/null @@ -1,313 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. - * Copyright (C) 2010, Howard Chu, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_LIBRTMP - -#include "curl_rtmp.h" -#include "urldata.h" -#include "nonblock.h" /* for curlx_nonblock */ -#include "progress.h" /* for Curl_pgrsSetUploadSize */ -#include "transfer.h" -#include "warnless.h" -#include -#include -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -#ifdef _WIN32 -#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e) -#define SET_RCVTIMEO(tv,s) int tv = s*1000 -#else -#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0} -#endif - -#define DEF_BUFTIME (2*60*60*1000) /* 2 hours */ - -static CURLcode rtmp_setup_connection(struct connectdata *conn); -static CURLcode rtmp_do(struct connectdata *conn, bool *done); -static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature); -static CURLcode rtmp_connect(struct connectdata *conn, bool *done); -static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead); - -static Curl_recv rtmp_recv; -static Curl_send rtmp_send; - -/* - * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu - */ - -const struct Curl_handler Curl_handler_rtmp = { - "RTMP", /* scheme */ - rtmp_setup_connection, /* setup_connection */ - rtmp_do, /* do_it */ - rtmp_done, /* done */ - ZERO_NULL, /* do_more */ - rtmp_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_RTMP, /* defport */ - CURLPROTO_RTMP, /* protocol */ - PROTOPT_NONE /* flags*/ -}; - -const struct Curl_handler Curl_handler_rtmpt = { - "RTMPT", /* scheme */ - rtmp_setup_connection, /* setup_connection */ - rtmp_do, /* do_it */ - rtmp_done, /* done */ - ZERO_NULL, /* do_more */ - rtmp_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_RTMPT, /* defport */ - CURLPROTO_RTMPT, /* protocol */ - PROTOPT_NONE /* flags*/ -}; - -const struct Curl_handler Curl_handler_rtmpe = { - "RTMPE", /* scheme */ - rtmp_setup_connection, /* setup_connection */ - rtmp_do, /* do_it */ - rtmp_done, /* done */ - ZERO_NULL, /* do_more */ - rtmp_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_RTMP, /* defport */ - CURLPROTO_RTMPE, /* protocol */ - PROTOPT_NONE /* flags*/ -}; - -const struct Curl_handler Curl_handler_rtmpte = { - "RTMPTE", /* scheme */ - rtmp_setup_connection, /* setup_connection */ - rtmp_do, /* do_it */ - rtmp_done, /* done */ - ZERO_NULL, /* do_more */ - rtmp_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_RTMPT, /* defport */ - CURLPROTO_RTMPTE, /* protocol */ - PROTOPT_NONE /* flags*/ -}; - -const struct Curl_handler Curl_handler_rtmps = { - "RTMPS", /* scheme */ - rtmp_setup_connection, /* setup_connection */ - rtmp_do, /* do_it */ - rtmp_done, /* done */ - ZERO_NULL, /* do_more */ - rtmp_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_RTMPS, /* defport */ - CURLPROTO_RTMPS, /* protocol */ - PROTOPT_NONE /* flags*/ -}; - -const struct Curl_handler Curl_handler_rtmpts = { - "RTMPTS", /* scheme */ - rtmp_setup_connection, /* setup_connection */ - rtmp_do, /* do_it */ - rtmp_done, /* done */ - ZERO_NULL, /* do_more */ - rtmp_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_RTMPS, /* defport */ - CURLPROTO_RTMPTS, /* protocol */ - PROTOPT_NONE /* flags*/ -}; - -static CURLcode rtmp_setup_connection(struct connectdata *conn) -{ - RTMP *r = RTMP_Alloc(); - if(!r) - return CURLE_OUT_OF_MEMORY; - - RTMP_Init(r); - RTMP_SetBufferMS(r, DEF_BUFTIME); - if(!RTMP_SetupURL(r, conn->data->change.url)) { - RTMP_Free(r); - return CURLE_URL_MALFORMAT; - } - conn->proto.generic = r; - return CURLE_OK; -} - -static CURLcode rtmp_connect(struct connectdata *conn, bool *done) -{ - RTMP *r = conn->proto.generic; - SET_RCVTIMEO(tv, 10); - - r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET]; - - /* We have to know if it's a write before we send the - * connect request packet - */ - if(conn->data->set.upload) - r->Link.protocol |= RTMP_FEATURE_WRITE; - - /* For plain streams, use the buffer toggle trick to keep data flowing */ - if(!(r->Link.lFlags & RTMP_LF_LIVE) && - !(r->Link.protocol & RTMP_FEATURE_HTTP)) - r->Link.lFlags |= RTMP_LF_BUFX; - - (void)curlx_nonblock(r->m_sb.sb_socket, FALSE); - setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, - (char *)&tv, sizeof(tv)); - - if(!RTMP_Connect1(r, NULL)) - return CURLE_FAILED_INIT; - - /* Clients must send a periodic BytesReceived report to the server */ - r->m_bSendCounter = true; - - *done = TRUE; - conn->recv[FIRSTSOCKET] = rtmp_recv; - conn->send[FIRSTSOCKET] = rtmp_send; - return CURLE_OK; -} - -static CURLcode rtmp_do(struct connectdata *conn, bool *done) -{ - RTMP *r = conn->proto.generic; - - if(!RTMP_ConnectStream(r, 0)) - return CURLE_FAILED_INIT; - - if(conn->data->set.upload) { - Curl_pgrsSetUploadSize(conn->data, conn->data->state.infilesize); - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); - } - else - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); - *done = TRUE; - return CURLE_OK; -} - -static CURLcode rtmp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - (void)conn; /* unused */ - (void)status; /* unused */ - (void)premature; /* unused */ - - return CURLE_OK; -} - -static CURLcode rtmp_disconnect(struct connectdata *conn, - bool dead_connection) -{ - RTMP *r = conn->proto.generic; - (void)dead_connection; - if(r) { - conn->proto.generic = NULL; - RTMP_Close(r); - RTMP_Free(r); - } - return CURLE_OK; -} - -static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf, - size_t len, CURLcode *err) -{ - RTMP *r = conn->proto.generic; - ssize_t nread; - - (void)sockindex; /* unused */ - - nread = RTMP_Read(r, buf, curlx_uztosi(len)); - if(nread < 0) { - if(r->m_read.status == RTMP_READ_COMPLETE || - r->m_read.status == RTMP_READ_EOF) { - conn->data->req.size = conn->data->req.bytecount; - nread = 0; - } - else - *err = CURLE_RECV_ERROR; - } - return nread; -} - -static ssize_t rtmp_send(struct connectdata *conn, int sockindex, - const void *buf, size_t len, CURLcode *err) -{ - RTMP *r = conn->proto.generic; - ssize_t num; - - (void)sockindex; /* unused */ - - num = RTMP_Write(r, (char *)buf, curlx_uztosi(len)); - if(num < 0) - *err = CURLE_SEND_ERROR; - - return num; -} -#endif /* USE_LIBRTMP */ diff --git a/dep/cpr/opt/curl/lib/curl_rtmp.h b/dep/cpr/opt/curl/lib/curl_rtmp.h deleted file mode 100644 index 3306e220059..00000000000 --- a/dep/cpr/opt/curl/lib/curl_rtmp.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef HEADER_CURL_RTMP_H -#define HEADER_CURL_RTMP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010, Howard Chu, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#ifdef USE_LIBRTMP -extern const struct Curl_handler Curl_handler_rtmp; -extern const struct Curl_handler Curl_handler_rtmpt; -extern const struct Curl_handler Curl_handler_rtmpe; -extern const struct Curl_handler Curl_handler_rtmpte; -extern const struct Curl_handler Curl_handler_rtmps; -extern const struct Curl_handler Curl_handler_rtmpts; -#endif - -#endif /* HEADER_CURL_RTMP_H */ diff --git a/dep/cpr/opt/curl/lib/curl_sasl.c b/dep/cpr/opt/curl/lib/curl_sasl.c deleted file mode 100644 index 550433d674f..00000000000 --- a/dep/cpr/opt/curl/lib/curl_sasl.c +++ /dev/null @@ -1,628 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC2195 CRAM-MD5 authentication - * RFC2617 Basic and Digest Access Authentication - * RFC2831 DIGEST-MD5 authentication - * RFC4422 Simple Authentication and Security Layer (SASL) - * RFC4616 PLAIN authentication - * RFC6749 OAuth 2.0 Authorization Framework - * RFC7628 A Set of SASL Mechanisms for OAuth - * Draft LOGIN SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include -#include "urldata.h" - -#include "curl_base64.h" -#include "curl_md5.h" -#include "vauth/vauth.h" -#include "vtls/vtls.h" -#include "curl_hmac.h" -#include "curl_sasl.h" -#include "warnless.h" -#include "strtok.h" -#include "sendf.h" -#include "non-ascii.h" /* included for Curl_convert_... prototypes */ -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Supported mechanisms */ -static const struct { - const char *name; /* Name */ - size_t len; /* Name length */ - unsigned int bit; /* Flag bit */ -} mechtable[] = { - { "LOGIN", 5, SASL_MECH_LOGIN }, - { "PLAIN", 5, SASL_MECH_PLAIN }, - { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 }, - { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 }, - { "GSSAPI", 6, SASL_MECH_GSSAPI }, - { "EXTERNAL", 8, SASL_MECH_EXTERNAL }, - { "NTLM", 4, SASL_MECH_NTLM }, - { "XOAUTH2", 7, SASL_MECH_XOAUTH2 }, - { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER }, - { ZERO_NULL, 0, 0 } -}; - -/* - * Curl_sasl_cleanup() - * - * This is used to cleanup any libraries or curl modules used by the sasl - * functions. - * - * Parameters: - * - * conn [in] - The connection data. - * authused [in] - The authentication mechanism used. - */ -void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) -{ -#if defined(USE_KERBEROS5) - /* Cleanup the gssapi structure */ - if(authused == SASL_MECH_GSSAPI) { - Curl_auth_gssapi_cleanup(&conn->krb5); - } -#endif - -#if defined(USE_NTLM) - /* Cleanup the NTLM structure */ - if(authused == SASL_MECH_NTLM) { - Curl_auth_ntlm_cleanup(&conn->ntlm); - } -#endif - -#if !defined(USE_KERBEROS5) && !defined(USE_NTLM) - /* Reserved for future use */ - (void)conn; - (void)authused; -#endif -} - -/* - * Curl_sasl_decode_mech() - * - * Convert a SASL mechanism name into a token. - * - * Parameters: - * - * ptr [in] - The mechanism string. - * maxlen [in] - Maximum mechanism string length. - * len [out] - If not NULL, effective name length. - * - * Returns the SASL mechanism token or 0 if no match. - */ -unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len) -{ - unsigned int i; - char c; - - for(i = 0; mechtable[i].name; i++) { - if(maxlen >= mechtable[i].len && - !memcmp(ptr, mechtable[i].name, mechtable[i].len)) { - if(len) - *len = mechtable[i].len; - - if(maxlen == mechtable[i].len) - return mechtable[i].bit; - - c = ptr[mechtable[i].len]; - if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_') - return mechtable[i].bit; - } - } - - return 0; -} - -/* - * Curl_sasl_parse_url_auth_option() - * - * Parse the URL login options. - */ -CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, - const char *value, size_t len) -{ - CURLcode result = CURLE_OK; - unsigned int mechbit; - size_t mechlen; - - if(!len) - return CURLE_URL_MALFORMAT; - - if(sasl->resetprefs) { - sasl->resetprefs = FALSE; - sasl->prefmech = SASL_AUTH_NONE; - } - - if(!strncmp(value, "*", len)) - sasl->prefmech = SASL_AUTH_DEFAULT; - else { - mechbit = Curl_sasl_decode_mech(value, len, &mechlen); - if(mechbit && mechlen == len) - sasl->prefmech |= mechbit; - else - result = CURLE_URL_MALFORMAT; - } - - return result; -} - -/* - * Curl_sasl_init() - * - * Initializes the SASL structure. - */ -void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params) -{ - sasl->params = params; /* Set protocol dependent parameters */ - sasl->state = SASL_STOP; /* Not yet running */ - sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ - sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */ - sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */ - sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */ - sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */ - sasl->force_ir = FALSE; /* Respect external option */ -} - -/* - * state() - * - * This is the ONLY way to change SASL state! - */ -static void state(struct SASL *sasl, struct connectdata *conn, - saslstate newstate) -{ -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ - static const char * const names[]={ - "STOP", - "PLAIN", - "LOGIN", - "LOGIN_PASSWD", - "EXTERNAL", - "CRAMMD5", - "DIGESTMD5", - "DIGESTMD5_RESP", - "NTLM", - "NTLM_TYPE2MSG", - "GSSAPI", - "GSSAPI_TOKEN", - "GSSAPI_NO_DATA", - "OAUTH2", - "OAUTH2_RESP", - "CANCEL", - "FINAL", - /* LAST */ - }; - - if(sasl->state != newstate) - infof(conn->data, "SASL %p state change from %s to %s\n", - (void *)sasl, names[sasl->state], names[newstate]); -#else - (void) conn; -#endif - - sasl->state = newstate; -} - -/* - * Curl_sasl_can_authenticate() - * - * Check if we have enough auth data and capabilities to authenticate. - */ -bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn) -{ - /* Have credentials been provided? */ - if(conn->bits.user_passwd) - return TRUE; - - /* EXTERNAL can authenticate without a user name and/or password */ - if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL) - return TRUE; - - return FALSE; -} - -/* - * Curl_sasl_start() - * - * Calculate the required login details for SASL authentication. - */ -CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, - bool force_ir, saslprogress *progress) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - unsigned int enabledmechs; - const char *mech = NULL; - char *resp = NULL; - size_t len = 0; - saslstate state1 = SASL_STOP; - saslstate state2 = SASL_FINAL; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; -#if defined(USE_KERBEROS5) - const char *service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : - sasl->params->service; -#endif - - sasl->force_ir = force_ir; /* Latch for future use */ - sasl->authused = 0; /* No mechanism used yet */ - enabledmechs = sasl->authmechs & sasl->prefmech; - *progress = SASL_IDLE; - - /* Calculate the supported authentication mechanism, by decreasing order of - security, as well as the initial response where appropriate */ - if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) { - mech = SASL_MECH_STRING_EXTERNAL; - state1 = SASL_EXTERNAL; - sasl->authused = SASL_MECH_EXTERNAL; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_external_message(data, conn->user, &resp, - &len); - } - else if(conn->bits.user_passwd) { -#if defined(USE_KERBEROS5) - if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() && - Curl_auth_user_contains_domain(conn->user)) { - sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ - mech = SASL_MECH_STRING_GSSAPI; - state1 = SASL_GSSAPI; - state2 = SASL_GSSAPI_TOKEN; - sasl->authused = SASL_MECH_GSSAPI; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_gssapi_user_message(data, conn->user, - conn->passwd, - service, - data->easy_conn-> - host.name, - sasl->mutual_auth, - NULL, &conn->krb5, - &resp, &len); - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if((enabledmechs & SASL_MECH_DIGEST_MD5) && - Curl_auth_is_digest_supported()) { - mech = SASL_MECH_STRING_DIGEST_MD5; - state1 = SASL_DIGESTMD5; - sasl->authused = SASL_MECH_DIGEST_MD5; - } - else if(enabledmechs & SASL_MECH_CRAM_MD5) { - mech = SASL_MECH_STRING_CRAM_MD5; - state1 = SASL_CRAMMD5; - sasl->authused = SASL_MECH_CRAM_MD5; - } - else -#endif -#ifdef USE_NTLM - if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) { - mech = SASL_MECH_STRING_NTLM; - state1 = SASL_NTLM; - state2 = SASL_NTLM_TYPE2MSG; - sasl->authused = SASL_MECH_NTLM; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_ntlm_type1_message(data, - conn->user, conn->passwd, - &conn->ntlm, &resp, &len); - } - else -#endif - if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) { - mech = SASL_MECH_STRING_OAUTHBEARER; - state1 = SASL_OAUTH2; - state2 = SASL_OAUTH2_RESP; - sasl->authused = SASL_MECH_OAUTHBEARER; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_oauth_bearer_message(data, conn->user, - hostname, - port, - conn->oauth_bearer, - &resp, &len); - } - else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) { - mech = SASL_MECH_STRING_XOAUTH2; - state1 = SASL_OAUTH2; - sasl->authused = SASL_MECH_XOAUTH2; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_oauth_bearer_message(data, conn->user, - NULL, 0, - conn->oauth_bearer, - &resp, &len); - } - else if(enabledmechs & SASL_MECH_LOGIN) { - mech = SASL_MECH_STRING_LOGIN; - state1 = SASL_LOGIN; - state2 = SASL_LOGIN_PASSWD; - sasl->authused = SASL_MECH_LOGIN; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_login_message(data, conn->user, &resp, &len); - } - else if(enabledmechs & SASL_MECH_PLAIN) { - mech = SASL_MECH_STRING_PLAIN; - state1 = SASL_PLAIN; - sasl->authused = SASL_MECH_PLAIN; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_plain_message(data, conn->user, conn->passwd, - &resp, &len); - } - } - - if(!result && mech) { - if(resp && sasl->params->maxirlen && - strlen(mech) + len > sasl->params->maxirlen) { - free(resp); - resp = NULL; - } - - result = sasl->params->sendauth(conn, mech, resp); - if(!result) { - *progress = SASL_INPROGRESS; - state(sasl, conn, resp ? state2 : state1); - } - } - - free(resp); - - return result; -} - -/* - * Curl_sasl_continue() - * - * Continue the authentication. - */ -CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, - int code, saslprogress *progress) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - saslstate newstate = SASL_FINAL; - char *resp = NULL; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; -#if !defined(CURL_DISABLE_CRYPTO_AUTH) - char *chlg = NULL; - size_t chlglen = 0; -#endif -#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) - const char *service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : - sasl->params->service; -#endif -#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ - defined(USE_NTLM) - char *serverdata; -#endif - size_t len = 0; - - *progress = SASL_INPROGRESS; - - if(sasl->state == SASL_FINAL) { - if(code != sasl->params->finalcode) - result = CURLE_LOGIN_DENIED; - *progress = SASL_DONE; - state(sasl, conn, SASL_STOP); - return result; - } - - if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP && - code != sasl->params->contcode) { - *progress = SASL_DONE; - state(sasl, conn, SASL_STOP); - return CURLE_LOGIN_DENIED; - } - - switch(sasl->state) { - case SASL_STOP: - *progress = SASL_DONE; - return result; - case SASL_PLAIN: - result = Curl_auth_create_plain_message(data, conn->user, conn->passwd, - &resp, - &len); - break; - case SASL_LOGIN: - result = Curl_auth_create_login_message(data, conn->user, &resp, &len); - newstate = SASL_LOGIN_PASSWD; - break; - case SASL_LOGIN_PASSWD: - result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len); - break; - case SASL_EXTERNAL: - result = Curl_auth_create_external_message(data, conn->user, &resp, &len); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case SASL_CRAMMD5: - sasl->params->getmessage(data->state.buffer, &serverdata); - result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen); - if(!result) - result = Curl_auth_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &resp, &len); - free(chlg); - break; - case SASL_DIGESTMD5: - sasl->params->getmessage(data->state.buffer, &serverdata); - result = Curl_auth_create_digest_md5_message(data, serverdata, - conn->user, conn->passwd, - service, - &resp, &len); - newstate = SASL_DIGESTMD5_RESP; - break; - case SASL_DIGESTMD5_RESP: - resp = strdup(""); - if(!resp) - result = CURLE_OUT_OF_MEMORY; - break; -#endif - -#ifdef USE_NTLM - case SASL_NTLM: - /* Create the type-1 message */ - result = Curl_auth_create_ntlm_type1_message(data, - conn->user, conn->passwd, - &conn->ntlm, &resp, &len); - newstate = SASL_NTLM_TYPE2MSG; - break; - case SASL_NTLM_TYPE2MSG: - /* Decode the type-2 message */ - sasl->params->getmessage(data->state.buffer, &serverdata); - result = Curl_auth_decode_ntlm_type2_message(data, serverdata, - &conn->ntlm); - if(!result) - result = Curl_auth_create_ntlm_type3_message(data, conn->user, - conn->passwd, &conn->ntlm, - &resp, &len); - break; -#endif - -#if defined(USE_KERBEROS5) - case SASL_GSSAPI: - result = Curl_auth_create_gssapi_user_message(data, conn->user, - conn->passwd, - service, - data->easy_conn->host.name, - sasl->mutual_auth, NULL, - &conn->krb5, - &resp, &len); - newstate = SASL_GSSAPI_TOKEN; - break; - case SASL_GSSAPI_TOKEN: - sasl->params->getmessage(data->state.buffer, &serverdata); - if(sasl->mutual_auth) { - /* Decode the user token challenge and create the optional response - message */ - result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, - NULL, NULL, - sasl->mutual_auth, - serverdata, &conn->krb5, - &resp, &len); - newstate = SASL_GSSAPI_NO_DATA; - } - else - /* Decode the security challenge and create the response message */ - result = Curl_auth_create_gssapi_security_message(data, serverdata, - &conn->krb5, - &resp, &len); - break; - case SASL_GSSAPI_NO_DATA: - sasl->params->getmessage(data->state.buffer, &serverdata); - /* Decode the security challenge and create the response message */ - result = Curl_auth_create_gssapi_security_message(data, serverdata, - &conn->krb5, - &resp, &len); - break; -#endif - - case SASL_OAUTH2: - /* Create the authorisation message */ - if(sasl->authused == SASL_MECH_OAUTHBEARER) { - result = Curl_auth_create_oauth_bearer_message(data, conn->user, - hostname, - port, - conn->oauth_bearer, - &resp, &len); - - /* Failures maybe sent by the server as continuations for OAUTHBEARER */ - newstate = SASL_OAUTH2_RESP; - } - else - result = Curl_auth_create_oauth_bearer_message(data, conn->user, - NULL, 0, - conn->oauth_bearer, - &resp, &len); - break; - - case SASL_OAUTH2_RESP: - /* The continuation is optional so check the response code */ - if(code == sasl->params->finalcode) { - /* Final response was received so we are done */ - *progress = SASL_DONE; - state(sasl, conn, SASL_STOP); - return result; - } - else if(code == sasl->params->contcode) { - /* Acknowledge the continuation by sending a 0x01 response base64 - encoded */ - resp = strdup("AQ=="); - if(!resp) - result = CURLE_OUT_OF_MEMORY; - break; - } - else { - *progress = SASL_DONE; - state(sasl, conn, SASL_STOP); - return CURLE_LOGIN_DENIED; - } - - case SASL_CANCEL: - /* Remove the offending mechanism from the supported list */ - sasl->authmechs ^= sasl->authused; - - /* Start an alternative SASL authentication */ - result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress); - newstate = sasl->state; /* Use state from Curl_sasl_start() */ - break; - default: - failf(data, "Unsupported SASL authentication mechanism"); - result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ - break; - } - - switch(result) { - case CURLE_BAD_CONTENT_ENCODING: - /* Cancel dialog */ - result = sasl->params->sendcont(conn, "*"); - newstate = SASL_CANCEL; - break; - case CURLE_OK: - if(resp) - result = sasl->params->sendcont(conn, resp); - break; - default: - newstate = SASL_STOP; /* Stop on error */ - *progress = SASL_DONE; - break; - } - - free(resp); - - state(sasl, conn, newstate); - - return result; -} diff --git a/dep/cpr/opt/curl/lib/curl_sasl.h b/dep/cpr/opt/curl/lib/curl_sasl.h deleted file mode 100644 index 7647a48be4c..00000000000 --- a/dep/cpr/opt/curl/lib/curl_sasl.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef HEADER_CURL_SASL_H -#define HEADER_CURL_SASL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -struct Curl_easy; -struct connectdata; - -/* Authentication mechanism flags */ -#define SASL_MECH_LOGIN (1 << 0) -#define SASL_MECH_PLAIN (1 << 1) -#define SASL_MECH_CRAM_MD5 (1 << 2) -#define SASL_MECH_DIGEST_MD5 (1 << 3) -#define SASL_MECH_GSSAPI (1 << 4) -#define SASL_MECH_EXTERNAL (1 << 5) -#define SASL_MECH_NTLM (1 << 6) -#define SASL_MECH_XOAUTH2 (1 << 7) -#define SASL_MECH_OAUTHBEARER (1 << 8) - -/* Authentication mechanism values */ -#define SASL_AUTH_NONE 0 -#define SASL_AUTH_ANY ~0U -#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) - -/* Authentication mechanism strings */ -#define SASL_MECH_STRING_LOGIN "LOGIN" -#define SASL_MECH_STRING_PLAIN "PLAIN" -#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" -#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" -#define SASL_MECH_STRING_GSSAPI "GSSAPI" -#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" -#define SASL_MECH_STRING_NTLM "NTLM" -#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" -#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" - -/* SASL machine states */ -typedef enum { - SASL_STOP, - SASL_PLAIN, - SASL_LOGIN, - SASL_LOGIN_PASSWD, - SASL_EXTERNAL, - SASL_CRAMMD5, - SASL_DIGESTMD5, - SASL_DIGESTMD5_RESP, - SASL_NTLM, - SASL_NTLM_TYPE2MSG, - SASL_GSSAPI, - SASL_GSSAPI_TOKEN, - SASL_GSSAPI_NO_DATA, - SASL_OAUTH2, - SASL_OAUTH2_RESP, - SASL_CANCEL, - SASL_FINAL -} saslstate; - -/* Progress indicator */ -typedef enum { - SASL_IDLE, - SASL_INPROGRESS, - SASL_DONE -} saslprogress; - -/* Protocol dependent SASL parameters */ -struct SASLproto { - const char *service; /* The service name */ - int contcode; /* Code to receive when continuation is expected */ - int finalcode; /* Code to receive upon authentication success */ - size_t maxirlen; /* Maximum initial response length */ - CURLcode (*sendauth)(struct connectdata *conn, - const char *mech, const char *ir); - /* Send authentication command */ - CURLcode (*sendcont)(struct connectdata *conn, const char *contauth); - /* Send authentication continuation */ - void (*getmessage)(char *buffer, char **outptr); - /* Get SASL response message */ -}; - -/* Per-connection parameters */ -struct SASL { - const struct SASLproto *params; /* Protocol dependent parameters */ - saslstate state; /* Current machine state */ - unsigned int authmechs; /* Accepted authentication mechanisms */ - unsigned int prefmech; /* Preferred authentication mechanism */ - unsigned int authused; /* Auth mechanism used for the connection */ - bool resetprefs; /* For URL auth option parsing. */ - bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ - bool force_ir; /* Protocol always supports initial response */ -}; - -/* This is used to test whether the line starts with the given mechanism */ -#define sasl_mech_equal(line, wordlen, mech) \ - (wordlen == (sizeof(mech) - 1) / sizeof(char) && \ - !memcmp(line, mech, wordlen)) - -/* This is used to cleanup any libraries or curl modules used by the sasl - functions */ -void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); - -/* Convert a mechanism name to a token */ -unsigned int Curl_sasl_decode_mech(const char *ptr, - size_t maxlen, size_t *len); - -/* Parse the URL login options */ -CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, - const char *value, size_t len); - -/* Initializes an SASL structure */ -void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); - -/* Check if we have enough auth data and capabilities to authenticate */ -bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn); - -/* Calculate the required login details for SASL authentication */ -CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, - bool force_ir, saslprogress *progress); - -/* Continue an SASL authentication */ -CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, - int code, saslprogress *progress); - -#endif /* HEADER_CURL_SASL_H */ diff --git a/dep/cpr/opt/curl/lib/curl_sec.h b/dep/cpr/opt/curl/lib/curl_sec.h deleted file mode 100644 index 7bdde269b1a..00000000000 --- a/dep/cpr/opt/curl/lib/curl_sec.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef HEADER_CURL_SECURITY_H -#define HEADER_CURL_SECURITY_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -struct Curl_sec_client_mech { - const char *name; - size_t size; - int (*init)(void *); - int (*auth)(void *, struct connectdata *); - void (*end)(void *); - int (*check_prot)(void *, int); - int (*overhead)(void *, int, int); - int (*encode)(void *, const void *, int, int, void **); - int (*decode)(void *, void *, int, int, struct connectdata *); -}; - -#define AUTH_OK 0 -#define AUTH_CONTINUE 1 -#define AUTH_ERROR 2 - -#ifdef HAVE_GSSAPI -int Curl_sec_read_msg(struct connectdata *conn, char *, - enum protection_level); -void Curl_sec_end(struct connectdata *); -CURLcode Curl_sec_login(struct connectdata *); -int Curl_sec_request_prot(struct connectdata *conn, const char *level); - -extern struct Curl_sec_client_mech Curl_krb5_client_mech; -#endif - -#endif /* HEADER_CURL_SECURITY_H */ diff --git a/dep/cpr/opt/curl/lib/curl_setup.h b/dep/cpr/opt/curl/lib/curl_setup.h deleted file mode 100644 index 402ebc03d21..00000000000 --- a/dep/cpr/opt/curl/lib/curl_setup.h +++ /dev/null @@ -1,762 +0,0 @@ -#ifndef HEADER_CURL_SETUP_H -#define HEADER_CURL_SETUP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#if defined(BUILDING_LIBCURL) && !defined(CURL_NO_OLDIES) -#define CURL_NO_OLDIES -#endif - -/* - * Define WIN32 when build target is Win32 API - */ - -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \ - !defined(__SYMBIAN32__) -#define WIN32 -#endif - -#ifdef WIN32 -/* - * Don't include unneeded stuff in Windows headers to avoid compiler - * warnings and macro clashes. - * Make sure to define this macro before including any Windows headers. - */ -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -#endif - -/* - * Include configuration script results or hand-crafted - * configuration file for platforms which lack config tool. - */ - -#ifdef HAVE_CONFIG_H - -#include "curl_config.h" - -#else /* HAVE_CONFIG_H */ - -#ifdef _WIN32_WCE -# include "config-win32ce.h" -#else -# ifdef WIN32 -# include "config-win32.h" -# endif -#endif - -#if defined(macintosh) && defined(__MRC__) -# include "config-mac.h" -#endif - -#ifdef __riscos__ -# include "config-riscos.h" -#endif - -#ifdef __AMIGA__ -# include "config-amigaos.h" -#endif - -#ifdef __SYMBIAN32__ -# include "config-symbian.h" -#endif - -#ifdef __OS400__ -# include "config-os400.h" -#endif - -#ifdef TPF -# include "config-tpf.h" -#endif - -#ifdef __VXWORKS__ -# include "config-vxworks.h" -#endif - -#endif /* HAVE_CONFIG_H */ - -/* ================================================================ */ -/* Definition of preprocessor macros/symbols which modify compiler */ -/* behavior or generated code characteristics must be done here, */ -/* as appropriate, before any system header file is included. It is */ -/* also possible to have them defined in the config file included */ -/* before this point. As a result of all this we frown inclusion of */ -/* system header files in our config files, avoid this at any cost. */ -/* ================================================================ */ - -/* - * AIX 4.3 and newer needs _THREAD_SAFE defined to build - * proper reentrant code. Others may also need it. - */ - -#ifdef NEED_THREAD_SAFE -# ifndef _THREAD_SAFE -# define _THREAD_SAFE -# endif -#endif - -/* - * Tru64 needs _REENTRANT set for a few function prototypes and - * things to appear in the system header files. Unixware needs it - * to build proper reentrant code. Others may also need it. - */ - -#ifdef NEED_REENTRANT -# ifndef _REENTRANT -# define _REENTRANT -# endif -#endif - -/* Solaris needs this to get a POSIX-conformant getpwuid_r */ -#if defined(sun) || defined(__sun) -# ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS 1 -# endif -#endif - -/* ================================================================ */ -/* If you need to include a system header file for your platform, */ -/* please, do it beyond the point further indicated in this file. */ -/* ================================================================ */ - -#include - -#define CURL_SIZEOF_CURL_OFF_T SIZEOF_CURL_OFF_T - -/* - * Disable other protocols when http is the only one desired. - */ - -#ifdef HTTP_ONLY -# ifndef CURL_DISABLE_TFTP -# define CURL_DISABLE_TFTP -# endif -# ifndef CURL_DISABLE_FTP -# define CURL_DISABLE_FTP -# endif -# ifndef CURL_DISABLE_LDAP -# define CURL_DISABLE_LDAP -# endif -# ifndef CURL_DISABLE_TELNET -# define CURL_DISABLE_TELNET -# endif -# ifndef CURL_DISABLE_DICT -# define CURL_DISABLE_DICT -# endif -# ifndef CURL_DISABLE_FILE -# define CURL_DISABLE_FILE -# endif -# ifndef CURL_DISABLE_RTSP -# define CURL_DISABLE_RTSP -# endif -# ifndef CURL_DISABLE_POP3 -# define CURL_DISABLE_POP3 -# endif -# ifndef CURL_DISABLE_IMAP -# define CURL_DISABLE_IMAP -# endif -# ifndef CURL_DISABLE_SMTP -# define CURL_DISABLE_SMTP -# endif -# ifndef CURL_DISABLE_GOPHER -# define CURL_DISABLE_GOPHER -# endif -# ifndef CURL_DISABLE_SMB -# define CURL_DISABLE_SMB -# endif -#endif - -/* - * When http is disabled rtsp is not supported. - */ - -#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP) -# define CURL_DISABLE_RTSP -#endif - -/* ================================================================ */ -/* No system header file shall be included in this file before this */ -/* point. The only allowed ones are those included from curl/system.h */ -/* ================================================================ */ - -/* - * OS/400 setup file includes some system headers. - */ - -#ifdef __OS400__ -# include "setup-os400.h" -#endif - -/* - * VMS setup file includes some system headers. - */ - -#ifdef __VMS -# include "setup-vms.h" -#endif - -/* - * Use getaddrinfo to resolve the IPv4 address literal. If the current network - * interface doesn’t support IPv4, but supports IPv6, NAT64, and DNS64, - * performing this task will result in a synthesized IPv6 address. - */ -#ifdef __APPLE__ -#define USE_RESOLVE_ON_IPS 1 -#endif - -/* - * Include header files for windows builds before redefining anything. - * Use this preprocessor block only to include or exclude windows.h, - * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs - * to any other further and independent block. Under Cygwin things work - * just as under linux (e.g. ) and the winsock headers should - * never be included when __CYGWIN__ is defined. configure script takes - * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, - * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. - */ - -#ifdef HAVE_WINDOWS_H -# if defined(UNICODE) && !defined(_UNICODE) -# define _UNICODE -# endif -# if defined(_UNICODE) && !defined(UNICODE) -# define UNICODE -# endif -# include -# ifdef HAVE_WINSOCK2_H -# include -# ifdef HAVE_WS2TCPIP_H -# include -# endif -# else -# ifdef HAVE_WINSOCK_H -# include -# endif -# endif -# include -# ifdef UNICODE - typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); -# endif -#endif - -/* - * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else - * define USE_WINSOCK to 1 if we have and use WINSOCK API, else - * undefine USE_WINSOCK. - */ - -#undef USE_WINSOCK - -#ifdef HAVE_WINSOCK2_H -# define USE_WINSOCK 2 -#else -# ifdef HAVE_WINSOCK_H -# define USE_WINSOCK 1 -# endif -#endif - -#ifdef USE_LWIPSOCK -# include -# include -# include -#endif - -#ifdef HAVE_EXTRA_STRICMP_H -# include -#endif - -#ifdef HAVE_EXTRA_STRDUP_H -# include -#endif - -#ifdef TPF -# include /* for bzero, strcasecmp, and strncasecmp */ -# include /* for strcpy and strlen */ -# include /* for rand and srand */ -# include /* for select and ioctl*/ -# include /* for in_addr_t definition */ -# include /* for tpf_process_signals */ - /* change which select is used for libcurl */ -# define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e) -#endif - -#ifdef __VXWORKS__ -# include /* for generic BSD socket functions */ -# include /* for basic I/O interface functions */ -#endif - -#ifdef __AMIGA__ -# ifndef __ixemul__ -# include -# include -# include -# include -# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) -# endif -#endif - -#include -#ifdef HAVE_ASSERT_H -#include -#endif - -#ifdef __TANDEM /* for nsr-tandem-nsk systems */ -#include -#endif - -#ifndef STDC_HEADERS /* no standard C headers! */ -#include -#endif - -#ifdef __POCC__ -# include -# include -# define sys_nerr EILSEQ -#endif - -/* - * Salford-C kludge section (mostly borrowed from wxWidgets). - */ -#ifdef __SALFORDC__ - #pragma suppress 353 /* Possible nested comments */ - #pragma suppress 593 /* Define not used */ - #pragma suppress 61 /* enum has no name */ - #pragma suppress 106 /* unnamed, unused parameter */ - #include -#endif - -/* - * Large file (>2Gb) support using WIN32 functions. - */ - -#ifdef USE_WIN32_LARGE_FILES -# include -# include -# include -# undef lseek -# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence) -# undef fstat -# define fstat(fdes,stp) _fstati64(fdes, stp) -# undef stat -# define stat(fname,stp) _stati64(fname, stp) -# define struct_stat struct _stati64 -# define LSEEK_ERROR (__int64)-1 -#endif - -/* - * Small file (<2Gb) support using WIN32 functions. - */ - -#ifdef USE_WIN32_SMALL_FILES -# include -# include -# include -# ifndef _WIN32_WCE -# undef lseek -# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) -# define fstat(fdes,stp) _fstat(fdes, stp) -# define stat(fname,stp) _stat(fname, stp) -# define struct_stat struct _stat -# endif -# define LSEEK_ERROR (long)-1 -#endif - -#ifndef struct_stat -# define struct_stat struct stat -#endif - -#ifndef LSEEK_ERROR -# define LSEEK_ERROR (off_t)-1 -#endif - -/* - * Default sizeof(off_t) in case it hasn't been defined in config file. - */ - -#ifndef SIZEOF_OFF_T -# if defined(__VMS) && !defined(__VAX) -# if defined(_LARGEFILE) -# define SIZEOF_OFF_T 8 -# endif -# elif defined(__OS400__) && defined(__ILEC400__) -# if defined(_LARGE_FILES) -# define SIZEOF_OFF_T 8 -# endif -# elif defined(__MVS__) && defined(__IBMC__) -# if defined(_LP64) || defined(_LARGE_FILES) -# define SIZEOF_OFF_T 8 -# endif -# elif defined(__370__) && defined(__IBMC__) -# if defined(_LP64) || defined(_LARGE_FILES) -# define SIZEOF_OFF_T 8 -# endif -# endif -# ifndef SIZEOF_OFF_T -# define SIZEOF_OFF_T 4 -# endif -#endif - -/* - * Arg 2 type for gethostname in case it hasn't been defined in config file. - */ - -#ifndef GETHOSTNAME_TYPE_ARG2 -# ifdef USE_WINSOCK -# define GETHOSTNAME_TYPE_ARG2 int -# else -# define GETHOSTNAME_TYPE_ARG2 size_t -# endif -#endif - -/* Below we define some functions. They should - - 4. set the SIGALRM signal timeout - 5. set dir/file naming defines - */ - -#ifdef WIN32 - -# define DIR_CHAR "\\" -# define DOT_CHAR "_" - -#else /* WIN32 */ - -# ifdef MSDOS /* Watt-32 */ - -# include -# define select(n,r,w,x,t) select_s(n,r,w,x,t) -# define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z)) -# include -# ifdef word -# undef word -# endif -# ifdef byte -# undef byte -# endif - -# endif /* MSDOS */ - -# ifdef __minix - /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */ - extern char *strtok_r(char *s, const char *delim, char **last); - extern struct tm *gmtime_r(const time_t * const timep, struct tm *tmp); -# endif - -# define DIR_CHAR "/" -# ifndef DOT_CHAR -# define DOT_CHAR "." -# endif - -# ifdef MSDOS -# undef DOT_CHAR -# define DOT_CHAR "_" -# endif - -# ifndef fileno /* sunos 4 have this as a macro! */ - int fileno(FILE *stream); -# endif - -#endif /* WIN32 */ - -/* - * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN - * defined in ws2tcpip.h as well as to provide IPv6 support. - * Does not apply if lwIP is used. - */ - -#if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK) -# if !defined(HAVE_WS2TCPIP_H) || \ - ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN)) -# undef HAVE_GETADDRINFO_THREADSAFE -# undef HAVE_FREEADDRINFO -# undef HAVE_GETADDRINFO -# undef HAVE_GETNAMEINFO -# undef ENABLE_IPV6 -# endif -#endif - -/* ---------------------------------------------------------------- */ -/* resolver specialty compile-time defines */ -/* CURLRES_* defines to use in the host*.c sources */ -/* ---------------------------------------------------------------- */ - -/* - * lcc-win32 doesn't have _beginthreadex(), lacks threads support. - */ - -#if defined(__LCC__) && defined(WIN32) -# undef USE_THREADS_POSIX -# undef USE_THREADS_WIN32 -#endif - -/* - * MSVC threads support requires a multi-threaded runtime library. - * _beginthreadex() is not available in single-threaded ones. - */ - -#if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT) -# undef USE_THREADS_POSIX -# undef USE_THREADS_WIN32 -#endif - -/* - * Mutually exclusive CURLRES_* definitions. - */ - -#ifdef USE_ARES -# define CURLRES_ASYNCH -# define CURLRES_ARES -/* now undef the stock libc functions just to avoid them being used */ -# undef HAVE_GETADDRINFO -# undef HAVE_FREEADDRINFO -# undef HAVE_GETHOSTBYNAME -#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -# define CURLRES_ASYNCH -# define CURLRES_THREADED -#else -# define CURLRES_SYNCH -#endif - -#ifdef ENABLE_IPV6 -# define CURLRES_IPV6 -#else -# define CURLRES_IPV4 -#endif - -/* ---------------------------------------------------------------- */ - -/* - * When using WINSOCK, TELNET protocol requires WINSOCK2 API. - */ - -#if defined(USE_WINSOCK) && (USE_WINSOCK != 2) -# define CURL_DISABLE_TELNET 1 -#endif - -/* - * msvc 6.0 does not have struct sockaddr_storage and - * does not define IPPROTO_ESP in winsock2.h. But both - * are available if PSDK is properly installed. - */ - -#if defined(_MSC_VER) && !defined(__POCC__) -# if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP)) -# undef HAVE_STRUCT_SOCKADDR_STORAGE -# endif -#endif - -/* - * Intentionally fail to build when using msvc 6.0 without PSDK installed. - * The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK - * in lib/config-win32.h although absolutely discouraged and unsupported. - */ - -#if defined(_MSC_VER) && !defined(__POCC__) -# if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_)) -# if !defined(ALLOW_MSVC6_WITHOUT_PSDK) -# error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. \ - "Windows Server 2003 PSDK" -# else -# define CURL_DISABLE_LDAP 1 -# endif -# endif -#endif - -#ifdef NETWARE -int netware_init(void); -#ifndef __NOVELL_LIBC__ -#include -#include -#endif -#endif - -#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN) -/* The lib and header are present */ -#define USE_LIBIDN2 -#endif - -#if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN) -#error "Both libidn2 and WinIDN are enabled, choose one." -#endif - -#ifndef SIZEOF_TIME_T -/* assume default size of time_t to be 32 bit */ -#define SIZEOF_TIME_T 4 -#endif - -#define LIBIDN_REQUIRED_VERSION "0.4.1" - -#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ - defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \ - defined(USE_CYASSL) || defined(USE_SCHANNEL) || \ - defined(USE_DARWINSSL) || defined(USE_GSKIT) -#define USE_SSL /* SSL support has been enabled */ -#endif - -/* Single point where USE_SPNEGO definition might be defined */ -#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ - (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) -#define USE_SPNEGO -#endif - -/* Single point where USE_KERBEROS5 definition might be defined */ -#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ - (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) -#define USE_KERBEROS5 -#endif - -/* Single point where USE_NTLM definition might be defined */ -#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH) -#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \ - defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \ - defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \ - defined(USE_MBEDTLS) - -#define USE_NTLM - -# if defined(USE_MBEDTLS) -/* Get definition of MBEDTLS_MD4_C */ -# include -# endif - -#endif -#endif - -#ifdef CURL_WANTS_CA_BUNDLE_ENV -#error "No longer supported. Set CURLOPT_CAINFO at runtime instead." -#endif - -/* - * Provide a mechanism to silence picky compilers, such as gcc 4.6+. - * Parameters should of course normally not be unused, but for example when - * we have multiple implementations of the same interface it may happen. - */ - -#if defined(__GNUC__) && ((__GNUC__ >= 3) || \ - ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7))) -# define UNUSED_PARAM __attribute__((__unused__)) -# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#else -# define UNUSED_PARAM /*NOTHING*/ -# define WARN_UNUSED_RESULT -#endif - -/* - * Include macros and defines that should only be processed once. - */ - -#ifndef HEADER_CURL_SETUP_ONCE_H -#include "curl_setup_once.h" -#endif - -/* - * Definition of our NOP statement Object-like macro - */ - -#ifndef Curl_nop_stmt -# define Curl_nop_stmt do { } WHILE_FALSE -#endif - -/* - * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. - */ - -#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H) -# if defined(SOCKET) || \ - defined(USE_WINSOCK) || \ - defined(HAVE_WINSOCK_H) || \ - defined(HAVE_WINSOCK2_H) || \ - defined(HAVE_WS2TCPIP_H) -# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!" -# endif -#endif - -/* - * Portable symbolic names for Winsock shutdown() mode flags. - */ - -#ifdef USE_WINSOCK -# define SHUT_RD 0x00 -# define SHUT_WR 0x01 -# define SHUT_RDWR 0x02 -#endif - -/* Define S_ISREG if not defined by system headers, f.e. MSVC */ -#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif - -/* Define S_ISDIR if not defined by system headers, f.e. MSVC */ -#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif - -/* In Windows the default file mode is text but an application can override it. -Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 -*/ -#if defined(WIN32) || defined(MSDOS) -#define FOPEN_READTEXT "rt" -#define FOPEN_WRITETEXT "wt" -#define FOPEN_APPENDTEXT "at" -#elif defined(__CYGWIN__) -/* Cygwin has specific behavior we need to address when WIN32 is not defined. -https://cygwin.com/cygwin-ug-net/using-textbinary.html -For write we want our output to have line endings of LF and be compatible with -other Cygwin utilities. For read we want to handle input that may have line -endings either CRLF or LF so 't' is appropriate. -*/ -#define FOPEN_READTEXT "rt" -#define FOPEN_WRITETEXT "w" -#define FOPEN_APPENDTEXT "a" -#else -#define FOPEN_READTEXT "r" -#define FOPEN_WRITETEXT "w" -#define FOPEN_APPENDTEXT "a" -#endif - -/* WinSock destroys recv() buffer when send() failed. - * Enabled automatically for Windows and for Cygwin as Cygwin sockets are - * wrappers for WinSock sockets. https://github.com/curl/curl/issues/657 - * Define DONT_USE_RECV_BEFORE_SEND_WORKAROUND to force disable workaround. - */ -#if !defined(DONT_USE_RECV_BEFORE_SEND_WORKAROUND) -# if defined(WIN32) || defined(__CYGWIN__) -# define USE_RECV_BEFORE_SEND_WORKAROUND -# endif -#else /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ -# ifdef USE_RECV_BEFORE_SEND_WORKAROUND -# undef USE_RECV_BEFORE_SEND_WORKAROUND -# endif -#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ - -/* Detect Windows App environment which has a restricted access - * to the Win32 APIs. */ -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602) -# include -# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ - !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -# define CURL_WINDOWS_APP -# endif -# endif - -#endif /* HEADER_CURL_SETUP_H */ diff --git a/dep/cpr/opt/curl/lib/curl_setup_once.h b/dep/cpr/opt/curl/lib/curl_setup_once.h deleted file mode 100644 index a5b542c6eea..00000000000 --- a/dep/cpr/opt/curl/lib/curl_setup_once.h +++ /dev/null @@ -1,537 +0,0 @@ -#ifndef HEADER_CURL_SETUP_ONCE_H -#define HEADER_CURL_SETUP_ONCE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - - -/* - * Inclusion of common header files. - */ - -#include -#include -#include -#include -#include - -#ifdef HAVE_ERRNO_H -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef NEED_MALLOC_H -#include -#endif - -#ifdef NEED_MEMORY_H -#include -#endif - -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#ifdef HAVE_SYS_TIME_H -#include -#ifdef TIME_WITH_SYS_TIME -#include -#endif -#else -#ifdef HAVE_TIME_H -#include -#endif -#endif - -#ifdef WIN32 -#include -#include -#endif - -#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T) -#include -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef __hpux -# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) -# ifdef _APP32_64BIT_OFF_T -# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T -# undef _APP32_64BIT_OFF_T -# else -# undef OLD_APP32_64BIT_OFF_T -# endif -# endif -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#ifdef __hpux -# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) -# ifdef OLD_APP32_64BIT_OFF_T -# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T -# undef OLD_APP32_64BIT_OFF_T -# endif -# endif -#endif - - -/* - * Definition of timeval struct for platforms that don't have it. - */ - -#ifndef HAVE_STRUCT_TIMEVAL -struct timeval { - long tv_sec; - long tv_usec; -}; -#endif - - -/* - * If we have the MSG_NOSIGNAL define, make sure we use - * it as the fourth argument of function send() - */ - -#ifdef HAVE_MSG_NOSIGNAL -#define SEND_4TH_ARG MSG_NOSIGNAL -#else -#define SEND_4TH_ARG 0 -#endif - - -#if defined(__minix) -/* Minix doesn't support recv on TCP sockets */ -#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \ - (RECV_TYPE_ARG2)(y), \ - (RECV_TYPE_ARG3)(z)) - -#elif defined(HAVE_RECV) -/* - * The definitions for the return type and arguments types - * of functions recv() and send() belong and come from the - * configuration file. Do not define them in any other place. - * - * HAVE_RECV is defined if you have a function named recv() - * which is used to read incoming data from sockets. If your - * function has another name then don't define HAVE_RECV. - * - * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2, - * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also - * be defined. - * - * HAVE_SEND is defined if you have a function named send() - * which is used to write outgoing data on a connected socket. - * If yours has another name then don't define HAVE_SEND. - * - * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2, - * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and - * SEND_TYPE_RETV must also be defined. - */ - -#if !defined(RECV_TYPE_ARG1) || \ - !defined(RECV_TYPE_ARG2) || \ - !defined(RECV_TYPE_ARG3) || \ - !defined(RECV_TYPE_ARG4) || \ - !defined(RECV_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_recv - /* */ -#else -#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \ - (RECV_TYPE_ARG2)(y), \ - (RECV_TYPE_ARG3)(z), \ - (RECV_TYPE_ARG4)(0)) -#endif -#else /* HAVE_RECV */ -#ifndef sread - /* */ - Error Missing_definition_of_macro_sread - /* */ -#endif -#endif /* HAVE_RECV */ - - -#if defined(__minix) -/* Minix doesn't support send on TCP sockets */ -#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \ - (SEND_TYPE_ARG2)(y), \ - (SEND_TYPE_ARG3)(z)) - -#elif defined(HAVE_SEND) -#if !defined(SEND_TYPE_ARG1) || \ - !defined(SEND_QUAL_ARG2) || \ - !defined(SEND_TYPE_ARG2) || \ - !defined(SEND_TYPE_ARG3) || \ - !defined(SEND_TYPE_ARG4) || \ - !defined(SEND_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_send - /* */ -#else -#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \ - (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \ - (SEND_TYPE_ARG3)(z), \ - (SEND_TYPE_ARG4)(SEND_4TH_ARG)) -#endif -#else /* HAVE_SEND */ -#ifndef swrite - /* */ - Error Missing_definition_of_macro_swrite - /* */ -#endif -#endif /* HAVE_SEND */ - - -#if 0 -#if defined(HAVE_RECVFROM) -/* - * Currently recvfrom is only used on udp sockets. - */ -#if !defined(RECVFROM_TYPE_ARG1) || \ - !defined(RECVFROM_TYPE_ARG2) || \ - !defined(RECVFROM_TYPE_ARG3) || \ - !defined(RECVFROM_TYPE_ARG4) || \ - !defined(RECVFROM_TYPE_ARG5) || \ - !defined(RECVFROM_TYPE_ARG6) || \ - !defined(RECVFROM_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_recvfrom - /* */ -#else -#define sreadfrom(s,b,bl,f,fl) (ssize_t)recvfrom((RECVFROM_TYPE_ARG1) (s), \ - (RECVFROM_TYPE_ARG2 *)(b), \ - (RECVFROM_TYPE_ARG3) (bl), \ - (RECVFROM_TYPE_ARG4) (0), \ - (RECVFROM_TYPE_ARG5 *)(f), \ - (RECVFROM_TYPE_ARG6 *)(fl)) -#endif -#else /* HAVE_RECVFROM */ -#ifndef sreadfrom - /* */ - Error Missing_definition_of_macro_sreadfrom - /* */ -#endif -#endif /* HAVE_RECVFROM */ - - -#ifdef RECVFROM_TYPE_ARG6_IS_VOID -# define RECVFROM_ARG6_T int -#else -# define RECVFROM_ARG6_T RECVFROM_TYPE_ARG6 -#endif -#endif /* if 0 */ - - -/* - * Function-like macro definition used to close a socket. - */ - -#if defined(HAVE_CLOSESOCKET) -# define sclose(x) closesocket((x)) -#elif defined(HAVE_CLOSESOCKET_CAMEL) -# define sclose(x) CloseSocket((x)) -#elif defined(HAVE_CLOSE_S) -# define sclose(x) close_s((x)) -#elif defined(USE_LWIPSOCK) -# define sclose(x) lwip_close((x)) -#else -# define sclose(x) close((x)) -#endif - -/* - * Stack-independent version of fcntl() on sockets: - */ -#if defined(USE_LWIPSOCK) -# define sfcntl lwip_fcntl -#else -# define sfcntl fcntl -#endif - -/* - * Uppercase macro versions of ANSI/ISO is*() functions/macros which - * avoid negative number inputs with argument byte codes > 127. - */ - -#define ISSPACE(x) (isspace((int) ((unsigned char)x))) -#define ISDIGIT(x) (isdigit((int) ((unsigned char)x))) -#define ISALNUM(x) (isalnum((int) ((unsigned char)x))) -#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x))) -#define ISGRAPH(x) (isgraph((int) ((unsigned char)x))) -#define ISALPHA(x) (isalpha((int) ((unsigned char)x))) -#define ISPRINT(x) (isprint((int) ((unsigned char)x))) -#define ISUPPER(x) (isupper((int) ((unsigned char)x))) -#define ISLOWER(x) (islower((int) ((unsigned char)x))) -#define ISASCII(x) (isascii((int) ((unsigned char)x))) - -#define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \ - (((unsigned char)x) == '\t')) - -#define TOLOWER(x) (tolower((int) ((unsigned char)x))) - - -/* - * 'bool' stuff compatible with HP-UX headers. - */ - -#if defined(__hpux) && !defined(HAVE_BOOL_T) - typedef int bool; -# define false 0 -# define true 1 -# define HAVE_BOOL_T -#endif - - -/* - * 'bool' exists on platforms with , i.e. C99 platforms. - * On non-C99 platforms there's no bool, so define an enum for that. - * On C99 platforms 'false' and 'true' also exist. Enum uses a - * global namespace though, so use bool_false and bool_true. - */ - -#ifndef HAVE_BOOL_T - typedef enum { - bool_false = 0, - bool_true = 1 - } bool; - -/* - * Use a define to let 'true' and 'false' use those enums. There - * are currently no use of true and false in libcurl proper, but - * there are some in the examples. This will cater for any later - * code happening to use true and false. - */ -# define false bool_false -# define true bool_true -# define HAVE_BOOL_T -#endif - - -/* - * Redefine TRUE and FALSE too, to catch current use. With this - * change, 'bool found = 1' will give a warning on MIPSPro, but - * 'bool found = TRUE' will not. Change tested on IRIX/MIPSPro, - * AIX 5.1/Xlc, Tru64 5.1/cc, w/make test too. - */ - -#ifndef TRUE -#define TRUE true -#endif -#ifndef FALSE -#define FALSE false -#endif - - -/* - * Macro WHILE_FALSE may be used to build single-iteration do-while loops, - * avoiding compiler warnings. Mostly intended for other macro definitions. - */ - -#define WHILE_FALSE while(0) - -#if defined(_MSC_VER) && !defined(__POCC__) -# undef WHILE_FALSE -# if (_MSC_VER < 1500) -# define WHILE_FALSE while(1, 0) -# else -# define WHILE_FALSE \ -__pragma(warning(push)) \ -__pragma(warning(disable:4127)) \ -while(0) \ -__pragma(warning(pop)) -# endif -#endif - - -/* - * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. - */ - -#ifndef HAVE_SIG_ATOMIC_T -typedef int sig_atomic_t; -#define HAVE_SIG_ATOMIC_T -#endif - - -/* - * Convenience SIG_ATOMIC_T definition - */ - -#ifdef HAVE_SIG_ATOMIC_T_VOLATILE -#define SIG_ATOMIC_T static sig_atomic_t -#else -#define SIG_ATOMIC_T static volatile sig_atomic_t -#endif - - -/* - * Default return type for signal handlers. - */ - -#ifndef RETSIGTYPE -#define RETSIGTYPE void -#endif - - -/* - * Macro used to include code only in debug builds. - */ - -#ifdef DEBUGBUILD -#define DEBUGF(x) x -#else -#define DEBUGF(x) do { } WHILE_FALSE -#endif - - -/* - * Macro used to include assertion code only in debug builds. - */ - -#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H) -#define DEBUGASSERT(x) assert(x) -#else -#define DEBUGASSERT(x) do { } WHILE_FALSE -#endif - - -/* - * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno - * (or equivalent) on this platform to hide platform details to code using it. - */ - -#ifdef USE_WINSOCK -#define SOCKERRNO ((int)WSAGetLastError()) -#define SET_SOCKERRNO(x) (WSASetLastError((int)(x))) -#else -#define SOCKERRNO (errno) -#define SET_SOCKERRNO(x) (errno = (x)) -#endif - - -/* - * Portable error number symbolic names defined to Winsock error codes. - */ - -#ifdef USE_WINSOCK -#undef EBADF /* override definition in errno.h */ -#define EBADF WSAEBADF -#undef EINTR /* override definition in errno.h */ -#define EINTR WSAEINTR -#undef EINVAL /* override definition in errno.h */ -#define EINVAL WSAEINVAL -#undef EWOULDBLOCK /* override definition in errno.h */ -#define EWOULDBLOCK WSAEWOULDBLOCK -#undef EINPROGRESS /* override definition in errno.h */ -#define EINPROGRESS WSAEINPROGRESS -#undef EALREADY /* override definition in errno.h */ -#define EALREADY WSAEALREADY -#undef ENOTSOCK /* override definition in errno.h */ -#define ENOTSOCK WSAENOTSOCK -#undef EDESTADDRREQ /* override definition in errno.h */ -#define EDESTADDRREQ WSAEDESTADDRREQ -#undef EMSGSIZE /* override definition in errno.h */ -#define EMSGSIZE WSAEMSGSIZE -#undef EPROTOTYPE /* override definition in errno.h */ -#define EPROTOTYPE WSAEPROTOTYPE -#undef ENOPROTOOPT /* override definition in errno.h */ -#define ENOPROTOOPT WSAENOPROTOOPT -#undef EPROTONOSUPPORT /* override definition in errno.h */ -#define EPROTONOSUPPORT WSAEPROTONOSUPPORT -#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT -#undef EOPNOTSUPP /* override definition in errno.h */ -#define EOPNOTSUPP WSAEOPNOTSUPP -#define EPFNOSUPPORT WSAEPFNOSUPPORT -#undef EAFNOSUPPORT /* override definition in errno.h */ -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#undef EADDRINUSE /* override definition in errno.h */ -#define EADDRINUSE WSAEADDRINUSE -#undef EADDRNOTAVAIL /* override definition in errno.h */ -#define EADDRNOTAVAIL WSAEADDRNOTAVAIL -#undef ENETDOWN /* override definition in errno.h */ -#define ENETDOWN WSAENETDOWN -#undef ENETUNREACH /* override definition in errno.h */ -#define ENETUNREACH WSAENETUNREACH -#undef ENETRESET /* override definition in errno.h */ -#define ENETRESET WSAENETRESET -#undef ECONNABORTED /* override definition in errno.h */ -#define ECONNABORTED WSAECONNABORTED -#undef ECONNRESET /* override definition in errno.h */ -#define ECONNRESET WSAECONNRESET -#undef ENOBUFS /* override definition in errno.h */ -#define ENOBUFS WSAENOBUFS -#undef EISCONN /* override definition in errno.h */ -#define EISCONN WSAEISCONN -#undef ENOTCONN /* override definition in errno.h */ -#define ENOTCONN WSAENOTCONN -#define ESHUTDOWN WSAESHUTDOWN -#define ETOOMANYREFS WSAETOOMANYREFS -#undef ETIMEDOUT /* override definition in errno.h */ -#define ETIMEDOUT WSAETIMEDOUT -#undef ECONNREFUSED /* override definition in errno.h */ -#define ECONNREFUSED WSAECONNREFUSED -#undef ELOOP /* override definition in errno.h */ -#define ELOOP WSAELOOP -#ifndef ENAMETOOLONG /* possible previous definition in errno.h */ -#define ENAMETOOLONG WSAENAMETOOLONG -#endif -#define EHOSTDOWN WSAEHOSTDOWN -#undef EHOSTUNREACH /* override definition in errno.h */ -#define EHOSTUNREACH WSAEHOSTUNREACH -#ifndef ENOTEMPTY /* possible previous definition in errno.h */ -#define ENOTEMPTY WSAENOTEMPTY -#endif -#define EPROCLIM WSAEPROCLIM -#define EUSERS WSAEUSERS -#define EDQUOT WSAEDQUOT -#define ESTALE WSAESTALE -#define EREMOTE WSAEREMOTE -#endif - -/* - * Macro argv_item_t hides platform details to code using it. - */ - -#ifdef __VMS -#define argv_item_t __char_ptr32 -#else -#define argv_item_t char * -#endif - - -/* - * We use this ZERO_NULL to avoid picky compiler warnings, - * when assigning a NULL pointer to a function pointer var. - */ - -#define ZERO_NULL 0 - - -#endif /* HEADER_CURL_SETUP_ONCE_H */ - diff --git a/dep/cpr/opt/curl/lib/curl_sspi.c b/dep/cpr/opt/curl/lib/curl_sspi.c deleted file mode 100644 index 11a7120a9f4..00000000000 --- a/dep/cpr/opt/curl/lib/curl_sspi.c +++ /dev/null @@ -1,235 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_WINDOWS_SSPI - -#include -#include "curl_sspi.h" -#include "curl_multibyte.h" -#include "system_win32.h" -#include "warnless.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* We use our own typedef here since some headers might lack these */ -typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID); - -/* See definition of SECURITY_ENTRYPOINT in sspi.h */ -#ifdef UNICODE -# ifdef _WIN32_WCE -# define SECURITYENTRYPOINT L"InitSecurityInterfaceW" -# else -# define SECURITYENTRYPOINT "InitSecurityInterfaceW" -# endif -#else -# define SECURITYENTRYPOINT "InitSecurityInterfaceA" -#endif - -/* Handle of security.dll or secur32.dll, depending on Windows version */ -HMODULE s_hSecDll = NULL; - -/* Pointer to SSPI dispatch table */ -PSecurityFunctionTable s_pSecFn = NULL; - -/* - * Curl_sspi_global_init() - * - * This is used to load the Security Service Provider Interface (SSPI) - * dynamic link library portably across all Windows versions, without - * the need to directly link libcurl, nor the application using it, at - * build time. - * - * Once this function has been executed, Windows SSPI functions can be - * called through the Security Service Provider Interface dispatch table. - * - * Parameters: - * - * None. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sspi_global_init(void) -{ - INITSECURITYINTERFACE_FN pInitSecurityInterface; - - /* If security interface is not yet initialized try to do this */ - if(!s_hSecDll) { - /* Security Service Provider Interface (SSPI) functions are located in - * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP - * have both these DLLs (security.dll forwards calls to secur32.dll) */ - - /* Load SSPI dll into the address space of the calling process */ - if(Curl_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL)) - s_hSecDll = Curl_load_library(TEXT("security.dll")); - else - s_hSecDll = Curl_load_library(TEXT("secur32.dll")); - if(!s_hSecDll) - return CURLE_FAILED_INIT; - - /* Get address of the InitSecurityInterfaceA function from the SSPI dll */ - pInitSecurityInterface = (INITSECURITYINTERFACE_FN) - GetProcAddress(s_hSecDll, SECURITYENTRYPOINT); - if(!pInitSecurityInterface) - return CURLE_FAILED_INIT; - - /* Get pointer to Security Service Provider Interface dispatch table */ - s_pSecFn = pInitSecurityInterface(); - if(!s_pSecFn) - return CURLE_FAILED_INIT; - } - - return CURLE_OK; -} - -/* - * Curl_sspi_global_cleanup() - * - * This deinitializes the Security Service Provider Interface from libcurl. - * - * Parameters: - * - * None. - */ -void Curl_sspi_global_cleanup(void) -{ - if(s_hSecDll) { - FreeLibrary(s_hSecDll); - s_hSecDll = NULL; - s_pSecFn = NULL; - } -} - -/* - * Curl_create_sspi_identity() - * - * This is used to populate a SSPI identity structure based on the supplied - * username and password. - * - * Parameters: - * - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * identity [in/out] - The identity structure. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, - SEC_WINNT_AUTH_IDENTITY *identity) -{ - xcharp_u useranddomain; - xcharp_u user, dup_user; - xcharp_u domain, dup_domain; - xcharp_u passwd, dup_passwd; - size_t domlen = 0; - - domain.const_tchar_ptr = TEXT(""); - - /* Initialize the identity */ - memset(identity, 0, sizeof(*identity)); - - useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp); - if(!useranddomain.tchar_ptr) - return CURLE_OUT_OF_MEMORY; - - user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\')); - if(!user.const_tchar_ptr) - user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/')); - - if(user.tchar_ptr) { - domain.tchar_ptr = useranddomain.tchar_ptr; - domlen = user.tchar_ptr - useranddomain.tchar_ptr; - user.tchar_ptr++; - } - else { - user.tchar_ptr = useranddomain.tchar_ptr; - domain.const_tchar_ptr = TEXT(""); - domlen = 0; - } - - /* Setup the identity's user and length */ - dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); - if(!dup_user.tchar_ptr) { - Curl_unicodefree(useranddomain.tchar_ptr); - return CURLE_OUT_OF_MEMORY; - } - identity->User = dup_user.tbyte_ptr; - identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr)); - dup_user.tchar_ptr = NULL; - - /* Setup the identity's domain and length */ - dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1)); - if(!dup_domain.tchar_ptr) { - Curl_unicodefree(useranddomain.tchar_ptr); - return CURLE_OUT_OF_MEMORY; - } - _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen); - *(dup_domain.tchar_ptr + domlen) = TEXT('\0'); - identity->Domain = dup_domain.tbyte_ptr; - identity->DomainLength = curlx_uztoul(domlen); - dup_domain.tchar_ptr = NULL; - - Curl_unicodefree(useranddomain.tchar_ptr); - - /* Setup the identity's password and length */ - passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp); - if(!passwd.tchar_ptr) - return CURLE_OUT_OF_MEMORY; - dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); - if(!dup_passwd.tchar_ptr) { - Curl_unicodefree(passwd.tchar_ptr); - return CURLE_OUT_OF_MEMORY; - } - identity->Password = dup_passwd.tbyte_ptr; - identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); - dup_passwd.tchar_ptr = NULL; - - Curl_unicodefree(passwd.tchar_ptr); - - /* Setup the identity's flags */ - identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY; - - return CURLE_OK; -} - -/* - * Curl_sspi_free_identity() - * - * This is used to free the contents of a SSPI identifier structure. - * - * Parameters: - * - * identity [in/out] - The identity structure. - */ -void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) -{ - if(identity) { - Curl_safefree(identity->User); - Curl_safefree(identity->Password); - Curl_safefree(identity->Domain); - } -} - -#endif /* USE_WINDOWS_SSPI */ diff --git a/dep/cpr/opt/curl/lib/curl_sspi.h b/dep/cpr/opt/curl/lib/curl_sspi.h deleted file mode 100644 index 2bbf9477bb0..00000000000 --- a/dep/cpr/opt/curl/lib/curl_sspi.h +++ /dev/null @@ -1,350 +0,0 @@ -#ifndef HEADER_CURL_SSPI_H -#define HEADER_CURL_SSPI_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_WINDOWS_SSPI - -#include - -/* - * When including the following three headers, it is mandatory to define either - * SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code. - */ - -#undef SECURITY_WIN32 -#undef SECURITY_KERNEL -#define SECURITY_WIN32 1 -#include -#include -#include - -CURLcode Curl_sspi_global_init(void); -void Curl_sspi_global_cleanup(void); - -/* This is used to populate the domain in a SSPI identity structure */ -CURLcode Curl_override_sspi_http_realm(const char *chlg, - SEC_WINNT_AUTH_IDENTITY *identity); - -/* This is used to generate an SSPI identity structure */ -CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, - SEC_WINNT_AUTH_IDENTITY *identity); - -/* This is used to free an SSPI identity structure */ -void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity); - -/* Forward-declaration of global variables defined in curl_sspi.c */ -extern HMODULE s_hSecDll; -extern PSecurityFunctionTable s_pSecFn; - -/* Provide some definitions missing in old headers */ -#define SP_NAME_DIGEST "WDigest" -#define SP_NAME_NTLM "NTLM" -#define SP_NAME_NEGOTIATE "Negotiate" -#define SP_NAME_KERBEROS "Kerberos" - -#ifndef ISC_REQ_USE_HTTP_STYLE -#define ISC_REQ_USE_HTTP_STYLE 0x01000000 -#endif - -#ifndef ISC_RET_REPLAY_DETECT -#define ISC_RET_REPLAY_DETECT 0x00000004 -#endif - -#ifndef ISC_RET_SEQUENCE_DETECT -#define ISC_RET_SEQUENCE_DETECT 0x00000008 -#endif - -#ifndef ISC_RET_CONFIDENTIALITY -#define ISC_RET_CONFIDENTIALITY 0x00000010 -#endif - -#ifndef ISC_RET_ALLOCATED_MEMORY -#define ISC_RET_ALLOCATED_MEMORY 0x00000100 -#endif - -#ifndef ISC_RET_STREAM -#define ISC_RET_STREAM 0x00008000 -#endif - -#ifndef SEC_E_INSUFFICIENT_MEMORY -# define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L) -#endif -#ifndef SEC_E_INVALID_HANDLE -# define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L) -#endif -#ifndef SEC_E_UNSUPPORTED_FUNCTION -# define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L) -#endif -#ifndef SEC_E_TARGET_UNKNOWN -# define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L) -#endif -#ifndef SEC_E_INTERNAL_ERROR -# define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L) -#endif -#ifndef SEC_E_SECPKG_NOT_FOUND -# define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L) -#endif -#ifndef SEC_E_NOT_OWNER -# define SEC_E_NOT_OWNER ((HRESULT)0x80090306L) -#endif -#ifndef SEC_E_CANNOT_INSTALL -# define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L) -#endif -#ifndef SEC_E_INVALID_TOKEN -# define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L) -#endif -#ifndef SEC_E_CANNOT_PACK -# define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L) -#endif -#ifndef SEC_E_QOP_NOT_SUPPORTED -# define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL) -#endif -#ifndef SEC_E_NO_IMPERSONATION -# define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL) -#endif -#ifndef SEC_E_LOGON_DENIED -# define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL) -#endif -#ifndef SEC_E_UNKNOWN_CREDENTIALS -# define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL) -#endif -#ifndef SEC_E_NO_CREDENTIALS -# define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL) -#endif -#ifndef SEC_E_MESSAGE_ALTERED -# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL) -#endif -#ifndef SEC_E_OUT_OF_SEQUENCE -# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L) -#endif -#ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY -# define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L) -#endif -#ifndef SEC_E_BAD_PKGID -# define SEC_E_BAD_PKGID ((HRESULT)0x80090316L) -#endif -#ifndef SEC_E_CONTEXT_EXPIRED -# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L) -#endif -#ifndef SEC_E_INCOMPLETE_MESSAGE -# define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L) -#endif -#ifndef SEC_E_INCOMPLETE_CREDENTIALS -# define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L) -#endif -#ifndef SEC_E_BUFFER_TOO_SMALL -# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L) -#endif -#ifndef SEC_E_WRONG_PRINCIPAL -# define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L) -#endif -#ifndef SEC_E_TIME_SKEW -# define SEC_E_TIME_SKEW ((HRESULT)0x80090324L) -#endif -#ifndef SEC_E_UNTRUSTED_ROOT -# define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L) -#endif -#ifndef SEC_E_ILLEGAL_MESSAGE -# define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L) -#endif -#ifndef SEC_E_CERT_UNKNOWN -# define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L) -#endif -#ifndef SEC_E_CERT_EXPIRED -# define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L) -#endif -#ifndef SEC_E_ENCRYPT_FAILURE -# define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L) -#endif -#ifndef SEC_E_DECRYPT_FAILURE -# define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L) -#endif -#ifndef SEC_E_ALGORITHM_MISMATCH -# define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L) -#endif -#ifndef SEC_E_SECURITY_QOS_FAILED -# define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L) -#endif -#ifndef SEC_E_UNFINISHED_CONTEXT_DELETED -# define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L) -#endif -#ifndef SEC_E_NO_TGT_REPLY -# define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L) -#endif -#ifndef SEC_E_NO_IP_ADDRESSES -# define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L) -#endif -#ifndef SEC_E_WRONG_CREDENTIAL_HANDLE -# define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L) -#endif -#ifndef SEC_E_CRYPTO_SYSTEM_INVALID -# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L) -#endif -#ifndef SEC_E_MAX_REFERRALS_EXCEEDED -# define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L) -#endif -#ifndef SEC_E_MUST_BE_KDC -# define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L) -#endif -#ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED -# define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL) -#endif -#ifndef SEC_E_TOO_MANY_PRINCIPALS -# define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL) -#endif -#ifndef SEC_E_NO_PA_DATA -# define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL) -#endif -#ifndef SEC_E_PKINIT_NAME_MISMATCH -# define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL) -#endif -#ifndef SEC_E_SMARTCARD_LOGON_REQUIRED -# define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL) -#endif -#ifndef SEC_E_SHUTDOWN_IN_PROGRESS -# define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL) -#endif -#ifndef SEC_E_KDC_INVALID_REQUEST -# define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L) -#endif -#ifndef SEC_E_KDC_UNABLE_TO_REFER -# define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L) -#endif -#ifndef SEC_E_KDC_UNKNOWN_ETYPE -# define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L) -#endif -#ifndef SEC_E_UNSUPPORTED_PREAUTH -# define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L) -#endif -#ifndef SEC_E_DELEGATION_REQUIRED -# define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L) -#endif -#ifndef SEC_E_BAD_BINDINGS -# define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L) -#endif -#ifndef SEC_E_MULTIPLE_ACCOUNTS -# define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L) -#endif -#ifndef SEC_E_NO_KERB_KEY -# define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L) -#endif -#ifndef SEC_E_CERT_WRONG_USAGE -# define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L) -#endif -#ifndef SEC_E_DOWNGRADE_DETECTED -# define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L) -#endif -#ifndef SEC_E_SMARTCARD_CERT_REVOKED -# define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L) -#endif -#ifndef SEC_E_ISSUING_CA_UNTRUSTED -# define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L) -#endif -#ifndef SEC_E_REVOCATION_OFFLINE_C -# define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L) -#endif -#ifndef SEC_E_PKINIT_CLIENT_FAILURE -# define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L) -#endif -#ifndef SEC_E_SMARTCARD_CERT_EXPIRED -# define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L) -#endif -#ifndef SEC_E_NO_S4U_PROT_SUPPORT -# define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L) -#endif -#ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE -# define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L) -#endif -#ifndef SEC_E_REVOCATION_OFFLINE_KDC -# define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L) -#endif -#ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC -# define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L) -#endif -#ifndef SEC_E_KDC_CERT_EXPIRED -# define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL) -#endif -#ifndef SEC_E_KDC_CERT_REVOKED -# define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL) -#endif -#ifndef SEC_E_INVALID_PARAMETER -# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) -#endif -#ifndef SEC_E_DELEGATION_POLICY -# define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL) -#endif -#ifndef SEC_E_POLICY_NLTM_ONLY -# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) -#endif - -#ifndef SEC_I_CONTINUE_NEEDED -# define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L) -#endif -#ifndef SEC_I_COMPLETE_NEEDED -# define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L) -#endif -#ifndef SEC_I_COMPLETE_AND_CONTINUE -# define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L) -#endif -#ifndef SEC_I_LOCAL_LOGON -# define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L) -#endif -#ifndef SEC_I_CONTEXT_EXPIRED -# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L) -#endif -#ifndef SEC_I_INCOMPLETE_CREDENTIALS -# define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L) -#endif -#ifndef SEC_I_RENEGOTIATE -# define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L) -#endif -#ifndef SEC_I_NO_LSA_CONTEXT -# define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L) -#endif -#ifndef SEC_I_SIGNATURE_NEEDED -# define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) -#endif - -#ifndef CRYPT_E_REVOKED -# define CRYPT_E_REVOKED ((HRESULT)0x80092010L) -#endif - -#ifdef UNICODE -# define SECFLAG_WINNT_AUTH_IDENTITY \ - (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE -#else -# define SECFLAG_WINNT_AUTH_IDENTITY \ - (unsigned long)SEC_WINNT_AUTH_IDENTITY_ANSI -#endif - -/* - * Definitions required from ntsecapi.h are directly provided below this point - * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h - */ -#define KERB_WRAP_NO_ENCRYPT 0x80000001 - -#endif /* USE_WINDOWS_SSPI */ - -#endif /* HEADER_CURL_SSPI_H */ diff --git a/dep/cpr/opt/curl/lib/curl_threads.c b/dep/cpr/opt/curl/lib/curl_threads.c deleted file mode 100644 index c1624a91366..00000000000 --- a/dep/cpr/opt/curl/lib/curl_threads.c +++ /dev/null @@ -1,146 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#if defined(USE_THREADS_POSIX) -# ifdef HAVE_PTHREAD_H -# include -# endif -#elif defined(USE_THREADS_WIN32) -# ifdef HAVE_PROCESS_H -# include -# endif -#endif - -#include "curl_threads.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -#if defined(USE_THREADS_POSIX) - -struct curl_actual_call { - unsigned int (*func)(void *); - void *arg; -}; - -static void *curl_thread_create_thunk(void *arg) -{ - struct curl_actual_call * ac = arg; - unsigned int (*func)(void *) = ac->func; - void *real_arg = ac->arg; - - free(ac); - - (*func)(real_arg); - - return 0; -} - -curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg) -{ - curl_thread_t t = malloc(sizeof(pthread_t)); - struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call)); - if(!(ac && t)) - goto err; - - ac->func = func; - ac->arg = arg; - - if(pthread_create(t, NULL, curl_thread_create_thunk, ac) != 0) - goto err; - - return t; - -err: - free(t); - free(ac); - return curl_thread_t_null; -} - -void Curl_thread_destroy(curl_thread_t hnd) -{ - if(hnd != curl_thread_t_null) { - pthread_detach(*hnd); - free(hnd); - } -} - -int Curl_thread_join(curl_thread_t *hnd) -{ - int ret = (pthread_join(**hnd, NULL) == 0); - - free(*hnd); - *hnd = curl_thread_t_null; - - return ret; -} - -#elif defined(USE_THREADS_WIN32) - -/* !checksrc! disable SPACEBEFOREPAREN 1 */ -curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), - void *arg) -{ - curl_thread_t t; -#ifdef _WIN32_WCE - t = CreateThread(NULL, 0, func, arg, 0, NULL); -#else - t = (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL); -#endif - if((t == 0) || (t == LongToHandle(-1L))) { -#ifdef _WIN32_WCE - DWORD gle = GetLastError(); - errno = ((gle == ERROR_ACCESS_DENIED || - gle == ERROR_NOT_ENOUGH_MEMORY) ? - EACCES : EINVAL); -#endif - return curl_thread_t_null; - } - return t; -} - -void Curl_thread_destroy(curl_thread_t hnd) -{ - CloseHandle(hnd); -} - -int Curl_thread_join(curl_thread_t *hnd) -{ -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ - (_WIN32_WINNT < _WIN32_WINNT_VISTA) - int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); -#else - int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); -#endif - - Curl_thread_destroy(*hnd); - - *hnd = curl_thread_t_null; - - return ret; -} - -#endif /* USE_THREADS_* */ diff --git a/dep/cpr/opt/curl/lib/curl_threads.h b/dep/cpr/opt/curl/lib/curl_threads.h deleted file mode 100644 index 9e0d14a30d9..00000000000 --- a/dep/cpr/opt/curl/lib/curl_threads.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef HEADER_CURL_THREADS_H -#define HEADER_CURL_THREADS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#if defined(USE_THREADS_POSIX) -# define CURL_STDCALL -# define curl_mutex_t pthread_mutex_t -# define curl_thread_t pthread_t * -# define curl_thread_t_null (pthread_t *)0 -# define Curl_mutex_init(m) pthread_mutex_init(m, NULL) -# define Curl_mutex_acquire(m) pthread_mutex_lock(m) -# define Curl_mutex_release(m) pthread_mutex_unlock(m) -# define Curl_mutex_destroy(m) pthread_mutex_destroy(m) -#elif defined(USE_THREADS_WIN32) -# define CURL_STDCALL __stdcall -# define curl_mutex_t CRITICAL_SECTION -# define curl_thread_t HANDLE -# define curl_thread_t_null (HANDLE)0 -# if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ - (_WIN32_WINNT < _WIN32_WINNT_VISTA) -# define Curl_mutex_init(m) InitializeCriticalSection(m) -# else -# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1) -# endif -# define Curl_mutex_acquire(m) EnterCriticalSection(m) -# define Curl_mutex_release(m) LeaveCriticalSection(m) -# define Curl_mutex_destroy(m) DeleteCriticalSection(m) -#endif - -#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) - -/* !checksrc! disable SPACEBEFOREPAREN 1 */ -curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), - void *arg); - -void Curl_thread_destroy(curl_thread_t hnd); - -int Curl_thread_join(curl_thread_t *hnd); - -#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ - -#endif /* HEADER_CURL_THREADS_H */ diff --git a/dep/cpr/opt/curl/lib/curlx.h b/dep/cpr/opt/curl/lib/curlx.h deleted file mode 100644 index 6168dc119f1..00000000000 --- a/dep/cpr/opt/curl/lib/curlx.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef HEADER_CURL_CURLX_H -#define HEADER_CURL_CURLX_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Defines protos and includes all header files that provide the curlx_* - * functions. The curlx_* functions are not part of the libcurl API, but are - * stand-alone functions whose sources can be built and linked by apps if need - * be. - */ - -#include -/* this is still a public header file that provides the curl_mprintf() - functions while they still are offered publicly. They will be made library- - private one day */ - -#include "strcase.h" -/* "strcase.h" provides the strcasecompare protos */ - -#include "strtoofft.h" -/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a - curl_off_t number from a given string. -*/ - -#include "timeval.h" -/* - "timeval.h" sets up a 'struct timeval' even for platforms that otherwise - don't have one and has protos for these functions: - - curlx_tvnow() - curlx_tvdiff() - curlx_tvdiff_secs() -*/ - -#include "nonblock.h" -/* "nonblock.h" provides curlx_nonblock() */ - -#include "warnless.h" -/* "warnless.h" provides functions: - - curlx_ultous() - curlx_ultouc() - curlx_uztosi() -*/ - -/* Now setup curlx_ * names for the functions that are to become curlx_ and - be removed from a future libcurl official API: - curlx_getenv - curlx_mprintf (and its variations) - curlx_strcasecompare - curlx_strncasecompare - -*/ - -#define curlx_getenv curl_getenv -#define curlx_mvsnprintf curl_mvsnprintf -#define curlx_msnprintf curl_msnprintf -#define curlx_maprintf curl_maprintf -#define curlx_mvaprintf curl_mvaprintf -#define curlx_msprintf curl_msprintf -#define curlx_mprintf curl_mprintf -#define curlx_mfprintf curl_mfprintf -#define curlx_mvsprintf curl_mvsprintf -#define curlx_mvprintf curl_mvprintf -#define curlx_mvfprintf curl_mvfprintf - -#ifdef ENABLE_CURLX_PRINTF -/* If this define is set, we define all "standard" printf() functions to use - the curlx_* version instead. It makes the source code transparent and - easier to understand/patch. Undefine them first. */ -# undef printf -# undef fprintf -# undef sprintf -# undef snprintf -# undef vprintf -# undef vfprintf -# undef vsprintf -# undef vsnprintf -# undef aprintf -# undef vaprintf - -# define printf curlx_mprintf -# define fprintf curlx_mfprintf -# define sprintf curlx_msprintf -# define snprintf curlx_msnprintf -# define vprintf curlx_mvprintf -# define vfprintf curlx_mvfprintf -# define vsprintf curlx_mvsprintf -# define vsnprintf curlx_mvsnprintf -# define aprintf curlx_maprintf -# define vaprintf curlx_mvaprintf -#endif /* ENABLE_CURLX_PRINTF */ - -#endif /* HEADER_CURL_CURLX_H */ - diff --git a/dep/cpr/opt/curl/lib/dict.c b/dep/cpr/opt/curl/lib/dict.c deleted file mode 100644 index 4fc85521d77..00000000000 --- a/dep/cpr/opt/curl/lib/dict.c +++ /dev/null @@ -1,279 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_DICT - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "escape.h" -#include "progress.h" -#include "dict.h" -#include "strcase.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * Forward declarations. - */ - -static CURLcode dict_do(struct connectdata *conn, bool *done); - -/* - * DICT protocol handler. - */ - -const struct Curl_handler Curl_handler_dict = { - "DICT", /* scheme */ - ZERO_NULL, /* setup_connection */ - dict_do, /* do_it */ - ZERO_NULL, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_DICT, /* defport */ - CURLPROTO_DICT, /* protocol */ - PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ -}; - -static char *unescape_word(struct Curl_easy *data, const char *inputbuff) -{ - char *newp = NULL; - char *dictp; - char *ptr; - size_t len; - char ch; - int olen = 0; - - CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE); - if(!newp || result) - return NULL; - - dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */ - if(dictp) { - /* According to RFC2229 section 2.2, these letters need to be escaped with - \[letter] */ - for(ptr = newp; - (ch = *ptr) != 0; - ptr++) { - if((ch <= 32) || (ch == 127) || - (ch == '\'') || (ch == '\"') || (ch == '\\')) { - dictp[olen++] = '\\'; - } - dictp[olen++] = ch; - } - dictp[olen] = 0; - } - free(newp); - return dictp; -} - -static CURLcode dict_do(struct connectdata *conn, bool *done) -{ - char *word; - char *eword; - char *ppath; - char *database = NULL; - char *strategy = NULL; - char *nthdef = NULL; /* This is not part of the protocol, but required - by RFC 2229 */ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - - char *path = data->state.path; - curl_off_t *bytecount = &data->req.bytecount; - - *done = TRUE; /* unconditionally */ - - if(conn->bits.user_passwd) { - /* AUTH is missing */ - } - - if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || - strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || - strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { - - word = strchr(path, ':'); - if(word) { - word++; - database = strchr(word, ':'); - if(database) { - *database++ = (char)0; - strategy = strchr(database, ':'); - if(strategy) { - *strategy++ = (char)0; - nthdef = strchr(strategy, ':'); - if(nthdef) { - *nthdef = (char)0; - } - } - } - } - - if((word == NULL) || (*word == (char)0)) { - infof(data, "lookup word is missing\n"); - word = (char *)"default"; - } - if((database == NULL) || (*database == (char)0)) { - database = (char *)"!"; - } - if((strategy == NULL) || (*strategy == (char)0)) { - strategy = (char *)"."; - } - - eword = unescape_word(data, word); - if(!eword) - return CURLE_OUT_OF_MEMORY; - - result = Curl_sendf(sockfd, conn, - "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" - "MATCH " - "%s " /* database */ - "%s " /* strategy */ - "%s\r\n" /* word */ - "QUIT\r\n", - - database, - strategy, - eword - ); - - free(eword); - - if(result) { - failf(data, "Failed sending DICT request"); - return result; - } - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, - -1, NULL); /* no upload */ - } - else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || - strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || - strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { - - word = strchr(path, ':'); - if(word) { - word++; - database = strchr(word, ':'); - if(database) { - *database++ = (char)0; - nthdef = strchr(database, ':'); - if(nthdef) { - *nthdef = (char)0; - } - } - } - - if((word == NULL) || (*word == (char)0)) { - infof(data, "lookup word is missing\n"); - word = (char *)"default"; - } - if((database == NULL) || (*database == (char)0)) { - database = (char *)"!"; - } - - eword = unescape_word(data, word); - if(!eword) - return CURLE_OUT_OF_MEMORY; - - result = Curl_sendf(sockfd, conn, - "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" - "DEFINE " - "%s " /* database */ - "%s\r\n" /* word */ - "QUIT\r\n", - database, - eword); - - free(eword); - - if(result) { - failf(data, "Failed sending DICT request"); - return result; - } - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, - -1, NULL); /* no upload */ - } - else { - - ppath = strchr(path, '/'); - if(ppath) { - int i; - - ppath++; - for(i = 0; ppath[i]; i++) { - if(ppath[i] == ':') - ppath[i] = ' '; - } - result = Curl_sendf(sockfd, conn, - "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" - "%s\r\n" - "QUIT\r\n", ppath); - if(result) { - failf(data, "Failed sending DICT request"); - return result; - } - - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL); - } - } - - return CURLE_OK; -} -#endif /*CURL_DISABLE_DICT*/ diff --git a/dep/cpr/opt/curl/lib/dict.h b/dep/cpr/opt/curl/lib/dict.h deleted file mode 100644 index 12c0f3394d5..00000000000 --- a/dep/cpr/opt/curl/lib/dict.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef HEADER_CURL_DICT_H -#define HEADER_CURL_DICT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#ifndef CURL_DISABLE_DICT -extern const struct Curl_handler Curl_handler_dict; -#endif - -#endif /* HEADER_CURL_DICT_H */ diff --git a/dep/cpr/opt/curl/lib/dotdot.c b/dep/cpr/opt/curl/lib/dotdot.c deleted file mode 100644 index cbb308d7853..00000000000 --- a/dep/cpr/opt/curl/lib/dotdot.c +++ /dev/null @@ -1,180 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "dotdot.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * "Remove Dot Segments" - * https://tools.ietf.org/html/rfc3986#section-5.2.4 - */ - -/* - * Curl_dedotdotify() - * @unittest: 1395 - * - * This function gets a zero-terminated path with dot and dotdot sequences - * passed in and strips them off according to the rules in RFC 3986 section - * 5.2.4. - * - * The function handles a query part ('?' + stuff) appended but it expects - * that fragments ('#' + stuff) have already been cut off. - * - * RETURNS - * - * an allocated dedotdotified output string - */ -char *Curl_dedotdotify(const char *input) -{ - size_t inlen = strlen(input); - char *clone; - size_t clen = inlen; /* the length of the cloned input */ - char *out = malloc(inlen + 1); - char *outptr; - char *orgclone; - char *queryp; - if(!out) - return NULL; /* out of memory */ - - /* get a cloned copy of the input */ - clone = strdup(input); - if(!clone) { - free(out); - return NULL; - } - orgclone = clone; - outptr = out; - - if(!*clone) { - /* zero length string, return that */ - free(out); - return clone; - } - - /* - * To handle query-parts properly, we must find it and remove it during the - * dotdot-operation and then append it again at the end to the output - * string. - */ - queryp = strchr(clone, '?'); - if(queryp) - *queryp = 0; - - do { - - /* A. If the input buffer begins with a prefix of "../" or "./", then - remove that prefix from the input buffer; otherwise, */ - - if(!strncmp("./", clone, 2)) { - clone += 2; - clen -= 2; - } - else if(!strncmp("../", clone, 3)) { - clone += 3; - clen -= 3; - } - - /* B. if the input buffer begins with a prefix of "/./" or "/.", where - "." is a complete path segment, then replace that prefix with "/" in - the input buffer; otherwise, */ - else if(!strncmp("/./", clone, 3)) { - clone += 2; - clen -= 2; - } - else if(!strcmp("/.", clone)) { - clone[1]='/'; - clone++; - clen -= 1; - } - - /* C. if the input buffer begins with a prefix of "/../" or "/..", where - ".." is a complete path segment, then replace that prefix with "/" in - the input buffer and remove the last segment and its preceding "/" (if - any) from the output buffer; otherwise, */ - - else if(!strncmp("/../", clone, 4)) { - clone += 3; - clen -= 3; - /* remove the last segment from the output buffer */ - while(outptr > out) { - outptr--; - if(*outptr == '/') - break; - } - *outptr = 0; /* zero-terminate where it stops */ - } - else if(!strcmp("/..", clone)) { - clone[2]='/'; - clone += 2; - clen -= 2; - /* remove the last segment from the output buffer */ - while(outptr > out) { - outptr--; - if(*outptr == '/') - break; - } - *outptr = 0; /* zero-terminate where it stops */ - } - - /* D. if the input buffer consists only of "." or "..", then remove - that from the input buffer; otherwise, */ - - else if(!strcmp(".", clone) || !strcmp("..", clone)) { - *clone = 0; - *out = 0; - } - - else { - /* E. move the first path segment in the input buffer to the end of - the output buffer, including the initial "/" character (if any) and - any subsequent characters up to, but not including, the next "/" - character or the end of the input buffer. */ - - do { - *outptr++ = *clone++; - clen--; - } while(*clone && (*clone != '/')); - *outptr = 0; - } - - } while(*clone); - - if(queryp) { - size_t qlen; - /* There was a query part, append that to the output. The 'clone' string - may now have been altered so we copy from the original input string - from the correct index. */ - size_t oindex = queryp - orgclone; - qlen = strlen(&input[oindex]); - memcpy(outptr, &input[oindex], qlen + 1); /* include the end zero byte */ - } - - free(orgclone); - return out; -} diff --git a/dep/cpr/opt/curl/lib/dotdot.h b/dep/cpr/opt/curl/lib/dotdot.h deleted file mode 100644 index fac8e6f2ada..00000000000 --- a/dep/cpr/opt/curl/lib/dotdot.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef HEADER_CURL_DOTDOT_H -#define HEADER_CURL_DOTDOT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -char *Curl_dedotdotify(const char *input); -#endif diff --git a/dep/cpr/opt/curl/lib/easy.c b/dep/cpr/opt/curl/lib/easy.c deleted file mode 100644 index 5328f9c2d94..00000000000 --- a/dep/cpr/opt/curl/lib/easy.c +++ /dev/null @@ -1,1141 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -/* - * See comment in curl_memory.h for the explanation of this sanity check. - */ - -#ifdef CURLX_NO_MEMORY_CALLBACKS -#error "libcurl shall not ever be built with CURLX_NO_MEMORY_CALLBACKS defined" -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "vtls/vtls.h" -#include "url.h" -#include "getinfo.h" -#include "hostip.h" -#include "share.h" -#include "strdup.h" -#include "progress.h" -#include "easyif.h" -#include "select.h" -#include "sendf.h" /* for failf function prototype */ -#include "connect.h" /* for Curl_getconnectinfo */ -#include "slist.h" -#include "amigaos.h" -#include "non-ascii.h" -#include "warnless.h" -#include "conncache.h" -#include "multiif.h" -#include "sigpipe.h" -#include "ssh.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -void Curl_version_init(void); - -/* win32_cleanup() is for win32 socket cleanup functionality, the opposite - of win32_init() */ -static void win32_cleanup(void) -{ -#ifdef USE_WINSOCK - WSACleanup(); -#endif -#ifdef USE_WINDOWS_SSPI - Curl_sspi_global_cleanup(); -#endif -} - -/* win32_init() performs win32 socket initialization to properly setup the - stack to allow networking */ -static CURLcode win32_init(void) -{ -#ifdef USE_WINSOCK - WORD wVersionRequested; - WSADATA wsaData; - int res; - -#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2) - Error IPV6_requires_winsock2 -#endif - - wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK); - - res = WSAStartup(wVersionRequested, &wsaData); - - if(res != 0) - /* Tell the user that we couldn't find a useable */ - /* winsock.dll. */ - return CURLE_FAILED_INIT; - - /* Confirm that the Windows Sockets DLL supports what we need.*/ - /* Note that if the DLL supports versions greater */ - /* than wVersionRequested, it will still return */ - /* wVersionRequested in wVersion. wHighVersion contains the */ - /* highest supported version. */ - - if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || - HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) { - /* Tell the user that we couldn't find a useable */ - - /* winsock.dll. */ - WSACleanup(); - return CURLE_FAILED_INIT; - } - /* The Windows Sockets DLL is acceptable. Proceed. */ -#elif defined(USE_LWIPSOCK) - lwip_init(); -#endif - -#ifdef USE_WINDOWS_SSPI - { - CURLcode result = Curl_sspi_global_init(); - if(result) - return result; - } -#endif - - return CURLE_OK; -} - -/* true globals -- for curl_global_init() and curl_global_cleanup() */ -static unsigned int initialized; -static long init_flags; - -/* - * strdup (and other memory functions) is redefined in complicated - * ways, but at this point it must be defined as the system-supplied strdup - * so the callback pointer is initialized correctly. - */ -#if defined(_WIN32_WCE) -#define system_strdup _strdup -#elif !defined(HAVE_STRDUP) -#define system_strdup curlx_strdup -#else -#define system_strdup strdup -#endif - -#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__) -# pragma warning(disable:4232) /* MSVC extension, dllimport identity */ -#endif - -#ifndef __SYMBIAN32__ -/* - * If a memory-using function (like curl_getenv) is used before - * curl_global_init() is called, we need to have these pointers set already. - */ -curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; -curl_free_callback Curl_cfree = (curl_free_callback)free; -curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; -curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; -curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; -#if defined(WIN32) && defined(UNICODE) -curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; -#endif -#else -/* - * Symbian OS doesn't support initialization to code in writable static data. - * Initialization will occur in the curl_global_init() call. - */ -curl_malloc_callback Curl_cmalloc; -curl_free_callback Curl_cfree; -curl_realloc_callback Curl_crealloc; -curl_strdup_callback Curl_cstrdup; -curl_calloc_callback Curl_ccalloc; -#endif - -#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__) -# pragma warning(default:4232) /* MSVC extension, dllimport identity */ -#endif - -/** - * curl_global_init() globally initializes curl given a bitwise set of the - * different features of what to initialize. - */ -static CURLcode global_init(long flags, bool memoryfuncs) -{ - if(initialized++) - return CURLE_OK; - - if(memoryfuncs) { - /* Setup the default memory functions here (again) */ - Curl_cmalloc = (curl_malloc_callback)malloc; - Curl_cfree = (curl_free_callback)free; - Curl_crealloc = (curl_realloc_callback)realloc; - Curl_cstrdup = (curl_strdup_callback)system_strdup; - Curl_ccalloc = (curl_calloc_callback)calloc; -#if defined(WIN32) && defined(UNICODE) - Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; -#endif - } - - if(flags & CURL_GLOBAL_SSL) - if(!Curl_ssl_init()) { - DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n")); - return CURLE_FAILED_INIT; - } - - if(flags & CURL_GLOBAL_WIN32) - if(win32_init()) { - DEBUGF(fprintf(stderr, "Error: win32_init failed\n")); - return CURLE_FAILED_INIT; - } - -#ifdef __AMIGA__ - if(!Curl_amiga_init()) { - DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n")); - return CURLE_FAILED_INIT; - } -#endif - -#ifdef NETWARE - if(netware_init()) { - DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n")); - } -#endif - - if(Curl_resolver_global_init()) { - DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); - return CURLE_FAILED_INIT; - } - - (void)Curl_ipv6works(); - -#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT) - if(libssh2_init(0)) { - DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n")); - return CURLE_FAILED_INIT; - } -#endif - - if(flags & CURL_GLOBAL_ACK_EINTR) - Curl_ack_eintr = 1; - - init_flags = flags; - - Curl_version_init(); - - return CURLE_OK; -} - - -/** - * curl_global_init() globally initializes curl given a bitwise set of the - * different features of what to initialize. - */ -CURLcode curl_global_init(long flags) -{ - return global_init(flags, TRUE); -} - -/* - * curl_global_init_mem() globally initializes curl and also registers the - * user provided callback routines. - */ -CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, - curl_free_callback f, curl_realloc_callback r, - curl_strdup_callback s, curl_calloc_callback c) -{ - /* Invalid input, return immediately */ - if(!m || !f || !r || !s || !c) - return CURLE_FAILED_INIT; - - if(initialized) { - /* Already initialized, don't do it again, but bump the variable anyway to - work like curl_global_init() and require the same amount of cleanup - calls. */ - initialized++; - return CURLE_OK; - } - - /* set memory functions before global_init() in case it wants memory - functions */ - Curl_cmalloc = m; - Curl_cfree = f; - Curl_cstrdup = s; - Curl_crealloc = r; - Curl_ccalloc = c; - - /* Call the actual init function, but without setting */ - return global_init(flags, FALSE); -} - -/** - * curl_global_cleanup() globally cleanups curl, uses the value of - * "init_flags" to determine what needs to be cleaned up and what doesn't. - */ -void curl_global_cleanup(void) -{ - if(!initialized) - return; - - if(--initialized) - return; - - Curl_global_host_cache_dtor(); - - if(init_flags & CURL_GLOBAL_SSL) - Curl_ssl_cleanup(); - - Curl_resolver_global_cleanup(); - - if(init_flags & CURL_GLOBAL_WIN32) - win32_cleanup(); - - Curl_amiga_cleanup(); - -#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT) - (void)libssh2_exit(); -#endif - - init_flags = 0; -} - -/* - * curl_easy_init() is the external interface to alloc, setup and init an - * easy handle that is returned. If anything goes wrong, NULL is returned. - */ -struct Curl_easy *curl_easy_init(void) -{ - CURLcode result; - struct Curl_easy *data; - - /* Make sure we inited the global SSL stuff */ - if(!initialized) { - result = curl_global_init(CURL_GLOBAL_DEFAULT); - if(result) { - /* something in the global init failed, return nothing */ - DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); - return NULL; - } - } - - /* We use curl_open() with undefined URL so far */ - result = Curl_open(&data); - if(result) { - DEBUGF(fprintf(stderr, "Error: Curl_open failed\n")); - return NULL; - } - - return data; -} - -/* - * curl_easy_setopt() is the external interface for setting options on an - * easy handle. - */ - -#undef curl_easy_setopt -CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...) -{ - va_list arg; - CURLcode result; - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - va_start(arg, tag); - - result = Curl_setopt(data, tag, arg); - - va_end(arg); - return result; -} - -#ifdef CURLDEBUG - -struct socketmonitor { - struct socketmonitor *next; /* the next node in the list or NULL */ - struct pollfd socket; /* socket info of what to monitor */ -}; - -struct events { - long ms; /* timeout, run the timeout function when reached */ - bool msbump; /* set TRUE when timeout is set by callback */ - int num_sockets; /* number of nodes in the monitor list */ - struct socketmonitor *list; /* list of sockets to monitor */ - int running_handles; /* store the returned number */ -}; - -/* events_timer - * - * Callback that gets called with a new value when the timeout should be - * updated. - */ - -static int events_timer(struct Curl_multi *multi, /* multi handle */ - long timeout_ms, /* see above */ - void *userp) /* private callback pointer */ -{ - struct events *ev = userp; - (void)multi; - if(timeout_ms == -1) - /* timeout removed */ - timeout_ms = 0; - else if(timeout_ms == 0) - /* timeout is already reached! */ - timeout_ms = 1; /* trigger asap */ - - ev->ms = timeout_ms; - ev->msbump = TRUE; - return 0; -} - - -/* poll2cselect - * - * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones - */ -static int poll2cselect(int pollmask) -{ - int omask = 0; - if(pollmask & POLLIN) - omask |= CURL_CSELECT_IN; - if(pollmask & POLLOUT) - omask |= CURL_CSELECT_OUT; - if(pollmask & POLLERR) - omask |= CURL_CSELECT_ERR; - return omask; -} - - -/* socketcb2poll - * - * convert from libcurl' CURL_POLL_* bit definitions to poll()'s - */ -static short socketcb2poll(int pollmask) -{ - short omask = 0; - if(pollmask & CURL_POLL_IN) - omask |= POLLIN; - if(pollmask & CURL_POLL_OUT) - omask |= POLLOUT; - return omask; -} - -/* events_socket - * - * Callback that gets called with information about socket activity to - * monitor. - */ -static int events_socket(struct Curl_easy *easy, /* easy handle */ - curl_socket_t s, /* socket */ - int what, /* see above */ - void *userp, /* private callback - pointer */ - void *socketp) /* private socket - pointer */ -{ - struct events *ev = userp; - struct socketmonitor *m; - struct socketmonitor *prev = NULL; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) easy; -#endif - (void)socketp; - - m = ev->list; - while(m) { - if(m->socket.fd == s) { - - if(what == CURL_POLL_REMOVE) { - struct socketmonitor *nxt = m->next; - /* remove this node from the list of monitored sockets */ - if(prev) - prev->next = nxt; - else - ev->list = nxt; - free(m); - m = nxt; - infof(easy, "socket cb: socket %d REMOVED\n", s); - } - else { - /* The socket 's' is already being monitored, update the activity - mask. Convert from libcurl bitmask to the poll one. */ - m->socket.events = socketcb2poll(what); - infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s, - what&CURL_POLL_IN?"IN":"", - what&CURL_POLL_OUT?"OUT":""); - } - break; - } - prev = m; - m = m->next; /* move to next node */ - } - if(!m) { - if(what == CURL_POLL_REMOVE) { - /* this happens a bit too often, libcurl fix perhaps? */ - /* fprintf(stderr, - "%s: socket %d asked to be REMOVED but not present!\n", - __func__, s); */ - } - else { - m = malloc(sizeof(struct socketmonitor)); - if(m) { - m->next = ev->list; - m->socket.fd = s; - m->socket.events = socketcb2poll(what); - m->socket.revents = 0; - ev->list = m; - infof(easy, "socket cb: socket %d ADDED as %s%s\n", s, - what&CURL_POLL_IN?"IN":"", - what&CURL_POLL_OUT?"OUT":""); - } - else - return CURLE_OUT_OF_MEMORY; - } - } - - return 0; -} - - -/* - * events_setup() - * - * Do the multi handle setups that only event-based transfers need. - */ -static void events_setup(struct Curl_multi *multi, struct events *ev) -{ - /* timer callback */ - curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer); - curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev); - - /* socket callback */ - curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket); - curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev); -} - - -/* wait_or_timeout() - * - * waits for activity on any of the given sockets, or the timeout to trigger. - */ - -static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) -{ - bool done = FALSE; - CURLMcode mcode = CURLM_OK; - CURLcode result = CURLE_OK; - - while(!done) { - CURLMsg *msg; - struct socketmonitor *m; - struct pollfd *f; - struct pollfd fds[4]; - int numfds = 0; - int pollrc; - int i; - struct curltime before; - struct curltime after; - - /* populate the fds[] array */ - for(m = ev->list, f = &fds[0]; m; m = m->next) { - f->fd = m->socket.fd; - f->events = m->socket.events; - f->revents = 0; - /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */ - f++; - numfds++; - } - - /* get the time stamp to use to figure out how long poll takes */ - before = curlx_tvnow(); - - /* wait for activity or timeout */ - pollrc = Curl_poll(fds, numfds, (int)ev->ms); - - after = curlx_tvnow(); - - ev->msbump = FALSE; /* reset here */ - - if(0 == pollrc) { - /* timeout! */ - ev->ms = 0; - /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ - mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, - &ev->running_handles); - } - else if(pollrc > 0) { - /* loop over the monitored sockets to see which ones had activity */ - for(i = 0; i< numfds; i++) { - if(fds[i].revents) { - /* socket activity, tell libcurl */ - int act = poll2cselect(fds[i].revents); /* convert */ - infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n", - fds[i].fd); - mcode = curl_multi_socket_action(multi, fds[i].fd, act, - &ev->running_handles); - } - } - - if(!ev->msbump) { - /* If nothing updated the timeout, we decrease it by the spent time. - * If it was updated, it has the new timeout time stored already. - */ - time_t timediff = curlx_tvdiff(after, before); - if(timediff > 0) { - if(timediff > ev->ms) - ev->ms = 0; - else - ev->ms -= (long)timediff; - } - } - } - else - return CURLE_RECV_ERROR; - - if(mcode) - return CURLE_URL_MALFORMAT; /* TODO: return a proper error! */ - - /* we don't really care about the "msgs_in_queue" value returned in the - second argument */ - msg = curl_multi_info_read(multi, &pollrc); - if(msg) { - result = msg->data.result; - done = TRUE; - } - } - - return result; -} - - -/* easy_events() - * - * Runs a transfer in a blocking manner using the events-based API - */ -static CURLcode easy_events(struct Curl_multi *multi) -{ - /* this struct is made static to allow it to be used after this function - returns and curl_multi_remove_handle() is called */ - static struct events evs = {2, FALSE, 0, NULL, 0}; - - /* if running event-based, do some further multi inits */ - events_setup(multi, &evs); - - return wait_or_timeout(multi, &evs); -} -#else /* CURLDEBUG */ -/* when not built with debug, this function doesn't exist */ -#define easy_events(x) CURLE_NOT_BUILT_IN -#endif - -static CURLcode easy_transfer(struct Curl_multi *multi) -{ - bool done = FALSE; - CURLMcode mcode = CURLM_OK; - CURLcode result = CURLE_OK; - struct curltime before; - int without_fds = 0; /* count number of consecutive returns from - curl_multi_wait() without any filedescriptors */ - - while(!done && !mcode) { - int still_running = 0; - int rc; - - before = curlx_tvnow(); - mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc); - - if(!mcode) { - if(!rc) { - struct curltime after = curlx_tvnow(); - - /* If it returns without any filedescriptor instantly, we need to - avoid busy-looping during periods where it has nothing particular - to wait for */ - if(curlx_tvdiff(after, before) <= 10) { - without_fds++; - if(without_fds > 2) { - int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000; - Curl_wait_ms(sleep_ms); - } - } - else - /* it wasn't "instant", restart counter */ - without_fds = 0; - } - else - /* got file descriptor, restart counter */ - without_fds = 0; - - mcode = curl_multi_perform(multi, &still_running); - } - - /* only read 'still_running' if curl_multi_perform() return OK */ - if(!mcode && !still_running) { - CURLMsg *msg = curl_multi_info_read(multi, &rc); - if(msg) { - result = msg->data.result; - done = TRUE; - } - } - } - - /* Make sure to return some kind of error if there was a multi problem */ - if(mcode) { - result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : - /* The other multi errors should never happen, so return - something suitably generic */ - CURLE_BAD_FUNCTION_ARGUMENT; - } - - return result; -} - - -/* - * easy_perform() is the external interface that performs a blocking - * transfer as previously setup. - * - * CONCEPT: This function creates a multi handle, adds the easy handle to it, - * runs curl_multi_perform() until the transfer is done, then detaches the - * easy handle, destroys the multi handle and returns the easy handle's return - * code. - * - * REALITY: it can't just create and destroy the multi handle that easily. It - * needs to keep it around since if this easy handle is used again by this - * function, the same multi handle must be re-used so that the same pools and - * caches can be used. - * - * DEBUG: if 'events' is set TRUE, this function will use a replacement engine - * instead of curl_multi_perform() and use curl_multi_socket_action(). - */ -static CURLcode easy_perform(struct Curl_easy *data, bool events) -{ - struct Curl_multi *multi; - CURLMcode mcode; - CURLcode result = CURLE_OK; - SIGPIPE_VARIABLE(pipe_st); - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - if(data->multi) { - failf(data, "easy handle already used in multi handle"); - return CURLE_FAILED_INIT; - } - - if(data->multi_easy) - multi = data->multi_easy; - else { - /* this multi handle will only ever have a single easy handled attached - to it, so make it use minimal hashes */ - multi = Curl_multi_handle(1, 3); - if(!multi) - return CURLE_OUT_OF_MEMORY; - data->multi_easy = multi; - } - - /* Copy the MAXCONNECTS option to the multi handle */ - curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects); - - mcode = curl_multi_add_handle(multi, data); - if(mcode) { - curl_multi_cleanup(multi); - if(mcode == CURLM_OUT_OF_MEMORY) - return CURLE_OUT_OF_MEMORY; - return CURLE_FAILED_INIT; - } - - sigpipe_ignore(data, &pipe_st); - - /* assign this after curl_multi_add_handle() since that function checks for - it and rejects this handle otherwise */ - data->multi = multi; - - /* run the transfer */ - result = events ? easy_events(multi) : easy_transfer(multi); - - /* ignoring the return code isn't nice, but atm we can't really handle - a failure here, room for future improvement! */ - (void)curl_multi_remove_handle(multi, data); - - sigpipe_restore(&pipe_st); - - /* The multi handle is kept alive, owned by the easy handle */ - return result; -} - - -/* - * curl_easy_perform() is the external interface that performs a blocking - * transfer as previously setup. - */ -CURLcode curl_easy_perform(struct Curl_easy *data) -{ - return easy_perform(data, FALSE); -} - -#ifdef CURLDEBUG -/* - * curl_easy_perform_ev() is the external interface that performs a blocking - * transfer using the event-based API internally. - */ -CURLcode curl_easy_perform_ev(struct Curl_easy *data) -{ - return easy_perform(data, TRUE); -} - -#endif - -/* - * curl_easy_cleanup() is the external interface to cleaning/freeing the given - * easy handle. - */ -void curl_easy_cleanup(struct Curl_easy *data) -{ - SIGPIPE_VARIABLE(pipe_st); - - if(!data) - return; - - sigpipe_ignore(data, &pipe_st); - Curl_close(data); - sigpipe_restore(&pipe_st); -} - -/* - * curl_easy_getinfo() is an external interface that allows an app to retrieve - * information from a performed transfer and similar. - */ -#undef curl_easy_getinfo -CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...) -{ - va_list arg; - void *paramp; - CURLcode result; - - va_start(arg, info); - paramp = va_arg(arg, void *); - - result = Curl_getinfo(data, info, paramp); - - va_end(arg); - return result; -} - -/* - * curl_easy_duphandle() is an external interface to allow duplication of a - * given input easy handle. The returned handle will be a new working handle - * with all options set exactly as the input source handle. - */ -struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) -{ - struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy)); - if(NULL == outcurl) - goto fail; - - /* - * We setup a few buffers we need. We should probably make them - * get setup on-demand in the code, as that would probably decrease - * the likeliness of us forgetting to init a buffer here in the future. - */ - outcurl->set.buffer_size = data->set.buffer_size; - outcurl->state.buffer = malloc(outcurl->set.buffer_size + 1); - if(!outcurl->state.buffer) - goto fail; - - outcurl->state.headerbuff = malloc(HEADERSIZE); - if(!outcurl->state.headerbuff) - goto fail; - outcurl->state.headersize = HEADERSIZE; - - /* copy all userdefined values */ - if(Curl_dupset(outcurl, data)) - goto fail; - - /* the connection cache is setup on demand */ - outcurl->state.conn_cache = NULL; - - outcurl->state.lastconnect = NULL; - - outcurl->progress.flags = data->progress.flags; - outcurl->progress.callback = data->progress.callback; - - if(data->cookies) { - /* If cookies are enabled in the parent handle, we enable them - in the clone as well! */ - outcurl->cookies = Curl_cookie_init(data, - data->cookies->filename, - outcurl->cookies, - data->set.cookiesession); - if(!outcurl->cookies) - goto fail; - } - - /* duplicate all values in 'change' */ - if(data->change.cookielist) { - outcurl->change.cookielist = - Curl_slist_duplicate(data->change.cookielist); - if(!outcurl->change.cookielist) - goto fail; - } - - if(data->change.url) { - outcurl->change.url = strdup(data->change.url); - if(!outcurl->change.url) - goto fail; - outcurl->change.url_alloc = TRUE; - } - - if(data->change.referer) { - outcurl->change.referer = strdup(data->change.referer); - if(!outcurl->change.referer) - goto fail; - outcurl->change.referer_alloc = TRUE; - } - - /* Clone the resolver handle, if present, for the new handle */ - if(Curl_resolver_duphandle(&outcurl->state.resolver, - data->state.resolver)) - goto fail; - - Curl_convert_setup(outcurl); - - Curl_initinfo(outcurl); - - outcurl->magic = CURLEASY_MAGIC_NUMBER; - - /* we reach this point and thus we are OK */ - - return outcurl; - - fail: - - if(outcurl) { - curl_slist_free_all(outcurl->change.cookielist); - outcurl->change.cookielist = NULL; - Curl_safefree(outcurl->state.buffer); - Curl_safefree(outcurl->state.headerbuff); - Curl_safefree(outcurl->change.url); - Curl_safefree(outcurl->change.referer); - Curl_freeset(outcurl); - free(outcurl); - } - - return NULL; -} - -/* - * curl_easy_reset() is an external interface that allows an app to re- - * initialize a session handle to the default values. - */ -void curl_easy_reset(struct Curl_easy *data) -{ - Curl_safefree(data->state.pathbuffer); - - data->state.path = NULL; - - Curl_free_request_state(data); - - /* zero out UserDefined data: */ - Curl_freeset(data); - memset(&data->set, 0, sizeof(struct UserDefined)); - (void)Curl_init_userdefined(&data->set); - - /* zero out Progress data: */ - memset(&data->progress, 0, sizeof(struct Progress)); - - /* zero out PureInfo data: */ - Curl_initinfo(data); - - data->progress.flags |= PGRS_HIDE; - data->state.current_speed = -1; /* init to negative == impossible */ - - /* zero out authentication data: */ - memset(&data->state.authhost, 0, sizeof(struct auth)); - memset(&data->state.authproxy, 0, sizeof(struct auth)); -} - -/* - * curl_easy_pause() allows an application to pause or unpause a specific - * transfer and direction. This function sets the full new state for the - * current connection this easy handle operates on. - * - * NOTE: if you have the receiving paused and you call this function to remove - * the pausing, you may get your write callback called at this point. - * - * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h - */ -CURLcode curl_easy_pause(struct Curl_easy *data, int action) -{ - struct SingleRequest *k = &data->req; - CURLcode result = CURLE_OK; - - /* first switch off both pause bits */ - int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); - - /* set the new desired pause bits */ - newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | - ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0); - - /* put it back in the keepon */ - k->keepon = newstate; - - if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempcount) { - /* there are buffers for sending that can be delivered as the receive - pausing is lifted! */ - unsigned int i; - unsigned int count = data->state.tempcount; - struct tempbuf writebuf[3]; /* there can only be three */ - - /* copy the structs to allow for immediate re-pausing */ - for(i = 0; i < data->state.tempcount; i++) { - writebuf[i] = data->state.tempwrite[i]; - data->state.tempwrite[i].buf = NULL; - } - data->state.tempcount = 0; - - for(i = 0; i < count; i++) { - /* even if one function returns error, this loops through and frees all - buffers */ - if(!result) - result = Curl_client_chop_write(data->easy_conn, - writebuf[i].type, - writebuf[i].buf, - writebuf[i].len); - free(writebuf[i].buf); - } - if(result) - return result; - } - - /* if there's no error and we're not pausing both directions, we want - to have this handle checked soon */ - if(!result && - ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != - (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) ) - Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */ - - return result; -} - - -static CURLcode easy_connection(struct Curl_easy *data, - curl_socket_t *sfd, - struct connectdata **connp) -{ - if(data == NULL) - return CURLE_BAD_FUNCTION_ARGUMENT; - - /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */ - if(!data->set.connect_only) { - failf(data, "CONNECT_ONLY is required!"); - return CURLE_UNSUPPORTED_PROTOCOL; - } - - *sfd = Curl_getconnectinfo(data, connp); - - if(*sfd == CURL_SOCKET_BAD) { - failf(data, "Failed to get recent socket"); - return CURLE_UNSUPPORTED_PROTOCOL; - } - - return CURLE_OK; -} - -/* - * Receives data from the connected socket. Use after successful - * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. - * Returns CURLE_OK on success, error code on error. - */ -CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, - size_t *n) -{ - curl_socket_t sfd; - CURLcode result; - ssize_t n1; - struct connectdata *c; - - result = easy_connection(data, &sfd, &c); - if(result) - return result; - - *n = 0; - result = Curl_read(c, sfd, buffer, buflen, &n1); - - if(result) - return result; - - *n = (size_t)n1; - - return CURLE_OK; -} - -/* - * Sends data over the connected socket. Use after successful - * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. - */ -CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, - size_t buflen, size_t *n) -{ - curl_socket_t sfd; - CURLcode result; - ssize_t n1; - struct connectdata *c = NULL; - - result = easy_connection(data, &sfd, &c); - if(result) - return result; - - *n = 0; - result = Curl_write(c, sfd, buffer, buflen, &n1); - - if(n1 == -1) - return CURLE_SEND_ERROR; - - /* detect EAGAIN */ - if(!result && !n1) - return CURLE_AGAIN; - - *n = (size_t)n1; - - return result; -} diff --git a/dep/cpr/opt/curl/lib/easyif.h b/dep/cpr/opt/curl/lib/easyif.h deleted file mode 100644 index f6132cc70d7..00000000000 --- a/dep/cpr/opt/curl/lib/easyif.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef HEADER_CURL_EASYIF_H -#define HEADER_CURL_EASYIF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Prototypes for library-wide functions provided by easy.c - */ -#ifdef CURLDEBUG -CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy); -#endif - -#endif /* HEADER_CURL_EASYIF_H */ - diff --git a/dep/cpr/opt/curl/lib/escape.c b/dep/cpr/opt/curl/lib/escape.c deleted file mode 100644 index b7e2d32a6ce..00000000000 --- a/dep/cpr/opt/curl/lib/escape.c +++ /dev/null @@ -1,242 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* Escape and unescape URL encoding in strings. The functions return a new - * allocated string or NULL if an error occurred. */ - -#include "curl_setup.h" - -#include - -#include "urldata.h" -#include "warnless.h" -#include "non-ascii.h" -#include "escape.h" -#include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Portable character check (remember EBCDIC). Do not use isalnum() because - its behavior is altered by the current locale. - See https://tools.ietf.org/html/rfc3986#section-2.3 -*/ -static bool Curl_isunreserved(unsigned char in) -{ - switch(in) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - case '-': case '.': case '_': case '~': - return TRUE; - default: - break; - } - return FALSE; -} - -/* for ABI-compatibility with previous versions */ -char *curl_escape(const char *string, int inlength) -{ - return curl_easy_escape(NULL, string, inlength); -} - -/* for ABI-compatibility with previous versions */ -char *curl_unescape(const char *string, int length) -{ - return curl_easy_unescape(NULL, string, length, NULL); -} - -char *curl_easy_escape(struct Curl_easy *data, const char *string, - int inlength) -{ - size_t alloc; - char *ns; - char *testing_ptr = NULL; - unsigned char in; /* we need to treat the characters unsigned */ - size_t newlen; - size_t strindex = 0; - size_t length; - CURLcode result; - - if(inlength < 0) - return NULL; - - alloc = (inlength?(size_t)inlength:strlen(string)) + 1; - newlen = alloc; - - ns = malloc(alloc); - if(!ns) - return NULL; - - length = alloc-1; - while(length--) { - in = *string; - - if(Curl_isunreserved(in)) - /* just copy this */ - ns[strindex++] = in; - else { - /* encode it */ - newlen += 2; /* the size grows with two, since this'll become a %XX */ - if(newlen > alloc) { - alloc *= 2; - testing_ptr = Curl_saferealloc(ns, alloc); - if(!testing_ptr) - return NULL; - ns = testing_ptr; - } - - result = Curl_convert_to_network(data, (char *)&in, 1); - if(result) { - /* Curl_convert_to_network calls failf if unsuccessful */ - free(ns); - return NULL; - } - - snprintf(&ns[strindex], 4, "%%%02X", in); - - strindex += 3; - } - string++; - } - ns[strindex] = 0; /* terminate it */ - return ns; -} - -/* - * Curl_urldecode() URL decodes the given string. - * - * Optionally detects control characters (byte codes lower than 32) in the - * data and rejects such data. - * - * Returns a pointer to a malloced string in *ostring with length given in - * *olen. If length == 0, the length is assumed to be strlen(string). - * - */ -CURLcode Curl_urldecode(struct Curl_easy *data, - const char *string, size_t length, - char **ostring, size_t *olen, - bool reject_ctrl) -{ - size_t alloc = (length?length:strlen(string)) + 1; - char *ns = malloc(alloc); - unsigned char in; - size_t strindex = 0; - unsigned long hex; - CURLcode result; - - if(!ns) - return CURLE_OUT_OF_MEMORY; - - while(--alloc > 0) { - in = *string; - if(('%' == in) && (alloc > 2) && - ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { - /* this is two hexadecimal digits following a '%' */ - char hexstr[3]; - char *ptr; - hexstr[0] = string[1]; - hexstr[1] = string[2]; - hexstr[2] = 0; - - hex = strtoul(hexstr, &ptr, 16); - - in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */ - - result = Curl_convert_from_network(data, (char *)&in, 1); - if(result) { - /* Curl_convert_from_network calls failf if unsuccessful */ - free(ns); - return result; - } - - string += 2; - alloc -= 2; - } - - if(reject_ctrl && (in < 0x20)) { - free(ns); - return CURLE_URL_MALFORMAT; - } - - ns[strindex++] = in; - string++; - } - ns[strindex] = 0; /* terminate it */ - - if(olen) - /* store output size */ - *olen = strindex; - - /* store output string */ - *ostring = ns; - - return CURLE_OK; -} - -/* - * Unescapes the given URL escaped string of given length. Returns a - * pointer to a malloced string with length given in *olen. - * If length == 0, the length is assumed to be strlen(string). - * If olen == NULL, no output length is stored. - */ -char *curl_easy_unescape(struct Curl_easy *data, const char *string, - int length, int *olen) -{ - char *str = NULL; - if(length >= 0) { - size_t inputlen = length; - size_t outputlen; - CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, - FALSE); - if(res) - return NULL; - - if(olen) { - if(outputlen <= (size_t) INT_MAX) - *olen = curlx_uztosi(outputlen); - else - /* too large to return in an int, fail! */ - Curl_safefree(str); - } - } - return str; -} - -/* For operating systems/environments that use different malloc/free - systems for the app and for this library, we provide a free that uses - the library's memory system */ -void curl_free(void *p) -{ - free(p); -} diff --git a/dep/cpr/opt/curl/lib/escape.h b/dep/cpr/opt/curl/lib/escape.h deleted file mode 100644 index 638666f0399..00000000000 --- a/dep/cpr/opt/curl/lib/escape.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef HEADER_CURL_ESCAPE_H -#define HEADER_CURL_ESCAPE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -/* Escape and unescape URL encoding in strings. The functions return a new - * allocated string or NULL if an error occurred. */ - -CURLcode Curl_urldecode(struct Curl_easy *data, - const char *string, size_t length, - char **ostring, size_t *olen, - bool reject_crlf); - -#endif /* HEADER_CURL_ESCAPE_H */ - diff --git a/dep/cpr/opt/curl/lib/file.c b/dep/cpr/opt/curl/lib/file.c deleted file mode 100644 index 7cfdab19f52..00000000000 --- a/dep/cpr/opt/curl/lib/file.c +++ /dev/null @@ -1,600 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_FILE - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_FCNTL_H -#include -#endif - -#include "strtoofft.h" -#include "urldata.h" -#include -#include "progress.h" -#include "sendf.h" -#include "escape.h" -#include "file.h" -#include "speedcheck.h" -#include "getinfo.h" -#include "transfer.h" -#include "url.h" -#include "parsedate.h" /* for the week day and month names */ -#include "warnless.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \ - defined(__SYMBIAN32__) -#define DOS_FILESYSTEM 1 -#endif - -#ifdef OPEN_NEEDS_ARG3 -# define open_readonly(p,f) open((p),(f),(0)) -#else -# define open_readonly(p,f) open((p),(f)) -#endif - -/* - * Forward declarations. - */ - -static CURLcode file_do(struct connectdata *, bool *done); -static CURLcode file_done(struct connectdata *conn, - CURLcode status, bool premature); -static CURLcode file_connect(struct connectdata *conn, bool *done); -static CURLcode file_disconnect(struct connectdata *conn, - bool dead_connection); -static CURLcode file_setup_connection(struct connectdata *conn); - -/* - * FILE scheme handler. - */ - -const struct Curl_handler Curl_handler_file = { - "FILE", /* scheme */ - file_setup_connection, /* setup_connection */ - file_do, /* do_it */ - file_done, /* done */ - ZERO_NULL, /* do_more */ - file_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - file_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - 0, /* defport */ - CURLPROTO_FILE, /* protocol */ - PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */ -}; - - -static CURLcode file_setup_connection(struct connectdata *conn) -{ - /* allocate the FILE specific struct */ - conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO)); - if(!conn->data->req.protop) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; -} - - /* - Check if this is a range download, and if so, set the internal variables - properly. This code is copied from the FTP implementation and might as - well be factored out. - */ -static CURLcode file_range(struct connectdata *conn) -{ - curl_off_t from, to; - curl_off_t totalsize = -1; - char *ptr; - char *ptr2; - struct Curl_easy *data = conn->data; - - if(data->state.use_range && data->state.range) { - CURLofft from_t; - CURLofft to_t; - from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); - if(from_t == CURL_OFFT_FLOW) - return CURLE_RANGE_ERROR; - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) - ptr++; - to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); - if(to_t == CURL_OFFT_FLOW) - return CURLE_RANGE_ERROR; - if((to_t == CURL_OFFT_INVAL) && !from_t) { - /* X - */ - data->state.resume_from = from; - DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n", - from)); - } - else if((from_t == CURL_OFFT_INVAL) && !to_t) { - /* -Y */ - data->req.maxdownload = to; - data->state.resume_from = -to; - DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n", - to)); - } - else { - /* X-Y */ - totalsize = to-from; - if(totalsize == CURL_OFF_T_MAX) - /* this is too big to increase, so bail out */ - return CURLE_RANGE_ERROR; - data->req.maxdownload = totalsize + 1; /* include last byte */ - data->state.resume_from = from; - DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T - " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", - from, data->req.maxdownload)); - } - DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T - " to %" CURL_FORMAT_CURL_OFF_T ", totally %" - CURL_FORMAT_CURL_OFF_T " bytes\n", - from, to, data->req.maxdownload)); - } - else - data->req.maxdownload = -1; - return CURLE_OK; -} - -/* - * file_connect() gets called from Curl_protocol_connect() to allow us to - * do protocol-specific actions at connect-time. We emulate a - * connect-then-transfer protocol and "connect" to the file here - */ -static CURLcode file_connect(struct connectdata *conn, bool *done) -{ - struct Curl_easy *data = conn->data; - char *real_path; - struct FILEPROTO *file = data->req.protop; - int fd; -#ifdef DOS_FILESYSTEM - size_t i; - char *actual_path; -#endif - size_t real_path_len; - - CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path, - &real_path_len, FALSE); - if(result) - return result; - -#ifdef DOS_FILESYSTEM - /* If the first character is a slash, and there's - something that looks like a drive at the beginning of - the path, skip the slash. If we remove the initial - slash in all cases, paths without drive letters end up - relative to the current directory which isn't how - browsers work. - - Some browsers accept | instead of : as the drive letter - separator, so we do too. - - On other platforms, we need the slash to indicate an - absolute pathname. On Windows, absolute paths start - with a drive letter. - */ - actual_path = real_path; - if((actual_path[0] == '/') && - actual_path[1] && - (actual_path[2] == ':' || actual_path[2] == '|')) { - actual_path[2] = ':'; - actual_path++; - real_path_len--; - } - - /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ - for(i = 0; i < real_path_len; ++i) - if(actual_path[i] == '/') - actual_path[i] = '\\'; - else if(!actual_path[i]) { /* binary zero */ - Curl_safefree(real_path); - return CURLE_URL_MALFORMAT; - } - - fd = open_readonly(actual_path, O_RDONLY|O_BINARY); - file->path = actual_path; -#else - if(memchr(real_path, 0, real_path_len)) { - /* binary zeroes indicate foul play */ - Curl_safefree(real_path); - return CURLE_URL_MALFORMAT; - } - - fd = open_readonly(real_path, O_RDONLY); - file->path = real_path; -#endif - file->freepath = real_path; /* free this when done */ - - file->fd = fd; - if(!data->set.upload && (fd == -1)) { - failf(data, "Couldn't open file %s", data->state.path); - file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE); - return CURLE_FILE_COULDNT_READ_FILE; - } - *done = TRUE; - - return CURLE_OK; -} - -static CURLcode file_done(struct connectdata *conn, - CURLcode status, bool premature) -{ - struct FILEPROTO *file = conn->data->req.protop; - (void)status; /* not used */ - (void)premature; /* not used */ - - if(file) { - Curl_safefree(file->freepath); - file->path = NULL; - if(file->fd != -1) - close(file->fd); - file->fd = -1; - } - - return CURLE_OK; -} - -static CURLcode file_disconnect(struct connectdata *conn, - bool dead_connection) -{ - struct FILEPROTO *file = conn->data->req.protop; - (void)dead_connection; /* not used */ - - if(file) { - Curl_safefree(file->freepath); - file->path = NULL; - if(file->fd != -1) - close(file->fd); - file->fd = -1; - } - - return CURLE_OK; -} - -#ifdef DOS_FILESYSTEM -#define DIRSEP '\\' -#else -#define DIRSEP '/' -#endif - -static CURLcode file_upload(struct connectdata *conn) -{ - struct FILEPROTO *file = conn->data->req.protop; - const char *dir = strchr(file->path, DIRSEP); - int fd; - int mode; - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - char *buf = data->state.buffer; - size_t nread; - size_t nwrite; - curl_off_t bytecount = 0; - struct_stat file_stat; - const char *buf2; - - /* - * Since FILE: doesn't do the full init, we need to provide some extra - * assignments here. - */ - conn->data->req.upload_fromhere = buf; - - if(!dir) - return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ - - if(!dir[1]) - return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ - -#ifdef O_BINARY -#define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY -#else -#define MODE_DEFAULT O_WRONLY|O_CREAT -#endif - - if(data->state.resume_from) - mode = MODE_DEFAULT|O_APPEND; - else - mode = MODE_DEFAULT|O_TRUNC; - - fd = open(file->path, mode, conn->data->set.new_file_perms); - if(fd < 0) { - failf(data, "Can't open %s for writing", file->path); - return CURLE_WRITE_ERROR; - } - - if(-1 != data->state.infilesize) - /* known size of data to "upload" */ - Curl_pgrsSetUploadSize(data, data->state.infilesize); - - /* treat the negative resume offset value as the case of "-" */ - if(data->state.resume_from < 0) { - if(fstat(fd, &file_stat)) { - close(fd); - failf(data, "Can't get the size of %s", file->path); - return CURLE_WRITE_ERROR; - } - data->state.resume_from = (curl_off_t)file_stat.st_size; - } - - while(!result) { - int readcount; - result = Curl_fillreadbuffer(conn, (int)data->set.buffer_size, &readcount); - if(result) - break; - - if(readcount <= 0) /* fix questionable compare error. curlvms */ - break; - - nread = (size_t)readcount; - - /*skip bytes before resume point*/ - if(data->state.resume_from) { - if((curl_off_t)nread <= data->state.resume_from) { - data->state.resume_from -= nread; - nread = 0; - buf2 = buf; - } - else { - buf2 = buf + data->state.resume_from; - nread -= (size_t)data->state.resume_from; - data->state.resume_from = 0; - } - } - else - buf2 = buf; - - /* write the data to the target */ - nwrite = write(fd, buf2, nread); - if(nwrite != nread) { - result = CURLE_SEND_ERROR; - break; - } - - bytecount += nread; - - Curl_pgrsSetUploadCounter(data, bytecount); - - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else - result = Curl_speedcheck(data, Curl_tvnow()); - } - if(!result && Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - - close(fd); - - return result; -} - -/* - * file_do() is the protocol-specific function for the do-phase, separated - * from the connect-phase above. Other protocols merely setup the transfer in - * the do-phase, to have it done in the main transfer loop but since some - * platforms we support don't allow select()ing etc on file handles (as - * opposed to sockets) we instead perform the whole do-operation in this - * function. - */ -static CURLcode file_do(struct connectdata *conn, bool *done) -{ - /* This implementation ignores the host name in conformance with - RFC 1738. Only local files (reachable via the standard file system) - are supported. This means that files on remotely mounted directories - (via NFS, Samba, NT sharing) can be accessed through a file:// URL - */ - CURLcode result = CURLE_OK; - struct_stat statbuf; /* struct_stat instead of struct stat just to allow the - Windows version to have a different struct without - having to redefine the simple word 'stat' */ - curl_off_t expected_size = 0; - bool size_known; - bool fstated = FALSE; - ssize_t nread; - struct Curl_easy *data = conn->data; - char *buf = data->state.buffer; - curl_off_t bytecount = 0; - int fd; - struct FILEPROTO *file; - - *done = TRUE; /* unconditionally */ - - Curl_initinfo(data); - Curl_pgrsStartNow(data); - - if(data->set.upload) - return file_upload(conn); - - file = conn->data->req.protop; - - /* get the fd from the connection phase */ - fd = file->fd; - - /* VMS: This only works reliable for STREAMLF files */ - if(-1 != fstat(fd, &statbuf)) { - /* we could stat it, then read out the size */ - expected_size = statbuf.st_size; - /* and store the modification time */ - data->info.filetime = (long)statbuf.st_mtime; - fstated = TRUE; - } - - if(fstated && !data->state.range && data->set.timecondition) { - if(!Curl_meets_timecondition(data, (time_t)data->info.filetime)) { - *done = TRUE; - return CURLE_OK; - } - } - - /* If we have selected NOBODY and HEADER, it means that we only want file - information. Which for FILE can't be much more than the file size and - date. */ - if(data->set.opt_no_body && data->set.include_header && fstated) { - time_t filetime; - struct tm buffer; - const struct tm *tm = &buffer; - char header[80]; - snprintf(header, sizeof(header), - "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0); - if(result) - return result; - - result = Curl_client_write(conn, CLIENTWRITE_BOTH, - (char *)"Accept-ranges: bytes\r\n", 0); - if(result) - return result; - - filetime = (time_t)statbuf.st_mtime; - result = Curl_gmtime(filetime, &buffer); - if(result) - return result; - - /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(header, sizeof(header), - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0); - if(!result) - /* set the file size to make it available post transfer */ - Curl_pgrsSetDownloadSize(data, expected_size); - return result; - } - - /* Check whether file range has been specified */ - file_range(conn); - - /* Adjust the start offset in case we want to get the N last bytes - * of the stream iff the filesize could be determined */ - if(data->state.resume_from < 0) { - if(!fstated) { - failf(data, "Can't get the size of file."); - return CURLE_READ_ERROR; - } - data->state.resume_from += (curl_off_t)statbuf.st_size; - } - - if(data->state.resume_from <= expected_size) - expected_size -= data->state.resume_from; - else { - failf(data, "failed to resume file:// transfer"); - return CURLE_BAD_DOWNLOAD_RESUME; - } - - /* A high water mark has been specified so we obey... */ - if(data->req.maxdownload > 0) - expected_size = data->req.maxdownload; - - if(!fstated || (expected_size == 0)) - size_known = FALSE; - else - size_known = TRUE; - - /* The following is a shortcut implementation of file reading - this is both more efficient than the former call to download() and - it avoids problems with select() and recv() on file descriptors - in Winsock */ - if(fstated) - Curl_pgrsSetDownloadSize(data, expected_size); - - if(data->state.resume_from) { - if(data->state.resume_from != - lseek(fd, data->state.resume_from, SEEK_SET)) - return CURLE_BAD_DOWNLOAD_RESUME; - } - - Curl_pgrsTime(data, TIMER_STARTTRANSFER); - - while(!result) { - /* Don't fill a whole buffer if we want less than all data */ - size_t bytestoread; - - if(size_known) { - bytestoread = (expected_size < data->set.buffer_size) ? - curlx_sotouz(expected_size) : (size_t)data->set.buffer_size; - } - else - bytestoread = data->set.buffer_size-1; - - nread = read(fd, buf, bytestoread); - - if(nread > 0) - buf[nread] = 0; - - if(nread <= 0 || (size_known && (expected_size == 0))) - break; - - bytecount += nread; - if(size_known) - expected_size -= nread; - - result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); - if(result) - return result; - - Curl_pgrsSetDownloadCounter(data, bytecount); - - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else - result = Curl_speedcheck(data, Curl_tvnow()); - } - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - - return result; -} - -#endif diff --git a/dep/cpr/opt/curl/lib/file.h b/dep/cpr/opt/curl/lib/file.h deleted file mode 100644 index c12ae0e09e6..00000000000 --- a/dep/cpr/opt/curl/lib/file.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef HEADER_CURL_FILE_H -#define HEADER_CURL_FILE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - - -/**************************************************************************** - * FILE unique setup - ***************************************************************************/ -struct FILEPROTO { - char *path; /* the path we operate on */ - char *freepath; /* pointer to the allocated block we must free, this might - differ from the 'path' pointer */ - int fd; /* open file descriptor to read from! */ -}; - -#ifndef CURL_DISABLE_FILE -extern const struct Curl_handler Curl_handler_file; -#endif - -#endif /* HEADER_CURL_FILE_H */ - diff --git a/dep/cpr/opt/curl/lib/fileinfo.c b/dep/cpr/opt/curl/lib/fileinfo.c deleted file mode 100644 index 38729884742..00000000000 --- a/dep/cpr/opt/curl/lib/fileinfo.c +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "strdup.h" -#include "fileinfo.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -struct fileinfo *Curl_fileinfo_alloc(void) -{ - return calloc(1, sizeof(struct fileinfo)); -} - -void Curl_fileinfo_dtor(void *user, void *element) -{ - struct fileinfo *finfo = element; - (void) user; - if(!finfo) - return; - - Curl_safefree(finfo->info.b_data); - - free(finfo); -} diff --git a/dep/cpr/opt/curl/lib/fileinfo.h b/dep/cpr/opt/curl/lib/fileinfo.h deleted file mode 100644 index c5d0ee5b646..00000000000 --- a/dep/cpr/opt/curl/lib/fileinfo.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HEADER_CURL_FILEINFO_H -#define HEADER_CURL_FILEINFO_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010, 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include -#include "llist.h" - -struct fileinfo { - struct curl_fileinfo info; - struct curl_llist_element list; -}; - -struct fileinfo *Curl_fileinfo_alloc(void); - -void Curl_fileinfo_dtor(void *, void *); - -#endif /* HEADER_CURL_FILEINFO_H */ diff --git a/dep/cpr/opt/curl/lib/firefox-db2pem.sh b/dep/cpr/opt/curl/lib/firefox-db2pem.sh deleted file mode 100644 index 7d691ff6b99..00000000000 --- a/dep/cpr/opt/curl/lib/firefox-db2pem.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -# *************************************************************************** -# * _ _ ____ _ -# * Project ___| | | | _ \| | -# * / __| | | | |_) | | -# * | (__| |_| | _ <| |___ -# * \___|\___/|_| \_\_____| -# * -# * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. -# * -# * This software is licensed as described in the file COPYING, which -# * you should have received as part of this distribution. The terms -# * are also available at https://curl.haxx.se/docs/copyright.html. -# * -# * 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, under the terms of the COPYING file. -# * -# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# * KIND, either express or implied. -# * -# *************************************************************************** -# This shell script creates a fresh ca-bundle.crt file for use with libcurl. -# It extracts all ca certs it finds in the local Firefox database and converts -# them all into PEM format. -# -db=`ls -1d $HOME/.mozilla/firefox/*default*` -out=$1 - -if test -z "$out"; then - out="ca-bundle.crt" # use a sensible default -fi - -currentdate=`date` - -cat >$out <> $out - diff --git a/dep/cpr/opt/curl/lib/formdata.c b/dep/cpr/opt/curl/lib/formdata.c deleted file mode 100644 index 3568ac5791d..00000000000 --- a/dep/cpr/opt/curl/lib/formdata.c +++ /dev/null @@ -1,1000 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#ifndef CURL_DISABLE_HTTP - -#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) -#include -#endif - -#include "urldata.h" /* for struct Curl_easy */ -#include "formdata.h" -#include "mime.h" -#include "non-ascii.h" -#include "vtls/vtls.h" -#include "strcase.h" -#include "sendf.h" -#include "strdup.h" -#include "rand.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - - -/* What kind of Content-Type to use on un-specified files with unrecognized - extensions. */ -#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream" - -#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME -#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME -#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS -#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE -#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER -#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK -#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER - -/*************************************************************************** - * - * AddHttpPost() - * - * Adds a HttpPost structure to the list, if parent_post is given becomes - * a subpost of parent_post instead of a direct list element. - * - * Returns newly allocated HttpPost on success and NULL if malloc failed. - * - ***************************************************************************/ -static struct curl_httppost * -AddHttpPost(char *name, size_t namelength, - char *value, curl_off_t contentslength, - char *buffer, size_t bufferlength, - char *contenttype, - long flags, - struct curl_slist *contentHeader, - char *showfilename, char *userp, - struct curl_httppost *parent_post, - struct curl_httppost **httppost, - struct curl_httppost **last_post) -{ - struct curl_httppost *post; - post = calloc(1, sizeof(struct curl_httppost)); - if(post) { - post->name = name; - post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); - post->contents = value; - post->contentlen = contentslength; - post->buffer = buffer; - post->bufferlength = (long)bufferlength; - post->contenttype = contenttype; - post->contentheader = contentHeader; - post->showfilename = showfilename; - post->userp = userp; - post->flags = flags | CURL_HTTPPOST_LARGE; - } - else - return NULL; - - if(parent_post) { - /* now, point our 'more' to the original 'more' */ - post->more = parent_post->more; - - /* then move the original 'more' to point to ourselves */ - parent_post->more = post; - } - else { - /* make the previous point to this */ - if(*last_post) - (*last_post)->next = post; - else - (*httppost) = post; - - (*last_post) = post; - } - return post; -} - -/*************************************************************************** - * - * AddFormInfo() - * - * Adds a FormInfo structure to the list presented by parent_form_info. - * - * Returns newly allocated FormInfo on success and NULL if malloc failed/ - * parent_form_info is NULL. - * - ***************************************************************************/ -static FormInfo * AddFormInfo(char *value, - char *contenttype, - FormInfo *parent_form_info) -{ - FormInfo *form_info; - form_info = calloc(1, sizeof(struct FormInfo)); - if(form_info) { - if(value) - form_info->value = value; - if(contenttype) - form_info->contenttype = contenttype; - form_info->flags = HTTPPOST_FILENAME; - } - else - return NULL; - - if(parent_form_info) { - /* now, point our 'more' to the original 'more' */ - form_info->more = parent_form_info->more; - - /* then move the original 'more' to point to ourselves */ - parent_form_info->more = form_info; - } - - return form_info; -} - -/*************************************************************************** - * - * ContentTypeForFilename() - * - * Provides content type for filename if one of the known types (else - * (either the prevtype or the default is returned). - * - * Returns some valid contenttype for filename. - * - ***************************************************************************/ -static const char *ContentTypeForFilename(const char *filename, - const char *prevtype) -{ - const char *contenttype = NULL; - unsigned int i; - /* - * No type was specified, we scan through a few well-known - * extensions and pick the first we match! - */ - struct ContentType { - const char *extension; - const char *type; - }; - static const struct ContentType ctts[]={ - {".gif", "image/gif"}, - {".jpg", "image/jpeg"}, - {".jpeg", "image/jpeg"}, - {".txt", "text/plain"}, - {".html", "text/html"}, - {".xml", "application/xml"} - }; - - if(prevtype) - /* default to the previously set/used! */ - contenttype = prevtype; - else - contenttype = HTTPPOST_CONTENTTYPE_DEFAULT; - - if(filename) { /* in case a NULL was passed in */ - for(i = 0; i= strlen(ctts[i].extension)) { - if(strcasecompare(filename + - strlen(filename) - strlen(ctts[i].extension), - ctts[i].extension)) { - contenttype = ctts[i].type; - break; - } - } - } - } - /* we have a contenttype by now */ - return contenttype; -} - -/*************************************************************************** - * - * FormAdd() - * - * Stores a formpost parameter and builds the appropriate linked list. - * - * Has two principal functionalities: using files and byte arrays as - * post parts. Byte arrays are either copied or just the pointer is stored - * (as the user requests) while for files only the filename and not the - * content is stored. - * - * While you may have only one byte array for each name, multiple filenames - * are allowed (and because of this feature CURLFORM_END is needed after - * using CURLFORM_FILE). - * - * Examples: - * - * Simple name/value pair with copied contents: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); - * - * name/value pair where only the content pointer is remembered: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); - * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) - * - * storing a filename (CONTENTTYPE is optional!): - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", - * CURLFORM_END); - * - * storing multiple filenames: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); - * - * Returns: - * CURL_FORMADD_OK on success - * CURL_FORMADD_MEMORY if the FormInfo allocation fails - * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form - * CURL_FORMADD_NULL if a null pointer was given for a char - * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed - * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used - * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) - * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated - * CURL_FORMADD_MEMORY if some allocation for string copying failed. - * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array - * - ***************************************************************************/ - -static -CURLFORMcode FormAdd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - va_list params) -{ - FormInfo *first_form, *current_form, *form = NULL; - CURLFORMcode return_value = CURL_FORMADD_OK; - const char *prevtype = NULL; - struct curl_httppost *post = NULL; - CURLformoption option; - struct curl_forms *forms = NULL; - char *array_value = NULL; /* value read from an array */ - - /* This is a state variable, that if TRUE means that we're parsing an - array that we got passed to us. If FALSE we're parsing the input - va_list arguments. */ - bool array_state = FALSE; - - /* - * We need to allocate the first struct to fill in. - */ - first_form = calloc(1, sizeof(struct FormInfo)); - if(!first_form) - return CURL_FORMADD_MEMORY; - - current_form = first_form; - - /* - * Loop through all the options set. Break if we have an error to report. - */ - while(return_value == CURL_FORMADD_OK) { - - /* first see if we have more parts of the array param */ - if(array_state && forms) { - /* get the upcoming option from the given array */ - option = forms->option; - array_value = (char *)forms->value; - - forms++; /* advance this to next entry */ - if(CURLFORM_END == option) { - /* end of array state */ - array_state = FALSE; - continue; - } - } - else { - /* This is not array-state, get next option */ - option = va_arg(params, CURLformoption); - if(CURLFORM_END == option) - break; - } - - switch(option) { - case CURLFORM_ARRAY: - if(array_state) - /* we don't support an array from within an array */ - return_value = CURL_FORMADD_ILLEGAL_ARRAY; - else { - forms = va_arg(params, struct curl_forms *); - if(forms) - array_state = TRUE; - else - return_value = CURL_FORMADD_NULL; - } - break; - - /* - * Set the Name property. - */ - case CURLFORM_PTRNAME: -#ifdef CURL_DOES_CONVERSIONS - /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy - * the data in all cases so that we'll have safe memory for the eventual - * conversion. - */ -#else - current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ -#endif - /* FALLTHROUGH */ - case CURLFORM_COPYNAME: - if(current_form->name) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *name = array_state? - array_value:va_arg(params, char *); - if(name) - current_form->name = name; /* store for the moment */ - else - return_value = CURL_FORMADD_NULL; - } - break; - case CURLFORM_NAMELENGTH: - if(current_form->namelength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->namelength = - array_state?(size_t)array_value:(size_t)va_arg(params, long); - break; - - /* - * Set the contents property. - */ - case CURLFORM_PTRCONTENTS: - current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */ - case CURLFORM_COPYCONTENTS: - if(current_form->value) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *value = - array_state?array_value:va_arg(params, char *); - if(value) - current_form->value = value; /* store for the moment */ - else - return_value = CURL_FORMADD_NULL; - } - break; - case CURLFORM_CONTENTSLENGTH: - current_form->contentslength = - array_state?(size_t)array_value:(size_t)va_arg(params, long); - break; - - case CURLFORM_CONTENTLEN: - current_form->flags |= CURL_HTTPPOST_LARGE; - current_form->contentslength = - array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t); - break; - - /* Get contents from a given file name */ - case CURLFORM_FILECONTENT: - if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE)) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - const char *filename = array_state? - array_value:va_arg(params, char *); - if(filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - else { - current_form->flags |= HTTPPOST_READFILE; - current_form->value_alloc = TRUE; - } - } - else - return_value = CURL_FORMADD_NULL; - } - break; - - /* We upload a file */ - case CURLFORM_FILE: - { - const char *filename = array_state?array_value: - va_arg(params, char *); - - if(current_form->value) { - if(current_form->flags & HTTPPOST_FILENAME) { - if(filename) { - char *fname = strdup(filename); - if(!fname) - return_value = CURL_FORMADD_MEMORY; - else { - form = AddFormInfo(fname, NULL, current_form); - if(!form) { - free(fname); - return_value = CURL_FORMADD_MEMORY; - } - else { - form->value_alloc = TRUE; - current_form = form; - form = NULL; - } - } - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if(filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - else { - current_form->flags |= HTTPPOST_FILENAME; - current_form->value_alloc = TRUE; - } - } - else - return_value = CURL_FORMADD_NULL; - } - break; - } - - case CURLFORM_BUFFERPTR: - current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER; - if(current_form->buffer) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *buffer = - array_state?array_value:va_arg(params, char *); - if(buffer) { - current_form->buffer = buffer; /* store for the moment */ - current_form->value = buffer; /* make it non-NULL to be accepted - as fine */ - } - else - return_value = CURL_FORMADD_NULL; - } - break; - - case CURLFORM_BUFFERLENGTH: - if(current_form->bufferlength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->bufferlength = - array_state?(size_t)array_value:(size_t)va_arg(params, long); - break; - - case CURLFORM_STREAM: - current_form->flags |= HTTPPOST_CALLBACK; - if(current_form->userp) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *userp = - array_state?array_value:va_arg(params, char *); - if(userp) { - current_form->userp = userp; - current_form->value = userp; /* this isn't strictly true but we - derive a value from this later on - and we need this non-NULL to be - accepted as a fine form part */ - } - else - return_value = CURL_FORMADD_NULL; - } - break; - - case CURLFORM_CONTENTTYPE: - { - const char *contenttype = - array_state?array_value:va_arg(params, char *); - if(current_form->contenttype) { - if(current_form->flags & HTTPPOST_FILENAME) { - if(contenttype) { - char *type = strdup(contenttype); - if(!type) - return_value = CURL_FORMADD_MEMORY; - else { - form = AddFormInfo(NULL, type, current_form); - if(!form) { - free(type); - return_value = CURL_FORMADD_MEMORY; - } - else { - form->contenttype_alloc = TRUE; - current_form = form; - form = NULL; - } - } - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if(contenttype) { - current_form->contenttype = strdup(contenttype); - if(!current_form->contenttype) - return_value = CURL_FORMADD_MEMORY; - else - current_form->contenttype_alloc = TRUE; - } - else - return_value = CURL_FORMADD_NULL; - } - break; - } - case CURLFORM_CONTENTHEADER: - { - /* this "cast increases required alignment of target type" but - we consider it OK anyway */ - struct curl_slist *list = array_state? - (struct curl_slist *)(void *)array_value: - va_arg(params, struct curl_slist *); - - if(current_form->contentheader) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->contentheader = list; - - break; - } - case CURLFORM_FILENAME: - case CURLFORM_BUFFER: - { - const char *filename = array_state?array_value: - va_arg(params, char *); - if(current_form->showfilename) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - current_form->showfilename = strdup(filename); - if(!current_form->showfilename) - return_value = CURL_FORMADD_MEMORY; - else - current_form->showfilename_alloc = TRUE; - } - break; - } - default: - return_value = CURL_FORMADD_UNKNOWN_OPTION; - break; - } - } - - if(CURL_FORMADD_OK != return_value) { - /* On error, free allocated fields for all nodes of the FormInfo linked - list without deallocating nodes. List nodes are deallocated later on */ - FormInfo *ptr; - for(ptr = first_form; ptr != NULL; ptr = ptr->more) { - if(ptr->name_alloc) { - Curl_safefree(ptr->name); - ptr->name_alloc = FALSE; - } - if(ptr->value_alloc) { - Curl_safefree(ptr->value); - ptr->value_alloc = FALSE; - } - if(ptr->contenttype_alloc) { - Curl_safefree(ptr->contenttype); - ptr->contenttype_alloc = FALSE; - } - if(ptr->showfilename_alloc) { - Curl_safefree(ptr->showfilename); - ptr->showfilename_alloc = FALSE; - } - } - } - - if(CURL_FORMADD_OK == return_value) { - /* go through the list, check for completeness and if everything is - * alright add the HttpPost item otherwise set return_value accordingly */ - - post = NULL; - for(form = first_form; - form != NULL; - form = form->more) { - if(((!form->name || !form->value) && !post) || - ( (form->contentslength) && - (form->flags & HTTPPOST_FILENAME) ) || - ( (form->flags & HTTPPOST_FILENAME) && - (form->flags & HTTPPOST_PTRCONTENTS) ) || - - ( (!form->buffer) && - (form->flags & HTTPPOST_BUFFER) && - (form->flags & HTTPPOST_PTRBUFFER) ) || - - ( (form->flags & HTTPPOST_READFILE) && - (form->flags & HTTPPOST_PTRCONTENTS) ) - ) { - return_value = CURL_FORMADD_INCOMPLETE; - break; - } - if(((form->flags & HTTPPOST_FILENAME) || - (form->flags & HTTPPOST_BUFFER)) && - !form->contenttype) { - char *f = form->flags & HTTPPOST_BUFFER? - form->showfilename : form->value; - - /* our contenttype is missing */ - form->contenttype = strdup(ContentTypeForFilename(f, prevtype)); - if(!form->contenttype) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->contenttype_alloc = TRUE; - } - if(form->name && form->namelength) { - /* Name should not contain nul bytes. */ - size_t i; - for(i = 0; i < form->namelength; i++) - if(!form->name[i]) { - return_value = CURL_FORMADD_NULL; - break; - } - if(return_value != CURL_FORMADD_OK) - break; - } - if(!(form->flags & HTTPPOST_PTRNAME) && - (form == first_form) ) { - /* Note that there's small risk that form->name is NULL here if the - app passed in a bad combo, so we better check for that first. */ - if(form->name) { - /* copy name (without strdup; possibly not nul-terminated) */ - form->name = Curl_memdup(form->name, form->namelength? - form->namelength: - strlen(form->name) + 1); - } - if(!form->name) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->name_alloc = TRUE; - } - if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | - HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | - HTTPPOST_CALLBACK)) && form->value) { - /* copy value (without strdup; possibly contains null characters) */ - size_t clen = (size_t) form->contentslength; - if(!clen) - clen = strlen(form->value) + 1; - - form->value = Curl_memdup(form->value, clen); - - if(!form->value) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->value_alloc = TRUE; - } - post = AddHttpPost(form->name, form->namelength, - form->value, form->contentslength, - form->buffer, form->bufferlength, - form->contenttype, form->flags, - form->contentheader, form->showfilename, - form->userp, - post, httppost, - last_post); - - if(!post) { - return_value = CURL_FORMADD_MEMORY; - break; - } - - if(form->contenttype) - prevtype = form->contenttype; - } - if(CURL_FORMADD_OK != return_value) { - /* On error, free allocated fields for nodes of the FormInfo linked - list which are not already owned by the httppost linked list - without deallocating nodes. List nodes are deallocated later on */ - FormInfo *ptr; - for(ptr = form; ptr != NULL; ptr = ptr->more) { - if(ptr->name_alloc) { - Curl_safefree(ptr->name); - ptr->name_alloc = FALSE; - } - if(ptr->value_alloc) { - Curl_safefree(ptr->value); - ptr->value_alloc = FALSE; - } - if(ptr->contenttype_alloc) { - Curl_safefree(ptr->contenttype); - ptr->contenttype_alloc = FALSE; - } - if(ptr->showfilename_alloc) { - Curl_safefree(ptr->showfilename); - ptr->showfilename_alloc = FALSE; - } - } - } - } - - /* Always deallocate FormInfo linked list nodes without touching node - fields given that these have either been deallocated or are owned - now by the httppost linked list */ - while(first_form) { - FormInfo *ptr = first_form->more; - free(first_form); - first_form = ptr; - } - - return return_value; -} - -/* - * curl_formadd() is a public API to add a section to the multipart formpost. - * - * @unittest: 1308 - */ - -CURLFORMcode curl_formadd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...) -{ - va_list arg; - CURLFORMcode result; - va_start(arg, last_post); - result = FormAdd(httppost, last_post, arg); - va_end(arg); - return result; -} - -/* - * curl_formget() - * Serialize a curl_httppost struct. - * Returns 0 on success. - * - * @unittest: 1308 - */ -int curl_formget(struct curl_httppost *form, void *arg, - curl_formget_callback append) -{ - CURLcode result; - curl_mimepart toppart; - - Curl_mime_initpart(&toppart, NULL); /* default form is empty */ - result = Curl_getformdata(NULL, &toppart, form, NULL); - if(!result) - result = Curl_mime_prepare_headers(&toppart, "multipart/form-data", - NULL, MIMESTRATEGY_FORM); - - while(!result) { - char buffer[8192]; - size_t nread = Curl_mime_read(buffer, 1, sizeof buffer, &toppart); - - if(!nread) - break; - - switch(nread) { - default: - if(append(arg, buffer, nread) != nread) - result = CURLE_READ_ERROR; - break; - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: - break; - } - } - - Curl_mime_cleanpart(&toppart); - return (int) result; -} - -/* - * curl_formfree() is an external function to free up a whole form post - * chain - */ -void curl_formfree(struct curl_httppost *form) -{ - struct curl_httppost *next; - - if(!form) - /* no form to free, just get out of this */ - return; - - do { - next = form->next; /* the following form line */ - - /* recurse to sub-contents */ - curl_formfree(form->more); - - if(!(form->flags & HTTPPOST_PTRNAME)) - free(form->name); /* free the name */ - if(!(form->flags & - (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) - ) - free(form->contents); /* free the contents */ - free(form->contenttype); /* free the content type */ - free(form->showfilename); /* free the faked file name */ - free(form); /* free the struct */ - form = next; - } while(form); /* continue */ -} - - -/* Set mime part name, taking care of non nul-terminated name string. */ -static CURLcode setname(curl_mimepart *part, const char *name, size_t len) -{ - char *zname; - CURLcode res; - - if(!name || !len) - return curl_mime_name(part, name); - zname = malloc(len + 1); - if(!zname) - return CURLE_OUT_OF_MEMORY; - memcpy(zname, name, len); - zname[len] = '\0'; - res = curl_mime_name(part, zname); - free(zname); - return res; -} - -/* - * Curl_getformdata() converts a linked list of "meta data" into a mime - * structure. The input list is in 'post', while the output is stored in - * mime part at '*finalform'. - * - * This function will not do a failf() for the potential memory failures but - * should for all other errors it spots. Just note that this function MAY get - * a NULL pointer in the 'data' argument. - */ - -CURLcode Curl_getformdata(struct Curl_easy *data, - curl_mimepart *finalform, - struct curl_httppost *post, - curl_read_callback fread_func) -{ - CURLcode result = CURLE_OK; - curl_mime *form = NULL; - curl_mime *multipart; - curl_mimepart *part; - struct curl_httppost *file; - - Curl_mime_cleanpart(finalform); /* default form is empty */ - - if(!post) - return result; /* no input => no output! */ - - form = curl_mime_init(data); - if(!form) - result = CURLE_OUT_OF_MEMORY; - - if(!result) - result = curl_mime_subparts(finalform, form); - - /* Process each top part. */ - for(; !result && post; post = post->next) { - /* If we have more than a file here, create a mime subpart and fill it. */ - multipart = form; - if(post->more) { - part = curl_mime_addpart(form); - if(!part) - result = CURLE_OUT_OF_MEMORY; - if(!result) - result = setname(part, post->name, post->namelength); - if(!result) { - multipart = curl_mime_init(data); - if(!multipart) - result = CURLE_OUT_OF_MEMORY; - } - if(!result) - result = curl_mime_subparts(part, multipart); - } - - /* Generate all the part contents. */ - for(file = post; !result && file; file = file->more) { - /* Create the part. */ - part = curl_mime_addpart(multipart); - if(!part) - result = CURLE_OUT_OF_MEMORY; - - /* Set the headers. */ - if(!result) - result = curl_mime_headers(part, file->contentheader, 0); - - /* Set the content type. */ - if(!result &&file->contenttype) - result = curl_mime_type(part, file->contenttype); - - /* Set field name. */ - if(!result && !post->more) - result = setname(part, post->name, post->namelength); - - /* Process contents. */ - if(!result) { - curl_off_t clen = post->contentslength; - - if(post->flags & CURL_HTTPPOST_LARGE) - clen = post->contentlen; - if(!clen) - clen = -1; - - if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) { - if(!strcmp(file->contents, "-")) { - /* There are a few cases where the code below won't work; in - particular, freopen(stdin) by the caller is not guaranteed - to result as expected. This feature has been kept for backward - compatibility: use of "-" pseudo file name should be avoided. */ - result = curl_mime_data_cb(part, (curl_off_t) -1, - (curl_read_callback) fread, - (curl_seek_callback) fseek, - NULL, (void *) stdin); - } - else - result = curl_mime_filedata(part, file->contents); - if(!result && (post->flags & HTTPPOST_READFILE)) - result = curl_mime_filename(part, NULL); - } - else if(post->flags & HTTPPOST_BUFFER) - result = curl_mime_data(part, post->buffer, - post->bufferlength? post->bufferlength: -1); - else if(post->flags & HTTPPOST_CALLBACK) - /* the contents should be read with the callback and the size is set - with the contentslength */ - result = curl_mime_data_cb(part, clen, - fread_func, NULL, NULL, post->userp); - else { - result = curl_mime_data(part, post->contents, (ssize_t) clen); -#ifdef CURL_DOES_CONVERSIONS - /* Convert textual contents now. */ - if(!result && data && part->datasize) - result = Curl_convert_to_network(data, part->data, part->datasize); -#endif - } - } - - /* Set fake file name. */ - if(!result && post->showfilename) - if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER | - HTTPPOST_CALLBACK))) - result = curl_mime_filename(part, post->showfilename); - } - } - - if(result) - Curl_mime_cleanpart(finalform); - - return result; -} - -#else /* CURL_DISABLE_HTTP */ -CURLFORMcode curl_formadd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...) -{ - (void)httppost; - (void)last_post; - return CURL_FORMADD_DISABLED; -} - -int curl_formget(struct curl_httppost *form, void *arg, - curl_formget_callback append) -{ - (void) form; - (void) arg; - (void) append; - return CURL_FORMADD_DISABLED; -} - -void curl_formfree(struct curl_httppost *form) -{ - (void)form; - /* does nothing HTTP is disabled */ -} - - -#endif /* !defined(CURL_DISABLE_HTTP) */ diff --git a/dep/cpr/opt/curl/lib/formdata.h b/dep/cpr/opt/curl/lib/formdata.h deleted file mode 100644 index 1246c2bc8ed..00000000000 --- a/dep/cpr/opt/curl/lib/formdata.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef HEADER_CURL_FORMDATA_H -#define HEADER_CURL_FORMDATA_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* used by FormAdd for temporary storage */ -typedef struct FormInfo { - char *name; - bool name_alloc; - size_t namelength; - char *value; - bool value_alloc; - curl_off_t contentslength; - char *contenttype; - bool contenttype_alloc; - long flags; - char *buffer; /* pointer to existing buffer used for file upload */ - size_t bufferlength; - char *showfilename; /* The file name to show. If not set, the actual - file name will be used */ - bool showfilename_alloc; - char *userp; /* pointer for the read callback */ - struct curl_slist *contentheader; - struct FormInfo *more; -} FormInfo; - -CURLcode Curl_getformdata(struct Curl_easy *data, - curl_mimepart *, - struct curl_httppost *post, - curl_read_callback fread_func); - -#endif /* HEADER_CURL_FORMDATA_H */ diff --git a/dep/cpr/opt/curl/lib/ftp.c b/dep/cpr/opt/curl/lib/ftp.c deleted file mode 100644 index 54ba4057fe9..00000000000 --- a/dep/cpr/opt/curl/lib/ftp.c +++ /dev/null @@ -1,4481 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_FTP - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_UTSNAME_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "if2ip.h" -#include "hostip.h" -#include "progress.h" -#include "transfer.h" -#include "escape.h" -#include "http.h" /* for HTTP proxy tunnel stuff */ -#include "socks.h" -#include "ftp.h" -#include "fileinfo.h" -#include "ftplistparser.h" -#include "curl_sec.h" -#include "strtoofft.h" -#include "strcase.h" -#include "vtls/vtls.h" -#include "connect.h" -#include "strerror.h" -#include "inet_ntop.h" -#include "inet_pton.h" -#include "select.h" -#include "parsedate.h" /* for the week day and month names */ -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "multiif.h" -#include "url.h" -#include "strcase.h" -#include "speedcheck.h" -#include "warnless.h" -#include "http_proxy.h" -#include "non-ascii.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifndef NI_MAXHOST -#define NI_MAXHOST 1025 -#endif -#ifndef INET_ADDRSTRLEN -#define INET_ADDRSTRLEN 16 -#endif - -#ifdef CURL_DISABLE_VERBOSE_STRINGS -#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt -#endif - -/* Local API functions */ -#ifndef DEBUGBUILD -static void _state(struct connectdata *conn, - ftpstate newstate); -#define state(x,y) _state(x,y) -#else -static void _state(struct connectdata *conn, - ftpstate newstate, - int lineno); -#define state(x,y) _state(x,y,__LINE__) -#endif - -static CURLcode ftp_sendquote(struct connectdata *conn, - struct curl_slist *quote); -static CURLcode ftp_quit(struct connectdata *conn); -static CURLcode ftp_parse_url_path(struct connectdata *conn); -static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done); -#ifndef CURL_DISABLE_VERBOSE_STRINGS -static void ftp_pasv_verbose(struct connectdata *conn, - Curl_addrinfo *ai, - char *newhost, /* ascii version */ - int port); -#endif -static CURLcode ftp_state_prepare_transfer(struct connectdata *conn); -static CURLcode ftp_state_mdtm(struct connectdata *conn); -static CURLcode ftp_state_quote(struct connectdata *conn, - bool init, ftpstate instate); -static CURLcode ftp_nb_type(struct connectdata *conn, - bool ascii, ftpstate newstate); -static int ftp_need_type(struct connectdata *conn, - bool ascii); -static CURLcode ftp_do(struct connectdata *conn, bool *done); -static CURLcode ftp_done(struct connectdata *conn, - CURLcode, bool premature); -static CURLcode ftp_connect(struct connectdata *conn, bool *done); -static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection); -static CURLcode ftp_do_more(struct connectdata *conn, int *completed); -static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done); -static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks); -static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks); -static CURLcode ftp_doing(struct connectdata *conn, - bool *dophase_done); -static CURLcode ftp_setup_connection(struct connectdata * conn); - -static CURLcode init_wc_data(struct connectdata *conn); -static CURLcode wc_statemach(struct connectdata *conn); - -static void wc_data_dtor(void *ptr); - -static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize); - -static CURLcode ftp_readresp(curl_socket_t sockfd, - struct pingpong *pp, - int *ftpcode, - size_t *size); -static CURLcode ftp_dophase_done(struct connectdata *conn, - bool connected); - -/* easy-to-use macro: */ -#define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \ - if(result) \ - return result - - -/* - * FTP protocol handler. - */ - -const struct Curl_handler Curl_handler_ftp = { - "FTP", /* scheme */ - ftp_setup_connection, /* setup_connection */ - ftp_do, /* do_it */ - ftp_done, /* done */ - ftp_do_more, /* do_more */ - ftp_connect, /* connect_it */ - ftp_multi_statemach, /* connecting */ - ftp_doing, /* doing */ - ftp_getsock, /* proto_getsock */ - ftp_getsock, /* doing_getsock */ - ftp_domore_getsock, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_FTP, /* defport */ - CURLPROTO_FTP, /* protocol */ - PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD | - PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP /* flags */ -}; - - -#ifdef USE_SSL -/* - * FTPS protocol handler. - */ - -const struct Curl_handler Curl_handler_ftps = { - "FTPS", /* scheme */ - ftp_setup_connection, /* setup_connection */ - ftp_do, /* do_it */ - ftp_done, /* done */ - ftp_do_more, /* do_more */ - ftp_connect, /* connect_it */ - ftp_multi_statemach, /* connecting */ - ftp_doing, /* doing */ - ftp_getsock, /* proto_getsock */ - ftp_getsock, /* doing_getsock */ - ftp_domore_getsock, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_FTPS, /* defport */ - CURLPROTO_FTPS, /* protocol */ - PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION | - PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */ -}; -#endif - -static void close_secondarysocket(struct connectdata *conn) -{ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } - conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; -} - -/* - * NOTE: back in the old days, we added code in the FTP code that made NOBODY - * requests on files respond with headers passed to the client/stdout that - * looked like HTTP ones. - * - * This approach is not very elegant, it causes confusion and is error-prone. - * It is subject for removal at the next (or at least a future) soname bump. - * Until then you can test the effects of the removal by undefining the - * following define named CURL_FTP_HTTPSTYLE_HEAD. - */ -#define CURL_FTP_HTTPSTYLE_HEAD 1 - -static void freedirs(struct ftp_conn *ftpc) -{ - int i; - if(ftpc->dirs) { - for(i = 0; i < ftpc->dirdepth; i++) { - free(ftpc->dirs[i]); - ftpc->dirs[i] = NULL; - } - free(ftpc->dirs); - ftpc->dirs = NULL; - ftpc->dirdepth = 0; - } - Curl_safefree(ftpc->file); - - /* no longer of any use */ - Curl_safefree(ftpc->newhost); -} - -/* Returns non-zero if the given string contains CR (\r) or LF (\n), - which are not allowed within RFC 959 . - Note: The input string is in the client's encoding which might - not be ASCII, so escape sequences \r & \n must be used instead - of hex values 0x0d & 0x0a. -*/ -static bool isBadFtpString(const char *string) -{ - return ((NULL != strchr(string, '\r')) || - (NULL != strchr(string, '\n'))) ? TRUE : FALSE; -} - -/*********************************************************************** - * - * AcceptServerConnect() - * - * After connection request is received from the server this function is - * called to accept the connection and close the listening socket - * - */ -static CURLcode AcceptServerConnect(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - curl_socket_t sock = conn->sock[SECONDARYSOCKET]; - curl_socket_t s = CURL_SOCKET_BAD; -#ifdef ENABLE_IPV6 - struct Curl_sockaddr_storage add; -#else - struct sockaddr_in add; -#endif - curl_socklen_t size = (curl_socklen_t) sizeof(add); - - if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { - size = sizeof(add); - - s = accept(sock, (struct sockaddr *) &add, &size); - } - Curl_closesocket(conn, sock); /* close the first socket */ - - if(CURL_SOCKET_BAD == s) { - failf(data, "Error accept()ing server connect"); - return CURLE_FTP_PORT_FAILED; - } - infof(data, "Connection accepted from server\n"); - /* when this happens within the DO state it is important that we mark us as - not needing DO_MORE anymore */ - conn->bits.do_more = FALSE; - - conn->sock[SECONDARYSOCKET] = s; - (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ - conn->sock_accepted[SECONDARYSOCKET] = TRUE; - - if(data->set.fsockopt) { - int error = 0; - - /* activate callback for setting socket options */ - error = data->set.fsockopt(data->set.sockopt_client, - s, - CURLSOCKTYPE_ACCEPT); - - if(error) { - close_secondarysocket(conn); - return CURLE_ABORTED_BY_CALLBACK; - } - } - - return CURLE_OK; - -} - -/* - * ftp_timeleft_accept() returns the amount of milliseconds left allowed for - * waiting server to connect. If the value is negative, the timeout time has - * already elapsed. - * - * The start time is stored in progress.t_acceptdata - as set with - * Curl_pgrsTime(..., TIMER_STARTACCEPT); - * - */ -static time_t ftp_timeleft_accept(struct Curl_easy *data) -{ - time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT; - time_t other; - struct curltime now; - - if(data->set.accepttimeout > 0) - timeout_ms = data->set.accepttimeout; - - now = Curl_tvnow(); - - /* check if the generic timeout possibly is set shorter */ - other = Curl_timeleft(data, &now, FALSE); - if(other && (other < timeout_ms)) - /* note that this also works fine for when other happens to be negative - due to it already having elapsed */ - timeout_ms = other; - else { - /* subtract elapsed time */ - timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata); - if(!timeout_ms) - /* avoid returning 0 as that means no timeout! */ - return -1; - } - - return timeout_ms; -} - - -/*********************************************************************** - * - * ReceivedServerConnect() - * - * After allowing server to connect to us from data port, this function - * checks both data connection for connection establishment and ctrl - * connection for a negative response regarding a failure in connecting - * - */ -static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) -{ - struct Curl_easy *data = conn->data; - curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; - curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - int result; - time_t timeout_ms; - ssize_t nread; - int ftpcode; - - *received = FALSE; - - timeout_ms = ftp_timeleft_accept(data); - infof(data, "Checking for server connect\n"); - if(timeout_ms < 0) { - /* if a timeout was already reached, bail out */ - failf(data, "Accept timeout occurred while waiting server connect"); - return CURLE_FTP_ACCEPT_TIMEOUT; - } - - /* First check whether there is a cached response from server */ - if(pp->cache_size && pp->cache && pp->cache[0] > '3') { - /* Data connection could not be established, let's return */ - infof(data, "There is negative response in cache while serv connect\n"); - Curl_GetFTPResponse(&nread, conn, &ftpcode); - return CURLE_FTP_ACCEPT_FAILED; - } - - result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); - - /* see if the connection request is already here */ - switch(result) { - case -1: /* error */ - /* let's die here */ - failf(data, "Error while waiting for server connect"); - return CURLE_FTP_ACCEPT_FAILED; - case 0: /* Server connect is not received yet */ - break; /* loop */ - default: - - if(result & CURL_CSELECT_IN2) { - infof(data, "Ready to accept data connection from server\n"); - *received = TRUE; - } - else if(result & CURL_CSELECT_IN) { - infof(data, "Ctrl conn has data while waiting for data conn\n"); - Curl_GetFTPResponse(&nread, conn, &ftpcode); - - if(ftpcode/100 > 3) - return CURLE_FTP_ACCEPT_FAILED; - - return CURLE_WEIRD_SERVER_REPLY; - } - - break; - } /* switch() */ - - return CURLE_OK; -} - - -/*********************************************************************** - * - * InitiateTransfer() - * - * After connection from server is accepted this function is called to - * setup transfer parameters and initiate the data transfer. - * - */ -static CURLcode InitiateTransfer(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - struct FTP *ftp = data->req.protop; - CURLcode result = CURLE_OK; - - if(conn->bits.ftp_use_data_ssl) { - /* since we only have a plaintext TCP connection here, we must now - * do the TLS stuff */ - infof(data, "Doing the SSL/TLS handshake on the data stream\n"); - result = Curl_ssl_connect(conn, SECONDARYSOCKET); - if(result) - return result; - } - - if(conn->proto.ftpc.state_saved == FTP_STOR) { - *(ftp->bytecountp) = 0; - - /* When we know we're uploading a specified file, we can get the file - size prior to the actual upload. */ - - Curl_pgrsSetUploadSize(data, data->state.infilesize); - - /* set the SO_SNDBUF for the secondary socket for those who need it */ - Curl_sndbufset(conn->sock[SECONDARYSOCKET]); - - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ - SECONDARYSOCKET, ftp->bytecountp); - } - else { - /* FTP download: */ - Curl_setup_transfer(conn, SECONDARYSOCKET, - conn->proto.ftpc.retr_size_saved, FALSE, - ftp->bytecountp, -1, NULL); /* no upload here */ - } - - conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ - state(conn, FTP_STOP); - - return CURLE_OK; -} - -/*********************************************************************** - * - * AllowServerConnect() - * - * When we've issue the PORT command, we have told the server to connect to - * us. This function checks whether data connection is established if so it is - * accepted. - * - */ -static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) -{ - struct Curl_easy *data = conn->data; - time_t timeout_ms; - CURLcode result = CURLE_OK; - - *connected = FALSE; - infof(data, "Preparing for accepting server on data port\n"); - - /* Save the time we start accepting server connect */ - Curl_pgrsTime(data, TIMER_STARTACCEPT); - - timeout_ms = ftp_timeleft_accept(data); - if(timeout_ms < 0) { - /* if a timeout was already reached, bail out */ - failf(data, "Accept timeout occurred while waiting server connect"); - return CURLE_FTP_ACCEPT_TIMEOUT; - } - - /* see if the connection request is already here */ - result = ReceivedServerConnect(conn, connected); - if(result) - return result; - - if(*connected) { - result = AcceptServerConnect(conn); - if(result) - return result; - - result = InitiateTransfer(conn); - if(result) - return result; - } - else { - /* Add timeout to multi handle and break out of the loop */ - if(!result && *connected == FALSE) { - Curl_expire(data, data->set.accepttimeout > 0 ? - data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0); - } - } - - return result; -} - -/* macro to check for a three-digit ftp status code at the start of the - given string */ -#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ - ISDIGIT(line[2])) - -/* macro to check for the last line in an FTP server response */ -#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3])) - -static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len, - int *code) -{ - (void)conn; - - if((len > 3) && LASTLINE(line)) { - *code = curlx_sltosi(strtol(line, NULL, 10)); - return TRUE; - } - - return FALSE; -} - -static CURLcode ftp_readresp(curl_socket_t sockfd, - struct pingpong *pp, - int *ftpcode, /* return the ftp-code if done */ - size_t *size) /* size of the response */ -{ - struct connectdata *conn = pp->conn; - struct Curl_easy *data = conn->data; -#ifdef HAVE_GSSAPI - char * const buf = data->state.buffer; -#endif - CURLcode result = CURLE_OK; - int code; - - result = Curl_pp_readresp(sockfd, pp, &code, size); - -#if defined(HAVE_GSSAPI) - /* handle the security-oriented responses 6xx ***/ - /* FIXME: some errorchecking perhaps... ***/ - switch(code) { - case 631: - code = Curl_sec_read_msg(conn, buf, PROT_SAFE); - break; - case 632: - code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE); - break; - case 633: - code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL); - break; - default: - /* normal ftp stuff we pass through! */ - break; - } -#endif - - /* store the latest code for later retrieval */ - data->info.httpcode = code; - - if(ftpcode) - *ftpcode = code; - - if(421 == code) { - /* 421 means "Service not available, closing control connection." and FTP - * servers use it to signal that idle session timeout has been exceeded. - * If we ignored the response, it could end up hanging in some cases. - * - * This response code can come at any point so having it treated - * generically is a good idea. - */ - infof(data, "We got a 421 - timeout!\n"); - state(conn, FTP_STOP); - return CURLE_OPERATION_TIMEDOUT; - } - - return result; -} - -/* --- parse FTP server responses --- */ - -/* - * Curl_GetFTPResponse() is a BLOCKING function to read the full response - * from a server after a command. - * - */ - -CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ - struct connectdata *conn, - int *ftpcode) /* return the ftp-code */ -{ - /* - * We cannot read just one byte per read() and then go back to select() as - * the OpenSSL read() doesn't grok that properly. - * - * Alas, read as much as possible, split up into lines, use the ending - * line in a response or continue reading. */ - - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - time_t timeout; /* timeout in milliseconds */ - time_t interval_ms; - struct Curl_easy *data = conn->data; - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - size_t nread; - int cache_skip = 0; - int value_to_be_ignored = 0; - - if(ftpcode) - *ftpcode = 0; /* 0 for errors */ - else - /* make the pointer point to something for the rest of this function */ - ftpcode = &value_to_be_ignored; - - *nreadp = 0; - - while(!*ftpcode && !result) { - /* check and reset timeout value every lap */ - timeout = Curl_pp_state_timeout(pp); - - if(timeout <= 0) { - failf(data, "FTP response timeout"); - return CURLE_OPERATION_TIMEDOUT; /* already too little time */ - } - - interval_ms = 1000; /* use 1 second timeout intervals */ - if(timeout < interval_ms) - interval_ms = timeout; - - /* - * Since this function is blocking, we need to wait here for input on the - * connection and only then we call the response reading function. We do - * timeout at least every second to make the timeout check run. - * - * A caution here is that the ftp_readresp() function has a cache that may - * contain pieces of a response from the previous invoke and we need to - * make sure we don't just wait for input while there is unhandled data in - * that cache. But also, if the cache is there, we call ftp_readresp() and - * the cache wasn't good enough to continue we must not just busy-loop - * around this function. - * - */ - - if(pp->cache && (cache_skip < 2)) { - /* - * There's a cache left since before. We then skipping the wait for - * socket action, unless this is the same cache like the previous round - * as then the cache was deemed not enough to act on and we then need to - * wait for more data anyway. - */ - } - else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) { - switch(SOCKET_READABLE(sockfd, interval_ms)) { - case -1: /* select() error, stop reading */ - failf(data, "FTP response aborted due to select/poll error: %d", - SOCKERRNO); - return CURLE_RECV_ERROR; - - case 0: /* timeout */ - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - continue; /* just continue in our loop for the timeout duration */ - - default: /* for clarity */ - break; - } - } - result = ftp_readresp(sockfd, pp, ftpcode, &nread); - if(result) - break; - - if(!nread && pp->cache) - /* bump cache skip counter as on repeated skips we must wait for more - data */ - cache_skip++; - else - /* when we got data or there is no cache left, we reset the cache skip - counter */ - cache_skip = 0; - - *nreadp += nread; - - } /* while there's buffer left and loop is requested */ - - pp->pending_resp = FALSE; - - return result; -} - -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ -static const char * const ftp_state_names[]={ - "STOP", - "WAIT220", - "AUTH", - "USER", - "PASS", - "ACCT", - "PBSZ", - "PROT", - "CCC", - "PWD", - "SYST", - "NAMEFMT", - "QUOTE", - "RETR_PREQUOTE", - "STOR_PREQUOTE", - "POSTQUOTE", - "CWD", - "MKD", - "MDTM", - "TYPE", - "LIST_TYPE", - "RETR_TYPE", - "STOR_TYPE", - "SIZE", - "RETR_SIZE", - "STOR_SIZE", - "REST", - "RETR_REST", - "PORT", - "PRET", - "PASV", - "LIST", - "RETR", - "STOR", - "QUIT" -}; -#endif - -/* This is the ONLY way to change FTP state! */ -static void _state(struct connectdata *conn, - ftpstate newstate -#ifdef DEBUGBUILD - , int lineno -#endif - ) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - -#if defined(DEBUGBUILD) - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) lineno; -#else - if(ftpc->state != newstate) - infof(conn->data, "FTP %p (line %d) state change from %s to %s\n", - (void *)ftpc, lineno, ftp_state_names[ftpc->state], - ftp_state_names[newstate]); -#endif -#endif - - ftpc->state = newstate; -} - -static CURLcode ftp_state_user(struct connectdata *conn) -{ - CURLcode result; - struct FTP *ftp = conn->data->req.protop; - /* send USER */ - PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:""); - - state(conn, FTP_USER); - conn->data->state.ftp_trying_alternative = FALSE; - - return CURLE_OK; -} - -static CURLcode ftp_state_pwd(struct connectdata *conn) -{ - CURLcode result; - - /* send PWD to discover our entry point */ - PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD"); - state(conn, FTP_PWD); - - return CURLE_OK; -} - -/* For the FTP "protocol connect" and "doing" phases only */ -static int ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); -} - -/* For the FTP "DO_MORE" phase only */ -static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(!numsocks) - return GETSOCK_BLANK; - - /* When in DO_MORE state, we could be either waiting for us to connect to a - * remote site, or we could wait for that site to connect to us. Or just - * handle ordinary commands. - */ - - if(FTP_STOP == ftpc->state) { - int bits = GETSOCK_READSOCK(0); - - /* if stopped and still in this state, then we're also waiting for a - connect on the secondary connection */ - socks[0] = conn->sock[FIRSTSOCKET]; - - if(!conn->data->set.ftp_use_port) { - int s; - int i; - /* PORT is used to tell the server to connect to us, and during that we - don't do happy eyeballs, but we do if we connect to the server */ - for(s = 1, i = 0; i<2; i++) { - if(conn->tempsock[i] != CURL_SOCKET_BAD) { - socks[s] = conn->tempsock[i]; - bits |= GETSOCK_WRITESOCK(s++); - } - } - } - else { - socks[1] = conn->sock[SECONDARYSOCKET]; - bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1); - } - - return bits; - } - return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); -} - -/* This is called after the FTP_QUOTE state is passed. - - ftp_state_cwd() sends the range of CWD commands to the server to change to - the correct directory. It may also need to send MKD commands to create - missing ones, if that option is enabled. -*/ -static CURLcode ftp_state_cwd(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(ftpc->cwddone) - /* already done and fine */ - result = ftp_state_mdtm(conn); - else { - ftpc->count2 = 0; /* count2 counts failed CWDs */ - - /* count3 is set to allow a MKD to fail once. In the case when first CWD - fails and then MKD fails (due to another session raced it to create the - dir) this then allows for a second try to CWD to it */ - ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0; - - if((conn->data->set.ftp_filemethod == FTPFILE_NOCWD) && !ftpc->cwdcount) - /* No CWD necessary */ - result = ftp_state_mdtm(conn); - else if(conn->bits.reuse && ftpc->entrypath) { - /* This is a re-used connection. Since we change directory to where the - transfer is taking place, we must first get back to the original dir - where we ended up after login: */ - ftpc->cwdcount = 0; /* we count this as the first path, then we add one - for all upcoming ones in the ftp->dirs[] array */ - PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath); - state(conn, FTP_CWD); - } - else { - if(ftpc->dirdepth) { - ftpc->cwdcount = 1; - /* issue the first CWD, the rest is sent when the CWD responses are - received... */ - PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]); - state(conn, FTP_CWD); - } - else { - /* No CWD necessary */ - result = ftp_state_mdtm(conn); - } - } - } - return result; -} - -typedef enum { - EPRT, - PORT, - DONE -} ftpport; - -static CURLcode ftp_state_use_port(struct connectdata *conn, - ftpport fcmd) /* start with this */ - -{ - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct Curl_easy *data = conn->data; - curl_socket_t portsock = CURL_SOCKET_BAD; - char myhost[256] = ""; - - struct Curl_sockaddr_storage ss; - Curl_addrinfo *res, *ai; - curl_socklen_t sslen; - char hbuf[NI_MAXHOST]; - struct sockaddr *sa = (struct sockaddr *)&ss; - struct sockaddr_in * const sa4 = (void *)sa; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 * const sa6 = (void *)sa; -#endif - char tmp[1024]; - static const char mode[][5] = { "EPRT", "PORT" }; - int rc; - int error; - char *host = NULL; - char *string_ftpport = data->set.str[STRING_FTPPORT]; - struct Curl_dns_entry *h = NULL; - unsigned short port_min = 0; - unsigned short port_max = 0; - unsigned short port; - bool possibly_non_local = TRUE; - - char *addr = NULL; - - /* Step 1, figure out what is requested, - * accepted format : - * (ipv4|ipv6|domain|interface)?(:port(-range)?)? - */ - - if(data->set.str[STRING_FTPPORT] && - (strlen(data->set.str[STRING_FTPPORT]) > 1)) { - -#ifdef ENABLE_IPV6 - size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ? - INET6_ADDRSTRLEN : strlen(string_ftpport); -#else - size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ? - INET_ADDRSTRLEN : strlen(string_ftpport); -#endif - char *ip_start = string_ftpport; - char *ip_end = NULL; - char *port_start = NULL; - char *port_sep = NULL; - - addr = calloc(addrlen + 1, 1); - if(!addr) - return CURLE_OUT_OF_MEMORY; - -#ifdef ENABLE_IPV6 - if(*string_ftpport == '[') { - /* [ipv6]:port(-range) */ - ip_start = string_ftpport + 1; - ip_end = strchr(string_ftpport, ']'); - if(ip_end) - strncpy(addr, ip_start, ip_end - ip_start); - } - else -#endif - if(*string_ftpport == ':') { - /* :port */ - ip_end = string_ftpport; - } - else { - ip_end = strchr(string_ftpport, ':'); - if(ip_end) { - /* either ipv6 or (ipv4|domain|interface):port(-range) */ -#ifdef ENABLE_IPV6 - if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) { - /* ipv6 */ - port_min = port_max = 0; - strcpy(addr, string_ftpport); - ip_end = NULL; /* this got no port ! */ - } - else -#endif - /* (ipv4|domain|interface):port(-range) */ - strncpy(addr, string_ftpport, ip_end - ip_start); - } - else - /* ipv4|interface */ - strcpy(addr, string_ftpport); - } - - /* parse the port */ - if(ip_end != NULL) { - port_start = strchr(ip_end, ':'); - if(port_start) { - port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10)); - port_sep = strchr(port_start, '-'); - if(port_sep) { - port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10)); - } - else - port_max = port_min; - } - } - - /* correct errors like: - * :1234-1230 - * :-4711, in this case port_min is (unsigned)-1, - * therefore port_min > port_max for all cases - * but port_max = (unsigned)-1 - */ - if(port_min > port_max) - port_min = port_max = 0; - - - if(*addr != '\0') { - /* attempt to get the address of the given interface name */ - switch(Curl_if2ip(conn->ip_addr->ai_family, - Curl_ipv6_scope(conn->ip_addr->ai_addr), - conn->scope_id, addr, hbuf, sizeof(hbuf))) { - case IF2IP_NOT_FOUND: - /* not an interface, use the given string as host name instead */ - host = addr; - break; - case IF2IP_AF_NOT_SUPPORTED: - return CURLE_FTP_PORT_FAILED; - case IF2IP_FOUND: - host = hbuf; /* use the hbuf for host name */ - } - } - else - /* there was only a port(-range) given, default the host */ - host = NULL; - } /* data->set.ftpport */ - - if(!host) { - /* not an interface and not a host name, get default by extracting - the IP from the control connection */ - - sslen = sizeof(ss); - if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(conn, SOCKERRNO) ); - free(addr); - return CURLE_FTP_PORT_FAILED; - } - switch(sa->sa_family) { -#ifdef ENABLE_IPV6 - case AF_INET6: - Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); - break; -#endif - default: - Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); - break; - } - host = hbuf; /* use this host name */ - possibly_non_local = FALSE; /* we know it is local now */ - } - - /* resolv ip/host to ip */ - rc = Curl_resolv(conn, host, 0, &h); - if(rc == CURLRESOLV_PENDING) - (void)Curl_resolver_wait_resolv(conn, &h); - if(h) { - res = h->addr; - /* when we return from this function, we can forget about this entry - to we can unlock it now already */ - Curl_resolv_unlock(data, h); - } /* (h) */ - else - res = NULL; /* failure! */ - - if(res == NULL) { - failf(data, "failed to resolve the address provided to PORT: %s", host); - free(addr); - return CURLE_FTP_PORT_FAILED; - } - - free(addr); - host = NULL; - - /* step 2, create a socket for the requested address */ - - portsock = CURL_SOCKET_BAD; - error = 0; - for(ai = res; ai; ai = ai->ai_next) { - result = Curl_socket(conn, ai, NULL, &portsock); - if(result) { - error = SOCKERRNO; - continue; - } - break; - } - if(!ai) { - failf(data, "socket failure: %s", Curl_strerror(conn, error)); - return CURLE_FTP_PORT_FAILED; - } - - /* step 3, bind to a suitable local address */ - - memcpy(sa, ai->ai_addr, ai->ai_addrlen); - sslen = ai->ai_addrlen; - - for(port = port_min; port <= port_max;) { - if(sa->sa_family == AF_INET) - sa4->sin_port = htons(port); -#ifdef ENABLE_IPV6 - else - sa6->sin6_port = htons(port); -#endif - /* Try binding the given address. */ - if(bind(portsock, sa, sslen) ) { - /* It failed. */ - error = SOCKERRNO; - if(possibly_non_local && (error == EADDRNOTAVAIL)) { - /* The requested bind address is not local. Use the address used for - * the control connection instead and restart the port loop - */ - - infof(data, "bind(port=%hu) on non-local address failed: %s\n", port, - Curl_strerror(conn, error) ); - - sslen = sizeof(ss); - if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(conn, SOCKERRNO) ); - Curl_closesocket(conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - port = port_min; - possibly_non_local = FALSE; /* don't try this again */ - continue; - } - if(error != EADDRINUSE && error != EACCES) { - failf(data, "bind(port=%hu) failed: %s", port, - Curl_strerror(conn, error) ); - Curl_closesocket(conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - } - else - break; - - port++; - } - - /* maybe all ports were in use already*/ - if(port > port_max) { - failf(data, "bind() failed, we ran out of ports!"); - Curl_closesocket(conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* get the name again after the bind() so that we can extract the - port number it uses now */ - sslen = sizeof(ss); - if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(conn, SOCKERRNO) ); - Curl_closesocket(conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* step 4, listen on the socket */ - - if(listen(portsock, 1)) { - failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO)); - Curl_closesocket(conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* step 5, send the proper FTP command */ - - /* get a plain printable version of the numerical address to work with - below */ - Curl_printable_address(ai, myhost, sizeof(myhost)); - -#ifdef ENABLE_IPV6 - if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) - /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the - request and enable EPRT again! */ - conn->bits.ftp_use_eprt = TRUE; -#endif - - for(; fcmd != DONE; fcmd++) { - - if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) - /* if disabled, goto next */ - continue; - - if((PORT == fcmd) && sa->sa_family != AF_INET) - /* PORT is IPv4 only */ - continue; - - switch(sa->sa_family) { - case AF_INET: - port = ntohs(sa4->sin_port); - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - port = ntohs(sa6->sin6_port); - break; -#endif - default: - continue; /* might as well skip this */ - } - - if(EPRT == fcmd) { - /* - * Two fine examples from RFC2428; - * - * EPRT |1|132.235.1.2|6275| - * - * EPRT |2|1080::8:800:200C:417A|5282| - */ - - result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], - sa->sa_family == AF_INET?1:2, - myhost, port); - if(result) { - failf(data, "Failure sending EPRT command: %s", - curl_easy_strerror(result)); - Curl_closesocket(conn, portsock); - /* don't retry using PORT */ - ftpc->count1 = PORT; - /* bail out */ - state(conn, FTP_STOP); - return result; - } - break; - } - if(PORT == fcmd) { - char *source = myhost; - char *dest = tmp; - - /* translate x.x.x.x to x,x,x,x */ - while(source && *source) { - if(*source == '.') - *dest = ','; - else - *dest = *source; - dest++; - source++; - } - *dest = 0; - snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); - - result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp); - if(result) { - failf(data, "Failure sending PORT command: %s", - curl_easy_strerror(result)); - Curl_closesocket(conn, portsock); - /* bail out */ - state(conn, FTP_STOP); - return result; - } - break; - } - } - - /* store which command was sent */ - ftpc->count1 = fcmd; - - close_secondarysocket(conn); - - /* we set the secondary socket variable to this for now, it is only so that - the cleanup function will close it in case we fail before the true - secondary stuff is made */ - conn->sock[SECONDARYSOCKET] = portsock; - - /* this tcpconnect assignment below is a hackish work-around to make the - multi interface with active FTP work - as it will not wait for a - (passive) connect in Curl_is_connected(). - - The *proper* fix is to make sure that the active connection from the - server is done in a non-blocking way. Currently, it is still BLOCKING. - */ - conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; - - state(conn, FTP_PORT); - return result; -} - -static CURLcode ftp_state_use_pasv(struct connectdata *conn) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = CURLE_OK; - /* - Here's the excecutive summary on what to do: - - PASV is RFC959, expect: - 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) - - LPSV is RFC1639, expect: - 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2) - - EPSV is RFC2428, expect: - 229 Entering Extended Passive Mode (|||port|) - - */ - - static const char mode[][5] = { "EPSV", "PASV" }; - int modeoff; - -#ifdef PF_INET6 - if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) - /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the - request and enable EPSV again! */ - conn->bits.ftp_use_epsv = TRUE; -#endif - - modeoff = conn->bits.ftp_use_epsv?0:1; - - PPSENDF(&ftpc->pp, "%s", mode[modeoff]); - - ftpc->count1 = modeoff; - state(conn, FTP_PASV); - infof(conn->data, "Connect data stream passively\n"); - - return result; -} - -/* - * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc. - * - * REST is the last command in the chain of commands when a "head"-like - * request is made. Thus, if an actual transfer is to be made this is where we - * take off for real. - */ -static CURLcode ftp_state_prepare_transfer(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->req.protop; - struct Curl_easy *data = conn->data; - - if(ftp->transfer != FTPTRANSFER_BODY) { - /* doesn't transfer any data */ - - /* still possibly do PRE QUOTE jobs */ - state(conn, FTP_RETR_PREQUOTE); - result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); - } - else if(data->set.ftp_use_port) { - /* We have chosen to use the PORT (or similar) command */ - result = ftp_state_use_port(conn, EPRT); - } - else { - /* We have chosen (this is default) to use the PASV (or similar) command */ - if(data->set.ftp_use_pret) { - /* The user has requested that we send a PRET command - to prepare the server for the upcoming PASV */ - if(!conn->proto.ftpc.file) { - PPSENDF(&conn->proto.ftpc.pp, "PRET %s", - data->set.str[STRING_CUSTOMREQUEST]? - data->set.str[STRING_CUSTOMREQUEST]: - (data->set.ftp_list_only?"NLST":"LIST")); - } - else if(data->set.upload) { - PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file); - } - else { - PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file); - } - state(conn, FTP_PRET); - } - else { - result = ftp_state_use_pasv(conn); - } - } - return result; -} - -static CURLcode ftp_state_rest(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) { - /* if a "head"-like request is being made (on a file) */ - - /* Determine if server can respond to REST command and therefore - whether it supports range */ - PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0); - - state(conn, FTP_REST); - } - else - result = ftp_state_prepare_transfer(conn); - - return result; -} - -static CURLcode ftp_state_size(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) { - /* if a "head"-like request is being made (on a file) */ - - /* we know ftpc->file is a valid pointer to a file name */ - PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); - - state(conn, FTP_SIZE); - } - else - result = ftp_state_rest(conn); - - return result; -} - -static CURLcode ftp_state_list(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - /* If this output is to be machine-parsed, the NLST command might be better - to use, since the LIST command output is not specified or standard in any - way. It has turned out that the NLST list output is not the same on all - servers either... */ - - /* - if FTPFILE_NOCWD was specified, we are currently in - the user's home directory, so we should add the path - as argument for the LIST / NLST / or custom command. - Whether the server will support this, is uncertain. - - The other ftp_filemethods will CWD into dir/dir/ first and - then just do LIST (in that case: nothing to do here) - */ - char *cmd, *lstArg, *slashPos; - - lstArg = NULL; - if((data->set.ftp_filemethod == FTPFILE_NOCWD) && - data->state.path && - data->state.path[0] && - strchr(data->state.path, '/')) { - - lstArg = strdup(data->state.path); - if(!lstArg) - return CURLE_OUT_OF_MEMORY; - - /* Check if path does not end with /, as then we cut off the file part */ - if(lstArg[strlen(lstArg) - 1] != '/') { - - /* chop off the file part if format is dir/dir/file */ - slashPos = strrchr(lstArg, '/'); - if(slashPos) - *(slashPos + 1) = '\0'; - } - } - - cmd = aprintf("%s%s%s", - data->set.str[STRING_CUSTOMREQUEST]? - data->set.str[STRING_CUSTOMREQUEST]: - (data->set.ftp_list_only?"NLST":"LIST"), - lstArg? " ": "", - lstArg? lstArg: ""); - - if(!cmd) { - free(lstArg); - return CURLE_OUT_OF_MEMORY; - } - - result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd); - - free(lstArg); - free(cmd); - - if(result) - return result; - - state(conn, FTP_LIST); - - return result; -} - -static CURLcode ftp_state_retr_prequote(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* We've sent the TYPE, now we must send the list of prequote strings */ - - result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); - - return result; -} - -static CURLcode ftp_state_stor_prequote(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* We've sent the TYPE, now we must send the list of prequote strings */ - - result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE); - - return result; -} - -static CURLcode ftp_state_type(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->req.protop; - struct Curl_easy *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - /* If we have selected NOBODY and HEADER, it means that we only want file - information. Which in FTP can't be much more than the file size and - date. */ - if(data->set.opt_no_body && ftpc->file && - ftp_need_type(conn, data->set.prefer_ascii)) { - /* The SIZE command is _not_ RFC 959 specified, and therefor many servers - may not support it! It is however the only way we have to get a file's - size! */ - - ftp->transfer = FTPTRANSFER_INFO; - /* this means no actual transfer will be made */ - - /* Some servers return different sizes for different modes, and thus we - must set the proper type before we check the size */ - result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE); - if(result) - return result; - } - else - result = ftp_state_size(conn); - - return result; -} - -/* This is called after the CWD commands have been done in the beginning of - the DO phase */ -static CURLcode ftp_state_mdtm(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - /* Requested time of file or time-depended transfer? */ - if((data->set.get_filetime || data->set.timecondition) && ftpc->file) { - - /* we have requested to get the modified-time of the file, this is a white - spot as the MDTM is not mentioned in RFC959 */ - PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file); - - state(conn, FTP_MDTM); - } - else - result = ftp_state_type(conn); - - return result; -} - - -/* This is called after the TYPE and possible quote commands have been sent */ -static CURLcode ftp_state_ul_setup(struct connectdata *conn, - bool sizechecked) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->req.protop; - struct Curl_easy *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - int seekerr = CURL_SEEKFUNC_OK; - - if((data->state.resume_from && !sizechecked) || - ((data->state.resume_from > 0) && sizechecked)) { - /* we're about to continue the uploading of a file */ - /* 1. get already existing file's size. We use the SIZE command for this - which may not exist in the server! The SIZE command is not in - RFC959. */ - - /* 2. This used to set REST. But since we can do append, we - don't another ftp command. We just skip the source file - offset and then we APPEND the rest on the file instead */ - - /* 3. pass file-size number of bytes in the source file */ - /* 4. lower the infilesize counter */ - /* => transfer as usual */ - - if(data->state.resume_from < 0) { - /* Got no given size to start from, figure it out */ - PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); - state(conn, FTP_STOR_SIZE); - return result; - } - - /* enable append */ - data->set.ftp_append = TRUE; - - /* Let's read off the proper amount of bytes from the input. */ - if(conn->seek_func) { - seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, - SEEK_SET); - } - - if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed = 0; - if(seekerr != CURL_SEEKFUNC_CANTSEEK) { - failf(data, "Could not seek stream"); - return CURLE_FTP_COULDNT_USE_REST; - } - /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ - do { - size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : - curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, readthisamountnow, - data->state.in); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Failed to read data"); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed < data->state.resume_from); - } - /* now, decrease the size of the read */ - if(data->state.infilesize>0) { - data->state.infilesize -= data->state.resume_from; - - if(data->state.infilesize <= 0) { - infof(data, "File already completely uploaded\n"); - - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - /* Set ->transfer so that we won't get any error in - * ftp_done() because we didn't transfer anything! */ - ftp->transfer = FTPTRANSFER_NONE; - - state(conn, FTP_STOP); - return CURLE_OK; - } - } - /* we've passed, proceed as normal */ - } /* resume_from */ - - PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s", - ftpc->file); - - state(conn, FTP_STOR); - - return result; -} - -static CURLcode ftp_state_quote(struct connectdata *conn, - bool init, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct FTP *ftp = data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - bool quote = FALSE; - struct curl_slist *item; - - switch(instate) { - case FTP_QUOTE: - default: - item = data->set.quote; - break; - case FTP_RETR_PREQUOTE: - case FTP_STOR_PREQUOTE: - item = data->set.prequote; - break; - case FTP_POSTQUOTE: - item = data->set.postquote; - break; - } - - /* - * This state uses: - * 'count1' to iterate over the commands to send - * 'count2' to store whether to allow commands to fail - */ - - if(init) - ftpc->count1 = 0; - else - ftpc->count1++; - - if(item) { - int i = 0; - - /* Skip count1 items in the linked list */ - while((i< ftpc->count1) && item) { - item = item->next; - i++; - } - if(item) { - char *cmd = item->data; - if(cmd[0] == '*') { - cmd++; - ftpc->count2 = 1; /* the sent command is allowed to fail */ - } - else - ftpc->count2 = 0; /* failure means cancel operation */ - - PPSENDF(&ftpc->pp, "%s", cmd); - state(conn, instate); - quote = TRUE; - } - } - - if(!quote) { - /* No more quote to send, continue to ... */ - switch(instate) { - case FTP_QUOTE: - default: - result = ftp_state_cwd(conn); - break; - case FTP_RETR_PREQUOTE: - if(ftp->transfer != FTPTRANSFER_BODY) - state(conn, FTP_STOP); - else { - if(ftpc->known_filesize != -1) { - Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); - result = ftp_state_retr(conn, ftpc->known_filesize); - } - else { - if(data->set.ignorecl) { - /* This code is to support download of growing files. It prevents - the state machine from requesting the file size from the - server. With an unknown file size the download continues until - the server terminates it, otherwise the client stops if the - received byte count exceeds the reported file size. Set option - CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/ - PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); - state(conn, FTP_RETR); - } - else { - PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); - state(conn, FTP_RETR_SIZE); - } - } - } - break; - case FTP_STOR_PREQUOTE: - result = ftp_state_ul_setup(conn, FALSE); - break; - case FTP_POSTQUOTE: - break; - } - } - - return result; -} - -/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV - problems */ -static CURLcode ftp_epsv_disable(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - if(conn->bits.ipv6) { - /* We can't disable EPSV when doing IPv6, so this is instead a fail */ - failf(conn->data, "Failed EPSV attempt, exiting\n"); - return CURLE_WEIRD_SERVER_REPLY; - } - - infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); - /* disable it for next transfer */ - conn->bits.ftp_use_epsv = FALSE; - conn->data->state.errorbuf = FALSE; /* allow error message to get - rewritten */ - PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV"); - conn->proto.ftpc.count1++; - /* remain in/go to the FTP_PASV state */ - state(conn, FTP_PASV); - return result; -} - - -static char *control_address(struct connectdata *conn) -{ - /* Returns the control connection IP address. - If a proxy tunnel is used, returns the original host name instead, because - the effective control connection address is the proxy address, - not the ftp host. */ - if(conn->bits.tunnel_proxy || conn->bits.socksproxy) - return conn->host.name; - - return conn->ip_addr_str; -} - -static CURLcode ftp_state_pasv_resp(struct connectdata *conn, - int ftpcode) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result; - struct Curl_easy *data = conn->data; - struct Curl_dns_entry *addr = NULL; - int rc; - unsigned short connectport; /* the local port connect() should use! */ - char *str = &data->state.buffer[4]; /* start on the first letter */ - - /* if we come here again, make sure the former name is cleared */ - Curl_safefree(ftpc->newhost); - - if((ftpc->count1 == 0) && - (ftpcode == 229)) { - /* positive EPSV response */ - char *ptr = strchr(str, '('); - if(ptr) { - unsigned int num; - char separator[4]; - ptr++; - if(5 == sscanf(ptr, "%c%c%c%u%c", - &separator[0], - &separator[1], - &separator[2], - &num, - &separator[3])) { - const char sep1 = separator[0]; - int i; - - /* The four separators should be identical, or else this is an oddly - formatted reply and we bail out immediately. */ - for(i = 1; i<4; i++) { - if(separator[i] != sep1) { - ptr = NULL; /* set to NULL to signal error */ - break; - } - } - if(num > 0xffff) { - failf(data, "Illegal port number in EPSV reply"); - return CURLE_FTP_WEIRD_PASV_REPLY; - } - if(ptr) { - ftpc->newport = (unsigned short)(num & 0xffff); - ftpc->newhost = strdup(control_address(conn)); - if(!ftpc->newhost) - return CURLE_OUT_OF_MEMORY; - } - } - else - ptr = NULL; - } - if(!ptr) { - failf(data, "Weirdly formatted EPSV reply"); - return CURLE_FTP_WEIRD_PASV_REPLY; - } - } - else if((ftpc->count1 == 1) && - (ftpcode == 227)) { - /* positive PASV response */ - int ip[4]; - int port[2]; - - /* - * Scan for a sequence of six comma-separated numbers and use them as - * IP+port indicators. - * - * Found reply-strings include: - * "227 Entering Passive Mode (127,0,0,1,4,51)" - * "227 Data transfer will passively listen to 127,0,0,1,4,51" - * "227 Entering passive mode. 127,0,0,1,4,51" - */ - while(*str) { - if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d", - &ip[0], &ip[1], &ip[2], &ip[3], - &port[0], &port[1])) - break; - str++; - } - - if(!*str) { - failf(data, "Couldn't interpret the 227-response"); - return CURLE_FTP_WEIRD_227_FORMAT; - } - - /* we got OK from server */ - if(data->set.ftp_skip_ip) { - /* told to ignore the remotely given IP but instead use the host we used - for the control connection */ - infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n", - ip[0], ip[1], ip[2], ip[3], - conn->host.name); - ftpc->newhost = strdup(control_address(conn)); - } - else - ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); - - if(!ftpc->newhost) - return CURLE_OUT_OF_MEMORY; - - ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); - } - else if(ftpc->count1 == 0) { - /* EPSV failed, move on to PASV */ - return ftp_epsv_disable(conn); - } - else { - failf(data, "Bad PASV/EPSV response: %03d", ftpcode); - return CURLE_FTP_WEIRD_PASV_REPLY; - } - - if(conn->bits.proxy) { - /* - * This connection uses a proxy and we need to connect to the proxy again - * here. We don't want to rely on a former host lookup that might've - * expired now, instead we remake the lookup here and now! - */ - const char * const host_name = conn->bits.socksproxy ? - conn->socks_proxy.host.name : conn->http_proxy.host.name; - rc = Curl_resolv(conn, host_name, (int)conn->port, &addr); - if(rc == CURLRESOLV_PENDING) - /* BLOCKING, ignores the return code but 'addr' will be NULL in - case of failure */ - (void)Curl_resolver_wait_resolv(conn, &addr); - - connectport = - (unsigned short)conn->port; /* we connect to the proxy's port */ - - if(!addr) { - failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport); - return CURLE_COULDNT_RESOLVE_PROXY; - } - } - else { - /* normal, direct, ftp connection */ - rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr); - if(rc == CURLRESOLV_PENDING) - /* BLOCKING */ - (void)Curl_resolver_wait_resolv(conn, &addr); - - connectport = ftpc->newport; /* we connect to the remote port */ - - if(!addr) { - failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport); - return CURLE_FTP_CANT_GET_HOST; - } - } - - conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; - result = Curl_connecthost(conn, addr); - - if(result) { - Curl_resolv_unlock(data, addr); /* we're done using this address */ - if(ftpc->count1 == 0 && ftpcode == 229) - return ftp_epsv_disable(conn); - - return result; - } - - - /* - * When this is used from the multi interface, this might've returned with - * the 'connected' set to FALSE and thus we are now awaiting a non-blocking - * connect to connect. - */ - - if(data->set.verbose) - /* this just dumps information about this second connection */ - ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport); - - Curl_resolv_unlock(data, addr); /* we're done using this address */ - - Curl_safefree(conn->secondaryhostname); - conn->secondary_port = ftpc->newport; - conn->secondaryhostname = strdup(ftpc->newhost); - if(!conn->secondaryhostname) - return CURLE_OUT_OF_MEMORY; - - conn->bits.do_more = TRUE; - state(conn, FTP_STOP); /* this phase is completed */ - - return result; -} - -static CURLcode ftp_state_port_resp(struct connectdata *conn, - int ftpcode) -{ - struct Curl_easy *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - ftpport fcmd = (ftpport)ftpc->count1; - CURLcode result = CURLE_OK; - - /* The FTP spec tells a positive response should have code 200. - Be more permissive here to tolerate deviant servers. */ - if(ftpcode / 100 != 2) { - /* the command failed */ - - if(EPRT == fcmd) { - infof(data, "disabling EPRT usage\n"); - conn->bits.ftp_use_eprt = FALSE; - } - fcmd++; - - if(fcmd == DONE) { - failf(data, "Failed to do PORT"); - result = CURLE_FTP_PORT_FAILED; - } - else - /* try next */ - result = ftp_state_use_port(conn, fcmd); - } - else { - infof(data, "Connect data stream actively\n"); - state(conn, FTP_STOP); /* end of DO phase */ - result = ftp_dophase_done(conn, FALSE); - } - - return result; -} - -static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, - int ftpcode) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct FTP *ftp = data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - switch(ftpcode) { - case 213: - { - /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the - last .sss part is optional and means fractions of a second */ - int year, month, day, hour, minute, second; - if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d", - &year, &month, &day, &hour, &minute, &second)) { - /* we have a time, reformat it */ - char timebuf[24]; - time_t secs = time(NULL); - - snprintf(timebuf, sizeof(timebuf), - "%04d%02d%02d %02d:%02d:%02d GMT", - year, month, day, hour, minute, second); - /* now, convert this into a time() value: */ - data->info.filetime = (long)curl_getdate(timebuf, &secs); - } - -#ifdef CURL_FTP_HTTPSTYLE_HEAD - /* If we asked for a time of the file and we actually got one as well, - we "emulate" a HTTP-style header in our output. */ - - if(data->set.opt_no_body && - ftpc->file && - data->set.get_filetime && - (data->info.filetime >= 0) ) { - char headerbuf[128]; - time_t filetime = (time_t)data->info.filetime; - struct tm buffer; - const struct tm *tm = &buffer; - - result = Curl_gmtime(filetime, &buffer); - if(result) - return result; - - /* format: "Tue, 15 Nov 1994 12:45:26" */ - snprintf(headerbuf, sizeof(headerbuf), - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0); - if(result) - return result; - } /* end of a ridiculous amount of conditionals */ -#endif - } - break; - default: - infof(data, "unsupported MDTM reply format\n"); - break; - case 550: /* "No such file or directory" */ - failf(data, "Given file does not exist"); - result = CURLE_FTP_COULDNT_RETR_FILE; - break; - } - - if(data->set.timecondition) { - if((data->info.filetime > 0) && (data->set.timevalue > 0)) { - switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: - default: - if(data->info.filetime <= data->set.timevalue) { - infof(data, "The requested document is not new enough\n"); - ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */ - data->info.timecond = TRUE; - state(conn, FTP_STOP); - return CURLE_OK; - } - break; - case CURL_TIMECOND_IFUNMODSINCE: - if(data->info.filetime > data->set.timevalue) { - infof(data, "The requested document is not old enough\n"); - ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */ - data->info.timecond = TRUE; - state(conn, FTP_STOP); - return CURLE_OK; - } - break; - } /* switch */ - } - else { - infof(data, "Skipping time comparison\n"); - } - } - - if(!result) - result = ftp_state_type(conn); - - return result; -} - -static CURLcode ftp_state_type_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - if(ftpcode/100 != 2) { - /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a - successful 'TYPE I'. While that is not as RFC959 says, it is still a - positive response code and we allow that. */ - failf(data, "Couldn't set desired mode"); - return CURLE_FTP_COULDNT_SET_TYPE; - } - if(ftpcode != 200) - infof(data, "Got a %03d response code instead of the assumed 200\n", - ftpcode); - - if(instate == FTP_TYPE) - result = ftp_state_size(conn); - else if(instate == FTP_LIST_TYPE) - result = ftp_state_list(conn); - else if(instate == FTP_RETR_TYPE) - result = ftp_state_retr_prequote(conn); - else if(instate == FTP_STOR_TYPE) - result = ftp_state_stor_prequote(conn); - - return result; -} - -static CURLcode ftp_state_retr(struct connectdata *conn, - curl_off_t filesize) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct FTP *ftp = data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(data->set.max_filesize && (filesize > data->set.max_filesize)) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } - ftp->downloadsize = filesize; - - if(data->state.resume_from) { - /* We always (attempt to) get the size of downloads, so it is done before - this even when not doing resumes. */ - if(filesize == -1) { - infof(data, "ftp server doesn't support SIZE\n"); - /* We couldn't get the size and therefore we can't know if there really - is a part of the file left to get, although the server will just - close the connection when we start the connection so it won't cause - us any harm, just not make us exit as nicely. */ - } - else { - /* We got a file size report, so we check that there actually is a - part of the file left to get, or else we go home. */ - if(data->state.resume_from< 0) { - /* We're supposed to download the last abs(from) bytes */ - if(filesize < -data->state.resume_from) { - failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T - ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", - data->state.resume_from, filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - /* convert to size to download */ - ftp->downloadsize = -data->state.resume_from; - /* download from where? */ - data->state.resume_from = filesize - ftp->downloadsize; - } - else { - if(filesize < data->state.resume_from) { - failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T - ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", - data->state.resume_from, filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - /* Now store the number of bytes we are expected to download */ - ftp->downloadsize = filesize-data->state.resume_from; - } - } - - if(ftp->downloadsize == 0) { - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - infof(data, "File already completely downloaded\n"); - - /* Set ->transfer so that we won't get any error in ftp_done() - * because we didn't transfer the any file */ - ftp->transfer = FTPTRANSFER_NONE; - state(conn, FTP_STOP); - return CURLE_OK; - } - - /* Set resume file transfer offset */ - infof(data, "Instructs server to resume from offset %" - CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from); - - PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T, - data->state.resume_from); - - state(conn, FTP_RETR_REST); - } - else { - /* no resume */ - PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); - state(conn, FTP_RETR); - } - - return result; -} - -static CURLcode ftp_state_size_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - curl_off_t filesize = -1; - char *buf = data->state.buffer; - - /* get the size from the ascii string: */ - if(ftpcode == 213) - /* ignores parsing errors, which will make the size remain unknown */ - (void)curlx_strtoofft(buf + 4, NULL, 0, &filesize); - - if(instate == FTP_SIZE) { -#ifdef CURL_FTP_HTTPSTYLE_HEAD - if(-1 != filesize) { - char clbuf[128]; - snprintf(clbuf, sizeof(clbuf), - "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0); - if(result) - return result; - } -#endif - Curl_pgrsSetDownloadSize(data, filesize); - result = ftp_state_rest(conn); - } - else if(instate == FTP_RETR_SIZE) { - Curl_pgrsSetDownloadSize(data, filesize); - result = ftp_state_retr(conn, filesize); - } - else if(instate == FTP_STOR_SIZE) { - data->state.resume_from = filesize; - result = ftp_state_ul_setup(conn, TRUE); - } - - return result; -} - -static CURLcode ftp_state_rest_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - switch(instate) { - case FTP_REST: - default: -#ifdef CURL_FTP_HTTPSTYLE_HEAD - if(ftpcode == 350) { - char buffer[24]= { "Accept-ranges: bytes\r\n" }; - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0); - if(result) - return result; - } -#endif - result = ftp_state_prepare_transfer(conn); - break; - - case FTP_RETR_REST: - if(ftpcode != 350) { - failf(conn->data, "Couldn't use REST"); - result = CURLE_FTP_COULDNT_USE_REST; - } - else { - PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); - state(conn, FTP_RETR); - } - break; - } - - return result; -} - -static CURLcode ftp_state_stor_resp(struct connectdata *conn, - int ftpcode, ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - if(ftpcode >= 400) { - failf(data, "Failed FTP upload: %0d", ftpcode); - state(conn, FTP_STOP); - /* oops, we never close the sockets! */ - return CURLE_UPLOAD_FAILED; - } - - conn->proto.ftpc.state_saved = instate; - - /* PORT means we are now awaiting the server to connect to us. */ - if(data->set.ftp_use_port) { - bool connected; - - state(conn, FTP_STOP); /* no longer in STOR state */ - - result = AllowServerConnect(conn, &connected); - if(result) - return result; - - if(!connected) { - struct ftp_conn *ftpc = &conn->proto.ftpc; - infof(data, "Data conn was not available immediately\n"); - ftpc->wait_data_conn = TRUE; - } - - return CURLE_OK; - } - return InitiateTransfer(conn); -} - -/* for LIST and RETR responses */ -static CURLcode ftp_state_get_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct FTP *ftp = data->req.protop; - - if((ftpcode == 150) || (ftpcode == 125)) { - - /* - A; - 150 Opening BINARY mode data connection for /etc/passwd (2241 - bytes). (ok, the file is being transferred) - - B: - 150 Opening ASCII mode data connection for /bin/ls - - C: - 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). - - D: - 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes) - - E: - 125 Data connection already open; Transfer starting. */ - - curl_off_t size = -1; /* default unknown size */ - - - /* - * It appears that there are FTP-servers that return size 0 for files when - * SIZE is used on the file while being in BINARY mode. To work around - * that (stupid) behavior, we attempt to parse the RETR response even if - * the SIZE returned size zero. - * - * Debugging help from Salvatore Sorrentino on February 26, 2003. - */ - - if((instate != FTP_LIST) && - !data->set.prefer_ascii && - (ftp->downloadsize < 1)) { - /* - * It seems directory listings either don't show the size or very - * often uses size 0 anyway. ASCII transfers may very well turn out - * that the transferred amount of data is not the same as this line - * tells, why using this number in those cases only confuses us. - * - * Example D above makes this parsing a little tricky */ - char *bytes; - char *buf = data->state.buffer; - bytes = strstr(buf, " bytes"); - if(bytes--) { - long in = (long)(bytes-buf); - /* this is a hint there is size information in there! ;-) */ - while(--in) { - /* scan for the left parenthesis and break there */ - if('(' == *bytes) - break; - /* skip only digits */ - if(!ISDIGIT(*bytes)) { - bytes = NULL; - break; - } - /* one more estep backwards */ - bytes--; - } - /* if we have nothing but digits: */ - if(bytes++) { - /* get the number! */ - (void)curlx_strtoofft(bytes, NULL, 0, &size); - } - } - } - else if(ftp->downloadsize > -1) - size = ftp->downloadsize; - - if(size > data->req.maxdownload && data->req.maxdownload > 0) - size = data->req.size = data->req.maxdownload; - else if((instate != FTP_LIST) && (data->set.prefer_ascii)) - size = -1; /* kludge for servers that understate ASCII mode file size */ - - infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n", - data->req.maxdownload); - - if(instate != FTP_LIST) - infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n", - size); - - /* FTP download: */ - conn->proto.ftpc.state_saved = instate; - conn->proto.ftpc.retr_size_saved = size; - - if(data->set.ftp_use_port) { - bool connected; - - result = AllowServerConnect(conn, &connected); - if(result) - return result; - - if(!connected) { - struct ftp_conn *ftpc = &conn->proto.ftpc; - infof(data, "Data conn was not available immediately\n"); - state(conn, FTP_STOP); - ftpc->wait_data_conn = TRUE; - } - } - else - return InitiateTransfer(conn); - } - else { - if((instate == FTP_LIST) && (ftpcode == 450)) { - /* simply no matching files in the dir listing */ - ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */ - state(conn, FTP_STOP); /* this phase is over */ - } - else { - failf(data, "RETR response: %03d", ftpcode); - return instate == FTP_RETR && ftpcode == 550? - CURLE_REMOTE_FILE_NOT_FOUND: - CURLE_FTP_COULDNT_RETR_FILE; - } - } - - return result; -} - -/* after USER, PASS and ACCT */ -static CURLcode ftp_state_loggedin(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - if(conn->ssl[FIRSTSOCKET].use) { - /* PBSZ = PROTECTION BUFFER SIZE. - - The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: - - Specifically, the PROT command MUST be preceded by a PBSZ - command and a PBSZ command MUST be preceded by a successful - security data exchange (the TLS negotiation in this case) - - ... (and on page 8): - - Thus the PBSZ command must still be issued, but must have a - parameter of '0' to indicate that no buffering is taking place - and the data connection should not be encapsulated. - */ - PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0); - state(conn, FTP_PBSZ); - } - else { - result = ftp_state_pwd(conn); - } - return result; -} - -/* for USER and PASS responses */ -static CURLcode ftp_state_user_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct FTP *ftp = data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - (void)instate; /* no use for this yet */ - - /* some need password anyway, and others just return 2xx ignored */ - if((ftpcode == 331) && (ftpc->state == FTP_USER)) { - /* 331 Password required for ... - (the server requires to send the user's password too) */ - PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:""); - state(conn, FTP_PASS); - } - else if(ftpcode/100 == 2) { - /* 230 User ... logged in. - (the user logged in with or without password) */ - result = ftp_state_loggedin(conn); - } - else if(ftpcode == 332) { - if(data->set.str[STRING_FTP_ACCOUNT]) { - PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]); - state(conn, FTP_ACCT); - } - else { - failf(data, "ACCT requested but none available"); - result = CURLE_LOGIN_DENIED; - } - } - else { - /* All other response codes, like: - - 530 User ... access denied - (the server denies to log the specified user) */ - - if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && - !conn->data->state.ftp_trying_alternative) { - /* Ok, USER failed. Let's try the supplied command. */ - PPSENDF(&conn->proto.ftpc.pp, "%s", - conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); - conn->data->state.ftp_trying_alternative = TRUE; - state(conn, FTP_USER); - result = CURLE_OK; - } - else { - failf(data, "Access denied: %03d", ftpcode); - result = CURLE_LOGIN_DENIED; - } - } - return result; -} - -/* for ACCT response */ -static CURLcode ftp_state_acct_resp(struct connectdata *conn, - int ftpcode) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - if(ftpcode != 230) { - failf(data, "ACCT rejected by server: %03d", ftpcode); - result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ - } - else - result = ftp_state_loggedin(conn); - - return result; -} - - -static CURLcode ftp_statemach_act(struct connectdata *conn) -{ - CURLcode result; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct Curl_easy *data = conn->data; - int ftpcode; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - static const char ftpauth[][4] = { "SSL", "TLS" }; - size_t nread = 0; - - if(pp->sendleft) - return Curl_pp_flushsend(pp); - - result = ftp_readresp(sock, pp, &ftpcode, &nread); - if(result) - return result; - - if(ftpcode) { - /* we have now received a full FTP server response */ - switch(ftpc->state) { - case FTP_WAIT220: - if(ftpcode == 230) - /* 230 User logged in - already! */ - return ftp_state_user_resp(conn, ftpcode, ftpc->state); - else if(ftpcode != 220) { - failf(data, "Got a %03d ftp-server response when 220 was expected", - ftpcode); - return CURLE_WEIRD_SERVER_REPLY; - } - - /* We have received a 220 response fine, now we proceed. */ -#ifdef HAVE_GSSAPI - if(data->set.krb) { - /* If not anonymous login, try a secure login. Note that this - procedure is still BLOCKING. */ - - Curl_sec_request_prot(conn, "private"); - /* We set private first as default, in case the line below fails to - set a valid level */ - Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); - - if(Curl_sec_login(conn)) - infof(data, "Logging in with password in cleartext!\n"); - else - infof(data, "Authentication successful\n"); - } -#endif - - if(data->set.use_ssl && - (!conn->ssl[FIRSTSOCKET].use || - (conn->bits.proxy_ssl_connected[FIRSTSOCKET] && - !conn->proxy_ssl[FIRSTSOCKET].use))) { - /* We don't have a SSL/TLS connection yet, but FTPS is - requested. Try a FTPS connection now */ - - ftpc->count3 = 0; - switch(data->set.ftpsslauth) { - case CURLFTPAUTH_DEFAULT: - case CURLFTPAUTH_SSL: - ftpc->count2 = 1; /* add one to get next */ - ftpc->count1 = 0; - break; - case CURLFTPAUTH_TLS: - ftpc->count2 = -1; /* subtract one to get next */ - ftpc->count1 = 1; - break; - default: - failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", - (int)data->set.ftpsslauth); - return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ - } - PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); - state(conn, FTP_AUTH); - } - else { - result = ftp_state_user(conn); - if(result) - return result; - } - - break; - - case FTP_AUTH: - /* we have gotten the response to a previous AUTH command */ - - /* RFC2228 (page 5) says: - * - * If the server is willing to accept the named security mechanism, - * and does not require any security data, it must respond with - * reply code 234/334. - */ - - if((ftpcode == 234) || (ftpcode == 334)) { - /* Curl_ssl_connect is BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(!result) { - conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ - result = ftp_state_user(conn); - } - } - else if(ftpc->count3 < 1) { - ftpc->count3++; - ftpc->count1 += ftpc->count2; /* get next attempt */ - result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); - /* remain in this same state */ - } - else { - if(data->set.use_ssl > CURLUSESSL_TRY) - /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ - result = CURLE_USE_SSL_FAILED; - else - /* ignore the failure and continue */ - result = ftp_state_user(conn); - } - - if(result) - return result; - break; - - case FTP_USER: - case FTP_PASS: - result = ftp_state_user_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_ACCT: - result = ftp_state_acct_resp(conn, ftpcode); - break; - - case FTP_PBSZ: - PPSENDF(&ftpc->pp, "PROT %c", - data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); - state(conn, FTP_PROT); - - break; - - case FTP_PROT: - if(ftpcode/100 == 2) - /* We have enabled SSL for the data connection! */ - conn->bits.ftp_use_data_ssl = - (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; - /* FTP servers typically responds with 500 if they decide to reject - our 'P' request */ - else if(data->set.use_ssl > CURLUSESSL_CONTROL) - /* we failed and bails out */ - return CURLE_USE_SSL_FAILED; - - if(data->set.ftp_ccc) { - /* CCC - Clear Command Channel - */ - PPSENDF(&ftpc->pp, "%s", "CCC"); - state(conn, FTP_CCC); - } - else { - result = ftp_state_pwd(conn); - if(result) - return result; - } - break; - - case FTP_CCC: - if(ftpcode < 500) { - /* First shut down the SSL layer (note: this call will block) */ - result = Curl_ssl_shutdown(conn, FIRSTSOCKET); - - if(result) { - failf(conn->data, "Failed to clear the command channel (CCC)"); - return result; - } - } - - /* Then continue as normal */ - result = ftp_state_pwd(conn); - if(result) - return result; - break; - - case FTP_PWD: - if(ftpcode == 257) { - char *ptr = &data->state.buffer[4]; /* start on the first letter */ - const size_t buf_size = data->set.buffer_size; - char *dir; - char *store; - bool entry_extracted = FALSE; - - dir = malloc(nread + 1); - if(!dir) - return CURLE_OUT_OF_MEMORY; - - /* Reply format is like - 257[rubbish]"" and the - RFC959 says - - The directory name can contain any character; embedded - double-quotes should be escaped by double-quotes (the - "quote-doubling" convention). - */ - - /* scan for the first double-quote for non-standard responses */ - while(ptr < &data->state.buffer[buf_size] - && *ptr != '\n' && *ptr != '\0' && *ptr != '"') - ptr++; - - if('\"' == *ptr) { - /* it started good */ - ptr++; - for(store = dir; *ptr;) { - if('\"' == *ptr) { - if('\"' == ptr[1]) { - /* "quote-doubling" */ - *store = ptr[1]; - ptr++; - } - else { - /* end of path */ - entry_extracted = TRUE; - break; /* get out of this loop */ - } - } - else - *store = *ptr; - store++; - ptr++; - } - *store = '\0'; /* zero terminate */ - } - if(entry_extracted) { - /* If the path name does not look like an absolute path (i.e.: it - does not start with a '/'), we probably need some server-dependent - adjustments. For example, this is the case when connecting to - an OS400 FTP server: this server supports two name syntaxes, - the default one being incompatible with standard paths. In - addition, this server switches automatically to the regular path - syntax when one is encountered in a command: this results in - having an entrypath in the wrong syntax when later used in CWD. - The method used here is to check the server OS: we do it only - if the path name looks strange to minimize overhead on other - systems. */ - - if(!ftpc->server_os && dir[0] != '/') { - - result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST"); - if(result) { - free(dir); - return result; - } - Curl_safefree(ftpc->entrypath); - ftpc->entrypath = dir; /* remember this */ - infof(data, "Entry path is '%s'\n", ftpc->entrypath); - /* also save it where getinfo can access it: */ - data->state.most_recent_ftp_entrypath = ftpc->entrypath; - state(conn, FTP_SYST); - break; - } - - Curl_safefree(ftpc->entrypath); - ftpc->entrypath = dir; /* remember this */ - infof(data, "Entry path is '%s'\n", ftpc->entrypath); - /* also save it where getinfo can access it: */ - data->state.most_recent_ftp_entrypath = ftpc->entrypath; - } - else { - /* couldn't get the path */ - free(dir); - infof(data, "Failed to figure out path\n"); - } - } - state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ - DEBUGF(infof(data, "protocol connect phase DONE\n")); - break; - - case FTP_SYST: - if(ftpcode == 215) { - char *ptr = &data->state.buffer[4]; /* start on the first letter */ - char *os; - char *store; - - os = malloc(nread + 1); - if(!os) - return CURLE_OUT_OF_MEMORY; - - /* Reply format is like - 215 - */ - while(*ptr == ' ') - ptr++; - for(store = os; *ptr && *ptr != ' ';) - *store++ = *ptr++; - *store = '\0'; /* zero terminate */ - - /* Check for special servers here. */ - - if(strcasecompare(os, "OS/400")) { - /* Force OS400 name format 1. */ - result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); - if(result) { - free(os); - return result; - } - /* remember target server OS */ - Curl_safefree(ftpc->server_os); - ftpc->server_os = os; - state(conn, FTP_NAMEFMT); - break; - } - /* Nothing special for the target server. */ - /* remember target server OS */ - Curl_safefree(ftpc->server_os); - ftpc->server_os = os; - } - else { - /* Cannot identify server OS. Continue anyway and cross fingers. */ - } - - state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ - DEBUGF(infof(data, "protocol connect phase DONE\n")); - break; - - case FTP_NAMEFMT: - if(ftpcode == 250) { - /* Name format change successful: reload initial path. */ - ftp_state_pwd(conn); - break; - } - - state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ - DEBUGF(infof(data, "protocol connect phase DONE\n")); - break; - - case FTP_QUOTE: - case FTP_POSTQUOTE: - case FTP_RETR_PREQUOTE: - case FTP_STOR_PREQUOTE: - if((ftpcode >= 400) && !ftpc->count2) { - /* failure response code, and not allowed to fail */ - failf(conn->data, "QUOT command failed with %03d", ftpcode); - return CURLE_QUOTE_ERROR; - } - result = ftp_state_quote(conn, FALSE, ftpc->state); - if(result) - return result; - - break; - - case FTP_CWD: - if(ftpcode/100 != 2) { - /* failure to CWD there */ - if(conn->data->set.ftp_create_missing_dirs && - ftpc->cwdcount && !ftpc->count2) { - /* try making it */ - ftpc->count2++; /* counter to prevent CWD-MKD loops */ - PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]); - state(conn, FTP_MKD); - } - else { - /* return failure */ - failf(data, "Server denied you to change to the given directory"); - ftpc->cwdfail = TRUE; /* don't remember this path as we failed - to enter it */ - return CURLE_REMOTE_ACCESS_DENIED; - } - } - else { - /* success */ - ftpc->count2 = 0; - if(++ftpc->cwdcount <= ftpc->dirdepth) { - /* send next CWD */ - PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]); - } - else { - result = ftp_state_mdtm(conn); - if(result) - return result; - } - } - break; - - case FTP_MKD: - if((ftpcode/100 != 2) && !ftpc->count3--) { - /* failure to MKD the dir */ - failf(data, "Failed to MKD dir: %03d", ftpcode); - return CURLE_REMOTE_ACCESS_DENIED; - } - state(conn, FTP_CWD); - /* send CWD */ - PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]); - break; - - case FTP_MDTM: - result = ftp_state_mdtm_resp(conn, ftpcode); - break; - - case FTP_TYPE: - case FTP_LIST_TYPE: - case FTP_RETR_TYPE: - case FTP_STOR_TYPE: - result = ftp_state_type_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_SIZE: - case FTP_RETR_SIZE: - case FTP_STOR_SIZE: - result = ftp_state_size_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_REST: - case FTP_RETR_REST: - result = ftp_state_rest_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_PRET: - if(ftpcode != 200) { - /* there only is this one standard OK return code. */ - failf(data, "PRET command not accepted: %03d", ftpcode); - return CURLE_FTP_PRET_FAILED; - } - result = ftp_state_use_pasv(conn); - break; - - case FTP_PASV: - result = ftp_state_pasv_resp(conn, ftpcode); - break; - - case FTP_PORT: - result = ftp_state_port_resp(conn, ftpcode); - break; - - case FTP_LIST: - case FTP_RETR: - result = ftp_state_get_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_STOR: - result = ftp_state_stor_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_QUIT: - /* fallthrough, just stop! */ - default: - /* internal error */ - state(conn, FTP_STOP); - break; - } - } /* if(ftpcode) */ - - return result; -} - - -/* called repeatedly until done from multi.c */ -static CURLcode ftp_multi_statemach(struct connectdata *conn, - bool *done) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE); - - /* Check for the state outside of the Curl_socket_check() return code checks - since at times we are in fact already in this state when this function - gets called. */ - *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; - - return result; -} - -static CURLcode ftp_block_statemach(struct connectdata *conn) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - CURLcode result = CURLE_OK; - - while(ftpc->state != FTP_STOP) { - result = Curl_pp_statemach(pp, TRUE); - if(result) - break; - } - - return result; -} - -/* - * ftp_connect() should do everything that is to be considered a part of - * the connection phase. - * - * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE if not. - * - */ -static CURLcode ftp_connect(struct connectdata *conn, - bool *done) /* see description above */ -{ - CURLcode result; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - - *done = FALSE; /* default to not done yet */ - - /* We always support persistent connections on ftp */ - connkeep(conn, "FTP default"); - - pp->response_time = RESP_TIMEOUT; /* set default response time-out */ - pp->statemach_act = ftp_statemach_act; - pp->endofresp = ftp_endofresp; - pp->conn = conn; - - if(conn->handler->flags & PROTOPT_SSL) { - /* BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(result) - return result; - } - - Curl_pp_init(pp); /* init the generic pingpong data */ - - /* When we connect, we start in the state where we await the 220 - response */ - state(conn, FTP_WAIT220); - - result = ftp_multi_statemach(conn, done); - - return result; -} - -/*********************************************************************** - * - * ftp_done() - * - * The DONE function. This does what needs to be done after a single DO has - * performed. - * - * Input argument is already checked for validity. - */ -static CURLcode ftp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - struct Curl_easy *data = conn->data; - struct FTP *ftp = data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - ssize_t nread; - int ftpcode; - CURLcode result = CURLE_OK; - char *path = NULL; - const char *path_to_use = data->state.path; - - if(!ftp) - return CURLE_OK; - - switch(status) { - case CURLE_BAD_DOWNLOAD_RESUME: - case CURLE_FTP_WEIRD_PASV_REPLY: - case CURLE_FTP_PORT_FAILED: - case CURLE_FTP_ACCEPT_FAILED: - case CURLE_FTP_ACCEPT_TIMEOUT: - case CURLE_FTP_COULDNT_SET_TYPE: - case CURLE_FTP_COULDNT_RETR_FILE: - case CURLE_PARTIAL_FILE: - case CURLE_UPLOAD_FAILED: - case CURLE_REMOTE_ACCESS_DENIED: - case CURLE_FILESIZE_EXCEEDED: - case CURLE_REMOTE_FILE_NOT_FOUND: - case CURLE_WRITE_ERROR: - /* the connection stays alive fine even though this happened */ - /* fall-through */ - case CURLE_OK: /* doesn't affect the control connection's status */ - if(!premature) - break; - - /* until we cope better with prematurely ended requests, let them - * fallback as if in complete failure */ - /* FALLTHROUGH */ - default: /* by default, an error means the control connection is - wedged and should not be used anymore */ - ftpc->ctl_valid = FALSE; - ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the - current path, as this connection is going */ - connclose(conn, "FTP ended with bad error code"); - result = status; /* use the already set error code */ - break; - } - - /* now store a copy of the directory we are in */ - free(ftpc->prevpath); - - if(data->set.wildcardmatch) { - if(data->set.chunk_end && ftpc->file) { - data->set.chunk_end(data->wildcard.customptr); - } - ftpc->known_filesize = -1; - } - - if(!result) - /* get the "raw" path */ - result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE); - if(result) { - /* We can limp along anyway (and should try to since we may already be in - * the error path) */ - ftpc->ctl_valid = FALSE; /* mark control connection as bad */ - connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ - ftpc->prevpath = NULL; /* no path remembering */ - } - else { - size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */ - size_t dlen = strlen(path)-flen; - if(!ftpc->cwdfail) { - ftpc->prevmethod = data->set.ftp_filemethod; - if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) { - ftpc->prevpath = path; - if(flen) - /* if 'path' is not the whole string */ - ftpc->prevpath[dlen] = 0; /* terminate */ - } - else { - /* we never changed dir */ - ftpc->prevpath = strdup(""); - free(path); - } - if(ftpc->prevpath) - infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath); - } - else { - ftpc->prevpath = NULL; /* no path */ - free(path); - } - } - /* free the dir tree and file parts */ - freedirs(ftpc); - - /* shut down the socket to inform the server we're done */ - -#ifdef _WIN32_WCE - shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ -#endif - - if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { - if(!result && ftpc->dont_check && data->req.maxdownload > 0) { - /* partial download completed */ - result = Curl_pp_sendf(pp, "%s", "ABOR"); - if(result) { - failf(data, "Failure sending ABOR command: %s", - curl_easy_strerror(result)); - ftpc->ctl_valid = FALSE; /* mark control connection as bad */ - connclose(conn, "ABOR command failed"); /* connection closure */ - } - } - - if(conn->ssl[SECONDARYSOCKET].use) { - /* The secondary socket is using SSL so we must close down that part - first before we close the socket for real */ - Curl_ssl_close(conn, SECONDARYSOCKET); - - /* Note that we keep "use" set to TRUE since that (next) connection is - still requested to use SSL */ - } - close_secondarysocket(conn); - } - - if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid && - pp->pending_resp && !premature) { - /* - * Let's see what the server says about the transfer we just performed, - * but lower the timeout as sometimes this connection has died while the - * data has been transferred. This happens when doing through NATs etc that - * abandon old silent connections. - */ - long old_time = pp->response_time; - - pp->response_time = 60*1000; /* give it only a minute for now */ - pp->response = Curl_tvnow(); /* timeout relative now */ - - result = Curl_GetFTPResponse(&nread, conn, &ftpcode); - - pp->response_time = old_time; /* set this back to previous value */ - - if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { - failf(data, "control connection looks dead"); - ftpc->ctl_valid = FALSE; /* mark control connection as bad */ - connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */ - } - - if(result) - return result; - - if(ftpc->dont_check && data->req.maxdownload > 0) { - /* we have just sent ABOR and there is no reliable way to check if it was - * successful or not; we have to close the connection now */ - infof(data, "partial download completed, closing connection\n"); - connclose(conn, "Partial download with no ability to check"); - return result; - } - - if(!ftpc->dont_check) { - /* 226 Transfer complete, 250 Requested file action okay, completed. */ - if((ftpcode != 226) && (ftpcode != 250)) { - failf(data, "server did not report OK, got %d", ftpcode); - result = CURLE_PARTIAL_FILE; - } - } - } - - if(result || premature) - /* the response code from the transfer showed an error already so no - use checking further */ - ; - else if(data->set.upload) { - if((-1 != data->state.infilesize) && - (data->state.infilesize != *ftp->bytecountp) && - !data->set.crlf && - (ftp->transfer == FTPTRANSFER_BODY)) { - failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T - " out of %" CURL_FORMAT_CURL_OFF_T " bytes)", - *ftp->bytecountp, data->state.infilesize); - result = CURLE_PARTIAL_FILE; - } - } - else { - if((-1 != data->req.size) && - (data->req.size != *ftp->bytecountp) && -#ifdef CURL_DO_LINEEND_CONV - /* Most FTP servers don't adjust their file SIZE response for CRLFs, so - * we'll check to see if the discrepancy can be explained by the number - * of CRLFs we've changed to LFs. - */ - ((data->req.size + data->state.crlf_conversions) != - *ftp->bytecountp) && -#endif /* CURL_DO_LINEEND_CONV */ - (data->req.maxdownload != *ftp->bytecountp)) { - failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T - " bytes", *ftp->bytecountp); - result = CURLE_PARTIAL_FILE; - } - else if(!ftpc->dont_check && - !*ftp->bytecountp && - (data->req.size>0)) { - failf(data, "No data was received!"); - result = CURLE_FTP_COULDNT_RETR_FILE; - } - } - - /* clear these for next connection */ - ftp->transfer = FTPTRANSFER_BODY; - ftpc->dont_check = FALSE; - - /* Send any post-transfer QUOTE strings? */ - if(!status && !result && !premature && data->set.postquote) - result = ftp_sendquote(conn, data->set.postquote); - - return result; -} - -/*********************************************************************** - * - * ftp_sendquote() - * - * Where a 'quote' means a list of custom commands to send to the server. - * The quote list is passed as an argument. - * - * BLOCKING - */ - -static -CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) -{ - struct curl_slist *item; - ssize_t nread; - int ftpcode; - CURLcode result; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - - item = quote; - while(item) { - if(item->data) { - char *cmd = item->data; - bool acceptfail = FALSE; - - /* if a command starts with an asterisk, which a legal FTP command never - can, the command will be allowed to fail without it causing any - aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ - - if(cmd[0] == '*') { - cmd++; - acceptfail = TRUE; - } - - PPSENDF(&conn->proto.ftpc.pp, "%s", cmd); - - pp->response = Curl_tvnow(); /* timeout relative now */ - - result = Curl_GetFTPResponse(&nread, conn, &ftpcode); - if(result) - return result; - - if(!acceptfail && (ftpcode >= 400)) { - failf(conn->data, "QUOT string not accepted: %s", cmd); - return CURLE_QUOTE_ERROR; - } - } - - item = item->next; - } - - return CURLE_OK; -} - -/*********************************************************************** - * - * ftp_need_type() - * - * Returns TRUE if we in the current situation should send TYPE - */ -static int ftp_need_type(struct connectdata *conn, - bool ascii_wanted) -{ - return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I'); -} - -/*********************************************************************** - * - * ftp_nb_type() - * - * Set TYPE. We only deal with ASCII or BINARY so this function - * sets one of them. - * If the transfer type is not sent, simulate on OK response in newstate - */ -static CURLcode ftp_nb_type(struct connectdata *conn, - bool ascii, ftpstate newstate) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result; - char want = (char)(ascii?'A':'I'); - - if(ftpc->transfertype == want) { - state(conn, newstate); - return ftp_state_type_resp(conn, 200, newstate); - } - - PPSENDF(&ftpc->pp, "TYPE %c", want); - state(conn, newstate); - - /* keep track of our current transfer type */ - ftpc->transfertype = want; - return CURLE_OK; -} - -/*************************************************************************** - * - * ftp_pasv_verbose() - * - * This function only outputs some informationals about this second connection - * when we've issued a PASV command before and thus we have connected to a - * possibly new IP address. - * - */ -#ifndef CURL_DISABLE_VERBOSE_STRINGS -static void -ftp_pasv_verbose(struct connectdata *conn, - Curl_addrinfo *ai, - char *newhost, /* ascii version */ - int port) -{ - char buf[256]; - Curl_printable_address(ai, buf, sizeof(buf)); - infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port); -} -#endif - -/* - Check if this is a range download, and if so, set the internal variables - properly. - */ - -static CURLcode ftp_range(struct connectdata *conn) -{ - curl_off_t from, to; - char *ptr; - struct Curl_easy *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(data->state.use_range && data->state.range) { - CURLofft from_t; - CURLofft to_t; - from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); - if(from_t == CURL_OFFT_FLOW) - return CURLE_RANGE_ERROR; - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) - ptr++; - to_t = curlx_strtoofft(ptr, NULL, 0, &to); - if(to_t == CURL_OFFT_FLOW) - return CURLE_RANGE_ERROR; - if((to_t == CURL_OFFT_INVAL) && !from_t) { - /* X - */ - data->state.resume_from = from; - DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T - " to end of file\n", from)); - } - else if(!to_t && (from_t == CURL_OFFT_INVAL)) { - /* -Y */ - data->req.maxdownload = to; - data->state.resume_from = -to; - DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T - " bytes\n", to)); - } - else { - /* X-Y */ - data->req.maxdownload = (to - from) + 1; /* include last byte */ - data->state.resume_from = from; - DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T - " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", - from, data->req.maxdownload)); - } - DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T - " to %" CURL_FORMAT_CURL_OFF_T ", totally %" - CURL_FORMAT_CURL_OFF_T " bytes\n", - from, to, data->req.maxdownload)); - ftpc->dont_check = TRUE; /* don't check for successful transfer */ - } - else - data->req.maxdownload = -1; - return CURLE_OK; -} - - -/* - * ftp_do_more() - * - * This function shall be called when the second FTP (data) connection is - * connected. - * - * 'complete' can return 0 for incomplete, 1 for done and -1 for go back - * (which basically is only for when PASV is being sent to retry a failed - * EPSV). - */ - -static CURLcode ftp_do_more(struct connectdata *conn, int *completep) -{ - struct Curl_easy *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = CURLE_OK; - bool connected = FALSE; - bool complete = FALSE; - - /* the ftp struct is inited in ftp_connect() */ - struct FTP *ftp = data->req.protop; - - /* if the second connection isn't done yet, wait for it */ - if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { - if(Curl_connect_ongoing(conn)) { - /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port - aren't used so we blank their arguments. TODO: make this nicer */ - result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0); - - return result; - } - - result = Curl_is_connected(conn, SECONDARYSOCKET, &connected); - - /* Ready to do more? */ - if(connected) { - DEBUGF(infof(data, "DO-MORE connected phase starts\n")); - } - else { - if(result && (ftpc->count1 == 0)) { - *completep = -1; /* go back to DOING please */ - /* this is a EPSV connect failing, try PASV instead */ - return ftp_epsv_disable(conn); - } - return result; - } - } - - result = Curl_proxy_connect(conn, SECONDARYSOCKET); - if(result) - return result; - - if(CONNECT_SECONDARYSOCKET_PROXY_SSL()) - return result; - - if(conn->bits.tunnel_proxy && conn->bits.httpproxy && - Curl_connect_ongoing(conn)) - return result; - - - if(ftpc->state) { - /* already in a state so skip the initial commands. - They are only done to kickstart the do_more state */ - result = ftp_multi_statemach(conn, &complete); - - *completep = (int)complete; - - /* if we got an error or if we don't wait for a data connection return - immediately */ - if(result || (ftpc->wait_data_conn != TRUE)) - return result; - - if(ftpc->wait_data_conn) - /* if we reach the end of the FTP state machine here, *complete will be - TRUE but so is ftpc->wait_data_conn, which says we need to wait for - the data connection and therefore we're not actually complete */ - *completep = 0; - } - - if(ftp->transfer <= FTPTRANSFER_INFO) { - /* a transfer is about to take place, or if not a file name was given - so we'll do a SIZE on it later and then we need the right TYPE first */ - - if(ftpc->wait_data_conn == TRUE) { - bool serv_conned; - - result = ReceivedServerConnect(conn, &serv_conned); - if(result) - return result; /* Failed to accept data connection */ - - if(serv_conned) { - /* It looks data connection is established */ - result = AcceptServerConnect(conn); - ftpc->wait_data_conn = FALSE; - if(!result) - result = InitiateTransfer(conn); - - if(result) - return result; - - *completep = 1; /* this state is now complete when the server has - connected back to us */ - } - } - else if(data->set.upload) { - result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE); - if(result) - return result; - - result = ftp_multi_statemach(conn, &complete); - if(ftpc->wait_data_conn) - /* if we reach the end of the FTP state machine here, *complete will be - TRUE but so is ftpc->wait_data_conn, which says we need to wait for - the data connection and therefore we're not actually complete */ - *completep = 0; - else - *completep = (int)complete; - } - else { - /* download */ - ftp->downloadsize = -1; /* unknown as of yet */ - - result = ftp_range(conn); - if(result) - ; - else if(data->set.ftp_list_only || !ftpc->file) { - /* The specified path ends with a slash, and therefore we think this - is a directory that is requested, use LIST. But before that we - need to set ASCII transfer mode. */ - - /* But only if a body transfer was requested. */ - if(ftp->transfer == FTPTRANSFER_BODY) { - result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE); - if(result) - return result; - } - /* otherwise just fall through */ - } - else { - result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE); - if(result) - return result; - } - - result = ftp_multi_statemach(conn, &complete); - *completep = (int)complete; - } - return result; - } - - if(!result && (ftp->transfer != FTPTRANSFER_BODY)) - /* no data to transfer. FIX: it feels like a kludge to have this here - too! */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - if(!ftpc->wait_data_conn) { - /* no waiting for the data connection so this is now complete */ - *completep = 1; - DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result)); - } - - return result; -} - - - -/*********************************************************************** - * - * ftp_perform() - * - * This is the actual DO function for FTP. Get a file/directory according to - * the options previously setup. - */ - -static -CURLcode ftp_perform(struct connectdata *conn, - bool *connected, /* connect status after PASV / PORT */ - bool *dophase_done) -{ - /* this is FTP and no proxy */ - CURLcode result = CURLE_OK; - - DEBUGF(infof(conn->data, "DO phase starts\n")); - - if(conn->data->set.opt_no_body) { - /* requested no body means no transfer... */ - struct FTP *ftp = conn->data->req.protop; - ftp->transfer = FTPTRANSFER_INFO; - } - - *dophase_done = FALSE; /* not done yet */ - - /* start the first command in the DO phase */ - result = ftp_state_quote(conn, TRUE, FTP_QUOTE); - if(result) - return result; - - /* run the state-machine */ - result = ftp_multi_statemach(conn, dophase_done); - - *connected = conn->bits.tcpconnect[SECONDARYSOCKET]; - - infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected); - - if(*dophase_done) - DEBUGF(infof(conn->data, "DO phase is complete1\n")); - - return result; -} - -static void wc_data_dtor(void *ptr) -{ - struct ftp_wc_tmpdata *tmp = ptr; - if(tmp) - Curl_ftp_parselist_data_free(&tmp->parser); - free(tmp); -} - -static CURLcode init_wc_data(struct connectdata *conn) -{ - char *last_slash; - char *path = conn->data->state.path; - struct WildcardData *wildcard = &(conn->data->wildcard); - CURLcode result = CURLE_OK; - struct ftp_wc_tmpdata *ftp_tmp; - - last_slash = strrchr(conn->data->state.path, '/'); - if(last_slash) { - last_slash++; - if(last_slash[0] == '\0') { - wildcard->state = CURLWC_CLEAN; - result = ftp_parse_url_path(conn); - return result; - } - wildcard->pattern = strdup(last_slash); - if(!wildcard->pattern) - return CURLE_OUT_OF_MEMORY; - last_slash[0] = '\0'; /* cut file from path */ - } - else { /* there is only 'wildcard pattern' or nothing */ - if(path[0]) { - wildcard->pattern = strdup(path); - if(!wildcard->pattern) - return CURLE_OUT_OF_MEMORY; - path[0] = '\0'; - } - else { /* only list */ - wildcard->state = CURLWC_CLEAN; - result = ftp_parse_url_path(conn); - return result; - } - } - - /* program continues only if URL is not ending with slash, allocate needed - resources for wildcard transfer */ - - /* allocate ftp protocol specific temporary wildcard data */ - ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata)); - if(!ftp_tmp) { - Curl_safefree(wildcard->pattern); - return CURLE_OUT_OF_MEMORY; - } - - /* INITIALIZE parselist structure */ - ftp_tmp->parser = Curl_ftp_parselist_data_alloc(); - if(!ftp_tmp->parser) { - Curl_safefree(wildcard->pattern); - free(ftp_tmp); - return CURLE_OUT_OF_MEMORY; - } - - wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */ - wildcard->tmp_dtor = wc_data_dtor; - - /* wildcard does not support NOCWD option (assert it?) */ - if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD) - conn->data->set.ftp_filemethod = FTPFILE_MULTICWD; - - /* try to parse ftp url */ - result = ftp_parse_url_path(conn); - if(result) { - Curl_safefree(wildcard->pattern); - wildcard->tmp_dtor(wildcard->tmp); - wildcard->tmp_dtor = ZERO_NULL; - wildcard->tmp = NULL; - return result; - } - - wildcard->path = strdup(conn->data->state.path); - if(!wildcard->path) { - Curl_safefree(wildcard->pattern); - wildcard->tmp_dtor(wildcard->tmp); - wildcard->tmp_dtor = ZERO_NULL; - wildcard->tmp = NULL; - return CURLE_OUT_OF_MEMORY; - } - - /* backup old write_function */ - ftp_tmp->backup.write_function = conn->data->set.fwrite_func; - /* parsing write function */ - conn->data->set.fwrite_func = Curl_ftp_parselist; - /* backup old file descriptor */ - ftp_tmp->backup.file_descriptor = conn->data->set.out; - /* let the writefunc callback know what curl pointer is working with */ - conn->data->set.out = conn; - - infof(conn->data, "Wildcard - Parsing started\n"); - return CURLE_OK; -} - -/* This is called recursively */ -static CURLcode wc_statemach(struct connectdata *conn) -{ - struct WildcardData * const wildcard = &(conn->data->wildcard); - CURLcode result = CURLE_OK; - - switch(wildcard->state) { - case CURLWC_INIT: - result = init_wc_data(conn); - if(wildcard->state == CURLWC_CLEAN) - /* only listing! */ - break; - wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; - break; - - case CURLWC_MATCHING: { - /* In this state is LIST response successfully parsed, so lets restore - previous WRITEFUNCTION callback and WRITEDATA pointer */ - struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp; - conn->data->set.fwrite_func = ftp_tmp->backup.write_function; - conn->data->set.out = ftp_tmp->backup.file_descriptor; - ftp_tmp->backup.write_function = ZERO_NULL; - ftp_tmp->backup.file_descriptor = NULL; - wildcard->state = CURLWC_DOWNLOADING; - - if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) { - /* error found in LIST parsing */ - wildcard->state = CURLWC_CLEAN; - return wc_statemach(conn); - } - if(wildcard->filelist.size == 0) { - /* no corresponding file */ - wildcard->state = CURLWC_CLEAN; - return CURLE_REMOTE_FILE_NOT_FOUND; - } - return wc_statemach(conn); - } - - case CURLWC_DOWNLOADING: { - /* filelist has at least one file, lets get first one */ - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; - - char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); - if(!tmp_path) - return CURLE_OUT_OF_MEMORY; - - /* switch default "state.pathbuffer" and tmp_path, good to see - ftp_parse_url_path function to understand this trick */ - Curl_safefree(conn->data->state.pathbuffer); - conn->data->state.pathbuffer = tmp_path; - conn->data->state.path = tmp_path; - - infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); - if(conn->data->set.chunk_bgn) { - long userresponse = conn->data->set.chunk_bgn( - finfo, wildcard->customptr, (int)wildcard->filelist.size); - switch(userresponse) { - case CURL_CHUNK_BGN_FUNC_SKIP: - infof(conn->data, "Wildcard - \"%s\" skipped by user\n", - finfo->filename); - wildcard->state = CURLWC_SKIP; - return wc_statemach(conn); - case CURL_CHUNK_BGN_FUNC_FAIL: - return CURLE_CHUNK_FAILED; - } - } - - if(finfo->filetype != CURLFILETYPE_FILE) { - wildcard->state = CURLWC_SKIP; - return wc_statemach(conn); - } - - if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) - ftpc->known_filesize = finfo->size; - - result = ftp_parse_url_path(conn); - if(result) - return result; - - /* we don't need the Curl_fileinfo of first file anymore */ - Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); - - if(wildcard->filelist.size == 0) { /* remains only one file to down. */ - wildcard->state = CURLWC_CLEAN; - /* after that will be ftp_do called once again and no transfer - will be done because of CURLWC_CLEAN state */ - return CURLE_OK; - } - } break; - - case CURLWC_SKIP: { - if(conn->data->set.chunk_end) - conn->data->set.chunk_end(conn->data->wildcard.customptr); - Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); - wildcard->state = (wildcard->filelist.size == 0) ? - CURLWC_CLEAN : CURLWC_DOWNLOADING; - return wc_statemach(conn); - } - - case CURLWC_CLEAN: { - struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp; - result = CURLE_OK; - if(ftp_tmp) - result = Curl_ftp_parselist_geterror(ftp_tmp->parser); - - wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; - } break; - - case CURLWC_DONE: - case CURLWC_ERROR: - case CURLWC_CLEAR: - break; - } - - return result; -} - -/*********************************************************************** - * - * ftp_do() - * - * This function is registered as 'curl_do' function. It decodes the path - * parts etc as a wrapper to the actual DO function (ftp_perform). - * - * The input argument is already checked for validity. - */ -static CURLcode ftp_do(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - *done = FALSE; /* default to false */ - ftpc->wait_data_conn = FALSE; /* default to no such wait */ - - if(conn->data->set.wildcardmatch) { - result = wc_statemach(conn); - if(conn->data->wildcard.state == CURLWC_SKIP || - conn->data->wildcard.state == CURLWC_DONE) { - /* do not call ftp_regular_transfer */ - return CURLE_OK; - } - if(result) /* error, loop or skipping the file */ - return result; - } - else { /* no wildcard FSM needed */ - result = ftp_parse_url_path(conn); - if(result) - return result; - } - - result = ftp_regular_transfer(conn, done); - - return result; -} - - -CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd) -{ - ssize_t bytes_written; -#define SBUF_SIZE 1024 - char s[SBUF_SIZE]; - size_t write_len; - char *sptr = s; - CURLcode result = CURLE_OK; -#ifdef HAVE_GSSAPI - enum protection_level data_sec = conn->data_prot; -#endif - - write_len = strlen(cmd); - if(write_len > (sizeof(s) -3)) - return CURLE_BAD_FUNCTION_ARGUMENT; - - strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ - write_len += 2; - bytes_written = 0; - - result = Curl_convert_to_network(conn->data, s, write_len); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(result) - return result; - - for(;;) { -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CMD; -#endif - result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); -#ifdef HAVE_GSSAPI - DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); - conn->data_prot = data_sec; -#endif - - if(result) - break; - - if(conn->data->set.verbose) - Curl_debug(conn->data, CURLINFO_HEADER_OUT, - sptr, (size_t)bytes_written, conn); - - if(bytes_written != (ssize_t)write_len) { - write_len -= bytes_written; - sptr += bytes_written; - } - else - break; - } - - return result; -} - -/*********************************************************************** - * - * ftp_quit() - * - * This should be called before calling sclose() on an ftp control connection - * (not data connections). We should then wait for the response from the - * server before returning. The calling code should then try to close the - * connection. - * - */ -static CURLcode ftp_quit(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - if(conn->proto.ftpc.ctl_valid) { - result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT"); - if(result) { - failf(conn->data, "Failure sending QUIT command: %s", - curl_easy_strerror(result)); - conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */ - connclose(conn, "QUIT command failed"); /* mark for connection closure */ - state(conn, FTP_STOP); - return result; - } - - state(conn, FTP_QUIT); - - result = ftp_block_statemach(conn); - } - - return result; -} - -/*********************************************************************** - * - * ftp_disconnect() - * - * Disconnect from an FTP server. Cleanup protocol-specific per-connection - * resources. BLOCKING. - */ -static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - - /* We cannot send quit unconditionally. If this connection is stale or - bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. - - ftp_quit() will check the state of ftp->ctl_valid. If it's ok it - will try to send the QUIT command, otherwise it will just return. - */ - if(dead_connection) - ftpc->ctl_valid = FALSE; - - /* The FTP session may or may not have been allocated/setup at this point! */ - (void)ftp_quit(conn); /* ignore errors on the QUIT */ - - if(ftpc->entrypath) { - struct Curl_easy *data = conn->data; - if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) { - data->state.most_recent_ftp_entrypath = NULL; - } - free(ftpc->entrypath); - ftpc->entrypath = NULL; - } - - freedirs(ftpc); - free(ftpc->prevpath); - ftpc->prevpath = NULL; - free(ftpc->server_os); - ftpc->server_os = NULL; - - Curl_pp_disconnect(pp); - -#ifdef HAVE_GSSAPI - Curl_sec_end(conn); -#endif - - return CURLE_OK; -} - -/*********************************************************************** - * - * ftp_parse_url_path() - * - * Parse the URL path into separate path components. - * - */ -static -CURLcode ftp_parse_url_path(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - /* the ftp struct is already inited in ftp_connect() */ - struct FTP *ftp = data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - const char *slash_pos; /* position of the first '/' char in curpos */ - const char *path_to_use = data->state.path; - const char *cur_pos; - const char *filename = NULL; - - cur_pos = path_to_use; /* current position in path. point at the begin of - next path component */ - - ftpc->ctl_valid = FALSE; - ftpc->cwdfail = FALSE; - - switch(data->set.ftp_filemethod) { - case FTPFILE_NOCWD: - /* fastest, but less standard-compliant */ - - /* - The best time to check whether the path is a file or directory is right - here. so: - - the first condition in the if() right here, is there just in case - someone decides to set path to NULL one day - */ - if(path_to_use[0] && - (path_to_use[strlen(path_to_use) - 1] != '/') ) - filename = path_to_use; /* this is a full file path */ - /* - else { - ftpc->file is not used anywhere other than for operations on a file. - In other words, never for directory operations. - So we can safely leave filename as NULL here and use it as a - argument in dir/file decisions. - } - */ - break; - - case FTPFILE_SINGLECWD: - /* get the last slash */ - if(!path_to_use[0]) { - /* no dir, no file */ - ftpc->dirdepth = 0; - break; - } - slash_pos = strrchr(cur_pos, '/'); - if(slash_pos || !*cur_pos) { - size_t dirlen = slash_pos-cur_pos; - CURLcode result; - - ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); - if(!ftpc->dirs) - return CURLE_OUT_OF_MEMORY; - - if(!dirlen) - dirlen++; - - result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/", - slash_pos ? dirlen : 1, - &ftpc->dirs[0], NULL, - FALSE); - if(result) { - freedirs(ftpc); - return result; - } - ftpc->dirdepth = 1; /* we consider it to be a single dir */ - filename = slash_pos ? slash_pos + 1 : cur_pos; /* rest is file name */ - } - else - filename = cur_pos; /* this is a file name only */ - break; - - default: /* allow pretty much anything */ - case FTPFILE_MULTICWD: - ftpc->dirdepth = 0; - ftpc->diralloc = 5; /* default dir depth to allocate */ - ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0])); - if(!ftpc->dirs) - return CURLE_OUT_OF_MEMORY; - - /* we have a special case for listing the root dir only */ - if(!strcmp(path_to_use, "/")) { - cur_pos++; /* make it point to the zero byte */ - ftpc->dirs[0] = strdup("/"); - ftpc->dirdepth++; - } - else { - /* parse the URL path into separate path components */ - while((slash_pos = strchr(cur_pos, '/')) != NULL) { - /* 1 or 0 pointer offset to indicate absolute directory */ - ssize_t absolute_dir = ((cur_pos - data->state.path > 0) && - (ftpc->dirdepth == 0))?1:0; - - /* seek out the next path component */ - if(slash_pos-cur_pos) { - /* we skip empty path components, like "x//y" since the FTP command - CWD requires a parameter and a non-existent parameter a) doesn't - work on many servers and b) has no effect on the others. */ - size_t len = slash_pos - cur_pos + absolute_dir; - CURLcode result = - Curl_urldecode(conn->data, cur_pos - absolute_dir, len, - &ftpc->dirs[ftpc->dirdepth], NULL, - TRUE); - if(result) { - freedirs(ftpc); - return result; - } - } - else { - cur_pos = slash_pos + 1; /* jump to the rest of the string */ - if(!ftpc->dirdepth) { - /* path starts with a slash, add that as a directory */ - ftpc->dirs[ftpc->dirdepth] = strdup("/"); - if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */ - failf(data, "no memory"); - freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; - } - } - continue; - } - - cur_pos = slash_pos + 1; /* jump to the rest of the string */ - if(++ftpc->dirdepth >= ftpc->diralloc) { - /* enlarge array */ - char **bigger; - ftpc->diralloc *= 2; /* double the size each time */ - bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0])); - if(!bigger) { - freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; - } - ftpc->dirs = bigger; - } - } - } - filename = cur_pos; /* the rest is the file name */ - break; - } /* switch */ - - if(filename && *filename) { - CURLcode result = - Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE); - - if(result) { - freedirs(ftpc); - return result; - } - } - else - ftpc->file = NULL; /* instead of point to a zero byte, we make it a NULL - pointer */ - - if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { - /* We need a file name when uploading. Return error! */ - failf(data, "Uploading to a URL without a file name!"); - return CURLE_URL_MALFORMAT; - } - - ftpc->cwddone = FALSE; /* default to not done */ - - if(ftpc->prevpath) { - /* prevpath is "raw" so we convert the input path before we compare the - strings */ - size_t dlen; - char *path; - CURLcode result = - Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE); - if(result) { - freedirs(ftpc); - return result; - } - - dlen -= ftpc->file?strlen(ftpc->file):0; - if((dlen == strlen(ftpc->prevpath)) && - !strncmp(path, ftpc->prevpath, dlen) && - (ftpc->prevmethod == data->set.ftp_filemethod)) { - infof(data, "Request has same path as previous transfer\n"); - ftpc->cwddone = TRUE; - } - free(path); - } - - return CURLE_OK; -} - -/* call this when the DO phase has completed */ -static CURLcode ftp_dophase_done(struct connectdata *conn, - bool connected) -{ - struct FTP *ftp = conn->data->req.protop; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(connected) { - int completed; - CURLcode result = ftp_do_more(conn, &completed); - - if(result) { - close_secondarysocket(conn); - return result; - } - } - - if(ftp->transfer != FTPTRANSFER_BODY) - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - else if(!connected) - /* since we didn't connect now, we want do_more to get called */ - conn->bits.do_more = TRUE; - - ftpc->ctl_valid = TRUE; /* seems good */ - - return CURLE_OK; -} - -/* called from multi.c while DOing */ -static CURLcode ftp_doing(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result = ftp_multi_statemach(conn, dophase_done); - - if(result) - DEBUGF(infof(conn->data, "DO phase failed\n")); - else if(*dophase_done) { - result = ftp_dophase_done(conn, FALSE /* not connected */); - - DEBUGF(infof(conn->data, "DO phase is complete2\n")); - } - return result; -} - -/*********************************************************************** - * - * ftp_regular_transfer() - * - * The input argument is already checked for validity. - * - * Performs all commands done before a regular transfer between a local and a - * remote host. - * - * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the - * ftp_done() function without finding any major problem. - */ -static -CURLcode ftp_regular_transfer(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - bool connected = FALSE; - struct Curl_easy *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - data->req.size = -1; /* make sure this is unknown at this point */ - - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, -1); - Curl_pgrsSetDownloadSize(data, -1); - - ftpc->ctl_valid = TRUE; /* starts good */ - - result = ftp_perform(conn, - &connected, /* have we connected after PASV/PORT */ - dophase_done); /* all commands in the DO-phase done? */ - - if(!result) { - - if(!*dophase_done) - /* the DO phase has not completed yet */ - return CURLE_OK; - - result = ftp_dophase_done(conn, connected); - - if(result) - return result; - } - else - freedirs(ftpc); - - return result; -} - -static CURLcode ftp_setup_connection(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - char *type; - char command; - struct FTP *ftp; - - conn->data->req.protop = ftp = malloc(sizeof(struct FTP)); - if(NULL == ftp) - return CURLE_OUT_OF_MEMORY; - - data->state.path++; /* don't include the initial slash */ - data->state.slash_removed = TRUE; /* we've skipped the slash */ - - /* FTP URLs support an extension like ";type=" that - * we'll try to get now! */ - type = strstr(data->state.path, ";type="); - - if(!type) - type = strstr(conn->host.rawalloc, ";type="); - - if(type) { - *type = 0; /* it was in the middle of the hostname */ - command = Curl_raw_toupper(type[6]); - conn->bits.type_set = TRUE; - - switch(command) { - case 'A': /* ASCII mode */ - data->set.prefer_ascii = TRUE; - break; - - case 'D': /* directory mode */ - data->set.ftp_list_only = TRUE; - break; - - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->set.prefer_ascii = FALSE; - break; - } - } - - /* get some initial data into the ftp struct */ - ftp->bytecountp = &conn->data->req.bytecount; - ftp->transfer = FTPTRANSFER_BODY; - ftp->downloadsize = 0; - - /* No need to duplicate user+password, the connectdata struct won't change - during a session, but we re-init them here since on subsequent inits - since the conn struct may have changed or been replaced. - */ - ftp->user = conn->user; - ftp->passwd = conn->passwd; - if(isBadFtpString(ftp->user)) - return CURLE_URL_MALFORMAT; - if(isBadFtpString(ftp->passwd)) - return CURLE_URL_MALFORMAT; - - conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ - - return CURLE_OK; -} - -#endif /* CURL_DISABLE_FTP */ diff --git a/dep/cpr/opt/curl/lib/ftp.h b/dep/cpr/opt/curl/lib/ftp.h deleted file mode 100644 index e4aa63f178a..00000000000 --- a/dep/cpr/opt/curl/lib/ftp.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef HEADER_CURL_FTP_H -#define HEADER_CURL_FTP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "pingpong.h" - -#ifndef CURL_DISABLE_FTP -extern const struct Curl_handler Curl_handler_ftp; - -#ifdef USE_SSL -extern const struct Curl_handler Curl_handler_ftps; -#endif - -CURLcode Curl_ftpsend(struct connectdata *, const char *cmd); -CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn, - int *ftpcode); -#endif /* CURL_DISABLE_FTP */ - -/**************************************************************************** - * FTP unique setup - ***************************************************************************/ -typedef enum { - FTP_STOP, /* do nothing state, stops the state machine */ - FTP_WAIT220, /* waiting for the initial 220 response immediately after - a connect */ - FTP_AUTH, - FTP_USER, - FTP_PASS, - FTP_ACCT, - FTP_PBSZ, - FTP_PROT, - FTP_CCC, - FTP_PWD, - FTP_SYST, - FTP_NAMEFMT, - FTP_QUOTE, /* waiting for a response to a command sent in a quote list */ - FTP_RETR_PREQUOTE, - FTP_STOR_PREQUOTE, - FTP_POSTQUOTE, - FTP_CWD, /* change dir */ - FTP_MKD, /* if the dir didn't exist */ - FTP_MDTM, /* to figure out the datestamp */ - FTP_TYPE, /* to set type when doing a head-like request */ - FTP_LIST_TYPE, /* set type when about to do a dir list */ - FTP_RETR_TYPE, /* set type when about to RETR a file */ - FTP_STOR_TYPE, /* set type when about to STOR a file */ - FTP_SIZE, /* get the remote file's size for head-like request */ - FTP_RETR_SIZE, /* get the remote file's size for RETR */ - FTP_STOR_SIZE, /* get the size for STOR */ - FTP_REST, /* when used to check if the server supports it in head-like */ - FTP_RETR_REST, /* when asking for "resume" in for RETR */ - FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */ - FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */ - FTP_PASV, /* generic state for PASV and EPSV, check count1 */ - FTP_LIST, /* generic state for LIST, NLST or a custom list command */ - FTP_RETR, - FTP_STOR, /* generic state for STOR and APPE */ - FTP_QUIT, - FTP_LAST /* never used */ -} ftpstate; - -struct ftp_parselist_data; /* defined later in ftplistparser.c */ - -struct ftp_wc_tmpdata { - struct ftp_parselist_data *parser; - - struct { - curl_write_callback write_function; - FILE *file_descriptor; - } backup; -}; - -typedef enum { - FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */ - FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */ - FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the - file */ -} curl_ftpfile; - -/* This FTP struct is used in the Curl_easy. All FTP data that is - connection-oriented must be in FTP_conn to properly deal with the fact that - perhaps the Curl_easy is changed between the times the connection is - used. */ -struct FTP { - curl_off_t *bytecountp; - char *user; /* user name string */ - char *passwd; /* password string */ - - /* transfer a file/body or not, done as a typedefed enum just to make - debuggers display the full symbol and not just the numerical value */ - curl_pp_transfer transfer; - curl_off_t downloadsize; -}; - - -/* ftp_conn is used for struct connection-oriented data in the connectdata - struct */ -struct ftp_conn { - struct pingpong pp; - char *entrypath; /* the PWD reply when we logged on */ - char **dirs; /* realloc()ed array for path components */ - int dirdepth; /* number of entries used in the 'dirs' array */ - int diralloc; /* number of entries allocated for the 'dirs' array */ - char *file; /* decoded file */ - bool dont_check; /* Set to TRUE to prevent the final (post-transfer) - file size and 226/250 status check. It should still - read the line, just ignore the result. */ - bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do anything. If - the connection has timed out or been closed, this - should be FALSE when it gets to Curl_ftp_quit() */ - bool cwddone; /* if it has been determined that the proper CWD combo - already has been done */ - int cwdcount; /* number of CWD commands issued */ - bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent - caching the current directory */ - bool wait_data_conn; /* this is set TRUE if data connection is waited */ - char *prevpath; /* conn->path from the previous transfer */ - curl_ftpfile prevmethod; /* ftp method in previous transfer */ - char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a - and others (A/I or zero) */ - int count1; /* general purpose counter for the state machine */ - int count2; /* general purpose counter for the state machine */ - int count3; /* general purpose counter for the state machine */ - ftpstate state; /* always use ftp.c:state() to change state! */ - ftpstate state_saved; /* transfer type saved to be reloaded after - data connection is established */ - curl_off_t retr_size_saved; /* Size of retrieved file saved */ - char *server_os; /* The target server operating system. */ - curl_off_t known_filesize; /* file size is different from -1, if wildcard - LIST parsing was done and wc_statemach set - it */ - /* newhost is the (allocated) IP addr or host name to connect the data - connection to */ - char *newhost; /* this is the pair to connect the DATA... */ - unsigned short newport; /* connection to */ - -}; - -#define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */ - -#endif /* HEADER_CURL_FTP_H */ diff --git a/dep/cpr/opt/curl/lib/ftplistparser.c b/dep/cpr/opt/curl/lib/ftplistparser.c deleted file mode 100644 index b2a8c0fdbcb..00000000000 --- a/dep/cpr/opt/curl/lib/ftplistparser.c +++ /dev/null @@ -1,1016 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/** - * Now implemented: - * - * 1) Unix version 1 - * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog - * 2) Unix version 2 - * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog - * 3) Unix version 3 - * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog - * 4) Unix symlink - * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000 - * 5) DOS style - * 01-29-97 11:32PM

prog - */ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_FTP - -#include - -#include "urldata.h" -#include "fileinfo.h" -#include "llist.h" -#include "strtoofft.h" -#include "ftp.h" -#include "ftplistparser.h" -#include "curl_fnmatch.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* allocs buffer which will contain one line of LIST command response */ -#define FTP_BUFFER_ALLOCSIZE 160 - -typedef enum { - PL_UNIX_TOTALSIZE = 0, - PL_UNIX_FILETYPE, - PL_UNIX_PERMISSION, - PL_UNIX_HLINKS, - PL_UNIX_USER, - PL_UNIX_GROUP, - PL_UNIX_SIZE, - PL_UNIX_TIME, - PL_UNIX_FILENAME, - PL_UNIX_SYMLINK -} pl_unix_mainstate; - -typedef union { - enum { - PL_UNIX_TOTALSIZE_INIT = 0, - PL_UNIX_TOTALSIZE_READING - } total_dirsize; - - enum { - PL_UNIX_HLINKS_PRESPACE = 0, - PL_UNIX_HLINKS_NUMBER - } hlinks; - - enum { - PL_UNIX_USER_PRESPACE = 0, - PL_UNIX_USER_PARSING - } user; - - enum { - PL_UNIX_GROUP_PRESPACE = 0, - PL_UNIX_GROUP_NAME - } group; - - enum { - PL_UNIX_SIZE_PRESPACE = 0, - PL_UNIX_SIZE_NUMBER - } size; - - enum { - PL_UNIX_TIME_PREPART1 = 0, - PL_UNIX_TIME_PART1, - PL_UNIX_TIME_PREPART2, - PL_UNIX_TIME_PART2, - PL_UNIX_TIME_PREPART3, - PL_UNIX_TIME_PART3 - } time; - - enum { - PL_UNIX_FILENAME_PRESPACE = 0, - PL_UNIX_FILENAME_NAME, - PL_UNIX_FILENAME_WINDOWSEOL - } filename; - - enum { - PL_UNIX_SYMLINK_PRESPACE = 0, - PL_UNIX_SYMLINK_NAME, - PL_UNIX_SYMLINK_PRETARGET1, - PL_UNIX_SYMLINK_PRETARGET2, - PL_UNIX_SYMLINK_PRETARGET3, - PL_UNIX_SYMLINK_PRETARGET4, - PL_UNIX_SYMLINK_TARGET, - PL_UNIX_SYMLINK_WINDOWSEOL - } symlink; -} pl_unix_substate; - -typedef enum { - PL_WINNT_DATE = 0, - PL_WINNT_TIME, - PL_WINNT_DIRORSIZE, - PL_WINNT_FILENAME -} pl_winNT_mainstate; - -typedef union { - enum { - PL_WINNT_TIME_PRESPACE = 0, - PL_WINNT_TIME_TIME - } time; - enum { - PL_WINNT_DIRORSIZE_PRESPACE = 0, - PL_WINNT_DIRORSIZE_CONTENT - } dirorsize; - enum { - PL_WINNT_FILENAME_PRESPACE = 0, - PL_WINNT_FILENAME_CONTENT, - PL_WINNT_FILENAME_WINEOL - } filename; -} pl_winNT_substate; - -/* This struct is used in wildcard downloading - for parsing LIST response */ -struct ftp_parselist_data { - enum { - OS_TYPE_UNKNOWN = 0, - OS_TYPE_UNIX, - OS_TYPE_WIN_NT - } os_type; - - union { - struct { - pl_unix_mainstate main; - pl_unix_substate sub; - } UNIX; - - struct { - pl_winNT_mainstate main; - pl_winNT_substate sub; - } NT; - } state; - - CURLcode error; - struct fileinfo *file_data; - unsigned int item_length; - size_t item_offset; - struct { - size_t filename; - size_t user; - size_t group; - size_t time; - size_t perm; - size_t symlink_target; - } offsets; -}; - -struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void) -{ - return calloc(1, sizeof(struct ftp_parselist_data)); -} - - -void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data) -{ - free(*pl_data); - *pl_data = NULL; -} - - -CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data) -{ - return pl_data->error; -} - - -#define FTP_LP_MALFORMATED_PERM 0x01000000 - -static int ftp_pl_get_permission(const char *str) -{ - int permissions = 0; - /* USER */ - if(str[0] == 'r') - permissions |= 1 << 8; - else if(str[0] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - if(str[1] == 'w') - permissions |= 1 << 7; - else if(str[1] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - - if(str[2] == 'x') - permissions |= 1 << 6; - else if(str[2] == 's') { - permissions |= 1 << 6; - permissions |= 1 << 11; - } - else if(str[2] == 'S') - permissions |= 1 << 11; - else if(str[2] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - /* GROUP */ - if(str[3] == 'r') - permissions |= 1 << 5; - else if(str[3] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - if(str[4] == 'w') - permissions |= 1 << 4; - else if(str[4] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - if(str[5] == 'x') - permissions |= 1 << 3; - else if(str[5] == 's') { - permissions |= 1 << 3; - permissions |= 1 << 10; - } - else if(str[5] == 'S') - permissions |= 1 << 10; - else if(str[5] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - /* others */ - if(str[6] == 'r') - permissions |= 1 << 2; - else if(str[6] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - if(str[7] == 'w') - permissions |= 1 << 1; - else if(str[7] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - if(str[8] == 'x') - permissions |= 1; - else if(str[8] == 't') { - permissions |= 1; - permissions |= 1 << 9; - } - else if(str[8] == 'T') - permissions |= 1 << 9; - else if(str[8] != '-') - permissions |= FTP_LP_MALFORMATED_PERM; - - return permissions; -} - -static void PL_ERROR(struct connectdata *conn, CURLcode err) -{ - struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp; - struct ftp_parselist_data *parser = tmpdata->parser; - if(parser->file_data) - Curl_fileinfo_dtor(NULL, parser->file_data); - parser->file_data = NULL; - parser->error = err; -} - -static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, - struct fileinfo *infop) -{ - curl_fnmatch_callback compare; - struct WildcardData *wc = &conn->data->wildcard; - struct ftp_wc_tmpdata *tmpdata = wc->tmp; - struct curl_llist *llist = &wc->filelist; - struct ftp_parselist_data *parser = tmpdata->parser; - bool add = TRUE; - struct curl_fileinfo *finfo = &infop->info; - - /* move finfo pointers to b_data */ - char *str = finfo->b_data; - finfo->filename = str + parser->offsets.filename; - finfo->strings.group = parser->offsets.group ? - str + parser->offsets.group : NULL; - finfo->strings.perm = parser->offsets.perm ? - str + parser->offsets.perm : NULL; - finfo->strings.target = parser->offsets.symlink_target ? - str + parser->offsets.symlink_target : NULL; - finfo->strings.time = str + parser->offsets.time; - finfo->strings.user = parser->offsets.user ? - str + parser->offsets.user : NULL; - - /* get correct fnmatch callback */ - compare = conn->data->set.fnmatch; - if(!compare) - compare = Curl_fnmatch; - - /* filter pattern-corresponding filenames */ - if(compare(conn->data->set.fnmatch_data, wc->pattern, - finfo->filename) == 0) { - /* discard symlink which is containing multiple " -> " */ - if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target && - (strstr(finfo->strings.target, " -> "))) { - add = FALSE; - } - } - else { - add = FALSE; - } - - if(add) { - Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list); - } - else { - Curl_fileinfo_dtor(NULL, finfo); - } - - tmpdata->parser->file_data = NULL; - return CURLE_OK; -} - -size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, - void *connptr) -{ - size_t bufflen = size*nmemb; - struct connectdata *conn = (struct connectdata *)connptr; - struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp; - struct ftp_parselist_data *parser = tmpdata->parser; - struct fileinfo *infop; - struct curl_fileinfo *finfo; - unsigned long i = 0; - CURLcode result; - - if(parser->error) { /* error in previous call */ - /* scenario: - * 1. call => OK.. - * 2. call => OUT_OF_MEMORY (or other error) - * 3. (last) call => is skipped RIGHT HERE and the error is hadled later - * in wc_statemach() - */ - return bufflen; - } - - if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) { - /* considering info about FILE response format */ - parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ? - OS_TYPE_WIN_NT : OS_TYPE_UNIX; - } - - while(i < bufflen) { /* FSM */ - - char c = buffer[i]; - if(!parser->file_data) { /* tmp file data is not allocated yet */ - parser->file_data = Curl_fileinfo_alloc(); - if(!parser->file_data) { - parser->error = CURLE_OUT_OF_MEMORY; - return bufflen; - } - parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE); - if(!parser->file_data->info.b_data) { - PL_ERROR(conn, CURLE_OUT_OF_MEMORY); - return bufflen; - } - parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE; - parser->item_offset = 0; - parser->item_length = 0; - } - - infop = parser->file_data; - finfo = &infop->info; - finfo->b_data[finfo->b_used++] = c; - - if(finfo->b_used >= finfo->b_size - 1) { - /* if it is important, extend buffer space for file data */ - char *tmp = realloc(finfo->b_data, - finfo->b_size + FTP_BUFFER_ALLOCSIZE); - if(tmp) { - finfo->b_size += FTP_BUFFER_ALLOCSIZE; - finfo->b_data = tmp; - } - else { - Curl_fileinfo_dtor(NULL, parser->file_data); - parser->file_data = NULL; - parser->error = CURLE_OUT_OF_MEMORY; - PL_ERROR(conn, CURLE_OUT_OF_MEMORY); - return bufflen; - } - } - - switch(parser->os_type) { - case OS_TYPE_UNIX: - switch(parser->state.UNIX.main) { - case PL_UNIX_TOTALSIZE: - switch(parser->state.UNIX.sub.total_dirsize) { - case PL_UNIX_TOTALSIZE_INIT: - if(c == 't') { - parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING; - parser->item_length++; - } - else { - parser->state.UNIX.main = PL_UNIX_FILETYPE; - /* start FSM again not considering size of directory */ - finfo->b_used = 0; - i--; - } - break; - case PL_UNIX_TOTALSIZE_READING: - parser->item_length++; - if(c == '\r') { - parser->item_length--; - finfo->b_used--; - } - else if(c == '\n') { - finfo->b_data[parser->item_length - 1] = 0; - if(strncmp("total ", finfo->b_data, 6) == 0) { - char *endptr = finfo->b_data + 6; - /* here we can deal with directory size, pass the leading white - spaces and then the digits */ - while(ISSPACE(*endptr)) - endptr++; - while(ISDIGIT(*endptr)) - endptr++; - if(*endptr != 0) { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - parser->state.UNIX.main = PL_UNIX_FILETYPE; - finfo->b_used = 0; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - break; - } - break; - case PL_UNIX_FILETYPE: - switch(c) { - case '-': - finfo->filetype = CURLFILETYPE_FILE; - break; - case 'd': - finfo->filetype = CURLFILETYPE_DIRECTORY; - break; - case 'l': - finfo->filetype = CURLFILETYPE_SYMLINK; - break; - case 'p': - finfo->filetype = CURLFILETYPE_NAMEDPIPE; - break; - case 's': - finfo->filetype = CURLFILETYPE_SOCKET; - break; - case 'c': - finfo->filetype = CURLFILETYPE_DEVICE_CHAR; - break; - case 'b': - finfo->filetype = CURLFILETYPE_DEVICE_BLOCK; - break; - case 'D': - finfo->filetype = CURLFILETYPE_DOOR; - break; - default: - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - parser->state.UNIX.main = PL_UNIX_PERMISSION; - parser->item_length = 0; - parser->item_offset = 1; - break; - case PL_UNIX_PERMISSION: - parser->item_length++; - if(parser->item_length <= 9) { - if(!strchr("rwx-tTsS", c)) { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - else if(parser->item_length == 10) { - unsigned int perm; - if(c != ' ') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - finfo->b_data[10] = 0; /* terminate permissions */ - perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset); - if(perm & FTP_LP_MALFORMATED_PERM) { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM; - parser->file_data->info.perm = perm; - parser->offsets.perm = parser->item_offset; - - parser->item_length = 0; - parser->state.UNIX.main = PL_UNIX_HLINKS; - parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE; - } - break; - case PL_UNIX_HLINKS: - switch(parser->state.UNIX.sub.hlinks) { - case PL_UNIX_HLINKS_PRESPACE: - if(c != ' ') { - if(c >= '0' && c <= '9') { - parser->item_offset = finfo->b_used - 1; - parser->item_length = 1; - parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - break; - case PL_UNIX_HLINKS_NUMBER: - parser->item_length ++; - if(c == ' ') { - char *p; - long int hlinks; - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10); - if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) { - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; - parser->file_data->info.hardlinks = hlinks; - } - parser->item_length = 0; - parser->item_offset = 0; - parser->state.UNIX.main = PL_UNIX_USER; - parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE; - } - else if(c < '0' || c > '9') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - } - break; - case PL_UNIX_USER: - switch(parser->state.UNIX.sub.user) { - case PL_UNIX_USER_PRESPACE: - if(c != ' ') { - parser->item_offset = finfo->b_used - 1; - parser->item_length = 1; - parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING; - } - break; - case PL_UNIX_USER_PARSING: - parser->item_length++; - if(c == ' ') { - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.user = parser->item_offset; - parser->state.UNIX.main = PL_UNIX_GROUP; - parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE; - parser->item_offset = 0; - parser->item_length = 0; - } - break; - } - break; - case PL_UNIX_GROUP: - switch(parser->state.UNIX.sub.group) { - case PL_UNIX_GROUP_PRESPACE: - if(c != ' ') { - parser->item_offset = finfo->b_used - 1; - parser->item_length = 1; - parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME; - } - break; - case PL_UNIX_GROUP_NAME: - parser->item_length++; - if(c == ' ') { - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.group = parser->item_offset; - parser->state.UNIX.main = PL_UNIX_SIZE; - parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE; - parser->item_offset = 0; - parser->item_length = 0; - } - break; - } - break; - case PL_UNIX_SIZE: - switch(parser->state.UNIX.sub.size) { - case PL_UNIX_SIZE_PRESPACE: - if(c != ' ') { - if(c >= '0' && c <= '9') { - parser->item_offset = finfo->b_used - 1; - parser->item_length = 1; - parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - break; - case PL_UNIX_SIZE_NUMBER: - parser->item_length++; - if(c == ' ') { - char *p; - curl_off_t fsize; - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - if(!curlx_strtoofft(finfo->b_data + parser->item_offset, - &p, 10, &fsize)) { - if(p[0] == '\0' && fsize != CURL_OFF_T_MAX && - fsize != CURL_OFF_T_MIN) { - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; - parser->file_data->info.size = fsize; - } - parser->item_length = 0; - parser->item_offset = 0; - parser->state.UNIX.main = PL_UNIX_TIME; - parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; - } - } - else if(!ISDIGIT(c)) { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - } - break; - case PL_UNIX_TIME: - switch(parser->state.UNIX.sub.time) { - case PL_UNIX_TIME_PREPART1: - if(c != ' ') { - if(ISALNUM(c)) { - parser->item_offset = finfo->b_used -1; - parser->item_length = 1; - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - break; - case PL_UNIX_TIME_PART1: - parser->item_length++; - if(c == ' ') { - parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2; - } - else if(!ISALNUM(c) && c != '.') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - case PL_UNIX_TIME_PREPART2: - parser->item_length++; - if(c != ' ') { - if(ISALNUM(c)) { - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - break; - case PL_UNIX_TIME_PART2: - parser->item_length++; - if(c == ' ') { - parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3; - } - else if(!ISALNUM(c) && c != '.') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - case PL_UNIX_TIME_PREPART3: - parser->item_length++; - if(c != ' ') { - if(ISALNUM(c)) { - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - break; - case PL_UNIX_TIME_PART3: - parser->item_length++; - if(c == ' ') { - finfo->b_data[parser->item_offset + parser->item_length -1] = 0; - parser->offsets.time = parser->item_offset; - /* - if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) { - parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; - } - */ - if(finfo->filetype == CURLFILETYPE_SYMLINK) { - parser->state.UNIX.main = PL_UNIX_SYMLINK; - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; - } - else { - parser->state.UNIX.main = PL_UNIX_FILENAME; - parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE; - } - } - else if(!ISALNUM(c) && c != '.' && c != ':') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - } - break; - case PL_UNIX_FILENAME: - switch(parser->state.UNIX.sub.filename) { - case PL_UNIX_FILENAME_PRESPACE: - if(c != ' ') { - parser->item_offset = finfo->b_used - 1; - parser->item_length = 1; - parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME; - } - break; - case PL_UNIX_FILENAME_NAME: - parser->item_length++; - if(c == '\r') { - parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; - } - else if(c == '\n') { - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.filename = parser->item_offset; - parser->state.UNIX.main = PL_UNIX_FILETYPE; - result = ftp_pl_insert_finfo(conn, infop); - if(result) { - PL_ERROR(conn, result); - return bufflen; - } - } - break; - case PL_UNIX_FILENAME_WINDOWSEOL: - if(c == '\n') { - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.filename = parser->item_offset; - parser->state.UNIX.main = PL_UNIX_FILETYPE; - result = ftp_pl_insert_finfo(conn, infop); - if(result) { - PL_ERROR(conn, result); - return bufflen; - } - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - } - break; - case PL_UNIX_SYMLINK: - switch(parser->state.UNIX.sub.symlink) { - case PL_UNIX_SYMLINK_PRESPACE: - if(c != ' ') { - parser->item_offset = finfo->b_used - 1; - parser->item_length = 1; - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; - } - break; - case PL_UNIX_SYMLINK_NAME: - parser->item_length++; - if(c == ' ') { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1; - } - else if(c == '\r' || c == '\n') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - case PL_UNIX_SYMLINK_PRETARGET1: - parser->item_length++; - if(c == '-') { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2; - } - else if(c == '\r' || c == '\n') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - else { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; - } - break; - case PL_UNIX_SYMLINK_PRETARGET2: - parser->item_length++; - if(c == '>') { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3; - } - else if(c == '\r' || c == '\n') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - else { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; - } - break; - case PL_UNIX_SYMLINK_PRETARGET3: - parser->item_length++; - if(c == ' ') { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4; - /* now place where is symlink following */ - finfo->b_data[parser->item_offset + parser->item_length - 4] = 0; - parser->offsets.filename = parser->item_offset; - parser->item_length = 0; - parser->item_offset = 0; - } - else if(c == '\r' || c == '\n') { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - else { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; - } - break; - case PL_UNIX_SYMLINK_PRETARGET4: - if(c != '\r' && c != '\n') { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET; - parser->item_offset = finfo->b_used - 1; - parser->item_length = 1; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - case PL_UNIX_SYMLINK_TARGET: - parser->item_length++; - if(c == '\r') { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; - } - else if(c == '\n') { - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.symlink_target = parser->item_offset; - result = ftp_pl_insert_finfo(conn, infop); - if(result) { - PL_ERROR(conn, result); - return bufflen; - } - parser->state.UNIX.main = PL_UNIX_FILETYPE; - } - break; - case PL_UNIX_SYMLINK_WINDOWSEOL: - if(c == '\n') { - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.symlink_target = parser->item_offset; - result = ftp_pl_insert_finfo(conn, infop); - if(result) { - PL_ERROR(conn, result); - return bufflen; - } - parser->state.UNIX.main = PL_UNIX_FILETYPE; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - } - break; - } - break; - case OS_TYPE_WIN_NT: - switch(parser->state.NT.main) { - case PL_WINNT_DATE: - parser->item_length++; - if(parser->item_length < 9) { - if(!strchr("0123456789-", c)) { /* only simple control */ - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - else if(parser->item_length == 9) { - if(c == ' ') { - parser->state.NT.main = PL_WINNT_TIME; - parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - case PL_WINNT_TIME: - parser->item_length++; - switch(parser->state.NT.sub.time) { - case PL_WINNT_TIME_PRESPACE: - if(!ISSPACE(c)) { - parser->state.NT.sub.time = PL_WINNT_TIME_TIME; - } - break; - case PL_WINNT_TIME_TIME: - if(c == ' ') { - parser->offsets.time = parser->item_offset; - finfo->b_data[parser->item_offset + parser->item_length -1] = 0; - parser->state.NT.main = PL_WINNT_DIRORSIZE; - parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE; - parser->item_length = 0; - } - else if(!strchr("APM0123456789:", c)) { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - } - break; - case PL_WINNT_DIRORSIZE: - switch(parser->state.NT.sub.dirorsize) { - case PL_WINNT_DIRORSIZE_PRESPACE: - if(c == ' ') { - - } - else { - parser->item_offset = finfo->b_used - 1; - parser->item_length = 1; - parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT; - } - break; - case PL_WINNT_DIRORSIZE_CONTENT: - parser->item_length ++; - if(c == ' ') { - finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - if(strcmp("", finfo->b_data + parser->item_offset) == 0) { - finfo->filetype = CURLFILETYPE_DIRECTORY; - finfo->size = 0; - } - else { - char *endptr; - if(curlx_strtoofft(finfo->b_data + - parser->item_offset, - &endptr, 10, &finfo->size)) { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - /* correct file type */ - parser->file_data->info.filetype = CURLFILETYPE_FILE; - } - - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; - parser->item_length = 0; - parser->state.NT.main = PL_WINNT_FILENAME; - parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; - } - break; - } - break; - case PL_WINNT_FILENAME: - switch(parser->state.NT.sub.filename) { - case PL_WINNT_FILENAME_PRESPACE: - if(c != ' ') { - parser->item_offset = finfo->b_used -1; - parser->item_length = 1; - parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT; - } - break; - case PL_WINNT_FILENAME_CONTENT: - parser->item_length++; - if(c == '\r') { - parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL; - finfo->b_data[finfo->b_used - 1] = 0; - } - else if(c == '\n') { - parser->offsets.filename = parser->item_offset; - finfo->b_data[finfo->b_used - 1] = 0; - parser->offsets.filename = parser->item_offset; - result = ftp_pl_insert_finfo(conn, infop); - if(result) { - PL_ERROR(conn, result); - return bufflen; - } - parser->state.NT.main = PL_WINNT_DATE; - parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; - } - break; - case PL_WINNT_FILENAME_WINEOL: - if(c == '\n') { - parser->offsets.filename = parser->item_offset; - result = ftp_pl_insert_finfo(conn, infop); - if(result) { - PL_ERROR(conn, result); - return bufflen; - } - parser->state.NT.main = PL_WINNT_DATE; - parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; - } - else { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - break; - } - break; - } - break; - default: - return bufflen + 1; - } - - i++; - } - - return bufflen; -} - -#endif /* CURL_DISABLE_FTP */ diff --git a/dep/cpr/opt/curl/lib/ftplistparser.h b/dep/cpr/opt/curl/lib/ftplistparser.h deleted file mode 100644 index 8128887c0b1..00000000000 --- a/dep/cpr/opt/curl/lib/ftplistparser.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef HEADER_CURL_FTPLISTPARSER_H -#define HEADER_CURL_FTPLISTPARSER_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifndef CURL_DISABLE_FTP - -/* WRITEFUNCTION callback for parsing LIST responses */ -size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, - void *connptr); - -struct ftp_parselist_data; /* defined inside ftplibparser.c */ - -CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data); - -struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void); - -void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data); - -#endif /* CURL_DISABLE_FTP */ -#endif /* HEADER_CURL_FTPLISTPARSER_H */ diff --git a/dep/cpr/opt/curl/lib/getenv.c b/dep/cpr/opt/curl/lib/getenv.c deleted file mode 100644 index 89d181de3c2..00000000000 --- a/dep/cpr/opt/curl/lib/getenv.c +++ /dev/null @@ -1,54 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include -#include "curl_memory.h" - -#include "memdebug.h" - -static -char *GetEnv(const char *variable) -{ -#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) - (void)variable; - return NULL; -#else -#ifdef WIN32 - char env[MAX_PATH]; /* MAX_PATH is from windef.h */ - char *temp = getenv(variable); - env[0] = '\0'; - if(temp != NULL) - ExpandEnvironmentStringsA(temp, env, sizeof(env)); - return (env[0] != '\0')?strdup(env):NULL; -#else - char *env = getenv(variable); - return (env && env[0])?strdup(env):NULL; -#endif -#endif -} - -char *curl_getenv(const char *v) -{ - return GetEnv(v); -} diff --git a/dep/cpr/opt/curl/lib/getinfo.c b/dep/cpr/opt/curl/lib/getinfo.c deleted file mode 100644 index 862ced0194a..00000000000 --- a/dep/cpr/opt/curl/lib/getinfo.c +++ /dev/null @@ -1,461 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "urldata.h" -#include "getinfo.h" - -#include "vtls/vtls.h" -#include "connect.h" /* Curl_getconnectinfo() */ -#include "progress.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Initialize statistical and informational data. - * - * This function is called in curl_easy_reset, curl_easy_duphandle and at the - * beginning of a perform session. It must reset the session-info variables, - * in particular all variables in struct PureInfo. - */ -CURLcode Curl_initinfo(struct Curl_easy *data) -{ - struct Progress *pro = &data->progress; - struct PureInfo *info = &data->info; - - pro->t_nslookup = 0; - pro->t_connect = 0; - pro->t_appconnect = 0; - pro->t_pretransfer = 0; - pro->t_starttransfer = 0; - pro->timespent = 0; - pro->t_redirect = 0; - pro->is_t_startransfer_set = false; - - info->httpcode = 0; - info->httpproxycode = 0; - info->httpversion = 0; - info->filetime = -1; /* -1 is an illegal time and thus means unknown */ - info->timecond = FALSE; - - info->header_size = 0; - info->request_size = 0; - info->proxyauthavail = 0; - info->httpauthavail = 0; - info->numconnects = 0; - - free(info->contenttype); - info->contenttype = NULL; - - free(info->wouldredirect); - info->wouldredirect = NULL; - - info->conn_primary_ip[0] = '\0'; - info->conn_local_ip[0] = '\0'; - info->conn_primary_port = 0; - info->conn_local_port = 0; - - info->conn_scheme = 0; - info->conn_protocol = 0; - -#ifdef USE_SSL - Curl_ssl_free_certinfo(data); -#endif - - return CURLE_OK; -} - -static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, - const char **param_charp) -{ - switch(info) { - case CURLINFO_EFFECTIVE_URL: - *param_charp = data->change.url?data->change.url:(char *)""; - break; - case CURLINFO_CONTENT_TYPE: - *param_charp = data->info.contenttype; - break; - case CURLINFO_PRIVATE: - *param_charp = (char *) data->set.private_data; - break; - case CURLINFO_FTP_ENTRY_PATH: - /* Return the entrypath string from the most recent connection. - This pointer was copied from the connectdata structure by FTP. - The actual string may be free()ed by subsequent libcurl calls so - it must be copied to a safer area before the next libcurl call. - Callers must never free it themselves. */ - *param_charp = data->state.most_recent_ftp_entrypath; - break; - case CURLINFO_REDIRECT_URL: - /* Return the URL this request would have been redirected to if that - option had been enabled! */ - *param_charp = data->info.wouldredirect; - break; - case CURLINFO_PRIMARY_IP: - /* Return the ip address of the most recent (primary) connection */ - *param_charp = data->info.conn_primary_ip; - break; - case CURLINFO_LOCAL_IP: - /* Return the source/local ip address of the most recent (primary) - connection */ - *param_charp = data->info.conn_local_ip; - break; - case CURLINFO_RTSP_SESSION_ID: - *param_charp = data->set.str[STRING_RTSP_SESSION_ID]; - break; - case CURLINFO_SCHEME: - *param_charp = data->info.conn_scheme; - break; - - default: - return CURLE_UNKNOWN_OPTION; - } - - return CURLE_OK; -} - -static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, - long *param_longp) -{ - curl_socket_t sockfd; - - union { - unsigned long *to_ulong; - long *to_long; - } lptr; - - switch(info) { - case CURLINFO_RESPONSE_CODE: - *param_longp = data->info.httpcode; - break; - case CURLINFO_HTTP_CONNECTCODE: - *param_longp = data->info.httpproxycode; - break; - case CURLINFO_FILETIME: - *param_longp = data->info.filetime; - break; - case CURLINFO_HEADER_SIZE: - *param_longp = data->info.header_size; - break; - case CURLINFO_REQUEST_SIZE: - *param_longp = data->info.request_size; - break; - case CURLINFO_SSL_VERIFYRESULT: - *param_longp = data->set.ssl.certverifyresult; - break; - case CURLINFO_PROXY_SSL_VERIFYRESULT: - *param_longp = data->set.proxy_ssl.certverifyresult; - break; - case CURLINFO_REDIRECT_COUNT: - *param_longp = data->set.followlocation; - break; - case CURLINFO_HTTPAUTH_AVAIL: - lptr.to_long = param_longp; - *lptr.to_ulong = data->info.httpauthavail; - break; - case CURLINFO_PROXYAUTH_AVAIL: - lptr.to_long = param_longp; - *lptr.to_ulong = data->info.proxyauthavail; - break; - case CURLINFO_OS_ERRNO: - *param_longp = data->state.os_errno; - break; - case CURLINFO_NUM_CONNECTS: - *param_longp = data->info.numconnects; - break; - case CURLINFO_LASTSOCKET: - sockfd = Curl_getconnectinfo(data, NULL); - - /* note: this is not a good conversion for systems with 64 bit sockets and - 32 bit longs */ - if(sockfd != CURL_SOCKET_BAD) - *param_longp = (long)sockfd; - else - /* this interface is documented to return -1 in case of badness, which - may not be the same as the CURL_SOCKET_BAD value */ - *param_longp = -1; - break; - case CURLINFO_PRIMARY_PORT: - /* Return the (remote) port of the most recent (primary) connection */ - *param_longp = data->info.conn_primary_port; - break; - case CURLINFO_LOCAL_PORT: - /* Return the local port of the most recent (primary) connection */ - *param_longp = data->info.conn_local_port; - break; - case CURLINFO_CONDITION_UNMET: - /* return if the condition prevented the document to get transferred */ - *param_longp = data->info.timecond ? 1L : 0L; - break; - case CURLINFO_RTSP_CLIENT_CSEQ: - *param_longp = data->state.rtsp_next_client_CSeq; - break; - case CURLINFO_RTSP_SERVER_CSEQ: - *param_longp = data->state.rtsp_next_server_CSeq; - break; - case CURLINFO_RTSP_CSEQ_RECV: - *param_longp = data->state.rtsp_CSeq_recv; - break; - case CURLINFO_HTTP_VERSION: - switch(data->info.httpversion) { - case 10: - *param_longp = CURL_HTTP_VERSION_1_0; - break; - case 11: - *param_longp = CURL_HTTP_VERSION_1_1; - break; - case 20: - *param_longp = CURL_HTTP_VERSION_2_0; - break; - default: - *param_longp = CURL_HTTP_VERSION_NONE; - break; - } - break; - case CURLINFO_PROTOCOL: - *param_longp = data->info.conn_protocol; - break; - - default: - return CURLE_UNKNOWN_OPTION; - } - - return CURLE_OK; -} - -#define DOUBLE_SECS(x) (double)(x)/1000000 - -static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, - curl_off_t *param_offt) -{ - switch(info) { - case CURLINFO_SIZE_UPLOAD_T: - *param_offt = data->progress.uploaded; - break; - case CURLINFO_SIZE_DOWNLOAD_T: - *param_offt = data->progress.downloaded; - break; - case CURLINFO_SPEED_DOWNLOAD_T: - *param_offt = data->progress.dlspeed; - break; - case CURLINFO_SPEED_UPLOAD_T: - *param_offt = data->progress.ulspeed; - break; - case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T: - *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)? - data->progress.size_dl:-1; - break; - case CURLINFO_CONTENT_LENGTH_UPLOAD_T: - *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? - data->progress.size_ul:-1; - break; - default: - return CURLE_UNKNOWN_OPTION; - } - - return CURLE_OK; -} - -static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, - double *param_doublep) -{ - switch(info) { - case CURLINFO_TOTAL_TIME: - *param_doublep = DOUBLE_SECS(data->progress.timespent); - break; - case CURLINFO_NAMELOOKUP_TIME: - *param_doublep = DOUBLE_SECS(data->progress.t_nslookup); - break; - case CURLINFO_CONNECT_TIME: - *param_doublep = DOUBLE_SECS(data->progress.t_connect); - break; - case CURLINFO_APPCONNECT_TIME: - *param_doublep = DOUBLE_SECS(data->progress.t_appconnect); - break; - case CURLINFO_PRETRANSFER_TIME: - *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer); - break; - case CURLINFO_STARTTRANSFER_TIME: - *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer); - break; - case CURLINFO_SIZE_UPLOAD: - *param_doublep = (double)data->progress.uploaded; - break; - case CURLINFO_SIZE_DOWNLOAD: - *param_doublep = (double)data->progress.downloaded; - break; - case CURLINFO_SPEED_DOWNLOAD: - *param_doublep = (double)data->progress.dlspeed; - break; - case CURLINFO_SPEED_UPLOAD: - *param_doublep = (double)data->progress.ulspeed; - break; - case CURLINFO_CONTENT_LENGTH_DOWNLOAD: - *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)? - (double)data->progress.size_dl:-1; - break; - case CURLINFO_CONTENT_LENGTH_UPLOAD: - *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? - (double)data->progress.size_ul:-1; - break; - case CURLINFO_REDIRECT_TIME: - *param_doublep = DOUBLE_SECS(data->progress.t_redirect); - break; - - default: - return CURLE_UNKNOWN_OPTION; - } - - return CURLE_OK; -} - -static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info, - struct curl_slist **param_slistp) -{ - union { - struct curl_certinfo *to_certinfo; - struct curl_slist *to_slist; - } ptr; - - switch(info) { - case CURLINFO_SSL_ENGINES: - *param_slistp = Curl_ssl_engines_list(data); - break; - case CURLINFO_COOKIELIST: - *param_slistp = Curl_cookie_list(data); - break; - case CURLINFO_CERTINFO: - /* Return the a pointer to the certinfo struct. Not really an slist - pointer but we can pretend it is here */ - ptr.to_certinfo = &data->info.certs; - *param_slistp = ptr.to_slist; - break; - case CURLINFO_TLS_SESSION: - case CURLINFO_TLS_SSL_PTR: - { - struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **) - param_slistp; - struct curl_tlssessioninfo *tsi = &data->tsi; -#ifdef USE_SSL - struct connectdata *conn = data->easy_conn; -#endif - - *tsip = tsi; - tsi->backend = Curl_ssl_backend(); - tsi->internals = NULL; - -#ifdef USE_SSL - if(conn && tsi->backend != CURLSSLBACKEND_NONE) { - unsigned int i; - for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) { - if(conn->ssl[i].use) { - tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info); - break; - } - } - } -#endif - } - break; - default: - return CURLE_UNKNOWN_OPTION; - } - - return CURLE_OK; -} - -static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info, - curl_socket_t *param_socketp) -{ - switch(info) { - case CURLINFO_ACTIVESOCKET: - *param_socketp = Curl_getconnectinfo(data, NULL); - break; - default: - return CURLE_UNKNOWN_OPTION; - } - - return CURLE_OK; -} - -CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) -{ - va_list arg; - long *param_longp = NULL; - double *param_doublep = NULL; - curl_off_t *param_offt = NULL; - const char **param_charp = NULL; - struct curl_slist **param_slistp = NULL; - curl_socket_t *param_socketp = NULL; - int type; - CURLcode result = CURLE_UNKNOWN_OPTION; - - if(!data) - return result; - - va_start(arg, info); - - type = CURLINFO_TYPEMASK & (int)info; - switch(type) { - case CURLINFO_STRING: - param_charp = va_arg(arg, const char **); - if(param_charp) - result = getinfo_char(data, info, param_charp); - break; - case CURLINFO_LONG: - param_longp = va_arg(arg, long *); - if(param_longp) - result = getinfo_long(data, info, param_longp); - break; - case CURLINFO_DOUBLE: - param_doublep = va_arg(arg, double *); - if(param_doublep) - result = getinfo_double(data, info, param_doublep); - break; - case CURLINFO_OFF_T: - param_offt = va_arg(arg, curl_off_t *); - if(param_offt) - result = getinfo_offt(data, info, param_offt); - break; - case CURLINFO_SLIST: - param_slistp = va_arg(arg, struct curl_slist **); - if(param_slistp) - result = getinfo_slist(data, info, param_slistp); - break; - case CURLINFO_SOCKET: - param_socketp = va_arg(arg, curl_socket_t *); - if(param_socketp) - result = getinfo_socket(data, info, param_socketp); - break; - default: - break; - } - - va_end(arg); - - return result; -} diff --git a/dep/cpr/opt/curl/lib/getinfo.h b/dep/cpr/opt/curl/lib/getinfo.h deleted file mode 100644 index aecf717f754..00000000000 --- a/dep/cpr/opt/curl/lib/getinfo.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef HEADER_CURL_GETINFO_H -#define HEADER_CURL_GETINFO_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...); -CURLcode Curl_initinfo(struct Curl_easy *data); - -#endif /* HEADER_CURL_GETINFO_H */ diff --git a/dep/cpr/opt/curl/lib/gopher.c b/dep/cpr/opt/curl/lib/gopher.c deleted file mode 100644 index b7c31b695e4..00000000000 --- a/dep/cpr/opt/curl/lib/gopher.c +++ /dev/null @@ -1,167 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_GOPHER - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "progress.h" -#include "gopher.h" -#include "select.h" -#include "url.h" -#include "escape.h" -#include "warnless.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * Forward declarations. - */ - -static CURLcode gopher_do(struct connectdata *conn, bool *done); - -/* - * Gopher protocol handler. - * This is also a nice simple template to build off for simple - * connect-command-download protocols. - */ - -const struct Curl_handler Curl_handler_gopher = { - "GOPHER", /* scheme */ - ZERO_NULL, /* setup_connection */ - gopher_do, /* do_it */ - ZERO_NULL, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_GOPHER, /* defport */ - CURLPROTO_GOPHER, /* protocol */ - PROTOPT_NONE /* flags */ -}; - -static CURLcode gopher_do(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - - curl_off_t *bytecount = &data->req.bytecount; - char *path = data->state.path; - char *sel = NULL; - char *sel_org = NULL; - ssize_t amount, k; - size_t len; - - *done = TRUE; /* unconditionally */ - - /* Create selector. Degenerate cases: / and /1 => convert to "" */ - if(strlen(path) <= 2) { - sel = (char *)""; - len = (int)strlen(sel); - } - else { - char *newp; - size_t j, i; - - /* Otherwise, drop / and the first character (i.e., item type) ... */ - newp = path; - newp += 2; - - /* ... then turn ? into TAB for search servers, Veronica, etc. ... */ - j = strlen(newp); - for(i = 0; i, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#ifndef CURL_DISABLE_GOPHER -extern const struct Curl_handler Curl_handler_gopher; -#endif - -#endif /* HEADER_CURL_GOPHER_H */ diff --git a/dep/cpr/opt/curl/lib/hash.c b/dep/cpr/opt/curl/lib/hash.c deleted file mode 100644 index c99b1b69948..00000000000 --- a/dep/cpr/opt/curl/lib/hash.c +++ /dev/null @@ -1,354 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "hash.h" -#include "llist.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -static void -hash_element_dtor(void *user, void *element) -{ - struct curl_hash *h = (struct curl_hash *) user; - struct curl_hash_element *e = (struct curl_hash_element *) element; - - if(e->ptr) { - h->dtor(e->ptr); - e->ptr = NULL; - } - - e->key_len = 0; - - free(e); -} - -/* Initializes a hash structure. - * Return 1 on error, 0 is fine. - * - * @unittest: 1602 - * @unittest: 1603 - */ -int -Curl_hash_init(struct curl_hash *h, - int slots, - hash_function hfunc, - comp_function comparator, - curl_hash_dtor dtor) -{ - int i; - - if(!slots || !hfunc || !comparator ||!dtor) { - return 1; /* failure */ - } - - h->hash_func = hfunc; - h->comp_func = comparator; - h->dtor = dtor; - h->size = 0; - h->slots = slots; - - h->table = malloc(slots * sizeof(struct curl_llist)); - if(h->table) { - for(i = 0; i < slots; ++i) - Curl_llist_init(&h->table[i], (curl_llist_dtor) hash_element_dtor); - return 0; /* fine */ - } - h->slots = 0; - return 1; /* failure */ -} - -static struct curl_hash_element * -mk_hash_element(const void *key, size_t key_len, const void *p) -{ - /* allocate the struct plus memory after it to store the key */ - struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element) + - key_len); - if(he) { - /* copy the key */ - memcpy(he->key, key, key_len); - he->key_len = key_len; - he->ptr = (void *) p; - } - return he; -} - -#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)] - -/* Insert the data in the hash. If there already was a match in the hash, - * that data is replaced. - * - * @unittest: 1305 - * @unittest: 1602 - * @unittest: 1603 - */ -void * -Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) -{ - struct curl_hash_element *he; - struct curl_llist_element *le; - struct curl_llist *l = FETCH_LIST(h, key, key_len); - - for(le = l->head; le; le = le->next) { - he = (struct curl_hash_element *) le->ptr; - if(h->comp_func(he->key, he->key_len, key, key_len)) { - Curl_llist_remove(l, le, (void *)h); - --h->size; - break; - } - } - - he = mk_hash_element(key, key_len, p); - if(he) { - Curl_llist_insert_next(l, l->tail, he, &he->list); - ++h->size; - return p; /* return the new entry */ - } - - return NULL; /* failure */ -} - -/* Remove the identified hash entry. - * Returns non-zero on failure. - * - * @unittest: 1603 - */ -int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len) -{ - struct curl_llist_element *le; - struct curl_hash_element *he; - struct curl_llist *l = FETCH_LIST(h, key, key_len); - - for(le = l->head; le; le = le->next) { - he = le->ptr; - if(h->comp_func(he->key, he->key_len, key, key_len)) { - Curl_llist_remove(l, le, (void *) h); - --h->size; - return 0; - } - } - return 1; -} - -/* Retrieves a hash element. - * - * @unittest: 1603 - */ -void * -Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len) -{ - struct curl_llist_element *le; - struct curl_hash_element *he; - struct curl_llist *l; - - if(h) { - l = FETCH_LIST(h, key, key_len); - for(le = l->head; le; le = le->next) { - he = le->ptr; - if(h->comp_func(he->key, he->key_len, key, key_len)) { - return he->ptr; - } - } - } - - return NULL; -} - -#if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST) -void -Curl_hash_apply(curl_hash *h, void *user, - void (*cb)(void *user, void *ptr)) -{ - struct curl_llist_element *le; - int i; - - for(i = 0; i < h->slots; ++i) { - for(le = (h->table[i])->head; - le; - le = le->next) { - curl_hash_element *el = le->ptr; - cb(user, el->ptr); - } - } -} -#endif - -/* Destroys all the entries in the given hash and resets its attributes, - * prepping the given hash for [static|dynamic] deallocation. - * - * @unittest: 1305 - * @unittest: 1602 - * @unittest: 1603 - */ -void -Curl_hash_destroy(struct curl_hash *h) -{ - int i; - - for(i = 0; i < h->slots; ++i) { - Curl_llist_destroy(&h->table[i], (void *) h); - } - - Curl_safefree(h->table); - h->size = 0; - h->slots = 0; -} - -/* Removes all the entries in the given hash. - * - * @unittest: 1602 - */ -void -Curl_hash_clean(struct curl_hash *h) -{ - Curl_hash_clean_with_criterium(h, NULL, NULL); -} - -/* Cleans all entries that pass the comp function criteria. */ -void -Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, - int (*comp)(void *, void *)) -{ - struct curl_llist_element *le; - struct curl_llist_element *lnext; - struct curl_llist *list; - int i; - - if(!h) - return; - - for(i = 0; i < h->slots; ++i) { - list = &h->table[i]; - le = list->head; /* get first list entry */ - while(le) { - struct curl_hash_element *he = le->ptr; - lnext = le->next; - /* ask the callback function if we shall remove this entry or not */ - if(comp == NULL || comp(user, he->ptr)) { - Curl_llist_remove(list, le, (void *) h); - --h->size; /* one less entry in the hash now */ - } - le = lnext; - } - } -} - -size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num) -{ - const char *key_str = (const char *) key; - const char *end = key_str + key_length; - unsigned long h = 5381; - - while(key_str < end) { - h += h << 5; - h ^= (unsigned long) *key_str++; - } - - return (h % slots_num); -} - -size_t Curl_str_key_compare(void *k1, size_t key1_len, - void *k2, size_t key2_len) -{ - if((key1_len == key2_len) && !memcmp(k1, k2, key1_len)) - return 1; - - return 0; -} - -void Curl_hash_start_iterate(struct curl_hash *hash, - struct curl_hash_iterator *iter) -{ - iter->hash = hash; - iter->slot_index = 0; - iter->current_element = NULL; -} - -struct curl_hash_element * -Curl_hash_next_element(struct curl_hash_iterator *iter) -{ - int i; - struct curl_hash *h = iter->hash; - - /* Get the next element in the current list, if any */ - if(iter->current_element) - iter->current_element = iter->current_element->next; - - /* If we have reached the end of the list, find the next one */ - if(!iter->current_element) { - for(i = iter->slot_index; i < h->slots; i++) { - if(h->table[i].head) { - iter->current_element = h->table[i].head; - iter->slot_index = i + 1; - break; - } - } - } - - if(iter->current_element) { - struct curl_hash_element *he = iter->current_element->ptr; - return he; - } - iter->current_element = NULL; - return NULL; -} - -#if 0 /* useful function for debugging hashes and their contents */ -void Curl_hash_print(struct curl_hash *h, - void (*func)(void *)) -{ - struct curl_hash_iterator iter; - struct curl_hash_element *he; - int last_index = -1; - - if(!h) - return; - - fprintf(stderr, "=Hash dump=\n"); - - Curl_hash_start_iterate(h, &iter); - - he = Curl_hash_next_element(&iter); - while(he) { - if(iter.slot_index != last_index) { - fprintf(stderr, "index %d:", iter.slot_index); - if(last_index >= 0) { - fprintf(stderr, "\n"); - } - last_index = iter.slot_index; - } - - if(func) - func(he->ptr); - else - fprintf(stderr, " [%p]", (void *)he->ptr); - - he = Curl_hash_next_element(&iter); - } - fprintf(stderr, "\n"); -} -#endif diff --git a/dep/cpr/opt/curl/lib/hash.h b/dep/cpr/opt/curl/lib/hash.h deleted file mode 100644 index 90a25d1ca3f..00000000000 --- a/dep/cpr/opt/curl/lib/hash.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef HEADER_CURL_HASH_H -#define HEADER_CURL_HASH_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "llist.h" - -/* Hash function prototype */ -typedef size_t (*hash_function) (void *key, - size_t key_length, - size_t slots_num); - -/* - Comparator function prototype. Compares two keys. -*/ -typedef size_t (*comp_function) (void *key1, - size_t key1_len, - void *key2, - size_t key2_len); - -typedef void (*curl_hash_dtor)(void *); - -struct curl_hash { - struct curl_llist *table; - - /* Hash function to be used for this hash table */ - hash_function hash_func; - - /* Comparator function to compare keys */ - comp_function comp_func; - curl_hash_dtor dtor; - int slots; - size_t size; -}; - -struct curl_hash_element { - struct curl_llist_element list; - void *ptr; - size_t key_len; - char key[1]; /* allocated memory following the struct */ -}; - -struct curl_hash_iterator { - struct curl_hash *hash; - int slot_index; - struct curl_llist_element *current_element; -}; - -int Curl_hash_init(struct curl_hash *h, - int slots, - hash_function hfunc, - comp_function comparator, - curl_hash_dtor dtor); - -void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p); -int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len); -void *Curl_hash_pick(struct curl_hash *, void *key, size_t key_len); -void Curl_hash_apply(struct curl_hash *h, void *user, - void (*cb)(void *user, void *ptr)); -int Curl_hash_count(struct curl_hash *h); -void Curl_hash_destroy(struct curl_hash *h); -void Curl_hash_clean(struct curl_hash *h); -void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, - int (*comp)(void *, void *)); -size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num); -size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2, - size_t key2_len); -void Curl_hash_start_iterate(struct curl_hash *hash, - struct curl_hash_iterator *iter); -struct curl_hash_element * -Curl_hash_next_element(struct curl_hash_iterator *iter); - -void Curl_hash_print(struct curl_hash *h, - void (*func)(void *)); - - -#endif /* HEADER_CURL_HASH_H */ diff --git a/dep/cpr/opt/curl/lib/hmac.c b/dep/cpr/opt/curl/lib/hmac.c deleted file mode 100644 index dae95054b0b..00000000000 --- a/dep/cpr/opt/curl/lib/hmac.c +++ /dev/null @@ -1,132 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC2104 Keyed-Hashing for Message Authentication - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_CRYPTO_AUTH - -#include - -#include "curl_hmac.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * Generic HMAC algorithm. - * - * This module computes HMAC digests based on any hash function. Parameters - * and computing procedures are set-up dynamically at HMAC computation - * context initialisation. - */ - -static const unsigned char hmac_ipad = 0x36; -static const unsigned char hmac_opad = 0x5C; - - - -HMAC_context * -Curl_HMAC_init(const HMAC_params * hashparams, - const unsigned char *key, - unsigned int keylen) -{ - size_t i; - HMAC_context *ctxt; - unsigned char *hkey; - unsigned char b; - - /* Create HMAC context. */ - i = sizeof *ctxt + 2 * hashparams->hmac_ctxtsize + - hashparams->hmac_resultlen; - ctxt = malloc(i); - - if(!ctxt) - return ctxt; - - ctxt->hmac_hash = hashparams; - ctxt->hmac_hashctxt1 = (void *) (ctxt + 1); - ctxt->hmac_hashctxt2 = (void *) ((char *) ctxt->hmac_hashctxt1 + - hashparams->hmac_ctxtsize); - - /* If the key is too long, replace it by its hash digest. */ - if(keylen > hashparams->hmac_maxkeylen) { - (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); - (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, key, keylen); - hkey = (unsigned char *) ctxt->hmac_hashctxt2 + hashparams->hmac_ctxtsize; - (*hashparams->hmac_hfinal)(hkey, ctxt->hmac_hashctxt1); - key = hkey; - keylen = hashparams->hmac_resultlen; - } - - /* Prime the two hash contexts with the modified key. */ - (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); - (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2); - - for(i = 0; i < keylen; i++) { - b = (unsigned char)(*key ^ hmac_ipad); - (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1); - b = (unsigned char)(*key++ ^ hmac_opad); - (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1); - } - - for(; i < hashparams->hmac_maxkeylen; i++) { - (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1); - (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1); - } - - /* Done, return pointer to HMAC context. */ - return ctxt; -} - -int Curl_HMAC_update(HMAC_context * ctxt, - const unsigned char *data, - unsigned int len) -{ - /* Update first hash calculation. */ - (*ctxt->hmac_hash->hmac_hupdate)(ctxt->hmac_hashctxt1, data, len); - return 0; -} - - -int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result) -{ - const HMAC_params * hashparams = ctxt->hmac_hash; - - /* Do not get result if called with a null parameter: only release - storage. */ - - if(!result) - result = (unsigned char *) ctxt->hmac_hashctxt2 + - ctxt->hmac_hash->hmac_ctxtsize; - - (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt1); - (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, - result, hashparams->hmac_resultlen); - (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt2); - free((char *) ctxt); - return 0; -} - -#endif /* CURL_DISABLE_CRYPTO_AUTH */ diff --git a/dep/cpr/opt/curl/lib/hostasyn.c b/dep/cpr/opt/curl/lib/hostasyn.c deleted file mode 100644 index 28bdf7a48ab..00000000000 --- a/dep/cpr/opt/curl/lib/hostasyn.c +++ /dev/null @@ -1,153 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/*********************************************************************** - * Only for builds using asynchronous name resolves - **********************************************************************/ -#ifdef CURLRES_ASYNCH - -/* - * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread() - * or getaddrinfo_thread() when we got the name resolved (or not!). - * - * If the status argument is CURL_ASYNC_SUCCESS, this function takes - * ownership of the Curl_addrinfo passed, storing the resolved data - * in the DNS cache. - * - * The storage operation locks and unlocks the DNS cache. - */ -CURLcode Curl_addrinfo_callback(struct connectdata *conn, - int status, - struct Curl_addrinfo *ai) -{ - struct Curl_dns_entry *dns = NULL; - CURLcode result = CURLE_OK; - - conn->async.status = status; - - if(CURL_ASYNC_SUCCESS == status) { - if(ai) { - struct Curl_easy *data = conn->data; - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - dns = Curl_cache_addr(data, ai, - conn->async.hostname, - conn->async.port); - if(!dns) { - /* failed to store, cleanup and return error */ - Curl_freeaddrinfo(ai); - result = CURLE_OUT_OF_MEMORY; - } - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - } - else { - result = CURLE_OUT_OF_MEMORY; - } - } - - conn->async.dns = dns; - - /* Set async.done TRUE last in this function since it may be used multi- - threaded and once this is TRUE the other thread may read fields from the - async struct */ - conn->async.done = TRUE; - - /* IPv4: The input hostent struct will be freed by ares when we return from - this function */ - return result; -} - -/* Call this function after Curl_connect() has returned async=TRUE and - then a successful name resolve has been received. - - Note: this function disconnects and frees the conn data in case of - resolve failure */ -CURLcode Curl_async_resolved(struct connectdata *conn, - bool *protocol_done) -{ - CURLcode result; - - if(conn->async.dns) { - conn->dns_entry = conn->async.dns; - conn->async.dns = NULL; - } - - result = Curl_setup_conn(conn, protocol_done); - - if(result) - /* We're not allowed to return failure with memory left allocated - in the connectdata struct, free those here */ - Curl_disconnect(conn, FALSE); /* close the connection */ - - return result; -} - -/* - * Curl_getaddrinfo() is the generic low-level name resolve API within this - * source file. There are several versions of this function - for different - * name resolve layers (selected at build-time). They all take this same set - * of arguments - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - return Curl_resolver_getaddrinfo(conn, hostname, port, waitp); -} - -#endif /* CURLRES_ASYNCH */ diff --git a/dep/cpr/opt/curl/lib/hostcheck.c b/dep/cpr/opt/curl/lib/hostcheck.c deleted file mode 100644 index 23dc3d2a7ce..00000000000 --- a/dep/cpr/opt/curl/lib/hostcheck.c +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_OPENSSL) \ - || defined(USE_AXTLS) \ - || defined(USE_GSKIT) \ - || (defined(USE_SCHANNEL) && defined(_WIN32_WCE)) -/* these backends use functions from this file */ - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include "hostcheck.h" -#include "strcase.h" -#include "inet_pton.h" - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * Match a hostname against a wildcard pattern. - * E.g. - * "foo.host.com" matches "*.host.com". - * - * We use the matching rule described in RFC6125, section 6.4.3. - * https://tools.ietf.org/html/rfc6125#section-6.4.3 - * - * In addition: ignore trailing dots in the host names and wildcards, so that - * the names are used normalized. This is what the browsers do. - * - * Do not allow wildcard matching on IP numbers. There are apparently - * certificates being used with an IP address in the CN field, thus making no - * apparent distinction between a name and an IP. We need to detect the use of - * an IP address and not wildcard match on such names. - * - * NOTE: hostmatch() gets called with copied buffers so that it can modify the - * contents at will. - */ - -static int hostmatch(char *hostname, char *pattern) -{ - const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; - int wildcard_enabled; - size_t prefixlen, suffixlen; - struct in_addr ignored; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 si6; -#endif - - /* normalize pattern and hostname by stripping off trailing dots */ - size_t len = strlen(hostname); - if(hostname[len-1]=='.') - hostname[len-1] = 0; - len = strlen(pattern); - if(pattern[len-1]=='.') - pattern[len-1] = 0; - - pattern_wildcard = strchr(pattern, '*'); - if(pattern_wildcard == NULL) - return strcasecompare(pattern, hostname) ? - CURL_HOST_MATCH : CURL_HOST_NOMATCH; - - /* detect IP address as hostname and fail the match if so */ - if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) - return CURL_HOST_NOMATCH; -#ifdef ENABLE_IPV6 - if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) - return CURL_HOST_NOMATCH; -#endif - - /* We require at least 2 dots in pattern to avoid too wide wildcard - match. */ - wildcard_enabled = 1; - pattern_label_end = strchr(pattern, '.'); - if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL || - pattern_wildcard > pattern_label_end || - strncasecompare(pattern, "xn--", 4)) { - wildcard_enabled = 0; - } - if(!wildcard_enabled) - return strcasecompare(pattern, hostname) ? - CURL_HOST_MATCH : CURL_HOST_NOMATCH; - - hostname_label_end = strchr(hostname, '.'); - if(hostname_label_end == NULL || - !strcasecompare(pattern_label_end, hostname_label_end)) - return CURL_HOST_NOMATCH; - - /* The wildcard must match at least one character, so the left-most - label of the hostname is at least as large as the left-most label - of the pattern. */ - if(hostname_label_end - hostname < pattern_label_end - pattern) - return CURL_HOST_NOMATCH; - - prefixlen = pattern_wildcard - pattern; - suffixlen = pattern_label_end - (pattern_wildcard + 1); - return strncasecompare(pattern, hostname, prefixlen) && - strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen, - suffixlen) ? - CURL_HOST_MATCH : CURL_HOST_NOMATCH; -} - -int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) -{ - char *matchp; - char *hostp; - int res = 0; - if(!match_pattern || !*match_pattern || - !hostname || !*hostname) /* sanity check */ - ; - else { - matchp = strdup(match_pattern); - if(matchp) { - hostp = strdup(hostname); - if(hostp) { - if(hostmatch(hostp, matchp) == CURL_HOST_MATCH) - res = 1; - free(hostp); - } - free(matchp); - } - } - - return res; -} - -#endif /* OPENSSL, AXTLS, GSKIT or schannel+wince */ diff --git a/dep/cpr/opt/curl/lib/hostcheck.h b/dep/cpr/opt/curl/lib/hostcheck.h deleted file mode 100644 index 86e3b96a977..00000000000 --- a/dep/cpr/opt/curl/lib/hostcheck.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef HEADER_CURL_HOSTCHECK_H -#define HEADER_CURL_HOSTCHECK_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -#define CURL_HOST_NOMATCH 0 -#define CURL_HOST_MATCH 1 -int Curl_cert_hostcheck(const char *match_pattern, const char *hostname); - -#endif /* HEADER_CURL_HOSTCHECK_H */ - diff --git a/dep/cpr/opt/curl/lib/hostip.c b/dep/cpr/opt/curl/lib/hostip.c deleted file mode 100644 index 1a18a3ed79e..00000000000 --- a/dep/cpr/opt/curl/lib/hostip.c +++ /dev/null @@ -1,884 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif -#ifdef HAVE_SIGNAL_H -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "inet_ntop.h" -#include "warnless.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#if defined(CURLRES_SYNCH) && \ - defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP) -/* alarm-based timeouts can only be used with all the dependencies satisfied */ -#define USE_ALARM_TIMEOUT -#endif - -/* - * hostip.c explained - * ================== - * - * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c - * source file are these: - * - * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use - * that. The host may not be able to resolve IPv6, but we don't really have to - * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4 - * defined. - * - * CURLRES_ARES - is defined if libcurl is built to use c-ares for - * asynchronous name resolves. This can be Windows or *nix. - * - * CURLRES_THREADED - is defined if libcurl is built to run under (native) - * Windows, and then the name resolve will be done in a new thread, and the - * supported API will be the same as for ares-builds. - * - * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If - * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is - * defined. - * - * The host*.c sources files are split up like this: - * - * hostip.c - method-independent resolver functions and utility functions - * hostasyn.c - functions for asynchronous name resolves - * hostsyn.c - functions for synchronous name resolves - * hostip4.c - IPv4 specific functions - * hostip6.c - IPv6 specific functions - * - * The two asynchronous name resolver backends are implemented in: - * asyn-ares.c - functions for ares-using name resolves - * asyn-thread.c - functions for threaded name resolves - - * The hostip.h is the united header file for all this. It defines the - * CURLRES_* defines based on the config*.h and curl_setup.h defines. - */ - -/* These two symbols are for the global DNS cache */ -static struct curl_hash hostname_cache; -static int host_cache_initialized; - -static void freednsentry(void *freethis); - -/* - * Curl_global_host_cache_init() initializes and sets up a global DNS cache. - * Global DNS cache is general badness. Do not use. This will be removed in - * a future version. Use the share interface instead! - * - * Returns a struct curl_hash pointer on success, NULL on failure. - */ -struct curl_hash *Curl_global_host_cache_init(void) -{ - int rc = 0; - if(!host_cache_initialized) { - rc = Curl_hash_init(&hostname_cache, 7, Curl_hash_str, - Curl_str_key_compare, freednsentry); - if(!rc) - host_cache_initialized = 1; - } - return rc?NULL:&hostname_cache; -} - -/* - * Destroy and cleanup the global DNS cache - */ -void Curl_global_host_cache_dtor(void) -{ - if(host_cache_initialized) { - Curl_hash_destroy(&hostname_cache); - host_cache_initialized = 0; - } -} - -/* - * Return # of addresses in a Curl_addrinfo struct - */ -int Curl_num_addresses(const Curl_addrinfo *addr) -{ - int i = 0; - while(addr) { - addr = addr->ai_next; - i++; - } - return i; -} - -/* - * Curl_printable_address() returns a printable version of the 1st address - * given in the 'ai' argument. The result will be stored in the buf that is - * bufsize bytes big. - * - * If the conversion fails, it returns NULL. - */ -const char * -Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize) -{ - const struct sockaddr_in *sa4; - const struct in_addr *ipaddr4; -#ifdef ENABLE_IPV6 - const struct sockaddr_in6 *sa6; - const struct in6_addr *ipaddr6; -#endif - - switch(ai->ai_family) { - case AF_INET: - sa4 = (const void *)ai->ai_addr; - ipaddr4 = &sa4->sin_addr; - return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, - bufsize); -#ifdef ENABLE_IPV6 - case AF_INET6: - sa6 = (const void *)ai->ai_addr; - ipaddr6 = &sa6->sin6_addr; - return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, - bufsize); -#endif - default: - break; - } - return NULL; -} - -/* - * Return a hostcache id string for the provided host + port, to be used by - * the DNS caching. - */ -static char * -create_hostcache_id(const char *name, int port) -{ - /* create and return the new allocated entry */ - char *id = aprintf("%s:%d", name, port); - char *ptr = id; - if(ptr) { - /* lower case the name part */ - while(*ptr && (*ptr != ':')) { - *ptr = (char)TOLOWER(*ptr); - ptr++; - } - } - return id; -} - -struct hostcache_prune_data { - long cache_timeout; - time_t now; -}; - -/* - * This function is set as a callback to be called for every entry in the DNS - * cache when we want to prune old unused entries. - * - * Returning non-zero means remove the entry, return 0 to keep it in the - * cache. - */ -static int -hostcache_timestamp_remove(void *datap, void *hc) -{ - struct hostcache_prune_data *data = - (struct hostcache_prune_data *) datap; - struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; - - return (0 != c->timestamp) - && (data->now - c->timestamp >= data->cache_timeout); -} - -/* - * Prune the DNS cache. This assumes that a lock has already been taken. - */ -static void -hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now) -{ - struct hostcache_prune_data user; - - user.cache_timeout = cache_timeout; - user.now = now; - - Curl_hash_clean_with_criterium(hostcache, - (void *) &user, - hostcache_timestamp_remove); -} - -/* - * Library-wide function for pruning the DNS cache. This function takes and - * returns the appropriate locks. - */ -void Curl_hostcache_prune(struct Curl_easy *data) -{ - time_t now; - - if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache) - /* cache forever means never prune, and NULL hostcache means - we can't do it */ - return; - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - time(&now); - - /* Remove outdated and unused entries from the hostcache */ - hostcache_prune(data->dns.hostcache, - data->set.dns_cache_timeout, - now); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); -} - -#ifdef HAVE_SIGSETJMP -/* Beware this is a global and unique instance. This is used to store the - return address that we can jump back to from inside a signal handler. This - is not thread-safe stuff. */ -sigjmp_buf curl_jmpenv; -#endif - -/* lookup address, returns entry if found and not stale */ -static struct Curl_dns_entry * -fetch_addr(struct connectdata *conn, - const char *hostname, - int port) -{ - char *entry_id = NULL; - struct Curl_dns_entry *dns = NULL; - size_t entry_len; - struct Curl_easy *data = conn->data; - - /* Create an entry id, based upon the hostname and port */ - entry_id = create_hostcache_id(hostname, port); - /* If we can't create the entry id, fail */ - if(!entry_id) - return dns; - - entry_len = strlen(entry_id); - - /* See if its already in our dns cache */ - dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); - - if(dns && (data->set.dns_cache_timeout != -1)) { - /* See whether the returned entry is stale. Done before we release lock */ - struct hostcache_prune_data user; - - time(&user.now); - user.cache_timeout = data->set.dns_cache_timeout; - - if(hostcache_timestamp_remove(&user, dns)) { - infof(data, "Hostname in DNS cache was stale, zapped\n"); - dns = NULL; /* the memory deallocation is being handled by the hash */ - Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); - } - } - - /* free the allocated entry_id again */ - free(entry_id); - - return dns; -} - -/* - * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. - * - * Curl_resolv() checks initially and multi_runsingle() checks each time - * it discovers the handle in the state WAITRESOLVE whether the hostname - * has already been resolved and the address has already been stored in - * the DNS cache. This short circuits waiting for a lot of pending - * lookups for the same hostname requested by different handles. - * - * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. - * - * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after - * use, or we'll leak memory! - */ -struct Curl_dns_entry * -Curl_fetch_addr(struct connectdata *conn, - const char *hostname, - int port) -{ - struct Curl_easy *data = conn->data; - struct Curl_dns_entry *dns = NULL; - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - dns = fetch_addr(conn, hostname, port); - - if(dns) - dns->inuse++; /* we use it! */ - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - - return dns; -} - -/* - * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. - * - * When calling Curl_resolv() has resulted in a response with a returned - * address, we call this function to store the information in the dns - * cache etc - * - * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. - */ -struct Curl_dns_entry * -Curl_cache_addr(struct Curl_easy *data, - Curl_addrinfo *addr, - const char *hostname, - int port) -{ - char *entry_id; - size_t entry_len; - struct Curl_dns_entry *dns; - struct Curl_dns_entry *dns2; - - /* Create an entry id, based upon the hostname and port */ - entry_id = create_hostcache_id(hostname, port); - /* If we can't create the entry id, fail */ - if(!entry_id) - return NULL; - entry_len = strlen(entry_id); - - /* Create a new cache entry */ - dns = calloc(1, sizeof(struct Curl_dns_entry)); - if(!dns) { - free(entry_id); - return NULL; - } - - dns->inuse = 1; /* the cache has the first reference */ - dns->addr = addr; /* this is the address(es) */ - time(&dns->timestamp); - if(dns->timestamp == 0) - dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */ - - /* Store the resolved data in our DNS cache. */ - dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1, - (void *)dns); - if(!dns2) { - free(dns); - free(entry_id); - return NULL; - } - - dns = dns2; - dns->inuse++; /* mark entry as in-use */ - - /* free the allocated entry_id */ - free(entry_id); - - return dns; -} - -/* - * Curl_resolv() is the main name resolve function within libcurl. It resolves - * a name and returns a pointer to the entry in the 'entry' argument (if one - * is provided). This function might return immediately if we're using asynch - * resolves. See the return codes. - * - * The cache entry we return will get its 'inuse' counter increased when this - * function is used. You MUST call Curl_resolv_unlock() later (when you're - * done using this struct) to decrease the counter again. - * - * In debug mode, we specifically test for an interface name "LocalHost" - * and resolve "localhost" instead as a means to permit test cases - * to connect to a local test server with any host name. - * - * Return codes: - * - * CURLRESOLV_ERROR (-1) = error, no pointer - * CURLRESOLV_RESOLVED (0) = OK, pointer provided - * CURLRESOLV_PENDING (1) = waiting for response, no pointer - */ - -int Curl_resolv(struct connectdata *conn, - const char *hostname, - int port, - struct Curl_dns_entry **entry) -{ - struct Curl_dns_entry *dns = NULL; - struct Curl_easy *data = conn->data; - CURLcode result; - int rc = CURLRESOLV_ERROR; /* default to failure */ - - *entry = NULL; - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - dns = fetch_addr(conn, hostname, port); - - if(dns) { - infof(data, "Hostname %s was found in DNS cache\n", hostname); - dns->inuse++; /* we use it! */ - rc = CURLRESOLV_RESOLVED; - } - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - - if(!dns) { - /* The entry was not in the cache. Resolve it to IP address */ - - Curl_addrinfo *addr; - int respwait; - - /* Check what IP specifics the app has requested and if we can provide it. - * If not, bail out. */ - if(!Curl_ipvalid(conn)) - return CURLRESOLV_ERROR; - - /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a - non-zero value indicating that we need to wait for the response to the - resolve call */ - addr = Curl_getaddrinfo(conn, -#ifdef DEBUGBUILD - (data->set.str[STRING_DEVICE] - && !strcmp(data->set.str[STRING_DEVICE], - "LocalHost"))?"localhost": -#endif - hostname, port, &respwait); - - if(!addr) { - if(respwait) { - /* the response to our resolve call will come asynchronously at - a later time, good or bad */ - /* First, check that we haven't received the info by now */ - result = Curl_resolver_is_resolved(conn, &dns); - if(result) /* error detected */ - return CURLRESOLV_ERROR; - if(dns) - rc = CURLRESOLV_RESOLVED; /* pointer provided */ - else - rc = CURLRESOLV_PENDING; /* no info yet */ - } - } - else { - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - /* we got a response, store it in the cache */ - dns = Curl_cache_addr(data, addr, hostname, port); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - - if(!dns) - /* returned failure, bail out nicely */ - Curl_freeaddrinfo(addr); - else - rc = CURLRESOLV_RESOLVED; - } - } - - *entry = dns; - - return rc; -} - -#ifdef USE_ALARM_TIMEOUT -/* - * This signal handler jumps back into the main libcurl code and continues - * execution. This effectively causes the remainder of the application to run - * within a signal handler which is nonportable and could lead to problems. - */ -static -RETSIGTYPE alarmfunc(int sig) -{ - /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ - (void)sig; - siglongjmp(curl_jmpenv, 1); -} -#endif /* USE_ALARM_TIMEOUT */ - -/* - * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a - * timeout. This function might return immediately if we're using asynch - * resolves. See the return codes. - * - * The cache entry we return will get its 'inuse' counter increased when this - * function is used. You MUST call Curl_resolv_unlock() later (when you're - * done using this struct) to decrease the counter again. - * - * If built with a synchronous resolver and use of signals is not - * disabled by the application, then a nonzero timeout will cause a - * timeout after the specified number of milliseconds. Otherwise, timeout - * is ignored. - * - * Return codes: - * - * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired - * CURLRESOLV_ERROR (-1) = error, no pointer - * CURLRESOLV_RESOLVED (0) = OK, pointer provided - * CURLRESOLV_PENDING (1) = waiting for response, no pointer - */ - -int Curl_resolv_timeout(struct connectdata *conn, - const char *hostname, - int port, - struct Curl_dns_entry **entry, - time_t timeoutms) -{ -#ifdef USE_ALARM_TIMEOUT -#ifdef HAVE_SIGACTION - struct sigaction keep_sigact; /* store the old struct here */ - volatile bool keep_copysig = FALSE; /* whether old sigact has been saved */ - struct sigaction sigact; -#else -#ifdef HAVE_SIGNAL - void (*keep_sigact)(int); /* store the old handler here */ -#endif /* HAVE_SIGNAL */ -#endif /* HAVE_SIGACTION */ - volatile long timeout; - volatile unsigned int prev_alarm = 0; - struct Curl_easy *data = conn->data; -#endif /* USE_ALARM_TIMEOUT */ - int rc; - - *entry = NULL; - - if(timeoutms < 0) - /* got an already expired timeout */ - return CURLRESOLV_TIMEDOUT; - -#ifdef USE_ALARM_TIMEOUT - if(data->set.no_signal) - /* Ignore the timeout when signals are disabled */ - timeout = 0; - else - timeout = (timeoutms > LONG_MAX) ? LONG_MAX : (long)timeoutms; - - if(!timeout) - /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */ - return Curl_resolv(conn, hostname, port, entry); - - if(timeout < 1000) { - /* The alarm() function only provides integer second resolution, so if - we want to wait less than one second we must bail out already now. */ - failf(data, - "remaining timeout of %ld too small to resolve via SIGALRM method", - timeout); - return CURLRESOLV_TIMEDOUT; - } - /* This allows us to time-out from the name resolver, as the timeout - will generate a signal and we will siglongjmp() from that here. - This technique has problems (see alarmfunc). - This should be the last thing we do before calling Curl_resolv(), - as otherwise we'd have to worry about variables that get modified - before we invoke Curl_resolv() (and thus use "volatile"). */ - if(sigsetjmp(curl_jmpenv, 1)) { - /* this is coming from a siglongjmp() after an alarm signal */ - failf(data, "name lookup timed out"); - rc = CURLRESOLV_ERROR; - goto clean_up; - } - else { - /************************************************************* - * Set signal handler to catch SIGALRM - * Store the old value to be able to set it back later! - *************************************************************/ -#ifdef HAVE_SIGACTION - sigaction(SIGALRM, NULL, &sigact); - keep_sigact = sigact; - keep_copysig = TRUE; /* yes, we have a copy */ - sigact.sa_handler = alarmfunc; -#ifdef SA_RESTART - /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ - sigact.sa_flags &= ~SA_RESTART; -#endif - /* now set the new struct */ - sigaction(SIGALRM, &sigact, NULL); -#else /* HAVE_SIGACTION */ - /* no sigaction(), revert to the much lamer signal() */ -#ifdef HAVE_SIGNAL - keep_sigact = signal(SIGALRM, alarmfunc); -#endif -#endif /* HAVE_SIGACTION */ - - /* alarm() makes a signal get sent when the timeout fires off, and that - will abort system calls */ - prev_alarm = alarm(curlx_sltoui(timeout/1000L)); - } - -#else -#ifndef CURLRES_ASYNCH - if(timeoutms) - infof(conn->data, "timeout on name lookup is not supported\n"); -#else - (void)timeoutms; /* timeoutms not used with an async resolver */ -#endif -#endif /* USE_ALARM_TIMEOUT */ - - /* Perform the actual name resolution. This might be interrupted by an - * alarm if it takes too long. - */ - rc = Curl_resolv(conn, hostname, port, entry); - -#ifdef USE_ALARM_TIMEOUT -clean_up: - - if(!prev_alarm) - /* deactivate a possibly active alarm before uninstalling the handler */ - alarm(0); - -#ifdef HAVE_SIGACTION - if(keep_copysig) { - /* we got a struct as it looked before, now put that one back nice - and clean */ - sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */ - } -#else -#ifdef HAVE_SIGNAL - /* restore the previous SIGALRM handler */ - signal(SIGALRM, keep_sigact); -#endif -#endif /* HAVE_SIGACTION */ - - /* switch back the alarm() to either zero or to what it was before minus - the time we spent until now! */ - if(prev_alarm) { - /* there was an alarm() set before us, now put it back */ - unsigned long elapsed_secs = (unsigned long) (Curl_tvdiff(Curl_tvnow(), - conn->created) / 1000); - - /* the alarm period is counted in even number of seconds */ - unsigned long alarm_set = prev_alarm - elapsed_secs; - - if(!alarm_set || - ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) { - /* if the alarm time-left reached zero or turned "negative" (counted - with unsigned values), we should fire off a SIGALRM here, but we - won't, and zero would be to switch it off so we never set it to - less than 1! */ - alarm(1); - rc = CURLRESOLV_TIMEDOUT; - failf(data, "Previous alarm fired off!"); - } - else - alarm((unsigned int)alarm_set); - } -#endif /* USE_ALARM_TIMEOUT */ - - return rc; -} - -/* - * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been - * made, the struct may be destroyed due to pruning. It is important that only - * one unlock is made for each Curl_resolv() call. - * - * May be called with 'data' == NULL for global cache. - */ -void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) -{ - if(data && data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - freednsentry(dns); - - if(data && data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); -} - -/* - * File-internal: release cache dns entry reference, free if inuse drops to 0 - */ -static void freednsentry(void *freethis) -{ - struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis; - DEBUGASSERT(dns && (dns->inuse>0)); - - dns->inuse--; - if(dns->inuse == 0) { - Curl_freeaddrinfo(dns->addr); - free(dns); - } -} - -/* - * Curl_mk_dnscache() inits a new DNS cache and returns success/failure. - */ -int Curl_mk_dnscache(struct curl_hash *hash) -{ - return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, - freednsentry); -} - -/* - * Curl_hostcache_clean() - * - * This _can_ be called with 'data' == NULL but then of course no locking - * can be done! - */ - -void Curl_hostcache_clean(struct Curl_easy *data, - struct curl_hash *hash) -{ - if(data && data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - Curl_hash_clean(hash); - - if(data && data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); -} - - -CURLcode Curl_loadhostpairs(struct Curl_easy *data) -{ - struct curl_slist *hostp; - char hostname[256]; - char address[256]; - int port; - - for(hostp = data->change.resolve; hostp; hostp = hostp->next) { - if(!hostp->data) - continue; - if(hostp->data[0] == '-') { - char *entry_id; - size_t entry_len; - - if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) { - infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n", - hostp->data); - continue; - } - - /* Create an entry id, based upon the hostname and port */ - entry_id = create_hostcache_id(hostname, port); - /* If we can't create the entry id, fail */ - if(!entry_id) { - return CURLE_OUT_OF_MEMORY; - } - - entry_len = strlen(entry_id); - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - /* delete entry, ignore if it didn't exist */ - Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - - /* free the allocated entry_id again */ - free(entry_id); - } - else { - struct Curl_dns_entry *dns; - Curl_addrinfo *addr; - char *entry_id; - size_t entry_len; - - if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port, - address)) { - infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n", - hostp->data); - continue; - } - - addr = Curl_str2addr(address, port); - if(!addr) { - infof(data, "Address in '%s' found illegal!\n", hostp->data); - continue; - } - - /* Create an entry id, based upon the hostname and port */ - entry_id = create_hostcache_id(hostname, port); - /* If we can't create the entry id, fail */ - if(!entry_id) { - Curl_freeaddrinfo(addr); - return CURLE_OUT_OF_MEMORY; - } - - entry_len = strlen(entry_id); - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - /* See if its already in our dns cache */ - dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); - - /* free the allocated entry_id again */ - free(entry_id); - - if(!dns) { - /* if not in the cache already, put this host in the cache */ - dns = Curl_cache_addr(data, addr, hostname, port); - if(dns) { - dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */ - /* release the returned reference; the cache itself will keep the - * entry alive: */ - dns->inuse--; - } - } - else - /* this is a duplicate, free it again */ - Curl_freeaddrinfo(addr); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - - if(!dns) { - Curl_freeaddrinfo(addr); - return CURLE_OUT_OF_MEMORY; - } - infof(data, "Added %s:%d:%s to DNS cache\n", - hostname, port, address); - } - } - data->change.resolve = NULL; /* dealt with now */ - - return CURLE_OK; -} diff --git a/dep/cpr/opt/curl/lib/hostip.h b/dep/cpr/opt/curl/lib/hostip.h deleted file mode 100644 index 298eeeee3b3..00000000000 --- a/dep/cpr/opt/curl/lib/hostip.h +++ /dev/null @@ -1,250 +0,0 @@ -#ifndef HEADER_CURL_HOSTIP_H -#define HEADER_CURL_HOSTIP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" -#include "hash.h" -#include "curl_addrinfo.h" -#include "asyn.h" - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifdef NETWARE -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -/* Allocate enough memory to hold the full name information structs and - * everything. OSF1 is known to require at least 8872 bytes. The buffer - * required for storing all possible aliases and IP numbers is according to - * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes! - */ -#define CURL_HOSTENT_SIZE 9000 - -#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this - many seconds for a name resolve */ - -#define CURL_ASYNC_SUCCESS CURLE_OK - -struct addrinfo; -struct hostent; -struct Curl_easy; -struct connectdata; - -/* - * Curl_global_host_cache_init() initializes and sets up a global DNS cache. - * Global DNS cache is general badness. Do not use. This will be removed in - * a future version. Use the share interface instead! - * - * Returns a struct curl_hash pointer on success, NULL on failure. - */ -struct curl_hash *Curl_global_host_cache_init(void); -void Curl_global_host_cache_dtor(void); - -struct Curl_dns_entry { - Curl_addrinfo *addr; - /* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */ - time_t timestamp; - /* use-counter, use Curl_resolv_unlock to release reference */ - long inuse; -}; - -/* - * Curl_resolv() returns an entry with the info for the specified host - * and port. - * - * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after - * use, or we'll leak memory! - */ -/* return codes */ -#define CURLRESOLV_TIMEDOUT -2 -#define CURLRESOLV_ERROR -1 -#define CURLRESOLV_RESOLVED 0 -#define CURLRESOLV_PENDING 1 -int Curl_resolv(struct connectdata *conn, const char *hostname, - int port, struct Curl_dns_entry **dnsentry); -int Curl_resolv_timeout(struct connectdata *conn, const char *hostname, - int port, struct Curl_dns_entry **dnsentry, - time_t timeoutms); - -#ifdef CURLRES_IPV6 -/* - * Curl_ipv6works() returns TRUE if IPv6 seems to work. - */ -bool Curl_ipv6works(void); -#else -#define Curl_ipv6works() FALSE -#endif - -/* - * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've - * been set and returns TRUE if they are OK. - */ -bool Curl_ipvalid(struct connectdata *conn); - - -/* - * Curl_getaddrinfo() is the generic low-level name resolve API within this - * source file. There are several versions of this function - for different - * name resolve layers (selected at build-time). They all take this same set - * of arguments - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp); - - -/* unlock a previously resolved dns entry */ -void Curl_resolv_unlock(struct Curl_easy *data, - struct Curl_dns_entry *dns); - -/* for debugging purposes only: */ -void Curl_scan_cache_used(void *user, void *ptr); - -/* init a new dns cache and return success */ -int Curl_mk_dnscache(struct curl_hash *hash); - -/* prune old entries from the DNS cache */ -void Curl_hostcache_prune(struct Curl_easy *data); - -/* Return # of addresses in a Curl_addrinfo struct */ -int Curl_num_addresses(const Curl_addrinfo *addr); - -#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) -int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, - GETNAMEINFO_TYPE_ARG2 salen, - char *host, GETNAMEINFO_TYPE_ARG46 hostlen, - char *serv, GETNAMEINFO_TYPE_ARG46 servlen, - GETNAMEINFO_TYPE_ARG7 flags, - int line, const char *source); -#endif - -/* IPv4 threadsafe resolve function used for synch and asynch builds */ -Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port); - -CURLcode Curl_async_resolved(struct connectdata *conn, - bool *protocol_connect); - -#ifndef CURLRES_ASYNCH -#define Curl_async_resolved(x,y) CURLE_OK -#endif - -/* - * Curl_addrinfo_callback() is used when we build with any asynch specialty. - * Handles end of async request processing. Inserts ai into hostcache when - * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async - * request completed whether successful or failed. - */ -CURLcode Curl_addrinfo_callback(struct connectdata *conn, - int status, - Curl_addrinfo *ai); - -/* - * Curl_printable_address() returns a printable version of the 1st address - * given in the 'ip' argument. The result will be stored in the buf that is - * bufsize bytes big. - */ -const char *Curl_printable_address(const Curl_addrinfo *ip, - char *buf, size_t bufsize); - -/* - * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. - * - * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. - * - * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after - * use, or we'll leak memory! - */ -struct Curl_dns_entry * -Curl_fetch_addr(struct connectdata *conn, - const char *hostname, - int port); -/* - * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. - * - * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. - */ -struct Curl_dns_entry * -Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr, - const char *hostname, int port); - -#ifndef INADDR_NONE -#define CURL_INADDR_NONE (in_addr_t) ~0 -#else -#define CURL_INADDR_NONE INADDR_NONE -#endif - -#ifdef HAVE_SIGSETJMP -/* Forward-declaration of variable defined in hostip.c. Beware this - * is a global and unique instance. This is used to store the return - * address that we can jump back to from inside a signal handler. - * This is not thread-safe stuff. - */ -extern sigjmp_buf curl_jmpenv; -#endif - -/* - * Function provided by the resolver backend to set DNS servers to use. - */ -CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers); - -/* - * Function provided by the resolver backend to set - * outgoing interface to use for DNS requests - */ -CURLcode Curl_set_dns_interface(struct Curl_easy *data, - const char *interf); - -/* - * Function provided by the resolver backend to set - * local IPv4 address to use as source address for DNS requests - */ -CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, - const char *local_ip4); - -/* - * Function provided by the resolver backend to set - * local IPv6 address to use as source address for DNS requests - */ -CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, - const char *local_ip6); - -/* - * Clean off entries from the cache - */ -void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash); - -/* - * Destroy the hostcache of this handle. - */ -void Curl_hostcache_destroy(struct Curl_easy *data); - -/* - * Populate the cache with specified entries from CURLOPT_RESOLVE. - */ -CURLcode Curl_loadhostpairs(struct Curl_easy *data); - -#endif /* HEADER_CURL_HOSTIP_H */ diff --git a/dep/cpr/opt/curl/lib/hostip4.c b/dep/cpr/opt/curl/lib/hostip4.c deleted file mode 100644 index 6a7c6e57677..00000000000 --- a/dep/cpr/opt/curl/lib/hostip4.c +++ /dev/null @@ -1,307 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "inet_pton.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/*********************************************************************** - * Only for plain IPv4 builds - **********************************************************************/ -#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */ -/* - * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've - * been set and returns TRUE if they are OK. - */ -bool Curl_ipvalid(struct connectdata *conn) -{ - if(conn->ip_version == CURL_IPRESOLVE_V6) - /* An IPv6 address was requested and we can't get/use one */ - return FALSE; - - return TRUE; /* OK, proceed */ -} - -#ifdef CURLRES_SYNCH - -/* - * Curl_getaddrinfo() - the IPv4 synchronous version. - * - * The original code to this function was from the Dancer source code, written - * by Bjorn Reese, it has since been patched and modified considerably. - * - * gethostbyname_r() is the thread-safe version of the gethostbyname() - * function. When we build for plain IPv4, we attempt to use this - * function. There are _three_ different gethostbyname_r() versions, and we - * detect which one this platform supports in the configure script and set up - * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or - * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME - * has the corresponding rules. This is primarily on *nix. Note that some unix - * flavours have thread-safe versions of the plain gethostbyname() etc. - * - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - Curl_addrinfo *ai = NULL; - -#ifdef CURL_DISABLE_VERBOSE_STRINGS - (void)conn; -#endif - - *waitp = 0; /* synchronous response only */ - - ai = Curl_ipv4_resolve_r(hostname, port); - if(!ai) - infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname); - - return ai; -} -#endif /* CURLRES_SYNCH */ -#endif /* CURLRES_IPV4 */ - -#if defined(CURLRES_IPV4) && !defined(CURLRES_ARES) - -/* - * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function. - * - * This is used for both synchronous and asynchronous resolver builds, - * implying that only threadsafe code and function calls may be used. - * - */ -Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, - int port) -{ -#if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3) - int res; -#endif - Curl_addrinfo *ai = NULL; - struct hostent *h = NULL; - struct in_addr in; - struct hostent *buf = NULL; - - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - -#if defined(HAVE_GETADDRINFO_THREADSAFE) - else { - struct addrinfo hints; - char sbuf[12]; - char *sbufptr = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET; - hints.ai_socktype = SOCK_STREAM; - if(port) { - snprintf(sbuf, sizeof(sbuf), "%d", port); - sbufptr = sbuf; - } - - (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai); - -#elif defined(HAVE_GETHOSTBYNAME_R) - /* - * gethostbyname_r() is the preferred resolve function for many platforms. - * Since there are three different versions of it, the following code is - * somewhat #ifdef-ridden. - */ - else { - int h_errnop; - - buf = calloc(1, CURL_HOSTENT_SIZE); - if(!buf) - return NULL; /* major failure */ - /* - * The clearing of the buffer is a workaround for a gethostbyname_r bug in - * qnx nto and it is also _required_ for some of these functions on some - * platforms. - */ - -#if defined(HAVE_GETHOSTBYNAME_R_5) - /* Solaris, IRIX and more */ - h = gethostbyname_r(hostname, - (struct hostent *)buf, - (char *)buf + sizeof(struct hostent), - CURL_HOSTENT_SIZE - sizeof(struct hostent), - &h_errnop); - - /* If the buffer is too small, it returns NULL and sets errno to - * ERANGE. The errno is thread safe if this is compiled with - * -D_REENTRANT as then the 'errno' variable is a macro defined to get - * used properly for threads. - */ - - if(h) { - ; - } - else -#elif defined(HAVE_GETHOSTBYNAME_R_6) - /* Linux */ - - (void)gethostbyname_r(hostname, - (struct hostent *)buf, - (char *)buf + sizeof(struct hostent), - CURL_HOSTENT_SIZE - sizeof(struct hostent), - &h, /* DIFFERENCE */ - &h_errnop); - /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a - * sudden this function returns EAGAIN if the given buffer size is too - * small. Previous versions are known to return ERANGE for the same - * problem. - * - * This wouldn't be such a big problem if older versions wouldn't - * sometimes return EAGAIN on a common failure case. Alas, we can't - * assume that EAGAIN *or* ERANGE means ERANGE for any given version of - * glibc. - * - * For now, we do that and thus we may call the function repeatedly and - * fail for older glibc versions that return EAGAIN, until we run out of - * buffer size (step_size grows beyond CURL_HOSTENT_SIZE). - * - * If anyone has a better fix, please tell us! - * - * ------------------------------------------------------------------- - * - * On October 23rd 2003, Dan C dug up more details on the mysteries of - * gethostbyname_r() in glibc: - * - * In glibc 2.2.5 the interface is different (this has also been - * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't - * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32 - * (shipped/upgraded by Redhat 7.2) don't show this behavior! - * - * In this "buggy" version, the return code is -1 on error and 'errno' - * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a - * thread-safe variable. - */ - - if(!h) /* failure */ -#elif defined(HAVE_GETHOSTBYNAME_R_3) - /* AIX, Digital Unix/Tru64, HPUX 10, more? */ - - /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of - * the plain fact that it does not return unique full buffers on each - * call, but instead several of the pointers in the hostent structs will - * point to the same actual data! This have the unfortunate down-side that - * our caching system breaks down horribly. Luckily for us though, AIX 4.3 - * and more recent versions have a "completely thread-safe"[*] libc where - * all the data is stored in thread-specific memory areas making calls to - * the plain old gethostbyname() work fine even for multi-threaded - * programs. - * - * This AIX 4.3 or later detection is all made in the configure script. - * - * Troels Walsted Hansen helped us work this out on March 3rd, 2003. - * - * [*] = much later we've found out that it isn't at all "completely - * thread-safe", but at least the gethostbyname() function is. - */ - - if(CURL_HOSTENT_SIZE >= - (sizeof(struct hostent) + sizeof(struct hostent_data))) { - - /* August 22nd, 2000: Albert Chin-A-Young brought an updated version - * that should work! September 20: Richard Prescott worked on the buffer - * size dilemma. - */ - - res = gethostbyname_r(hostname, - (struct hostent *)buf, - (struct hostent_data *)((char *)buf + - sizeof(struct hostent))); - h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */ - } - else - res = -1; /* failure, too smallish buffer size */ - - if(!res) { /* success */ - - h = buf; /* result expected in h */ - - /* This is the worst kind of the different gethostbyname_r() interfaces. - * Since we don't know how big buffer this particular lookup required, - * we can't realloc down the huge alloc without doing closer analysis of - * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every - * name lookup. Fixing this would require an extra malloc() and then - * calling Curl_addrinfo_copy() that subsequent realloc()s down the new - * memory area to the actually used amount. - */ - } - else -#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */ - { - h = NULL; /* set return code to NULL */ - free(buf); - } -#else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */ - /* - * Here is code for platforms that don't have a thread safe - * getaddrinfo() nor gethostbyname_r() function or for which - * gethostbyname() is the preferred one. - */ - else { - h = gethostbyname((void *)hostname); -#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */ - } - - if(h) { - ai = Curl_he2ai(h, port); - - if(buf) /* used a *_r() function */ - free(buf); - } - - return ai; -} -#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */ diff --git a/dep/cpr/opt/curl/lib/hostip6.c b/dep/cpr/opt/curl/lib/hostip6.c deleted file mode 100644 index edeebec9e2d..00000000000 --- a/dep/cpr/opt/curl/lib/hostip6.c +++ /dev/null @@ -1,234 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "inet_pton.h" -#include "connect.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/*********************************************************************** - * Only for IPv6-enabled builds - **********************************************************************/ -#ifdef CURLRES_IPV6 - -#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) -/* These are strictly for memory tracing and are using the same style as the - * family otherwise present in memdebug.c. I put these ones here since they - * require a bunch of structs I didn't want to include in memdebug.c - */ - -/* - * For CURLRES_ARS, this should be written using ares_gethostbyaddr() - * (ignoring the fact c-ares doesn't return 'serv'). - */ - -int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, - GETNAMEINFO_TYPE_ARG2 salen, - char *host, GETNAMEINFO_TYPE_ARG46 hostlen, - char *serv, GETNAMEINFO_TYPE_ARG46 servlen, - GETNAMEINFO_TYPE_ARG7 flags, - int line, const char *source) -{ - int res = (getnameinfo)(sa, salen, - host, hostlen, - serv, servlen, - flags); - if(0 == res) - /* success */ - curl_memlog("GETNAME %s:%d getnameinfo()\n", - source, line); - else - curl_memlog("GETNAME %s:%d getnameinfo() failed = %d\n", - source, line, res); - return res; -} -#endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */ - -/* - * Curl_ipv6works() returns TRUE if IPv6 seems to work. - */ -bool Curl_ipv6works(void) -{ - /* the nature of most system is that IPv6 status doesn't come and go - during a program's lifetime so we only probe the first time and then we - have the info kept for fast re-use */ - static int ipv6_works = -1; - if(-1 == ipv6_works) { - /* probe to see if we have a working IPv6 stack */ - curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); - if(s == CURL_SOCKET_BAD) - /* an IPv6 address was requested but we can't get/use one */ - ipv6_works = 0; - else { - ipv6_works = 1; - Curl_closesocket(NULL, s); - } - } - return (ipv6_works>0)?TRUE:FALSE; -} - -/* - * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've - * been set and returns TRUE if they are OK. - */ -bool Curl_ipvalid(struct connectdata *conn) -{ - if(conn->ip_version == CURL_IPRESOLVE_V6) - return Curl_ipv6works(); - - return TRUE; -} - -#if defined(CURLRES_SYNCH) - -#ifdef DEBUG_ADDRINFO -static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) -{ - printf("dump_addrinfo:\n"); - for(; ai; ai = ai->ai_next) { - char buf[INET6_ADDRSTRLEN]; - - printf(" fam %2d, CNAME %s, ", - ai->ai_family, ai->ai_canonname ? ai->ai_canonname : ""); - if(Curl_printable_address(ai, buf, sizeof(buf))) - printf("%s\n", buf); - else - printf("failed; %s\n", Curl_strerror(conn, SOCKERRNO)); - } -} -#else -#define dump_addrinfo(x,y) Curl_nop_stmt -#endif - -/* - * Curl_getaddrinfo() when built IPv6-enabled (non-threading and - * non-ares version). - * - * Returns name information about the given hostname and port number. If - * successful, the 'addrinfo' is returned and the forth argument will point to - * memory we need to free after use. That memory *MUST* be freed with - * Curl_freeaddrinfo(), nothing else. - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - struct addrinfo hints; - Curl_addrinfo *res; - int error; - char sbuf[12]; - char *sbufptr = NULL; -#ifndef USE_RESOLVE_ON_IPS - char addrbuf[128]; -#endif - int pf; -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) - struct Curl_easy *data = conn->data; -#endif - - *waitp = 0; /* synchronous response only */ - - /* Check if a limited name resolve has been requested */ - switch(conn->ip_version) { - case CURL_IPRESOLVE_V4: - pf = PF_INET; - break; - case CURL_IPRESOLVE_V6: - pf = PF_INET6; - break; - default: - pf = PF_UNSPEC; - break; - } - - if((pf != PF_INET) && !Curl_ipv6works()) - /* The stack seems to be a non-IPv6 one */ - pf = PF_INET; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = pf; - hints.ai_socktype = conn->socktype; - -#ifndef USE_RESOLVE_ON_IPS - /* - * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from - * an IPv4 address on iOS and Mac OS X. - */ - if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) || - (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) { - /* the given address is numerical only, prevent a reverse lookup */ - hints.ai_flags = AI_NUMERICHOST; - } -#endif - - if(port) { - snprintf(sbuf, sizeof(sbuf), "%d", port); - sbufptr = sbuf; - } - - error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res); - if(error) { - infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port); - return NULL; - } - - if(port) { - Curl_addrinfo_set_port(res, port); - } - - dump_addrinfo(conn, res); - - return res; -} -#endif /* CURLRES_SYNCH */ - -#endif /* CURLRES_IPV6 */ diff --git a/dep/cpr/opt/curl/lib/hostsyn.c b/dep/cpr/opt/curl/lib/hostsyn.c deleted file mode 100644 index 1a95263c625..00000000000 --- a/dep/cpr/opt/curl/lib/hostsyn.c +++ /dev/null @@ -1,107 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/*********************************************************************** - * Only for builds using synchronous name resolves - **********************************************************************/ -#ifdef CURLRES_SYNCH - -/* - * Function provided by the resolver backend to set DNS servers to use. - */ -CURLcode Curl_set_dns_servers(struct Curl_easy *data, - char *servers) -{ - (void)data; - (void)servers; - return CURLE_NOT_BUILT_IN; - -} - -/* - * Function provided by the resolver backend to set - * outgoing interface to use for DNS requests - */ -CURLcode Curl_set_dns_interface(struct Curl_easy *data, - const char *interf) -{ - (void)data; - (void)interf; - return CURLE_NOT_BUILT_IN; -} - -/* - * Function provided by the resolver backend to set - * local IPv4 address to use as source address for DNS requests - */ -CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, - const char *local_ip4) -{ - (void)data; - (void)local_ip4; - return CURLE_NOT_BUILT_IN; -} - -/* - * Function provided by the resolver backend to set - * local IPv6 address to use as source address for DNS requests - */ -CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, - const char *local_ip6) -{ - (void)data; - (void)local_ip6; - return CURLE_NOT_BUILT_IN; -} - -#endif /* truly sync */ diff --git a/dep/cpr/opt/curl/lib/http.c b/dep/cpr/opt/curl/lib/http.c deleted file mode 100644 index 38227eb6cfa..00000000000 --- a/dep/cpr/opt/curl/lib/http.c +++ /dev/null @@ -1,3820 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_HTTP - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "formdata.h" -#include "mime.h" -#include "progress.h" -#include "curl_base64.h" -#include "cookie.h" -#include "vauth/vauth.h" -#include "vtls/vtls.h" -#include "http_digest.h" -#include "http_ntlm.h" -#include "curl_ntlm_wb.h" -#include "http_negotiate.h" -#include "url.h" -#include "share.h" -#include "hostip.h" -#include "http.h" -#include "select.h" -#include "parsedate.h" /* for the week day and month names */ -#include "strtoofft.h" -#include "multiif.h" -#include "strcase.h" -#include "content_encoding.h" -#include "http_proxy.h" -#include "warnless.h" -#include "non-ascii.h" -#include "conncache.h" -#include "pipeline.h" -#include "http2.h" -#include "connect.h" -#include "strdup.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Forward declarations. - */ - -static int http_getsock_do(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); -static int http_should_fail(struct connectdata *conn); - -#ifdef USE_SSL -static CURLcode https_connecting(struct connectdata *conn, bool *done); -static int https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); -#else -#define https_connecting(x,y) CURLE_COULDNT_CONNECT -#endif - -/* - * HTTP handler interface. - */ -const struct Curl_handler Curl_handler_http = { - "HTTP", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - Curl_http_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - http_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_HTTP, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_CREDSPERREQUEST /* flags */ -}; - -#ifdef USE_SSL -/* - * HTTPS handler interface. - */ -const struct Curl_handler Curl_handler_https = { - "HTTPS", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - Curl_http_connect, /* connect_it */ - https_connecting, /* connecting */ - ZERO_NULL, /* doing */ - https_getsock, /* proto_getsock */ - http_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_HTTPS, /* defport */ - CURLPROTO_HTTPS, /* protocol */ - PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */ -}; -#endif - -CURLcode Curl_http_setup_conn(struct connectdata *conn) -{ - /* allocate the HTTP-specific struct for the Curl_easy, only to survive - during this request */ - struct HTTP *http; - DEBUGASSERT(conn->data->req.protop == NULL); - - http = calloc(1, sizeof(struct HTTP)); - if(!http) - return CURLE_OUT_OF_MEMORY; - - Curl_mime_initpart(&http->form, conn->data); - conn->data->req.protop = http; - - Curl_http2_setup_conn(conn); - Curl_http2_setup_req(conn->data); - - return CURLE_OK; -} - - -/* - * checkProxyHeaders() checks the linked list of custom proxy headers - * if proxy headers are not available, then it will lookup into http header - * link list - * - * It takes a connectdata struct as input instead of the Curl_easy simply - * to know if this is a proxy request or not, as it then might check a - * different header list. - */ -char *Curl_checkProxyheaders(const struct connectdata *conn, - const char *thisheader) -{ - struct curl_slist *head; - size_t thislen = strlen(thisheader); - struct Curl_easy *data = conn->data; - - for(head = (conn->bits.proxy && data->set.sep_headers) ? - data->set.proxyheaders : data->set.headers; - head; head = head->next) { - if(strncasecompare(head->data, thisheader, thislen)) - return head->data; - } - - return NULL; -} - -/* - * Strip off leading and trailing whitespace from the value in the - * given HTTP header line and return a strdupped copy. Returns NULL in - * case of allocation failure. Returns an empty string if the header value - * consists entirely of whitespace. - */ -char *Curl_copy_header_value(const char *header) -{ - const char *start; - const char *end; - char *value; - size_t len; - - DEBUGASSERT(header); - - /* Find the end of the header name */ - while(*header && (*header != ':')) - ++header; - - if(*header) - /* Skip over colon */ - ++header; - - /* Find the first non-space letter */ - start = header; - while(*start && ISSPACE(*start)) - start++; - - /* data is in the host encoding so - use '\r' and '\n' instead of 0x0d and 0x0a */ - end = strchr(start, '\r'); - if(!end) - end = strchr(start, '\n'); - if(!end) - end = strchr(start, '\0'); - if(!end) - return NULL; - - /* skip all trailing space letters */ - while((end > start) && ISSPACE(*end)) - end--; - - /* get length of the type */ - len = end - start + 1; - - value = malloc(len + 1); - if(!value) - return NULL; - - memcpy(value, start, len); - value[len] = 0; /* zero terminate */ - - return value; -} - -/* - * http_output_basic() sets up an Authorization: header (or the proxy version) - * for HTTP Basic authentication. - * - * Returns CURLcode. - */ -static CURLcode http_output_basic(struct connectdata *conn, bool proxy) -{ - size_t size = 0; - char *authorization = NULL; - struct Curl_easy *data = conn->data; - char **userp; - const char *user; - const char *pwd; - CURLcode result; - char *out; - - if(proxy) { - userp = &conn->allocptr.proxyuserpwd; - user = conn->http_proxy.user; - pwd = conn->http_proxy.passwd; - } - else { - userp = &conn->allocptr.userpwd; - user = conn->user; - pwd = conn->passwd; - } - - out = aprintf("%s:%s", user, pwd); - if(!out) - return CURLE_OUT_OF_MEMORY; - - result = Curl_base64_encode(data, out, strlen(out), &authorization, &size); - if(result) - goto fail; - - if(!authorization) { - result = CURLE_REMOTE_ACCESS_DENIED; - goto fail; - } - - free(*userp); - *userp = aprintf("%sAuthorization: Basic %s\r\n", - proxy ? "Proxy-" : "", - authorization); - free(authorization); - if(!*userp) { - result = CURLE_OUT_OF_MEMORY; - goto fail; - } - - fail: - free(out); - return result; -} - -/* pickoneauth() selects the most favourable authentication method from the - * ones available and the ones we want. - * - * return TRUE if one was picked - */ -static bool pickoneauth(struct auth *pick) -{ - bool picked; - /* only deal with authentication we want */ - unsigned long avail = pick->avail & pick->want; - picked = TRUE; - - /* The order of these checks is highly relevant, as this will be the order - of preference in case of the existence of multiple accepted types. */ - if(avail & CURLAUTH_NEGOTIATE) - pick->picked = CURLAUTH_NEGOTIATE; - else if(avail & CURLAUTH_DIGEST) - pick->picked = CURLAUTH_DIGEST; - else if(avail & CURLAUTH_NTLM) - pick->picked = CURLAUTH_NTLM; - else if(avail & CURLAUTH_NTLM_WB) - pick->picked = CURLAUTH_NTLM_WB; - else if(avail & CURLAUTH_BASIC) - pick->picked = CURLAUTH_BASIC; - else { - pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */ - picked = FALSE; - } - pick->avail = CURLAUTH_NONE; /* clear it here */ - - return picked; -} - -/* - * Curl_http_perhapsrewind() - * - * If we are doing POST or PUT { - * If we have more data to send { - * If we are doing NTLM { - * Keep sending since we must not disconnect - * } - * else { - * If there is more than just a little data left to send, close - * the current connection by force. - * } - * } - * If we have sent any data { - * If we don't have track of all the data { - * call app to tell it to rewind - * } - * else { - * rewind internally so that the operation can restart fine - * } - * } - * } - */ -static CURLcode http_perhapsrewind(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - struct HTTP *http = data->req.protop; - curl_off_t bytessent; - curl_off_t expectsend = -1; /* default is unknown */ - - if(!http) - /* If this is still NULL, we have not reach very far and we can safely - skip this rewinding stuff */ - return CURLE_OK; - - switch(data->set.httpreq) { - case HTTPREQ_GET: - case HTTPREQ_HEAD: - return CURLE_OK; - default: - break; - } - - bytessent = http->writebytecount; - - if(conn->bits.authneg) { - /* This is a state where we are known to be negotiating and we don't send - any data then. */ - expectsend = 0; - } - else if(!conn->bits.protoconnstart) { - /* HTTP CONNECT in progress: there is no body */ - expectsend = 0; - } - else { - /* figure out how much data we are expected to send */ - switch(data->set.httpreq) { - case HTTPREQ_POST: - if(data->state.infilesize != -1) - expectsend = data->state.infilesize; - break; - case HTTPREQ_PUT: - if(data->state.infilesize != -1) - expectsend = data->state.infilesize; - break; - case HTTPREQ_POST_FORM: - case HTTPREQ_POST_MIME: - expectsend = http->postsize; - break; - default: - break; - } - } - - conn->bits.rewindaftersend = FALSE; /* default */ - - if((expectsend == -1) || (expectsend > bytessent)) { -#if defined(USE_NTLM) - /* There is still data left to send */ - if((data->state.authproxy.picked == CURLAUTH_NTLM) || - (data->state.authhost.picked == CURLAUTH_NTLM) || - (data->state.authproxy.picked == CURLAUTH_NTLM_WB) || - (data->state.authhost.picked == CURLAUTH_NTLM_WB)) { - if(((expectsend - bytessent) < 2000) || - (conn->ntlm.state != NTLMSTATE_NONE) || - (conn->proxyntlm.state != NTLMSTATE_NONE)) { - /* The NTLM-negotiation has started *OR* there is just a little (<2K) - data left to send, keep on sending. */ - - /* rewind data when completely done sending! */ - if(!conn->bits.authneg) { - conn->bits.rewindaftersend = TRUE; - infof(data, "Rewind stream after send\n"); - } - - return CURLE_OK; - } - - if(conn->bits.close) - /* this is already marked to get closed */ - return CURLE_OK; - - infof(data, "NTLM send, close instead of sending %" - CURL_FORMAT_CURL_OFF_T " bytes\n", - (curl_off_t)(expectsend - bytessent)); - } -#endif - - /* This is not NTLM or many bytes left to send: close */ - streamclose(conn, "Mid-auth HTTP and much data left to send"); - data->req.size = 0; /* don't download any more than 0 bytes */ - - /* There still is data left to send, but this connection is marked for - closure so we can safely do the rewind right now */ - } - - if(bytessent) - /* we rewind now at once since if we already sent something */ - return Curl_readrewind(conn); - - return CURLE_OK; -} - -/* - * Curl_http_auth_act() gets called when all HTTP headers have been received - * and it checks what authentication methods that are available and decides - * which one (if any) to use. It will set 'newurl' if an auth method was - * picked. - */ - -CURLcode Curl_http_auth_act(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - bool pickhost = FALSE; - bool pickproxy = FALSE; - CURLcode result = CURLE_OK; - - if(100 <= data->req.httpcode && 199 >= data->req.httpcode) - /* this is a transient response code, ignore */ - return CURLE_OK; - - if(data->state.authproblem) - return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; - - if(conn->bits.user_passwd && - ((data->req.httpcode == 401) || - (conn->bits.authneg && data->req.httpcode < 300))) { - pickhost = pickoneauth(&data->state.authhost); - if(!pickhost) - data->state.authproblem = TRUE; - } - if(conn->bits.proxy_user_passwd && - ((data->req.httpcode == 407) || - (conn->bits.authneg && data->req.httpcode < 300))) { - pickproxy = pickoneauth(&data->state.authproxy); - if(!pickproxy) - data->state.authproblem = TRUE; - } - - if(pickhost || pickproxy) { - /* In case this is GSS auth, the newurl field is already allocated so - we must make sure to free it before allocating a new one. As figured - out in bug #2284386 */ - Curl_safefree(data->req.newurl); - data->req.newurl = strdup(data->change.url); /* clone URL */ - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - - if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD) && - !conn->bits.rewindaftersend) { - result = http_perhapsrewind(conn); - if(result) - return result; - } - } - else if((data->req.httpcode < 300) && - (!data->state.authhost.done) && - conn->bits.authneg) { - /* no (known) authentication available, - authentication is not "done" yet and - no authentication seems to be required and - we didn't try HEAD or GET */ - if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD)) { - data->req.newurl = strdup(data->change.url); /* clone URL */ - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - data->state.authhost.done = TRUE; - } - } - if(http_should_fail(conn)) { - failf(data, "The requested URL returned error: %d", - data->req.httpcode); - result = CURLE_HTTP_RETURNED_ERROR; - } - - return result; -} - -/* - * Output the correct authentication header depending on the auth type - * and whether or not it is to a proxy. - */ -static CURLcode -output_auth_headers(struct connectdata *conn, - struct auth *authstatus, - const char *request, - const char *path, - bool proxy) -{ - const char *auth = NULL; - CURLcode result = CURLE_OK; -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO) - struct Curl_easy *data = conn->data; -#endif -#ifdef USE_SPNEGO - struct negotiatedata *negdata = proxy ? - &data->state.proxyneg : &data->state.negotiate; -#endif - -#ifdef CURL_DISABLE_CRYPTO_AUTH - (void)request; - (void)path; -#endif - -#ifdef USE_SPNEGO - negdata->state = GSS_AUTHNONE; - if((authstatus->picked == CURLAUTH_NEGOTIATE) && - negdata->context && !GSS_ERROR(negdata->status)) { - auth = "Negotiate"; - result = Curl_output_negotiate(conn, proxy); - if(result) - return result; - authstatus->done = TRUE; - negdata->state = GSS_AUTHSENT; - } - else -#endif -#ifdef USE_NTLM - if(authstatus->picked == CURLAUTH_NTLM) { - auth = "NTLM"; - result = Curl_output_ntlm(conn, proxy); - if(result) - return result; - } - else -#endif -#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) - if(authstatus->picked == CURLAUTH_NTLM_WB) { - auth = "NTLM_WB"; - result = Curl_output_ntlm_wb(conn, proxy); - if(result) - return result; - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(authstatus->picked == CURLAUTH_DIGEST) { - auth = "Digest"; - result = Curl_output_digest(conn, - proxy, - (const unsigned char *)request, - (const unsigned char *)path); - if(result) - return result; - } - else -#endif - if(authstatus->picked == CURLAUTH_BASIC) { - /* Basic */ - if((proxy && conn->bits.proxy_user_passwd && - !Curl_checkProxyheaders(conn, "Proxy-authorization:")) || - (!proxy && conn->bits.user_passwd && - !Curl_checkheaders(conn, "Authorization:"))) { - auth = "Basic"; - result = http_output_basic(conn, proxy); - if(result) - return result; - } - - /* NOTE: this function should set 'done' TRUE, as the other auth - functions work that way */ - authstatus->done = TRUE; - } - - if(auth) { - infof(data, "%s auth using %s with user '%s'\n", - proxy ? "Proxy" : "Server", auth, - proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") : - (conn->user ? conn->user : "")); - authstatus->multipass = (!authstatus->done) ? TRUE : FALSE; - } - else - authstatus->multipass = FALSE; - - return CURLE_OK; -} - -/** - * Curl_http_output_auth() setups the authentication headers for the - * host/proxy and the correct authentication - * method. conn->data->state.authdone is set to TRUE when authentication is - * done. - * - * @param conn all information about the current connection - * @param request pointer to the request keyword - * @param path pointer to the requested path - * @param proxytunnel boolean if this is the request setting up a "proxy - * tunnel" - * - * @returns CURLcode - */ -CURLcode -Curl_http_output_auth(struct connectdata *conn, - const char *request, - const char *path, - bool proxytunnel) /* TRUE if this is the request setting - up the proxy tunnel */ -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct auth *authhost; - struct auth *authproxy; - - DEBUGASSERT(data); - - authhost = &data->state.authhost; - authproxy = &data->state.authproxy; - - if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || - conn->bits.user_passwd) - /* continue please */; - else { - authhost->done = TRUE; - authproxy->done = TRUE; - return CURLE_OK; /* no authentication with no user or password */ - } - - if(authhost->want && !authhost->picked) - /* The app has selected one or more methods, but none has been picked - so far by a server round-trip. Then we set the picked one to the - want one, and if this is one single bit it'll be used instantly. */ - authhost->picked = authhost->want; - - if(authproxy->want && !authproxy->picked) - /* The app has selected one or more methods, but none has been picked so - far by a proxy round-trip. Then we set the picked one to the want one, - and if this is one single bit it'll be used instantly. */ - authproxy->picked = authproxy->want; - -#ifndef CURL_DISABLE_PROXY - /* Send proxy authentication header if needed */ - if(conn->bits.httpproxy && - (conn->bits.tunnel_proxy == proxytunnel)) { - result = output_auth_headers(conn, authproxy, request, path, TRUE); - if(result) - return result; - } - else -#else - (void)proxytunnel; -#endif /* CURL_DISABLE_PROXY */ - /* we have no proxy so let's pretend we're done authenticating - with it */ - authproxy->done = TRUE; - - /* To prevent the user+password to get sent to other than the original - host due to a location-follow, we do some weirdo checks here */ - if(!data->state.this_is_a_follow || - conn->bits.netrc || - !data->state.first_host || - data->set.http_disable_hostname_check_before_authentication || - strcasecompare(data->state.first_host, conn->host.name)) { - result = output_auth_headers(conn, authhost, request, path, FALSE); - } - else - authhost->done = TRUE; - - return result; -} - -/* - * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: - * headers. They are dealt with both in the transfer.c main loop and in the - * proxy CONNECT loop. - */ - -CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, - const char *auth) /* the first non-space */ -{ - /* - * This resource requires authentication - */ - struct Curl_easy *data = conn->data; - -#ifdef USE_SPNEGO - struct negotiatedata *negdata = proxy? - &data->state.proxyneg:&data->state.negotiate; -#endif - unsigned long *availp; - struct auth *authp; - - if(proxy) { - availp = &data->info.proxyauthavail; - authp = &data->state.authproxy; - } - else { - availp = &data->info.httpauthavail; - authp = &data->state.authhost; - } - - /* - * Here we check if we want the specific single authentication (using ==) and - * if we do, we initiate usage of it. - * - * If the provided authentication is wanted as one out of several accepted - * types (using &), we OR this authentication type to the authavail - * variable. - * - * Note: - * - * ->picked is first set to the 'want' value (one or more bits) before the - * request is sent, and then it is again set _after_ all response 401/407 - * headers have been received but then only to a single preferred method - * (bit). - */ - - while(*auth) { -#ifdef USE_SPNEGO - if(checkprefix("Negotiate", auth)) { - if((authp->avail & CURLAUTH_NEGOTIATE) || - Curl_auth_is_spnego_supported()) { - *availp |= CURLAUTH_NEGOTIATE; - authp->avail |= CURLAUTH_NEGOTIATE; - - if(authp->picked == CURLAUTH_NEGOTIATE) { - if(negdata->state == GSS_AUTHSENT || - negdata->state == GSS_AUTHNONE) { - CURLcode result = Curl_input_negotiate(conn, proxy, auth); - if(!result) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->change.url); - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - data->state.authproblem = FALSE; - /* we received a GSS auth token and we dealt with it fine */ - negdata->state = GSS_AUTHRECV; - } - else - data->state.authproblem = TRUE; - } - } - } - } - else -#endif -#ifdef USE_NTLM - /* NTLM support requires the SSL crypto libs */ - if(checkprefix("NTLM", auth)) { - if((authp->avail & CURLAUTH_NTLM) || - (authp->avail & CURLAUTH_NTLM_WB) || - Curl_auth_is_ntlm_supported()) { - *availp |= CURLAUTH_NTLM; - authp->avail |= CURLAUTH_NTLM; - - if(authp->picked == CURLAUTH_NTLM || - authp->picked == CURLAUTH_NTLM_WB) { - /* NTLM authentication is picked and activated */ - CURLcode result = Curl_input_ntlm(conn, proxy, auth); - if(!result) { - data->state.authproblem = FALSE; -#ifdef NTLM_WB_ENABLED - if(authp->picked == CURLAUTH_NTLM_WB) { - *availp &= ~CURLAUTH_NTLM; - authp->avail &= ~CURLAUTH_NTLM; - *availp |= CURLAUTH_NTLM_WB; - authp->avail |= CURLAUTH_NTLM_WB; - - /* Get the challenge-message which will be passed to - * ntlm_auth for generating the type 3 message later */ - while(*auth && ISSPACE(*auth)) - auth++; - if(checkprefix("NTLM", auth)) { - auth += strlen("NTLM"); - while(*auth && ISSPACE(*auth)) - auth++; - if(*auth) { - conn->challenge_header = strdup(auth); - if(!conn->challenge_header) - return CURLE_OUT_OF_MEMORY; - } - } - } -#endif - } - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } - } - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(checkprefix("Digest", auth)) { - if((authp->avail & CURLAUTH_DIGEST) != 0) - infof(data, "Ignoring duplicate digest auth header.\n"); - else if(Curl_auth_is_digest_supported()) { - CURLcode result; - - *availp |= CURLAUTH_DIGEST; - authp->avail |= CURLAUTH_DIGEST; - - /* We call this function on input Digest headers even if Digest - * authentication isn't activated yet, as we need to store the - * incoming data from this header in case we are going to use - * Digest */ - result = Curl_input_digest(conn, proxy, auth); - if(result) { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } - } - else -#endif - if(checkprefix("Basic", auth)) { - *availp |= CURLAUTH_BASIC; - authp->avail |= CURLAUTH_BASIC; - if(authp->picked == CURLAUTH_BASIC) { - /* We asked for Basic authentication but got a 40X back - anyway, which basically means our name+password isn't - valid. */ - authp->avail = CURLAUTH_NONE; - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } - - /* there may be multiple methods on one line, so keep reading */ - while(*auth && *auth != ',') /* read up to the next comma */ - auth++; - if(*auth == ',') /* if we're on a comma, skip it */ - auth++; - while(*auth && ISSPACE(*auth)) - auth++; - } - - return CURLE_OK; -} - -/** - * http_should_fail() determines whether an HTTP response has gotten us - * into an error state or not. - * - * @param conn all information about the current connection - * - * @retval 0 communications should continue - * - * @retval 1 communications should not continue - */ -static int http_should_fail(struct connectdata *conn) -{ - struct Curl_easy *data; - int httpcode; - - DEBUGASSERT(conn); - data = conn->data; - DEBUGASSERT(data); - - httpcode = data->req.httpcode; - - /* - ** If we haven't been asked to fail on error, - ** don't fail. - */ - if(!data->set.http_fail_on_error) - return 0; - - /* - ** Any code < 400 is never terminal. - */ - if(httpcode < 400) - return 0; - - /* - ** Any code >= 400 that's not 401 or 407 is always - ** a terminal error - */ - if((httpcode != 401) && (httpcode != 407)) - return 1; - - /* - ** All we have left to deal with is 401 and 407 - */ - DEBUGASSERT((httpcode == 401) || (httpcode == 407)); - - /* - ** Examine the current authentication state to see if this - ** is an error. The idea is for this function to get - ** called after processing all the headers in a response - ** message. So, if we've been to asked to authenticate a - ** particular stage, and we've done it, we're OK. But, if - ** we're already completely authenticated, it's not OK to - ** get another 401 or 407. - ** - ** It is possible for authentication to go stale such that - ** the client needs to reauthenticate. Once that info is - ** available, use it here. - */ - - /* - ** Either we're not authenticating, or we're supposed to - ** be authenticating something else. This is an error. - */ - if((httpcode == 401) && !conn->bits.user_passwd) - return TRUE; - if((httpcode == 407) && !conn->bits.proxy_user_passwd) - return TRUE; - - return data->state.authproblem; -} - -/* - * readmoredata() is a "fread() emulation" to provide POST and/or request - * data. It is used when a huge POST is to be made and the entire chunk wasn't - * sent in the first send(). This function will then be called from the - * transfer.c loop when more data is to be sent to the peer. - * - * Returns the amount of bytes it filled the buffer with. - */ -static size_t readmoredata(char *buffer, - size_t size, - size_t nitems, - void *userp) -{ - struct connectdata *conn = (struct connectdata *)userp; - struct HTTP *http = conn->data->req.protop; - size_t fullsize = size * nitems; - - if(!http->postsize) - /* nothing to return */ - return 0; - - /* make sure that a HTTP request is never sent away chunked! */ - conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE; - - if(http->postsize <= (curl_off_t)fullsize) { - memcpy(buffer, http->postdata, (size_t)http->postsize); - fullsize = (size_t)http->postsize; - - if(http->backup.postsize) { - /* move backup data into focus and continue on that */ - http->postdata = http->backup.postdata; - http->postsize = http->backup.postsize; - conn->data->state.fread_func = http->backup.fread_func; - conn->data->state.in = http->backup.fread_in; - - http->sending++; /* move one step up */ - - http->backup.postsize = 0; - } - else - http->postsize = 0; - - return fullsize; - } - - memcpy(buffer, http->postdata, fullsize); - http->postdata += fullsize; - http->postsize -= fullsize; - - return fullsize; -} - -/* ------------------------------------------------------------------------- */ -/* add_buffer functions */ - -/* - * Curl_add_buffer_init() sets up and returns a fine buffer struct - */ -Curl_send_buffer *Curl_add_buffer_init(void) -{ - return calloc(1, sizeof(Curl_send_buffer)); -} - -/* - * Curl_add_buffer_free() frees all associated resources. - */ -void Curl_add_buffer_free(Curl_send_buffer *buff) -{ - if(buff) /* deal with NULL input */ - free(buff->buffer); - free(buff); -} - -/* - * Curl_add_buffer_send() sends a header buffer and frees all associated - * memory. Body data may be appended to the header data if desired. - * - * Returns CURLcode - */ -CURLcode Curl_add_buffer_send(Curl_send_buffer *in, - struct connectdata *conn, - - /* add the number of sent bytes to this - counter */ - long *bytes_written, - - /* how much of the buffer contains body data */ - size_t included_body_bytes, - int socketindex) - -{ - ssize_t amount; - CURLcode result; - char *ptr; - size_t size; - struct HTTP *http = conn->data->req.protop; - size_t sendsize; - curl_socket_t sockfd; - size_t headersize; - - DEBUGASSERT(socketindex <= SECONDARYSOCKET); - - sockfd = conn->sock[socketindex]; - - /* The looping below is required since we use non-blocking sockets, but due - to the circumstances we will just loop and try again and again etc */ - - ptr = in->buffer; - size = in->size_used; - - headersize = size - included_body_bytes; /* the initial part that isn't body - is header */ - - DEBUGASSERT(size > included_body_bytes); - - result = Curl_convert_to_network(conn->data, ptr, headersize); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(result) { - /* conversion failed, free memory and return to the caller */ - Curl_add_buffer_free(in); - return result; - } - - if((conn->handler->flags & PROTOPT_SSL || - conn->http_proxy.proxytype == CURLPROXY_HTTPS) - && conn->httpversion != 20) { - /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk - when we speak HTTPS, as if only a fraction of it is sent now, this data - needs to fit into the normal read-callback buffer later on and that - buffer is using this size. - */ - - sendsize = CURLMIN(size, CURL_MAX_WRITE_SIZE); - - /* OpenSSL is very picky and we must send the SAME buffer pointer to the - library when we attempt to re-send this buffer. Sending the same data - is not enough, we must use the exact same address. For this reason, we - must copy the data to the uploadbuffer first, since that is the buffer - we will be using if this send is retried later. - */ - memcpy(conn->data->state.uploadbuffer, ptr, sendsize); - ptr = conn->data->state.uploadbuffer; - } - else - sendsize = size; - - result = Curl_write(conn, sockfd, ptr, sendsize, &amount); - - if(!result) { - /* - * Note that we may not send the entire chunk at once, and we have a set - * number of data bytes at the end of the big buffer (out of which we may - * only send away a part). - */ - /* how much of the header that was sent */ - size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount; - size_t bodylen = amount - headlen; - - if(conn->data->set.verbose) { - /* this data _may_ contain binary stuff */ - Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, headlen, conn); - if(bodylen) { - /* there was body data sent beyond the initial header part, pass that - on to the debug callback too */ - Curl_debug(conn->data, CURLINFO_DATA_OUT, - ptr + headlen, bodylen, conn); - } - } - - /* 'amount' can never be a very large value here so typecasting it so a - signed 31 bit value should not cause problems even if ssize_t is - 64bit */ - *bytes_written += (long)amount; - - if(http) { - /* if we sent a piece of the body here, up the byte counter for it - accordingly */ - http->writebytecount += bodylen; - - if((size_t)amount != size) { - /* The whole request could not be sent in one system call. We must - queue it up and send it later when we get the chance. We must not - loop here and wait until it might work again. */ - - size -= amount; - - ptr = in->buffer + amount; - - /* backup the currently set pointers */ - http->backup.fread_func = conn->data->state.fread_func; - http->backup.fread_in = conn->data->state.in; - http->backup.postdata = http->postdata; - http->backup.postsize = http->postsize; - - /* set the new pointers for the request-sending */ - conn->data->state.fread_func = (curl_read_callback)readmoredata; - conn->data->state.in = (void *)conn; - http->postdata = ptr; - http->postsize = (curl_off_t)size; - - http->send_buffer = in; - http->sending = HTTPSEND_REQUEST; - - return CURLE_OK; - } - http->sending = HTTPSEND_BODY; - /* the full buffer was sent, clean up and return */ - } - else { - if((size_t)amount != size) - /* We have no continue-send mechanism now, fail. This can only happen - when this function is used from the CONNECT sending function. We - currently (stupidly) assume that the whole request is always sent - away in the first single chunk. - - This needs FIXing. - */ - return CURLE_SEND_ERROR; - Curl_pipeline_leave_write(conn); - } - } - Curl_add_buffer_free(in); - - return result; -} - - -/* - * add_bufferf() add the formatted input to the buffer. - */ -CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...) -{ - char *s; - va_list ap; - va_start(ap, fmt); - s = vaprintf(fmt, ap); /* this allocs a new string to append */ - va_end(ap); - - if(s) { - CURLcode result = Curl_add_buffer(in, s, strlen(s)); - free(s); - return result; - } - /* If we failed, we cleanup the whole buffer and return error */ - free(in->buffer); - free(in); - return CURLE_OUT_OF_MEMORY; -} - -/* - * add_buffer() appends a memory chunk to the existing buffer - */ -CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size) -{ - char *new_rb; - size_t new_size; - - if(~size < in->size_used) { - /* If resulting used size of send buffer would wrap size_t, cleanup - the whole buffer and return error. Otherwise the required buffer - size will fit into a single allocatable memory chunk */ - Curl_safefree(in->buffer); - free(in); - return CURLE_OUT_OF_MEMORY; - } - - if(!in->buffer || - ((in->size_used + size) > (in->size_max - 1))) { - - /* If current buffer size isn't enough to hold the result, use a - buffer size that doubles the required size. If this new size - would wrap size_t, then just use the largest possible one */ - - if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) || - (~(size * 2) < (in->size_used * 2))) - new_size = (size_t)-1; - else - new_size = (in->size_used + size) * 2; - - if(in->buffer) - /* we have a buffer, enlarge the existing one */ - new_rb = Curl_saferealloc(in->buffer, new_size); - else - /* create a new buffer */ - new_rb = malloc(new_size); - - if(!new_rb) { - /* If we failed, we cleanup the whole buffer and return error */ - free(in); - return CURLE_OUT_OF_MEMORY; - } - - in->buffer = new_rb; - in->size_max = new_size; - } - memcpy(&in->buffer[in->size_used], inptr, size); - - in->size_used += size; - - return CURLE_OK; -} - -/* end of the add_buffer functions */ -/* ------------------------------------------------------------------------- */ - - - -/* - * Curl_compareheader() - * - * Returns TRUE if 'headerline' contains the 'header' with given 'content'. - * Pass headers WITH the colon. - */ -bool -Curl_compareheader(const char *headerline, /* line to check */ - const char *header, /* header keyword _with_ colon */ - const char *content) /* content string to find */ -{ - /* RFC2616, section 4.2 says: "Each header field consists of a name followed - * by a colon (":") and the field value. Field names are case-insensitive. - * The field value MAY be preceded by any amount of LWS, though a single SP - * is preferred." */ - - size_t hlen = strlen(header); - size_t clen; - size_t len; - const char *start; - const char *end; - - if(!strncasecompare(headerline, header, hlen)) - return FALSE; /* doesn't start with header */ - - /* pass the header */ - start = &headerline[hlen]; - - /* pass all white spaces */ - while(*start && ISSPACE(*start)) - start++; - - /* find the end of the header line */ - end = strchr(start, '\r'); /* lines end with CRLF */ - if(!end) { - /* in case there's a non-standard compliant line here */ - end = strchr(start, '\n'); - - if(!end) - /* hm, there's no line ending here, use the zero byte! */ - end = strchr(start, '\0'); - } - - len = end-start; /* length of the content part of the input line */ - clen = strlen(content); /* length of the word to find */ - - /* find the content string in the rest of the line */ - for(; len >= clen; len--, start++) { - if(strncasecompare(start, content, clen)) - return TRUE; /* match! */ - } - - return FALSE; /* no match */ -} - -/* - * Curl_http_connect() performs HTTP stuff to do at connect-time, called from - * the generic Curl_connect(). - */ -CURLcode Curl_http_connect(struct connectdata *conn, bool *done) -{ - CURLcode result; - - /* We default to persistent connections. We set this already in this connect - function to make the re-use checks properly be able to check this bit. */ - connkeep(conn, "HTTP default"); - - /* the CONNECT procedure might not have been completed */ - result = Curl_proxy_connect(conn, FIRSTSOCKET); - if(result) - return result; - - if(conn->bits.proxy_connect_closed) - /* this is not an error, just part of the connection negotiation */ - return CURLE_OK; - - if(CONNECT_FIRSTSOCKET_PROXY_SSL()) - return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */ - - if(Curl_connect_ongoing(conn)) - /* nothing else to do except wait right now - we're not done here. */ - return CURLE_OK; - - if(conn->given->protocol & CURLPROTO_HTTPS) { - /* perform SSL initialization */ - result = https_connecting(conn, done); - if(result) - return result; - } - else - *done = TRUE; - - return CURLE_OK; -} - -/* this returns the socket to wait for in the DO and DOING state for the multi - interface and then we're always _sending_ a request and thus we wait for - the single socket to become writable only */ -static int http_getsock_do(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - /* write mode */ - (void)numsocks; /* unused, we trust it to be at least 1 */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); -} - -#ifdef USE_SSL -static CURLcode https_connecting(struct connectdata *conn, bool *done) -{ - CURLcode result; - DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL)); - - /* perform SSL initialization for this socket */ - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done); - if(result) - connclose(conn, "Failed HTTPS connection"); - - return result; -} - -static int https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - if(conn->handler->flags & PROTOPT_SSL) - return Curl_ssl_getsock(conn, socks, numsocks); - return GETSOCK_BLANK; -} -#endif /* USE_SSL */ - -/* - * Curl_http_done() gets called after a single HTTP request has been - * performed. - */ - -CURLcode Curl_http_done(struct connectdata *conn, - CURLcode status, bool premature) -{ - struct Curl_easy *data = conn->data; - struct HTTP *http = data->req.protop; - - /* Clear multipass flag. If authentication isn't done yet, then it will get - * a chance to be set back to true when we output the next auth header */ - data->state.authhost.multipass = FALSE; - data->state.authproxy.multipass = FALSE; - - Curl_unencode_cleanup(conn); - -#ifdef USE_SPNEGO - if(data->state.proxyneg.state == GSS_AUTHSENT || - data->state.negotiate.state == GSS_AUTHSENT) { - /* add forbid re-use if http-code != 401/407 as a WA only needed for - * 401/407 that signal auth failure (empty) otherwise state will be RECV - * with current code. - * Do not close CONNECT_ONLY connections. */ - if((data->req.httpcode != 401) && (data->req.httpcode != 407) && - !data->set.connect_only) - streamclose(conn, "Negotiate transfer completed"); - Curl_cleanup_negotiate(data); - } -#endif - - /* set the proper values (possibly modified on POST) */ - conn->seek_func = data->set.seek_func; /* restore */ - conn->seek_client = data->set.seek_client; /* restore */ - - if(!http) - return CURLE_OK; - - if(http->send_buffer) { - Curl_add_buffer_free(http->send_buffer); - http->send_buffer = NULL; /* clear the pointer */ - } - - Curl_http2_done(conn, premature); - - Curl_mime_cleanpart(&http->form); - - switch(data->set.httpreq) { - case HTTPREQ_PUT: - case HTTPREQ_POST_FORM: - case HTTPREQ_POST_MIME: - data->req.bytecount = http->readbytecount + http->writebytecount; - break; - default: - break; - } - - if(status) - return status; - - if(!premature && /* this check is pointless when DONE is called before the - entire operation is complete */ - !conn->bits.retry && - !data->set.connect_only && - (http->readbytecount + - data->req.headerbytecount - - data->req.deductheadercount) <= 0) { - /* If this connection isn't simply closed to be retried, AND nothing was - read from the HTTP server (that counts), this can't be right so we - return an error here */ - failf(data, "Empty reply from server"); - return CURLE_GOT_NOTHING; - } - - return CURLE_OK; -} - -/* - * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons - * to avoid it include: - * - * - if the user specifically requested HTTP 1.0 - * - if the server we are connected to only supports 1.0 - * - if any server previously contacted to handle this request only supports - * 1.0. - */ -static bool use_http_1_1plus(const struct Curl_easy *data, - const struct connectdata *conn) -{ - if((data->state.httpversion == 10) || (conn->httpversion == 10)) - return FALSE; - if((data->set.httpversion == CURL_HTTP_VERSION_1_0) && - (conn->httpversion <= 10)) - return FALSE; - return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) || - (data->set.httpversion >= CURL_HTTP_VERSION_1_1)); -} - -static const char *get_http_string(const struct Curl_easy *data, - const struct connectdata *conn) -{ -#ifdef USE_NGHTTP2 - if(conn->proto.httpc.h2) - return "2"; -#endif - - if(use_http_1_1plus(data, conn)) - return "1.1"; - - return "1.0"; -} - -/* check and possibly add an Expect: header */ -static CURLcode expect100(struct Curl_easy *data, - struct connectdata *conn, - Curl_send_buffer *req_buffer) -{ - CURLcode result = CURLE_OK; - const char *ptr; - data->state.expect100header = FALSE; /* default to false unless it is set - to TRUE below */ - if(use_http_1_1plus(data, conn) && - (conn->httpversion != 20)) { - /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an - Expect: 100-continue to the headers which actually speeds up post - operations (as there is one packet coming back from the web server) */ - ptr = Curl_checkheaders(conn, "Expect:"); - if(ptr) { - data->state.expect100header = - Curl_compareheader(ptr, "Expect:", "100-continue"); - } - else { - result = Curl_add_bufferf(req_buffer, - "Expect: 100-continue\r\n"); - if(!result) - data->state.expect100header = TRUE; - } - } - - return result; -} - -enum proxy_use { - HEADER_SERVER, /* direct to server */ - HEADER_PROXY, /* regular request to proxy */ - HEADER_CONNECT /* sending CONNECT to a proxy */ -}; - -CURLcode Curl_add_custom_headers(struct connectdata *conn, - bool is_connect, - Curl_send_buffer *req_buffer) -{ - char *ptr; - struct curl_slist *h[2]; - struct curl_slist *headers; - int numlists = 1; /* by default */ - struct Curl_easy *data = conn->data; - int i; - - enum proxy_use proxy; - - if(is_connect) - proxy = HEADER_CONNECT; - else - proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? - HEADER_PROXY:HEADER_SERVER; - - switch(proxy) { - case HEADER_SERVER: - h[0] = data->set.headers; - break; - case HEADER_PROXY: - h[0] = data->set.headers; - if(data->set.sep_headers) { - h[1] = data->set.proxyheaders; - numlists++; - } - break; - case HEADER_CONNECT: - if(data->set.sep_headers) - h[0] = data->set.proxyheaders; - else - h[0] = data->set.headers; - break; - } - - /* loop through one or two lists */ - for(i = 0; i < numlists; i++) { - headers = h[i]; - - while(headers) { - ptr = strchr(headers->data, ':'); - if(ptr) { - /* we require a colon for this to be a true header */ - - ptr++; /* pass the colon */ - while(*ptr && ISSPACE(*ptr)) - ptr++; - - if(*ptr) { - /* only send this if the contents was non-blank */ - - if(conn->allocptr.host && - /* a Host: header was sent already, don't pass on any custom Host: - header as that will produce *two* in the same request! */ - checkprefix("Host:", headers->data)) - ; - else if(data->set.httpreq == HTTPREQ_POST_FORM && - /* this header (extended by formdata.c) is sent later */ - checkprefix("Content-Type:", headers->data)) - ; - else if(data->set.httpreq == HTTPREQ_POST_MIME && - /* this header is sent later */ - checkprefix("Content-Type:", headers->data)) - ; - else if(conn->bits.authneg && - /* while doing auth neg, don't allow the custom length since - we will force length zero then */ - checkprefix("Content-Length:", headers->data)) - ; - else if(conn->allocptr.te && - /* when asking for Transfer-Encoding, don't pass on a custom - Connection: */ - checkprefix("Connection:", headers->data)) - ; - else if((conn->httpversion == 20) && - checkprefix("Transfer-Encoding:", headers->data)) - /* HTTP/2 doesn't support chunked requests */ - ; - else { - CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", - headers->data); - if(result) - return result; - } - } - } - else { - ptr = strchr(headers->data, ';'); - if(ptr) { - - ptr++; /* pass the semicolon */ - while(*ptr && ISSPACE(*ptr)) - ptr++; - - if(*ptr) { - /* this may be used for something else in the future */ - } - else { - if(*(--ptr) == ';') { - CURLcode result; - - /* send no-value custom header if terminated by semicolon */ - *ptr = ':'; - result = Curl_add_bufferf(req_buffer, "%s\r\n", - headers->data); - - /* restore the previous value */ - *ptr = ';'; - - if(result) - return result; - } - } - } - } - headers = headers->next; - } - } - - return CURLE_OK; -} - -CURLcode Curl_add_timecondition(struct Curl_easy *data, - Curl_send_buffer *req_buffer) -{ - const struct tm *tm; - struct tm keeptime; - CURLcode result; - char datestr[80]; - const char *condp; - - if(data->set.timecondition == CURL_TIMECOND_NONE) - /* no condition was asked for */ - return CURLE_OK; - - result = Curl_gmtime(data->set.timevalue, &keeptime); - if(result) { - failf(data, "Invalid TIMEVALUE"); - return result; - } - tm = &keeptime; - - switch(data->set.timecondition) { - default: - return CURLE_BAD_FUNCTION_ARGUMENT; - - case CURL_TIMECOND_IFMODSINCE: - condp = "If-Modified-Since"; - break; - case CURL_TIMECOND_IFUNMODSINCE: - condp = "If-Unmodified-Since"; - break; - case CURL_TIMECOND_LASTMOD: - condp = "Last-Modified"; - break; - } - - /* The If-Modified-Since header family should have their times set in - * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be - * represented in Greenwich Mean Time (GMT), without exception. For the - * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal - * Time)." (see page 20 of RFC2616). - */ - - /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(datestr, sizeof(datestr), - "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - condp, - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - - result = Curl_add_buffer(req_buffer, datestr, strlen(datestr)); - - return result; -} - -/* - * Curl_http() gets called from the generic multi_do() function when a HTTP - * request is to be performed. This creates and sends a properly constructed - * HTTP request. - */ -CURLcode Curl_http(struct connectdata *conn, bool *done) -{ - struct Curl_easy *data = conn->data; - CURLcode result = CURLE_OK; - struct HTTP *http; - const char *ppath = data->state.path; - bool paste_ftp_userpwd = FALSE; - char ftp_typecode[sizeof("/;type=?")] = ""; - const char *host = conn->host.name; - const char *te = ""; /* transfer-encoding */ - const char *ptr; - const char *request; - Curl_HttpReq httpreq = data->set.httpreq; -#if !defined(CURL_DISABLE_COOKIES) - char *addcookies = NULL; -#endif - curl_off_t included_body = 0; - const char *httpstring; - Curl_send_buffer *req_buffer; - curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ - int seekerr = CURL_SEEKFUNC_CANTSEEK; - - /* Always consider the DO phase done after this function call, even if there - may be parts of the request that is not yet sent, since we can deal with - the rest of the request in the PERFORM phase. */ - *done = TRUE; - - if(conn->httpversion < 20) { /* unless the connection is re-used and already - http2 */ - switch(conn->negnpn) { - case CURL_HTTP_VERSION_2: - conn->httpversion = 20; /* we know we're on HTTP/2 now */ - - result = Curl_http2_switched(conn, NULL, 0); - if(result) - return result; - break; - case CURL_HTTP_VERSION_1_1: - /* continue with HTTP/1.1 when explicitly requested */ - break; - default: - /* Check if user wants to use HTTP/2 with clear TCP*/ -#ifdef USE_NGHTTP2 - if(conn->data->set.httpversion == - CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { - DEBUGF(infof(data, "HTTP/2 over clean TCP\n")); - conn->httpversion = 20; - - result = Curl_http2_switched(conn, NULL, 0); - if(result) - return result; - } -#endif - break; - } - } - else { - /* prepare for a http2 request */ - result = Curl_http2_setup(conn); - if(result) - return result; - } - - http = data->req.protop; - - if(!data->state.this_is_a_follow) { - /* Free to avoid leaking memory on multiple requests*/ - free(data->state.first_host); - - data->state.first_host = strdup(conn->host.name); - if(!data->state.first_host) - return CURLE_OUT_OF_MEMORY; - - data->state.first_remote_port = conn->remote_port; - } - http->writebytecount = http->readbytecount = 0; - - if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && - data->set.upload) { - httpreq = HTTPREQ_PUT; - } - - /* Now set the 'request' pointer to the proper request string */ - if(data->set.str[STRING_CUSTOMREQUEST]) - request = data->set.str[STRING_CUSTOMREQUEST]; - else { - if(data->set.opt_no_body) - request = "HEAD"; - else { - DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST)); - switch(httpreq) { - case HTTPREQ_POST: - case HTTPREQ_POST_FORM: - case HTTPREQ_POST_MIME: - request = "POST"; - break; - case HTTPREQ_PUT: - request = "PUT"; - break; - case HTTPREQ_OPTIONS: - request = "OPTIONS"; - break; - default: /* this should never happen */ - case HTTPREQ_GET: - request = "GET"; - break; - case HTTPREQ_HEAD: - request = "HEAD"; - break; - } - } - } - - /* The User-Agent string might have been allocated in url.c already, because - it might have been used in the proxy connect, but if we have got a header - with the user-agent string specified, we erase the previously made string - here. */ - if(Curl_checkheaders(conn, "User-Agent:")) { - free(conn->allocptr.uagent); - conn->allocptr.uagent = NULL; - } - - /* setup the authentication headers */ - result = Curl_http_output_auth(conn, request, ppath, FALSE); - if(result) - return result; - - if((data->state.authhost.multipass || data->state.authproxy.multipass) && - (httpreq != HTTPREQ_GET) && - (httpreq != HTTPREQ_HEAD)) { - /* Auth is required and we are not authenticated yet. Make a PUT or POST - with content-length zero as a "probe". */ - conn->bits.authneg = TRUE; - } - else - conn->bits.authneg = FALSE; - - Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) { - conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); - if(!conn->allocptr.ref) - return CURLE_OUT_OF_MEMORY; - } - else - conn->allocptr.ref = NULL; - -#if !defined(CURL_DISABLE_COOKIES) - if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie:")) - addcookies = data->set.str[STRING_COOKIE]; -#endif - - if(!Curl_checkheaders(conn, "Accept-Encoding:") && - data->set.str[STRING_ENCODING]) { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = - aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); - if(!conn->allocptr.accept_encoding) - return CURLE_OUT_OF_MEMORY; - } - else { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = NULL; - } - -#ifdef HAVE_LIBZ - /* we only consider transfer-encoding magic if libz support is built-in */ - - if(!Curl_checkheaders(conn, "TE:") && - data->set.http_transfer_encoding) { - /* When we are to insert a TE: header in the request, we must also insert - TE in a Connection: header, so we need to merge the custom provided - Connection: header and prevent the original to get sent. Note that if - the user has inserted his/hers own TE: header we don't do this magic - but then assume that the user will handle it all! */ - char *cptr = Curl_checkheaders(conn, "Connection:"); -#define TE_HEADER "TE: gzip\r\n" - - Curl_safefree(conn->allocptr.te); - - /* Create the (updated) Connection: header */ - conn->allocptr.te = cptr? aprintf("%s, TE\r\n" TE_HEADER, cptr): - strdup("Connection: TE\r\n" TE_HEADER); - - if(!conn->allocptr.te) - return CURLE_OUT_OF_MEMORY; - } -#endif - - switch(httpreq) { - case HTTPREQ_POST_MIME: - http->sendit = &data->set.mimepost; - break; - case HTTPREQ_POST_FORM: - /* Convert the form structure into a mime structure. */ - Curl_mime_cleanpart(&http->form); - result = Curl_getformdata(data, &http->form, data->set.httppost, - data->state.fread_func); - if(result) - return result; - http->sendit = &http->form; - break; - default: - http->sendit = NULL; - } - - if(http->sendit) { - const char *cthdr = Curl_checkheaders(conn, "Content-Type:"); - - /* Read and seek body only. */ - http->sendit->flags |= MIME_BODY_ONLY; - - /* Prepare the mime structure headers & set content type. */ - - if(cthdr) - for(cthdr += 13; *cthdr == ' '; cthdr++) - ; - else if(http->sendit->kind == MIMEKIND_MULTIPART) - cthdr = "multipart/form-data"; - - curl_mime_headers(http->sendit, data->set.headers, 0); - result = Curl_mime_prepare_headers(http->sendit, cthdr, - NULL, MIMESTRATEGY_FORM); - curl_mime_headers(http->sendit, NULL, 0); - if(!result) - result = Curl_mime_rewind(http->sendit); - if(result) - return result; - http->postsize = Curl_mime_size(http->sendit); - } - - ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); - if(ptr) { - /* Some kind of TE is requested, check if 'chunked' is chosen */ - data->req.upload_chunky = - Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); - } - else { - if((conn->handler->protocol & PROTO_FAMILY_HTTP) && - (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && - http->postsize < 0) || - (data->set.upload && data->state.infilesize == -1))) { - if(conn->bits.authneg) - /* don't enable chunked during auth neg */ - ; - else if(use_http_1_1plus(data, conn)) { - /* HTTP, upload, unknown file size and not HTTP 1.0 */ - data->req.upload_chunky = TRUE; - } - else { - failf(data, "Chunky upload is not supported by HTTP 1.0"); - return CURLE_UPLOAD_FAILED; - } - } - else { - /* else, no chunky upload */ - data->req.upload_chunky = FALSE; - } - - if(data->req.upload_chunky) - te = "Transfer-Encoding: chunked\r\n"; - } - - Curl_safefree(conn->allocptr.host); - - ptr = Curl_checkheaders(conn, "Host:"); - if(ptr && (!data->state.this_is_a_follow || - strcasecompare(data->state.first_host, conn->host.name))) { -#if !defined(CURL_DISABLE_COOKIES) - /* If we have a given custom Host: header, we extract the host name in - order to possibly use it for cookie reasons later on. We only allow the - custom Host: header if this is NOT a redirect, as setting Host: in the - redirected request is being out on thin ice. Except if the host name - is the same as the first one! */ - char *cookiehost = Curl_copy_header_value(ptr); - if(!cookiehost) - return CURLE_OUT_OF_MEMORY; - if(!*cookiehost) - /* ignore empty data */ - free(cookiehost); - else { - /* If the host begins with '[', we start searching for the port after - the bracket has been closed */ - int startsearch = 0; - if(*cookiehost == '[') { - char *closingbracket; - /* since the 'cookiehost' is an allocated memory area that will be - freed later we cannot simply increment the pointer */ - memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1); - closingbracket = strchr(cookiehost, ']'); - if(closingbracket) - *closingbracket = 0; - } - else { - char *colon = strchr(cookiehost + startsearch, ':'); - if(colon) - *colon = 0; /* The host must not include an embedded port number */ - } - Curl_safefree(conn->allocptr.cookiehost); - conn->allocptr.cookiehost = cookiehost; - } -#endif - - if(strcmp("Host:", ptr)) { - conn->allocptr.host = aprintf("%s\r\n", ptr); - if(!conn->allocptr.host) - return CURLE_OUT_OF_MEMORY; - } - else - /* when clearing the header */ - conn->allocptr.host = NULL; - } - else { - /* When building Host: headers, we must put the host name within - [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ - - if(((conn->given->protocol&CURLPROTO_HTTPS) && - (conn->remote_port == PORT_HTTPS)) || - ((conn->given->protocol&CURLPROTO_HTTP) && - (conn->remote_port == PORT_HTTP)) ) - /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include - the port number in the host string */ - conn->allocptr.host = aprintf("Host: %s%s%s\r\n", - conn->bits.ipv6_ip?"[":"", - host, - conn->bits.ipv6_ip?"]":""); - else - conn->allocptr.host = aprintf("Host: %s%s%s:%hu\r\n", - conn->bits.ipv6_ip?"[":"", - host, - conn->bits.ipv6_ip?"]":"", - conn->remote_port); - - if(!conn->allocptr.host) - /* without Host: we can't make a nice request */ - return CURLE_OUT_OF_MEMORY; - } - -#ifndef CURL_DISABLE_PROXY - if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { - /* Using a proxy but does not tunnel through it */ - - /* The path sent to the proxy is in fact the entire URL. But if the remote - host is a IDN-name, we must make sure that the request we produce only - uses the encoded host name! */ - if(conn->host.dispname != conn->host.name) { - char *url = data->change.url; - ptr = strstr(url, conn->host.dispname); - if(ptr) { - /* This is where the display name starts in the URL, now replace this - part with the encoded name. TODO: This method of replacing the host - name is rather crude as I believe there's a slight risk that the - user has entered a user name or password that contain the host name - string. */ - size_t currlen = strlen(conn->host.dispname); - size_t newlen = strlen(conn->host.name); - size_t urllen = strlen(url); - - char *newurl; - - newurl = malloc(urllen + newlen - currlen + 1); - if(newurl) { - /* copy the part before the host name */ - memcpy(newurl, url, ptr - url); - /* append the new host name instead of the old */ - memcpy(newurl + (ptr - url), conn->host.name, newlen); - /* append the piece after the host name */ - memcpy(newurl + newlen + (ptr - url), - ptr + currlen, /* copy the trailing zero byte too */ - urllen - (ptr-url) - currlen + 1); - if(data->change.url_alloc) { - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - data->change.url = newurl; - data->change.url_alloc = TRUE; - } - else - return CURLE_OUT_OF_MEMORY; - } - } - ppath = data->change.url; - if(checkprefix("ftp://", ppath)) { - if(data->set.proxy_transfer_mode) { - /* when doing ftp, append ;type= if not present */ - char *type = strstr(ppath, ";type="); - if(type && type[6] && type[7] == 0) { - switch(Curl_raw_toupper(type[6])) { - case 'A': - case 'D': - case 'I': - break; - default: - type = NULL; - } - } - if(!type) { - char *p = ftp_typecode; - /* avoid sending invalid URLs like ftp://example.com;type=i if the - * user specified ftp://example.com without the slash */ - if(!*data->state.path && ppath[strlen(ppath) - 1] != '/') { - *p++ = '/'; - } - snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c", - data->set.prefer_ascii ? 'a' : 'i'); - } - } - if(conn->bits.user_passwd && !conn->bits.userpwd_in_url) - paste_ftp_userpwd = TRUE; - } - } -#endif /* CURL_DISABLE_PROXY */ - - http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n"; - - if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) && - data->state.resume_from) { - /********************************************************************** - * Resuming upload in HTTP means that we PUT or POST and that we have - * got a resume_from value set. The resume value has already created - * a Range: header that will be passed along. We need to "fast forward" - * the file the given number of bytes and decrease the assume upload - * file size before we continue this venture in the dark lands of HTTP. - * Resuming mime/form posting at an offset > 0 has no sense and is ignored. - *********************************************************************/ - - if(data->state.resume_from < 0) { - /* - * This is meant to get the size of the present remote-file by itself. - * We don't support this now. Bail out! - */ - data->state.resume_from = 0; - } - - if(data->state.resume_from && !data->state.this_is_a_follow) { - /* do we still game? */ - - /* Now, let's read off the proper amount of bytes from the - input. */ - if(conn->seek_func) { - seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, - SEEK_SET); - } - - if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed = 0; - - if(seekerr != CURL_SEEKFUNC_CANTSEEK) { - failf(data, "Could not seek stream"); - return CURLE_READ_ERROR; - } - /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ - do { - size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : - curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, readthisamountnow, - data->state.in); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T - " bytes from the input", passed); - return CURLE_READ_ERROR; - } - } while(passed < data->state.resume_from); - } - - /* now, decrease the size of the read */ - if(data->state.infilesize>0) { - data->state.infilesize -= data->state.resume_from; - - if(data->state.infilesize <= 0) { - failf(data, "File already completely uploaded"); - return CURLE_PARTIAL_FILE; - } - } - /* we've passed, proceed as normal */ - } - } - if(data->state.use_range) { - /* - * A range is selected. We use different headers whether we're downloading - * or uploading and we always let customized headers override our internal - * ones if any such are specified. - */ - if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && - !Curl_checkheaders(conn, "Range:")) { - /* if a line like this was already allocated, free the previous one */ - free(conn->allocptr.rangeline); - conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", - data->state.range); - } - else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && - !Curl_checkheaders(conn, "Content-Range:")) { - - /* if a line like this was already allocated, free the previous one */ - free(conn->allocptr.rangeline); - - if(data->set.set_resume_from < 0) { - /* Upload resume was asked for, but we don't know the size of the - remote part so we tell the server (and act accordingly) that we - upload the whole file (again) */ - conn->allocptr.rangeline = - aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T - "/%" CURL_FORMAT_CURL_OFF_T "\r\n", - data->state.infilesize - 1, data->state.infilesize); - - } - else if(data->state.resume_from) { - /* This is because "resume" was selected */ - curl_off_t total_expected_size = - data->state.resume_from + data->state.infilesize; - conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T - "/%" CURL_FORMAT_CURL_OFF_T "\r\n", - data->state.range, total_expected_size-1, - total_expected_size); - } - else { - /* Range was selected and then we just pass the incoming range and - append total size */ - conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n", - data->state.range, data->state.infilesize); - } - if(!conn->allocptr.rangeline) - return CURLE_OUT_OF_MEMORY; - } - } - - httpstring = get_http_string(data, conn); - - /* initialize a dynamic send-buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; - - /* add the main request stuff */ - /* GET/HEAD/POST/PUT */ - result = Curl_add_bufferf(req_buffer, "%s ", request); - if(result) - return result; - - if(data->set.str[STRING_TARGET]) - ppath = data->set.str[STRING_TARGET]; - - /* url */ - if(paste_ftp_userpwd) - result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s", - conn->user, conn->passwd, - ppath + sizeof("ftp://") - 1); - else - result = Curl_add_buffer(req_buffer, ppath, strlen(ppath)); - if(result) - return result; - - result = - Curl_add_bufferf(req_buffer, - "%s" /* ftp typecode (;type=x) */ - " HTTP/%s\r\n" /* HTTP version */ - "%s" /* host */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - "%s" /* range */ - "%s" /* user agent */ - "%s" /* accept */ - "%s" /* TE: */ - "%s" /* accept-encoding */ - "%s" /* referer */ - "%s" /* Proxy-Connection */ - "%s",/* transfer-encoding */ - - ftp_typecode, - httpstring, - (conn->allocptr.host?conn->allocptr.host:""), - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - conn->allocptr.userpwd?conn->allocptr.userpwd:"", - (data->state.use_range && conn->allocptr.rangeline)? - conn->allocptr.rangeline:"", - (data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && - conn->allocptr.uagent)? - conn->allocptr.uagent:"", - http->p_accept?http->p_accept:"", - conn->allocptr.te?conn->allocptr.te:"", - (data->set.str[STRING_ENCODING] && - *data->set.str[STRING_ENCODING] && - conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)? - conn->allocptr.ref:"" /* Referer: */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkProxyheaders(conn, "Proxy-Connection:"))? - "Proxy-Connection: Keep-Alive\r\n":"", - te - ); - - /* clear userpwd and proxyuserpwd to avoid re-using old credentials - * from re-used connections */ - Curl_safefree(conn->allocptr.userpwd); - Curl_safefree(conn->allocptr.proxyuserpwd); - - if(result) - return result; - - if(!(conn->handler->flags&PROTOPT_SSL) && - conn->httpversion != 20 && - (data->set.httpversion == CURL_HTTP_VERSION_2)) { - /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done - over SSL */ - result = Curl_http2_request_upgrade(req_buffer, conn); - if(result) - return result; - } - -#if !defined(CURL_DISABLE_COOKIES) - if(data->cookies || addcookies) { - struct Cookie *co = NULL; /* no cookies from start */ - int count = 0; - - if(data->cookies) { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - co = Curl_cookie_getlist(data->cookies, - conn->allocptr.cookiehost? - conn->allocptr.cookiehost:host, - data->state.path, - (conn->handler->protocol&CURLPROTO_HTTPS)? - TRUE:FALSE); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - if(co) { - struct Cookie *store = co; - /* now loop through all cookies that matched */ - while(co) { - if(co->value) { - if(0 == count) { - result = Curl_add_bufferf(req_buffer, "Cookie: "); - if(result) - break; - } - result = Curl_add_bufferf(req_buffer, - "%s%s=%s", count?"; ":"", - co->name, co->value); - if(result) - break; - count++; - } - co = co->next; /* next cookie please */ - } - Curl_cookie_freelist(store); - } - if(addcookies && !result) { - if(!count) - result = Curl_add_bufferf(req_buffer, "Cookie: "); - if(!result) { - result = Curl_add_bufferf(req_buffer, "%s%s", count?"; ":"", - addcookies); - count++; - } - } - if(count && !result) - result = Curl_add_buffer(req_buffer, "\r\n", 2); - - if(result) - return result; - } -#endif - - result = Curl_add_timecondition(data, req_buffer); - if(result) - return result; - - result = Curl_add_custom_headers(conn, FALSE, req_buffer); - if(result) - return result; - - http->postdata = NULL; /* nothing to post at this point */ - Curl_pgrsSetUploadSize(data, -1); /* upload size is unknown atm */ - - /* If 'authdone' is FALSE, we must not set the write socket index to the - Curl_transfer() call below, as we're not ready to actually upload any - data yet. */ - - switch(httpreq) { - - case HTTPREQ_PUT: /* Let's PUT the data to the server! */ - - if(conn->bits.authneg) - postsize = 0; - else - postsize = data->state.infilesize; - - if((postsize != -1) && !data->req.upload_chunky && - (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { - /* only add Content-Length if not uploading chunked */ - result = Curl_add_bufferf(req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); - if(result) - return result; - } - - if(postsize != 0) { - result = expect100(data, conn, req_buffer); - if(result) - return result; - } - - result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */ - if(result) - return result; - - /* set the upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, postsize); - - /* this sends the buffer and frees all the buffer resources */ - result = Curl_add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - if(result) - failf(data, "Failed sending PUT request"); - else - /* prepare for transfer */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, postsize?FIRSTSOCKET:-1, - postsize?&http->writebytecount:NULL); - if(result) - return result; - break; - - case HTTPREQ_POST_FORM: - case HTTPREQ_POST_MIME: - /* This is form posting using mime data. */ - if(conn->bits.authneg) { - /* nothing to post! */ - result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n"); - if(result) - return result; - - result = Curl_add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - if(result) - failf(data, "Failed sending POST request"); - else - /* setup variables for the upcoming transfer */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - -1, NULL); - break; - } - - postsize = http->postsize; - - /* We only set Content-Length and allow a custom Content-Length if - we don't upload data chunked, as RFC2616 forbids us to set both - kinds of headers (Transfer-Encoding: chunked and Content-Length) */ - if(postsize != -1 && !data->req.upload_chunky && - (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { - /* we allow replacing this header if not during auth negotiation, - although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); - if(result) - return result; - } - - /* Output mime-generated headers. */ - { - struct curl_slist *hdr; - - for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) { - result = Curl_add_bufferf(req_buffer, "%s\r\n", hdr->data); - if(result) - return result; - } - } - - /* For really small posts we don't use Expect: headers at all, and for - the somewhat bigger ones we allow the app to disable it. Just make - sure that the expect100header is always set to the preferred value - here. */ - ptr = Curl_checkheaders(conn, "Expect:"); - if(ptr) { - data->state.expect100header = - Curl_compareheader(ptr, "Expect:", "100-continue"); - } - else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { - result = expect100(data, conn, req_buffer); - if(result) - return result; - } - else - data->state.expect100header = FALSE; - - /* make the request end in a true CRLF */ - result = Curl_add_buffer(req_buffer, "\r\n", 2); - if(result) - return result; - - /* set the upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, postsize); - - /* Read from mime structure. */ - data->state.fread_func = (curl_read_callback) Curl_mime_read; - data->state.in = (void *) http->sendit; - http->sending = HTTPSEND_BODY; - - /* this sends the buffer and frees all the buffer resources */ - result = Curl_add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - if(result) - failf(data, "Failed sending POST request"); - else - /* prepare for transfer */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, postsize?FIRSTSOCKET:-1, - postsize?&http->writebytecount:NULL); - if(result) - return result; - - break; - - case HTTPREQ_POST: - /* this is the simple POST, using x-www-form-urlencoded style */ - - if(conn->bits.authneg) - postsize = 0; - else - /* the size of the post body */ - postsize = data->state.infilesize; - - /* We only set Content-Length and allow a custom Content-Length if - we don't upload data chunked, as RFC2616 forbids us to set both - kinds of headers (Transfer-Encoding: chunked and Content-Length) */ - if((postsize != -1) && !data->req.upload_chunky && - (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { - /* we allow replacing this header if not during auth negotiation, - although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); - if(result) - return result; - } - - if(!Curl_checkheaders(conn, "Content-Type:")) { - result = Curl_add_bufferf(req_buffer, - "Content-Type: application/" - "x-www-form-urlencoded\r\n"); - if(result) - return result; - } - - /* For really small posts we don't use Expect: headers at all, and for - the somewhat bigger ones we allow the app to disable it. Just make - sure that the expect100header is always set to the preferred value - here. */ - ptr = Curl_checkheaders(conn, "Expect:"); - if(ptr) { - data->state.expect100header = - Curl_compareheader(ptr, "Expect:", "100-continue"); - } - else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { - result = expect100(data, conn, req_buffer); - if(result) - return result; - } - else - data->state.expect100header = FALSE; - - if(data->set.postfields) { - - /* In HTTP2, we send request body in DATA frame regardless of - its size. */ - if(conn->httpversion != 20 && - !data->state.expect100header && - (postsize < MAX_INITIAL_POST_SIZE)) { - /* if we don't use expect: 100 AND - postsize is less than MAX_INITIAL_POST_SIZE - - then append the post data to the HTTP request header. This limit - is no magic limit but only set to prevent really huge POSTs to - get the data duplicated with malloc() and family. */ - - result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ - if(result) - return result; - - if(!data->req.upload_chunky) { - /* We're not sending it 'chunked', append it to the request - already now to reduce the number if send() calls */ - result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); - included_body = postsize; - } - else { - if(postsize) { - /* Append the POST data chunky-style */ - result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize); - if(!result) { - result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); - if(!result) - result = Curl_add_buffer(req_buffer, "\r\n", 2); - included_body = postsize + 2; - } - } - if(!result) - result = Curl_add_buffer(req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); - /* 0 CR LF CR LF */ - included_body += 5; - } - if(result) - return result; - /* Make sure the progress information is accurate */ - Curl_pgrsSetUploadSize(data, postsize); - } - else { - /* A huge POST coming up, do data separate from the request */ - http->postsize = postsize; - http->postdata = data->set.postfields; - - http->sending = HTTPSEND_BODY; - - data->state.fread_func = (curl_read_callback)readmoredata; - data->state.in = (void *)conn; - - /* set the upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, http->postsize); - - result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ - if(result) - return result; - } - } - else { - result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ - if(result) - return result; - - if(data->req.upload_chunky && conn->bits.authneg) { - /* Chunky upload is selected and we're negotiating auth still, send - end-of-data only */ - result = Curl_add_buffer(req_buffer, - "\x30\x0d\x0a\x0d\x0a", 5); - /* 0 CR LF CR LF */ - if(result) - return result; - } - - else if(data->state.infilesize) { - /* set the upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, postsize?postsize:-1); - - /* set the pointer to mark that we will send the post body using the - read callback, but only if we're not in authenticate - negotiation */ - if(!conn->bits.authneg) { - http->postdata = (char *)&http->postdata; - http->postsize = postsize; - } - } - } - /* issue the request */ - result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size, - (size_t)included_body, FIRSTSOCKET); - - if(result) - failf(data, "Failed sending HTTP POST request"); - else - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, http->postdata?FIRSTSOCKET:-1, - http->postdata?&http->writebytecount:NULL); - break; - - default: - result = Curl_add_buffer(req_buffer, "\r\n", 2); - if(result) - return result; - - /* issue the request */ - result = Curl_add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - - if(result) - failf(data, "Failed sending HTTP request"); - else - /* HTTP GET/HEAD download: */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - http->postdata?FIRSTSOCKET:-1, - http->postdata?&http->writebytecount:NULL); - } - if(result) - return result; - - if(http->writebytecount) { - /* if a request-body has been sent off, we make sure this progress is noted - properly */ - Curl_pgrsSetUploadCounter(data, http->writebytecount); - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - - if(http->writebytecount >= postsize) { - /* already sent the entire request body, mark the "upload" as - complete */ - infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T - " out of %" CURL_FORMAT_CURL_OFF_T " bytes\n", - http->writebytecount, postsize); - data->req.upload_done = TRUE; - data->req.keepon &= ~KEEP_SEND; /* we're done writing */ - data->req.exp100 = EXP100_SEND_DATA; /* already sent */ - Curl_expire_done(data, EXPIRE_100_TIMEOUT); - } - } - - if((conn->httpversion == 20) && data->req.upload_chunky) - /* upload_chunky was set above to set up the request in a chunky fashion, - but is disabled here again to avoid that the chunked encoded version is - actually used when sending the request body over h2 */ - data->req.upload_chunky = FALSE; - return result; -} - -/* - * checkhttpprefix() - * - * Returns TRUE if member of the list matches prefix of string - */ -static bool -checkhttpprefix(struct Curl_easy *data, - const char *s) -{ - struct curl_slist *head = data->set.http200aliases; - bool rc = FALSE; -#ifdef CURL_DOES_CONVERSIONS - /* convert from the network encoding using a scratch area */ - char *scratch = strdup(s); - if(NULL == scratch) { - failf(data, "Failed to allocate memory for conversion!"); - return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ - } - if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { - /* Curl_convert_from_network calls failf if unsuccessful */ - free(scratch); - return FALSE; /* can't return CURLE_foobar so return FALSE */ - } - s = scratch; -#endif /* CURL_DOES_CONVERSIONS */ - - while(head) { - if(checkprefix(head->data, s)) { - rc = TRUE; - break; - } - head = head->next; - } - - if(!rc && (checkprefix("HTTP/", s))) - rc = TRUE; - -#ifdef CURL_DOES_CONVERSIONS - free(scratch); -#endif /* CURL_DOES_CONVERSIONS */ - return rc; -} - -#ifndef CURL_DISABLE_RTSP -static bool -checkrtspprefix(struct Curl_easy *data, - const char *s) -{ - bool result = FALSE; - -#ifdef CURL_DOES_CONVERSIONS - /* convert from the network encoding using a scratch area */ - char *scratch = strdup(s); - if(NULL == scratch) { - failf(data, "Failed to allocate memory for conversion!"); - return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ - } - if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { - /* Curl_convert_from_network calls failf if unsuccessful */ - result = FALSE; /* can't return CURLE_foobar so return FALSE */ - } - else - result = checkprefix("RTSP/", scratch)? TRUE: FALSE; - free(scratch); -#else - (void)data; /* unused */ - result = checkprefix("RTSP/", s)? TRUE: FALSE; -#endif /* CURL_DOES_CONVERSIONS */ - - return result; -} -#endif /* CURL_DISABLE_RTSP */ - -static bool -checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, - const char *s) -{ -#ifndef CURL_DISABLE_RTSP - if(conn->handler->protocol & CURLPROTO_RTSP) - return checkrtspprefix(data, s); -#else - (void)conn; -#endif /* CURL_DISABLE_RTSP */ - - return checkhttpprefix(data, s); -} - -/* - * header_append() copies a chunk of data to the end of the already received - * header. We make sure that the full string fit in the allocated header - * buffer, or else we enlarge it. - */ -static CURLcode header_append(struct Curl_easy *data, - struct SingleRequest *k, - size_t length) -{ - if(k->hbuflen + length >= data->state.headersize) { - /* We enlarge the header buffer as it is too small */ - char *newbuff; - size_t hbufp_index; - size_t newsize; - - if(k->hbuflen + length > CURL_MAX_HTTP_HEADER) { - /* The reason to have a max limit for this is to avoid the risk of a bad - server feeding libcurl with a never-ending header that will cause - reallocs infinitely */ - failf(data, "Avoided giant realloc for header (max is %d)!", - CURL_MAX_HTTP_HEADER); - return CURLE_OUT_OF_MEMORY; - } - - newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2); - hbufp_index = k->hbufp - data->state.headerbuff; - newbuff = realloc(data->state.headerbuff, newsize); - if(!newbuff) { - failf(data, "Failed to alloc memory for big header!"); - return CURLE_OUT_OF_MEMORY; - } - data->state.headersize = newsize; - data->state.headerbuff = newbuff; - k->hbufp = data->state.headerbuff + hbufp_index; - } - memcpy(k->hbufp, k->str_start, length); - k->hbufp += length; - k->hbuflen += length; - *k->hbufp = 0; - - return CURLE_OK; -} - -static void print_http_error(struct Curl_easy *data) -{ - struct SingleRequest *k = &data->req; - char *beg = k->p; - - /* make sure that data->req.p points to the HTTP status line */ - if(!strncmp(beg, "HTTP", 4)) { - - /* skip to HTTP status code */ - beg = strchr(beg, ' '); - if(beg && *++beg) { - - /* find trailing CR */ - char end_char = '\r'; - char *end = strchr(beg, end_char); - if(!end) { - /* try to find LF (workaround for non-compliant HTTP servers) */ - end_char = '\n'; - end = strchr(beg, end_char); - } - - if(end) { - /* temporarily replace CR or LF by NUL and print the error message */ - *end = '\0'; - failf(data, "The requested URL returned error: %s", beg); - - /* restore the previously replaced CR or LF */ - *end = end_char; - return; - } - } - } - - /* fall-back to printing the HTTP status code only */ - failf(data, "The requested URL returned error: %d", k->httpcode); -} - -/* - * Read any HTTP header lines from the server and pass them to the client app. - */ -CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, - struct connectdata *conn, - ssize_t *nread, - bool *stop_reading) -{ - CURLcode result; - struct SingleRequest *k = &data->req; - - /* header line within buffer loop */ - do { - size_t rest_length; - size_t full_length; - int writetype; - - /* str_start is start of line within buf */ - k->str_start = k->str; - - /* data is in network encoding so use 0x0a instead of '\n' */ - k->end_ptr = memchr(k->str_start, 0x0a, *nread); - - if(!k->end_ptr) { - /* Not a complete header line within buffer, append the data to - the end of the headerbuff. */ - result = header_append(data, k, *nread); - if(result) - return result; - - if(!k->headerline && (k->hbuflen>5)) { - /* make a first check that this looks like a protocol header */ - if(!checkprotoprefix(data, conn, data->state.headerbuff)) { - /* this is not the beginning of a protocol first header line */ - k->header = FALSE; - k->badheader = HEADER_ALLBAD; - break; - } - } - - break; /* read more and try again */ - } - - /* decrease the size of the remaining (supposed) header line */ - rest_length = (k->end_ptr - k->str) + 1; - *nread -= (ssize_t)rest_length; - - k->str = k->end_ptr + 1; /* move past new line */ - - full_length = k->str - k->str_start; - - result = header_append(data, k, full_length); - if(result) - return result; - - k->end_ptr = k->hbufp; - k->p = data->state.headerbuff; - - /**** - * We now have a FULL header line that p points to - *****/ - - if(!k->headerline) { - /* the first read header */ - if((k->hbuflen>5) && - !checkprotoprefix(data, conn, data->state.headerbuff)) { - /* this is not the beginning of a protocol first header line */ - k->header = FALSE; - if(*nread) - /* since there's more, this is a partial bad header */ - k->badheader = HEADER_PARTHEADER; - else { - /* this was all we read so it's all a bad header */ - k->badheader = HEADER_ALLBAD; - *nread = (ssize_t)rest_length; - } - break; - } - } - - /* headers are in network encoding so - use 0x0a and 0x0d instead of '\n' and '\r' */ - if((0x0a == *k->p) || (0x0d == *k->p)) { - size_t headerlen; - /* Zero-length header line means end of headers! */ - -#ifdef CURL_DOES_CONVERSIONS - if(0x0d == *k->p) { - *k->p = '\r'; /* replace with CR in host encoding */ - k->p++; /* pass the CR byte */ - } - if(0x0a == *k->p) { - *k->p = '\n'; /* replace with LF in host encoding */ - k->p++; /* pass the LF byte */ - } -#else - if('\r' == *k->p) - k->p++; /* pass the \r byte */ - if('\n' == *k->p) - k->p++; /* pass the \n byte */ -#endif /* CURL_DOES_CONVERSIONS */ - - if(100 <= k->httpcode && 199 >= k->httpcode) { - /* "A user agent MAY ignore unexpected 1xx status responses." */ - switch(k->httpcode) { - case 100: - /* - * We have made a HTTP PUT or POST and this is 1.1-lingo - * that tells us that the server is OK with this and ready - * to receive the data. - * However, we'll get more headers now so we must get - * back into the header-parsing state! - */ - k->header = TRUE; - k->headerline = 0; /* restart the header line counter */ - - /* if we did wait for this do enable write now! */ - if(k->exp100 > EXP100_SEND_DATA) { - k->exp100 = EXP100_SEND_DATA; - k->keepon |= KEEP_SEND; - Curl_expire_done(data, EXPIRE_100_TIMEOUT); - } - break; - case 101: - /* Switching Protocols */ - if(k->upgr101 == UPGR101_REQUESTED) { - /* Switching to HTTP/2 */ - infof(data, "Received 101\n"); - k->upgr101 = UPGR101_RECEIVED; - - /* we'll get more headers (HTTP/2 response) */ - k->header = TRUE; - k->headerline = 0; /* restart the header line counter */ - - /* switch to http2 now. The bytes after response headers - are also processed here, otherwise they are lost. */ - result = Curl_http2_switched(conn, k->str, *nread); - if(result) - return result; - *nread = 0; - } - else { - /* Switching to another protocol (e.g. WebSocket) */ - k->header = FALSE; /* no more header to parse! */ - } - break; - default: - /* the status code 1xx indicates a provisional response, so - we'll get another set of headers */ - k->header = TRUE; - k->headerline = 0; /* restart the header line counter */ - break; - } - } - else { - k->header = FALSE; /* no more header to parse! */ - - if((k->size == -1) && !k->chunk && !conn->bits.close && - (conn->httpversion == 11) && - !(conn->handler->protocol & CURLPROTO_RTSP) && - data->set.httpreq != HTTPREQ_HEAD) { - /* On HTTP 1.1, when connection is not to get closed, but no - Content-Length nor Content-Encoding chunked have been - received, according to RFC2616 section 4.4 point 5, we - assume that the server will close the connection to - signal the end of the document. */ - infof(data, "no chunk, no close, no size. Assume close to " - "signal end\n"); - streamclose(conn, "HTTP: No end-of-message indicator"); - } - } - - /* At this point we have some idea about the fate of the connection. - If we are closing the connection it may result auth failure. */ -#if defined(USE_NTLM) - if(conn->bits.close && - (((data->req.httpcode == 401) && - (conn->ntlm.state == NTLMSTATE_TYPE2)) || - ((data->req.httpcode == 407) && - (conn->proxyntlm.state == NTLMSTATE_TYPE2)))) { - infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n"); - data->state.authproblem = TRUE; - } -#endif - - /* - * When all the headers have been parsed, see if we should give - * up and return an error. - */ - if(http_should_fail(conn)) { - failf(data, "The requested URL returned error: %d", - k->httpcode); - return CURLE_HTTP_RETURNED_ERROR; - } - - /* now, only output this if the header AND body are requested: - */ - writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; - - headerlen = k->p - data->state.headerbuff; - - result = Curl_client_write(conn, writetype, - data->state.headerbuff, - headerlen); - if(result) - return result; - - data->info.header_size += (long)headerlen; - data->req.headerbytecount += (long)headerlen; - - data->req.deductheadercount = - (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; - - /* Curl_http_auth_act() checks what authentication methods - * that are available and decides which one (if any) to - * use. It will set 'newurl' if an auth method was picked. */ - result = Curl_http_auth_act(conn); - - if(result) - return result; - - if(k->httpcode >= 300) { - if((!conn->bits.authneg) && !conn->bits.close && - !conn->bits.rewindaftersend) { - /* - * General treatment of errors when about to send data. Including : - * "417 Expectation Failed", while waiting for 100-continue. - * - * The check for close above is done simply because of something - * else has already deemed the connection to get closed then - * something else should've considered the big picture and we - * avoid this check. - * - * rewindaftersend indicates that something has told libcurl to - * continue sending even if it gets discarded - */ - - switch(data->set.httpreq) { - case HTTPREQ_PUT: - case HTTPREQ_POST: - case HTTPREQ_POST_FORM: - case HTTPREQ_POST_MIME: - /* We got an error response. If this happened before the whole - * request body has been sent we stop sending and mark the - * connection for closure after we've read the entire response. - */ - Curl_expire_done(data, EXPIRE_100_TIMEOUT); - if(!k->upload_done) { - if(data->set.http_keep_sending_on_error) { - infof(data, "HTTP error before end of send, keep sending\n"); - if(k->exp100 > EXP100_SEND_DATA) { - k->exp100 = EXP100_SEND_DATA; - k->keepon |= KEEP_SEND; - } - } - else { - infof(data, "HTTP error before end of send, stop sending\n"); - streamclose(conn, "Stop sending data before everything sent"); - k->upload_done = TRUE; - k->keepon &= ~KEEP_SEND; /* don't send */ - if(data->state.expect100header) - k->exp100 = EXP100_FAILED; - } - } - break; - - default: /* default label present to avoid compiler warnings */ - break; - } - } - - if(conn->bits.rewindaftersend) { - /* We rewind after a complete send, so thus we continue - sending now */ - infof(data, "Keep sending data to get tossed away!\n"); - k->keepon |= KEEP_SEND; - } - } - - if(!k->header) { - /* - * really end-of-headers. - * - * If we requested a "no body", this is a good time to get - * out and return home. - */ - if(data->set.opt_no_body) - *stop_reading = TRUE; -#ifndef CURL_DISABLE_RTSP - else if((conn->handler->protocol & CURLPROTO_RTSP) && - (data->set.rtspreq == RTSPREQ_DESCRIBE) && - (k->size <= -1)) - /* Respect section 4.4 of rfc2326: If the Content-Length header is - absent, a length 0 must be assumed. It will prevent libcurl from - hanging on DESCRIBE request that got refused for whatever - reason */ - *stop_reading = TRUE; -#endif - else { - /* If we know the expected size of this document, we set the - maximum download size to the size of the expected - document or else, we won't know when to stop reading! - - Note that we set the download maximum even if we read a - "Connection: close" header, to make sure that - "Content-Length: 0" still prevents us from attempting to - read the (missing) response-body. - */ - /* According to RFC2616 section 4.4, we MUST ignore - Content-Length: headers if we are now receiving data - using chunked Transfer-Encoding. - */ - if(k->chunk) - k->maxdownload = k->size = -1; - } - if(-1 != k->size) { - /* We do this operation even if no_body is true, since this - data might be retrieved later with curl_easy_getinfo() - and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */ - - Curl_pgrsSetDownloadSize(data, k->size); - k->maxdownload = k->size; - } - - /* If max download size is *zero* (nothing) we already have - nothing and can safely return ok now! But for HTTP/2, we'd - like to call http2_handle_stream_close to properly close a - stream. In order to do this, we keep reading until we - close the stream. */ - if(0 == k->maxdownload -#if defined(USE_NGHTTP2) - && !((conn->handler->protocol & PROTO_FAMILY_HTTP) && - conn->httpversion == 20) -#endif - ) - *stop_reading = TRUE; - - if(*stop_reading) { - /* we make sure that this socket isn't read more now */ - k->keepon &= ~KEEP_RECV; - } - - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - k->str_start, headerlen, conn); - break; /* exit header line loop */ - } - - /* We continue reading headers, so reset the line-based - header parsing variables hbufp && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; - continue; - } - - /* - * Checks for special headers coming up. - */ - - if(!k->headerline++) { - /* This is the first header, it MUST be the error code line - or else we consider this to be the body right away! */ - int httpversion_major; - int rtspversion_major; - int nc = 0; -#ifdef CURL_DOES_CONVERSIONS -#define HEADER1 scratch -#define SCRATCHSIZE 21 - CURLcode res; - char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */ - /* We can't really convert this yet because we - don't know if it's the 1st header line or the body. - So we do a partial conversion into a scratch area, - leaving the data at k->p as-is. - */ - strncpy(&scratch[0], k->p, SCRATCHSIZE); - scratch[SCRATCHSIZE] = 0; /* null terminate */ - res = Curl_convert_from_network(data, - &scratch[0], - SCRATCHSIZE); - if(res) - /* Curl_convert_from_network calls failf if unsuccessful */ - return res; -#else -#define HEADER1 k->p /* no conversion needed, just use k->p */ -#endif /* CURL_DOES_CONVERSIONS */ - - if(conn->handler->protocol & PROTO_FAMILY_HTTP) { - /* - * https://tools.ietf.org/html/rfc7230#section-3.1.2 - * - * The response code is always a three-digit number in HTTP as the spec - * says. We try to allow any number here, but we cannot make - * guarantees on future behaviors since it isn't within the protocol. - */ - char separator; - nc = sscanf(HEADER1, - " HTTP/%1d.%1d%c%3d", - &httpversion_major, - &conn->httpversion, - &separator, - &k->httpcode); - - if(nc == 1 && httpversion_major == 2 && - 1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) { - conn->httpversion = 0; - nc = 4; - separator = ' '; - } - - if((nc == 4) && (' ' == separator)) { - conn->httpversion += 10 * httpversion_major; - - if(k->upgr101 == UPGR101_RECEIVED) { - /* supposedly upgraded to http2 now */ - if(conn->httpversion != 20) - infof(data, "Lying server, not serving HTTP/2\n"); - } - } - else if(!nc) { - /* this is the real world, not a Nirvana - NCSA 1.5.x returns this crap when asked for HTTP/1.1 - */ - nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode); - conn->httpversion = 10; - - /* If user has set option HTTP200ALIASES, - compare header line against list of aliases - */ - if(!nc) { - if(checkhttpprefix(data, k->p)) { - nc = 1; - k->httpcode = 200; - conn->httpversion = 10; - } - } - } - else { - failf(data, "Unsupported HTTP version in response\n"); - return CURLE_UNSUPPORTED_PROTOCOL; - } - } - else if(conn->handler->protocol & CURLPROTO_RTSP) { - nc = sscanf(HEADER1, - " RTSP/%d.%d %3d", - &rtspversion_major, - &conn->rtspversion, - &k->httpcode); - if(nc == 3) { - conn->rtspversion += 10 * rtspversion_major; - conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */ - } - else { - /* TODO: do we care about the other cases here? */ - nc = 0; - } - } - - if(nc) { - data->info.httpcode = k->httpcode; - - data->info.httpversion = conn->httpversion; - if(!data->state.httpversion || - data->state.httpversion > conn->httpversion) - /* store the lowest server version we encounter */ - data->state.httpversion = conn->httpversion; - - /* - * This code executes as part of processing the header. As a - * result, it's not totally clear how to interpret the - * response code yet as that depends on what other headers may - * be present. 401 and 407 may be errors, but may be OK - * depending on how authentication is working. Other codes - * are definitely errors, so give up here. - */ - if(data->set.http_fail_on_error && (k->httpcode >= 400) && - ((k->httpcode != 401) || !conn->bits.user_passwd) && - ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) { - - if(data->state.resume_from && - (data->set.httpreq == HTTPREQ_GET) && - (k->httpcode == 416)) { - /* "Requested Range Not Satisfiable", just proceed and - pretend this is no error */ - } - else { - /* serious error, go home! */ - print_http_error(data); - return CURLE_HTTP_RETURNED_ERROR; - } - } - - if(conn->httpversion == 10) { - /* Default action for HTTP/1.0 must be to close, unless - we get one of those fancy headers that tell us the - server keeps it open for us! */ - infof(data, "HTTP 1.0, assume close after body\n"); - connclose(conn, "HTTP/1.0 close after body"); - } - else if(conn->httpversion == 20 || - (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { - DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n")); - - /* HTTP/2 cannot blacklist multiplexing since it is a core - functionality of the protocol */ - conn->bundle->multiuse = BUNDLE_MULTIPLEX; - } - else if(conn->httpversion >= 11 && - !conn->bits.close) { - /* If HTTP version is >= 1.1 and connection is persistent - server supports pipelining. */ - DEBUGF(infof(data, - "HTTP 1.1 or later with persistent connection, " - "pipelining supported\n")); - /* Activate pipelining if needed */ - if(conn->bundle) { - if(!Curl_pipeline_site_blacklisted(data, conn)) - conn->bundle->multiuse = BUNDLE_PIPELINING; - } - } - - switch(k->httpcode) { - case 204: - /* (quote from RFC2616, section 10.2.5): The server has - * fulfilled the request but does not need to return an - * entity-body ... The 204 response MUST NOT include a - * message-body, and thus is always terminated by the first - * empty line after the header fields. */ - /* FALLTHROUGH */ - case 304: - /* (quote from RFC2616, section 10.3.5): The 304 response - * MUST NOT contain a message-body, and thus is always - * terminated by the first empty line after the header - * fields. */ - if(data->set.timecondition) - data->info.timecond = TRUE; - k->size = 0; - k->maxdownload = 0; - k->ignorecl = TRUE; /* ignore Content-Length headers */ - break; - default: - /* nothing */ - break; - } - } - else { - k->header = FALSE; /* this is not a header line */ - break; - } - } - - result = Curl_convert_from_network(data, k->p, strlen(k->p)); - /* Curl_convert_from_network calls failf if unsuccessful */ - if(result) - return result; - - /* Check for Content-Length: header lines to get size */ - if(!k->ignorecl && !data->set.ignorecl && - checkprefix("Content-Length:", k->p)) { - curl_off_t contentlength; - if(!curlx_strtoofft(k->p + 15, NULL, 10, &contentlength)) { - if(data->set.max_filesize && - contentlength > data->set.max_filesize) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } - if(contentlength >= 0) { - k->size = contentlength; - k->maxdownload = k->size; - /* we set the progress download size already at this point - just to make it easier for apps/callbacks to extract this - info as soon as possible */ - Curl_pgrsSetDownloadSize(data, k->size); - } - else { - /* Negative Content-Length is really odd, and we know it - happens for example when older Apache servers send large - files */ - streamclose(conn, "negative content-length"); - infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T - ", closing after transfer\n", contentlength); - } - } - else - infof(data, "Illegal Content-Length: header\n"); - } - /* check for Content-Type: header lines to get the MIME-type */ - else if(checkprefix("Content-Type:", k->p)) { - char *contenttype = Curl_copy_header_value(k->p); - if(!contenttype) - return CURLE_OUT_OF_MEMORY; - if(!*contenttype) - /* ignore empty data */ - free(contenttype); - else { - Curl_safefree(data->info.contenttype); - data->info.contenttype = contenttype; - } - } - else if(checkprefix("Server:", k->p)) { - if(conn->httpversion < 20) { - /* only do this for non-h2 servers */ - char *server_name = Curl_copy_header_value(k->p); - - /* Turn off pipelining if the server version is blacklisted */ - if(conn->bundle && (conn->bundle->multiuse == BUNDLE_PIPELINING)) { - if(Curl_pipeline_server_blacklisted(data, server_name)) - conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; - } - free(server_name); - } - } - else if((conn->httpversion == 10) && - conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "keep-alive")) { - /* - * When a HTTP/1.0 reply comes when using a proxy, the - * 'Proxy-Connection: keep-alive' line tells us the - * connection will be kept alive for our pleasure. - * Default action for 1.0 is to close. - */ - connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */ - infof(data, "HTTP/1.0 proxy connection set to keep alive!\n"); - } - else if((conn->httpversion == 11) && - conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "close")) { - /* - * We get a HTTP/1.1 response from a proxy and it says it'll - * close down after this transfer. - */ - connclose(conn, "Proxy-Connection: asked to close after done"); - infof(data, "HTTP/1.1 proxy connection set close!\n"); - } - else if((conn->httpversion == 10) && - Curl_compareheader(k->p, "Connection:", "keep-alive")) { - /* - * A HTTP/1.0 reply with the 'Connection: keep-alive' line - * tells us the connection will be kept alive for our - * pleasure. Default action for 1.0 is to close. - * - * [RFC2068, section 19.7.1] */ - connkeep(conn, "Connection keep-alive"); - infof(data, "HTTP/1.0 connection set to keep alive!\n"); - } - else if(Curl_compareheader(k->p, "Connection:", "close")) { - /* - * [RFC 2616, section 8.1.2.1] - * "Connection: close" is HTTP/1.1 language and means that - * the connection will close when this request has been - * served. - */ - streamclose(conn, "Connection: close used"); - } - else if(checkprefix("Transfer-Encoding:", k->p)) { - /* One or more encodings. We check for chunked and/or a compression - algorithm. */ - /* - * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding - * means that the server will send a series of "chunks". Each - * chunk starts with line with info (including size of the - * coming block) (terminated with CRLF), then a block of data - * with the previously mentioned size. There can be any amount - * of chunks, and a chunk-data set to zero signals the - * end-of-chunks. */ - - char *start; - - /* Find the first non-space letter */ - start = k->p + 18; - - for(;;) { - /* skip whitespaces and commas */ - while(*start && (ISSPACE(*start) || (*start == ','))) - start++; - - if(checkprefix("chunked", start)) { - k->chunk = TRUE; /* chunks coming our way */ - - /* init our chunky engine */ - Curl_httpchunk_init(conn); - - start += 7; - } - - if(k->auto_decoding) - /* TODO: we only support the first mentioned compression for now */ - break; - - if(checkprefix("identity", start)) { - k->auto_decoding = IDENTITY; - start += 8; - } - else if(checkprefix("deflate", start)) { - k->auto_decoding = DEFLATE; - start += 7; - } - else if(checkprefix("gzip", start)) { - k->auto_decoding = GZIP; - start += 4; - } - else if(checkprefix("x-gzip", start)) { - k->auto_decoding = GZIP; - start += 6; - } - else - /* unknown! */ - break; - - } - - } - else if(checkprefix("Content-Encoding:", k->p) && - data->set.str[STRING_ENCODING]) { - /* - * Process Content-Encoding. Look for the values: identity, - * gzip, deflate, compress, x-gzip and x-compress. x-gzip and - * x-compress are the same as gzip and compress. (Sec 3.5 RFC - * 2616). zlib cannot handle compress. However, errors are - * handled further down when the response body is processed - */ - char *start; - - /* Find the first non-space letter */ - start = k->p + 17; - while(*start && ISSPACE(*start)) - start++; - - /* Record the content-encoding for later use */ - if(checkprefix("identity", start)) - k->auto_decoding = IDENTITY; - else if(checkprefix("deflate", start)) - k->auto_decoding = DEFLATE; - else if(checkprefix("gzip", start) - || checkprefix("x-gzip", start)) - k->auto_decoding = GZIP; - } - else if(checkprefix("Content-Range:", k->p)) { - /* Content-Range: bytes [num]- - Content-Range: bytes: [num]- - Content-Range: [num]- - Content-Range: [asterisk]/[total] - - The second format was added since Sun's webserver - JavaWebServer/1.1.1 obviously sends the header this way! - The third added since some servers use that! - The forth means the requested range was unsatisfied. - */ - - char *ptr = k->p + 14; - - /* Move forward until first digit or asterisk */ - while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') - ptr++; - - /* if it truly stopped on a digit */ - if(ISDIGIT(*ptr)) { - if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) { - if(data->state.resume_from == k->offset) - /* we asked for a resume and we got it */ - k->content_range = TRUE; - } - } - else - data->state.resume_from = 0; /* get everything */ - } -#if !defined(CURL_DISABLE_COOKIES) - else if(data->cookies && - checkprefix("Set-Cookie:", k->p)) { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, - CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_add(data, - data->cookies, TRUE, k->p + 11, - /* If there is a custom-set Host: name, use it - here, or else use real peer host name. */ - conn->allocptr.cookiehost? - conn->allocptr.cookiehost:conn->host.name, - data->state.path); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } -#endif - else if(checkprefix("Last-Modified:", k->p) && - (data->set.timecondition || data->set.get_filetime) ) { - time_t secs = time(NULL); - k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"), - &secs); - if(data->set.get_filetime) - data->info.filetime = (long)k->timeofdoc; - } - else if((checkprefix("WWW-Authenticate:", k->p) && - (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", k->p) && - (407 == k->httpcode))) { - - bool proxy = (k->httpcode == 407) ? TRUE : FALSE; - char *auth = Curl_copy_header_value(k->p); - if(!auth) - return CURLE_OUT_OF_MEMORY; - - result = Curl_http_input_auth(conn, proxy, auth); - - free(auth); - - if(result) - return result; - } - else if((k->httpcode >= 300 && k->httpcode < 400) && - checkprefix("Location:", k->p) && - !data->req.location) { - /* this is the URL that the server advises us to use instead */ - char *location = Curl_copy_header_value(k->p); - if(!location) - return CURLE_OUT_OF_MEMORY; - if(!*location) - /* ignore empty data */ - free(location); - else { - data->req.location = location; - - if(data->set.http_follow_location) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->req.location); /* clone */ - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - - /* some cases of POST and PUT etc needs to rewind the data - stream at this point */ - result = http_perhapsrewind(conn); - if(result) - return result; - } - } - } - else if(conn->handler->protocol & CURLPROTO_RTSP) { - result = Curl_rtsp_parseheader(conn, k->p); - if(result) - return result; - } - - /* - * End of header-checks. Write them to the client. - */ - - writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; - - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - k->p, (size_t)k->hbuflen, conn); - - result = Curl_client_write(conn, writetype, k->p, k->hbuflen); - if(result) - return result; - - data->info.header_size += (long)k->hbuflen; - data->req.headerbytecount += (long)k->hbuflen; - - /* reset hbufp pointer && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; - } - while(*k->str); /* header line within buffer */ - - /* We might have reached the end of the header part here, but - there might be a non-header part left in the end of the read - buffer. */ - - return CURLE_OK; -} - -#endif /* CURL_DISABLE_HTTP */ diff --git a/dep/cpr/opt/curl/lib/http.h b/dep/cpr/opt/curl/lib/http.h deleted file mode 100644 index d2781bc0f08..00000000000 --- a/dep/cpr/opt/curl/lib/http.h +++ /dev/null @@ -1,261 +0,0 @@ -#ifndef HEADER_CURL_HTTP_H -#define HEADER_CURL_HTTP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifndef CURL_DISABLE_HTTP - -#ifdef USE_NGHTTP2 -#include -#endif - -extern const struct Curl_handler Curl_handler_http; - -#ifdef USE_SSL -extern const struct Curl_handler Curl_handler_https; -#endif - -/* Header specific functions */ -bool Curl_compareheader(const char *headerline, /* line to check */ - const char *header, /* header keyword _with_ colon */ - const char *content); /* content string to find */ - -char *Curl_copy_header_value(const char *header); - -char *Curl_checkProxyheaders(const struct connectdata *conn, - const char *thisheader); -/* ------------------------------------------------------------------------- */ -/* - * The add_buffer series of functions are used to build one large memory chunk - * from repeated function invokes. Used so that the entire HTTP request can - * be sent in one go. - */ -struct Curl_send_buffer { - char *buffer; - size_t size_max; - size_t size_used; -}; -typedef struct Curl_send_buffer Curl_send_buffer; - -Curl_send_buffer *Curl_add_buffer_init(void); -void Curl_add_buffer_free(Curl_send_buffer *buff); -CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...); -CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size); -CURLcode Curl_add_buffer_send(Curl_send_buffer *in, - struct connectdata *conn, - long *bytes_written, - size_t included_body_bytes, - int socketindex); - -CURLcode Curl_add_timecondition(struct Curl_easy *data, - Curl_send_buffer *buf); -CURLcode Curl_add_custom_headers(struct connectdata *conn, - bool is_connect, - Curl_send_buffer *req_buffer); - -/* protocol-specific functions set up to be called by the main engine */ -CURLcode Curl_http(struct connectdata *conn, bool *done); -CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature); -CURLcode Curl_http_connect(struct connectdata *conn, bool *done); -CURLcode Curl_http_setup_conn(struct connectdata *conn); - -/* The following functions are defined in http_chunks.c */ -void Curl_httpchunk_init(struct connectdata *conn); -CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, - ssize_t length, ssize_t *wrote); - -/* These functions are in http.c */ -void Curl_http_auth_stage(struct Curl_easy *data, int stage); -CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, - const char *auth); -CURLcode Curl_http_auth_act(struct connectdata *conn); -CURLcode Curl_http_perhapsrewind(struct connectdata *conn); - -/* If only the PICKNONE bit is set, there has been a round-trip and we - selected to use no auth at all. Ie, we actively select no auth, as opposed - to not having one selected. The other CURLAUTH_* defines are present in the - public curl/curl.h header. */ -#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */ - -/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST - data get included in the initial data chunk sent to the server. If the - data is larger than this, it will automatically get split up in multiple - system calls. - - This value used to be fairly big (100K), but we must take into account that - if the server rejects the POST due for authentication reasons, this data - will always be uncondtionally sent and thus it may not be larger than can - always be afforded to send twice. - - It must not be greater than 64K to work on VMS. -*/ -#ifndef MAX_INITIAL_POST_SIZE -#define MAX_INITIAL_POST_SIZE (64*1024) -#endif - -/* EXPECT_100_THRESHOLD is the request body size limit for when libcurl will - * automatically add an "Expect: 100-continue" header in HTTP requests. When - * the size is unknown, it will always add it. - * - */ -#ifndef EXPECT_100_THRESHOLD -#define EXPECT_100_THRESHOLD 1024 -#endif - -#endif /* CURL_DISABLE_HTTP */ - -/**************************************************************************** - * HTTP unique setup - ***************************************************************************/ -struct HTTP { - curl_mimepart *sendit; - curl_off_t postsize; /* off_t to handle large file sizes */ - const char *postdata; - - const char *p_pragma; /* Pragma: string */ - const char *p_accept; /* Accept: string */ - curl_off_t readbytecount; - curl_off_t writebytecount; - - /* For FORM posting */ - curl_mimepart form; - - struct back { - curl_read_callback fread_func; /* backup storage for fread pointer */ - void *fread_in; /* backup storage for fread_in pointer */ - const char *postdata; - curl_off_t postsize; - } backup; - - enum { - HTTPSEND_NADA, /* init */ - HTTPSEND_REQUEST, /* sending a request */ - HTTPSEND_BODY, /* sending body */ - HTTPSEND_LAST /* never use this */ - } sending; - - void *send_buffer; /* used if the request couldn't be sent in one chunk, - points to an allocated send_buffer struct */ - -#ifdef USE_NGHTTP2 - /*********** for HTTP/2 we store stream-local data here *************/ - int32_t stream_id; /* stream we are interested in */ - - bool bodystarted; - /* We store non-final and final response headers here, per-stream */ - Curl_send_buffer *header_recvbuf; - size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into - upper layer */ - Curl_send_buffer *trailer_recvbuf; - int status_code; /* HTTP status code */ - const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ - size_t pauselen; /* the number of bytes left in data */ - bool closed; /* TRUE on HTTP2 stream close */ - bool close_handled; /* TRUE if stream closure is handled by libcurl */ - uint32_t error_code; /* HTTP/2 error code */ - - char *mem; /* points to a buffer in memory to store received data */ - size_t len; /* size of the buffer 'mem' points to */ - size_t memlen; /* size of data copied to mem */ - - const uint8_t *upload_mem; /* points to a buffer to read from */ - size_t upload_len; /* size of the buffer 'upload_mem' points to */ - curl_off_t upload_left; /* number of bytes left to upload */ - - char **push_headers; /* allocated array */ - size_t push_headers_used; /* number of entries filled in */ - size_t push_headers_alloc; /* number of entries allocated */ -#endif -}; - -typedef int (*sending)(void); /* Curl_send */ -typedef int (*recving)(void); /* Curl_recv */ - -#ifdef USE_NGHTTP2 -/* h2 settings for this connection */ -struct h2settings { - uint32_t max_concurrent_streams; - bool enable_push; -}; -#endif - - -struct http_conn { -#ifdef USE_NGHTTP2 -#define H2_BINSETTINGS_LEN 80 - nghttp2_session *h2; - uint8_t binsettings[H2_BINSETTINGS_LEN]; - size_t binlen; /* length of the binsettings data */ - sending send_underlying; /* underlying send Curl_send callback */ - recving recv_underlying; /* underlying recv Curl_recv callback */ - char *inbuf; /* buffer to receive data from underlying socket */ - size_t inbuflen; /* number of bytes filled in inbuf */ - size_t nread_inbuf; /* number of bytes read from in inbuf */ - /* We need separate buffer for transmission and reception because we - may call nghttp2_session_send() after the - nghttp2_session_mem_recv() but mem buffer is still not full. In - this case, we wrongly sends the content of mem buffer if we share - them for both cases. */ - int32_t pause_stream_id; /* stream ID which paused - nghttp2_session_mem_recv */ - size_t drain_total; /* sum of all stream's UrlState.drain */ - - /* this is a hash of all individual streams (Curl_easy structs) */ - struct h2settings settings; - - /* list of settings that will be sent */ - nghttp2_settings_entry local_settings[3]; - size_t local_settings_num; -#else - int unused; /* prevent a compiler warning */ -#endif -}; - -CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, - struct connectdata *conn, - ssize_t *nread, - bool *stop_reading); - -/** - * Curl_http_output_auth() setups the authentication headers for the - * host/proxy and the correct authentication - * method. conn->data->state.authdone is set to TRUE when authentication is - * done. - * - * @param conn all information about the current connection - * @param request pointer to the request keyword - * @param path pointer to the requested path - * @param proxytunnel boolean if this is the request setting up a "proxy - * tunnel" - * - * @returns CURLcode - */ -CURLcode -Curl_http_output_auth(struct connectdata *conn, - const char *request, - const char *path, - bool proxytunnel); /* TRUE if this is the request setting - up the proxy tunnel */ - -#endif /* HEADER_CURL_HTTP_H */ - diff --git a/dep/cpr/opt/curl/lib/http2.c b/dep/cpr/opt/curl/lib/http2.c deleted file mode 100644 index 9a2a1dd555a..00000000000 --- a/dep/cpr/opt/curl/lib/http2.c +++ /dev/null @@ -1,2287 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_NGHTTP2 -#include -#include "urldata.h" -#include "http2.h" -#include "http.h" -#include "sendf.h" -#include "select.h" -#include "curl_base64.h" -#include "strcase.h" -#include "multiif.h" -#include "conncache.h" -#include "url.h" -#include "connect.h" -#include "strtoofft.h" -#include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#define MIN(x,y) ((x)<(y)?(x):(y)) - -#if (NGHTTP2_VERSION_NUM < 0x010000) -#error too old nghttp2 version, upgrade! -#endif - -#if (NGHTTP2_VERSION_NUM > 0x010800) -#define NGHTTP2_HAS_HTTP2_STRERROR 1 -#endif - -#if (NGHTTP2_VERSION_NUM >= 0x010900) -/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or - later */ -#define NGHTTP2_HAS_ERROR_CALLBACK 1 -#else -#define nghttp2_session_callbacks_set_error_callback(x,y) -#endif - -#if (NGHTTP2_VERSION_NUM >= 0x010c00) -#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1 -#endif - -#define HTTP2_HUGE_WINDOW_SIZE (1 << 30) - -/* - * Curl_http2_init_state() is called when the easy handle is created and - * allows for HTTP/2 specific init of state. - */ -void Curl_http2_init_state(struct UrlState *state) -{ - state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; -} - -/* - * Curl_http2_init_userset() is called when the easy handle is created and - * allows for HTTP/2 specific user-set fields. - */ -void Curl_http2_init_userset(struct UserDefined *set) -{ - set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; -} - -static int http2_perform_getsock(const struct connectdata *conn, - curl_socket_t *sock, /* points to - numsocks - number of - sockets */ - int numsocks) -{ - const struct http_conn *c = &conn->proto.httpc; - int bitmap = GETSOCK_BLANK; - (void)numsocks; - - /* TODO We should check underlying socket state if it is SSL socket - because of renegotiation. */ - sock[0] = conn->sock[FIRSTSOCKET]; - - /* in a HTTP/2 connection we can basically always get a frame so we should - always be ready for one */ - bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); - - if(nghttp2_session_want_write(c->h2)) - bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); - - return bitmap; -} - -static int http2_getsock(struct connectdata *conn, - curl_socket_t *sock, /* points to numsocks - number of sockets */ - int numsocks) -{ - return http2_perform_getsock(conn, sock, numsocks); -} - -/* - * http2_stream_free() free HTTP2 stream related data - */ -static void http2_stream_free(struct HTTP *http) -{ - if(http) { - Curl_add_buffer_free(http->header_recvbuf); - http->header_recvbuf = NULL; /* clear the pointer */ - Curl_add_buffer_free(http->trailer_recvbuf); - http->trailer_recvbuf = NULL; /* clear the pointer */ - for(; http->push_headers_used > 0; --http->push_headers_used) { - free(http->push_headers[http->push_headers_used - 1]); - } - free(http->push_headers); - http->push_headers = NULL; - } -} - -static CURLcode http2_disconnect(struct connectdata *conn, - bool dead_connection) -{ - struct http_conn *c = &conn->proto.httpc; - (void)dead_connection; - - DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); - - nghttp2_session_del(c->h2); - Curl_safefree(c->inbuf); - http2_stream_free(conn->data->req.protop); - - DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n")); - - return CURLE_OK; -} - -/* - * The server may send us data at any point (e.g. PING frames). Therefore, - * we cannot assume that an HTTP/2 socket is dead just because it is readable. - * - * Instead, if it is readable, run Curl_connalive() to peek at the socket - * and distinguish between closed and data. - */ -static bool http2_connisdead(struct connectdata *check) -{ - int sval; - bool ret_val = TRUE; - - sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0); - if(sval == 0) { - /* timeout */ - ret_val = FALSE; - } - else if(sval & CURL_CSELECT_ERR) { - /* socket is in an error state */ - ret_val = TRUE; - } - else if(sval & CURL_CSELECT_IN) { - /* readable with no error. could still be closed */ - ret_val = !Curl_connalive(check); - } - - return ret_val; -} - - -static unsigned int http2_conncheck(struct connectdata *check, - unsigned int checks_to_perform) -{ - unsigned int ret_val = CONNRESULT_NONE; - - if(checks_to_perform & CONNCHECK_ISDEAD) { - if(http2_connisdead(check)) - ret_val |= CONNRESULT_DEAD; - } - - return ret_val; -} - -/* called from Curl_http_setup_conn */ -void Curl_http2_setup_req(struct Curl_easy *data) -{ - struct HTTP *http = data->req.protop; - - http->nread_header_recvbuf = 0; - http->bodystarted = FALSE; - http->status_code = -1; - http->pausedata = NULL; - http->pauselen = 0; - http->error_code = NGHTTP2_NO_ERROR; - http->closed = FALSE; - http->close_handled = FALSE; - http->mem = data->state.buffer; - http->len = data->set.buffer_size; - http->memlen = 0; -} - -/* called from Curl_http_setup_conn */ -void Curl_http2_setup_conn(struct connectdata *conn) -{ - conn->proto.httpc.settings.max_concurrent_streams = - DEFAULT_MAX_CONCURRENT_STREAMS; -} - -/* - * HTTP2 handler interface. This isn't added to the general list of protocols - * but will be used at run-time when the protocol is dynamically switched from - * HTTP to HTTP2. - */ -static const struct Curl_handler Curl_handler_http2 = { - "HTTP", /* scheme */ - ZERO_NULL, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - http2_getsock, /* proto_getsock */ - http2_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - http2_perform_getsock, /* perform_getsock */ - http2_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - http2_conncheck, /* connection_check */ - PORT_HTTP, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_STREAM /* flags */ -}; - -static const struct Curl_handler Curl_handler_http2_ssl = { - "HTTPS", /* scheme */ - ZERO_NULL, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - http2_getsock, /* proto_getsock */ - http2_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - http2_perform_getsock, /* perform_getsock */ - http2_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - http2_conncheck, /* connection_check */ - PORT_HTTP, /* defport */ - CURLPROTO_HTTPS, /* protocol */ - PROTOPT_SSL | PROTOPT_STREAM /* flags */ -}; - -/* - * Store nghttp2 version info in this buffer, Prefix with a space. Return - * total length written. - */ -int Curl_http2_ver(char *p, size_t len) -{ - nghttp2_info *h2 = nghttp2_version(0); - return snprintf(p, len, " nghttp2/%s", h2->version_str); -} - -/* HTTP/2 error code to name based on the Error Code Registry. -https://tools.ietf.org/html/rfc7540#page-77 -nghttp2_error_code enums are identical. -*/ -const char *Curl_http2_strerror(uint32_t err) -{ -#ifndef NGHTTP2_HAS_HTTP2_STRERROR - const char *str[] = { - "NO_ERROR", /* 0x0 */ - "PROTOCOL_ERROR", /* 0x1 */ - "INTERNAL_ERROR", /* 0x2 */ - "FLOW_CONTROL_ERROR", /* 0x3 */ - "SETTINGS_TIMEOUT", /* 0x4 */ - "STREAM_CLOSED", /* 0x5 */ - "FRAME_SIZE_ERROR", /* 0x6 */ - "REFUSED_STREAM", /* 0x7 */ - "CANCEL", /* 0x8 */ - "COMPRESSION_ERROR", /* 0x9 */ - "CONNECT_ERROR", /* 0xA */ - "ENHANCE_YOUR_CALM", /* 0xB */ - "INADEQUATE_SECURITY", /* 0xC */ - "HTTP_1_1_REQUIRED" /* 0xD */ - }; - return (err < sizeof str / sizeof str[0]) ? str[err] : "unknown"; -#else - return nghttp2_http2_strerror(err); -#endif -} - -/* - * The implementation of nghttp2_send_callback type. Here we write |data| with - * size |length| to the network and return the number of bytes actually - * written. See the documentation of nghttp2_send_callback for the details. - */ -static ssize_t send_callback(nghttp2_session *h2, - const uint8_t *data, size_t length, int flags, - void *userp) -{ - struct connectdata *conn = (struct connectdata *)userp; - struct http_conn *c = &conn->proto.httpc; - ssize_t written; - CURLcode result = CURLE_OK; - - (void)h2; - (void)flags; - - written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET, - data, length, &result); - - if(result == CURLE_AGAIN) { - return NGHTTP2_ERR_WOULDBLOCK; - } - - if(written == -1) { - failf(conn->data, "Failed sending HTTP2 data"); - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - if(!written) - return NGHTTP2_ERR_WOULDBLOCK; - - return written; -} - - -/* We pass a pointer to this struct in the push callback, but the contents of - the struct are hidden from the user. */ -struct curl_pushheaders { - struct Curl_easy *data; - const nghttp2_push_promise *frame; -}; - -/* - * push header access function. Only to be used from within the push callback - */ -char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) -{ - /* Verify that we got a good easy handle in the push header struct, mostly to - detect rubbish input fast(er). */ - if(!h || !GOOD_EASY_HANDLE(h->data)) - return NULL; - else { - struct HTTP *stream = h->data->req.protop; - if(num < stream->push_headers_used) - return stream->push_headers[num]; - } - return NULL; -} - -/* - * push header access function. Only to be used from within the push callback - */ -char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) -{ - /* Verify that we got a good easy handle in the push header struct, - mostly to detect rubbish input fast(er). Also empty header name - is just a rubbish too. We have to allow ":" at the beginning of - the header, but header == ":" must be rejected. If we have ':' in - the middle of header, it could be matched in middle of the value, - this is because we do prefix match.*/ - if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || - !strcmp(header, ":") || strchr(header + 1, ':')) - return NULL; - else { - struct HTTP *stream = h->data->req.protop; - size_t len = strlen(header); - size_t i; - for(i = 0; ipush_headers_used; i++) { - if(!strncmp(header, stream->push_headers[i], len)) { - /* sub-match, make sure that it is followed by a colon */ - if(stream->push_headers[i][len] != ':') - continue; - return &stream->push_headers[i][len + 1]; - } - } - } - return NULL; -} - -static struct Curl_easy *duphandle(struct Curl_easy *data) -{ - struct Curl_easy *second = curl_easy_duphandle(data); - if(second) { - /* setup the request struct */ - struct HTTP *http = calloc(1, sizeof(struct HTTP)); - if(!http) { - (void)Curl_close(second); - second = NULL; - } - else { - second->req.protop = http; - http->header_recvbuf = Curl_add_buffer_init(); - if(!http->header_recvbuf) { - free(http); - (void)Curl_close(second); - second = NULL; - } - else { - Curl_http2_setup_req(second); - second->state.stream_weight = data->state.stream_weight; - } - } - } - return second; -} - - -static int push_promise(struct Curl_easy *data, - struct connectdata *conn, - const nghttp2_push_promise *frame) -{ - int rv; - DEBUGF(infof(data, "PUSH_PROMISE received, stream %u!\n", - frame->promised_stream_id)); - if(data->multi->push_cb) { - struct HTTP *stream; - struct HTTP *newstream; - struct curl_pushheaders heads; - CURLMcode rc; - struct http_conn *httpc; - size_t i; - /* clone the parent */ - struct Curl_easy *newhandle = duphandle(data); - if(!newhandle) { - infof(data, "failed to duplicate handle\n"); - rv = 1; /* FAIL HARD */ - goto fail; - } - - heads.data = data; - heads.frame = frame; - /* ask the application */ - DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n")); - - stream = data->req.protop; - if(!stream) { - failf(data, "Internal NULL stream!\n"); - (void)Curl_close(newhandle); - rv = 1; - goto fail; - } - - rv = data->multi->push_cb(data, newhandle, - stream->push_headers_used, &heads, - data->multi->push_userp); - - /* free the headers again */ - for(i = 0; ipush_headers_used; i++) - free(stream->push_headers[i]); - free(stream->push_headers); - stream->push_headers = NULL; - stream->push_headers_used = 0; - - if(rv) { - /* denied, kill off the new handle again */ - http2_stream_free(newhandle->req.protop); - (void)Curl_close(newhandle); - goto fail; - } - - newstream = newhandle->req.protop; - newstream->stream_id = frame->promised_stream_id; - newhandle->req.maxdownload = -1; - newhandle->req.size = -1; - - /* approved, add to the multi handle and immediately switch to PERFORM - state with the given connection !*/ - rc = Curl_multi_add_perform(data->multi, newhandle, conn); - if(rc) { - infof(data, "failed to add handle to multi\n"); - http2_stream_free(newhandle->req.protop); - Curl_close(newhandle); - rv = 1; - goto fail; - } - - httpc = &conn->proto.httpc; - nghttp2_session_set_stream_user_data(httpc->h2, - frame->promised_stream_id, newhandle); - } - else { - DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n")); - rv = 1; - } - fail: - return rv; -} - -static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, - void *userp) -{ - struct connectdata *conn = (struct connectdata *)userp; - struct http_conn *httpc = &conn->proto.httpc; - struct Curl_easy *data_s = NULL; - struct HTTP *stream = NULL; - static int lastStream = -1; - int rv; - size_t left, ncopy; - int32_t stream_id = frame->hd.stream_id; - - if(!stream_id) { - /* stream ID zero is for connection-oriented stuff */ - if(frame->hd.type == NGHTTP2_SETTINGS) { - uint32_t max_conn = httpc->settings.max_concurrent_streams; - DEBUGF(infof(conn->data, "Got SETTINGS\n")); - httpc->settings.max_concurrent_streams = - nghttp2_session_get_remote_settings( - session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); - httpc->settings.enable_push = - nghttp2_session_get_remote_settings( - session, NGHTTP2_SETTINGS_ENABLE_PUSH); - DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n", - httpc->settings.max_concurrent_streams)); - DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n", - httpc->settings.enable_push?"TRUE":"false")); - if(max_conn != httpc->settings.max_concurrent_streams) { - /* only signal change if the value actually changed */ - infof(conn->data, - "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n"); - Curl_multi_connchanged(conn->data->multi); - } - } - return 0; - } - data_s = nghttp2_session_get_stream_user_data(session, stream_id); - if(lastStream != stream_id) { - lastStream = stream_id; - } - if(!data_s) { - DEBUGF(infof(conn->data, - "No Curl_easy associated with stream: %x\n", - stream_id)); - return 0; - } - - stream = data_s->req.protop; - if(!stream) { - DEBUGF(infof(conn->data, "No proto pointer for stream: %x\n", - stream_id)); - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", - frame->hd.type, stream_id)); - - switch(frame->hd.type) { - case NGHTTP2_DATA: - /* If body started on this stream, then receiving DATA is illegal. */ - if(!stream->bodystarted) { - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - stream_id, NGHTTP2_PROTOCOL_ERROR); - - if(nghttp2_is_fatal(rv)) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - break; - case NGHTTP2_HEADERS: - if(stream->bodystarted) { - /* Only valid HEADERS after body started is trailer HEADERS. We - buffer them in on_header callback. */ - break; - } - - /* nghttp2 guarantees that :status is received, and we store it to - stream->status_code */ - DEBUGASSERT(stream->status_code != -1); - - /* Only final status code signals the end of header */ - if(stream->status_code / 100 != 1) { - stream->bodystarted = TRUE; - stream->status_code = -1; - } - - Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); - - left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf; - ncopy = MIN(stream->len, left); - - memcpy(&stream->mem[stream->memlen], - stream->header_recvbuf->buffer + stream->nread_header_recvbuf, - ncopy); - stream->nread_header_recvbuf += ncopy; - - DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n", - ncopy, stream_id, stream->mem)); - - stream->len -= ncopy; - stream->memlen += ncopy; - - data_s->state.drain++; - httpc->drain_total++; - { - /* get the pointer from userp again since it was re-assigned above */ - struct connectdata *conn_s = (struct connectdata *)userp; - - /* if we receive data for another handle, wake that up */ - if(conn_s->data != data_s) - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); - } - break; - case NGHTTP2_PUSH_PROMISE: - rv = push_promise(data_s, conn, &frame->push_promise); - if(rv) { /* deny! */ - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - frame->push_promise.promised_stream_id, - NGHTTP2_CANCEL); - if(nghttp2_is_fatal(rv)) { - return rv; - } - } - break; - default: - DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n", - frame->hd.type, stream_id)); - break; - } - return 0; -} - -static int on_invalid_frame_recv(nghttp2_session *session, - const nghttp2_frame *frame, - int lib_error_code, void *userp) -{ - struct Curl_easy *data_s = NULL; - (void)userp; -#if !defined(DEBUGBUILD) || defined(CURL_DISABLE_VERBOSE_STRINGS) - (void)lib_error_code; -#endif - - data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); - if(data_s) { - DEBUGF(infof(data_s, - "on_invalid_frame_recv() was called, error=%d:%s\n", - lib_error_code, nghttp2_strerror(lib_error_code))); - } - return 0; -} - -static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const uint8_t *data, size_t len, void *userp) -{ - struct HTTP *stream; - struct Curl_easy *data_s; - size_t nread; - struct connectdata *conn = (struct connectdata *)userp; - (void)session; - (void)flags; - (void)data; - - DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ - - /* get the stream from the hash based on Stream ID */ - data_s = nghttp2_session_get_stream_user_data(session, stream_id); - if(!data_s) - /* Receiving a Stream ID not in the hash should not happen, this is an - internal error more than anything else! */ - return NGHTTP2_ERR_CALLBACK_FAILURE; - - stream = data_s->req.protop; - if(!stream) - return NGHTTP2_ERR_CALLBACK_FAILURE; - - nread = MIN(stream->len, len); - memcpy(&stream->mem[stream->memlen], data, nread); - - stream->len -= nread; - stream->memlen += nread; - - data_s->state.drain++; - conn->proto.httpc.drain_total++; - - /* if we receive data for another handle, wake that up */ - if(conn->data != data_s) - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); - - DEBUGF(infof(data_s, "%zu data received for stream %u " - "(%zu left in buffer %p, total %zu)\n", - nread, stream_id, - stream->len, stream->mem, - stream->memlen)); - - if(nread < len) { - stream->pausedata = data + nread; - stream->pauselen = len - nread; - DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer" - ", stream %u\n", - len - nread, stream_id)); - data_s->easy_conn->proto.httpc.pause_stream_id = stream_id; - - return NGHTTP2_ERR_PAUSE; - } - - /* pause execution of nghttp2 if we received data for another handle - in order to process them first. */ - if(conn->data != data_s) { - data_s->easy_conn->proto.httpc.pause_stream_id = stream_id; - - return NGHTTP2_ERR_PAUSE; - } - - return 0; -} - -static int before_frame_send(nghttp2_session *session, - const nghttp2_frame *frame, - void *userp) -{ - struct Curl_easy *data_s; - (void)userp; - - data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); - if(data_s) { - DEBUGF(infof(data_s, "before_frame_send() was called\n")); - } - - return 0; -} -static int on_frame_send(nghttp2_session *session, - const nghttp2_frame *frame, - void *userp) -{ - struct Curl_easy *data_s; - (void)userp; - - data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); - if(data_s) { - DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n", - frame->hd.length)); - } - return 0; -} -static int on_frame_not_send(nghttp2_session *session, - const nghttp2_frame *frame, - int lib_error_code, void *userp) -{ - struct Curl_easy *data_s; - (void)userp; -#if !defined(DEBUGBUILD) || defined(CURL_DISABLE_VERBOSE_STRINGS) - (void)lib_error_code; -#endif - - data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); - if(data_s) { - DEBUGF(infof(data_s, - "on_frame_not_send() was called, lib_error_code = %d\n", - lib_error_code)); - } - return 0; -} -static int on_stream_close(nghttp2_session *session, int32_t stream_id, - uint32_t error_code, void *userp) -{ - struct Curl_easy *data_s; - struct HTTP *stream; - struct connectdata *conn = (struct connectdata *)userp; - (void)session; - (void)stream_id; - - if(stream_id) { - /* get the stream from the hash based on Stream ID, stream ID zero is for - connection-oriented stuff */ - data_s = nghttp2_session_get_stream_user_data(session, stream_id); - if(!data_s) { - /* We could get stream ID not in the hash. For example, if we - decided to reject stream (e.g., PUSH_PROMISE). */ - return 0; - } - DEBUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n", - Curl_http2_strerror(error_code), error_code, stream_id)); - stream = data_s->req.protop; - if(!stream) - return NGHTTP2_ERR_CALLBACK_FAILURE; - - stream->error_code = error_code; - stream->closed = TRUE; - data_s->state.drain++; - conn->proto.httpc.drain_total++; - - /* remove the entry from the hash as the stream is now gone */ - nghttp2_session_set_stream_user_data(session, stream_id, 0); - DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id)); - } - return 0; -} - -static int on_begin_headers(nghttp2_session *session, - const nghttp2_frame *frame, void *userp) -{ - struct HTTP *stream; - struct Curl_easy *data_s = NULL; - (void)userp; - - data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); - if(!data_s) { - return 0; - } - - DEBUGF(infof(data_s, "on_begin_headers() was called\n")); - - if(frame->hd.type != NGHTTP2_HEADERS) { - return 0; - } - - stream = data_s->req.protop; - if(!stream || !stream->bodystarted) { - return 0; - } - - /* This is trailer HEADERS started. Allocate buffer for them. */ - DEBUGF(infof(data_s, "trailer field started\n")); - - DEBUGASSERT(stream->trailer_recvbuf == NULL); - - stream->trailer_recvbuf = Curl_add_buffer_init(); - if(!stream->trailer_recvbuf) { - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - - return 0; -} - -/* Decode HTTP status code. Returns -1 if no valid status code was - decoded. */ -static int decode_status_code(const uint8_t *value, size_t len) -{ - int i; - int res; - - if(len != 3) { - return -1; - } - - res = 0; - - for(i = 0; i < 3; ++i) { - char c = value[i]; - - if(c < '0' || c > '9') { - return -1; - } - - res *= 10; - res += c - '0'; - } - - return res; -} - -/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */ -static int on_header(nghttp2_session *session, const nghttp2_frame *frame, - const uint8_t *name, size_t namelen, - const uint8_t *value, size_t valuelen, - uint8_t flags, - void *userp) -{ - struct HTTP *stream; - struct Curl_easy *data_s; - int32_t stream_id = frame->hd.stream_id; - struct connectdata *conn = (struct connectdata *)userp; - (void)flags; - - DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ - - /* get the stream from the hash based on Stream ID */ - data_s = nghttp2_session_get_stream_user_data(session, stream_id); - if(!data_s) - /* Receiving a Stream ID not in the hash should not happen, this is an - internal error more than anything else! */ - return NGHTTP2_ERR_CALLBACK_FAILURE; - - stream = data_s->req.protop; - if(!stream) { - failf(data_s, "Internal NULL stream! 5\n"); - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - /* Store received PUSH_PROMISE headers to be used when the subsequent - PUSH_PROMISE callback comes */ - if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { - char *h; - - if(!stream->push_headers) { - stream->push_headers_alloc = 10; - stream->push_headers = malloc(stream->push_headers_alloc * - sizeof(char *)); - stream->push_headers_used = 0; - } - else if(stream->push_headers_used == - stream->push_headers_alloc) { - char **headp; - stream->push_headers_alloc *= 2; - headp = Curl_saferealloc(stream->push_headers, - stream->push_headers_alloc * sizeof(char *)); - if(!headp) { - stream->push_headers = NULL; - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - stream->push_headers = headp; - } - h = aprintf("%s:%s", name, value); - if(h) - stream->push_headers[stream->push_headers_used++] = h; - return 0; - } - - if(stream->bodystarted) { - /* This is trailer fields. */ - /* 3 is for ":" and "\r\n". */ - uint32_t n = (uint32_t)(namelen + valuelen + 3); - - DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen, - value)); - - Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n)); - Curl_add_buffer(stream->trailer_recvbuf, name, namelen); - Curl_add_buffer(stream->trailer_recvbuf, ": ", 2); - Curl_add_buffer(stream->trailer_recvbuf, value, valuelen); - Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3); - - return 0; - } - - if(namelen == sizeof(":status") - 1 && - memcmp(":status", name, namelen) == 0) { - /* nghttp2 guarantees :status is received first and only once, and - value is 3 digits status code, and decode_status_code always - succeeds. */ - stream->status_code = decode_status_code(value, valuelen); - DEBUGASSERT(stream->status_code != -1); - - Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7); - Curl_add_buffer(stream->header_recvbuf, value, valuelen); - /* the space character after the status code is mandatory */ - Curl_add_buffer(stream->header_recvbuf, " \r\n", 3); - /* if we receive data for another handle, wake that up */ - if(conn->data != data_s) - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); - - DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n", - stream->status_code, data_s)); - return 0; - } - - /* nghttp2 guarantees that namelen > 0, and :status was already - received, and this is not pseudo-header field . */ - /* convert to a HTTP1-style header */ - Curl_add_buffer(stream->header_recvbuf, name, namelen); - Curl_add_buffer(stream->header_recvbuf, ": ", 2); - Curl_add_buffer(stream->header_recvbuf, value, valuelen); - Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); - /* if we receive data for another handle, wake that up */ - if(conn->data != data_s) - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); - - DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, - value)); - - return 0; /* 0 is successful */ -} - -static ssize_t data_source_read_callback(nghttp2_session *session, - int32_t stream_id, - uint8_t *buf, size_t length, - uint32_t *data_flags, - nghttp2_data_source *source, - void *userp) -{ - struct Curl_easy *data_s; - struct HTTP *stream = NULL; - size_t nread; - (void)source; - (void)userp; - - if(stream_id) { - /* get the stream from the hash based on Stream ID, stream ID zero is for - connection-oriented stuff */ - data_s = nghttp2_session_get_stream_user_data(session, stream_id); - if(!data_s) - /* Receiving a Stream ID not in the hash should not happen, this is an - internal error more than anything else! */ - return NGHTTP2_ERR_CALLBACK_FAILURE; - - stream = data_s->req.protop; - if(!stream) - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - else - return NGHTTP2_ERR_INVALID_ARGUMENT; - - nread = MIN(stream->upload_len, length); - if(nread > 0) { - memcpy(buf, stream->upload_mem, nread); - stream->upload_mem += nread; - stream->upload_len -= nread; - if(data_s->state.infilesize != -1) - stream->upload_left -= nread; - } - - if(stream->upload_left == 0) - *data_flags = NGHTTP2_DATA_FLAG_EOF; - else if(nread == 0) - return NGHTTP2_ERR_DEFERRED; - - DEBUGF(infof(data_s, "data_source_read_callback: " - "returns %zu bytes stream %u\n", - nread, stream_id)); - - return nread; -} - -#define H2_BUFSIZE 32768 - -#ifdef NGHTTP2_HAS_ERROR_CALLBACK -static int error_callback(nghttp2_session *session, - const char *msg, - size_t len, - void *userp) -{ - struct connectdata *conn = (struct connectdata *)userp; - (void)session; - infof(conn->data, "http2 error: %.*s\n", len, msg); - return 0; -} -#endif - -static void populate_settings(struct connectdata *conn, - struct http_conn *httpc) -{ - nghttp2_settings_entry *iv = httpc->local_settings; - - iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; - iv[0].value = 100; - - iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; - iv[1].value = HTTP2_HUGE_WINDOW_SIZE; - - iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; - iv[2].value = conn->data->multi->push_cb != NULL; - - httpc->local_settings_num = 3; -} - -void Curl_http2_done(struct connectdata *conn, bool premature) -{ - struct Curl_easy *data = conn->data; - struct HTTP *http = data->req.protop; - struct http_conn *httpc = &conn->proto.httpc; - - if(http->header_recvbuf) { - DEBUGF(infof(data, "free header_recvbuf!!\n")); - Curl_add_buffer_free(http->header_recvbuf); - http->header_recvbuf = NULL; /* clear the pointer */ - Curl_add_buffer_free(http->trailer_recvbuf); - http->trailer_recvbuf = NULL; /* clear the pointer */ - if(http->push_headers) { - /* if they weren't used and then freed before */ - for(; http->push_headers_used > 0; --http->push_headers_used) { - free(http->push_headers[http->push_headers_used - 1]); - } - free(http->push_headers); - http->push_headers = NULL; - } - } - - if(premature) { - /* RST_STREAM */ - nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id, - NGHTTP2_STREAM_CLOSED); - if(http->stream_id == httpc->pause_stream_id) { - infof(data, "stopped the pause stream!\n"); - httpc->pause_stream_id = 0; - } - } - if(http->stream_id) { - nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); - http->stream_id = 0; - } -} - -/* - * Initialize nghttp2 for a Curl connection - */ -CURLcode Curl_http2_init(struct connectdata *conn) -{ - if(!conn->proto.httpc.h2) { - int rc; - nghttp2_session_callbacks *callbacks; - - conn->proto.httpc.inbuf = malloc(H2_BUFSIZE); - if(conn->proto.httpc.inbuf == NULL) - return CURLE_OUT_OF_MEMORY; - - rc = nghttp2_session_callbacks_new(&callbacks); - - if(rc) { - failf(conn->data, "Couldn't initialize nghttp2 callbacks!"); - return CURLE_OUT_OF_MEMORY; /* most likely at least */ - } - - /* nghttp2_send_callback */ - nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); - /* nghttp2_on_frame_recv_callback */ - nghttp2_session_callbacks_set_on_frame_recv_callback - (callbacks, on_frame_recv); - /* nghttp2_on_invalid_frame_recv_callback */ - nghttp2_session_callbacks_set_on_invalid_frame_recv_callback - (callbacks, on_invalid_frame_recv); - /* nghttp2_on_data_chunk_recv_callback */ - nghttp2_session_callbacks_set_on_data_chunk_recv_callback - (callbacks, on_data_chunk_recv); - /* nghttp2_before_frame_send_callback */ - nghttp2_session_callbacks_set_before_frame_send_callback - (callbacks, before_frame_send); - /* nghttp2_on_frame_send_callback */ - nghttp2_session_callbacks_set_on_frame_send_callback - (callbacks, on_frame_send); - /* nghttp2_on_frame_not_send_callback */ - nghttp2_session_callbacks_set_on_frame_not_send_callback - (callbacks, on_frame_not_send); - /* nghttp2_on_stream_close_callback */ - nghttp2_session_callbacks_set_on_stream_close_callback - (callbacks, on_stream_close); - /* nghttp2_on_begin_headers_callback */ - nghttp2_session_callbacks_set_on_begin_headers_callback - (callbacks, on_begin_headers); - /* nghttp2_on_header_callback */ - nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header); - - nghttp2_session_callbacks_set_error_callback(callbacks, error_callback); - - /* The nghttp2 session is not yet setup, do it */ - rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); - - nghttp2_session_callbacks_del(callbacks); - - if(rc) { - failf(conn->data, "Couldn't initialize nghttp2!"); - return CURLE_OUT_OF_MEMORY; /* most likely at least */ - } - } - return CURLE_OK; -} - -/* - * Append headers to ask for a HTTP1.1 to HTTP2 upgrade. - */ -CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, - struct connectdata *conn) -{ - CURLcode result; - ssize_t binlen; - char *base64; - size_t blen; - struct SingleRequest *k = &conn->data->req; - uint8_t *binsettings = conn->proto.httpc.binsettings; - struct http_conn *httpc = &conn->proto.httpc; - - populate_settings(conn, httpc); - - /* this returns number of bytes it wrote */ - binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, - httpc->local_settings, - httpc->local_settings_num); - if(!binlen) { - failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); - return CURLE_FAILED_INIT; - } - conn->proto.httpc.binlen = binlen; - - result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen, - &base64, &blen); - if(result) - return result; - - result = Curl_add_bufferf(req, - "Connection: Upgrade, HTTP2-Settings\r\n" - "Upgrade: %s\r\n" - "HTTP2-Settings: %s\r\n", - NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); - free(base64); - - k->upgr101 = UPGR101_REQUESTED; - - return result; -} - -/* - * Returns nonzero if current HTTP/2 session should be closed. - */ -static int should_close_session(struct http_conn *httpc) -{ - return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) && - !nghttp2_session_want_write(httpc->h2); -} - -static int h2_session_send(struct Curl_easy *data, - nghttp2_session *h2); - -/* - * h2_process_pending_input() processes pending input left in - * httpc->inbuf. Then, call h2_session_send() to send pending data. - * This function returns 0 if it succeeds, or -1 and error code will - * be assigned to *err. - */ -static int h2_process_pending_input(struct Curl_easy *data, - struct http_conn *httpc, - CURLcode *err) -{ - ssize_t nread; - char *inbuf; - ssize_t rv; - - nread = httpc->inbuflen - httpc->nread_inbuf; - inbuf = httpc->inbuf + httpc->nread_inbuf; - - rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); - if(rv < 0) { - failf(data, - "h2_process_pending_input: nghttp2_session_mem_recv() returned " - "%d:%s\n", rv, nghttp2_strerror((int)rv)); - *err = CURLE_RECV_ERROR; - return -1; - } - - if(nread == rv) { - DEBUGF(infof(data, - "h2_process_pending_input: All data in connection buffer " - "processed\n")); - httpc->inbuflen = 0; - httpc->nread_inbuf = 0; - } - else { - httpc->nread_inbuf += rv; - DEBUGF(infof(data, - "h2_process_pending_input: %zu bytes left in connection " - "buffer\n", - httpc->inbuflen - httpc->nread_inbuf)); - } - - rv = h2_session_send(data, httpc->h2); - if(rv != 0) { - *err = CURLE_SEND_ERROR; - return -1; - } - - if(should_close_session(httpc)) { - DEBUGF(infof(data, - "h2_process_pending_input: nothing to do in this session\n")); - *err = CURLE_HTTP2; - return -1; - } - - return 0; -} - -/* - * Called from transfer.c:done_sending when we stop uploading. - */ -CURLcode Curl_http2_done_sending(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - if((conn->handler == &Curl_handler_http2_ssl) || - (conn->handler == &Curl_handler_http2)) { - /* make sure this is only attempted for HTTP/2 transfers */ - - struct HTTP *stream = conn->data->req.protop; - - if(stream->upload_left) { - /* If the stream still thinks there's data left to upload. */ - struct http_conn *httpc = &conn->proto.httpc; - nghttp2_session *h2 = httpc->h2; - - stream->upload_left = 0; /* DONE! */ - - /* resume sending here to trigger the callback to get called again so - that it can signal EOF to nghttp2 */ - (void)nghttp2_session_resume_data(h2, stream->stream_id); - - (void)h2_process_pending_input(conn->data, httpc, &result); - } - } - return result; -} - - -static ssize_t http2_handle_stream_close(struct connectdata *conn, - struct Curl_easy *data, - struct HTTP *stream, CURLcode *err) -{ - char *trailer_pos, *trailer_end; - CURLcode result; - struct http_conn *httpc = &conn->proto.httpc; - - if(httpc->pause_stream_id == stream->stream_id) { - httpc->pause_stream_id = 0; - } - - DEBUGASSERT(httpc->drain_total >= data->state.drain); - httpc->drain_total -= data->state.drain; - data->state.drain = 0; - - if(httpc->pause_stream_id == 0) { - if(h2_process_pending_input(data, httpc, err) != 0) { - return -1; - } - } - - DEBUGASSERT(data->state.drain == 0); - - /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ - stream->closed = FALSE; - if(stream->error_code != NGHTTP2_NO_ERROR) { - failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)", - stream->stream_id, Curl_http2_strerror(stream->error_code), - stream->error_code); - *err = CURLE_HTTP2_STREAM; - return -1; - } - - if(!stream->bodystarted) { - failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " - " all response header fields, teated as error", - stream->stream_id); - *err = CURLE_HTTP2_STREAM; - return -1; - } - - if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) { - trailer_pos = stream->trailer_recvbuf->buffer; - trailer_end = trailer_pos + stream->trailer_recvbuf->size_used; - - for(; trailer_pos < trailer_end;) { - uint32_t n; - memcpy(&n, trailer_pos, sizeof(n)); - trailer_pos += sizeof(n); - - result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n); - if(result) { - *err = result; - return -1; - } - - trailer_pos += n + 1; - } - } - - stream->close_handled = TRUE; - - DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); - return 0; -} - -/* - * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight - * and dependency to the peer. It also stores the updated values in the state - * struct. - */ - -static void h2_pri_spec(struct Curl_easy *data, - nghttp2_priority_spec *pri_spec) -{ - struct HTTP *depstream = (data->set.stream_depends_on? - data->set.stream_depends_on->req.protop:NULL); - int32_t depstream_id = depstream? depstream->stream_id:0; - nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight, - data->set.stream_depends_e); - data->state.stream_weight = data->set.stream_weight; - data->state.stream_depends_e = data->set.stream_depends_e; - data->state.stream_depends_on = data->set.stream_depends_on; -} - -/* - * h2_session_send() checks if there's been an update in the priority / - * dependency settings and if so it submits a PRIORITY frame with the updated - * info. - */ -static int h2_session_send(struct Curl_easy *data, - nghttp2_session *h2) -{ - struct HTTP *stream = data->req.protop; - if((data->set.stream_weight != data->state.stream_weight) || - (data->set.stream_depends_e != data->state.stream_depends_e) || - (data->set.stream_depends_on != data->state.stream_depends_on) ) { - /* send new weight and/or dependency */ - nghttp2_priority_spec pri_spec; - int rv; - - h2_pri_spec(data, &pri_spec); - - DEBUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n", - stream->stream_id, data)); - rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id, - &pri_spec); - if(rv) - return rv; - } - - return nghttp2_session_send(h2); -} - -static ssize_t http2_recv(struct connectdata *conn, int sockindex, - char *mem, size_t len, CURLcode *err) -{ - CURLcode result = CURLE_OK; - ssize_t rv; - ssize_t nread; - struct http_conn *httpc = &conn->proto.httpc; - struct Curl_easy *data = conn->data; - struct HTTP *stream = data->req.protop; - - (void)sockindex; /* we always do HTTP2 on sockindex 0 */ - - if(should_close_session(httpc)) { - DEBUGF(infof(data, - "http2_recv: nothing to do in this session\n")); - *err = CURLE_HTTP2; - return -1; - } - - /* Nullify here because we call nghttp2_session_send() and they - might refer to the old buffer. */ - stream->upload_mem = NULL; - stream->upload_len = 0; - - /* - * At this point 'stream' is just in the Curl_easy the connection - * identifies as its owner at this time. - */ - - if(stream->bodystarted && - stream->nread_header_recvbuf < stream->header_recvbuf->size_used) { - /* If there is body data pending for this stream to return, do that */ - size_t left = - stream->header_recvbuf->size_used - stream->nread_header_recvbuf; - size_t ncopy = MIN(len, left); - memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf, - ncopy); - stream->nread_header_recvbuf += ncopy; - - DEBUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", - (int)ncopy)); - return ncopy; - } - - DEBUGF(infof(data, "http2_recv: easy %p (stream %u)\n", - data, stream->stream_id)); - - if((data->state.drain) && stream->memlen) { - DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n", - stream->memlen, stream->stream_id, - stream->mem, mem)); - if(mem != stream->mem) { - /* if we didn't get the same buffer this time, we must move the data to - the beginning */ - memmove(mem, stream->mem, stream->memlen); - stream->len = len - stream->memlen; - stream->mem = mem; - } - if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) { - /* We have paused nghttp2, but we have no pause data (see - on_data_chunk_recv). */ - httpc->pause_stream_id = 0; - if(h2_process_pending_input(data, httpc, &result) != 0) { - *err = result; - return -1; - } - } - } - else if(stream->pausedata) { - DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); - nread = MIN(len, stream->pauselen); - memcpy(mem, stream->pausedata, nread); - - stream->pausedata += nread; - stream->pauselen -= nread; - - infof(data, "%zu data bytes written\n", nread); - if(stream->pauselen == 0) { - DEBUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id)); - DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); - httpc->pause_stream_id = 0; - - stream->pausedata = NULL; - stream->pauselen = 0; - - /* When NGHTTP2_ERR_PAUSE is returned from - data_source_read_callback, we might not process DATA frame - fully. Calling nghttp2_session_mem_recv() again will - continue to process DATA frame, but if there is no incoming - frames, then we have to call it again with 0-length data. - Without this, on_stream_close callback will not be called, - and stream could be hanged. */ - if(h2_process_pending_input(data, httpc, &result) != 0) { - *err = result; - return -1; - } - } - DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n", - nread, stream->stream_id)); - return nread; - } - else if(httpc->pause_stream_id) { - /* If a stream paused nghttp2_session_mem_recv previously, and has - not processed all data, it still refers to the buffer in - nghttp2_session. If we call nghttp2_session_mem_recv(), we may - overwrite that buffer. To avoid that situation, just return - here with CURLE_AGAIN. This could be busy loop since data in - socket is not read. But it seems that usually streams are - notified with its drain property, and socket is read again - quickly. */ - DEBUGF(infof(data, "stream %x is paused, pause id: %x\n", - stream->stream_id, httpc->pause_stream_id)); - *err = CURLE_AGAIN; - return -1; - } - else { - char *inbuf; - /* remember where to store incoming data for this stream and how big the - buffer is */ - stream->mem = mem; - stream->len = len; - stream->memlen = 0; - - if(httpc->inbuflen == 0) { - nread = ((Curl_recv *)httpc->recv_underlying)( - conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); - - if(nread == -1) { - if(result != CURLE_AGAIN) - failf(data, "Failed receiving HTTP2 data"); - else if(stream->closed) - /* received when the stream was already closed! */ - return http2_handle_stream_close(conn, data, stream, err); - - *err = result; - return -1; - } - - if(nread == 0) { - failf(data, "Unexpected EOF"); - *err = CURLE_RECV_ERROR; - return -1; - } - - DEBUGF(infof(data, "nread=%zd\n", nread)); - - httpc->inbuflen = nread; - inbuf = httpc->inbuf; - } - else { - nread = httpc->inbuflen - httpc->nread_inbuf; - inbuf = httpc->inbuf + httpc->nread_inbuf; - - DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n", - nread)); - } - rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); - - if(nghttp2_is_fatal((int)rv)) { - failf(data, "nghttp2_session_mem_recv() returned %d:%s\n", - rv, nghttp2_strerror((int)rv)); - *err = CURLE_RECV_ERROR; - return -1; - } - DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv)); - if(nread == rv) { - DEBUGF(infof(data, "All data in connection buffer processed\n")); - httpc->inbuflen = 0; - httpc->nread_inbuf = 0; - } - else { - httpc->nread_inbuf += rv; - DEBUGF(infof(data, "%zu bytes left in connection buffer\n", - httpc->inbuflen - httpc->nread_inbuf)); - } - /* Always send pending frames in nghttp2 session, because - nghttp2_session_mem_recv() may queue new frame */ - rv = h2_session_send(data, httpc->h2); - if(rv != 0) { - *err = CURLE_SEND_ERROR; - return -1; - } - - if(should_close_session(httpc)) { - DEBUGF(infof(data, "http2_recv: nothing to do in this session\n")); - *err = CURLE_HTTP2; - return -1; - } - } - if(stream->memlen) { - ssize_t retlen = stream->memlen; - DEBUGF(infof(data, "http2_recv: returns %zd for stream %u\n", - retlen, stream->stream_id)); - stream->memlen = 0; - - if(httpc->pause_stream_id == stream->stream_id) { - /* data for this stream is returned now, but this stream caused a pause - already so we need it called again asap */ - DEBUGF(infof(data, "Data returned for PAUSED stream %u\n", - stream->stream_id)); - } - else if(!stream->closed) { - DEBUGASSERT(httpc->drain_total >= data->state.drain); - httpc->drain_total -= data->state.drain; - data->state.drain = 0; /* this stream is hereby drained */ - } - - return retlen; - } - /* If stream is closed, return 0 to signal the http routine to close - the connection */ - if(stream->closed) { - return http2_handle_stream_close(conn, data, stream, err); - } - *err = CURLE_AGAIN; - DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n", - stream->stream_id)); - return -1; -} - -/* Index where :authority header field will appear in request header - field list. */ -#define AUTHORITY_DST_IDX 3 - -#define HEADER_OVERFLOW(x) \ - (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen) - -/* - * Check header memory for the token "trailers". - * Parse the tokens as separated by comma and surrounded by whitespace. - * Returns TRUE if found or FALSE if not. - */ -static bool contains_trailers(const char *p, size_t len) -{ - const char *end = p + len; - for(;;) { - for(; p != end && (*p == ' ' || *p == '\t'); ++p) - ; - if(p == end || (size_t)(end - p) < sizeof("trailers") - 1) - return FALSE; - if(strncasecompare("trailers", p, sizeof("trailers") - 1)) { - p += sizeof("trailers") - 1; - for(; p != end && (*p == ' ' || *p == '\t'); ++p) - ; - if(p == end || *p == ',') - return TRUE; - } - /* skip to next token */ - for(; p != end && *p != ','; ++p) - ; - if(p == end) - return FALSE; - ++p; - } -} - -typedef enum { - /* Send header to server */ - HEADERINST_FORWARD, - /* Don't send header to server */ - HEADERINST_IGNORE, - /* Discard header, and replace it with "te: trailers" */ - HEADERINST_TE_TRAILERS -} header_instruction; - -/* Decides how to treat given header field. */ -static header_instruction inspect_header(const char *name, size_t namelen, - const char *value, size_t valuelen) { - switch(namelen) { - case 2: - if(!strncasecompare("te", name, namelen)) - return HEADERINST_FORWARD; - - return contains_trailers(value, valuelen) ? - HEADERINST_TE_TRAILERS : HEADERINST_IGNORE; - case 7: - return strncasecompare("upgrade", name, namelen) ? - HEADERINST_IGNORE : HEADERINST_FORWARD; - case 10: - return (strncasecompare("connection", name, namelen) || - strncasecompare("keep-alive", name, namelen)) ? - HEADERINST_IGNORE : HEADERINST_FORWARD; - case 16: - return strncasecompare("proxy-connection", name, namelen) ? - HEADERINST_IGNORE : HEADERINST_FORWARD; - case 17: - return strncasecompare("transfer-encoding", name, namelen) ? - HEADERINST_IGNORE : HEADERINST_FORWARD; - default: - return HEADERINST_FORWARD; - } -} - -static ssize_t http2_send(struct connectdata *conn, int sockindex, - const void *mem, size_t len, CURLcode *err) -{ - /* - * BIG TODO: Currently, we send request in this function, but this - * function is also used to send request body. It would be nice to - * add dedicated function for request. - */ - int rv; - struct http_conn *httpc = &conn->proto.httpc; - struct HTTP *stream = conn->data->req.protop; - nghttp2_nv *nva = NULL; - size_t nheader; - size_t i; - size_t authority_idx; - char *hdbuf = (char *)mem; - char *end, *line_end; - nghttp2_data_provider data_prd; - int32_t stream_id; - nghttp2_session *h2 = httpc->h2; - nghttp2_priority_spec pri_spec; - - (void)sockindex; - - DEBUGF(infof(conn->data, "http2_send len=%zu\n", len)); - - if(stream->stream_id != -1) { - if(stream->close_handled) { - infof(conn->data, "stream %d closed\n", stream->stream_id); - *err = CURLE_HTTP2_STREAM; - return -1; - } - else if(stream->closed) { - return http2_handle_stream_close(conn, conn->data, stream, err); - } - /* If stream_id != -1, we have dispatched request HEADERS, and now - are going to send or sending request body in DATA frame */ - stream->upload_mem = mem; - stream->upload_len = len; - nghttp2_session_resume_data(h2, stream->stream_id); - rv = h2_session_send(conn->data, h2); - if(nghttp2_is_fatal(rv)) { - *err = CURLE_SEND_ERROR; - return -1; - } - len -= stream->upload_len; - - /* Nullify here because we call nghttp2_session_send() and they - might refer to the old buffer. */ - stream->upload_mem = NULL; - stream->upload_len = 0; - - if(should_close_session(httpc)) { - DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); - *err = CURLE_HTTP2; - return -1; - } - - if(stream->upload_left) { - /* we are sure that we have more data to send here. Calling the - following API will make nghttp2_session_want_write() return - nonzero if remote window allows it, which then libcurl checks - socket is writable or not. See http2_perform_getsock(). */ - nghttp2_session_resume_data(h2, stream->stream_id); - } - - DEBUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len, - stream->stream_id)); - return len; - } - - /* Calculate number of headers contained in [mem, mem + len) */ - /* Here, we assume the curl http code generate *correct* HTTP header - field block */ - nheader = 0; - for(i = 1; i < len; ++i) { - if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') { - ++nheader; - ++i; - } - } - if(nheader < 2) - goto fail; - - /* We counted additional 2 \r\n in the first and last line. We need 3 - new headers: :method, :path and :scheme. Therefore we need one - more space. */ - nheader += 1; - nva = malloc(sizeof(nghttp2_nv) * nheader); - if(nva == NULL) { - *err = CURLE_OUT_OF_MEMORY; - return -1; - } - - /* Extract :method, :path from request line */ - line_end = strstr(hdbuf, "\r\n"); - - /* Method does not contain spaces */ - end = memchr(hdbuf, ' ', line_end - hdbuf); - if(!end || end == hdbuf) - goto fail; - nva[0].name = (unsigned char *)":method"; - nva[0].namelen = strlen((char *)nva[0].name); - nva[0].value = (unsigned char *)hdbuf; - nva[0].valuelen = (size_t)(end - hdbuf); - nva[0].flags = NGHTTP2_NV_FLAG_NONE; - if(HEADER_OVERFLOW(nva[0])) { - failf(conn->data, "Failed sending HTTP request: Header overflow"); - goto fail; - } - - hdbuf = end + 1; - - /* Path may contain spaces so scan backwards */ - end = NULL; - for(i = (size_t)(line_end - hdbuf); i; --i) { - if(hdbuf[i - 1] == ' ') { - end = &hdbuf[i - 1]; - break; - } - } - if(!end || end == hdbuf) - goto fail; - nva[1].name = (unsigned char *)":path"; - nva[1].namelen = strlen((char *)nva[1].name); - nva[1].value = (unsigned char *)hdbuf; - nva[1].valuelen = (size_t)(end - hdbuf); - nva[1].flags = NGHTTP2_NV_FLAG_NONE; - if(HEADER_OVERFLOW(nva[1])) { - failf(conn->data, "Failed sending HTTP request: Header overflow"); - goto fail; - } - - hdbuf = end + 1; - - end = line_end; - nva[2].name = (unsigned char *)":scheme"; - nva[2].namelen = strlen((char *)nva[2].name); - if(conn->handler->flags & PROTOPT_SSL) - nva[2].value = (unsigned char *)"https"; - else - nva[2].value = (unsigned char *)"http"; - nva[2].valuelen = strlen((char *)nva[2].value); - nva[2].flags = NGHTTP2_NV_FLAG_NONE; - if(HEADER_OVERFLOW(nva[2])) { - failf(conn->data, "Failed sending HTTP request: Header overflow"); - goto fail; - } - - authority_idx = 0; - i = 3; - while(i < nheader) { - size_t hlen; - - hdbuf = line_end + 2; - - line_end = strstr(hdbuf, "\r\n"); - if(line_end == hdbuf) - goto fail; - - /* header continuation lines are not supported */ - if(*hdbuf == ' ' || *hdbuf == '\t') - goto fail; - - for(end = hdbuf; end < line_end && *end != ':'; ++end) - ; - if(end == hdbuf || end == line_end) - goto fail; - hlen = end - hdbuf; - - if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { - authority_idx = i; - nva[i].name = (unsigned char *)":authority"; - nva[i].namelen = strlen((char *)nva[i].name); - } - else { - nva[i].name = (unsigned char *)hdbuf; - nva[i].namelen = (size_t)(end - hdbuf); - } - hdbuf = end + 1; - while(*hdbuf == ' ' || *hdbuf == '\t') - ++hdbuf; - end = line_end; - - switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf, - end - hdbuf)) { - case HEADERINST_IGNORE: - /* skip header fields prohibited by HTTP/2 specification. */ - --nheader; - continue; - case HEADERINST_TE_TRAILERS: - nva[i].value = (uint8_t*)"trailers"; - nva[i].valuelen = sizeof("trailers") - 1; - break; - default: - nva[i].value = (unsigned char *)hdbuf; - nva[i].valuelen = (size_t)(end - hdbuf); - } - - nva[i].flags = NGHTTP2_NV_FLAG_NONE; - if(HEADER_OVERFLOW(nva[i])) { - failf(conn->data, "Failed sending HTTP request: Header overflow"); - goto fail; - } - ++i; - } - - /* :authority must come before non-pseudo header fields */ - if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) { - nghttp2_nv authority = nva[authority_idx]; - for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) { - nva[i] = nva[i - 1]; - } - nva[i] = authority; - } - - /* Warn stream may be rejected if cumulative length of headers is too large. - It appears nghttp2 will not send a header frame larger than 64KB. */ -#define MAX_ACC 60000 /* <64KB to account for some overhead */ - { - size_t acc = 0; - - for(i = 0; i < nheader; ++i) { - acc += nva[i].namelen + nva[i].valuelen; - - DEBUGF(infof(conn->data, "h2 header: %.*s:%.*s\n", - nva[i].namelen, nva[i].name, - nva[i].valuelen, nva[i].value)); - } - - if(acc > MAX_ACC) { - infof(conn->data, "http2_send: Warning: The cumulative length of all " - "headers exceeds %zu bytes and that could cause the " - "stream to be rejected.\n", MAX_ACC); - } - } - - h2_pri_spec(conn->data, &pri_spec); - - switch(conn->data->set.httpreq) { - case HTTPREQ_POST: - case HTTPREQ_POST_FORM: - case HTTPREQ_POST_MIME: - case HTTPREQ_PUT: - if(conn->data->state.infilesize != -1) - stream->upload_left = conn->data->state.infilesize; - else - /* data sending without specifying the data amount up front */ - stream->upload_left = -1; /* unknown, but not zero */ - - data_prd.read_callback = data_source_read_callback; - data_prd.source.ptr = NULL; - stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, - &data_prd, conn->data); - break; - default: - stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, - NULL, conn->data); - } - - Curl_safefree(nva); - - if(stream_id < 0) { - DEBUGF(infof(conn->data, "http2_send() send error\n")); - *err = CURLE_SEND_ERROR; - return -1; - } - - infof(conn->data, "Using Stream ID: %x (easy handle %p)\n", - stream_id, conn->data); - stream->stream_id = stream_id; - - /* this does not call h2_session_send() since there can not have been any - * priority upodate since the nghttp2_submit_request() call above */ - rv = nghttp2_session_send(h2); - - if(rv != 0) { - *err = CURLE_SEND_ERROR; - return -1; - } - - if(should_close_session(httpc)) { - DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); - *err = CURLE_HTTP2; - return -1; - } - - if(stream->stream_id != -1) { - /* If whole HEADERS frame was sent off to the underlying socket, - the nghttp2 library calls data_source_read_callback. But only - it found that no data available, so it deferred the DATA - transmission. Which means that nghttp2_session_want_write() - returns 0 on http2_perform_getsock(), which results that no - writable socket check is performed. To workaround this, we - issue nghttp2_session_resume_data() here to bring back DATA - transmission from deferred state. */ - nghttp2_session_resume_data(h2, stream->stream_id); - } - - return len; - -fail: - free(nva); - *err = CURLE_SEND_ERROR; - return -1; -} - -CURLcode Curl_http2_setup(struct connectdata *conn) -{ - CURLcode result; - struct http_conn *httpc = &conn->proto.httpc; - struct HTTP *stream = conn->data->req.protop; - - stream->stream_id = -1; - - if(!stream->header_recvbuf) - stream->header_recvbuf = Curl_add_buffer_init(); - - if((conn->handler == &Curl_handler_http2_ssl) || - (conn->handler == &Curl_handler_http2)) - return CURLE_OK; /* already done */ - - if(conn->handler->flags & PROTOPT_SSL) - conn->handler = &Curl_handler_http2_ssl; - else - conn->handler = &Curl_handler_http2; - - result = Curl_http2_init(conn); - if(result) - return result; - - infof(conn->data, "Using HTTP2, server supports multi-use\n"); - stream->upload_left = 0; - stream->upload_mem = NULL; - stream->upload_len = 0; - - httpc->inbuflen = 0; - httpc->nread_inbuf = 0; - - httpc->pause_stream_id = 0; - httpc->drain_total = 0; - - conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - conn->httpversion = 20; - conn->bundle->multiuse = BUNDLE_MULTIPLEX; - - infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); - Curl_multi_connchanged(conn->data->multi); - - return CURLE_OK; -} - -CURLcode Curl_http2_switched(struct connectdata *conn, - const char *mem, size_t nread) -{ - CURLcode result; - struct http_conn *httpc = &conn->proto.httpc; - int rv; - ssize_t nproc; - struct Curl_easy *data = conn->data; - struct HTTP *stream = conn->data->req.protop; - - result = Curl_http2_setup(conn); - if(result) - return result; - - httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET]; - httpc->send_underlying = (sending)conn->send[FIRSTSOCKET]; - conn->recv[FIRSTSOCKET] = http2_recv; - conn->send[FIRSTSOCKET] = http2_send; - - if(conn->data->req.upgr101 == UPGR101_RECEIVED) { - /* stream 1 is opened implicitly on upgrade */ - stream->stream_id = 1; - /* queue SETTINGS frame (again) */ - rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings, - httpc->binlen, NULL); - if(rv != 0) { - failf(data, "nghttp2_session_upgrade() failed: %s(%d)", - nghttp2_strerror(rv), rv); - return CURLE_HTTP2; - } - - nghttp2_session_set_stream_user_data(httpc->h2, - stream->stream_id, - conn->data); - } - else { - populate_settings(conn, httpc); - - /* stream ID is unknown at this point */ - stream->stream_id = -1; - rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, - httpc->local_settings, - httpc->local_settings_num); - if(rv != 0) { - failf(data, "nghttp2_submit_settings() failed: %s(%d)", - nghttp2_strerror(rv), rv); - return CURLE_HTTP2; - } - } - -#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE - rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0, - HTTP2_HUGE_WINDOW_SIZE); - if(rv != 0) { - failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", - nghttp2_strerror(rv), rv); - return CURLE_HTTP2; - } -#endif - - /* we are going to copy mem to httpc->inbuf. This is required since - mem is part of buffer pointed by stream->mem, and callbacks - called by nghttp2_session_mem_recv() will write stream specific - data into stream->mem, overwriting data already there. */ - if(H2_BUFSIZE < nread) { - failf(data, "connection buffer size is too small to store data following " - "HTTP Upgrade response header: buflen=%zu, datalen=%zu", - H2_BUFSIZE, nread); - return CURLE_HTTP2; - } - - infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer" - " after upgrade: len=%zu\n", - nread); - - if(nread) - memcpy(httpc->inbuf, mem, nread); - httpc->inbuflen = nread; - - nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf, - httpc->inbuflen); - - if(nghttp2_is_fatal((int)nproc)) { - failf(data, "nghttp2_session_mem_recv() failed: %s(%d)", - nghttp2_strerror((int)nproc), (int)nproc); - return CURLE_HTTP2; - } - - DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc)); - - if((ssize_t)nread == nproc) { - httpc->inbuflen = 0; - httpc->nread_inbuf = 0; - } - else { - httpc->nread_inbuf += nproc; - } - - /* Try to send some frames since we may read SETTINGS already. */ - rv = h2_session_send(data, httpc->h2); - - if(rv != 0) { - failf(data, "nghttp2_session_send() failed: %s(%d)", - nghttp2_strerror(rv), rv); - return CURLE_HTTP2; - } - - if(should_close_session(httpc)) { - DEBUGF(infof(data, - "nghttp2_session_send(): nothing to do in this session\n")); - return CURLE_HTTP2; - } - - return CURLE_OK; -} - -CURLcode Curl_http2_add_child(struct Curl_easy *parent, - struct Curl_easy *child, - bool exclusive) -{ - if(parent) { - struct Curl_http2_dep **tail; - struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep)); - if(!dep) - return CURLE_OUT_OF_MEMORY; - dep->data = child; - - if(parent->set.stream_dependents && exclusive) { - struct Curl_http2_dep *node = parent->set.stream_dependents; - while(node) { - node->data->set.stream_depends_on = child; - node = node->next; - } - - tail = &child->set.stream_dependents; - while(*tail) - tail = &(*tail)->next; - - DEBUGASSERT(!*tail); - *tail = parent->set.stream_dependents; - parent->set.stream_dependents = 0; - } - - tail = &parent->set.stream_dependents; - while(*tail) { - (*tail)->data->set.stream_depends_e = FALSE; - tail = &(*tail)->next; - } - - DEBUGASSERT(!*tail); - *tail = dep; - } - - child->set.stream_depends_on = parent; - child->set.stream_depends_e = exclusive; - return CURLE_OK; -} - -void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child) -{ - struct Curl_http2_dep *last = 0; - struct Curl_http2_dep *data = parent->set.stream_dependents; - DEBUGASSERT(child->set.stream_depends_on == parent); - - while(data && data->data != child) { - last = data; - data = data->next; - } - - DEBUGASSERT(data); - - if(data) { - if(last) { - last->next = data->next; - } - else { - parent->set.stream_dependents = data->next; - } - free(data); - } - - child->set.stream_depends_on = 0; - child->set.stream_depends_e = FALSE; -} - -void Curl_http2_cleanup_dependencies(struct Curl_easy *data) -{ - while(data->set.stream_dependents) { - struct Curl_easy *tmp = data->set.stream_dependents->data; - Curl_http2_remove_child(data, tmp); - if(data->set.stream_depends_on) - Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE); - } - - if(data->set.stream_depends_on) - Curl_http2_remove_child(data->set.stream_depends_on, data); -} - -#else /* !USE_NGHTTP2 */ - -/* Satisfy external references even if http2 is not compiled in. */ - -#define CURL_DISABLE_TYPECHECK -#include - -char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) -{ - (void) h; - (void) num; - return NULL; -} - -char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) -{ - (void) h; - (void) header; - return NULL; -} - -#endif /* USE_NGHTTP2 */ diff --git a/dep/cpr/opt/curl/lib/http2.h b/dep/cpr/opt/curl/lib/http2.h deleted file mode 100644 index f597c805e5d..00000000000 --- a/dep/cpr/opt/curl/lib/http2.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef HEADER_CURL_HTTP2_H -#define HEADER_CURL_HTTP2_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_NGHTTP2 -#include "http.h" - -/* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting - from the peer */ -#define DEFAULT_MAX_CONCURRENT_STREAMS 13 - -/* - * Store nghttp2 version info in this buffer, Prefix with a space. Return - * total length written. - */ -int Curl_http2_ver(char *p, size_t len); - -const char *Curl_http2_strerror(uint32_t err); - -CURLcode Curl_http2_init(struct connectdata *conn); -void Curl_http2_init_state(struct UrlState *state); -void Curl_http2_init_userset(struct UserDefined *set); -CURLcode Curl_http2_send_request(struct connectdata *conn); -CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, - struct connectdata *conn); -CURLcode Curl_http2_setup(struct connectdata *conn); -CURLcode Curl_http2_switched(struct connectdata *conn, - const char *data, size_t nread); -/* called from Curl_http_setup_conn */ -void Curl_http2_setup_conn(struct connectdata *conn); -void Curl_http2_setup_req(struct Curl_easy *data); -void Curl_http2_done(struct connectdata *conn, bool premature); -CURLcode Curl_http2_done_sending(struct connectdata *conn); -CURLcode Curl_http2_add_child(struct Curl_easy *parent, - struct Curl_easy *child, - bool exclusive); -void Curl_http2_remove_child(struct Curl_easy *parent, - struct Curl_easy *child); -void Curl_http2_cleanup_dependencies(struct Curl_easy *data); -#else /* USE_NGHTTP2 */ -#define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL -#define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL -#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL -#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL -#define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL -#define Curl_http2_setup_conn(x) -#define Curl_http2_setup_req(x) -#define Curl_http2_init_state(x) -#define Curl_http2_init_userset(x) -#define Curl_http2_done(x,y) -#define Curl_http2_done_sending(x) -#define Curl_http2_add_child(x, y, z) -#define Curl_http2_remove_child(x, y) -#define Curl_http2_cleanup_dependencies(x) -#endif - -#endif /* HEADER_CURL_HTTP2_H */ - diff --git a/dep/cpr/opt/curl/lib/http_chunks.c b/dep/cpr/opt/curl/lib/http_chunks.c deleted file mode 100644 index 92d773112ba..00000000000 --- a/dep/cpr/opt/curl/lib/http_chunks.c +++ /dev/null @@ -1,379 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_HTTP - -#include "urldata.h" /* it includes http_chunks.h */ -#include "sendf.h" /* for the client write stuff */ - -#include "content_encoding.h" -#include "http.h" -#include "non-ascii.h" /* for Curl_convert_to_network prototype */ -#include "strtoofft.h" -#include "warnless.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Chunk format (simplified): - * - * [ chunk extension ] CRLF - * CRLF - * - * Highlights from RFC2616 section 3.6 say: - - The chunked encoding modifies the body of a message in order to - transfer it as a series of chunks, each with its own size indicator, - followed by an OPTIONAL trailer containing entity-header fields. This - allows dynamically produced content to be transferred along with the - information necessary for the recipient to verify that it has - received the full message. - - Chunked-Body = *chunk - last-chunk - trailer - CRLF - - chunk = chunk-size [ chunk-extension ] CRLF - chunk-data CRLF - chunk-size = 1*HEX - last-chunk = 1*("0") [ chunk-extension ] CRLF - - chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) - chunk-ext-name = token - chunk-ext-val = token | quoted-string - chunk-data = chunk-size(OCTET) - trailer = *(entity-header CRLF) - - The chunk-size field is a string of hex digits indicating the size of - the chunk. The chunked encoding is ended by any chunk whose size is - zero, followed by the trailer, which is terminated by an empty line. - - */ - -/* Check for an ASCII hex digit. - We avoid the use of isxdigit to accommodate non-ASCII hosts. */ -static bool Curl_isxdigit(char digit) -{ - return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ - || (digit >= 0x41 && digit <= 0x46) /* A-F */ - || (digit >= 0x61 && digit <= 0x66) /* a-f */) ? TRUE : FALSE; -} - -void Curl_httpchunk_init(struct connectdata *conn) -{ - struct Curl_chunker *chunk = &conn->chunk; - chunk->hexindex = 0; /* start at 0 */ - chunk->dataleft = 0; /* no data left yet! */ - chunk->state = CHUNK_HEX; /* we get hex first! */ -} - -/* - * chunk_read() returns a OK for normal operations, or a positive return code - * for errors. STOP means this sequence of chunks is complete. The 'wrote' - * argument is set to tell the caller how many bytes we actually passed to the - * client (for byte-counting and whatever). - * - * The states and the state-machine is further explained in the header file. - * - * This function always uses ASCII hex values to accommodate non-ASCII hosts. - * For example, 0x0d and 0x0a are used instead of '\r' and '\n'. - */ -CHUNKcode Curl_httpchunk_read(struct connectdata *conn, - char *datap, - ssize_t datalen, - ssize_t *wrotep) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct Curl_chunker *ch = &conn->chunk; - struct SingleRequest *k = &data->req; - size_t piece; - curl_off_t length = (curl_off_t)datalen; - size_t *wrote = (size_t *)wrotep; - - *wrote = 0; /* nothing's written yet */ - - /* the original data is written to the client, but we go on with the - chunk read process, to properly calculate the content length*/ - if(data->set.http_te_skip && !k->ignorebody) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, datalen); - if(result) - return CHUNKE_WRITE_ERROR; - } - - while(length) { - switch(ch->state) { - case CHUNK_HEX: - if(Curl_isxdigit(*datap)) { - if(ch->hexindex < MAXNUM_SIZE) { - ch->hexbuffer[ch->hexindex] = *datap; - datap++; - length--; - ch->hexindex++; - } - else { - return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */ - } - } - else { - char *endptr; - if(0 == ch->hexindex) - /* This is illegal data, we received junk where we expected - a hexadecimal digit. */ - return CHUNKE_ILLEGAL_HEX; - - /* length and datap are unmodified */ - ch->hexbuffer[ch->hexindex] = 0; - - /* convert to host encoding before calling strtoul */ - result = Curl_convert_from_network(conn->data, ch->hexbuffer, - ch->hexindex); - if(result) { - /* Curl_convert_from_network calls failf if unsuccessful */ - /* Treat it as a bad hex character */ - return CHUNKE_ILLEGAL_HEX; - } - - if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize)) - return CHUNKE_ILLEGAL_HEX; - ch->state = CHUNK_LF; /* now wait for the CRLF */ - } - break; - - case CHUNK_LF: - /* waiting for the LF after a chunk size */ - if(*datap == 0x0a) { - /* we're now expecting data to come, unless size was zero! */ - if(0 == ch->datasize) { - ch->state = CHUNK_TRAILER; /* now check for trailers */ - conn->trlPos = 0; - } - else - ch->state = CHUNK_DATA; - } - - datap++; - length--; - break; - - case CHUNK_DATA: - /* We expect 'datasize' of data. We have 'length' right now, it can be - more or less than 'datasize'. Get the smallest piece. - */ - piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize); - - /* Write the data portion available */ -#ifdef HAVE_LIBZ - switch(conn->data->set.http_ce_skip? - IDENTITY : data->req.auto_decoding) { - case IDENTITY: -#endif - if(!k->ignorebody) { - if(!data->set.http_te_skip) - result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, - piece); - else - result = CURLE_OK; - } -#ifdef HAVE_LIBZ - break; - - case DEFLATE: - /* update data->req.keep.str to point to the chunk data. */ - data->req.str = datap; - result = Curl_unencode_deflate_write(conn, &data->req, - (ssize_t)piece); - break; - - case GZIP: - /* update data->req.keep.str to point to the chunk data. */ - data->req.str = datap; - result = Curl_unencode_gzip_write(conn, &data->req, - (ssize_t)piece); - break; - - default: - failf(conn->data, - "Unrecognized content encoding type. " - "libcurl understands `identity', `deflate' and `gzip' " - "content encodings."); - return CHUNKE_BAD_ENCODING; - } -#endif - - if(result) - return CHUNKE_WRITE_ERROR; - - *wrote += piece; - - ch->datasize -= piece; /* decrease amount left to expect */ - datap += piece; /* move read pointer forward */ - length -= piece; /* decrease space left in this round */ - - if(0 == ch->datasize) - /* end of data this round, we now expect a trailing CRLF */ - ch->state = CHUNK_POSTLF; - break; - - case CHUNK_POSTLF: - if(*datap == 0x0a) { - /* The last one before we go back to hex state and start all over. */ - Curl_httpchunk_init(conn); /* sets state back to CHUNK_HEX */ - } - else if(*datap != 0x0d) - return CHUNKE_BAD_CHUNK; - datap++; - length--; - break; - - case CHUNK_TRAILER: - if((*datap == 0x0d) || (*datap == 0x0a)) { - /* this is the end of a trailer, but if the trailer was zero bytes - there was no trailer and we move on */ - - if(conn->trlPos) { - /* we allocate trailer with 3 bytes extra room to fit this */ - conn->trailer[conn->trlPos++] = 0x0d; - conn->trailer[conn->trlPos++] = 0x0a; - conn->trailer[conn->trlPos] = 0; - - /* Convert to host encoding before calling Curl_client_write */ - result = Curl_convert_from_network(conn->data, conn->trailer, - conn->trlPos); - if(result) - /* Curl_convert_from_network calls failf if unsuccessful */ - /* Treat it as a bad chunk */ - return CHUNKE_BAD_CHUNK; - - if(!data->set.http_te_skip) { - result = Curl_client_write(conn, CLIENTWRITE_HEADER, - conn->trailer, conn->trlPos); - if(result) - return CHUNKE_WRITE_ERROR; - } - conn->trlPos = 0; - ch->state = CHUNK_TRAILER_CR; - if(*datap == 0x0a) - /* already on the LF */ - break; - } - else { - /* no trailer, we're on the final CRLF pair */ - ch->state = CHUNK_TRAILER_POSTCR; - break; /* don't advance the pointer */ - } - } - else { - /* conn->trailer is assumed to be freed in url.c on a - connection basis */ - if(conn->trlPos >= conn->trlMax) { - /* we always allocate three extra bytes, just because when the full - header has been received we append CRLF\0 */ - char *ptr; - if(conn->trlMax) { - conn->trlMax *= 2; - ptr = realloc(conn->trailer, conn->trlMax + 3); - } - else { - conn->trlMax = 128; - ptr = malloc(conn->trlMax + 3); - } - if(!ptr) - return CHUNKE_OUT_OF_MEMORY; - conn->trailer = ptr; - } - conn->trailer[conn->trlPos++]=*datap; - } - datap++; - length--; - break; - - case CHUNK_TRAILER_CR: - if(*datap == 0x0a) { - ch->state = CHUNK_TRAILER_POSTCR; - datap++; - length--; - } - else - return CHUNKE_BAD_CHUNK; - break; - - case CHUNK_TRAILER_POSTCR: - /* We enter this state when a CR should arrive so we expect to - have to first pass a CR before we wait for LF */ - if((*datap != 0x0d) && (*datap != 0x0a)) { - /* not a CR then it must be another header in the trailer */ - ch->state = CHUNK_TRAILER; - break; - } - if(*datap == 0x0d) { - /* skip if CR */ - datap++; - length--; - } - /* now wait for the final LF */ - ch->state = CHUNK_STOP; - break; - - case CHUNK_STOP: - if(*datap == 0x0a) { - length--; - - /* Record the length of any data left in the end of the buffer - even if there's no more chunks to read */ - ch->dataleft = curlx_sotouz(length); - - return CHUNKE_STOP; /* return stop */ - } - else - return CHUNKE_BAD_CHUNK; - } - } - return CHUNKE_OK; -} - -const char *Curl_chunked_strerror(CHUNKcode code) -{ - switch(code) { - default: - return "OK"; - case CHUNKE_TOO_LONG_HEX: - return "Too long hexadecimal number"; - case CHUNKE_ILLEGAL_HEX: - return "Illegal or missing hexadecimal sequence"; - case CHUNKE_BAD_CHUNK: - return "Malformed encoding found"; - case CHUNKE_WRITE_ERROR: - return "Write error"; - case CHUNKE_BAD_ENCODING: - return "Bad content-encoding found"; - case CHUNKE_OUT_OF_MEMORY: - return "Out of memory"; - } -} - -#endif /* CURL_DISABLE_HTTP */ diff --git a/dep/cpr/opt/curl/lib/http_chunks.h b/dep/cpr/opt/curl/lib/http_chunks.h deleted file mode 100644 index 3a8b4ddf373..00000000000 --- a/dep/cpr/opt/curl/lib/http_chunks.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef HEADER_CURL_HTTP_CHUNKS_H -#define HEADER_CURL_HTTP_CHUNKS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -/* - * The longest possible hexadecimal number we support in a chunked transfer. - * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul() - * to convert it, we "only" support 2^32 bytes chunk data. - */ -#define MAXNUM_SIZE 16 - -typedef enum { - /* await and buffer all hexadecimal digits until we get one that isn't a - hexadecimal digit. When done, we go CHUNK_LF */ - CHUNK_HEX, - - /* wait for LF, ignore all else */ - CHUNK_LF, - - /* We eat the amount of data specified. When done, we move on to the - POST_CR state. */ - CHUNK_DATA, - - /* POSTLF should get a CR and then a LF and nothing else, then move back to - HEX as the CRLF combination marks the end of a chunk. A missing CR is no - big deal. */ - CHUNK_POSTLF, - - /* Used to mark that we're out of the game. NOTE: that there's a 'dataleft' - field in the struct that will tell how many bytes that were not passed to - the client in the end of the last buffer! */ - CHUNK_STOP, - - /* At this point optional trailer headers can be found, unless the next line - is CRLF */ - CHUNK_TRAILER, - - /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR. - Next char must be a LF */ - CHUNK_TRAILER_CR, - - /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be - signalled If this is an empty trailer CHUNKE_STOP will be signalled. - Otherwise the trailer will be broadcasted via Curl_client_write() and the - next state will be CHUNK_TRAILER */ - CHUNK_TRAILER_POSTCR -} ChunkyState; - -typedef enum { - CHUNKE_STOP = -1, - CHUNKE_OK = 0, - CHUNKE_TOO_LONG_HEX = 1, - CHUNKE_ILLEGAL_HEX, - CHUNKE_BAD_CHUNK, - CHUNKE_WRITE_ERROR, - CHUNKE_BAD_ENCODING, - CHUNKE_OUT_OF_MEMORY, - CHUNKE_LAST -} CHUNKcode; - -const char *Curl_chunked_strerror(CHUNKcode code); - -struct Curl_chunker { - char hexbuffer[ MAXNUM_SIZE + 1]; - int hexindex; - ChunkyState state; - curl_off_t datasize; - size_t dataleft; /* untouched data amount at the end of the last buffer */ -}; - -#endif /* HEADER_CURL_HTTP_CHUNKS_H */ - diff --git a/dep/cpr/opt/curl/lib/http_digest.c b/dep/cpr/opt/curl/lib/http_digest.c deleted file mode 100644 index e2d865b0af0..00000000000 --- a/dep/cpr/opt/curl/lib/http_digest.c +++ /dev/null @@ -1,180 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) - -#include "urldata.h" -#include "strcase.h" -#include "vauth/vauth.h" -#include "http_digest.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Test example headers: - -WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" -Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" - -*/ - -CURLcode Curl_input_digest(struct connectdata *conn, - bool proxy, - const char *header) /* rest of the *-authenticate: - header */ -{ - struct Curl_easy *data = conn->data; - - /* Point to the correct struct with this */ - struct digestdata *digest; - - if(proxy) { - digest = &data->state.proxydigest; - } - else { - digest = &data->state.digest; - } - - if(!checkprefix("Digest", header)) - return CURLE_BAD_CONTENT_ENCODING; - - header += strlen("Digest"); - while(*header && ISSPACE(*header)) - header++; - - return Curl_auth_decode_digest_http_message(header, digest); -} - -CURLcode Curl_output_digest(struct connectdata *conn, - bool proxy, - const unsigned char *request, - const unsigned char *uripath) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - unsigned char *path = NULL; - char *tmp = NULL; - char *response; - size_t len; - bool have_chlg; - - /* Point to the address of the pointer that holds the string to send to the - server, which is for a plain host or for a HTTP proxy */ - char **allocuserpwd; - - /* Point to the name and password for this */ - const char *userp; - const char *passwdp; - - /* Point to the correct struct with this */ - struct digestdata *digest; - struct auth *authp; - - if(proxy) { - digest = &data->state.proxydigest; - allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->http_proxy.user; - passwdp = conn->http_proxy.passwd; - authp = &data->state.authproxy; - } - else { - digest = &data->state.digest; - allocuserpwd = &conn->allocptr.userpwd; - userp = conn->user; - passwdp = conn->passwd; - authp = &data->state.authhost; - } - - Curl_safefree(*allocuserpwd); - - /* not set means empty */ - if(!userp) - userp = ""; - - if(!passwdp) - passwdp = ""; - -#if defined(USE_WINDOWS_SSPI) - have_chlg = digest->input_token ? TRUE : FALSE; -#else - have_chlg = digest->nonce ? TRUE : FALSE; -#endif - - if(!have_chlg) { - authp->done = FALSE; - return CURLE_OK; - } - - /* So IE browsers < v7 cut off the URI part at the query part when they - evaluate the MD5 and some (IIS?) servers work with them so we may need to - do the Digest IE-style. Note that the different ways cause different MD5 - sums to get sent. - - Apache servers can be set to do the Digest IE-style automatically using - the BrowserMatch feature: - https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie - - Further details on Digest implementation differences: - http://www.fngtps.com/2006/09/http-authentication - */ - - if(authp->iestyle) { - tmp = strchr((char *)uripath, '?'); - if(tmp) { - size_t urilen = tmp - (char *)uripath; - path = (unsigned char *) aprintf("%.*s", urilen, uripath); - } - } - if(!tmp) - path = (unsigned char *) strdup((char *) uripath); - - if(!path) - return CURLE_OUT_OF_MEMORY; - - result = Curl_auth_create_digest_http_message(data, userp, passwdp, request, - path, digest, &response, &len); - free(path); - if(result) - return result; - - *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n", - proxy ? "Proxy-" : "", - response); - free(response); - if(!*allocuserpwd) - return CURLE_OUT_OF_MEMORY; - - authp->done = TRUE; - - return CURLE_OK; -} - -void Curl_digest_cleanup(struct Curl_easy *data) -{ - Curl_auth_digest_cleanup(&data->state.digest); - Curl_auth_digest_cleanup(&data->state.proxydigest); -} - -#endif diff --git a/dep/cpr/opt/curl/lib/http_digest.h b/dep/cpr/opt/curl/lib/http_digest.h deleted file mode 100644 index fd225c7c1b3..00000000000 --- a/dep/cpr/opt/curl/lib/http_digest.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef HEADER_CURL_HTTP_DIGEST_H -#define HEADER_CURL_HTTP_DIGEST_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -/* this is for digest header input */ -CURLcode Curl_input_digest(struct connectdata *conn, - bool proxy, const char *header); - -/* this is for creating digest header output */ -CURLcode Curl_output_digest(struct connectdata *conn, - bool proxy, - const unsigned char *request, - const unsigned char *uripath); - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) -void Curl_digest_cleanup(struct Curl_easy *data); -#else -#define Curl_digest_cleanup(x) Curl_nop_stmt -#endif - -#endif /* HEADER_CURL_HTTP_DIGEST_H */ diff --git a/dep/cpr/opt/curl/lib/http_negotiate.c b/dep/cpr/opt/curl/lib/http_negotiate.c deleted file mode 100644 index 51375e81d13..00000000000 --- a/dep/cpr/opt/curl/lib/http_negotiate.c +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) - -#include "urldata.h" -#include "sendf.h" -#include "http_negotiate.h" -#include "vauth/vauth.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - size_t len; - - /* Point to the username, password, service and host */ - const char *userp; - const char *passwdp; - const char *service; - const char *host; - - /* Point to the correct struct with this */ - struct negotiatedata *neg_ctx; - - if(proxy) { - userp = conn->http_proxy.user; - passwdp = conn->http_proxy.passwd; - service = data->set.str[STRING_PROXY_SERVICE_NAME] ? - data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; - host = conn->http_proxy.host.name; - neg_ctx = &data->state.proxyneg; - } - else { - userp = conn->user; - passwdp = conn->passwd; - service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : "HTTP"; - host = conn->host.name; - neg_ctx = &data->state.negotiate; - } - - /* Not set means empty */ - if(!userp) - userp = ""; - - if(!passwdp) - passwdp = ""; - - /* Obtain the input token, if any */ - header += strlen("Negotiate"); - while(*header && ISSPACE(*header)) - header++; - - len = strlen(header); - if(!len) { - /* Is this the first call in a new negotiation? */ - if(neg_ctx->context) { - /* The server rejected our authentication and hasn't suppled any more - negotiation mechanisms */ - return CURLE_LOGIN_DENIED; - } - } - - /* Initilise the security context and decode our challenge */ - result = Curl_auth_decode_spnego_message(data, userp, passwdp, service, - host, header, neg_ctx); - - if(result) - Curl_auth_spnego_cleanup(neg_ctx); - - return result; -} - -CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) -{ - struct negotiatedata *neg_ctx = proxy ? &conn->data->state.proxyneg : - &conn->data->state.negotiate; - char *base64 = NULL; - size_t len = 0; - char *userp; - CURLcode result; - - result = Curl_auth_create_spnego_message(conn->data, neg_ctx, &base64, &len); - if(result) - return result; - - userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", - base64); - - if(proxy) { - Curl_safefree(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = userp; - } - else { - Curl_safefree(conn->allocptr.userpwd); - conn->allocptr.userpwd = userp; - } - - free(base64); - - return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; -} - -void Curl_cleanup_negotiate(struct Curl_easy *data) -{ - Curl_auth_spnego_cleanup(&data->state.negotiate); - Curl_auth_spnego_cleanup(&data->state.proxyneg); -} - -#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ diff --git a/dep/cpr/opt/curl/lib/http_negotiate.h b/dep/cpr/opt/curl/lib/http_negotiate.h deleted file mode 100644 index c64e5482518..00000000000 --- a/dep/cpr/opt/curl/lib/http_negotiate.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef HEADER_CURL_HTTP_NEGOTIATE_H -#define HEADER_CURL_HTTP_NEGOTIATE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#ifdef USE_SPNEGO - -/* this is for Negotiate header input */ -CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header); - -/* this is for creating Negotiate header output */ -CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy); - -void Curl_cleanup_negotiate(struct Curl_easy *data); - -#endif /* USE_SPNEGO */ - -#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */ diff --git a/dep/cpr/opt/curl/lib/http_ntlm.c b/dep/cpr/opt/curl/lib/http_ntlm.c deleted file mode 100644 index 0f1edcf65dc..00000000000 --- a/dep/cpr/opt/curl/lib/http_ntlm.c +++ /dev/null @@ -1,241 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) - -/* - * NTLM details: - * - * https://davenport.sourceforge.io/ntlm.html - * https://www.innovation.ch/java/ntlm.html - */ - -#define DEBUG_ME 0 - -#include "urldata.h" -#include "sendf.h" -#include "strcase.h" -#include "http_ntlm.h" -#include "curl_ntlm_core.h" -#include "curl_ntlm_wb.h" -#include "vauth/vauth.h" -#include "url.h" - -/* SSL backend-specific #if branches in this file must be kept in the order - documented in curl_ntlm_core. */ -#if defined(NTLM_NEEDS_NSS_INIT) -#include "vtls/nssg.h" -#elif defined(USE_WINDOWS_SSPI) -#include "curl_sspi.h" -#endif - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#if DEBUG_ME -# define DEBUG_OUT(x) x -#else -# define DEBUG_OUT(x) Curl_nop_stmt -#endif - -CURLcode Curl_input_ntlm(struct connectdata *conn, - bool proxy, /* if proxy or not */ - const char *header) /* rest of the www-authenticate: - header */ -{ - /* point to the correct struct with this */ - struct ntlmdata *ntlm; - CURLcode result = CURLE_OK; - - ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; - - if(checkprefix("NTLM", header)) { - header += strlen("NTLM"); - - while(*header && ISSPACE(*header)) - header++; - - if(*header) { - result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm); - if(result) - return result; - - ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ - } - else { - if(ntlm->state == NTLMSTATE_LAST) { - infof(conn->data, "NTLM auth restarted\n"); - Curl_http_ntlm_cleanup(conn); - } - else if(ntlm->state == NTLMSTATE_TYPE3) { - infof(conn->data, "NTLM handshake rejected\n"); - Curl_http_ntlm_cleanup(conn); - ntlm->state = NTLMSTATE_NONE; - return CURLE_REMOTE_ACCESS_DENIED; - } - else if(ntlm->state >= NTLMSTATE_TYPE1) { - infof(conn->data, "NTLM handshake failure (internal error)\n"); - return CURLE_REMOTE_ACCESS_DENIED; - } - - ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ - } - } - - return result; -} - -/* - * This is for creating ntlm header output - */ -CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) -{ - char *base64 = NULL; - size_t len = 0; - CURLcode result; - - /* point to the address of the pointer that holds the string to send to the - server, which is for a plain host or for a HTTP proxy */ - char **allocuserpwd; - - /* point to the name and password for this */ - const char *userp; - const char *passwdp; - - /* point to the correct struct with this */ - struct ntlmdata *ntlm; - struct auth *authp; - - DEBUGASSERT(conn); - DEBUGASSERT(conn->data); - -#if defined(NTLM_NEEDS_NSS_INIT) - if(CURLE_OK != Curl_nss_force_init(conn->data)) - return CURLE_OUT_OF_MEMORY; -#endif - - if(proxy) { - allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->http_proxy.user; - passwdp = conn->http_proxy.passwd; - ntlm = &conn->proxyntlm; - authp = &conn->data->state.authproxy; - } - else { - allocuserpwd = &conn->allocptr.userpwd; - userp = conn->user; - passwdp = conn->passwd; - ntlm = &conn->ntlm; - authp = &conn->data->state.authhost; - } - authp->done = FALSE; - - /* not set means empty */ - if(!userp) - userp = ""; - - if(!passwdp) - passwdp = ""; - -#ifdef USE_WINDOWS_SSPI - if(s_hSecDll == NULL) { - /* not thread safe and leaks - use curl_global_init() to avoid */ - CURLcode err = Curl_sspi_global_init(); - if(s_hSecDll == NULL) - return err; - } -#endif - - switch(ntlm->state) { - case NTLMSTATE_TYPE1: - default: /* for the weird cases we (re)start here */ - /* Create a type-1 message */ - result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp, - ntlm, &base64, &len); - if(result) - return result; - - if(base64) { - free(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy ? "Proxy-" : "", - base64); - free(base64); - if(!*allocuserpwd) - return CURLE_OUT_OF_MEMORY; - - DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); - } - break; - - case NTLMSTATE_TYPE2: - /* We already received the type-2 message, create a type-3 message */ - result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp, - ntlm, &base64, &len); - if(result) - return result; - - if(base64) { - free(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy ? "Proxy-" : "", - base64); - free(base64); - if(!*allocuserpwd) - return CURLE_OUT_OF_MEMORY; - - DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); - - ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ - authp->done = TRUE; - } - break; - - case NTLMSTATE_TYPE3: - /* connection is already authenticated, - * don't send a header in future requests */ - ntlm->state = NTLMSTATE_LAST; - /* fall-through */ - case NTLMSTATE_LAST: - Curl_safefree(*allocuserpwd); - authp->done = TRUE; - break; - } - - return CURLE_OK; -} - -void Curl_http_ntlm_cleanup(struct connectdata *conn) -{ - Curl_auth_ntlm_cleanup(&conn->ntlm); - Curl_auth_ntlm_cleanup(&conn->proxyntlm); - -#if defined(NTLM_WB_ENABLED) - Curl_ntlm_wb_cleanup(conn); -#endif -} - -#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ diff --git a/dep/cpr/opt/curl/lib/http_ntlm.h b/dep/cpr/opt/curl/lib/http_ntlm.h deleted file mode 100644 index d186bbe3707..00000000000 --- a/dep/cpr/opt/curl/lib/http_ntlm.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef HEADER_CURL_NTLM_H -#define HEADER_CURL_NTLM_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) - -/* this is for ntlm header input */ -CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy, - const char *header); - -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); - -void Curl_http_ntlm_cleanup(struct connectdata *conn); - -#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ - -#endif /* HEADER_CURL_NTLM_H */ diff --git a/dep/cpr/opt/curl/lib/http_proxy.c b/dep/cpr/opt/curl/lib/http_proxy.c deleted file mode 100644 index dff9d230a08..00000000000 --- a/dep/cpr/opt/curl/lib/http_proxy.c +++ /dev/null @@ -1,686 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "http_proxy.h" - -#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) - -#include -#include "sendf.h" -#include "http.h" -#include "url.h" -#include "select.h" -#include "progress.h" -#include "non-ascii.h" -#include "connect.h" -#include "curlx.h" -#include "vtls/vtls.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Perform SSL initialization for HTTPS proxy. Sets - * proxy_ssl_connected connection bit when complete. Can be - * called multiple times. - */ -static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex) -{ -#ifdef USE_SSL - CURLcode result = CURLE_OK; - DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS); - if(!conn->bits.proxy_ssl_connected[sockindex]) { - /* perform SSL initialization for this socket */ - result = - Curl_ssl_connect_nonblocking(conn, sockindex, - &conn->bits.proxy_ssl_connected[sockindex]); - if(result) - conn->bits.close = TRUE; /* a failed connection is marked for closure to - prevent (bad) re-use or similar */ - } - return result; -#else - (void) conn; - (void) sockindex; - return CURLE_NOT_BUILT_IN; -#endif -} - -CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) -{ - if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) { - const CURLcode result = https_proxy_connect(conn, sockindex); - if(result) - return result; - if(!conn->bits.proxy_ssl_connected[sockindex]) - return result; /* wait for HTTPS proxy SSL initialization to complete */ - } - - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { -#ifndef CURL_DISABLE_PROXY - /* for [protocol] tunneled through HTTP proxy */ - struct HTTP http_proxy; - void *prot_save; - const char *hostname; - int remote_port; - CURLcode result; - - /* BLOCKING */ - /* We want "seamless" operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the - * member conn->proto.http; we want [protocol] through HTTP and we have - * to change the member temporarily for connecting to the HTTP - * proxy. After Curl_proxyCONNECT we have to set back the member to the - * original pointer - * - * This function might be called several times in the multi interface case - * if the proxy's CONNECT response is not instant. - */ - prot_save = conn->data->req.protop; - memset(&http_proxy, 0, sizeof(http_proxy)); - conn->data->req.protop = &http_proxy; - connkeep(conn, "HTTP proxy CONNECT"); - - /* for the secondary socket (FTP), use the "connect to host" - * but ignore the "connect to port" (use the secondary port) - */ - - if(conn->bits.conn_to_host) - hostname = conn->conn_to_host.name; - else if(sockindex == SECONDARYSOCKET) - hostname = conn->secondaryhostname; - else - hostname = conn->host.name; - - if(sockindex == SECONDARYSOCKET) - remote_port = conn->secondary_port; - else if(conn->bits.conn_to_port) - remote_port = conn->conn_to_port; - else - remote_port = conn->remote_port; - result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port); - conn->data->req.protop = prot_save; - if(CURLE_OK != result) - return result; - Curl_safefree(conn->allocptr.proxyuserpwd); -#else - return CURLE_NOT_BUILT_IN; -#endif - } - /* no HTTP tunnel proxy, just return */ - return CURLE_OK; -} - -bool Curl_connect_complete(struct connectdata *conn) -{ - return !conn->connect_state || - (conn->connect_state->tunnel_state == TUNNEL_COMPLETE); -} - -bool Curl_connect_ongoing(struct connectdata *conn) -{ - return conn->connect_state && - (conn->connect_state->tunnel_state != TUNNEL_COMPLETE); -} - -static CURLcode connect_init(struct connectdata *conn, bool reinit) -{ - struct http_connect_state *s; - if(!reinit) { - DEBUGASSERT(!conn->connect_state); - s = calloc(1, sizeof(struct http_connect_state)); - if(!s) - return CURLE_OUT_OF_MEMORY; - infof(conn->data, "allocate connect buffer!\n"); - conn->connect_state = s; - } - else { - DEBUGASSERT(conn->connect_state); - s = conn->connect_state; - } - s->tunnel_state = TUNNEL_INIT; - s->keepon = TRUE; - s->line_start = s->connect_buffer; - s->ptr = s->line_start; - s->cl = 0; - return CURLE_OK; -} - -static void connect_done(struct connectdata *conn) -{ - struct http_connect_state *s = conn->connect_state; - s->tunnel_state = TUNNEL_COMPLETE; - infof(conn->data, "CONNECT phase completed!\n"); -} - -static CURLcode CONNECT(struct connectdata *conn, - int sockindex, - const char *hostname, - int remote_port) -{ - int subversion = 0; - struct Curl_easy *data = conn->data; - struct SingleRequest *k = &data->req; - CURLcode result; - curl_socket_t tunnelsocket = conn->sock[sockindex]; - bool closeConnection = FALSE; - time_t check; - struct http_connect_state *s = conn->connect_state; - -#define SELECT_OK 0 -#define SELECT_ERROR 1 -#define SELECT_TIMEOUT 2 - - if(Curl_connect_complete(conn)) - return CURLE_OK; /* CONNECT is already completed */ - - conn->bits.proxy_connect_closed = FALSE; - - do { - if(TUNNEL_INIT == s->tunnel_state) { - /* BEGIN CONNECT PHASE */ - char *host_port; - Curl_send_buffer *req_buffer; - - infof(data, "Establish HTTP proxy tunnel to %s:%hu\n", - hostname, remote_port); - - /* This only happens if we've looped here due to authentication - reasons, and we don't really use the newly cloned URL here - then. Just free() it. */ - free(data->req.newurl); - data->req.newurl = NULL; - - /* initialize a dynamic send-buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; - - host_port = aprintf("%s:%hu", hostname, remote_port); - if(!host_port) { - Curl_add_buffer_free(req_buffer); - return CURLE_OUT_OF_MEMORY; - } - - /* Setup the proxy-authorization header, if any */ - result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE); - - free(host_port); - - if(!result) { - char *host = NULL; - const char *proxyconn = ""; - const char *useragent = ""; - const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? - "1.0" : "1.1"; - bool ipv6_ip = conn->bits.ipv6_ip; - char *hostheader; - - /* the hostname may be different */ - if(hostname != conn->host.name) - ipv6_ip = (strchr(hostname, ':') != NULL); - hostheader = /* host:port with IPv6 support */ - aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", - remote_port); - if(!hostheader) { - Curl_add_buffer_free(req_buffer); - return CURLE_OUT_OF_MEMORY; - } - - if(!Curl_checkProxyheaders(conn, "Host:")) { - host = aprintf("Host: %s\r\n", hostheader); - if(!host) { - free(hostheader); - Curl_add_buffer_free(req_buffer); - return CURLE_OUT_OF_MEMORY; - } - } - if(!Curl_checkProxyheaders(conn, "Proxy-Connection:")) - proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - - if(!Curl_checkProxyheaders(conn, "User-Agent:") && - data->set.str[STRING_USERAGENT]) - useragent = conn->allocptr.uagent; - - result = - Curl_add_bufferf(req_buffer, - "CONNECT %s HTTP/%s\r\n" - "%s" /* Host: */ - "%s" /* Proxy-Authorization */ - "%s" /* User-Agent */ - "%s", /* Proxy-Connection */ - hostheader, - http, - host?host:"", - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - useragent, - proxyconn); - - if(host) - free(host); - free(hostheader); - - if(!result) - result = Curl_add_custom_headers(conn, TRUE, req_buffer); - - if(!result) - /* CRLF terminate the request */ - result = Curl_add_bufferf(req_buffer, "\r\n"); - - if(!result) { - /* Send the connect request to the proxy */ - /* BLOCKING */ - result = - Curl_add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, sockindex); - } - req_buffer = NULL; - if(result) - failf(data, "Failed sending CONNECT to proxy"); - } - - Curl_add_buffer_free(req_buffer); - if(result) - return result; - - s->tunnel_state = TUNNEL_CONNECT; - s->perline = 0; - } /* END CONNECT PHASE */ - - check = Curl_timeleft(data, NULL, TRUE); - if(check <= 0) { - failf(data, "Proxy CONNECT aborted due to timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(!Curl_conn_data_pending(conn, sockindex)) - /* return so we'll be called again polling-style */ - return CURLE_OK; - - /* at this point, the tunnel_connecting phase is over. */ - - { /* READING RESPONSE PHASE */ - int error = SELECT_OK; - - while(s->keepon && !error) { - ssize_t gotbytes; - - /* make sure we have space to read more data */ - if(s->ptr >= &s->connect_buffer[CONNECT_BUFFER_SIZE]) { - failf(data, "CONNECT response too large!"); - return CURLE_RECV_ERROR; - } - - /* Read one byte at a time to avoid a race condition. Wait at most one - second before looping to ensure continuous pgrsUpdates. */ - result = Curl_read(conn, tunnelsocket, s->ptr, 1, &gotbytes); - if(result == CURLE_AGAIN) - /* socket buffer drained, return */ - return CURLE_OK; - - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - - if(result) { - s->keepon = FALSE; - break; - } - else if(gotbytes <= 0) { - if(data->set.proxyauth && data->state.authproxy.avail) { - /* proxy auth was requested and there was proxy auth available, - then deem this as "mere" proxy disconnect */ - conn->bits.proxy_connect_closed = TRUE; - infof(data, "Proxy CONNECT connection closed\n"); - } - else { - error = SELECT_ERROR; - failf(data, "Proxy CONNECT aborted"); - } - s->keepon = FALSE; - break; - } - - - if(s->keepon > TRUE) { - /* This means we are currently ignoring a response-body */ - - s->ptr = s->connect_buffer; - if(s->cl) { - /* A Content-Length based body: simply count down the counter - and make sure to break out of the loop when we're done! */ - s->cl--; - if(s->cl <= 0) { - s->keepon = FALSE; - s->tunnel_state = TUNNEL_COMPLETE; - break; - } - } - else { - /* chunked-encoded body, so we need to do the chunked dance - properly to know when the end of the body is reached */ - CHUNKcode r; - ssize_t tookcareof = 0; - - /* now parse the chunked piece of data so that we can - properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, s->ptr, 1, &tookcareof); - if(r == CHUNKE_STOP) { - /* we're done reading chunks! */ - infof(data, "chunk reading DONE\n"); - s->keepon = FALSE; - /* we did the full CONNECT treatment, go COMPLETE */ - s->tunnel_state = TUNNEL_COMPLETE; - } - } - continue; - } - - s->perline++; /* amount of bytes in this line so far */ - - /* if this is not the end of a header line then continue */ - if(*s->ptr != 0x0a) { - s->ptr++; - continue; - } - - /* convert from the network encoding */ - result = Curl_convert_from_network(data, s->line_start, - (size_t)s->perline); - /* Curl_convert_from_network calls failf if unsuccessful */ - if(result) - return result; - - /* output debug if that is requested */ - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - s->line_start, (size_t)s->perline, conn); - - if(!data->set.suppress_connect_headers) { - /* send the header to the callback */ - int writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; - - result = Curl_client_write(conn, writetype, - s->line_start, s->perline); - if(result) - return result; - } - - data->info.header_size += (long)s->perline; - data->req.headerbytecount += (long)s->perline; - - /* Newlines are CRLF, so the CR is ignored as the line isn't - really terminated until the LF comes. Treat a following CR - as end-of-headers as well.*/ - - if(('\r' == s->line_start[0]) || - ('\n' == s->line_start[0])) { - /* end of response-headers from the proxy */ - s->ptr = s->connect_buffer; - if((407 == k->httpcode) && !data->state.authproblem) { - /* If we get a 407 response code with content length - when we have no auth problem, we must ignore the - whole response-body */ - s->keepon = 2; - - if(s->cl) { - infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T - " bytes of response-body\n", s->cl); - } - else if(s->chunked_encoding) { - CHUNKcode r; - - infof(data, "Ignore chunked response-body\n"); - - /* We set ignorebody true here since the chunked - decoder function will acknowledge that. Pay - attention so that this is cleared again when this - function returns! */ - k->ignorebody = TRUE; - - if(s->line_start[1] == '\n') { - /* this can only be a LF if the letter at index 0 - was a CR */ - s->line_start++; - } - - /* now parse the chunked piece of data so that we can - properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, s->line_start + 1, 1, &gotbytes); - if(r == CHUNKE_STOP) { - /* we're done reading chunks! */ - infof(data, "chunk reading DONE\n"); - s->keepon = FALSE; - /* we did the full CONNECT treatment, go to COMPLETE */ - s->tunnel_state = TUNNEL_COMPLETE; - } - } - else { - /* without content-length or chunked encoding, we - can't keep the connection alive since the close is - the end signal so we bail out at once instead */ - s->keepon = FALSE; - } - } - else - s->keepon = FALSE; - if(!s->cl) - /* we did the full CONNECT treatment, go to COMPLETE */ - s->tunnel_state = TUNNEL_COMPLETE; - continue; - } - - s->line_start[s->perline] = 0; /* zero terminate the buffer */ - if((checkprefix("WWW-Authenticate:", s->line_start) && - (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", s->line_start) && - (407 == k->httpcode))) { - - bool proxy = (k->httpcode == 407) ? TRUE : FALSE; - char *auth = Curl_copy_header_value(s->line_start); - if(!auth) - return CURLE_OUT_OF_MEMORY; - - result = Curl_http_input_auth(conn, proxy, auth); - - free(auth); - - if(result) - return result; - } - else if(checkprefix("Content-Length:", s->line_start)) { - if(k->httpcode/100 == 2) { - /* A client MUST ignore any Content-Length or Transfer-Encoding - header fields received in a successful response to CONNECT. - "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ - infof(data, "Ignoring Content-Length in CONNECT %03d response\n", - k->httpcode); - } - else { - (void)curlx_strtoofft(s->line_start + - strlen("Content-Length:"), NULL, 10, &s->cl); - } - } - else if(Curl_compareheader(s->line_start, "Connection:", "close")) - closeConnection = TRUE; - else if(checkprefix("Transfer-Encoding:", s->line_start)) { - if(k->httpcode/100 == 2) { - /* A client MUST ignore any Content-Length or Transfer-Encoding - header fields received in a successful response to CONNECT. - "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ - infof(data, "Ignoring Transfer-Encoding in " - "CONNECT %03d response\n", k->httpcode); - } - else if(Curl_compareheader(s->line_start, - "Transfer-Encoding:", "chunked")) { - infof(data, "CONNECT responded chunked\n"); - s->chunked_encoding = TRUE; - /* init our chunky engine */ - Curl_httpchunk_init(conn); - } - } - else if(Curl_compareheader(s->line_start, - "Proxy-Connection:", "close")) - closeConnection = TRUE; - else if(2 == sscanf(s->line_start, "HTTP/1.%d %d", - &subversion, - &k->httpcode)) { - /* store the HTTP code from the proxy */ - data->info.httpproxycode = k->httpcode; - } - - s->perline = 0; /* line starts over here */ - s->ptr = s->connect_buffer; - s->line_start = s->ptr; - } /* while there's buffer left and loop is requested */ - - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - - if(error) - return CURLE_RECV_ERROR; - - if(data->info.httpproxycode/100 != 2) { - /* Deal with the possibly already received authenticate - headers. 'newurl' is set to a new URL if we must loop. */ - result = Curl_http_auth_act(conn); - if(result) - return result; - - if(conn->bits.close) - /* the connection has been marked for closure, most likely in the - Curl_http_auth_act() function and thus we can kill it at once - below */ - closeConnection = TRUE; - } - - if(closeConnection && data->req.newurl) { - /* Connection closed by server. Don't use it anymore */ - Curl_closesocket(conn, conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - break; - } - } /* END READING RESPONSE PHASE */ - - /* If we are supposed to continue and request a new URL, which basically - * means the HTTP authentication is still going on so if the tunnel - * is complete we start over in INIT state */ - if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) { - connect_init(conn, TRUE); /* reinit */ - } - - } while(data->req.newurl); - - if(data->info.httpproxycode/100 != 2) { - if(closeConnection && data->req.newurl) { - conn->bits.proxy_connect_closed = TRUE; - infof(data, "Connect me again please\n"); - connect_done(conn); - } - else { - free(data->req.newurl); - data->req.newurl = NULL; - /* failure, close this connection to avoid re-use */ - streamclose(conn, "proxy CONNECT failure"); - Curl_closesocket(conn, conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - } - - /* to back to init state */ - s->tunnel_state = TUNNEL_INIT; - - if(conn->bits.proxy_connect_closed) - /* this is not an error, just part of the connection negotiation */ - return CURLE_OK; - failf(data, "Received HTTP code %d from proxy after CONNECT", - data->req.httpcode); - return CURLE_RECV_ERROR; - } - - s->tunnel_state = TUNNEL_COMPLETE; - - /* If a proxy-authorization header was used for the proxy, then we should - make sure that it isn't accidentally used for the document request - after we've connected. So let's free and clear it here. */ - Curl_safefree(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = NULL; - - data->state.authproxy.done = TRUE; - - infof(data, "Proxy replied %d to CONNECT request\n", - data->info.httpproxycode); - data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */ - conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the - document request */ - return CURLE_OK; -} - -void Curl_connect_free(struct Curl_easy *data) -{ - struct connectdata *conn = data->easy_conn; - struct http_connect_state *s = conn->connect_state; - if(s) { - free(s); - conn->connect_state = NULL; - } -} - -/* - * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This - * function will issue the necessary commands to get a seamless tunnel through - * this proxy. After that, the socket can be used just as a normal socket. - */ - -CURLcode Curl_proxyCONNECT(struct connectdata *conn, - int sockindex, - const char *hostname, - int remote_port) -{ - CURLcode result; - if(!conn->connect_state) { - result = connect_init(conn, FALSE); - if(result) - return result; - } - result = CONNECT(conn, sockindex, hostname, remote_port); - - if(result || Curl_connect_complete(conn)) - connect_done(conn); - - return result; -} - -#else -void Curl_connect_free(struct Curl_easy *data) -{ - (void)data; -} - -#endif /* CURL_DISABLE_PROXY */ diff --git a/dep/cpr/opt/curl/lib/http_proxy.h b/dep/cpr/opt/curl/lib/http_proxy.h deleted file mode 100644 index e19fa859a06..00000000000 --- a/dep/cpr/opt/curl/lib/http_proxy.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef HEADER_CURL_HTTP_PROXY_H -#define HEADER_CURL_HTTP_PROXY_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" -#include "urldata.h" - -#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) -/* ftp can use this as well */ -CURLcode Curl_proxyCONNECT(struct connectdata *conn, - int tunnelsocket, - const char *hostname, int remote_port); - -/* Default proxy timeout in milliseconds */ -#define PROXY_TIMEOUT (3600*1000) - -CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex); - -bool Curl_connect_complete(struct connectdata *conn); -bool Curl_connect_ongoing(struct connectdata *conn); - -#else -#define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN -#define Curl_proxy_connect(x,y) CURLE_OK -#define Curl_connect_complete(x) CURLE_OK -#define Curl_connect_ongoing(x) FALSE -#endif - -void Curl_connect_free(struct Curl_easy *data); - -#endif /* HEADER_CURL_HTTP_PROXY_H */ diff --git a/dep/cpr/opt/curl/lib/idn_win32.c b/dep/cpr/opt/curl/lib/idn_win32.c deleted file mode 100644 index 8dc300b36d0..00000000000 --- a/dep/cpr/opt/curl/lib/idn_win32.c +++ /dev/null @@ -1,111 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - - /* - * IDN conversions using Windows kernel32 and normaliz libraries. - */ - -#include "curl_setup.h" - -#ifdef USE_WIN32_IDN - -#include "curl_multibyte.h" -#include "curl_memory.h" -#include "warnless.h" - - /* The last #include file should be: */ -#include "memdebug.h" - -#ifdef WANT_IDN_PROTOTYPES -# if defined(_SAL_VERSION) -WINNORMALIZEAPI int WINAPI -IdnToAscii(_In_ DWORD dwFlags, - _In_reads_(cchUnicodeChar) LPCWSTR lpUnicodeCharStr, - _In_ int cchUnicodeChar, - _Out_writes_opt_(cchASCIIChar) LPWSTR lpASCIICharStr, - _In_ int cchASCIIChar); -WINNORMALIZEAPI int WINAPI -IdnToUnicode(_In_ DWORD dwFlags, - _In_reads_(cchASCIIChar) LPCWSTR lpASCIICharStr, - _In_ int cchASCIIChar, - _Out_writes_opt_(cchUnicodeChar) LPWSTR lpUnicodeCharStr, - _In_ int cchUnicodeChar); -# else -WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags, - const WCHAR *lpUnicodeCharStr, - int cchUnicodeChar, - WCHAR *lpASCIICharStr, - int cchASCIIChar); -WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, - const WCHAR *lpASCIICharStr, - int cchASCIIChar, - WCHAR *lpUnicodeCharStr, - int cchUnicodeChar); -# endif -#endif - -#define IDN_MAX_LENGTH 255 - -bool curl_win32_idn_to_ascii(const char *in, char **out); -bool curl_win32_ascii_to_idn(const char *in, char **out); - -bool curl_win32_idn_to_ascii(const char *in, char **out) -{ - bool success = FALSE; - - wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); - if(in_w) { - wchar_t punycode[IDN_MAX_LENGTH]; - int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH); - free(in_w); - if(chars) { - *out = Curl_convert_wchar_to_UTF8(punycode); - if(*out) - success = TRUE; - } - } - - return success; -} - -bool curl_win32_ascii_to_idn(const char *in, char **out) -{ - bool success = FALSE; - - wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); - if(in_w) { - size_t in_len = wcslen(in_w) + 1; - wchar_t unicode[IDN_MAX_LENGTH]; - int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len), - unicode, IDN_MAX_LENGTH); - free(in_w); - if(chars) { - *out = Curl_convert_wchar_to_UTF8(unicode); - if(*out) - success = TRUE; - } - } - - return success; -} - -#endif /* USE_WIN32_IDN */ diff --git a/dep/cpr/opt/curl/lib/if2ip.c b/dep/cpr/opt/curl/lib/if2ip.c deleted file mode 100644 index ce38ea117b7..00000000000 --- a/dep/cpr/opt/curl/lib/if2ip.c +++ /dev/null @@ -1,274 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif -#ifdef HAVE_NET_IF_H -# include -#endif -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#ifdef HAVE_NETDB_H -# include -#endif -#ifdef HAVE_SYS_SOCKIO_H -# include -#endif -#ifdef HAVE_IFADDRS_H -# include -#endif -#ifdef HAVE_STROPTS_H -# include -#endif -#ifdef __VMS -# include -#endif - -#include "inet_ntop.h" -#include "strcase.h" -#include "if2ip.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* ------------------------------------------------------------------ */ - -/* Return the scope of the given address. */ -unsigned int Curl_ipv6_scope(const struct sockaddr *sa) -{ -#ifndef ENABLE_IPV6 - (void) sa; -#else - if(sa->sa_family == AF_INET6) { - const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa; - const unsigned char *b = sa6->sin6_addr.s6_addr; - unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); - - if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */ - return IPV6_SCOPE_UNIQUELOCAL; - switch(w & 0xFFC0) { - case 0xFE80: - return IPV6_SCOPE_LINKLOCAL; - case 0xFEC0: - return IPV6_SCOPE_SITELOCAL; - case 0x0000: - w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] | - b[10] | b[11] | b[12] | b[13] | b[14]; - if(w || b[15] != 0x01) - break; - return IPV6_SCOPE_NODELOCAL; - default: - break; - } - } -#endif - - return IPV6_SCOPE_GLOBAL; -} - - -#if defined(HAVE_GETIFADDRS) - -bool Curl_if_is_interface_name(const char *interf) -{ - bool result = FALSE; - - struct ifaddrs *iface, *head; - - if(getifaddrs(&head) >= 0) { - for(iface = head; iface != NULL; iface = iface->ifa_next) { - if(strcasecompare(iface->ifa_name, interf)) { - result = TRUE; - break; - } - } - freeifaddrs(head); - } - return result; -} - -if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, - unsigned int remote_scope_id, const char *interf, - char *buf, int buf_size) -{ - struct ifaddrs *iface, *head; - if2ip_result_t res = IF2IP_NOT_FOUND; - -#ifndef ENABLE_IPV6 - (void) remote_scope; -#endif - -#if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \ - !defined(ENABLE_IPV6) - (void) remote_scope_id; -#endif - - if(getifaddrs(&head) >= 0) { - for(iface = head; iface != NULL; iface = iface->ifa_next) { - if(iface->ifa_addr != NULL) { - if(iface->ifa_addr->sa_family == af) { - if(strcasecompare(iface->ifa_name, interf)) { - void *addr; - char *ip; - char scope[12] = ""; - char ipstr[64]; -#ifdef ENABLE_IPV6 - if(af == AF_INET6) { - unsigned int scopeid = 0; - unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); - - if(ifscope != remote_scope) { - /* We are interested only in interface addresses whose - scope matches the remote address we want to - connect to: global for global, link-local for - link-local, etc... */ - if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; - continue; - } - - addr = - &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr; -#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID - /* Include the scope of this interface as part of the address */ - scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr) - ->sin6_scope_id; - - /* If given, scope id should match. */ - if(remote_scope_id && scopeid != remote_scope_id) { - if(res == IF2IP_NOT_FOUND) - res = IF2IP_AF_NOT_SUPPORTED; - - continue; - } -#endif - if(scopeid) - snprintf(scope, sizeof(scope), "%%%u", scopeid); - } - else -#endif - addr = - &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; - res = IF2IP_FOUND; - ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); - snprintf(buf, buf_size, "%s%s", ip, scope); - break; - } - } - else if((res == IF2IP_NOT_FOUND) && - strcasecompare(iface->ifa_name, interf)) { - res = IF2IP_AF_NOT_SUPPORTED; - } - } - } - - freeifaddrs(head); - } - - return res; -} - -#elif defined(HAVE_IOCTL_SIOCGIFADDR) - -bool Curl_if_is_interface_name(const char *interf) -{ - /* This is here just to support the old interfaces */ - char buf[256]; - - return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) == - IF2IP_NOT_FOUND) ? FALSE : TRUE; -} - -if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, - unsigned int remote_scope_id, const char *interf, - char *buf, int buf_size) -{ - struct ifreq req; - struct in_addr in; - struct sockaddr_in *s; - curl_socket_t dummy; - size_t len; - - (void)remote_scope; - (void)remote_scope_id; - - if(!interf || (af != AF_INET)) - return IF2IP_NOT_FOUND; - - len = strlen(interf); - if(len >= sizeof(req.ifr_name)) - return IF2IP_NOT_FOUND; - - dummy = socket(AF_INET, SOCK_STREAM, 0); - if(CURL_SOCKET_BAD == dummy) - return IF2IP_NOT_FOUND; - - memset(&req, 0, sizeof(req)); - memcpy(req.ifr_name, interf, len + 1); - req.ifr_addr.sa_family = AF_INET; - - if(ioctl(dummy, SIOCGIFADDR, &req) < 0) { - sclose(dummy); - /* With SIOCGIFADDR, we cannot tell the difference between an interface - that does not exist and an interface that has no address of the - correct family. Assume the interface does not exist */ - return IF2IP_NOT_FOUND; - } - - s = (struct sockaddr_in *)(void *)&req.ifr_addr; - memcpy(&in, &s->sin_addr, sizeof(in)); - Curl_inet_ntop(s->sin_family, &in, buf, buf_size); - - sclose(dummy); - return IF2IP_FOUND; -} - -#else - -bool Curl_if_is_interface_name(const char *interf) -{ - (void) interf; - - return FALSE; -} - -if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, - unsigned int remote_scope_id, const char *interf, - char *buf, int buf_size) -{ - (void) af; - (void) remote_scope; - (void) remote_scope_id; - (void) interf; - (void) buf; - (void) buf_size; - return IF2IP_NOT_FOUND; -} - -#endif diff --git a/dep/cpr/opt/curl/lib/if2ip.h b/dep/cpr/opt/curl/lib/if2ip.h deleted file mode 100644 index a90e662164d..00000000000 --- a/dep/cpr/opt/curl/lib/if2ip.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef HEADER_CURL_IF2IP_H -#define HEADER_CURL_IF2IP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -/* IPv6 address scopes. */ -#define IPV6_SCOPE_GLOBAL 0 /* Global scope. */ -#define IPV6_SCOPE_LINKLOCAL 1 /* Link-local scope. */ -#define IPV6_SCOPE_SITELOCAL 2 /* Site-local scope (deprecated). */ -#define IPV6_SCOPE_UNIQUELOCAL 3 /* Unique local */ -#define IPV6_SCOPE_NODELOCAL 4 /* Loopback. */ - -unsigned int Curl_ipv6_scope(const struct sockaddr *sa); - -bool Curl_if_is_interface_name(const char *interf); - -typedef enum { - IF2IP_NOT_FOUND = 0, /* Interface not found */ - IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */ - IF2IP_FOUND = 2 /* The address has been stored in "buf" */ -} if2ip_result_t; - -if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, - unsigned int remote_scope_id, const char *interf, - char *buf, int buf_size); - -#ifdef __INTERIX - -/* Nedelcho Stanev's work-around for SFU 3.0 */ -struct ifreq { -#define IFNAMSIZ 16 -#define IFHWADDRLEN 6 - union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - int ifru_metric; - int ifru_mtu; - } ifr_ifru; -}; - -/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the - C code. */ - -#define ifr_name ifr_ifrn.ifrn_name /* interface name */ -#define ifr_addr ifr_ifru.ifru_addr /* address */ -#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ -#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ -#define ifr_flags ifr_ifru.ifru_flags /* flags */ -#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ -#define ifr_metric ifr_ifru.ifru_metric /* metric */ -#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ - -#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ - -#endif /* __INTERIX */ - -#endif /* HEADER_CURL_IF2IP_H */ diff --git a/dep/cpr/opt/curl/lib/imap.c b/dep/cpr/opt/curl/lib/imap.c deleted file mode 100644 index 954d18f3786..00000000000 --- a/dep/cpr/opt/curl/lib/imap.c +++ /dev/null @@ -1,2093 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC2195 CRAM-MD5 authentication - * RFC2595 Using TLS with IMAP, POP3 and ACAP - * RFC2831 DIGEST-MD5 authentication - * RFC3501 IMAPv4 protocol - * RFC4422 Simple Authentication and Security Layer (SASL) - * RFC4616 PLAIN authentication - * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism - * RFC4959 IMAP Extension for SASL Initial Client Response - * RFC5092 IMAP URL Scheme - * RFC6749 OAuth 2.0 Authorization Framework - * Draft LOGIN SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_IMAP - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_UTSNAME_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "progress.h" -#include "transfer.h" -#include "escape.h" -#include "http.h" /* for HTTP proxy tunnel stuff */ -#include "socks.h" -#include "imap.h" -#include "mime.h" -#include "strtoofft.h" -#include "strcase.h" -#include "vtls/vtls.h" -#include "connect.h" -#include "strerror.h" -#include "select.h" -#include "multiif.h" -#include "url.h" -#include "strcase.h" -#include "curl_sasl.h" -#include "warnless.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Local API functions */ -static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done); -static CURLcode imap_do(struct connectdata *conn, bool *done); -static CURLcode imap_done(struct connectdata *conn, CURLcode status, - bool premature); -static CURLcode imap_connect(struct connectdata *conn, bool *done); -static CURLcode imap_disconnect(struct connectdata *conn, bool dead); -static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done); -static int imap_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks); -static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done); -static CURLcode imap_setup_connection(struct connectdata *conn); -static char *imap_atom(const char *str, bool escape_only); -static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...); -static CURLcode imap_parse_url_options(struct connectdata *conn); -static CURLcode imap_parse_url_path(struct connectdata *conn); -static CURLcode imap_parse_custom_request(struct connectdata *conn); -static CURLcode imap_perform_authenticate(struct connectdata *conn, - const char *mech, - const char *initresp); -static CURLcode imap_continue_authenticate(struct connectdata *conn, - const char *resp); -static void imap_get_message(char *buffer, char **outptr); - -/* - * IMAP protocol handler. - */ - -const struct Curl_handler Curl_handler_imap = { - "IMAP", /* scheme */ - imap_setup_connection, /* setup_connection */ - imap_do, /* do_it */ - imap_done, /* done */ - ZERO_NULL, /* do_more */ - imap_connect, /* connect_it */ - imap_multi_statemach, /* connecting */ - imap_doing, /* doing */ - imap_getsock, /* proto_getsock */ - imap_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - imap_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_IMAP, /* defport */ - CURLPROTO_IMAP, /* protocol */ - PROTOPT_CLOSEACTION| /* flags */ - PROTOPT_URLOPTIONS -}; - -#ifdef USE_SSL -/* - * IMAPS protocol handler. - */ - -const struct Curl_handler Curl_handler_imaps = { - "IMAPS", /* scheme */ - imap_setup_connection, /* setup_connection */ - imap_do, /* do_it */ - imap_done, /* done */ - ZERO_NULL, /* do_more */ - imap_connect, /* connect_it */ - imap_multi_statemach, /* connecting */ - imap_doing, /* doing */ - imap_getsock, /* proto_getsock */ - imap_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - imap_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_IMAPS, /* defport */ - CURLPROTO_IMAPS, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */ -}; -#endif - -#define IMAP_RESP_OK 1 -#define IMAP_RESP_NOT_OK 2 -#define IMAP_RESP_PREAUTH 3 - -/* SASL parameters for the imap protocol */ -static const struct SASLproto saslimap = { - "imap", /* The service name */ - '+', /* Code received when continuation is expected */ - IMAP_RESP_OK, /* Code to receive upon authentication success */ - 0, /* Maximum initial response length (no max) */ - imap_perform_authenticate, /* Send authentication command */ - imap_continue_authenticate, /* Send authentication continuation */ - imap_get_message /* Get SASL response message */ -}; - - -#ifdef USE_SSL -static void imap_to_imaps(struct connectdata *conn) -{ - /* Change the connection handler */ - conn->handler = &Curl_handler_imaps; - - /* Set the connection's upgraded to TLS flag */ - conn->tls_upgraded = TRUE; -} -#else -#define imap_to_imaps(x) Curl_nop_stmt -#endif - -/*********************************************************************** - * - * imap_matchresp() - * - * Determines whether the untagged response is related to the specified - * command by checking if it is in format "* ..." or - * "* ...". - * - * The "* " marker is assumed to have already been checked by the caller. - */ -static bool imap_matchresp(const char *line, size_t len, const char *cmd) -{ - const char *end = line + len; - size_t cmd_len = strlen(cmd); - - /* Skip the untagged response marker */ - line += 2; - - /* Do we have a number after the marker? */ - if(line < end && ISDIGIT(*line)) { - /* Skip the number */ - do - line++; - while(line < end && ISDIGIT(*line)); - - /* Do we have the space character? */ - if(line == end || *line != ' ') - return FALSE; - - line++; - } - - /* Does the command name match and is it followed by a space character or at - the end of line? */ - if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) && - (line[cmd_len] == ' ' || line + cmd_len + 2 == end)) - return TRUE; - - return FALSE; -} - -/*********************************************************************** - * - * imap_endofresp() - * - * Checks whether the given string is a valid tagged, untagged or continuation - * response which can be processed by the response handler. - */ -static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, - int *resp) -{ - struct IMAP *imap = conn->data->req.protop; - struct imap_conn *imapc = &conn->proto.imapc; - const char *id = imapc->resptag; - size_t id_len = strlen(id); - - /* Do we have a tagged command response? */ - if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') { - line += id_len + 1; - len -= id_len + 1; - - if(len >= 2 && !memcmp(line, "OK", 2)) - *resp = IMAP_RESP_OK; - else if(len >= 7 && !memcmp(line, "PREAUTH", 7)) - *resp = IMAP_RESP_PREAUTH; - else - *resp = IMAP_RESP_NOT_OK; - - return TRUE; - } - - /* Do we have an untagged command response? */ - if(len >= 2 && !memcmp("* ", line, 2)) { - switch(imapc->state) { - /* States which are interested in untagged responses */ - case IMAP_CAPABILITY: - if(!imap_matchresp(line, len, "CAPABILITY")) - return FALSE; - break; - - case IMAP_LIST: - if((!imap->custom && !imap_matchresp(line, len, "LIST")) || - (imap->custom && !imap_matchresp(line, len, imap->custom) && - (strcmp(imap->custom, "STORE") || - !imap_matchresp(line, len, "FETCH")) && - strcmp(imap->custom, "SELECT") && - strcmp(imap->custom, "EXAMINE") && - strcmp(imap->custom, "SEARCH") && - strcmp(imap->custom, "EXPUNGE") && - strcmp(imap->custom, "LSUB") && - strcmp(imap->custom, "UID") && - strcmp(imap->custom, "NOOP"))) - return FALSE; - break; - - case IMAP_SELECT: - /* SELECT is special in that its untagged responses do not have a - common prefix so accept anything! */ - break; - - case IMAP_FETCH: - if(!imap_matchresp(line, len, "FETCH")) - return FALSE; - break; - - case IMAP_SEARCH: - if(!imap_matchresp(line, len, "SEARCH")) - return FALSE; - break; - - /* Ignore other untagged responses */ - default: - return FALSE; - } - - *resp = '*'; - return TRUE; - } - - /* Do we have a continuation response? This should be a + symbol followed by - a space and optionally some text as per RFC-3501 for the AUTHENTICATE and - APPEND commands and as outlined in Section 4. Examples of RFC-4959 but - some e-mail servers ignore this and only send a single + instead. */ - if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) || - (len >= 2 && !memcmp("+ ", line, 2)))) { - switch(imapc->state) { - /* States which are interested in continuation responses */ - case IMAP_AUTHENTICATE: - case IMAP_APPEND: - *resp = '+'; - break; - - default: - failf(conn->data, "Unexpected continuation response"); - *resp = -1; - break; - } - - return TRUE; - } - - return FALSE; /* Nothing for us */ -} - -/*********************************************************************** - * - * imap_get_message() - * - * Gets the authentication message from the response buffer. - */ -static void imap_get_message(char *buffer, char **outptr) -{ - size_t len = 0; - char *message = NULL; - - /* Find the start of the message */ - for(message = buffer + 2; *message == ' ' || *message == '\t'; message++) - ; - - /* Find the end of the message */ - for(len = strlen(message); len--;) - if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && - message[len] != '\t') - break; - - /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } - - *outptr = message; -} - -/*********************************************************************** - * - * state() - * - * This is the ONLY way to change IMAP state! - */ -static void state(struct connectdata *conn, imapstate newstate) -{ - struct imap_conn *imapc = &conn->proto.imapc; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ - static const char * const names[]={ - "STOP", - "SERVERGREET", - "CAPABILITY", - "STARTTLS", - "UPGRADETLS", - "AUTHENTICATE", - "LOGIN", - "LIST", - "SELECT", - "FETCH", - "FETCH_FINAL", - "APPEND", - "APPEND_FINAL", - "SEARCH", - "LOGOUT", - /* LAST */ - }; - - if(imapc->state != newstate) - infof(conn->data, "IMAP %p state change from %s to %s\n", - (void *)imapc, names[imapc->state], names[newstate]); -#endif - - imapc->state = newstate; -} - -/*********************************************************************** - * - * imap_perform_capability() - * - * Sends the CAPABILITY command in order to obtain a list of server side - * supported capabilities. - */ -static CURLcode imap_perform_capability(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - - imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ - imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ - imapc->tls_supported = FALSE; /* Clear the TLS capability */ - - /* Send the CAPABILITY command */ - result = imap_sendf(conn, "CAPABILITY"); - - if(!result) - state(conn, IMAP_CAPABILITY); - - return result; -} - -/*********************************************************************** - * - * imap_perform_starttls() - * - * Sends the STARTTLS command to start the upgrade to TLS. - */ -static CURLcode imap_perform_starttls(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* Send the STARTTLS command */ - result = imap_sendf(conn, "STARTTLS"); - - if(!result) - state(conn, IMAP_STARTTLS); - - return result; -} - -/*********************************************************************** - * - * imap_perform_upgrade_tls() - * - * Performs the upgrade to TLS. - */ -static CURLcode imap_perform_upgrade_tls(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - - /* Start the SSL connection */ - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone); - - if(!result) { - if(imapc->state != IMAP_UPGRADETLS) - state(conn, IMAP_UPGRADETLS); - - if(imapc->ssldone) { - imap_to_imaps(conn); - result = imap_perform_capability(conn); - } - } - - return result; -} - -/*********************************************************************** - * - * imap_perform_login() - * - * Sends a clear text LOGIN command to authenticate with. - */ -static CURLcode imap_perform_login(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - char *user; - char *passwd; - - /* Check we have a username and password to authenticate with and end the - connect phase if we don't */ - if(!conn->bits.user_passwd) { - state(conn, IMAP_STOP); - - return result; - } - - /* Make sure the username and password are in the correct atom format */ - user = imap_atom(conn->user, false); - passwd = imap_atom(conn->passwd, false); - - /* Send the LOGIN command */ - result = imap_sendf(conn, "LOGIN %s %s", user ? user : "", - passwd ? passwd : ""); - - free(user); - free(passwd); - - if(!result) - state(conn, IMAP_LOGIN); - - return result; -} - -/*********************************************************************** - * - * imap_perform_authenticate() - * - * Sends an AUTHENTICATE command allowing the client to login with the given - * SASL authentication mechanism. - */ -static CURLcode imap_perform_authenticate(struct connectdata *conn, - const char *mech, - const char *initresp) -{ - CURLcode result = CURLE_OK; - - if(initresp) { - /* Send the AUTHENTICATE command with the initial response */ - result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp); - } - else { - /* Send the AUTHENTICATE command */ - result = imap_sendf(conn, "AUTHENTICATE %s", mech); - } - - return result; -} - -/*********************************************************************** - * - * imap_continue_authenticate() - * - * Sends SASL continuation data or cancellation. - */ -static CURLcode imap_continue_authenticate(struct connectdata *conn, - const char *resp) -{ - struct imap_conn *imapc = &conn->proto.imapc; - - return Curl_pp_sendf(&imapc->pp, "%s", resp); -} - -/*********************************************************************** - * - * imap_perform_authentication() - * - * Initiates the authentication sequence, with the appropriate SASL - * authentication mechanism, falling back to clear text should a common - * mechanism not be available between the client and server. - */ -static CURLcode imap_perform_authentication(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - saslprogress progress; - - /* Check if already authenticated OR if there is enough data to authenticate - with and end the connect phase if we don't */ - if(imapc->preauth || - !Curl_sasl_can_authenticate(&imapc->sasl, conn)) { - state(conn, IMAP_STOP); - return result; - } - - /* Calculate the SASL login details */ - result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress); - - if(!result) { - if(progress == SASL_INPROGRESS) - state(conn, IMAP_AUTHENTICATE); - else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) - /* Perform clear text authentication */ - result = imap_perform_login(conn); - else { - /* Other mechanisms not supported */ - infof(conn->data, "No known authentication mechanisms supported!\n"); - result = CURLE_LOGIN_DENIED; - } - } - - return result; -} - -/*********************************************************************** - * - * imap_perform_list() - * - * Sends a LIST command or an alternative custom request. - */ -static CURLcode imap_perform_list(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap = data->req.protop; - char *mailbox; - - if(imap->custom) - /* Send the custom request */ - result = imap_sendf(conn, "%s%s", imap->custom, - imap->custom_params ? imap->custom_params : ""); - else { - /* Make sure the mailbox is in the correct atom format if necessary */ - mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) : strdup(""); - if(!mailbox) - return CURLE_OUT_OF_MEMORY; - - /* Send the LIST command */ - result = imap_sendf(conn, "LIST \"%s\" *", mailbox); - - free(mailbox); - } - - if(!result) - state(conn, IMAP_LIST); - - return result; -} - -/*********************************************************************** - * - * imap_perform_select() - * - * Sends a SELECT command to ask the server to change the selected mailbox. - */ -static CURLcode imap_perform_select(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap = data->req.protop; - struct imap_conn *imapc = &conn->proto.imapc; - char *mailbox; - - /* Invalidate old information as we are switching mailboxes */ - Curl_safefree(imapc->mailbox); - Curl_safefree(imapc->mailbox_uidvalidity); - - /* Check we have a mailbox */ - if(!imap->mailbox) { - failf(conn->data, "Cannot SELECT without a mailbox."); - return CURLE_URL_MALFORMAT; - } - - /* Make sure the mailbox is in the correct atom format */ - mailbox = imap_atom(imap->mailbox, false); - if(!mailbox) - return CURLE_OUT_OF_MEMORY; - - /* Send the SELECT command */ - result = imap_sendf(conn, "SELECT %s", mailbox); - - free(mailbox); - - if(!result) - state(conn, IMAP_SELECT); - - return result; -} - -/*********************************************************************** - * - * imap_perform_fetch() - * - * Sends a FETCH command to initiate the download of a message. - */ -static CURLcode imap_perform_fetch(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct IMAP *imap = conn->data->req.protop; - - /* Check we have a UID */ - if(!imap->uid) { - failf(conn->data, "Cannot FETCH without a UID."); - return CURLE_URL_MALFORMAT; - } - - /* Send the FETCH command */ - if(imap->partial) - result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>", - imap->uid, - imap->section ? imap->section : "", - imap->partial); - else - result = imap_sendf(conn, "FETCH %s BODY[%s]", - imap->uid, - imap->section ? imap->section : ""); - - if(!result) - state(conn, IMAP_FETCH); - - return result; -} - -/*********************************************************************** - * - * imap_perform_append() - * - * Sends an APPEND command to initiate the upload of a message. - */ -static CURLcode imap_perform_append(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap = data->req.protop; - char *mailbox; - - /* Check we have a mailbox */ - if(!imap->mailbox) { - failf(data, "Cannot APPEND without a mailbox."); - return CURLE_URL_MALFORMAT; - } - - /* Prepare the mime data if some. */ - if(data->set.mimepost.kind != MIMEKIND_NONE) { - /* Use the whole structure as data. */ - data->set.mimepost.flags &= ~MIME_BODY_ONLY; - - /* Add external headers and mime version. */ - curl_mime_headers(&data->set.mimepost, data->set.headers, 0); - result = Curl_mime_prepare_headers(&data->set.mimepost, NULL, - NULL, MIMESTRATEGY_MAIL); - - if(!result) - if(!Curl_checkheaders(conn, "Mime-Version")) - result = Curl_mime_add_header(&data->set.mimepost.curlheaders, - "Mime-Version: 1.0"); - - /* Make sure we will read the entire mime structure. */ - if(!result) - result = Curl_mime_rewind(&data->set.mimepost); - - if(result) - return result; - - data->state.infilesize = Curl_mime_size(&data->set.mimepost); - - /* Read from mime structure. */ - data->state.fread_func = (curl_read_callback) Curl_mime_read; - data->state.in = (void *) &data->set.mimepost; - } - - /* Check we know the size of the upload */ - if(data->state.infilesize < 0) { - failf(data, "Cannot APPEND with unknown input file size\n"); - return CURLE_UPLOAD_FAILED; - } - - /* Make sure the mailbox is in the correct atom format */ - mailbox = imap_atom(imap->mailbox, false); - if(!mailbox) - return CURLE_OUT_OF_MEMORY; - - /* Send the APPEND command */ - result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", - mailbox, data->state.infilesize); - - free(mailbox); - - if(!result) - state(conn, IMAP_APPEND); - - return result; -} - -/*********************************************************************** - * - * imap_perform_search() - * - * Sends a SEARCH command. - */ -static CURLcode imap_perform_search(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct IMAP *imap = conn->data->req.protop; - - /* Check we have a query string */ - if(!imap->query) { - failf(conn->data, "Cannot SEARCH without a query string."); - return CURLE_URL_MALFORMAT; - } - - /* Send the SEARCH command */ - result = imap_sendf(conn, "SEARCH %s", imap->query); - - if(!result) - state(conn, IMAP_SEARCH); - - return result; -} - -/*********************************************************************** - * - * imap_perform_logout() - * - * Performs the logout action prior to sclose() being called. - */ -static CURLcode imap_perform_logout(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* Send the LOGOUT command */ - result = imap_sendf(conn, "LOGOUT"); - - if(!result) - state(conn, IMAP_LOGOUT); - - return result; -} - -/* For the initial server greeting */ -static CURLcode imap_state_servergreet_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - struct Curl_easy *data = conn->data; - (void)instate; /* no use for this yet */ - - if(imapcode == IMAP_RESP_PREAUTH) { - /* PREAUTH */ - struct imap_conn *imapc = &conn->proto.imapc; - imapc->preauth = TRUE; - infof(data, "PREAUTH connection, already authenticated!\n"); - } - else if(imapcode != IMAP_RESP_OK) { - failf(data, "Got unexpected imap-server response"); - return CURLE_WEIRD_SERVER_REPLY; - } - - return imap_perform_capability(conn); -} - -/* For CAPABILITY responses */ -static CURLcode imap_state_capability_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - const char *line = data->state.buffer; - size_t wordlen; - - (void)instate; /* no use for this yet */ - - /* Do we have a untagged response? */ - if(imapcode == '*') { - line += 2; - - /* Loop through the data line */ - for(;;) { - while(*line && - (*line == ' ' || *line == '\t' || - *line == '\r' || *line == '\n')) { - - line++; - } - - if(!*line) - break; - - /* Extract the word */ - for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' && - line[wordlen] != '\t' && line[wordlen] != '\r' && - line[wordlen] != '\n';) - wordlen++; - - /* Does the server support the STARTTLS capability? */ - if(wordlen == 8 && !memcmp(line, "STARTTLS", 8)) - imapc->tls_supported = TRUE; - - /* Has the server explicitly disabled clear text authentication? */ - else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13)) - imapc->login_disabled = TRUE; - - /* Does the server support the SASL-IR capability? */ - else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7)) - imapc->ir_supported = TRUE; - - /* Do we have a SASL based authentication mechanism? */ - else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) { - size_t llen; - unsigned int mechbit; - - line += 5; - wordlen -= 5; - - /* Test the word for a matching authentication mechanism */ - mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); - if(mechbit && llen == wordlen) - imapc->sasl.authmechs |= mechbit; - } - - line += wordlen; - } - } - else if(imapcode == IMAP_RESP_OK) { - if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested */ - if(imapc->tls_supported) - /* Switch to TLS connection now */ - result = imap_perform_starttls(conn); - else if(data->set.use_ssl == CURLUSESSL_TRY) - /* Fallback and carry on with authentication */ - result = imap_perform_authentication(conn); - else { - failf(data, "STARTTLS not supported."); - result = CURLE_USE_SSL_FAILED; - } - } - else - result = imap_perform_authentication(conn); - } - else - result = imap_perform_authentication(conn); - - return result; -} - -/* For STARTTLS responses */ -static CURLcode imap_state_starttls_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(imapcode != IMAP_RESP_OK) { - if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied"); - result = CURLE_USE_SSL_FAILED; - } - else - result = imap_perform_authentication(conn); - } - else - result = imap_perform_upgrade_tls(conn); - - return result; -} - -/* For SASL authentication responses */ -static CURLcode imap_state_auth_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - saslprogress progress; - - (void)instate; /* no use for this yet */ - - result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress); - if(!result) - switch(progress) { - case SASL_DONE: - state(conn, IMAP_STOP); /* Authenticated */ - break; - case SASL_IDLE: /* No mechanism left after cancellation */ - if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) - /* Perform clear text authentication */ - result = imap_perform_login(conn); - else { - failf(data, "Authentication cancelled"); - result = CURLE_LOGIN_DENIED; - } - break; - default: - break; - } - - return result; -} - -/* For LOGIN responses */ -static CURLcode imap_state_login_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(imapcode != IMAP_RESP_OK) { - failf(data, "Access denied. %c", imapcode); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, IMAP_STOP); - - return result; -} - -/* For LIST and SEARCH responses */ -static CURLcode imap_state_listsearch_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - char *line = conn->data->state.buffer; - size_t len = strlen(line); - - (void)instate; /* No use for this yet */ - - if(imapcode == '*') { - /* Temporarily add the LF character back and send as body to the client */ - line[len] = '\n'; - result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); - line[len] = '\0'; - } - else if(imapcode != IMAP_RESP_OK) - result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */ - else - /* End of DO phase */ - state(conn, IMAP_STOP); - - return result; -} - -/* For SELECT responses */ -static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap = conn->data->req.protop; - struct imap_conn *imapc = &conn->proto.imapc; - const char *line = data->state.buffer; - char tmp[20]; - - (void)instate; /* no use for this yet */ - - if(imapcode == '*') { - /* See if this is an UIDVALIDITY response */ - if(sscanf(line + 2, "OK [UIDVALIDITY %19[0123456789]]", tmp) == 1) { - Curl_safefree(imapc->mailbox_uidvalidity); - imapc->mailbox_uidvalidity = strdup(tmp); - } - } - else if(imapcode == IMAP_RESP_OK) { - /* Check if the UIDVALIDITY has been specified and matches */ - if(imap->uidvalidity && imapc->mailbox_uidvalidity && - strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) { - failf(conn->data, "Mailbox UIDVALIDITY has changed"); - result = CURLE_REMOTE_FILE_NOT_FOUND; - } - else { - /* Note the currently opened mailbox on this connection */ - imapc->mailbox = strdup(imap->mailbox); - - if(imap->custom) - result = imap_perform_list(conn); - else if(imap->query) - result = imap_perform_search(conn); - else - result = imap_perform_fetch(conn); - } - } - else { - failf(data, "Select failed"); - result = CURLE_LOGIN_DENIED; - } - - return result; -} - -/* For the (first line of the) FETCH responses */ -static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - struct pingpong *pp = &imapc->pp; - const char *ptr = data->state.buffer; - bool parsed = FALSE; - curl_off_t size = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '*') { - Curl_pgrsSetDownloadSize(data, -1); - state(conn, IMAP_STOP); - return CURLE_REMOTE_FILE_NOT_FOUND; /* TODO: Fix error code */ - } - - /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse - the continuation data contained within the curly brackets */ - while(*ptr && (*ptr != '{')) - ptr++; - - if(*ptr == '{') { - char *endptr; - if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) { - if(endptr - ptr > 1 && endptr[0] == '}' && - endptr[1] == '\r' && endptr[2] == '\0') - parsed = TRUE; - } - } - - if(parsed) { - infof(data, "Found %" CURL_FORMAT_CURL_OFF_TU " bytes to download\n", - size); - Curl_pgrsSetDownloadSize(data, size); - - if(pp->cache) { - /* At this point there is a bunch of data in the header "cache" that is - actually body content, send it as body and then skip it. Do note - that there may even be additional "headers" after the body. */ - size_t chunk = pp->cache_size; - - if(chunk > (size_t)size) - /* The conversion from curl_off_t to size_t is always fine here */ - chunk = (size_t)size; - - result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk); - if(result) - return result; - - data->req.bytecount += chunk; - - infof(data, "Written %" CURL_FORMAT_CURL_OFF_TU - " bytes, %" CURL_FORMAT_CURL_OFF_TU - " bytes are left for transfer\n", (curl_off_t)chunk, - size - chunk); - - /* Have we used the entire cache or just part of it?*/ - if(pp->cache_size > chunk) { - /* Only part of it so shrink the cache to fit the trailing data */ - memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk); - pp->cache_size -= chunk; - } - else { - /* Free the cache */ - Curl_safefree(pp->cache); - - /* Reset the cache size */ - pp->cache_size = 0; - } - } - - if(data->req.bytecount == size) - /* The entire data is already transferred! */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - else { - /* IMAP download */ - data->req.maxdownload = size; - Curl_setup_transfer(conn, FIRSTSOCKET, size, FALSE, NULL, -1, NULL); - } - } - else { - /* We don't know how to parse this line */ - failf(pp->conn->data, "Failed to parse FETCH response."); - result = CURLE_WEIRD_SERVER_REPLY; - } - - /* End of DO phase */ - state(conn, IMAP_STOP); - - return result; -} - -/* For final FETCH responses performed after the download */ -static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - - (void)instate; /* No use for this yet */ - - if(imapcode != IMAP_RESP_OK) - result = CURLE_WEIRD_SERVER_REPLY; - else - /* End of DONE phase */ - state(conn, IMAP_STOP); - - return result; -} - -/* For APPEND responses */ -static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* No use for this yet */ - - if(imapcode != '+') { - result = CURLE_UPLOAD_FAILED; - } - else { - /* Set the progress upload size */ - Curl_pgrsSetUploadSize(data, data->state.infilesize); - - /* IMAP upload */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); - - /* End of DO phase */ - state(conn, IMAP_STOP); - } - - return result; -} - -/* For final APPEND responses performed after the upload */ -static CURLcode imap_state_append_final_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - - (void)instate; /* No use for this yet */ - - if(imapcode != IMAP_RESP_OK) - result = CURLE_UPLOAD_FAILED; - else - /* End of DONE phase */ - state(conn, IMAP_STOP); - - return result; -} - -static CURLcode imap_statemach_act(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int imapcode; - struct imap_conn *imapc = &conn->proto.imapc; - struct pingpong *pp = &imapc->pp; - size_t nread = 0; - - /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */ - if(imapc->state == IMAP_UPGRADETLS) - return imap_perform_upgrade_tls(conn); - - /* Flush any data that needs to be sent */ - if(pp->sendleft) - return Curl_pp_flushsend(pp); - - do { - /* Read the response from the server */ - result = Curl_pp_readresp(sock, pp, &imapcode, &nread); - if(result) - return result; - - /* Was there an error parsing the response line? */ - if(imapcode == -1) - return CURLE_WEIRD_SERVER_REPLY; - - if(!imapcode) - break; - - /* We have now received a full IMAP server response */ - switch(imapc->state) { - case IMAP_SERVERGREET: - result = imap_state_servergreet_resp(conn, imapcode, imapc->state); - break; - - case IMAP_CAPABILITY: - result = imap_state_capability_resp(conn, imapcode, imapc->state); - break; - - case IMAP_STARTTLS: - result = imap_state_starttls_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE: - result = imap_state_auth_resp(conn, imapcode, imapc->state); - break; - - case IMAP_LOGIN: - result = imap_state_login_resp(conn, imapcode, imapc->state); - break; - - case IMAP_LIST: - result = imap_state_listsearch_resp(conn, imapcode, imapc->state); - break; - - case IMAP_SELECT: - result = imap_state_select_resp(conn, imapcode, imapc->state); - break; - - case IMAP_FETCH: - result = imap_state_fetch_resp(conn, imapcode, imapc->state); - break; - - case IMAP_FETCH_FINAL: - result = imap_state_fetch_final_resp(conn, imapcode, imapc->state); - break; - - case IMAP_APPEND: - result = imap_state_append_resp(conn, imapcode, imapc->state); - break; - - case IMAP_APPEND_FINAL: - result = imap_state_append_final_resp(conn, imapcode, imapc->state); - break; - - case IMAP_SEARCH: - result = imap_state_listsearch_resp(conn, imapcode, imapc->state); - break; - - case IMAP_LOGOUT: - /* fallthrough, just stop! */ - default: - /* internal error */ - state(conn, IMAP_STOP); - break; - } - } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp)); - - return result; -} - -/* Called repeatedly until done from multi.c */ -static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - - if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) { - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone); - if(result || !imapc->ssldone) - return result; - } - - result = Curl_pp_statemach(&imapc->pp, FALSE); - *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE; - - return result; -} - -static CURLcode imap_block_statemach(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - - while(imapc->state != IMAP_STOP && !result) - result = Curl_pp_statemach(&imapc->pp, TRUE); - - return result; -} - -/* Allocate and initialize the struct IMAP for the current Curl_easy if - required */ -static CURLcode imap_init(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap; - - imap = data->req.protop = calloc(sizeof(struct IMAP), 1); - if(!imap) - result = CURLE_OUT_OF_MEMORY; - - return result; -} - -/* For the IMAP "protocol connect" and "doing" phases only */ -static int imap_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks) -{ - return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks); -} - -/*********************************************************************** - * - * imap_connect() - * - * This function should do everything that is to be considered a part of the - * connection phase. - * - * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE if not. - */ -static CURLcode imap_connect(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - struct pingpong *pp = &imapc->pp; - - *done = FALSE; /* default to not done yet */ - - /* We always support persistent connections in IMAP */ - connkeep(conn, "IMAP default"); - - /* Set the default response time-out */ - pp->response_time = RESP_TIMEOUT; - pp->statemach_act = imap_statemach_act; - pp->endofresp = imap_endofresp; - pp->conn = conn; - - /* Set the default preferred authentication type and mechanism */ - imapc->preftype = IMAP_TYPE_ANY; - Curl_sasl_init(&imapc->sasl, &saslimap); - - /* Initialise the pingpong layer */ - Curl_pp_init(pp); - - /* Parse the URL options */ - result = imap_parse_url_options(conn); - if(result) - return result; - - /* Start off waiting for the server greeting response */ - state(conn, IMAP_SERVERGREET); - - /* Start off with an response id of '*' */ - strcpy(imapc->resptag, "*"); - - result = imap_multi_statemach(conn, done); - - return result; -} - -/*********************************************************************** - * - * imap_done() - * - * The DONE function. This does what needs to be done after a single DO has - * performed. - * - * Input argument is already checked for validity. - */ -static CURLcode imap_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap = data->req.protop; - - (void)premature; - - if(!imap) - return CURLE_OK; - - if(status) { - connclose(conn, "IMAP done with bad status"); /* marked for closure */ - result = status; /* use the already set error code */ - } - else if(!data->set.connect_only && !imap->custom && - (imap->uid || data->set.upload || - data->set.mimepost.kind != MIMEKIND_NONE)) { - /* Handle responses after FETCH or APPEND transfer has finished */ - if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE) - state(conn, IMAP_FETCH_FINAL); - else { - /* End the APPEND command first by sending an empty line */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", ""); - if(!result) - state(conn, IMAP_APPEND_FINAL); - } - - /* Run the state-machine - - TODO: when the multi interface is used, this _really_ should be using - the imap_multi_statemach function but we have no general support for - non-blocking DONE operations! - */ - if(!result) - result = imap_block_statemach(conn); - } - - /* Cleanup our per-request based variables */ - Curl_safefree(imap->mailbox); - Curl_safefree(imap->uidvalidity); - Curl_safefree(imap->uid); - Curl_safefree(imap->section); - Curl_safefree(imap->partial); - Curl_safefree(imap->query); - Curl_safefree(imap->custom); - Curl_safefree(imap->custom_params); - - /* Clear the transfer mode for the next request */ - imap->transfer = FTPTRANSFER_BODY; - - return result; -} - -/*********************************************************************** - * - * imap_perform() - * - * This is the actual DO function for IMAP. Fetch or append a message, or do - * other things according to the options previously setup. - */ -static CURLcode imap_perform(struct connectdata *conn, bool *connected, - bool *dophase_done) -{ - /* This is IMAP and no proxy */ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap = data->req.protop; - struct imap_conn *imapc = &conn->proto.imapc; - bool selected = FALSE; - - DEBUGF(infof(conn->data, "DO phase starts\n")); - - if(conn->data->set.opt_no_body) { - /* Requested no body means no transfer */ - imap->transfer = FTPTRANSFER_INFO; - } - - *dophase_done = FALSE; /* not done yet */ - - /* Determine if the requested mailbox (with the same UIDVALIDITY if set) - has already been selected on this connection */ - if(imap->mailbox && imapc->mailbox && - !strcmp(imap->mailbox, imapc->mailbox) && - (!imap->uidvalidity || !imapc->mailbox_uidvalidity || - !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity))) - selected = TRUE; - - /* Start the first command in the DO phase */ - if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE) - /* APPEND can be executed directly */ - result = imap_perform_append(conn); - else if(imap->custom && (selected || !imap->mailbox)) - /* Custom command using the same mailbox or no mailbox */ - result = imap_perform_list(conn); - else if(!imap->custom && selected && imap->uid) - /* FETCH from the same mailbox */ - result = imap_perform_fetch(conn); - else if(!imap->custom && selected && imap->query) - /* SEARCH the current mailbox */ - result = imap_perform_search(conn); - else if(imap->mailbox && !selected && - (imap->custom || imap->uid || imap->query)) - /* SELECT the mailbox */ - result = imap_perform_select(conn); - else - /* LIST */ - result = imap_perform_list(conn); - - if(result) - return result; - - /* Run the state-machine */ - result = imap_multi_statemach(conn, dophase_done); - - *connected = conn->bits.tcpconnect[FIRSTSOCKET]; - - if(*dophase_done) - DEBUGF(infof(conn->data, "DO phase is complete\n")); - - return result; -} - -/*********************************************************************** - * - * imap_do() - * - * This function is registered as 'curl_do' function. It decodes the path - * parts etc as a wrapper to the actual DO function (imap_perform). - * - * The input argument is already checked for validity. - */ -static CURLcode imap_do(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - - *done = FALSE; /* default to false */ - - /* Parse the URL path */ - result = imap_parse_url_path(conn); - if(result) - return result; - - /* Parse the custom request */ - result = imap_parse_custom_request(conn); - if(result) - return result; - - result = imap_regular_transfer(conn, done); - - return result; -} - -/*********************************************************************** - * - * imap_disconnect() - * - * Disconnect from an IMAP server. Cleanup protocol-specific per-connection - * resources. BLOCKING. - */ -static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection) -{ - struct imap_conn *imapc = &conn->proto.imapc; - - /* We cannot send quit unconditionally. If this connection is stale or - bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. */ - - /* The IMAP session may or may not have been allocated/setup at this - point! */ - if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart) - if(!imap_perform_logout(conn)) - (void)imap_block_statemach(conn); /* ignore errors on LOGOUT */ - - /* Disconnect from the server */ - Curl_pp_disconnect(&imapc->pp); - - /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, imapc->sasl.authused); - - /* Cleanup our connection based variables */ - Curl_safefree(imapc->mailbox); - Curl_safefree(imapc->mailbox_uidvalidity); - - return CURLE_OK; -} - -/* Call this when the DO phase has completed */ -static CURLcode imap_dophase_done(struct connectdata *conn, bool connected) -{ - struct IMAP *imap = conn->data->req.protop; - - (void)connected; - - if(imap->transfer != FTPTRANSFER_BODY) - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - return CURLE_OK; -} - -/* Called from multi.c while DOing */ -static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done) -{ - CURLcode result = imap_multi_statemach(conn, dophase_done); - - if(result) - DEBUGF(infof(conn->data, "DO phase failed\n")); - else if(*dophase_done) { - result = imap_dophase_done(conn, FALSE /* not connected */); - - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - - return result; -} - -/*********************************************************************** - * - * imap_regular_transfer() - * - * The input argument is already checked for validity. - * - * Performs all commands done before a regular transfer between a local and a - * remote host. - */ -static CURLcode imap_regular_transfer(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - bool connected = FALSE; - struct Curl_easy *data = conn->data; - - /* Make sure size is unknown at this point */ - data->req.size = -1; - - /* Set the progress data */ - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, -1); - Curl_pgrsSetDownloadSize(data, -1); - - /* Carry out the perform */ - result = imap_perform(conn, &connected, dophase_done); - - /* Perform post DO phase operations if necessary */ - if(!result && *dophase_done) - result = imap_dophase_done(conn, connected); - - return result; -} - -static CURLcode imap_setup_connection(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - - /* Initialise the IMAP layer */ - CURLcode result = imap_init(conn); - if(result) - return result; - - /* Clear the TLS upgraded flag */ - conn->tls_upgraded = FALSE; - data->state.path++; /* don't include the initial slash */ - - return CURLE_OK; -} - -/*********************************************************************** - * - * imap_sendf() - * - * Sends the formatted string as an IMAP command to the server. - * - * Designed to never block. - */ -static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) -{ - CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - char *taggedfmt; - va_list ap; - - DEBUGASSERT(fmt); - - /* Calculate the next command ID wrapping at 3 digits */ - imapc->cmdid = (imapc->cmdid + 1) % 1000; - - /* Calculate the tag based on the connection ID and command ID */ - snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", - 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid); - - /* Prefix the format with the tag */ - taggedfmt = aprintf("%s %s", imapc->resptag, fmt); - if(!taggedfmt) - return CURLE_OUT_OF_MEMORY; - - /* Send the data with the tag */ - va_start(ap, fmt); - result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap); - va_end(ap); - - free(taggedfmt); - - return result; -} - -/*********************************************************************** - * - * imap_atom() - * - * Checks the input string for characters that need escaping and returns an - * atom ready for sending to the server. - * - * The returned string needs to be freed. - * - */ -static char *imap_atom(const char *str, bool escape_only) -{ - /* !checksrc! disable PARENBRACE 1 */ - const char atom_specials[] = "(){ %*]"; - const char *p1; - char *p2; - size_t backsp_count = 0; - size_t quote_count = 0; - bool others_exists = FALSE; - size_t newlen = 0; - char *newstr = NULL; - - if(!str) - return NULL; - - /* Look for "atom-specials", counting the backslash and quote characters as - these will need escapping */ - p1 = str; - while(*p1) { - if(*p1 == '\\') - backsp_count++; - else if(*p1 == '"') - quote_count++; - else if(!escape_only) { - const char *p3 = atom_specials; - - while(*p3 && !others_exists) { - if(*p1 == *p3) - others_exists = TRUE; - - p3++; - } - } - - p1++; - } - - /* Does the input contain any "atom-special" characters? */ - if(!backsp_count && !quote_count && !others_exists) - return strdup(str); - - /* Calculate the new string length */ - newlen = strlen(str) + backsp_count + quote_count + (escape_only ? 0 : 2); - - /* Allocate the new string */ - newstr = (char *) malloc((newlen + 1) * sizeof(char)); - if(!newstr) - return NULL; - - /* Surround the string in quotes if necessary */ - p2 = newstr; - if(!escape_only) { - newstr[0] = '"'; - newstr[newlen - 1] = '"'; - p2++; - } - - /* Copy the string, escaping backslash and quote characters along the way */ - p1 = str; - while(*p1) { - if(*p1 == '\\' || *p1 == '"') { - *p2 = '\\'; - p2++; - } - - *p2 = *p1; - - p1++; - p2++; - } - - /* Terminate the string */ - newstr[newlen] = '\0'; - - return newstr; -} - -/*********************************************************************** - * - * imap_is_bchar() - * - * Portable test of whether the specified char is a "bchar" as defined in the - * grammar of RFC-5092. - */ -static bool imap_is_bchar(char ch) -{ - switch(ch) { - /* bchar */ - case ':': case '@': case '/': - /* bchar -> achar */ - case '&': case '=': - /* bchar -> achar -> uchar -> unreserved */ - case '0': case '1': case '2': case '3': case '4': case '5': case '6': - case '7': case '8': case '9': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': - case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': - case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': - case 'V': case 'W': case 'X': case 'Y': case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': - case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': - case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': - case 'v': case 'w': case 'x': case 'y': case 'z': - case '-': case '.': case '_': case '~': - /* bchar -> achar -> uchar -> sub-delims-sh */ - case '!': case '$': case '\'': case '(': case ')': case '*': - case '+': case ',': - /* bchar -> achar -> uchar -> pct-encoded */ - case '%': /* HEXDIG chars are already included above */ - return true; - - default: - return false; - } -} - -/*********************************************************************** - * - * imap_parse_url_options() - * - * Parse the URL login options. - */ -static CURLcode imap_parse_url_options(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - const char *ptr = conn->options; - - imapc->sasl.resetprefs = TRUE; - - while(!result && ptr && *ptr) { - const char *key = ptr; - const char *value; - - while(*ptr && *ptr != '=') - ptr++; - - value = ptr + 1; - - while(*ptr && *ptr != ';') - ptr++; - - if(strncasecompare(key, "AUTH=", 5)) - result = Curl_sasl_parse_url_auth_option(&imapc->sasl, - value, ptr - value); - else - result = CURLE_URL_MALFORMAT; - - if(*ptr == ';') - ptr++; - } - - switch(imapc->sasl.prefmech) { - case SASL_AUTH_NONE: - imapc->preftype = IMAP_TYPE_NONE; - break; - case SASL_AUTH_DEFAULT: - imapc->preftype = IMAP_TYPE_ANY; - break; - default: - imapc->preftype = IMAP_TYPE_SASL; - break; - } - - return result; -} - -/*********************************************************************** - * - * imap_parse_url_path() - * - * Parse the URL path into separate path components. - * - */ -static CURLcode imap_parse_url_path(struct connectdata *conn) -{ - /* The imap struct is already initialised in imap_connect() */ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap = data->req.protop; - const char *begin = data->state.path; - const char *ptr = begin; - - /* See how much of the URL is a valid path and decode it */ - while(imap_is_bchar(*ptr)) - ptr++; - - if(ptr != begin) { - /* Remove the trailing slash if present */ - const char *end = ptr; - if(end > begin && end[-1] == '/') - end--; - - result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL, - TRUE); - if(result) - return result; - } - else - imap->mailbox = NULL; - - /* There can be any number of parameters in the form ";NAME=VALUE" */ - while(*ptr == ';') { - char *name; - char *value; - size_t valuelen; - - /* Find the length of the name parameter */ - begin = ++ptr; - while(*ptr && *ptr != '=') - ptr++; - - if(!*ptr) - return CURLE_URL_MALFORMAT; - - /* Decode the name parameter */ - result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE); - if(result) - return result; - - /* Find the length of the value parameter */ - begin = ++ptr; - while(imap_is_bchar(*ptr)) - ptr++; - - /* Decode the value parameter */ - result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE); - if(result) { - free(name); - return result; - } - - DEBUGF(infof(conn->data, "IMAP URL parameter '%s' = '%s'\n", name, value)); - - /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and - PARTIAL) stripping of the trailing slash character if it is present. - - Note: Unknown parameters trigger a URL_MALFORMAT error. */ - if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->uidvalidity = value; - value = NULL; - } - else if(strcasecompare(name, "UID") && !imap->uid) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->uid = value; - value = NULL; - } - else if(strcasecompare(name, "SECTION") && !imap->section) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->section = value; - value = NULL; - } - else if(strcasecompare(name, "PARTIAL") && !imap->partial) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->partial = value; - value = NULL; - } - else { - free(name); - free(value); - - return CURLE_URL_MALFORMAT; - } - - free(name); - free(value); - } - - /* Does the URL contain a query parameter? Only valid when we have a mailbox - and no UID as per RFC-5092 */ - if(imap->mailbox && !imap->uid && *ptr == '?') { - /* Find the length of the query parameter */ - begin = ++ptr; - while(imap_is_bchar(*ptr)) - ptr++; - - /* Decode the query parameter */ - result = Curl_urldecode(data, begin, ptr - begin, &imap->query, NULL, - TRUE); - if(result) - return result; - } - - /* Any extra stuff at the end of the URL is an error */ - if(*ptr) - return CURLE_URL_MALFORMAT; - - return CURLE_OK; -} - -/*********************************************************************** - * - * imap_parse_custom_request() - * - * Parse the custom request. - */ -static CURLcode imap_parse_custom_request(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct IMAP *imap = data->req.protop; - const char *custom = data->set.str[STRING_CUSTOMREQUEST]; - - if(custom) { - /* URL decode the custom request */ - result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE); - - /* Extract the parameters if specified */ - if(!result) { - const char *params = imap->custom; - - while(*params && *params != ' ') - params++; - - if(*params) { - imap->custom_params = strdup(params); - imap->custom[params - imap->custom] = '\0'; - - if(!imap->custom_params) - result = CURLE_OUT_OF_MEMORY; - } - } - } - - return result; -} - -#endif /* CURL_DISABLE_IMAP */ diff --git a/dep/cpr/opt/curl/lib/imap.h b/dep/cpr/opt/curl/lib/imap.h deleted file mode 100644 index 9fc4ff5a3da..00000000000 --- a/dep/cpr/opt/curl/lib/imap.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef HEADER_CURL_IMAP_H -#define HEADER_CURL_IMAP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2009 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "pingpong.h" -#include "curl_sasl.h" - -/**************************************************************************** - * IMAP unique setup - ***************************************************************************/ -typedef enum { - IMAP_STOP, /* do nothing state, stops the state machine */ - IMAP_SERVERGREET, /* waiting for the initial greeting immediately after - a connect */ - IMAP_CAPABILITY, - IMAP_STARTTLS, - IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS - (multi mode only) */ - IMAP_AUTHENTICATE, - IMAP_LOGIN, - IMAP_LIST, - IMAP_SELECT, - IMAP_FETCH, - IMAP_FETCH_FINAL, - IMAP_APPEND, - IMAP_APPEND_FINAL, - IMAP_SEARCH, - IMAP_LOGOUT, - IMAP_LAST /* never used */ -} imapstate; - -/* This IMAP struct is used in the Curl_easy. All IMAP data that is - connection-oriented must be in imap_conn to properly deal with the fact that - perhaps the Curl_easy is changed between the times the connection is - used. */ -struct IMAP { - curl_pp_transfer transfer; - char *mailbox; /* Mailbox to select */ - char *uidvalidity; /* UIDVALIDITY to check in select */ - char *uid; /* Message UID to fetch */ - char *section; /* Message SECTION to fetch */ - char *partial; /* Message PARTIAL to fetch */ - char *query; /* Query to search for */ - char *custom; /* Custom request */ - char *custom_params; /* Parameters for the custom request */ -}; - -/* imap_conn is used for struct connection-oriented data in the connectdata - struct */ -struct imap_conn { - struct pingpong pp; - imapstate state; /* Always use imap.c:state() to change state! */ - bool ssldone; /* Is connect() over SSL done? */ - bool preauth; /* Is this connection PREAUTH? */ - struct SASL sasl; /* SASL-related parameters */ - unsigned int preftype; /* Preferred authentication type */ - int cmdid; /* Last used command ID */ - char resptag[5]; /* Response tag to wait for */ - bool tls_supported; /* StartTLS capability supported by server */ - bool login_disabled; /* LOGIN command disabled by server */ - bool ir_supported; /* Initial response supported by server */ - char *mailbox; /* The last selected mailbox */ - char *mailbox_uidvalidity; /* UIDVALIDITY parsed from select response */ -}; - -extern const struct Curl_handler Curl_handler_imap; -extern const struct Curl_handler Curl_handler_imaps; - -/* Authentication type flags */ -#define IMAP_TYPE_CLEARTEXT (1 << 0) -#define IMAP_TYPE_SASL (1 << 1) - -/* Authentication type values */ -#define IMAP_TYPE_NONE 0 -#define IMAP_TYPE_ANY ~0U - -#endif /* HEADER_CURL_IMAP_H */ diff --git a/dep/cpr/opt/curl/lib/inet_ntop.c b/dep/cpr/opt/curl/lib/inet_ntop.c deleted file mode 100644 index fb91a505db9..00000000000 --- a/dep/cpr/opt/curl/lib/inet_ntop.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 1996-2001 Internet Software Consortium. - * - * 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 INTERNET SOFTWARE CONSORTIUM - * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * INTERNET SOFTWARE CONSORTIUM 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 code by Paul Vixie. "curlified" by Gisle Vanem. - */ - -#include "curl_setup.h" - -#ifndef HAVE_INET_NTOP - -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#include "inet_ntop.h" -#include "curl_printf.h" - -#define IN6ADDRSZ 16 -#define INADDRSZ 4 -#define INT16SZ 2 - -/* - * Format an IPv4 address, more or less like inet_ntoa(). - * - * Returns `dst' (as a const) - * Note: - * - uses no statics - * - takes a unsigned char* not an in_addr as input - */ -static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) -{ - char tmp[sizeof "255.255.255.255"]; - size_t len; - - DEBUGASSERT(size >= 16); - - tmp[0] = '\0'; - (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", - ((int)((unsigned char)src[0])) & 0xff, - ((int)((unsigned char)src[1])) & 0xff, - ((int)((unsigned char)src[2])) & 0xff, - ((int)((unsigned char)src[3])) & 0xff); - - len = strlen(tmp); - if(len == 0 || len >= size) { - errno = ENOSPC; - return (NULL); - } - strcpy(dst, tmp); - return dst; -} - -#ifdef ENABLE_IPV6 -/* - * Convert IPv6 binary address into presentation (printable) format. - */ -static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) -{ - /* - * Note that int32_t and int16_t need only be "at least" large enough - * to contain a value of the specified size. On some systems, like - * Crays, there is no such thing as an integer variable with 16 bits. - * Keep this in mind if you think this function should have been coded - * to use pointer overlays. All the world's not a VAX. - */ - char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; - char *tp; - struct { - long base; - long len; - } best, cur; - unsigned long words[IN6ADDRSZ / INT16SZ]; - int i; - - /* Preprocess: - * Copy the input (bytewise) array into a wordwise array. - * Find the longest run of 0x00's in src[] for :: shorthanding. - */ - memset(words, '\0', sizeof(words)); - for(i = 0; i < IN6ADDRSZ; i++) - words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); - - best.base = -1; - cur.base = -1; - best.len = 0; - cur.len = 0; - - for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { - if(words[i] == 0) { - if(cur.base == -1) - cur.base = i, cur.len = 1; - else - cur.len++; - } - else if(cur.base != -1) { - if(best.base == -1 || cur.len > best.len) - best = cur; - cur.base = -1; - } - } - if((cur.base != -1) && (best.base == -1 || cur.len > best.len)) - best = cur; - if(best.base != -1 && best.len < 2) - best.base = -1; - /* Format the result. */ - tp = tmp; - for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { - /* Are we inside the best run of 0x00's? */ - if(best.base != -1 && i >= best.base && i < (best.base + best.len)) { - if(i == best.base) - *tp++ = ':'; - continue; - } - - /* Are we following an initial run of 0x00s or any real hex? - */ - if(i != 0) - *tp++ = ':'; - - /* Is this address an encapsulated IPv4? - */ - if(i == 6 && best.base == 0 && - (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { - if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) { - errno = ENOSPC; - return (NULL); - } - tp += strlen(tp); - break; - } - tp += snprintf(tp, 5, "%lx", words[i]); - } - - /* Was it a trailing run of 0x00's? - */ - if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) - *tp++ = ':'; - *tp++ = '\0'; - - /* Check for overflow, copy, and we're done. - */ - if((size_t)(tp - tmp) > size) { - errno = ENOSPC; - return (NULL); - } - strcpy(dst, tmp); - return dst; -} -#endif /* ENABLE_IPV6 */ - -/* - * Convert a network format address to presentation format. - * - * Returns pointer to presentation format address (`buf'). - * Returns NULL on error and errno set with the specific - * error, EAFNOSUPPORT or ENOSPC. - * - * On Windows we store the error in the thread errno, not - * in the winsock error code. This is to avoid losing the - * actual last winsock error. So when this function returns - * NULL, check errno not SOCKERRNO. - */ -char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) -{ - switch(af) { - case AF_INET: - return inet_ntop4((const unsigned char *)src, buf, size); -#ifdef ENABLE_IPV6 - case AF_INET6: - return inet_ntop6((const unsigned char *)src, buf, size); -#endif - default: - errno = EAFNOSUPPORT; - return NULL; - } -} -#endif /* HAVE_INET_NTOP */ diff --git a/dep/cpr/opt/curl/lib/inet_ntop.h b/dep/cpr/opt/curl/lib/inet_ntop.h deleted file mode 100644 index 9f446127108..00000000000 --- a/dep/cpr/opt/curl/lib/inet_ntop.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef HEADER_CURL_INET_NTOP_H -#define HEADER_CURL_INET_NTOP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); - -#ifdef HAVE_INET_NTOP -#ifdef HAVE_ARPA_INET_H -#include -#endif -#define Curl_inet_ntop(af,addr,buf,size) \ - inet_ntop(af, addr, buf, (curl_socklen_t)size) -#endif - -#endif /* HEADER_CURL_INET_NTOP_H */ - diff --git a/dep/cpr/opt/curl/lib/inet_pton.c b/dep/cpr/opt/curl/lib/inet_pton.c deleted file mode 100644 index fef9610d1e5..00000000000 --- a/dep/cpr/opt/curl/lib/inet_pton.c +++ /dev/null @@ -1,236 +0,0 @@ -/* This is from the BIND 4.9.4 release, modified to compile by itself */ - -/* Copyright (c) 1996 by Internet Software Consortium. - * - * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -#include "curl_setup.h" - -#ifndef HAVE_INET_PTON - -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#include "inet_pton.h" - -#define IN6ADDRSZ 16 -#define INADDRSZ 4 -#define INT16SZ 2 - -/* - * WARNING: Don't even consider trying to compile this on a system where - * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. - */ - -static int inet_pton4(const char *src, unsigned char *dst); -#ifdef ENABLE_IPV6 -static int inet_pton6(const char *src, unsigned char *dst); -#endif - -/* int - * inet_pton(af, src, dst) - * convert from presentation format (which usually means ASCII printable) - * to network format (which is usually some kind of binary format). - * return: - * 1 if the address was valid for the specified address family - * 0 if the address wasn't valid (`dst' is untouched in this case) - * -1 if some other error occurred (`dst' is untouched in this case, too) - * notice: - * On Windows we store the error in the thread errno, not - * in the winsock error code. This is to avoid losing the - * actual last winsock error. So when this function returns - * -1, check errno not SOCKERRNO. - * author: - * Paul Vixie, 1996. - */ -int -Curl_inet_pton(int af, const char *src, void *dst) -{ - switch(af) { - case AF_INET: - return (inet_pton4(src, (unsigned char *)dst)); -#ifdef ENABLE_IPV6 - case AF_INET6: - return (inet_pton6(src, (unsigned char *)dst)); -#endif - default: - errno = EAFNOSUPPORT; - return (-1); - } - /* NOTREACHED */ -} - -/* int - * inet_pton4(src, dst) - * like inet_aton() but without all the hexadecimal and shorthand. - * return: - * 1 if `src' is a valid dotted quad, else 0. - * notice: - * does not touch `dst' unless it's returning 1. - * author: - * Paul Vixie, 1996. - */ -static int -inet_pton4(const char *src, unsigned char *dst) -{ - static const char digits[] = "0123456789"; - int saw_digit, octets, ch; - unsigned char tmp[INADDRSZ], *tp; - - saw_digit = 0; - octets = 0; - tp = tmp; - *tp = 0; - while((ch = *src++) != '\0') { - const char *pch; - - pch = strchr(digits, ch); - if(pch) { - unsigned int val = *tp * 10 + (unsigned int)(pch - digits); - - if(saw_digit && *tp == 0) - return (0); - if(val > 255) - return (0); - *tp = (unsigned char)val; - if(! saw_digit) { - if(++octets > 4) - return (0); - saw_digit = 1; - } - } - else if(ch == '.' && saw_digit) { - if(octets == 4) - return (0); - *++tp = 0; - saw_digit = 0; - } - else - return (0); - } - if(octets < 4) - return (0); - memcpy(dst, tmp, INADDRSZ); - return (1); -} - -#ifdef ENABLE_IPV6 -/* int - * inet_pton6(src, dst) - * convert presentation level address to network order binary form. - * return: - * 1 if `src' is a valid [RFC1884 2.2] address, else 0. - * notice: - * (1) does not touch `dst' unless it's returning 1. - * (2) :: in a full address is silently ignored. - * credit: - * inspired by Mark Andrews. - * author: - * Paul Vixie, 1996. - */ -static int -inet_pton6(const char *src, unsigned char *dst) -{ - static const char xdigits_l[] = "0123456789abcdef", - xdigits_u[] = "0123456789ABCDEF"; - unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; - const char *xdigits, *curtok; - int ch, saw_xdigit; - size_t val; - - memset((tp = tmp), 0, IN6ADDRSZ); - endp = tp + IN6ADDRSZ; - colonp = NULL; - /* Leading :: requires some special handling. */ - if(*src == ':') - if(*++src != ':') - return (0); - curtok = src; - saw_xdigit = 0; - val = 0; - while((ch = *src++) != '\0') { - const char *pch; - - pch = strchr((xdigits = xdigits_l), ch); - if(!pch) - pch = strchr((xdigits = xdigits_u), ch); - if(pch != NULL) { - val <<= 4; - val |= (pch - xdigits); - if(++saw_xdigit > 4) - return (0); - continue; - } - if(ch == ':') { - curtok = src; - if(!saw_xdigit) { - if(colonp) - return (0); - colonp = tp; - continue; - } - if(tp + INT16SZ > endp) - return (0); - *tp++ = (unsigned char) ((val >> 8) & 0xff); - *tp++ = (unsigned char) (val & 0xff); - saw_xdigit = 0; - val = 0; - continue; - } - if(ch == '.' && ((tp + INADDRSZ) <= endp) && - inet_pton4(curtok, tp) > 0) { - tp += INADDRSZ; - saw_xdigit = 0; - break; /* '\0' was seen by inet_pton4(). */ - } - return (0); - } - if(saw_xdigit) { - if(tp + INT16SZ > endp) - return (0); - *tp++ = (unsigned char) ((val >> 8) & 0xff); - *tp++ = (unsigned char) (val & 0xff); - } - if(colonp != NULL) { - /* - * Since some memmove()'s erroneously fail to handle - * overlapping regions, we'll do the shift by hand. - */ - const ssize_t n = tp - colonp; - ssize_t i; - - if(tp == endp) - return (0); - for(i = 1; i <= n; i++) { - *(endp - i) = *(colonp + n - i); - *(colonp + n - i) = 0; - } - tp = endp; - } - if(tp != endp) - return (0); - memcpy(dst, tmp, IN6ADDRSZ); - return (1); -} -#endif /* ENABLE_IPV6 */ - -#endif /* HAVE_INET_PTON */ diff --git a/dep/cpr/opt/curl/lib/inet_pton.h b/dep/cpr/opt/curl/lib/inet_pton.h deleted file mode 100644 index e216f4efa9a..00000000000 --- a/dep/cpr/opt/curl/lib/inet_pton.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef HEADER_CURL_INET_PTON_H -#define HEADER_CURL_INET_PTON_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -int Curl_inet_pton(int, const char *, void *); - -#ifdef HAVE_INET_PTON -#ifdef HAVE_ARPA_INET_H -#include -#elif defined(HAVE_WS2TCPIP_H) -/* inet_pton() exists in Vista or later */ -#include -#endif -#define Curl_inet_pton(x,y,z) inet_pton(x,y,z) -#endif - -#endif /* HEADER_CURL_INET_PTON_H */ - diff --git a/dep/cpr/opt/curl/lib/krb5.c b/dep/cpr/opt/curl/lib/krb5.c deleted file mode 100644 index 69a35979a89..00000000000 --- a/dep/cpr/opt/curl/lib/krb5.c +++ /dev/null @@ -1,342 +0,0 @@ -/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c - * - * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * Copyright (c) 2004 - 2016 Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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 "curl_setup.h" - -#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) - -#ifdef HAVE_NETDB_H -#include -#endif - -#include "urldata.h" -#include "curl_base64.h" -#include "ftp.h" -#include "curl_gssapi.h" -#include "sendf.h" -#include "curl_sec.h" -#include "warnless.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -static int -krb5_init(void *app_data) -{ - gss_ctx_id_t *context = app_data; - /* Make sure our context is initialized for krb5_end. */ - *context = GSS_C_NO_CONTEXT; - return 0; -} - -static int -krb5_check_prot(void *app_data, int level) -{ - (void)app_data; /* unused */ - if(level == PROT_CONFIDENTIAL) - return -1; - return 0; -} - -static int -krb5_decode(void *app_data, void *buf, int len, - int level UNUSED_PARAM, - struct connectdata *conn UNUSED_PARAM) -{ - gss_ctx_id_t *context = app_data; - OM_uint32 maj, min; - gss_buffer_desc enc, dec; - - (void)level; - (void)conn; - - enc.value = buf; - enc.length = len; - maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL); - if(maj != GSS_S_COMPLETE) { - if(len >= 4) - strcpy(buf, "599 "); - return -1; - } - - memcpy(buf, dec.value, dec.length); - len = curlx_uztosi(dec.length); - gss_release_buffer(&min, &dec); - - return len; -} - -static int -krb5_overhead(void *app_data, int level, int len) -{ - /* no arguments are used */ - (void)app_data; - (void)level; - (void)len; - return 0; -} - -static int -krb5_encode(void *app_data, const void *from, int length, int level, void **to) -{ - gss_ctx_id_t *context = app_data; - gss_buffer_desc dec, enc; - OM_uint32 maj, min; - int state; - int len; - - /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal - * libraries modify the input buffer in gss_seal() - */ - dec.value = (void *)from; - dec.length = length; - maj = gss_seal(&min, *context, - level == PROT_PRIVATE, - GSS_C_QOP_DEFAULT, - &dec, &state, &enc); - - if(maj != GSS_S_COMPLETE) - return -1; - - /* malloc a new buffer, in case gss_release_buffer doesn't work as - expected */ - *to = malloc(enc.length); - if(!*to) - return -1; - memcpy(*to, enc.value, enc.length); - len = curlx_uztosi(enc.length); - gss_release_buffer(&min, &enc); - return len; -} - -static int -krb5_auth(void *app_data, struct connectdata *conn) -{ - int ret = AUTH_OK; - char *p; - const char *host = conn->host.name; - ssize_t nread; - curl_socklen_t l = sizeof(conn->local_addr); - struct Curl_easy *data = conn->data; - CURLcode result; - const char *service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : - "ftp"; - const char *srv_host = "host"; - gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp; - OM_uint32 maj, min; - gss_name_t gssname; - gss_ctx_id_t *context = app_data; - struct gss_channel_bindings_struct chan; - size_t base64_sz = 0; - struct sockaddr_in **remote_addr = - (struct sockaddr_in **)&conn->ip_addr->ai_addr; - char *stringp; - - if(getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)&conn->local_addr, &l) < 0) - perror("getsockname()"); - - chan.initiator_addrtype = GSS_C_AF_INET; - chan.initiator_address.length = l - 4; - chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; - chan.acceptor_addrtype = GSS_C_AF_INET; - chan.acceptor_address.length = l - 4; - chan.acceptor_address.value = &(*remote_addr)->sin_addr.s_addr; - chan.application_data.length = 0; - chan.application_data.value = NULL; - - /* this loop will execute twice (once for service, once for host) */ - for(;;) { - /* this really shouldn't be repeated here, but can't help it */ - if(service == srv_host) { - result = Curl_ftpsend(conn, "AUTH GSSAPI"); - if(result) - return -2; - - if(Curl_GetFTPResponse(&nread, conn, NULL)) - return -1; - - if(data->state.buffer[0] != '3') - return -1; - } - - stringp = aprintf("%s@%s", service, host); - if(!stringp) - return -2; - - input_buffer.value = stringp; - input_buffer.length = strlen(stringp); - maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE, - &gssname); - free(stringp); - if(maj != GSS_S_COMPLETE) { - gss_release_name(&min, &gssname); - if(service == srv_host) { - Curl_failf(data, "Error importing service name %s@%s", service, host); - return AUTH_ERROR; - } - service = srv_host; - continue; - } - /* We pass NULL as |output_name_type| to avoid a leak. */ - gss_display_name(&min, gssname, &output_buffer, NULL); - Curl_infof(data, "Trying against %s\n", output_buffer.value); - gssresp = GSS_C_NO_BUFFER; - *context = GSS_C_NO_CONTEXT; - - do { - /* Release the buffer at each iteration to avoid leaking: the first time - we are releasing the memory from gss_display_name. The last item is - taken care by a final gss_release_buffer. */ - gss_release_buffer(&min, &output_buffer); - ret = AUTH_OK; - maj = Curl_gss_init_sec_context(data, - &min, - context, - gssname, - &Curl_krb5_mech_oid, - &chan, - gssresp, - &output_buffer, - TRUE, - NULL); - - if(gssresp) { - free(_gssresp.value); - gssresp = NULL; - } - - if(GSS_ERROR(maj)) { - Curl_infof(data, "Error creating security context\n"); - ret = AUTH_ERROR; - break; - } - - if(output_buffer.length != 0) { - char *cmd; - - result = Curl_base64_encode(data, (char *)output_buffer.value, - output_buffer.length, &p, &base64_sz); - if(result) { - Curl_infof(data, "base64-encoding: %s\n", - curl_easy_strerror(result)); - ret = AUTH_ERROR; - break; - } - - cmd = aprintf("ADAT %s", p); - if(cmd) - result = Curl_ftpsend(conn, cmd); - else - result = CURLE_OUT_OF_MEMORY; - - free(p); - - if(result) { - ret = -2; - break; - } - - if(Curl_GetFTPResponse(&nread, conn, NULL)) { - ret = -1; - break; - } - - if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') { - Curl_infof(data, "Server didn't accept auth data\n"); - ret = AUTH_ERROR; - break; - } - - p = data->state.buffer + 4; - p = strstr(p, "ADAT="); - if(p) { - result = Curl_base64_decode(p + 5, - (unsigned char **)&_gssresp.value, - &_gssresp.length); - if(result) { - Curl_failf(data, "base64-decoding: %s", - curl_easy_strerror(result)); - ret = AUTH_CONTINUE; - break; - } - } - - gssresp = &_gssresp; - } - } while(maj == GSS_S_CONTINUE_NEEDED); - - gss_release_name(&min, &gssname); - gss_release_buffer(&min, &output_buffer); - - if(gssresp) - free(_gssresp.value); - - if(ret == AUTH_OK || service == srv_host) - return ret; - - service = srv_host; - } - return ret; -} - -static void krb5_end(void *app_data) -{ - OM_uint32 min; - gss_ctx_id_t *context = app_data; - if(*context != GSS_C_NO_CONTEXT) { -#ifdef DEBUGBUILD - OM_uint32 maj = -#endif - gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER); - DEBUGASSERT(maj == GSS_S_COMPLETE); - } -} - -struct Curl_sec_client_mech Curl_krb5_client_mech = { - "GSSAPI", - sizeof(gss_ctx_id_t), - krb5_init, - krb5_auth, - krb5_end, - krb5_check_prot, - krb5_overhead, - krb5_encode, - krb5_decode -}; - -#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */ diff --git a/dep/cpr/opt/curl/lib/ldap.c b/dep/cpr/opt/curl/lib/ldap.c deleted file mode 100644 index 040641cf8e1..00000000000 --- a/dep/cpr/opt/curl/lib/ldap.c +++ /dev/null @@ -1,1085 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP) - -/* - * Notice that USE_OPENLDAP is only a source code selection switch. When - * libcurl is built with USE_OPENLDAP defined the libcurl source code that - * gets compiled is the code from openldap.c, otherwise the code that gets - * compiled is the code from ldap.c. - * - * When USE_OPENLDAP is defined a recent version of the OpenLDAP library - * might be required for compilation and runtime. In order to use ancient - * OpenLDAP library versions, USE_OPENLDAP shall not be defined. - */ - -#ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */ -# include -# ifndef LDAP_VENDOR_NAME -# error Your Platform SDK is NOT sufficient for LDAP support! \ - Update your Platform SDK, or disable LDAP support! -# else -# include -# endif -#else -# define LDAP_DEPRECATED 1 /* Be sure ldap_init() is defined. */ -# ifdef HAVE_LBER_H -# include -# endif -# include -# if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H)) -# include -# endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */ -#endif - -/* These are macros in both (in above ) and typedefs - * in BoringSSL's - */ -#ifdef HAVE_BORINGSSL -# undef X509_NAME -# undef X509_CERT_PAIR -# undef X509_EXTENSIONS -#endif - -#include "urldata.h" -#include -#include "sendf.h" -#include "escape.h" -#include "progress.h" -#include "transfer.h" -#include "strcase.h" -#include "strtok.h" -#include "curl_ldap.h" -#include "curl_multibyte.h" -#include "curl_base64.h" -#include "connect.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifndef HAVE_LDAP_URL_PARSE - -/* Use our own implementation. */ - -typedef struct { - char *lud_host; - int lud_port; -#if defined(USE_WIN32_LDAP) - TCHAR *lud_dn; - TCHAR **lud_attrs; -#else - char *lud_dn; - char **lud_attrs; -#endif - int lud_scope; -#if defined(USE_WIN32_LDAP) - TCHAR *lud_filter; -#else - char *lud_filter; -#endif - char **lud_exts; - size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the - "real" struct so can only be used in code - without HAVE_LDAP_URL_PARSE defined */ -} CURL_LDAPURLDesc; - -#undef LDAPURLDesc -#define LDAPURLDesc CURL_LDAPURLDesc - -static int _ldap_url_parse(const struct connectdata *conn, - LDAPURLDesc **ludp); -static void _ldap_free_urldesc(LDAPURLDesc *ludp); - -#undef ldap_free_urldesc -#define ldap_free_urldesc _ldap_free_urldesc -#endif - -#ifdef DEBUG_LDAP - #define LDAP_TRACE(x) do { \ - _ldap_trace("%u: ", __LINE__); \ - _ldap_trace x; \ - } WHILE_FALSE - - static void _ldap_trace(const char *fmt, ...); -#else - #define LDAP_TRACE(x) Curl_nop_stmt -#endif - - -static CURLcode Curl_ldap(struct connectdata *conn, bool *done); - -/* - * LDAP protocol handler. - */ - -const struct Curl_handler Curl_handler_ldap = { - "LDAP", /* scheme */ - ZERO_NULL, /* setup_connection */ - Curl_ldap, /* do_it */ - ZERO_NULL, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_LDAP, /* defport */ - CURLPROTO_LDAP, /* protocol */ - PROTOPT_NONE /* flags */ -}; - -#ifdef HAVE_LDAP_SSL -/* - * LDAPS protocol handler. - */ - -const struct Curl_handler Curl_handler_ldaps = { - "LDAPS", /* scheme */ - ZERO_NULL, /* setup_connection */ - Curl_ldap, /* do_it */ - ZERO_NULL, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_LDAPS, /* defport */ - CURLPROTO_LDAPS, /* protocol */ - PROTOPT_SSL /* flags */ -}; -#endif - -#if defined(USE_WIN32_LDAP) - -#if defined(USE_WINDOWS_SSPI) -static int ldap_win_bind_auth(LDAP *server, const char *user, - const char *passwd, unsigned long authflags) -{ - ULONG method = 0; - SEC_WINNT_AUTH_IDENTITY cred = { 0, }; - int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; - -#if defined(USE_SPNEGO) - if(authflags & CURLAUTH_NEGOTIATE) { - method = LDAP_AUTH_NEGOTIATE; - } - else -#endif -#if defined(USE_NTLM) - if(authflags & CURLAUTH_NTLM) { - method = LDAP_AUTH_NTLM; - } - else -#endif -#if !defined(CURL_DISABLE_CRYPTO_AUTH) - if(authflags & CURLAUTH_DIGEST) { - method = LDAP_AUTH_DIGEST; - } - else -#endif - { - /* required anyway if one of upper preprocessor definitions enabled */ - } - - if(method && user && passwd) { - rc = Curl_create_sspi_identity(user, passwd, &cred); - if(!rc) { - rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method); - Curl_sspi_free_identity(&cred); - } - } - else { - /* proceed with current user credentials */ - method = LDAP_AUTH_NEGOTIATE; - rc = ldap_bind_s(server, NULL, NULL, method); - } - return rc; -} -#endif /* #if defined(USE_WINDOWS_SSPI) */ - -static int ldap_win_bind(struct connectdata *conn, LDAP *server, - const char *user, const char *passwd) -{ - int rc = LDAP_INVALID_CREDENTIALS; - - PTCHAR inuser = NULL; - PTCHAR inpass = NULL; - - if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) { - inuser = Curl_convert_UTF8_to_tchar((char *) user); - inpass = Curl_convert_UTF8_to_tchar((char *) passwd); - - rc = ldap_simple_bind_s(server, inuser, inpass); - - Curl_unicodefree(inuser); - Curl_unicodefree(inpass); - } -#if defined(USE_WINDOWS_SSPI) - else { - rc = ldap_win_bind_auth(server, user, passwd, conn->data->set.httpauth); - } -#endif - - return rc; -} -#endif /* #if defined(USE_WIN32_LDAP) */ - -static CURLcode Curl_ldap(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - int rc = 0; - LDAP *server = NULL; - LDAPURLDesc *ludp = NULL; - LDAPMessage *ldapmsg = NULL; - LDAPMessage *entryIterator; - int num = 0; - struct Curl_easy *data = conn->data; - int ldap_proto = LDAP_VERSION3; - int ldap_ssl = 0; - char *val_b64 = NULL; - size_t val_b64_sz = 0; - curl_off_t dlsize = 0; -#ifdef LDAP_OPT_NETWORK_TIMEOUT - struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */ -#endif -#if defined(USE_WIN32_LDAP) - TCHAR *host = NULL; -#else - char *host = NULL; -#endif - char *user = NULL; - char *passwd = NULL; - - *done = TRUE; /* unconditionally */ - infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n", - LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION); - infof(data, "LDAP local: %s\n", data->change.url); - -#ifdef HAVE_LDAP_URL_PARSE - rc = ldap_url_parse(data->change.url, &ludp); -#else - rc = _ldap_url_parse(conn, &ludp); -#endif - if(rc != 0) { - failf(data, "LDAP local: %s", ldap_err2string(rc)); - result = CURLE_LDAP_INVALID_URL; - goto quit; - } - - /* Get the URL scheme (either ldap or ldaps) */ - if(conn->given->flags & PROTOPT_SSL) - ldap_ssl = 1; - infof(data, "LDAP local: trying to establish %s connection\n", - ldap_ssl ? "encrypted" : "cleartext"); - -#if defined(USE_WIN32_LDAP) - host = Curl_convert_UTF8_to_tchar(conn->host.name); - if(!host) { - result = CURLE_OUT_OF_MEMORY; - - goto quit; - } -#else - host = conn->host.name; -#endif - - if(conn->bits.user_passwd) { - user = conn->user; - passwd = conn->passwd; - } - -#ifdef LDAP_OPT_NETWORK_TIMEOUT - ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); -#endif - ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); - - if(ldap_ssl) { -#ifdef HAVE_LDAP_SSL -#ifdef USE_WIN32_LDAP - /* Win32 LDAP SDK doesn't support insecure mode without CA! */ - server = ldap_sslinit(host, (int)conn->port, 1); - ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); -#else - int ldap_option; - char *ldap_ca = conn->ssl_config.CAfile; -#if defined(CURL_HAS_NOVELL_LDAPSDK) - rc = ldapssl_client_init(NULL, NULL); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc)); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } - if(conn->ssl_config.verifypeer) { - /* Novell SDK supports DER or BASE64 files. */ - int cert_type = LDAPSSL_CERT_FILETYPE_B64; - if((data->set.ssl.cert_type) && - (strcasecompare(data->set.ssl.cert_type, "DER"))) - cert_type = LDAPSSL_CERT_FILETYPE_DER; - if(!ldap_ca) { - failf(data, "LDAP local: ERROR %s CA cert not set!", - (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM")); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } - infof(data, "LDAP local: using %s CA cert '%s'\n", - (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), - ldap_ca); - rc = ldapssl_add_trusted_cert(ldap_ca, cert_type); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ERROR setting %s CA cert: %s", - (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), - ldap_err2string(rc)); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } - ldap_option = LDAPSSL_VERIFY_SERVER; - } - else - ldap_option = LDAPSSL_VERIFY_NONE; - rc = ldapssl_set_verify_mode(ldap_option); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ERROR setting cert verify mode: %s", - ldap_err2string(rc)); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } - server = ldapssl_init(host, (int)conn->port, 1); - if(server == NULL) { - failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.dispname, conn->port); - result = CURLE_COULDNT_CONNECT; - goto quit; - } -#elif defined(LDAP_OPT_X_TLS) - if(conn->ssl_config.verifypeer) { - /* OpenLDAP SDK supports BASE64 files. */ - if((data->set.ssl.cert_type) && - (!strcasecompare(data->set.ssl.cert_type, "PEM"))) { - failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } - if(!ldap_ca) { - failf(data, "LDAP local: ERROR PEM CA cert not set!"); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } - infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca); - rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ERROR setting PEM CA cert: %s", - ldap_err2string(rc)); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } - ldap_option = LDAP_OPT_X_TLS_DEMAND; - } - else - ldap_option = LDAP_OPT_X_TLS_NEVER; - - rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ERROR setting cert verify mode: %s", - ldap_err2string(rc)); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } - server = ldap_init(host, (int)conn->port); - if(server == NULL) { - failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.dispname, conn->port); - result = CURLE_COULDNT_CONNECT; - goto quit; - } - ldap_option = LDAP_OPT_X_TLS_HARD; - rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s", - ldap_err2string(rc)); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } -/* - rc = ldap_start_tls_s(server, NULL, NULL); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", - ldap_err2string(rc)); - result = CURLE_SSL_CERTPROBLEM; - goto quit; - } -*/ -#else - /* we should probably never come up to here since configure - should check in first place if we can support LDAP SSL/TLS */ - failf(data, "LDAP local: SSL/TLS not supported with this version " - "of the OpenLDAP toolkit\n"); - result = CURLE_SSL_CERTPROBLEM; - goto quit; -#endif -#endif -#endif /* CURL_LDAP_USE_SSL */ - } - else { - server = ldap_init(host, (int)conn->port); - if(server == NULL) { - failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.dispname, conn->port); - result = CURLE_COULDNT_CONNECT; - goto quit; - } - } -#ifdef USE_WIN32_LDAP - ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); -#endif - -#ifdef USE_WIN32_LDAP - rc = ldap_win_bind(conn, server, user, passwd); -#else - rc = ldap_simple_bind_s(server, user, passwd); -#endif - if(!ldap_ssl && rc != 0) { - ldap_proto = LDAP_VERSION2; - ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); -#ifdef USE_WIN32_LDAP - rc = ldap_win_bind(conn, server, user, passwd); -#else - rc = ldap_simple_bind_s(server, user, passwd); -#endif - } - if(rc != 0) { - failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc)); - result = CURLE_LDAP_CANNOT_BIND; - goto quit; - } - - rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg); - - if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { - failf(data, "LDAP remote: %s", ldap_err2string(rc)); - result = CURLE_LDAP_SEARCH_FAILED; - goto quit; - } - - for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg); - entryIterator; - entryIterator = ldap_next_entry(server, entryIterator), num++) { - BerElement *ber = NULL; -#if defined(USE_WIN32_LDAP) - TCHAR *attribute; -#else - char *attribute; /*! suspicious that this isn't 'const' */ -#endif - int i; - - /* Get the DN and write it to the client */ - { - char *name; - size_t name_len; -#if defined(USE_WIN32_LDAP) - TCHAR *dn = ldap_get_dn(server, entryIterator); - name = Curl_convert_tchar_to_UTF8(dn); - if(!name) { - ldap_memfree(dn); - - result = CURLE_OUT_OF_MEMORY; - - goto quit; - } -#else - char *dn = name = ldap_get_dn(server, entryIterator); -#endif - name_len = strlen(name); - - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - if(result) { -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(name); -#endif - ldap_memfree(dn); - - goto quit; - } - - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name, - name_len); - if(result) { -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(name); -#endif - ldap_memfree(dn); - - goto quit; - } - - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); - if(result) { -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(name); -#endif - ldap_memfree(dn); - - goto quit; - } - - dlsize += name_len + 5; - -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(name); -#endif - ldap_memfree(dn); - } - - /* Get the attributes and write them to the client */ - for(attribute = ldap_first_attribute(server, entryIterator, &ber); - attribute; - attribute = ldap_next_attribute(server, entryIterator, ber)) { - BerValue **vals; - size_t attr_len; -#if defined(USE_WIN32_LDAP) - char *attr = Curl_convert_tchar_to_UTF8(attribute); - if(!attr) { - if(ber) - ber_free(ber, 0); - - result = CURLE_OUT_OF_MEMORY; - - goto quit; - } -#else - char *attr = attribute; -#endif - attr_len = strlen(attr); - - vals = ldap_get_values_len(server, entryIterator, attribute); - if(vals != NULL) { - for(i = 0; (vals[i] != NULL); i++) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - if(result) { - ldap_value_free_len(vals); -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); -#endif - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - result = Curl_client_write(conn, CLIENTWRITE_BODY, - (char *) attr, attr_len); - if(result) { - ldap_value_free_len(vals); -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); -#endif - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); - if(result) { - ldap_value_free_len(vals); -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); -#endif - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - dlsize += attr_len + 3; - - if((attr_len > 7) && - (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) { - /* Binary attribute, encode to base64. */ - result = Curl_base64_encode(data, - vals[i]->bv_val, - vals[i]->bv_len, - &val_b64, - &val_b64_sz); - if(result) { - ldap_value_free_len(vals); -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); -#endif - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - if(val_b64_sz > 0) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, - val_b64_sz); - free(val_b64); - if(result) { - ldap_value_free_len(vals); -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); -#endif - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - dlsize += val_b64_sz; - } - } - else { - result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, - vals[i]->bv_len); - if(result) { - ldap_value_free_len(vals); -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); -#endif - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - dlsize += vals[i]->bv_len; - } - - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); - if(result) { - ldap_value_free_len(vals); -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); -#endif - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - dlsize++; - } - - /* Free memory used to store values */ - ldap_value_free_len(vals); - } - - /* Free the attribute as we are done with it */ -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); -#endif - ldap_memfree(attribute); - - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); - if(result) - goto quit; - dlsize++; - Curl_pgrsSetDownloadCounter(data, dlsize); - } - - if(ber) - ber_free(ber, 0); - } - -quit: - if(ldapmsg) { - ldap_msgfree(ldapmsg); - LDAP_TRACE(("Received %d entries\n", num)); - } - if(rc == LDAP_SIZELIMIT_EXCEEDED) - infof(data, "There are more than %d entries\n", num); - if(ludp) - ldap_free_urldesc(ludp); - if(server) - ldap_unbind_s(server); -#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK) - if(ldap_ssl) - ldapssl_client_deinit(); -#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */ - -#if defined(USE_WIN32_LDAP) - Curl_unicodefree(host); -#endif - - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - connclose(conn, "LDAP connection always disable re-use"); - - return result; -} - -#ifdef DEBUG_LDAP -static void _ldap_trace(const char *fmt, ...) -{ - static int do_trace = -1; - va_list args; - - if(do_trace == -1) { - const char *env = getenv("CURL_TRACE"); - do_trace = (env && strtol(env, NULL, 10) > 0); - } - if(!do_trace) - return; - - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); -} -#endif - -#ifndef HAVE_LDAP_URL_PARSE - -/* - * Return scope-value for a scope-string. - */ -static int str2scope(const char *p) -{ - if(strcasecompare(p, "one")) - return LDAP_SCOPE_ONELEVEL; - if(strcasecompare(p, "onetree")) - return LDAP_SCOPE_ONELEVEL; - if(strcasecompare(p, "base")) - return LDAP_SCOPE_BASE; - if(strcasecompare(p, "sub")) - return LDAP_SCOPE_SUBTREE; - if(strcasecompare(p, "subtree")) - return LDAP_SCOPE_SUBTREE; - return (-1); -} - -/* - * Split 'str' into strings separated by commas. - * Note: out[] points into 'str'. - */ -static bool split_str(char *str, char ***out, size_t *count) -{ - char **res; - char *lasts; - char *s; - size_t i; - size_t items = 1; - - s = strchr(str, ','); - while(s) { - items++; - s = strchr(++s, ','); - } - - res = calloc(items, sizeof(char *)); - if(!res) - return FALSE; - - for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items; - s = strtok_r(NULL, ",", &lasts), i++) - res[i] = s; - - *out = res; - *count = items; - - return TRUE; -} - -/* - * Break apart the pieces of an LDAP URL. - * Syntax: - * ldap://:/???? - * - * already known from 'conn->host.name'. - * already known from 'conn->remote_port'. - * extract the rest from 'conn->data->state.path+1'. All fields are optional. - * e.g. - * ldap://:/??? - * yields ludp->lud_dn = "". - * - * Defined in RFC4516 section 2. - */ -static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) -{ - int rc = LDAP_SUCCESS; - char *path; - char *p; - char *q; - size_t i; - - if(!conn->data || - !conn->data->state.path || - conn->data->state.path[0] != '/' || - !checkprefix("LDAP", conn->data->change.url)) - return LDAP_INVALID_SYNTAX; - - ludp->lud_scope = LDAP_SCOPE_BASE; - ludp->lud_port = conn->remote_port; - ludp->lud_host = conn->host.name; - - /* Duplicate the path */ - p = path = strdup(conn->data->state.path + 1); - if(!path) - return LDAP_NO_MEMORY; - - /* Parse the DN (Distinguished Name) */ - q = strchr(p, '?'); - if(q) - *q++ = '\0'; - - if(*p) { - char *dn = p; - char *unescaped; - CURLcode result; - - LDAP_TRACE(("DN '%s'\n", dn)); - - /* Unescape the DN */ - result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE); - if(result) { - rc = LDAP_NO_MEMORY; - - goto quit; - } - -#if defined(USE_WIN32_LDAP) - /* Convert the unescaped string to a tchar */ - ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped); - - /* Free the unescaped string as we are done with it */ - Curl_unicodefree(unescaped); - - if(!ludp->lud_dn) { - rc = LDAP_NO_MEMORY; - - goto quit; - } -#else - ludp->lud_dn = unescaped; -#endif - } - - p = q; - if(!p) - goto quit; - - /* Parse the attributes. skip "??" */ - q = strchr(p, '?'); - if(q) - *q++ = '\0'; - - if(*p) { - char **attributes; - size_t count = 0; - - /* Split the string into an array of attributes */ - if(!split_str(p, &attributes, &count)) { - rc = LDAP_NO_MEMORY; - - goto quit; - } - - /* Allocate our array (+1 for the NULL entry) */ -#if defined(USE_WIN32_LDAP) - ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *)); -#else - ludp->lud_attrs = calloc(count + 1, sizeof(char *)); -#endif - if(!ludp->lud_attrs) { - free(attributes); - - rc = LDAP_NO_MEMORY; - - goto quit; - } - - for(i = 0; i < count; i++) { - char *unescaped; - CURLcode result; - - LDAP_TRACE(("attr[%d] '%s'\n", i, attributes[i])); - - /* Unescape the attribute */ - result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL, - FALSE); - if(result) { - free(attributes); - - rc = LDAP_NO_MEMORY; - - goto quit; - } - -#if defined(USE_WIN32_LDAP) - /* Convert the unescaped string to a tchar */ - ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped); - - /* Free the unescaped string as we are done with it */ - Curl_unicodefree(unescaped); - - if(!ludp->lud_attrs[i]) { - free(attributes); - - rc = LDAP_NO_MEMORY; - - goto quit; - } -#else - ludp->lud_attrs[i] = unescaped; -#endif - - ludp->lud_attrs_dups++; - } - - free(attributes); - } - - p = q; - if(!p) - goto quit; - - /* Parse the scope. skip "??" */ - q = strchr(p, '?'); - if(q) - *q++ = '\0'; - - if(*p) { - ludp->lud_scope = str2scope(p); - if(ludp->lud_scope == -1) { - rc = LDAP_INVALID_SYNTAX; - - goto quit; - } - LDAP_TRACE(("scope %d\n", ludp->lud_scope)); - } - - p = q; - if(!p) - goto quit; - - /* Parse the filter */ - q = strchr(p, '?'); - if(q) - *q++ = '\0'; - - if(*p) { - char *filter = p; - char *unescaped; - CURLcode result; - - LDAP_TRACE(("filter '%s'\n", filter)); - - /* Unescape the filter */ - result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE); - if(result) { - rc = LDAP_NO_MEMORY; - - goto quit; - } - -#if defined(USE_WIN32_LDAP) - /* Convert the unescaped string to a tchar */ - ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped); - - /* Free the unescaped string as we are done with it */ - Curl_unicodefree(unescaped); - - if(!ludp->lud_filter) { - rc = LDAP_NO_MEMORY; - - goto quit; - } -#else - ludp->lud_filter = unescaped; -#endif - } - - p = q; - if(p && !*p) { - rc = LDAP_INVALID_SYNTAX; - - goto quit; - } - -quit: - free(path); - - return rc; -} - -static int _ldap_url_parse(const struct connectdata *conn, - LDAPURLDesc **ludpp) -{ - LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); - int rc; - - *ludpp = NULL; - if(!ludp) - return LDAP_NO_MEMORY; - - rc = _ldap_url_parse2(conn, ludp); - if(rc != LDAP_SUCCESS) { - _ldap_free_urldesc(ludp); - ludp = NULL; - } - *ludpp = ludp; - return (rc); -} - -static void _ldap_free_urldesc(LDAPURLDesc *ludp) -{ - size_t i; - - if(!ludp) - return; - - free(ludp->lud_dn); - free(ludp->lud_filter); - - if(ludp->lud_attrs) { - for(i = 0; i < ludp->lud_attrs_dups; i++) - free(ludp->lud_attrs[i]); - free(ludp->lud_attrs); - } - - free(ludp); -} -#endif /* !HAVE_LDAP_URL_PARSE */ -#endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */ diff --git a/dep/cpr/opt/curl/lib/libcurl.plist b/dep/cpr/opt/curl/lib/libcurl.plist deleted file mode 100644 index 622f66cfbf6..00000000000 --- a/dep/cpr/opt/curl/lib/libcurl.plist +++ /dev/null @@ -1,35 +0,0 @@ - - - - - CFBundleInfoDictionaryVersion - 6.0 - - CFBundleDevelopmentRegion - English - - CFBundleExecutable - curl - - CFBundleIdentifier - se.haxx.curl.libcurl - - CFBundleVersion - 7.12.3 - - CFBundleName - libcurl - - CFBundlePackageType - FMWK - - CFBundleSignature - ???? - - CFBundleShortVersionString - libcurl 7.12.3 - - CFBundleGetInfoString - libcurl.plist 7.12.3 - - diff --git a/dep/cpr/opt/curl/lib/libcurl.rc b/dep/cpr/opt/curl/lib/libcurl.rc deleted file mode 100644 index 3316fba191a..00000000000 --- a/dep/cpr/opt/curl/lib/libcurl.rc +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include -#include "../include/curl/curlver.h" - -LANGUAGE 0x09,0x01 - -#define RC_VERSION LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0 - -VS_VERSION_INFO VERSIONINFO - FILEVERSION RC_VERSION - PRODUCTVERSION RC_VERSION - FILEFLAGSMASK 0x3fL -#if defined(DEBUGBUILD) || defined(_DEBUG) - FILEFLAGS 1 -#else - FILEFLAGS 0 -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE 0x0L - -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "The curl library, https://curl.haxx.se/\0" - VALUE "FileDescription", "libcurl Shared Library\0" - VALUE "FileVersion", LIBCURL_VERSION "\0" - VALUE "InternalName", "libcurl\0" - VALUE "OriginalFilename", "libcurl.dll\0" - VALUE "ProductName", "The curl library\0" - VALUE "ProductVersion", LIBCURL_VERSION "\0" - VALUE "LegalCopyright", "\xa9 " LIBCURL_COPYRIGHT "\0" /* a9: Copyright symbol */ - VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" - END - END - - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END diff --git a/dep/cpr/opt/curl/lib/libcurl.vers.in b/dep/cpr/opt/curl/lib/libcurl.vers.in deleted file mode 100644 index ae978a485d3..00000000000 --- a/dep/cpr/opt/curl/lib/libcurl.vers.in +++ /dev/null @@ -1,13 +0,0 @@ -HIDDEN -{ - local: - __*; - _rest*; - _save*; -}; - -CURL_@CURL_LT_SHLIB_VERSIONED_FLAVOUR@4 -{ - global: curl_*; - local: *; -}; diff --git a/dep/cpr/opt/curl/lib/llist.c b/dep/cpr/opt/curl/lib/llist.c deleted file mode 100644 index 4bb0a51b865..00000000000 --- a/dep/cpr/opt/curl/lib/llist.c +++ /dev/null @@ -1,193 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "llist.h" -#include "curl_memory.h" - -/* this must be the last include file */ -#include "memdebug.h" - -/* - * @unittest: 1300 - */ -void -Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor) -{ - l->size = 0; - l->dtor = dtor; - l->head = NULL; - l->tail = NULL; -} - -/* - * Curl_llist_insert_next() - * - * Inserts a new list element after the given one 'e'. If the given existing - * entry is NULL and the list already has elements, the new one will be - * inserted first in the list. - * - * The 'ne' argument should be a pointer into the object to store. - * - * @unittest: 1300 - */ -void -Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, - const void *p, - struct curl_llist_element *ne) -{ - ne->ptr = (void *) p; - if(list->size == 0) { - list->head = ne; - list->head->prev = NULL; - list->head->next = NULL; - list->tail = ne; - } - else { - /* if 'e' is NULL here, we insert the new element first in the list */ - ne->next = e?e->next:list->head; - ne->prev = e; - if(!e) { - list->head->prev = ne; - list->head = ne; - } - else if(e->next) { - e->next->prev = ne; - } - else { - list->tail = ne; - } - if(e) - e->next = ne; - } - - ++list->size; -} - -/* - * @unittest: 1300 - */ -void -Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, - void *user) -{ - void *ptr; - if(e == NULL || list->size == 0) - return; - - if(e == list->head) { - list->head = e->next; - - if(list->head == NULL) - list->tail = NULL; - else - e->next->prev = NULL; - } - else { - e->prev->next = e->next; - if(!e->next) - list->tail = e->prev; - else - e->next->prev = e->prev; - } - - ptr = e->ptr; - - e->ptr = NULL; - e->prev = NULL; - e->next = NULL; - - --list->size; - - /* call the dtor() last for when it actually frees the 'e' memory itself */ - if(list->dtor) - list->dtor(user, ptr); -} - -void -Curl_llist_destroy(struct curl_llist *list, void *user) -{ - if(list) { - while(list->size > 0) - Curl_llist_remove(list, list->tail, user); - } -} - -size_t -Curl_llist_count(struct curl_llist *list) -{ - return list->size; -} - -/* - * @unittest: 1300 - */ -void Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e, - struct curl_llist *to_list, - struct curl_llist_element *to_e) -{ - /* Remove element from list */ - if(e == NULL || list->size == 0) - return; - - if(e == list->head) { - list->head = e->next; - - if(list->head == NULL) - list->tail = NULL; - else - e->next->prev = NULL; - } - else { - e->prev->next = e->next; - if(!e->next) - list->tail = e->prev; - else - e->next->prev = e->prev; - } - - --list->size; - - /* Add element to to_list after to_e */ - if(to_list->size == 0) { - to_list->head = e; - to_list->head->prev = NULL; - to_list->head->next = NULL; - to_list->tail = e; - } - else { - e->next = to_e->next; - e->prev = to_e; - if(to_e->next) { - to_e->next->prev = e; - } - else { - to_list->tail = e; - } - to_e->next = e; - } - - ++to_list->size; -} diff --git a/dep/cpr/opt/curl/lib/llist.h b/dep/cpr/opt/curl/lib/llist.h deleted file mode 100644 index 6b644b99c85..00000000000 --- a/dep/cpr/opt/curl/lib/llist.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef HEADER_CURL_LLIST_H -#define HEADER_CURL_LLIST_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" -#include - -typedef void (*curl_llist_dtor)(void *, void *); - -struct curl_llist_element { - void *ptr; - struct curl_llist_element *prev; - struct curl_llist_element *next; -}; - -struct curl_llist { - struct curl_llist_element *head; - struct curl_llist_element *tail; - curl_llist_dtor dtor; - size_t size; -}; - -void Curl_llist_init(struct curl_llist *, curl_llist_dtor); -void Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *, - const void *, struct curl_llist_element *node); -void Curl_llist_remove(struct curl_llist *, struct curl_llist_element *, - void *); -size_t Curl_llist_count(struct curl_llist *); -void Curl_llist_destroy(struct curl_llist *, void *); -void Curl_llist_move(struct curl_llist *, struct curl_llist_element *, - struct curl_llist *, struct curl_llist_element *); - -#endif /* HEADER_CURL_LLIST_H */ - diff --git a/dep/cpr/opt/curl/lib/makefile.amiga b/dep/cpr/opt/curl/lib/makefile.amiga deleted file mode 100644 index c692e5ebe36..00000000000 --- a/dep/cpr/opt/curl/lib/makefile.amiga +++ /dev/null @@ -1,21 +0,0 @@ -# -# libcurl Makefile for AmigaOS ... -# - -# change the follow to where you have the AmiTCP SDK v4.3 includes: - -ATCPSDKI= /GG/netinclude - - -CC = m68k-amigaos-gcc -CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall - -include Makefile.inc -OBJS = $(CSOURCES:.c=.o) - -all: $(OBJS) - ar cru libcurl.a $(OBJS) - ranlib libcurl.a - -install: - $(INSTALL) -c ./libcurl.a /lib/libcurl.a diff --git a/dep/cpr/opt/curl/lib/makefile.dj b/dep/cpr/opt/curl/lib/makefile.dj deleted file mode 100644 index 8ab2d575dab..00000000000 --- a/dep/cpr/opt/curl/lib/makefile.dj +++ /dev/null @@ -1,72 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2003 - 2008, Gisle Vanem . -# Copyright (C) 2003 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -# -# Adapted for djgpp2 / Watt-32 / DOS -# - -DEPEND_PREREQ = curl_config.h -VPATH = vtls vauth -TOPDIR = .. - -include ../packages/DOS/common.dj -include Makefile.inc - -CFLAGS += -DBUILDING_LIBCURL - -SOURCES = $(sort $(CSOURCES)) -OBJECTS = $(addprefix $(OBJ_DIR)/, $(notdir $(SOURCES:.c=.o))) - -CURL_LIB = libcurl.a - -all: $(OBJ_DIR) curl_config.h $(CURL_LIB) - -$(CURL_LIB): $(OBJECTS) - ar rs $@ $? - -curl_config.h: config-dos.h - $(COPY) $^ $@ - -# clean generated files -# -genclean: - - $(DELETE) curl_config.h - -# clean object files and subdir -# -objclean: genclean - - $(DELETE) $(OBJ_DIR)$(DS)*.o - - $(RMDIR) $(OBJ_DIR) - -# clean without removing built library -# -clean: objclean - - $(DELETE) depend.dj - -# clean everything -# -realclean vclean: clean - - $(DELETE) $(CURL_LIB) - --include depend.dj - diff --git a/dep/cpr/opt/curl/lib/md4.c b/dep/cpr/opt/curl/lib/md4.c deleted file mode 100644 index 2bb7dcc25ae..00000000000 --- a/dep/cpr/opt/curl/lib/md4.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. - * MD4 Message-Digest Algorithm (RFC 1320). - * - * Homepage: - http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 - * - * Author: - * Alexander Peslyak, better known as Solar Designer - * - * This software was written by Alexander Peslyak in 2001. No copyright is - * claimed, and the software is hereby placed in the public domain. In case - * this attempt to disclaim copyright and place the software in the public - * domain is deemed null and void, then the software is Copyright (c) 2001 - * Alexander Peslyak and it is hereby released to the general public under the - * following terms: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted. - * - * There's ABSOLUTELY NO WARRANTY, express or implied. - * - * (This is a heavily cut-down "BSD license".) - * - * This differs from Colin Plumb's older public domain implementation in that - * no exactly 32-bit integer data type is required (any 32-bit or wider - * unsigned integer data type will do), there's no compile-time endianness - * configuration, and the function prototypes match OpenSSL's. No code from - * Colin Plumb's implementation has been reused; this comment merely compares - * the properties of the two independent implementations. - * - * The primary goals of this implementation are portability and ease of use. - * It is meant to be fast, but not as fast as possible. Some known - * optimizations are not included to reduce source code size and avoid - * compile-time configuration. - */ - -#include "curl_setup.h" - -/* The NSS, OS/400 and sometimes mbed TLS crypto libraries do not provide the - * MD4 hash algorithm, so we have a local implementation of it */ -#if defined(USE_NSS) || defined(USE_OS400CRYPTO) || \ - (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) - -#include "curl_md4.h" -#include "warnless.h" - -#ifndef HAVE_OPENSSL - -#include - -/* Any 32-bit or wider unsigned integer data type will do */ -typedef unsigned int MD4_u32plus; - -typedef struct { - MD4_u32plus lo, hi; - MD4_u32plus a, b, c, d; - unsigned char buffer[64]; - MD4_u32plus block[16]; -} MD4_CTX; - -static void MD4_Init(MD4_CTX *ctx); -static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size); -static void MD4_Final(unsigned char *result, MD4_CTX *ctx); - -/* - * The basic MD4 functions. - * - * F and G are optimized compared to their RFC 1320 definitions, with the - * optimization for F borrowed from Colin Plumb's MD5 implementation. - */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) - -/* - * The MD4 transformation for all three rounds. - */ -#define STEP(f, a, b, c, d, x, s) \ - (a) += f((b), (c), (d)) + (x); \ - (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); - -/* - * SET reads 4 input bytes in little-endian byte order and stores them - * in a properly aligned word in host byte order. - * - * The check for little-endian architectures that tolerate unaligned - * memory accesses is just an optimization. Nothing will break if it - * doesn't work. - */ -#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) -#define SET(n) \ - (*(MD4_u32plus *)(void *)&ptr[(n) * 4]) -#define GET(n) \ - SET(n) -#else -#define SET(n) \ - (ctx->block[(n)] = \ - (MD4_u32plus)ptr[(n) * 4] | \ - ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \ - ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \ - ((MD4_u32plus)ptr[(n) * 4 + 3] << 24)) -#define GET(n) \ - (ctx->block[(n)]) -#endif - -/* - * This processes one or more 64-byte data blocks, but does NOT update - * the bit counters. There are no alignment requirements. - */ -static const void *body(MD4_CTX *ctx, const void *data, unsigned long size) -{ - const unsigned char *ptr; - MD4_u32plus a, b, c, d; - MD4_u32plus saved_a, saved_b, saved_c, saved_d; - - ptr = (const unsigned char *)data; - - a = ctx->a; - b = ctx->b; - c = ctx->c; - d = ctx->d; - - do { - saved_a = a; - saved_b = b; - saved_c = c; - saved_d = d; - -/* Round 1 */ - STEP(F, a, b, c, d, SET(0), 3) - STEP(F, d, a, b, c, SET(1), 7) - STEP(F, c, d, a, b, SET(2), 11) - STEP(F, b, c, d, a, SET(3), 19) - STEP(F, a, b, c, d, SET(4), 3) - STEP(F, d, a, b, c, SET(5), 7) - STEP(F, c, d, a, b, SET(6), 11) - STEP(F, b, c, d, a, SET(7), 19) - STEP(F, a, b, c, d, SET(8), 3) - STEP(F, d, a, b, c, SET(9), 7) - STEP(F, c, d, a, b, SET(10), 11) - STEP(F, b, c, d, a, SET(11), 19) - STEP(F, a, b, c, d, SET(12), 3) - STEP(F, d, a, b, c, SET(13), 7) - STEP(F, c, d, a, b, SET(14), 11) - STEP(F, b, c, d, a, SET(15), 19) - -/* Round 2 */ - STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3) - STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5) - STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9) - STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13) - STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3) - STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5) - STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9) - STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13) - STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3) - STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5) - STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9) - STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13) - STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3) - STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5) - STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9) - STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13) - -/* Round 3 */ - STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3) - STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9) - STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11) - STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15) - STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3) - STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9) - STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11) - STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15) - STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3) - STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9) - STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11) - STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15) - STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3) - STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9) - STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11) - STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15) - - a += saved_a; - b += saved_b; - c += saved_c; - d += saved_d; - - ptr += 64; - } while(size -= 64); - - ctx->a = a; - ctx->b = b; - ctx->c = c; - ctx->d = d; - - return ptr; -} - -static void MD4_Init(MD4_CTX *ctx) -{ - ctx->a = 0x67452301; - ctx->b = 0xefcdab89; - ctx->c = 0x98badcfe; - ctx->d = 0x10325476; - - ctx->lo = 0; - ctx->hi = 0; -} - -static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) -{ - MD4_u32plus saved_lo; - unsigned long used, available; - - saved_lo = ctx->lo; - ctx->lo = (saved_lo + size) & 0x1fffffff; - if(ctx->lo < saved_lo) - ctx->hi++; - ctx->hi += (MD4_u32plus)size >> 29; - - used = saved_lo & 0x3f; - - if(used) { - available = 64 - used; - - if(size < available) { - memcpy(&ctx->buffer[used], data, size); - return; - } - - memcpy(&ctx->buffer[used], data, available); - data = (const unsigned char *)data + available; - size -= available; - body(ctx, ctx->buffer, 64); - } - - if(size >= 64) { - data = body(ctx, data, size & ~(unsigned long)0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - -static void MD4_Final(unsigned char *result, MD4_CTX *ctx) -{ - unsigned long used, available; - - used = ctx->lo & 0x3f; - - ctx->buffer[used++] = 0x80; - - available = 64 - used; - - if(available < 8) { - memset(&ctx->buffer[used], 0, available); - body(ctx, ctx->buffer, 64); - used = 0; - available = 64; - } - - memset(&ctx->buffer[used], 0, available - 8); - - ctx->lo <<= 3; - ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); - ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); - ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); - ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff); - ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); - ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); - ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); - ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); - - body(ctx, ctx->buffer, 64); - - result[0] = curlx_ultouc((ctx->a)&0xff); - result[1] = curlx_ultouc((ctx->a >> 8)&0xff); - result[2] = curlx_ultouc((ctx->a >> 16)&0xff); - result[3] = curlx_ultouc(ctx->a >> 24); - result[4] = curlx_ultouc((ctx->b)&0xff); - result[5] = curlx_ultouc((ctx->b >> 8)&0xff); - result[6] = curlx_ultouc((ctx->b >> 16)&0xff); - result[7] = curlx_ultouc(ctx->b >> 24); - result[8] = curlx_ultouc((ctx->c)&0xff); - result[9] = curlx_ultouc((ctx->c >> 8)&0xff); - result[10] = curlx_ultouc((ctx->c >> 16)&0xff); - result[11] = curlx_ultouc(ctx->c >> 24); - result[12] = curlx_ultouc((ctx->d)&0xff); - result[13] = curlx_ultouc((ctx->d >> 8)&0xff); - result[14] = curlx_ultouc((ctx->d >> 16)&0xff); - result[15] = curlx_ultouc(ctx->d >> 24); - - memset(ctx, 0, sizeof(*ctx)); -} - -#endif - -void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len) -{ - MD4_CTX ctx; - MD4_Init(&ctx); - MD4_Update(&ctx, input, curlx_uztoui(len)); - MD4_Final(output, &ctx); -} -#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) || - (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) */ diff --git a/dep/cpr/opt/curl/lib/md5.c b/dep/cpr/opt/curl/lib/md5.c deleted file mode 100644 index 80301a14125..00000000000 --- a/dep/cpr/opt/curl/lib/md5.c +++ /dev/null @@ -1,563 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_CRYPTO_AUTH - -#include - -#include "curl_md5.h" -#include "curl_hmac.h" -#include "warnless.h" - -#if defined(USE_GNUTLS_NETTLE) - -#include -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -typedef struct md5_ctx MD5_CTX; - -static void MD5_Init(MD5_CTX * ctx) -{ - md5_init(ctx); -} - -static void MD5_Update(MD5_CTX * ctx, - const unsigned char *input, - unsigned int inputLen) -{ - md5_update(ctx, inputLen, input); -} - -static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx) -{ - md5_digest(ctx, 16, digest); -} - -#elif defined(USE_GNUTLS) - -#include -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -typedef gcry_md_hd_t MD5_CTX; - -static void MD5_Init(MD5_CTX * ctx) -{ - gcry_md_open(ctx, GCRY_MD_MD5, 0); -} - -static void MD5_Update(MD5_CTX * ctx, - const unsigned char *input, - unsigned int inputLen) -{ - gcry_md_write(*ctx, input, inputLen); -} - -static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx) -{ - memcpy(digest, gcry_md_read(*ctx, 0), 16); - gcry_md_close(*ctx); -} - -#elif defined(USE_OPENSSL) -/* When OpenSSL is available we use the MD5-function from OpenSSL */ -#include -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ - (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ - (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ - (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) - -/* For Apple operating systems: CommonCrypto has the functions we need. - These functions are available on Tiger and later, as well as iOS 2.0 - and later. If you're building for an older cat, well, sorry. - - Declaring the functions as static like this seems to be a bit more - reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */ -# include -# define MD5_CTX CC_MD5_CTX -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -static void MD5_Init(MD5_CTX *ctx) -{ - CC_MD5_Init(ctx); -} - -static void MD5_Update(MD5_CTX *ctx, - const unsigned char *input, - unsigned int inputLen) -{ - CC_MD5_Update(ctx, input, inputLen); -} - -static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) -{ - CC_MD5_Final(digest, ctx); -} - -#elif defined(_WIN32) && !defined(CURL_WINDOWS_APP) - -#include -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -typedef struct { - HCRYPTPROV hCryptProv; - HCRYPTHASH hHash; -} MD5_CTX; - -static void MD5_Init(MD5_CTX *ctx) -{ - if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, - PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); - } -} - -static void MD5_Update(MD5_CTX *ctx, - const unsigned char *input, - unsigned int inputLen) -{ - CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); -} - -static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) -{ - unsigned long length = 0; - CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); - if(length == 16) - CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); - if(ctx->hHash) - CryptDestroyHash(ctx->hHash); - if(ctx->hCryptProv) - CryptReleaseContext(ctx->hCryptProv, 0); -} - -#elif defined(USE_AXTLS) -#include -#include -#include -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" -#else -/* When no other crypto library is available we use this code segment */ -/* - * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. - * MD5 Message-Digest Algorithm (RFC 1321). - * - * Homepage: - http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 - * - * Author: - * Alexander Peslyak, better known as Solar Designer - * - * This software was written by Alexander Peslyak in 2001. No copyright is - * claimed, and the software is hereby placed in the public domain. - * In case this attempt to disclaim copyright and place the software in the - * public domain is deemed null and void, then the software is - * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the - * general public under the following terms: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted. - * - * There's ABSOLUTELY NO WARRANTY, express or implied. - * - * (This is a heavily cut-down "BSD license".) - * - * This differs from Colin Plumb's older public domain implementation in that - * no exactly 32-bit integer data type is required (any 32-bit or wider - * unsigned integer data type will do), there's no compile-time endianness - * configuration, and the function prototypes match OpenSSL's. No code from - * Colin Plumb's implementation has been reused; this comment merely compares - * the properties of the two independent implementations. - * - * The primary goals of this implementation are portability and ease of use. - * It is meant to be fast, but not as fast as possible. Some known - * optimizations are not included to reduce source code size and avoid - * compile-time configuration. - */ - -#include - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* Any 32-bit or wider unsigned integer data type will do */ -typedef unsigned int MD5_u32plus; - -typedef struct { - MD5_u32plus lo, hi; - MD5_u32plus a, b, c, d; - unsigned char buffer[64]; - MD5_u32plus block[16]; -} MD5_CTX; - -static void MD5_Init(MD5_CTX *ctx); -static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); -static void MD5_Final(unsigned char *result, MD5_CTX *ctx); - -/* - * The basic MD5 functions. - * - * F and G are optimized compared to their RFC 1321 definitions for - * architectures that lack an AND-NOT instruction, just like in Colin Plumb's - * implementation. - */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) -#define H(x, y, z) (((x) ^ (y)) ^ (z)) -#define H2(x, y, z) ((x) ^ ((y) ^ (z))) -#define I(x, y, z) ((y) ^ ((x) | ~(z))) - -/* - * The MD5 transformation for all four rounds. - */ -#define STEP(f, a, b, c, d, x, t, s) \ - (a) += f((b), (c), (d)) + (x) + (t); \ - (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ - (a) += (b); - -/* - * SET reads 4 input bytes in little-endian byte order and stores them - * in a properly aligned word in host byte order. - * - * The check for little-endian architectures that tolerate unaligned - * memory accesses is just an optimization. Nothing will break if it - * doesn't work. - */ -#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) -#define SET(n) \ - (*(MD5_u32plus *)(void *)&ptr[(n) * 4]) -#define GET(n) \ - SET(n) -#else -#define SET(n) \ - (ctx->block[(n)] = \ - (MD5_u32plus)ptr[(n) * 4] | \ - ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ - ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ - ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) -#define GET(n) \ - (ctx->block[(n)]) -#endif - -/* - * This processes one or more 64-byte data blocks, but does NOT update - * the bit counters. There are no alignment requirements. - */ -static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) -{ - const unsigned char *ptr; - MD5_u32plus a, b, c, d; - MD5_u32plus saved_a, saved_b, saved_c, saved_d; - - ptr = (const unsigned char *)data; - - a = ctx->a; - b = ctx->b; - c = ctx->c; - d = ctx->d; - - do { - saved_a = a; - saved_b = b; - saved_c = c; - saved_d = d; - -/* Round 1 */ - STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) - STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) - STEP(F, c, d, a, b, SET(2), 0x242070db, 17) - STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) - STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) - STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) - STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) - STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) - STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) - STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) - STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) - STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) - STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) - STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) - STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) - STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) - -/* Round 2 */ - STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) - STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) - STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) - STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) - STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) - STEP(G, d, a, b, c, GET(10), 0x02441453, 9) - STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) - STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) - STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) - STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) - STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) - STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) - STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) - STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) - STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) - STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) - -/* Round 3 */ - STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) - STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) - STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) - STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) - STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) - STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) - STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) - STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) - STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) - STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) - STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) - STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) - STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) - STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) - STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) - STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) - -/* Round 4 */ - STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) - STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) - STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) - STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) - STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) - STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) - STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) - STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) - STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) - STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) - STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) - STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) - STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) - STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) - STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) - STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) - - a += saved_a; - b += saved_b; - c += saved_c; - d += saved_d; - - ptr += 64; - } while(size -= 64); - - ctx->a = a; - ctx->b = b; - ctx->c = c; - ctx->d = d; - - return ptr; -} - -static void MD5_Init(MD5_CTX *ctx) -{ - ctx->a = 0x67452301; - ctx->b = 0xefcdab89; - ctx->c = 0x98badcfe; - ctx->d = 0x10325476; - - ctx->lo = 0; - ctx->hi = 0; -} - -static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) -{ - MD5_u32plus saved_lo; - unsigned long used, available; - - saved_lo = ctx->lo; - ctx->lo = (saved_lo + size) & 0x1fffffff; - if(ctx->lo < saved_lo) - ctx->hi++; - ctx->hi += (MD5_u32plus)size >> 29; - - used = saved_lo & 0x3f; - - if(used) { - available = 64 - used; - - if(size < available) { - memcpy(&ctx->buffer[used], data, size); - return; - } - - memcpy(&ctx->buffer[used], data, available); - data = (const unsigned char *)data + available; - size -= available; - body(ctx, ctx->buffer, 64); - } - - if(size >= 64) { - data = body(ctx, data, size & ~(unsigned long)0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - -static void MD5_Final(unsigned char *result, MD5_CTX *ctx) -{ - unsigned long used, available; - - used = ctx->lo & 0x3f; - - ctx->buffer[used++] = 0x80; - - available = 64 - used; - - if(available < 8) { - memset(&ctx->buffer[used], 0, available); - body(ctx, ctx->buffer, 64); - used = 0; - available = 64; - } - - memset(&ctx->buffer[used], 0, available - 8); - - ctx->lo <<= 3; - ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); - ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); - ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); - ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24); - ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); - ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); - ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); - ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); - - body(ctx, ctx->buffer, 64); - - result[0] = curlx_ultouc((ctx->a)&0xff); - result[1] = curlx_ultouc((ctx->a >> 8)&0xff); - result[2] = curlx_ultouc((ctx->a >> 16)&0xff); - result[3] = curlx_ultouc(ctx->a >> 24); - result[4] = curlx_ultouc((ctx->b)&0xff); - result[5] = curlx_ultouc((ctx->b >> 8)&0xff); - result[6] = curlx_ultouc((ctx->b >> 16)&0xff); - result[7] = curlx_ultouc(ctx->b >> 24); - result[8] = curlx_ultouc((ctx->c)&0xff); - result[9] = curlx_ultouc((ctx->c >> 8)&0xff); - result[10] = curlx_ultouc((ctx->c >> 16)&0xff); - result[11] = curlx_ultouc(ctx->c >> 24); - result[12] = curlx_ultouc((ctx->d)&0xff); - result[13] = curlx_ultouc((ctx->d >> 8)&0xff); - result[14] = curlx_ultouc((ctx->d >> 16)&0xff); - result[15] = curlx_ultouc(ctx->d >> 24); - - memset(ctx, 0, sizeof(*ctx)); -} - -#endif /* CRYPTO LIBS */ - -const HMAC_params Curl_HMAC_MD5[] = { - { - (HMAC_hinit_func) MD5_Init, /* Hash initialization function. */ - (HMAC_hupdate_func) MD5_Update, /* Hash update function. */ - (HMAC_hfinal_func) MD5_Final, /* Hash computation end function. */ - sizeof(MD5_CTX), /* Size of hash context structure. */ - 64, /* Maximum key length. */ - 16 /* Result size. */ - } -}; - -const MD5_params Curl_DIGEST_MD5[] = { - { - (Curl_MD5_init_func) MD5_Init, /* Digest initialization function */ - (Curl_MD5_update_func) MD5_Update, /* Digest update function */ - (Curl_MD5_final_func) MD5_Final, /* Digest computation end function */ - sizeof(MD5_CTX), /* Size of digest context struct */ - 16 /* Result size */ - } -}; - -/* - * @unittest: 1601 - */ -void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */ - const unsigned char *input) -{ - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, input, curlx_uztoui(strlen((char *)input))); - MD5_Final(outbuffer, &ctx); -} - -MD5_context *Curl_MD5_init(const MD5_params *md5params) -{ - MD5_context *ctxt; - - /* Create MD5 context */ - ctxt = malloc(sizeof *ctxt); - - if(!ctxt) - return ctxt; - - ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize); - - if(!ctxt->md5_hashctx) { - free(ctxt); - return NULL; - } - - ctxt->md5_hash = md5params; - - (*md5params->md5_init_func)(ctxt->md5_hashctx); - - return ctxt; -} - -int Curl_MD5_update(MD5_context *context, - const unsigned char *data, - unsigned int len) -{ - (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len); - - return 0; -} - -int Curl_MD5_final(MD5_context *context, unsigned char *result) -{ - (*context->md5_hash->md5_final_func)(result, context->md5_hashctx); - - free(context->md5_hashctx); - free(context); - - return 0; -} - -#endif /* CURL_DISABLE_CRYPTO_AUTH */ diff --git a/dep/cpr/opt/curl/lib/memdebug.c b/dep/cpr/opt/curl/lib/memdebug.c deleted file mode 100644 index 0eb249ce9d6..00000000000 --- a/dep/cpr/opt/curl/lib/memdebug.c +++ /dev/null @@ -1,485 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef CURLDEBUG - -#include - -#include "urldata.h" - -#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Until 2011-08-17 libcurl's Memory Tracking feature also performed - * automatic malloc and free filling operations using 0xA5 and 0x13 - * values. Our own preinitialization of dynamically allocated memory - * might be useful when not using third party memory debuggers, but - * on the other hand this would fool memory debuggers into thinking - * that all dynamically allocated memory is properly initialized. - * - * As a default setting, libcurl's Memory Tracking feature no longer - * performs preinitialization of dynamically allocated memory on its - * own. If you know what you are doing, and really want to retain old - * behavior, you can achieve this compiling with preprocessor symbols - * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate - * values. - */ - -#ifdef CURL_MT_MALLOC_FILL -# if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff) -# error "invalid CURL_MT_MALLOC_FILL or out of range" -# endif -#endif - -#ifdef CURL_MT_FREE_FILL -# if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff) -# error "invalid CURL_MT_FREE_FILL or out of range" -# endif -#endif - -#if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL) -# if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL) -# error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL" -# endif -#endif - -#ifdef CURL_MT_MALLOC_FILL -# define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len)) -#else -# define mt_malloc_fill(buf,len) Curl_nop_stmt -#endif - -#ifdef CURL_MT_FREE_FILL -# define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len)) -#else -# define mt_free_fill(buf,len) Curl_nop_stmt -#endif - -struct memdebug { - size_t size; - union { - curl_off_t o; - double d; - void *p; - } mem[1]; - /* I'm hoping this is the thing with the strictest alignment - * requirements. That also means we waste some space :-( */ -}; - -/* - * Note that these debug functions are very simple and they are meant to - * remain so. For advanced analysis, record a log file and write perl scripts - * to analyze them! - * - * Don't use these with multithreaded test programs! - */ - -#define logfile curl_debuglogfile -FILE *curl_debuglogfile = NULL; -static bool memlimit = FALSE; /* enable memory limit */ -static long memsize = 0; /* set number of mallocs allowed */ - -/* this sets the log file name */ -void curl_memdebug(const char *logname) -{ - if(!logfile) { - if(logname && *logname) - logfile = fopen(logname, FOPEN_WRITETEXT); - else - logfile = stderr; -#ifdef MEMDEBUG_LOG_SYNC - /* Flush the log file after every line so the log isn't lost in a crash */ - if(logfile) - setbuf(logfile, (char *)NULL); -#endif - } -} - -/* This function sets the number of malloc() calls that should return - successfully! */ -void curl_memlimit(long limit) -{ - if(!memlimit) { - memlimit = TRUE; - memsize = limit; - } -} - -/* returns TRUE if this isn't allowed! */ -static bool countcheck(const char *func, int line, const char *source) -{ - /* if source is NULL, then the call is made internally and this check - should not be made */ - if(memlimit && source) { - if(!memsize) { - if(source) { - /* log to file */ - curl_memlog("LIMIT %s:%d %s reached memlimit\n", - source, line, func); - /* log to stderr also */ - fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", - source, line, func); - fflush(logfile); /* because it might crash now */ - } - errno = ENOMEM; - return TRUE; /* RETURN ERROR! */ - } - else - memsize--; /* countdown */ - - - } - - return FALSE; /* allow this */ -} - -void *curl_domalloc(size_t wantedsize, int line, const char *source) -{ - struct memdebug *mem; - size_t size; - - DEBUGASSERT(wantedsize != 0); - - if(countcheck("malloc", line, source)) - return NULL; - - /* alloc at least 64 bytes */ - size = sizeof(struct memdebug) + wantedsize; - - mem = (Curl_cmalloc)(size); - if(mem) { - /* fill memory with junk */ - mt_malloc_fill(mem->mem, wantedsize); - mem->size = wantedsize; - } - - if(source) - curl_memlog("MEM %s:%d malloc(%zu) = %p\n", - source, line, wantedsize, - mem ? (void *)mem->mem : (void *)0); - - return (mem ? mem->mem : NULL); -} - -void *curl_docalloc(size_t wanted_elements, size_t wanted_size, - int line, const char *source) -{ - struct memdebug *mem; - size_t size, user_size; - - DEBUGASSERT(wanted_elements != 0); - DEBUGASSERT(wanted_size != 0); - - if(countcheck("calloc", line, source)) - return NULL; - - /* alloc at least 64 bytes */ - user_size = wanted_size * wanted_elements; - size = sizeof(struct memdebug) + user_size; - - mem = (Curl_ccalloc)(1, size); - if(mem) - mem->size = user_size; - - if(source) - curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n", - source, line, wanted_elements, wanted_size, - mem ? (void *)mem->mem : (void *)0); - - return (mem ? mem->mem : NULL); -} - -char *curl_dostrdup(const char *str, int line, const char *source) -{ - char *mem; - size_t len; - - DEBUGASSERT(str != NULL); - - if(countcheck("strdup", line, source)) - return NULL; - - len = strlen(str) + 1; - - mem = curl_domalloc(len, 0, NULL); /* NULL prevents logging */ - if(mem) - memcpy(mem, str, len); - - if(source) - curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n", - source, line, (const void *)str, len, (const void *)mem); - - return mem; -} - -#if defined(WIN32) && defined(UNICODE) -wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source) -{ - wchar_t *mem; - size_t wsiz, bsiz; - - DEBUGASSERT(str != NULL); - - if(countcheck("wcsdup", line, source)) - return NULL; - - wsiz = wcslen(str) + 1; - bsiz = wsiz * sizeof(wchar_t); - - mem = curl_domalloc(bsiz, 0, NULL); /* NULL prevents logging */ - if(mem) - memcpy(mem, str, bsiz); - - if(source) - curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n", - source, line, (void *)str, bsiz, (void *)mem); - - return mem; -} -#endif - -/* We provide a realloc() that accepts a NULL as pointer, which then - performs a malloc(). In order to work with ares. */ -void *curl_dorealloc(void *ptr, size_t wantedsize, - int line, const char *source) -{ - struct memdebug *mem = NULL; - - size_t size = sizeof(struct memdebug) + wantedsize; - - DEBUGASSERT(wantedsize != 0); - - if(countcheck("realloc", line, source)) - return NULL; - -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:1684) - /* 1684: conversion from pointer to same-sized integral type */ -#endif - - if(ptr) - mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif - - mem = (Curl_crealloc)(mem, size); - if(source) - curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n", - source, line, (void *)ptr, wantedsize, - mem ? (void *)mem->mem : (void *)0); - - if(mem) { - mem->size = wantedsize; - return mem->mem; - } - - return NULL; -} - -void curl_dofree(void *ptr, int line, const char *source) -{ - struct memdebug *mem; - - if(ptr) { - -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:1684) - /* 1684: conversion from pointer to same-sized integral type */ -#endif - - mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif - - /* destroy */ - mt_free_fill(mem->mem, mem->size); - - /* free for real */ - (Curl_cfree)(mem); - } - - if(source) - curl_memlog("MEM %s:%d free(%p)\n", source, line, (void *)ptr); -} - -curl_socket_t curl_socket(int domain, int type, int protocol, - int line, const char *source) -{ - const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d socket() = %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d socket() = %ld\n" : - "FD %s:%d socket() = %zd\n"; - - curl_socket_t sockfd = socket(domain, type, protocol); - - if(source && (sockfd != CURL_SOCKET_BAD)) - curl_memlog(fmt, source, line, sockfd); - - return sockfd; -} - -#ifdef HAVE_SOCKETPAIR -int curl_socketpair(int domain, int type, int protocol, - curl_socket_t socket_vector[2], - int line, const char *source) -{ - const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d socketpair() = %d %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d socketpair() = %ld %ld\n" : - "FD %s:%d socketpair() = %zd %zd\n"; - - int res = socketpair(domain, type, protocol, socket_vector); - - if(source && (0 == res)) - curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]); - - return res; -} -#endif - -curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, - int line, const char *source) -{ - const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d accept() = %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d accept() = %ld\n" : - "FD %s:%d accept() = %zd\n"; - - struct sockaddr *addr = (struct sockaddr *)saddr; - curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; - - curl_socket_t sockfd = accept(s, addr, addrlen); - - if(source && (sockfd != CURL_SOCKET_BAD)) - curl_memlog(fmt, source, line, sockfd); - - return sockfd; -} - -/* separate function to allow libcurl to mark a "faked" close */ -void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source) -{ - const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d sclose(%d)\n": - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d sclose(%ld)\n": - "FD %s:%d sclose(%zd)\n"; - - if(source) - curl_memlog(fmt, source, line, sockfd); -} - -/* this is our own defined way to close sockets on *ALL* platforms */ -int curl_sclose(curl_socket_t sockfd, int line, const char *source) -{ - int res = sclose(sockfd); - curl_mark_sclose(sockfd, line, source); - return res; -} - -FILE *curl_fopen(const char *file, const char *mode, - int line, const char *source) -{ - FILE *res = fopen(file, mode); - - if(source) - curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", - source, line, file, mode, (void *)res); - - return res; -} - -#ifdef HAVE_FDOPEN -FILE *curl_fdopen(int filedes, const char *mode, - int line, const char *source) -{ - FILE *res = fdopen(filedes, mode); - - if(source) - curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", - source, line, filedes, mode, (void *)res); - - return res; -} -#endif - -int curl_fclose(FILE *file, int line, const char *source) -{ - int res; - - DEBUGASSERT(file != NULL); - - res = fclose(file); - - if(source) - curl_memlog("FILE %s:%d fclose(%p)\n", - source, line, (void *)file); - - return res; -} - -#define LOGLINE_BUFSIZE 1024 - -/* this does the writing to the memory tracking log file */ -void curl_memlog(const char *format, ...) -{ - char *buf; - int nchars; - va_list ap; - - if(!logfile) - return; - - buf = (Curl_cmalloc)(LOGLINE_BUFSIZE); - if(!buf) - return; - - va_start(ap, format); - nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap); - va_end(ap); - - if(nchars > LOGLINE_BUFSIZE - 1) - nchars = LOGLINE_BUFSIZE - 1; - - if(nchars > 0) - fwrite(buf, 1, (size_t)nchars, logfile); - - (Curl_cfree)(buf); -} - -#endif /* CURLDEBUG */ diff --git a/dep/cpr/opt/curl/lib/memdebug.h b/dep/cpr/opt/curl/lib/memdebug.h deleted file mode 100644 index 835dab38c7f..00000000000 --- a/dep/cpr/opt/curl/lib/memdebug.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef HEADER_CURL_MEMDEBUG_H -#define HEADER_CURL_MEMDEBUG_H -#ifdef CURLDEBUG -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * CAUTION: this header is designed to work when included by the app-side - * as well as the library. Do not mix with library internals! - */ - -#define CURL_MT_LOGFNAME_BUFSIZE 512 - -#define logfile curl_debuglogfile - -extern FILE *logfile; - -/* memory functions */ -CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source); -CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line, - const char *source); -CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, - const char *source); -CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source); -CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source); -#if defined(WIN32) && defined(UNICODE) -CURL_EXTERN wchar_t *curl_dowcsdup(const wchar_t *str, int line, - const char *source); -#endif - -CURL_EXTERN void curl_memdebug(const char *logname); -CURL_EXTERN void curl_memlimit(long limit); -CURL_EXTERN void curl_memlog(const char *format, ...); - -/* file descriptor manipulators */ -CURL_EXTERN curl_socket_t curl_socket(int domain, int type, int protocol, - int line, const char *source); -CURL_EXTERN void curl_mark_sclose(curl_socket_t sockfd, - int line, const char *source); -CURL_EXTERN int curl_sclose(curl_socket_t sockfd, - int line, const char *source); -CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen, - int line, const char *source); -#ifdef HAVE_SOCKETPAIR -CURL_EXTERN int curl_socketpair(int domain, int type, int protocol, - curl_socket_t socket_vector[2], - int line, const char *source); -#endif - -/* FILE functions */ -CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line, - const char *source); -#ifdef HAVE_FDOPEN -CURL_EXTERN FILE *curl_fdopen(int filedes, const char *mode, int line, - const char *source); -#endif -CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); - -#ifndef MEMDEBUG_NODEFINES - -/* Set this symbol on the command-line, recompile all lib-sources */ -#undef strdup -#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__) -#define malloc(size) curl_domalloc(size, __LINE__, __FILE__) -#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__) -#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__) -#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__) - -#ifdef WIN32 -# ifdef UNICODE -# undef wcsdup -# define wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) -# undef _wcsdup -# define _wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) -# undef _tcsdup -# define _tcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) -# else -# undef _tcsdup -# define _tcsdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__) -# endif -#endif - -#undef socket -#define socket(domain,type,protocol)\ - curl_socket(domain, type, protocol, __LINE__, __FILE__) -#undef accept /* for those with accept as a macro */ -#define accept(sock,addr,len)\ - curl_accept(sock, addr, len, __LINE__, __FILE__) -#ifdef HAVE_SOCKETPAIR -#define socketpair(domain,type,protocol,socket_vector)\ - curl_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__) -#endif - -#ifdef HAVE_GETADDRINFO -#if defined(getaddrinfo) && defined(__osf__) -/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define - our macro as for other platforms. Instead, we redefine the new name they - define getaddrinfo to become! */ -#define ogetaddrinfo(host,serv,hint,res) \ - curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__) -#else -#undef getaddrinfo -#define getaddrinfo(host,serv,hint,res) \ - curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__) -#endif -#endif /* HAVE_GETADDRINFO */ - -#ifdef HAVE_GETNAMEINFO -#undef getnameinfo -#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \ - curl_dogetnameinfo(sa, salen, host, hostlen, serv, servlen, flags, \ - __LINE__, __FILE__) -#endif /* HAVE_GETNAMEINFO */ - -#ifdef HAVE_FREEADDRINFO -#undef freeaddrinfo -#define freeaddrinfo(data) \ - curl_dofreeaddrinfo(data, __LINE__, __FILE__) -#endif /* HAVE_FREEADDRINFO */ - -/* sclose is probably already defined, redefine it! */ -#undef sclose -#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__) - -#define fake_sclose(sockfd) curl_mark_sclose(sockfd,__LINE__,__FILE__) - -#undef fopen -#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__) -#undef fdopen -#define fdopen(file,mode) curl_fdopen(file,mode,__LINE__,__FILE__) -#define fclose(file) curl_fclose(file,__LINE__,__FILE__) - -#endif /* MEMDEBUG_NODEFINES */ - -#endif /* CURLDEBUG */ - -/* -** Following section applies even when CURLDEBUG is not defined. -*/ - -#ifndef fake_sclose -#define fake_sclose(x) Curl_nop_stmt -#endif - -/* - * Curl_safefree defined as a macro to allow MemoryTracking feature - * to log free() calls at same location where Curl_safefree is used. - * This macro also assigns NULL to given pointer when free'd. - */ - -#define Curl_safefree(ptr) \ - do { free((ptr)); (ptr) = NULL;} WHILE_FALSE - -#endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/dep/cpr/opt/curl/lib/mime.c b/dep/cpr/opt/curl/lib/mime.c deleted file mode 100644 index 496f5e6fb25..00000000000 --- a/dep/cpr/opt/curl/lib/mime.c +++ /dev/null @@ -1,1860 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "mime.h" -#include "non-ascii.h" - -#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ - !defined(CURL_DISABLE_IMAP) - -#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) -#include -#endif - -#include "rand.h" -#include "slist.h" -#include "strcase.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifdef WIN32 -# ifndef R_OK -# define R_OK 4 -# endif -#endif - - -#define FILE_CONTENTTYPE_DEFAULT "application/octet-stream" -#define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed" -#define DISPOSITION_DEFAULT "attachment" - -#define READ_ERROR ((size_t) -1) - -/* Encoders. */ -static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part); -static curl_off_t encoder_nop_size(curl_mimepart *part); -static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part); -static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part); -static curl_off_t encoder_base64_size(curl_mimepart *part); -static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part); -static curl_off_t encoder_qp_size(curl_mimepart *part); - -static const mime_encoder encoders[] = { - {"binary", encoder_nop_read, encoder_nop_size}, - {"8bit", encoder_nop_read, encoder_nop_size}, - {"7bit", encoder_7bit_read, encoder_nop_size}, - {"base64", encoder_base64_read, encoder_base64_size}, - {"quoted-printable", encoder_qp_read, encoder_qp_size}, - {ZERO_NULL, ZERO_NULL, ZERO_NULL} -}; - -/* Base64 encoding table */ -static const char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* Quoted-printable character class table. - * - * We cannot rely on ctype functions since quoted-printable input data - * is assumed to be ascii-compatible, even on non-ascii platforms. */ -#define QP_OK 1 /* Can be represented by itself. */ -#define QP_SP 2 /* Space or tab. */ -#define QP_CR 3 /* Carriage return. */ -#define QP_LF 4 /* Line-feed. */ -static const unsigned char qp_class[] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */ - 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */ - QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ -}; - - -/* Binary --> hexadecimal ASCII table. */ -static const char aschex[] = - "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46"; - - - -#ifndef __VMS -#define filesize(name, stat_data) (stat_data.st_size) -#define fopen_read fopen - -#else - -#include -/* - * get_vms_file_size does what it takes to get the real size of the file - * - * For fixed files, find out the size of the EOF block and adjust. - * - * For all others, have to read the entire file in, discarding the contents. - * Most posted text files will be small, and binary files like zlib archives - * and CD/DVD images should be either a STREAM_LF format or a fixed format. - * - */ -curl_off_t VmsRealFileSize(const char *name, - const struct_stat *stat_buf) -{ - char buffer[8192]; - curl_off_t count; - int ret_stat; - FILE * file; - - file = fopen(name, FOPEN_READTEXT); /* VMS */ - if(file == NULL) - return 0; - - count = 0; - ret_stat = 1; - while(ret_stat > 0) { - ret_stat = fread(buffer, 1, sizeof(buffer), file); - if(ret_stat != 0) - count += ret_stat; - } - fclose(file); - - return count; -} - -/* - * - * VmsSpecialSize checks to see if the stat st_size can be trusted and - * if not to call a routine to get the correct size. - * - */ -static curl_off_t VmsSpecialSize(const char *name, - const struct_stat *stat_buf) -{ - switch(stat_buf->st_fab_rfm) { - case FAB$C_VAR: - case FAB$C_VFC: - return VmsRealFileSize(name, stat_buf); - break; - default: - return stat_buf->st_size; - } -} - -#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) - -/* - * vmsfopenread - * - * For upload to work as expected on VMS, different optional - * parameters must be added to the fopen command based on - * record format of the file. - * - */ -static FILE * vmsfopenread(const char *file, const char *mode) -{ - struct_stat statbuf; - int result; - - result = stat(file, &statbuf); - - switch(statbuf.st_fab_rfm) { - case FAB$C_VAR: - case FAB$C_VFC: - case FAB$C_STMCR: - return fopen(file, FOPEN_READTEXT); /* VMS */ - break; - default: - return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); - } -} - -#define fopen_read vmsfopenread -#endif - - -#ifndef HAVE_BASENAME -/* - (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 - Edition) - - The basename() function shall take the pathname pointed to by path and - return a pointer to the final component of the pathname, deleting any - trailing '/' characters. - - If the string pointed to by path consists entirely of the '/' character, - basename() shall return a pointer to the string "/". If the string pointed - to by path is exactly "//", it is implementation-defined whether '/' or "//" - is returned. - - If path is a null pointer or points to an empty string, basename() shall - return a pointer to the string ".". - - The basename() function may modify the string pointed to by path, and may - return a pointer to static storage that may then be overwritten by a - subsequent call to basename(). - - The basename() function need not be reentrant. A function that is not - required to be reentrant is not required to be thread-safe. - -*/ -static char *Curl_basename(char *path) -{ - /* Ignore all the details above for now and make a quick and simple - implementaion here */ - char *s1; - char *s2; - - s1 = strrchr(path, '/'); - s2 = strrchr(path, '\\'); - - if(s1 && s2) { - path = (s1 > s2? s1 : s2) + 1; - } - else if(s1) - path = s1 + 1; - else if(s2) - path = s2 + 1; - - return path; -} - -#define basename(x) Curl_basename((x)) -#endif - - -/* Set readback state. */ -static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr) -{ - state->state = tok; - state->ptr = ptr; - state->offset = 0; -} - - -/* Escape header string into allocated memory. */ -static char *escape_string(const char *src) -{ - size_t bytecount = 0; - size_t i; - char *dst; - - for(i = 0; src[i]; i++) - if(src[i] == '"' || src[i] == '\\') - bytecount++; - - bytecount += i; - dst = malloc(bytecount + 1); - if(!dst) - return NULL; - - for(i = 0; *src; src++) { - if(*src == '"' || *src == '\\') - dst[i++] = '\\'; - dst[i++] = *src; - } - - dst[i] = '\0'; - return dst; -} - -/* Check if header matches. */ -static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len) -{ - char *value = NULL; - - if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':') - for(value = hdr->data + len + 1; *value == ' '; value++) - ; - return value; -} - -/* Get a header from an slist. */ -static char *search_header(struct curl_slist *hdrlist, const char *hdr) -{ - size_t len = strlen(hdr); - char *value = NULL; - - for(; !value && hdrlist; hdrlist = hdrlist->next) - value = match_header(hdrlist, hdr, len); - - return value; -} - -static char *strippath(const char *fullfile) -{ - char *filename; - char *base; - filename = strdup(fullfile); /* duplicate since basename() may ruin the - buffer it works on */ - if(!filename) - return NULL; - base = strdup(basename(filename)); - - free(filename); /* free temporary buffer */ - - return base; /* returns an allocated string or NULL ! */ -} - -/* Initialize data encoder state. */ -static void cleanup_encoder_state(mime_encoder_state *p) -{ - p->pos = 0; - p->bufbeg = 0; - p->bufend = 0; -} - - -/* Dummy encoder. This is used for 8bit and binary content encodings. */ -static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part) -{ - mime_encoder_state *st = &part->encstate; - size_t insize = st->bufend - st->bufbeg; - - (void) ateof; - - if(size > insize) - size = insize; - if(size) - memcpy(buffer, st->buf, size); - st->bufbeg += size; - return size; -} - -static curl_off_t encoder_nop_size(curl_mimepart *part) -{ - return part->datasize; -} - - -/* 7bit encoder: the encoder is just a data validity check. */ -static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part) -{ - mime_encoder_state *st = &part->encstate; - size_t cursize = st->bufend - st->bufbeg; - - (void) ateof; - - if(size > cursize) - size = cursize; - - for(cursize = 0; cursize < size; cursize++) { - *buffer = st->buf[st->bufbeg]; - if(*buffer++ & 0x80) - return cursize? cursize: READ_ERROR; - st->bufbeg++; - } - - return cursize; -} - - -/* Base64 content encoder. */ -static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part) -{ - mime_encoder_state *st = &part->encstate; - size_t cursize = 0; - int i; - char *ptr = buffer; - - while(st->bufbeg < st->bufend) { - /* Line full ? */ - if(st->pos >= MAX_ENCODED_LINE_LENGTH - 4) { - /* Yes, we need 2 characters for CRLF. */ - if(size < 2) - break; - *ptr++ = '\r'; - *ptr++ = '\n'; - st->pos = 0; - cursize += 2; - size -= 2; - } - - /* Be sure there is enough space and input data for a base64 group. */ - if(size < 4 || st->bufend - st->bufbeg < 3) - break; - - /* Encode three bytes a four characters. */ - i = st->buf[st->bufbeg++] & 0xFF; - i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); - i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); - *ptr++ = base64[(i >> 18) & 0x3F]; - *ptr++ = base64[(i >> 12) & 0x3F]; - *ptr++ = base64[(i >> 6) & 0x3F]; - *ptr++ = base64[i & 0x3F]; - cursize += 4; - st->pos += 4; - size -= 4; - } - - /* If at eof, we have to flush the buffered data. */ - if(ateof && size >= 4) { - /* Buffered data size can only be 0, 1 or 2. */ - ptr[2] = ptr[3] = '='; - i = 0; - switch(st->bufend - st->bufbeg) { - case 2: - i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; - /* FALLTHROUGH */ - case 1: - i |= (st->buf[st->bufbeg] & 0xFF) << 16; - ptr[0] = base64[(i >> 18) & 0x3F]; - ptr[1] = base64[(i >> 12) & 0x3F]; - if(++st->bufbeg != st->bufend) { - ptr[2] = base64[(i >> 6) & 0x3F]; - st->bufbeg++; - } - cursize += 4; - st->pos += 4; - break; - } - } - -#ifdef CURL_DOES_CONVERSIONS - /* This is now textual data, Convert character codes. */ - if(part->easy && cursize) { - CURLcode result = Curl_convert_to_network(part->easy, buffer, cursize); - if(result) - return READ_ERROR; - } -#endif - - return cursize; -} - -static curl_off_t encoder_base64_size(curl_mimepart *part) -{ - curl_off_t size = part->datasize; - - if(size <= 0) - return size; /* Unknown size or no data. */ - - /* Compute base64 character count. */ - size = 4 * (1 + (size - 1) / 3); - - /* Effective character count must include CRLFs. */ - return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH); -} - - -/* Quoted-printable lookahead. - * - * Check if a CRLF or end of data is in input buffer at current position + n. - * Return -1 if more data needed, 1 if CRLF or end of data, else 0. - */ -static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n) -{ - n += st->bufbeg; - if(n >= st->bufend && ateof) - return 1; - if(n + 2 > st->bufend) - return ateof? 0: -1; - if(qp_class[st->buf[n] & 0xFF] == QP_CR && - qp_class[st->buf[n + 1] & 0xFF] == QP_LF) - return 1; - return 0; -} - -/* Quoted-printable encoder. */ -static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part) -{ - mime_encoder_state *st = &part->encstate; - char *ptr = buffer; - size_t cursize = 0; - int i; - size_t len; - size_t consumed; - int softlinebreak; - char buf[4]; - - /* On all platforms, input is supposed to be ASCII compatible: for this - reason, we use hexadecimal ASCII codes in this function rather than - character constants that can be interpreted as non-ascii on some - platforms. Preserve ASCII encoding on output too. */ - while(st->bufbeg < st->bufend) { - len = 1; - consumed = 1; - i = st->buf[st->bufbeg]; - buf[0] = (char) i; - buf[1] = aschex[(i >> 4) & 0xF]; - buf[2] = aschex[i & 0xF]; - - switch(qp_class[st->buf[st->bufbeg] & 0xFF]) { - case QP_OK: /* Not a special character. */ - break; - case QP_SP: /* Space or tab. */ - /* Spacing must be escaped if followed by CRLF. */ - switch(qp_lookahead_eol(st, ateof, 1)) { - case -1: /* More input data needed. */ - return cursize; - case 0: /* No encoding needed. */ - break; - default: /* CRLF after space or tab. */ - buf[0] = '\x3D'; /* '=' */ - len = 3; - break; - } - break; - case QP_CR: /* Carriage return. */ - /* If followed by a line-feed, output the CRLF pair. - Else escape it. */ - switch(qp_lookahead_eol(st, ateof, 0)) { - case -1: /* Need more data. */ - return cursize; - case 1: /* CRLF found. */ - buf[len++] = '\x0A'; /* Append '\n'. */ - consumed = 2; - break; - default: /* Not followed by LF: escape. */ - buf[0] = '\x3D'; /* '=' */ - len = 3; - break; - } - break; - default: /* Character must be escaped. */ - buf[0] = '\x3D'; /* '=' */ - len = 3; - break; - } - - /* Be sure the encoded character fits within maximum line length. */ - if(buf[len - 1] != '\x0A') { /* '\n' */ - softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH; - if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) { - /* We may use the current line only if end of data or followed by - a CRLF. */ - switch(qp_lookahead_eol(st, ateof, consumed)) { - case -1: /* Need more data. */ - return cursize; - break; - case 0: /* Not followed by a CRLF. */ - softlinebreak = 1; - break; - } - } - if(softlinebreak) { - strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */ - len = 3; - consumed = 0; - } - } - - /* If the output buffer would overflow, do not store. */ - if(len > size) - break; - - /* Append to output buffer. */ - memcpy(ptr, buf, len); - cursize += len; - ptr += len; - size -= len; - st->pos += len; - if(buf[len - 1] == '\x0A') /* '\n' */ - st->pos = 0; - st->bufbeg += consumed; - } - - return cursize; -} - -static curl_off_t encoder_qp_size(curl_mimepart *part) -{ - /* Determining the size can only be done by reading the data: unless the - data size is 0, we return it as unknown (-1). */ - return part->datasize? -1: 0; -} - - -/* In-memory data callbacks. */ -/* Argument is a pointer to the mime part. */ -static size_t mime_mem_read(char *buffer, size_t size, size_t nitems, - void *instream) -{ - curl_mimepart *part = (curl_mimepart *) instream; - size_t sz = (size_t) part->datasize - part->state.offset; - - (void) size; /* Always 1.*/ - - if(sz > nitems) - sz = nitems; - - if(sz) - memcpy(buffer, (char *) part->data, sz); - - part->state.offset += sz; - return sz; -} - -static int mime_mem_seek(void *instream, curl_off_t offset, int whence) -{ - curl_mimepart *part = (curl_mimepart *) instream; - - switch(whence) { - case SEEK_CUR: - offset += part->state.offset; - break; - case SEEK_END: - offset += part->datasize; - break; - } - - if(offset < 0 || offset > part->datasize) - return CURL_SEEKFUNC_FAIL; - - part->state.offset = (size_t) offset; - return CURL_SEEKFUNC_OK; -} - -static void mime_mem_free(void *ptr) -{ - Curl_safefree(((curl_mimepart *) ptr)->data); -} - - -/* Named file callbacks. */ -/* Argument is a pointer to the mime part. */ -static int mime_open_file(curl_mimepart * part) -{ - /* Open a MIMEKIND_FILE part. */ - - if(part->fp) - return 0; - part->fp = fopen_read(part->data, "rb"); - return part->fp? 0: -1; -} - -static size_t mime_file_read(char *buffer, size_t size, size_t nitems, - void *instream) -{ - curl_mimepart *part = (curl_mimepart *) instream; - - if(mime_open_file(part)) - return READ_ERROR; - - return fread(buffer, size, nitems, part->fp); -} - -static int mime_file_seek(void *instream, curl_off_t offset, int whence) -{ - curl_mimepart *part = (curl_mimepart *) instream; - - if(whence == SEEK_SET && !offset && !part->fp) - return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */ - - if(mime_open_file(part)) - return CURL_SEEKFUNC_FAIL; - - return fseek(part->fp, (long) offset, whence)? - CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK; -} - -static void mime_file_free(void *ptr) -{ - curl_mimepart *part = (curl_mimepart *) ptr; - - if(part->fp) { - fclose(part->fp); - part->fp = NULL; - } - Curl_safefree(part->data); - part->data = NULL; -} - - -/* Subparts callbacks. */ -/* Argument is a pointer to the mime structure. */ - -/* Readback a byte string segment. */ -static size_t readback_bytes(mime_state *state, - char *buffer, size_t bufsize, - const char *bytes, size_t numbytes, - const char *trail) -{ - size_t sz; - - sz = numbytes - state->offset; - - if(numbytes > state->offset) { - sz = numbytes - state->offset; - bytes += state->offset; - } - else { - size_t tsz = strlen(trail); - - sz = state->offset - numbytes; - if(sz >= tsz) - return 0; - bytes = trail + sz; - sz = tsz - sz; - } - - if(sz > bufsize) - sz = bufsize; - - memcpy(buffer, bytes, sz); - state->offset += sz; - return sz; -} - -/* Read a non-encoded part content. */ -static size_t read_part_content(curl_mimepart *part, - char *buffer, size_t bufsize) -{ - size_t sz = 0; - - if(part->readfunc) - sz = part->readfunc(buffer, 1, bufsize, part->arg); - return sz; -} - -/* Read and encode part content. */ -static size_t read_encoded_part_content(curl_mimepart *part, - char *buffer, size_t bufsize) -{ - mime_encoder_state *st = &part->encstate; - size_t cursize = 0; - size_t sz; - bool ateof = FALSE; - - while(bufsize) { - if(st->bufbeg < st->bufend || ateof) { - /* Encode buffered data. */ - sz = part->encoder->encodefunc(buffer, bufsize, ateof, part); - switch(sz) { - case 0: - if(ateof) - return cursize; - break; - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: - case READ_ERROR: - return cursize? cursize: sz; - default: - cursize += sz; - buffer += sz; - bufsize -= sz; - continue; - } - } - - /* We need more data in input buffer. */ - if(st->bufbeg) { - size_t len = st->bufend - st->bufbeg; - - if(len) - memmove(st->buf, st->buf + st->bufbeg, len); - st->bufbeg = 0; - st->bufend = len; - } - if(st->bufend >= sizeof st->buf) - return cursize? cursize: READ_ERROR; /* Buffer full. */ - sz = read_part_content(part, st->buf + st->bufend, - sizeof st->buf - st->bufend); - switch(sz) { - case 0: - ateof = TRUE; - break; - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: - case READ_ERROR: - return cursize? cursize: sz; - default: - st->bufend += sz; - break; - } - } - - return cursize; -} - -/* Readback a mime part. */ -static size_t readback_part(curl_mimepart *part, - char *buffer, size_t bufsize) -{ - size_t cursize = 0; - size_t sz; - struct curl_slist *hdr; -#ifdef CURL_DOES_CONVERSIONS - char *convbuf = buffer; -#endif - - /* Readback from part. */ - - while(bufsize) { - sz = 0; - hdr = (struct curl_slist *) part->state.ptr; - switch(part->state.state) { - case MIMESTATE_BEGIN: - mimesetstate(&part->state, part->flags & MIME_BODY_ONLY? MIMESTATE_BODY: - MIMESTATE_CURLHEADERS, part->curlheaders); - break; - case MIMESTATE_USERHEADERS: - if(!hdr) { - mimesetstate(&part->state, MIMESTATE_EOH, NULL); - break; - } - if(match_header(hdr, "Content-Type", 12)) { - mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next); - break; - } - /* FALLTHROUGH */ - case MIMESTATE_CURLHEADERS: - if(!hdr) - mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders); - else { - sz = readback_bytes(&part->state, buffer, bufsize, - hdr->data, strlen(hdr->data), "\r\n"); - if(!sz) - mimesetstate(&part->state, part->state.state, hdr->next); - } - break; - case MIMESTATE_EOH: - sz = readback_bytes(&part->state, buffer, bufsize, "\r\n", 2, ""); - if(!sz) - mimesetstate(&part->state, MIMESTATE_BODY, NULL); - break; - case MIMESTATE_BODY: -#ifdef CURL_DOES_CONVERSIONS - if(part->easy && convbuf < buffer) { - CURLcode result = Curl_convert_to_network(part->easy, convbuf, - buffer - convbuf); - if(result) - return READ_ERROR; - convbuf = buffer; - } -#endif - cleanup_encoder_state(&part->encstate); - mimesetstate(&part->state, MIMESTATE_CONTENT, NULL); - break; - case MIMESTATE_CONTENT: - if(part->encoder) - sz = read_encoded_part_content(part, buffer, bufsize); - else - sz = read_part_content(part, buffer, bufsize); - switch(sz) { - case 0: - mimesetstate(&part->state, MIMESTATE_END, NULL); - /* Try sparing open file descriptors. */ - if(part->kind == MIMEKIND_FILE && part->fp) { - fclose(part->fp); - part->fp = NULL; - } - /* FALLTHROUGH */ - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: - case READ_ERROR: - return cursize? cursize: sz; - } - break; - case MIMESTATE_END: - return cursize; - default: - break; /* Other values not in part state. */ - } - - /* Bump buffer and counters according to read size. */ - cursize += sz; - buffer += sz; - bufsize -= sz; - } - -#ifdef CURL_DOES_CONVERSIONS - if(part->easy && convbuf < buffer && - part->state.state < MIMESTATE_BODY) { - CURLcode result = Curl_convert_to_network(part->easy, convbuf, - buffer - convbuf); - if(result) - return READ_ERROR; - } -#endif - - return cursize; -} - -/* Readback from mime. */ -static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, - void *instream) -{ - curl_mime *mime = (curl_mime *) instream; - size_t cursize = 0; - size_t sz; - curl_mimepart *part; -#ifdef CURL_DOES_CONVERSIONS - char *convbuf = buffer; -#endif - - (void) size; /* Always 1. */ - - while(nitems) { - sz = 0; - part = mime->state.ptr; - switch(mime->state.state) { - case MIMESTATE_BEGIN: - case MIMESTATE_BODY: -#ifdef CURL_DOES_CONVERSIONS - convbuf = buffer; -#endif - mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart); - /* The first boundary always follows the header termination empty line, - so is always preceded by a CRLK. We can then spare 2 characters - by skipping the leading CRLF in boundary. */ - mime->state.offset += 2; - break; - case MIMESTATE_BOUNDARY1: - sz = readback_bytes(&mime->state, buffer, nitems, "\r\n--", 4, ""); - if(!sz) - mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part); - break; - case MIMESTATE_BOUNDARY2: - sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary, - strlen(mime->boundary), part? "\r\n": "--\r\n"); - if(!sz) { -#ifdef CURL_DOES_CONVERSIONS - if(mime->easy && convbuf < buffer) { - CURLcode result = Curl_convert_to_network(mime->easy, convbuf, - buffer - convbuf); - if(result) - return READ_ERROR; - convbuf = buffer; - } -#endif - mimesetstate(&mime->state, MIMESTATE_CONTENT, part); - } - break; - case MIMESTATE_CONTENT: - if(!part) { - mimesetstate(&mime->state, MIMESTATE_END, NULL); - break; - } - sz = readback_part(part, buffer, nitems); - switch(sz) { - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: - case READ_ERROR: - return cursize? cursize: sz; - case 0: -#ifdef CURL_DOES_CONVERSIONS - convbuf = buffer; -#endif - mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart); - break; - } - break; - case MIMESTATE_END: - return cursize; - default: - break; /* other values not used in mime state. */ - } - - /* Bump buffer and counters according to read size. */ - cursize += sz; - buffer += sz; - nitems -= sz; - } - -#ifdef CURL_DOES_CONVERSIONS - if(mime->easy && convbuf < buffer && - mime->state.state <= MIMESTATE_CONTENT) { - CURLcode result = Curl_convert_to_network(mime->easy, convbuf, - buffer - convbuf); - if(result) - return READ_ERROR; - } -#endif - - return cursize; -} - -static int mime_part_rewind(curl_mimepart *part) -{ - int res = CURL_SEEKFUNC_OK; - enum mimestate targetstate = MIMESTATE_BEGIN; - - if(part->flags & MIME_BODY_ONLY) - targetstate = MIMESTATE_BODY; - cleanup_encoder_state(&part->encstate); - if(part->state.state > targetstate) { - res = CURL_SEEKFUNC_CANTSEEK; - if(part->seekfunc) { - res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET); - switch(res) { - case CURL_SEEKFUNC_OK: - case CURL_SEEKFUNC_FAIL: - case CURL_SEEKFUNC_CANTSEEK: - break; - case -1: /* For fseek() error. */ - res = CURL_SEEKFUNC_CANTSEEK; - break; - default: - res = CURL_SEEKFUNC_FAIL; - break; - } - } - } - - if(res == CURL_SEEKFUNC_OK) - mimesetstate(&part->state, targetstate, NULL); - - return res; -} - -static int mime_subparts_seek(void *instream, curl_off_t offset, int whence) -{ - curl_mime *mime = (curl_mime *) instream; - curl_mimepart *part; - int result = CURL_SEEKFUNC_OK; - int res; - - if(whence != SEEK_SET || offset) - return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */ - - if(mime->state.state == MIMESTATE_BEGIN) - return CURL_SEEKFUNC_OK; /* Already rewound. */ - - for(part = mime->firstpart; part; part = part->nextpart) { - res = mime_part_rewind(part); - if(res != CURL_SEEKFUNC_OK) - result = res; - } - - if(result == CURL_SEEKFUNC_OK) - mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL); - - return result; -} - -static void mime_subparts_free(void *ptr) -{ - curl_mime *mime = (curl_mime *) ptr; - curl_mime_free(mime); -} - - -/* Release part content. */ -static void cleanup_part_content(curl_mimepart *part) -{ - if(part->freefunc) - part->freefunc(part->arg); - - part->readfunc = NULL; - part->seekfunc = NULL; - part->freefunc = NULL; - part->arg = (void *) part; /* Defaults to part itself. */ - part->data = NULL; - part->fp = NULL; - part->datasize = (curl_off_t) 0; /* No size yet. */ - part->encoder = NULL; - cleanup_encoder_state(&part->encstate); - part->kind = MIMEKIND_NONE; -} - -void Curl_mime_cleanpart(curl_mimepart *part) -{ - cleanup_part_content(part); - curl_slist_free_all(part->curlheaders); - if(part->flags & MIME_USERHEADERS_OWNER) - curl_slist_free_all(part->userheaders); - Curl_safefree(part->mimetype); - Curl_safefree(part->name); - Curl_safefree(part->filename); - Curl_mime_initpart(part, part->easy); -} - -/* Recursively delete a mime handle and its parts. */ -void curl_mime_free(curl_mime *mime) -{ - curl_mimepart *part; - - if(mime) { - while(mime->firstpart) { - part = mime->firstpart; - mime->firstpart = part->nextpart; - Curl_mime_cleanpart(part); - free(part); - } - - free(mime->boundary); - free(mime); - } -} - -/* - * Mime build functions. - */ - -/* Create a mime handle. */ -curl_mime *curl_mime_init(struct Curl_easy *easy) -{ - curl_mime *mime; - - mime = (curl_mime *) malloc(sizeof *mime); - - if(mime) { - mime->easy = easy; - mime->parent = NULL; - mime->firstpart = NULL; - mime->lastpart = NULL; - - /* Get a part boundary. */ - mime->boundary = malloc(24 + MIME_RAND_BOUNDARY_CHARS + 1); - if(!mime->boundary) { - free(mime); - return NULL; - } - - memset(mime->boundary, '-', 24); - Curl_rand_hex(easy, (unsigned char *) mime->boundary + 24, - MIME_RAND_BOUNDARY_CHARS + 1); - mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL); - } - - return mime; -} - -/* Initialize a mime part. */ -void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy) -{ - memset((char *) part, 0, sizeof *part); - part->easy = easy; - mimesetstate(&part->state, MIMESTATE_BEGIN, NULL); -} - -/* Create a mime part and append it to a mime handle's part list. */ -curl_mimepart *curl_mime_addpart(curl_mime *mime) -{ - curl_mimepart *part; - - if(!mime) - return NULL; - - part = (curl_mimepart *) malloc(sizeof *part); - - if(part) { - Curl_mime_initpart(part, mime->easy); - part->parent = mime; - - if(mime->lastpart) - mime->lastpart->nextpart = part; - else - mime->firstpart = part; - - mime->lastpart = part; - } - - return part; -} - -/* Set mime part name. */ -CURLcode curl_mime_name(curl_mimepart *part, const char *name) -{ - if(!part) - return CURLE_BAD_FUNCTION_ARGUMENT; - - Curl_safefree(part->name); - part->name = NULL; - - if(name) { - part->name = strdup(name); - if(!part->name) - return CURLE_OUT_OF_MEMORY; - } - - return CURLE_OK; -} - -/* Set mime part remote file name. */ -CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) -{ - if(!part) - return CURLE_BAD_FUNCTION_ARGUMENT; - - Curl_safefree(part->filename); - part->filename = NULL; - - if(filename) { - part->filename = strdup(filename); - if(!part->filename) - return CURLE_OUT_OF_MEMORY; - } - - return CURLE_OK; -} - -/* Set mime part content from memory data. */ -CURLcode curl_mime_data(curl_mimepart *part, - const char *data, size_t datasize) -{ - if(!part) - return CURLE_BAD_FUNCTION_ARGUMENT; - - cleanup_part_content(part); - - if(data) { - if(datasize == CURL_ZERO_TERMINATED) - datasize = strlen(data); - - part->data = malloc(datasize + 1); - if(!part->data) - return CURLE_OUT_OF_MEMORY; - - part->datasize = datasize; - - if(datasize) - memcpy(part->data, data, datasize); - part->data[datasize] = '\0'; /* Set a nul terminator as sentinel. */ - - part->readfunc = mime_mem_read; - part->seekfunc = mime_mem_seek; - part->freefunc = mime_mem_free; - part->kind = MIMEKIND_DATA; - } - - return CURLE_OK; -} - -/* Set mime part content from named local file. */ -CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) -{ - CURLcode result = CURLE_OK; - char *base; - - if(!part) - return CURLE_BAD_FUNCTION_ARGUMENT; - - cleanup_part_content(part); - - if(filename) { - struct_stat sbuf; - - if(stat(filename, &sbuf) || access(filename, R_OK)) - result = CURLE_READ_ERROR; - - part->data = strdup(filename); - if(!part->data) - result = CURLE_OUT_OF_MEMORY; - - part->datasize = -1; - if(!result && S_ISREG(sbuf.st_mode)) { - part->datasize = filesize(filename, sbuf); - part->seekfunc = mime_file_seek; - } - - part->readfunc = mime_file_read; - part->freefunc = mime_file_free; - part->kind = MIMEKIND_FILE; - - /* As a side effect, set the filename to the current file's base name. - It is possible to withdraw this by explicitly calling - curl_mime_filename() with a NULL filename argument after the current - call. */ - base = strippath(filename); - if(!base) - result = CURLE_OUT_OF_MEMORY; - else { - CURLcode res = curl_mime_filename(part, base); - - if(res) - result = res; - free(base); - } - } - return result; -} - -/* Set mime part type. */ -CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) -{ - if(!part) - return CURLE_BAD_FUNCTION_ARGUMENT; - - Curl_safefree(part->mimetype); - part->mimetype = NULL; - - if(mimetype) { - part->mimetype = strdup(mimetype); - if(!part->mimetype) - return CURLE_OUT_OF_MEMORY; - } - - return CURLE_OK; -} - -/* Set mime data transfer encoder. */ -CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) -{ - CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; - const mime_encoder *mep; - - if(!part) - return result; - - part->encoder = NULL; - - if(!encoding) - return CURLE_OK; /* Removing current encoder. */ - - for(mep = encoders; mep->name; mep++) - if(strcasecompare(encoding, mep->name)) { - part->encoder = mep; - result = CURLE_OK; - } - - return result; -} - -/* Set mime part headers. */ -CURLcode curl_mime_headers(curl_mimepart *part, - struct curl_slist *headers, int take_ownership) -{ - if(!part) - return CURLE_BAD_FUNCTION_ARGUMENT; - - if(part->flags & MIME_USERHEADERS_OWNER) { - curl_slist_free_all(part->userheaders); - part->flags &= ~MIME_USERHEADERS_OWNER; - } - part->userheaders = headers; - if(headers && take_ownership) - part->flags |= MIME_USERHEADERS_OWNER; - return CURLE_OK; -} - -/* Set mime part content from callback. */ -CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize, - curl_read_callback readfunc, - curl_seek_callback seekfunc, - curl_free_callback freefunc, void *arg) -{ - if(!part) - return CURLE_BAD_FUNCTION_ARGUMENT; - - cleanup_part_content(part); - - if(readfunc) { - part->readfunc = readfunc; - part->seekfunc = seekfunc; - part->freefunc = freefunc; - part->arg = arg; - part->datasize = datasize; - part->kind = MIMEKIND_CALLBACK; - } - - return CURLE_OK; -} - -/* Set mime part content from subparts. */ -CURLcode curl_mime_subparts(curl_mimepart *part, - curl_mime *subparts) -{ - if(!part) - return CURLE_BAD_FUNCTION_ARGUMENT; - - /* Accept setting twice the same subparts. */ - if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts) - return CURLE_OK; - - cleanup_part_content(part); - - if(subparts) { - /* Must belong to the same data handle. */ - if(part->easy && subparts->easy && part->easy != subparts->easy) - return CURLE_BAD_FUNCTION_ARGUMENT; - - /* Should not have been attached already. */ - if(subparts->parent) - return CURLE_BAD_FUNCTION_ARGUMENT; - - subparts->parent = part; - part->readfunc = mime_subparts_read; - part->seekfunc = mime_subparts_seek; - part->freefunc = mime_subparts_free; - part->arg = subparts; - part->datasize = -1; - part->kind = MIMEKIND_MULTIPART; - } - - return CURLE_OK; -} - - -/* Readback from top mime. */ -/* Argument is the dummy top part. */ -size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) -{ - curl_mimepart *part = (curl_mimepart *) instream; - - (void) size; /* Always 1. */ - return readback_part(part, buffer, nitems); -} - -/* Rewind mime stream. */ -CURLcode Curl_mime_rewind(curl_mimepart *part) -{ - return mime_part_rewind(part) == CURL_SEEKFUNC_OK? - CURLE_OK: CURLE_SEND_FAIL_REWIND; -} - -/* Compute header list size. */ -static size_t slist_size(struct curl_slist *s, - size_t overhead, const char *skip) -{ - size_t size = 0; - size_t skiplen = skip? strlen(skip): 0; - - for(; s; s = s->next) - if(!skip || !match_header(s, skip, skiplen)) - size += strlen(s->data) + overhead; - return size; -} - -/* Get/compute multipart size. */ -static curl_off_t multipart_size(curl_mime *mime) -{ - curl_off_t size; - curl_off_t sz; - size_t boundarysize; - curl_mimepart *part; - - if(!mime) - return 0; /* Not present -> empty. */ - - boundarysize = 4 + strlen(mime->boundary) + 2; - size = boundarysize; /* Final boundary - CRLF after headers. */ - - for(part = mime->firstpart; part; part = part->nextpart) { - sz = Curl_mime_size(part); - - if(sz < 0) - size = sz; - - if(size >= 0) - size += boundarysize + sz; - } - - return size; -} - -/* Get/compute mime size. */ -curl_off_t Curl_mime_size(curl_mimepart *part) -{ - curl_off_t size; - - if(part->datasize < 0 && part->kind == MIMEKIND_MULTIPART) - part->datasize = multipart_size(part->arg); - - size = part->datasize; - - if(part->encoder) - size = part->encoder->sizefunc(part); - - if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) { - /* Compute total part size. */ - size += slist_size(part->curlheaders, 2, NULL); - size += slist_size(part->userheaders, 2, "Content-Type"); - size += 2; /* CRLF after headers. */ - } - return size; -} - -/* Add a header. */ -/* VARARGS2 */ -CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) -{ - struct curl_slist *hdr = NULL; - char *s = NULL; - va_list ap; - - va_start(ap, fmt); - s = curl_mvaprintf(fmt, ap); - va_end(ap); - - if(s) { - hdr = Curl_slist_append_nodup(*slp, s); - if(hdr) - *slp = hdr; - else - free(s); - } - - return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY; -} - -/* Add a content type header. */ -static CURLcode add_content_type(struct curl_slist **slp, - const char *type, const char *boundary) -{ - return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type, - boundary? "; boundary=": "", - boundary? boundary: ""); -} - - -static const char *ContentTypeForFilename(const char *filename) -{ - unsigned int i; - - /* - * If no content type was specified, we scan through a few well-known - * extensions and pick the first we match! - */ - struct ContentType { - const char *extension; - const char *type; - }; - static const struct ContentType ctts[] = { - {".gif", "image/gif"}, - {".jpg", "image/jpeg"}, - {".jpeg", "image/jpeg"}, - {".png", "image/png"}, - {".svg", "image/svg+xml"}, - {".txt", "text/plain"}, - {".htm", "text/html"}, - {".html", "text/html"}, - {".pdf", "application/pdf"}, - {".xml", "application/xml"} - }; - - if(filename) { - size_t len1 = strlen(filename); - const char *nameend = filename + len1; - - for(i = 0; i < sizeof ctts / sizeof ctts[0]; i++) { - size_t len2 = strlen(ctts[i].extension); - - if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension)) - return ctts[i].type; - } - } - return NULL; -} - -CURLcode Curl_mime_prepare_headers(curl_mimepart *part, - const char *contenttype, - const char *disposition, - enum mimestrategy strategy) -{ - curl_mime *mime = NULL; - const char *boundary = NULL; - char *s; - const char *cte = NULL; - CURLcode ret = CURLE_OK; - - /* Get rid of previously prepared headers. */ - curl_slist_free_all(part->curlheaders); - part->curlheaders = NULL; - - /* Be sure we won't access old headers later. */ - if(part->state.state == MIMESTATE_CURLHEADERS) - mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL); - - /* Build the content-type header. */ - s = search_header(part->userheaders, "Content-Type"); - if(s) - contenttype = s; - if(part->mimetype) - contenttype = part->mimetype; - if(!contenttype) { - switch(part->kind) { - case MIMEKIND_MULTIPART: - contenttype = MULTIPART_CONTENTTYPE_DEFAULT; - break; - case MIMEKIND_FILE: - contenttype = ContentTypeForFilename(part->filename); - if(!contenttype) - contenttype = ContentTypeForFilename(part->data); - if(!contenttype && part->filename) - contenttype = FILE_CONTENTTYPE_DEFAULT; - break; - default: - contenttype = ContentTypeForFilename(part->filename); - break; - } - } - - if(part->kind == MIMEKIND_MULTIPART) { - mime = (curl_mime *) part->arg; - if(mime) - boundary = mime->boundary; - } - else if(contenttype && strcasecompare(contenttype, "text/plain")) - if(strategy == MIMESTRATEGY_MAIL || !part->filename) - contenttype = NULL; - - /* Issue content-disposition header only if not already set by caller. */ - if(!search_header(part->userheaders, "Content-Disposition")) { - if(!disposition) - if(part->filename || part->name || - (contenttype && !strncasecompare(contenttype, "multipart/", 10))) - disposition = DISPOSITION_DEFAULT; - if(disposition && curl_strequal(disposition, "attachment") && - !part->name && !part->filename) - disposition = NULL; - if(disposition) { - char *name = NULL; - char *filename = NULL; - - if(part->name) { - name = escape_string(part->name); - if(!name) - ret = CURLE_OUT_OF_MEMORY; - } - if(!ret && part->filename) { - filename = escape_string(part->filename); - if(!filename) - ret = CURLE_OUT_OF_MEMORY; - } - if(!ret) - ret = Curl_mime_add_header(&part->curlheaders, - "Content-Disposition: %s%s%s%s%s%s%s", - disposition, - name? "; name=\"": "", - name? name: "", - name? "\"": "", - filename? "; filename=\"": "", - filename? filename: "", - filename? "\"": ""); - Curl_safefree(name); - Curl_safefree(filename); - if(ret) - return ret; - } - } - - /* Issue Content-Type header. */ - if(contenttype) { - ret = add_content_type(&part->curlheaders, contenttype, boundary); - if(ret) - return ret; - } - - /* Content-Transfer-Encoding header. */ - if(!search_header(part->userheaders, "Content-Transfer-Encoding")) { - if(part->encoder) - cte = part->encoder->name; - else if(contenttype && strategy == MIMESTRATEGY_MAIL && - part->kind != MIMEKIND_MULTIPART) - cte = "8bit"; - if(cte) { - ret = Curl_mime_add_header(&part->curlheaders, - "Content-Transfer-Encoding: %s", cte); - if(ret) - return ret; - } - } - - /* If we were reading curl-generated headers, restart with new ones (this - should not occur). */ - if(part->state.state == MIMESTATE_CURLHEADERS) - mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders); - - /* Process subparts. */ - if(part->kind == MIMEKIND_MULTIPART && mime) { - curl_mimepart *subpart; - - disposition = NULL; - if(strcasecompare(contenttype, "multipart/form-data")) - disposition = "form-data"; - for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) { - ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy); - if(ret) - return ret; - } - } - return ret; -} - -#else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ - -/* Mime not compiled in: define stubs for externally-referenced functions. */ -curl_mime *curl_mime_init(CURL *easy) -{ - (void) easy; - return NULL; -} - -void curl_mime_free(curl_mime *mime) -{ - (void) mime; -} - -curl_mimepart *curl_mime_addpart(curl_mime *mime) -{ - (void) mime; - return NULL; -} - -CURLcode curl_mime_name(curl_mimepart *part, const char *name) -{ - (void) part; - (void) name; - return CURLE_NOT_BUILT_IN; -} - -CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) -{ - (void) part; - (void) filename; - return CURLE_NOT_BUILT_IN; -} - -CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) -{ - (void) part; - (void) mimetype; - return CURLE_NOT_BUILT_IN; -} - -CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) -{ - (void) part; - (void) encoding; - return CURLE_NOT_BUILT_IN; -} - -CURLcode curl_mime_data(curl_mimepart *part, - const char *data, size_t datasize) -{ - (void) part; - (void) data; - (void) datasize; - return CURLE_NOT_BUILT_IN; -} - -CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) -{ - (void) part; - (void) filename; - return CURLE_NOT_BUILT_IN; -} - -CURLcode curl_mime_data_cb(curl_mimepart *part, - curl_off_t datasize, - curl_read_callback readfunc, - curl_seek_callback seekfunc, - curl_free_callback freefunc, - void *arg) -{ - (void) part; - (void) datasize; - (void) readfunc; - (void) seekfunc; - (void) freefunc; - (void) arg; - return CURLE_NOT_BUILT_IN; -} - -CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) -{ - (void) part; - (void) subparts; - return CURLE_NOT_BUILT_IN; -} - -CURLcode curl_mime_headers(curl_mimepart *part, - struct curl_slist *headers, int take_ownership) -{ - (void) part; - (void) headers; - (void) take_ownership; - return CURLE_NOT_BUILT_IN; -} - -void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy) -{ - (void) part; - (void) easy; -} - -void Curl_mime_cleanpart(curl_mimepart *part) -{ - (void) part; -} - -CURLcode Curl_mime_prepare_headers(curl_mimepart *part, - const char *contenttype, - const char *disposition, - enum mimestrategy strategy) -{ - (void) part; - (void) contenttype; - (void) disposition; - (void) strategy; - return CURLE_NOT_BUILT_IN; -} - -curl_off_t Curl_mime_size(curl_mimepart *part) -{ - (void) part; - return (curl_off_t) -1; -} - -size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) -{ - (void) buffer; - (void) size; - (void) nitems; - (void) instream; - return 0; -} - -CURLcode Curl_mime_rewind(curl_mimepart *part) -{ - (void) part; - return CURLE_NOT_BUILT_IN; -} - -/* VARARGS2 */ -CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) -{ - (void) slp; - (void) fmt; - return CURLE_NOT_BUILT_IN; -} - -#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ diff --git a/dep/cpr/opt/curl/lib/mime.h b/dep/cpr/opt/curl/lib/mime.h deleted file mode 100644 index a144857076d..00000000000 --- a/dep/cpr/opt/curl/lib/mime.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef HEADER_CURL_MIME_H -#define HEADER_CURL_MIME_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#define MIME_RAND_BOUNDARY_CHARS 16 /* Nb. of random boundary chars. */ -#define MAX_ENCODED_LINE_LENGTH 76 /* Maximum encoded line length. */ -#define ENCODING_BUFFER_SIZE 256 /* Encoding temp buffers size. */ - -/* Part flags. */ -#define MIME_USERHEADERS_OWNER (1 << 0) -#define MIME_BODY_ONLY (1 << 1) - -/* Part source kinds. */ -enum mimekind { - MIMEKIND_NONE = 0, /* Part not set. */ - MIMEKIND_DATA, /* Allocated mime data. */ - MIMEKIND_FILE, /* Data from file. */ - MIMEKIND_CALLBACK, /* Data from `read' callback. */ - MIMEKIND_MULTIPART, /* Data is a mime subpart. */ - MIMEKIND_LAST -}; - -/* Readback state tokens. */ -enum mimestate { - MIMESTATE_BEGIN, /* Readback has not yet started. */ - MIMESTATE_CURLHEADERS, /* In curl-generated headers. */ - MIMESTATE_USERHEADERS, /* In caller's supplied headers. */ - MIMESTATE_EOH, /* End of headers. */ - MIMESTATE_BODY, /* Placeholder. */ - MIMESTATE_BOUNDARY1, /* In boundary prefix. */ - MIMESTATE_BOUNDARY2, /* In boundary. */ - MIMESTATE_CONTENT, /* In content. */ - MIMESTATE_END, /* End of part reached. */ - MIMESTATE_LAST -}; - -/* Mime headers strategies. */ -enum mimestrategy { - MIMESTRATEGY_MAIL, /* Mime mail. */ - MIMESTRATEGY_FORM, /* HTTP post form. */ - MIMESTRATEGY_LAST -}; - -/* Content transfer encoder. */ -typedef struct { - const char * name; /* Encoding name. */ - size_t (*encodefunc)(char *buffer, size_t size, bool ateof, - curl_mimepart *part); /* Encoded read. */ - curl_off_t (*sizefunc)(curl_mimepart *part); /* Encoded size. */ -} mime_encoder; - -/* Content transfer encoder state. */ -typedef struct { - size_t pos; /* Position on output line. */ - size_t bufbeg; /* Next data index in input buffer. */ - size_t bufend; /* First unused byte index in input buffer. */ - char buf[ENCODING_BUFFER_SIZE]; /* Input buffer. */ -} mime_encoder_state; - -/* Mime readback state. */ -typedef struct { - enum mimestate state; /* Current state token. */ - void *ptr; /* State-dependent pointer. */ - size_t offset; /* State-dependent offset. */ -} mime_state; - -/* A mime multipart. */ -struct curl_mime_s { - struct Curl_easy *easy; /* The associated easy handle. */ - curl_mimepart *parent; /* Parent part. */ - curl_mimepart *firstpart; /* First part. */ - curl_mimepart *lastpart; /* Last part. */ - char *boundary; /* The part boundary. */ - mime_state state; /* Current readback state. */ -}; - -/* A mime part. */ -struct curl_mimepart_s { - struct Curl_easy *easy; /* The associated easy handle. */ - curl_mime *parent; /* Parent mime structure. */ - curl_mimepart *nextpart; /* Forward linked list. */ - enum mimekind kind; /* The part kind. */ - char *data; /* Memory data or file name. */ - curl_read_callback readfunc; /* Read function. */ - curl_seek_callback seekfunc; /* Seek function. */ - curl_free_callback freefunc; /* Argument free function. */ - void *arg; /* Argument to callback functions. */ - FILE *fp; /* File pointer. */ - struct curl_slist *curlheaders; /* Part headers. */ - struct curl_slist *userheaders; /* Part headers. */ - char *mimetype; /* Part mime type. */ - char *filename; /* Remote file name. */ - char *name; /* Data name. */ - curl_off_t datasize; /* Expected data size. */ - unsigned int flags; /* Flags. */ - mime_state state; /* Current readback state. */ - const mime_encoder *encoder; /* Content data encoder. */ - mime_encoder_state encstate; /* Data encoder state. */ -}; - - -/* Prototypes. */ -void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy); -void Curl_mime_cleanpart(curl_mimepart *part); -CURLcode Curl_mime_prepare_headers(curl_mimepart *part, - const char *contenttype, - const char *disposition, - enum mimestrategy strategy); -curl_off_t Curl_mime_size(curl_mimepart *part); -size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, - void *instream); -CURLcode Curl_mime_rewind(curl_mimepart *part); -CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); - -#endif /* HEADER_CURL_MIME_H */ diff --git a/dep/cpr/opt/curl/lib/mk-ca-bundle.pl b/dep/cpr/opt/curl/lib/mk-ca-bundle.pl deleted file mode 100644 index cc36c7680c8..00000000000 --- a/dep/cpr/opt/curl/lib/mk-ca-bundle.pl +++ /dev/null @@ -1,554 +0,0 @@ -#!/usr/bin/perl -w -# *************************************************************************** -# * _ _ ____ _ -# * Project ___| | | | _ \| | -# * / __| | | | |_) | | -# * | (__| |_| | _ <| |___ -# * \___|\___/|_| \_\_____| -# * -# * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. -# * -# * This software is licensed as described in the file COPYING, which -# * you should have received as part of this distribution. The terms -# * are also available at https://curl.haxx.se/docs/copyright.html. -# * -# * 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, under the terms of the COPYING file. -# * -# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# * KIND, either express or implied. -# * -# *************************************************************************** -# This Perl script creates a fresh ca-bundle.crt file for use with libcurl. -# It downloads certdata.txt from Mozilla's source tree (see URL below), -# then parses certdata.txt and extracts CA Root Certificates into PEM format. -# These are then processed with the OpenSSL commandline tool to produce the -# final ca-bundle.crt file. -# The script is based on the parse-certs script written by Roland Krikava. -# This Perl script works on almost any platform since its only external -# dependency is the OpenSSL commandline tool for optional text listing. -# Hacked by Guenter Knauf. -# -use Encode; -use Getopt::Std; -use MIME::Base64; -use strict; -use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_k $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); -use List::Util; -use Text::Wrap; -my $MOD_SHA = "Digest::SHA"; -eval "require $MOD_SHA"; -if ($@) { - $MOD_SHA = "Digest::SHA::PurePerl"; - eval "require $MOD_SHA"; -} -eval "require LWP::UserAgent"; - -my %urls = ( - 'nss' => - 'https://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt', - 'central' => - 'https://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', - 'aurora' => - 'https://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', - 'beta' => - 'https://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', - 'release' => - 'https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', -); - -$opt_d = 'release'; - -# If the OpenSSL commandline is not in search path you can configure it here! -my $openssl = 'openssl'; - -my $version = '1.27'; - -$opt_w = 76; # default base64 encoded lines length - -# default cert types to include in the output (default is to include CAs which may issue SSL server certs) -my $default_mozilla_trust_purposes = "SERVER_AUTH"; -my $default_mozilla_trust_levels = "TRUSTED_DELEGATOR"; -$opt_p = $default_mozilla_trust_purposes . ":" . $default_mozilla_trust_levels; - -my @valid_mozilla_trust_purposes = ( - "DIGITAL_SIGNATURE", - "NON_REPUDIATION", - "KEY_ENCIPHERMENT", - "DATA_ENCIPHERMENT", - "KEY_AGREEMENT", - "KEY_CERT_SIGN", - "CRL_SIGN", - "SERVER_AUTH", - "CLIENT_AUTH", - "CODE_SIGNING", - "EMAIL_PROTECTION", - "IPSEC_END_SYSTEM", - "IPSEC_TUNNEL", - "IPSEC_USER", - "TIME_STAMPING", - "STEP_UP_APPROVED" -); - -my @valid_mozilla_trust_levels = ( - "TRUSTED_DELEGATOR", # CAs - "NOT_TRUSTED", # Don't trust these certs. - "MUST_VERIFY_TRUST", # This explicitly tells us that it ISN'T a CA but is otherwise ok. In other words, this should tell the app to ignore any other sources that claim this is a CA. - "TRUSTED" # This cert is trusted, but only for itself and not for delegates (i.e. it is not a CA). -); - -my $default_signature_algorithms = $opt_s = "MD5"; - -my @valid_signature_algorithms = ( - "MD5", - "SHA1", - "SHA256", - "SHA384", - "SHA512" -); - -$0 =~ s@.*(/|\\)@@; -$Getopt::Std::STANDARD_HELP_VERSION = 1; -getopts('bd:fhiklmnp:qs:tuvw:'); - -if(!defined($opt_d)) { - # to make plain "-d" use not cause warnings, and actually still work - $opt_d = 'release'; -} - -# Use predefined URL or else custom URL specified on command line. -my $url; -if(defined($urls{$opt_d})) { - $url = $urls{$opt_d}; - if(!$opt_k && $url !~ /^https:\/\//i) { - die "The URL for '$opt_d' is not HTTPS. Use -k to override (insecure).\n"; - } -} -else { - $url = $opt_d; -} - -my $curl = `curl -V`; - -if ($opt_i) { - print ("=" x 78 . "\n"); - print "Script Version : $version\n"; - print "Perl Version : $]\n"; - print "Operating System Name : $^O\n"; - print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; - print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; - print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n" if($LWP::UserAgent::VERSION); - print "LWP.pm Version : ${LWP::VERSION}\n" if($LWP::VERSION); - print "Digest::SHA.pm Version : ${Digest::SHA::VERSION}\n" if ($Digest::SHA::VERSION); - print "Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION}\n" if ($Digest::SHA::PurePerl::VERSION); - print ("=" x 78 . "\n"); -} - -sub warning_message() { - if ( $opt_d =~ m/^risk$/i ) { # Long Form Warning and Exit - print "Warning: Use of this script may pose some risk:\n"; - print "\n"; - print " 1) If you use HTTP URLs they are subject to a man in the middle attack\n"; - print " 2) Default to 'release', but more recent updates may be found in other trees\n"; - print " 3) certdata.txt file format may change, lag time to update this script\n"; - print " 4) Generally unwise to blindly trust CAs without manual review & verification\n"; - print " 5) Mozilla apps use additional security checks aren't represented in certdata\n"; - print " 6) Use of this script will make a security engineer grind his teeth and\n"; - print " swear at you. ;)\n"; - exit; - } else { # Short Form Warning - print "Warning: Use of this script may pose some risk, -d risk for more details.\n"; - } -} - -sub HELP_MESSAGE() { - print "Usage:\t${0} [-b] [-d] [-f] [-i] [-k] [-l] [-n] [-p] [-q] [-s] [-t] [-u] [-v] [-w] []\n"; - print "\t-b\tbackup an existing version of ca-bundle.crt\n"; - print "\t-d\tspecify Mozilla tree to pull certdata.txt or custom URL\n"; - print "\t\t Valid names are:\n"; - print "\t\t ", join( ", ", map { ( $_ =~ m/$opt_d/ ) ? "$_ (default)" : "$_" } sort keys %urls ), "\n"; - print "\t-f\tforce rebuild even if certdata.txt is current\n"; - print "\t-i\tprint version info about used modules\n"; - print "\t-k\tallow URLs other than HTTPS, enable HTTP fallback (insecure)\n"; - print "\t-l\tprint license info about certdata.txt\n"; - print "\t-m\tinclude meta data in output\n"; - print "\t-n\tno download of certdata.txt (to use existing)\n"; - print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; - print "\t\t Valid purposes are:\n"; - print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_purposes ) ), "\n"; - print "\t\t Valid levels are:\n"; - print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_levels ) ), "\n"; - print "\t-q\tbe really quiet (no progress output at all)\n"; - print wrap("\t","\t\t", "-s\tcomma separated list of certificate signatures/hashes to output in plain text mode. (default: $default_signature_algorithms)\n"); - print "\t\t Valid signature algorithms are:\n"; - print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_signature_algorithms ) ), "\n"; - print "\t-t\tinclude plain text listing of certificates\n"; - print "\t-u\tunlink (remove) certdata.txt after processing\n"; - print "\t-v\tbe verbose and print out processed CAs\n"; - print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; - exit; -} - -sub VERSION_MESSAGE() { - print "${0} version ${version} running Perl ${]} on ${^O}\n"; -} - -warning_message() unless ($opt_q || $url =~ m/^(ht|f)tps:/i ); -HELP_MESSAGE() if ($opt_h); - -sub report($@) { - my $output = shift; - - print STDERR $output . "\n" unless $opt_q; -} - -sub is_in_list($@) { - my $target = shift; - - return defined(List::Util::first { $target eq $_ } @_); -} - -# Parses $param_string as a case insensitive comma separated list with optional whitespace -# validates that only allowed parameters are supplied -sub parse_csv_param($$@) { - my $description = shift; - my $param_string = shift; - my @valid_values = @_; - - my @values = map { - s/^\s+//; # strip leading spaces - s/\s+$//; # strip trailing spaces - uc $_ # return the modified string as upper case - } split( ',', $param_string ); - - # Find all values which are not in the list of valid values or "ALL" - my @invalid = grep { !is_in_list($_,"ALL",@valid_values) } @values; - - if ( scalar(@invalid) > 0 ) { - # Tell the user which parameters were invalid and print the standard help message which will exit - print "Error: Invalid ", $description, scalar(@invalid) == 1 ? ": " : "s: ", join( ", ", map { "\"$_\"" } @invalid ), "\n"; - HELP_MESSAGE(); - } - - @values = @valid_values if ( is_in_list("ALL",@values) ); - - return @values; -} - -sub sha256 { - my $result; - if ($Digest::SHA::VERSION || $Digest::SHA::PurePerl::VERSION) { - open(FILE, $_[0]) or die "Can't open '$_[0]': $!"; - binmode(FILE); - $result = $MOD_SHA->new(256)->addfile(*FILE)->hexdigest; - close(FILE); - } else { - # Use OpenSSL command if Perl Digest::SHA modules not available - $result = `"$openssl" dgst -r -sha256 "$_[0]"`; - $result =~ s/^([0-9a-f]{64}) .+/$1/is; - } - return $result; -} - - -sub oldhash { - my $hash = ""; - open(C, "<$_[0]") || return 0; - while() { - chomp; - if($_ =~ /^\#\# SHA256: (.*)/) { - $hash = $1; - last; - } - } - close(C); - return $hash; -} - -if ( $opt_p !~ m/:/ ) { - print "Error: Mozilla trust identifier list must include both purposes and levels\n"; - HELP_MESSAGE(); -} - -(my $included_mozilla_trust_purposes_string, my $included_mozilla_trust_levels_string) = split( ':', $opt_p ); -my @included_mozilla_trust_purposes = parse_csv_param( "trust purpose", $included_mozilla_trust_purposes_string, @valid_mozilla_trust_purposes ); -my @included_mozilla_trust_levels = parse_csv_param( "trust level", $included_mozilla_trust_levels_string, @valid_mozilla_trust_levels ); - -my @included_signature_algorithms = parse_csv_param( "signature algorithm", $opt_s, @valid_signature_algorithms ); - -sub should_output_cert(%) { - my %trust_purposes_by_level = @_; - - foreach my $level (@included_mozilla_trust_levels) { - # for each level we want to output, see if any of our desired purposes are included - return 1 if ( defined( List::Util::first { is_in_list( $_, @included_mozilla_trust_purposes ) } @{$trust_purposes_by_level{$level}} ) ); - } - - return 0; -} - -my $crt = $ARGV[0] || 'ca-bundle.crt'; -(my $txt = $url) =~ s@(.*/|\?.*)@@g; - -my $stdout = $crt eq '-'; -my $resp; -my $fetched; - -my $oldhash = oldhash($crt); - -report "SHA256 of old file: $oldhash"; - -if(!$opt_n) { - report "Downloading $txt ..."; - - # If we have an HTTPS URL then use curl - if($url =~ /^https:\/\//i) { - if($curl) { - if($curl =~ /^Protocols:.* https( |$)/m) { - report "Get certdata with curl!"; - my $proto = !$opt_k ? "--proto =https" : ""; - my $quiet = $opt_q ? "-s" : ""; - my @out = `curl -w %{response_code} $proto $quiet -o "$txt" "$url"`; - if(!$? && @out && $out[0] == 200) { - $fetched = 1; - report "Downloaded $txt"; - } - else { - report "Failed downloading via HTTPS with curl"; - if(-e $txt && !unlink($txt)) { - report "Failed to remove '$txt': $!"; - } - } - } - else { - report "curl lacks https support"; - } - } - else { - report "curl not found"; - } - } - - # If nothing was fetched then use LWP - if(!$fetched) { - if($url =~ /^https:\/\//i) { - report "Falling back to HTTP"; - $url =~ s/^https:\/\//http:\/\//i; - } - if(!$opt_k) { - report "URLs other than HTTPS are disabled by default, to enable use -k"; - exit 1; - } - report "Get certdata with LWP!"; - if(!defined(${LWP::UserAgent::VERSION})) { - report "LWP is not available (LWP::UserAgent not found)"; - exit 1; - } - my $ua = new LWP::UserAgent(agent => "$0/$version"); - $ua->env_proxy(); - $resp = $ua->mirror($url, $txt); - if($resp && $resp->code eq '304') { - report "Not modified"; - exit 0 if -e $crt && !$opt_f; - } - else { - $fetched = 1; - report "Downloaded $txt"; - } - if(!$resp || $resp->code !~ /^(?:200|304)$/) { - report "Unable to download latest data: " - . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed"); - exit 1 if -e $crt || ! -r $txt; - } - } -} - -my $filedate = $resp ? $resp->last_modified : (stat($txt))[9]; -my $datesrc = "as of"; -if(!$filedate) { - # mxr.mozilla.org gave us a time, hg.mozilla.org does not! - $filedate = time(); - $datesrc="downloaded on"; -} - -# get the hash from the download file -my $newhash= sha256($txt); - -if(!$opt_f && $oldhash eq $newhash) { - report "Downloaded file identical to previous run\'s source file. Exiting"; - exit; -} - -report "SHA256 of new file: $newhash"; - -my $currentdate = scalar gmtime($filedate); - -my $format = $opt_t ? "plain text and " : ""; -if( $stdout ) { - open(CRT, '> -') or die "Couldn't open STDOUT: $!\n"; -} else { - open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n"; -} -print CRT <) { - if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { - print CRT; - print if ($opt_l); - while () { - print CRT; - print if ($opt_l); - last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); - } - } - elsif(/^# (Issuer|Serial Number|Subject|Not Valid Before|Not Valid After |Fingerprint \(MD5\)|Fingerprint \(SHA1\)):/) { - push @precert, $_; - next; - } - elsif(/^#|^\s*$/) { - undef @precert; - next; - } - chomp; - - # this is a match for the start of a certificate - if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { - $start_of_cert = 1 - } - if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) { - $caname = $1; - } - my %trust_purposes_by_level; - if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { - my $data; - while () { - last if (/^END/); - chomp; - my @octets = split(/\\/); - shift @octets; - for (@octets) { - $data .= chr(oct); - } - } - # scan forwards until the trust part - while () { - last if (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/); - chomp; - } - # now scan the trust part to determine how we should trust this cert - while () { - last if (/^#/); - if (/^CKA_TRUST_([A-Z_]+)\s+CK_TRUST\s+CKT_NSS_([A-Z_]+)\s*$/) { - if ( !is_in_list($1,@valid_mozilla_trust_purposes) ) { - report "Warning: Unrecognized trust purpose for cert: $caname. Trust purpose: $1. Trust Level: $2"; - } elsif ( !is_in_list($2,@valid_mozilla_trust_levels) ) { - report "Warning: Unrecognized trust level for cert: $caname. Trust purpose: $1. Trust Level: $2"; - } else { - push @{$trust_purposes_by_level{$2}}, $1; - } - } - } - - if ( !should_output_cert(%trust_purposes_by_level) ) { - $skipnum ++; - } else { - my $encoded = MIME::Base64::encode_base64($data, ''); - $encoded =~ s/(.{1,${opt_w}})/$1\n/g; - my $pem = "-----BEGIN CERTIFICATE-----\n" - . $encoded - . "-----END CERTIFICATE-----\n"; - print CRT "\n$caname\n"; - print CRT @precert if($opt_m); - my $maxStringLength = length(decode('UTF-8', $caname, Encode::FB_CROAK)); - if ($opt_t) { - foreach my $key (keys %trust_purposes_by_level) { - my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); - $maxStringLength = List::Util::max( length($string), $maxStringLength ); - print CRT $string . "\n"; - } - } - print CRT ("=" x $maxStringLength . "\n"); - if (!$opt_t) { - print CRT $pem; - } else { - my $pipe = ""; - foreach my $hash (@included_signature_algorithms) { - $pipe = "|$openssl x509 -" . $hash . " -fingerprint -noout -inform PEM"; - if (!$stdout) { - $pipe .= " >> $crt.~"; - close(CRT) or die "Couldn't close $crt.~: $!"; - } - open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; - print TMP $pem; - close(TMP) or die "Couldn't close openssl pipe: $!"; - if (!$stdout) { - open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; - } - } - $pipe = "|$openssl x509 -text -inform PEM"; - if (!$stdout) { - $pipe .= " >> $crt.~"; - close(CRT) or die "Couldn't close $crt.~: $!"; - } - open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; - print TMP $pem; - close(TMP) or die "Couldn't close openssl pipe: $!"; - if (!$stdout) { - open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; - } - } - report "Parsing: $caname" if ($opt_v); - $certnum ++; - $start_of_cert = 0; - } - undef @precert; - } - -} -close(TXT) or die "Couldn't close $txt: $!\n"; -close(CRT) or die "Couldn't close $crt.~: $!\n"; -unless( $stdout ) { - if ($opt_b && -e $crt) { - my $bk = 1; - while (-e "$crt.~${bk}~") { - $bk++; - } - rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n"; - } elsif( -e $crt ) { - unlink( $crt ) or die "Failed to remove $crt: $!\n"; - } - rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; -} -if($opt_u && -e $txt && !unlink($txt)) { - report "Failed to remove $txt: $!\n"; -} -report "Done ($certnum CA certs processed, $skipnum skipped)."; diff --git a/dep/cpr/opt/curl/lib/mk-ca-bundle.vbs b/dep/cpr/opt/curl/lib/mk-ca-bundle.vbs deleted file mode 100644 index da7a577ea7c..00000000000 --- a/dep/cpr/opt/curl/lib/mk-ca-bundle.vbs +++ /dev/null @@ -1,431 +0,0 @@ -'*************************************************************************** -'* _ _ ____ _ -'* Project ___| | | | _ \| | -'* / __| | | | |_) | | -'* | (__| |_| | _ <| |___ -'* \___|\___/|_| \_\_____| -'* -'* Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. -'* -'* This software is licensed as described in the file COPYING, which -'* you should have received as part of this distribution. The terms -'* are also available at https://curl.haxx.se/docs/copyright.html. -'* -'* 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, under the terms of the COPYING file. -'* -'* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -'* KIND, either express or implied. -'* -'*************************************************************************** -'* Script to fetch certdata.txt from Mozilla.org site and create a -'* ca-bundle.crt for use with OpenSSL / libcurl / libcurl bindings -'* Requires WinHttp.WinHttpRequest.5.1 and ADODB.Stream which are part of -'* W2000 SP3 or later, WXP SP1 or later, W2003 Server SP1 or later. -'* Hacked by Guenter Knauf -'*************************************************************************** -Option Explicit -Const myVersion = "0.4.0" - -Const myUrl = "https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt" - -Const myOpenSSL = "openssl.exe" -Dim myUseOpenSSL -myUseOpenSSL = TRUE ' Flag: TRUE to use OpenSSL. If TRUE and is not - ' found then a warning is shown before continuing. - -Const myCdSavF = TRUE ' Flag: save downloaded data to file certdata.txt -Const myCaBakF = TRUE ' Flag: backup existing ca-bundle certificate -Const myAskLiF = TRUE ' Flag: display certdata.txt license agreement -Const myWrapLe = 76 ' Default length of base64 output lines - -' cert info code doesn't work properly with any recent openssl, leave disabled. -' Also: we want our certificate output by default to be as similar as possible -' to mk-ca-bundle.pl and setting this TRUE changes the base64 width to -' OpenSSL's built-in default width, which is not the same as mk-ca-bundle.pl. -Const myAskTiF = FALSE ' Flag: ask to include certificate text info - -' -'******************* Nothing to configure below! ******************* -' -Const adTypeBinary = 1 -Const adTypeText = 2 -Const adSaveCreateNotExist = 1 -Const adSaveCreateOverWrite = 2 -Dim objShell, objNetwork, objFSO, objHttp -Dim myBase, mySelf, myStream, myTmpFh, myCdData, myCdFile -Dim myCaFile, myTmpName, myBakNum, myOptTxt, i -Set objNetwork = WScript.CreateObject("WScript.Network") -Set objShell = WScript.CreateObject("WScript.Shell") -Set objFSO = WScript.CreateObject("Scripting.FileSystemObject") -Set objHttp = WScript.CreateObject("WinHttp.WinHttpRequest.5.1") -If objHttp Is Nothing Then Set objHttp = WScript.CreateObject("WinHttp.WinHttpRequest") -myBase = Left(WScript.ScriptFullName, InstrRev(WScript.ScriptFullName, "\")) -mySelf = Left(WScript.ScriptName, InstrRev(WScript.ScriptName, ".") - 1) & " " & myVersion - -myCdFile = Mid(myUrl, InstrRev(myUrl, "/") + 1) -myCaFile = "ca-bundle.crt" -myTmpName = InputBox("It will take a minute to download and parse the " & _ - "certificate data." & _ - vbLf & vbLf & _ - "Please enter the output filename:", mySelf, myCaFile) -If (myTmpName = "") Then - WScript.Quit 1 -End If -myCaFile = myTmpName -If (myCdFile = "") Then - MsgBox("URL does not contain filename!"), vbCritical, mySelf - WScript.Quit 1 -End If - -' Don't use OpenSSL if it's not present. -If (myUseOpenSSL = TRUE) Then - Dim errnum - - On Error Resume Next - Call objShell.Run("""" & myOpenSSL & """ version", 0, TRUE) - errnum = Err.Number - On Error GoTo 0 - - If Not (errnum = 0) Then - myUseOpenSSL = FALSE - MsgBox("OpenSSL was not found so the certificate bundle will not " & _ - "include the SHA256 hash of the raw certificate data file " & _ - "that was used to generate the certificates in the bundle. " & _ - vbLf & vbLf & _ - "This does not have any effect on the certificate output, " & _ - "so this script will continue." & _ - vbLf & vbLf & _ - "If you want to set a custom location for OpenSSL or disable " & _ - "this message then edit the variables at the start of the " & _ - "script."), vbInformation, mySelf - End If -End If - -If (myAskTiF = TRUE) And (myUseOpenSSL = TRUE) Then - If (6 = objShell.PopUp("Do you want to include text information about " & _ - "each certificate?" & vbLf & _ - "(Requires OpenSSL.exe in the current directory " & _ - "or search path)",, _ - mySelf, vbQuestion + vbYesNo + vbDefaultButton2)) Then - myOptTxt = TRUE - Else - myOptTxt = FALSE - End If -End If - -' Uncomment the line below to ignore SSL invalid cert errors -' objHttp.Option(4) = 256 + 512 + 4096 + 8192 -objHttp.SetTimeouts 0, 5000, 10000, 10000 -objHttp.Open "GET", myUrl, FALSE -objHttp.setRequestHeader "User-Agent", WScript.ScriptName & "/" & myVersion -objHttp.Send "" -If Not (objHttp.Status = 200) Then - MsgBox("Failed to download '" & myCdFile & "': " & objHttp.Status & " - " & objHttp.StatusText), vbCritical, mySelf - WScript.Quit 1 -End If -' Write received data to file if enabled -If (myCdSavF = TRUE) Then - Call SaveBinaryData(myCdFile, objHttp.ResponseBody) -End If -' Convert data from ResponseBody instead of using ResponseText because of UTF-8 -myCdData = ConvertBinaryToUTF8(objHttp.ResponseBody) -Set objHttp = Nothing -' Backup exitsing ca-bundle certificate file -If (myCaBakF = TRUE) Then - If objFSO.FileExists(myCaFile) Then - Dim myBakFile, b - b = 1 - myBakFile = myCaFile & ".~" & b & "~" - While objFSO.FileExists(myBakFile) - b = b + 1 - myBakFile = myCaFile & ".~" & b & "~" - Wend - Set myTmpFh = objFSO.GetFile(myCaFile) - myTmpFh.Move myBakFile - End If -End If - -' Process the received data -Dim myLines, myPattern, myInsideCert, myInsideLicense, myLicenseText, myNumCerts, myNumSkipped -Dim myLabel, myOctets, myData, myPem, myRev, myUntrusted, j -myNumSkipped = 0 -myNumCerts = 0 -myData = "" -myLines = Split(myCdData, vbLf, -1) -Set myStream = CreateObject("ADODB.Stream") -myStream.Open -myStream.Type = adTypeText -myStream.Charset = "utf-8" -myStream.WriteText "##" & vbLf & _ - "## Bundle of CA Root Certificates" & vbLf & _ - "##" & vbLf & _ - "## Certificate data from Mozilla as of: " & _ - ConvertDateToString(LocalDateToUTC(Now)) & " GMT" & vbLf & _ - "##" & vbLf & _ - "## This is a bundle of X.509 certificates of public Certificate Authorities" & vbLf & _ - "## (CA). These were automatically extracted from Mozilla's root certificates" & vbLf & _ - "## file (certdata.txt). This file can be found in the mozilla source tree:" & vbLf & _ - "## " & myUrl & vbLf & _ - "##" & vbLf & _ - "## It contains the certificates in PEM format and therefore" & vbLf & _ - "## can be directly used with curl / libcurl / php_curl, or with" & vbLf & _ - "## an Apache+mod_ssl webserver for SSL client authentication." & vbLf & _ - "## Just configure this file as the SSLCACertificateFile." & vbLf & _ - "##" & vbLf & _ - "## Conversion done with mk-ca-bundle.vbs version " & myVersion & "." & vbLf -If (myCdSavF = TRUE) And (myUseOpenSSL = TRUE) Then - myStream.WriteText "## SHA256: " & FileSHA256(myCdFile) & vbLf -End If -myStream.WriteText "##" & vbLf & vbLf - -myStream.WriteText vbLf -For i = 0 To UBound(myLines) - If InstrRev(myLines(i), "CKA_LABEL ") Then - myPattern = "^CKA_LABEL\s+[A-Z0-9]+\s+""(.+?)""" - myLabel = RegExprFirst(myPattern, myLines(i)) - End If - If (myInsideCert = TRUE) Then - If InstrRev(myLines(i), "END") Then - myInsideCert = FALSE - While (i < UBound(myLines)) And Not (myLines(i) = "#") - i = i + 1 - If InstrRev(myLines(i), "CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR") Then - myUntrusted = FALSE - End If - Wend - If (myUntrusted = TRUE) Then - myNumSkipped = myNumSkipped + 1 - Else - myStream.WriteText myLabel & vbLf - myStream.WriteText String(Len(myLabel), "=") & vbLf - myPem = "-----BEGIN CERTIFICATE-----" & vbLf & _ - Base64Encode(myData) & vbLf & _ - "-----END CERTIFICATE-----" & vbLf - If (myOptTxt = FALSE) Then - myStream.WriteText myPem & vbLf - Else - Dim myCmd, myRval, myTmpIn, myTmpOut - myTmpIn = objFSO.GetSpecialFolder(2).Path & "\" & objFSO.GetTempName - myTmpOut = objFSO.GetSpecialFolder(2).Path & "\" & objFSO.GetTempName - Set myTmpFh = objFSO.OpenTextFile(myTmpIn, 2, TRUE) - myTmpFh.Write myPem - myTmpFh.Close - myCmd = """" & myOpenSSL & """ x509 -md5 -fingerprint -text " & _ - "-inform PEM -in " & myTmpIn & " -out " & myTmpOut - myRval = objShell.Run (myCmd, 0, TRUE) - objFSO.DeleteFile myTmpIn, TRUE - If Not (myRval = 0) Then - MsgBox("Failed to process PEM cert with OpenSSL commandline!"), vbCritical, mySelf - objFSO.DeleteFile myTmpOut, TRUE - WScript.Quit 3 - End If - Set myTmpFh = objFSO.OpenTextFile(myTmpOut, 1) - myStream.WriteText myTmpFh.ReadAll & vbLf - myTmpFh.Close - objFSO.DeleteFile myTmpOut, TRUE - End If - myNumCerts = myNumCerts + 1 - End If - Else - myOctets = Split(myLines(i), "\") - For j = 1 To UBound(myOctets) - myData = myData & Chr(CByte("&o" & myOctets(j))) - Next - End If - End If - If InstrRev(myLines(i), "CVS_ID ") Then - myPattern = "^CVS_ID\s+""(.+?)""" - myRev = RegExprFirst(myPattern, myLines(i)) - myStream.WriteText "# " & myRev & vbLf & vbLf - End If - If InstrRev(myLines(i), "CKA_VALUE MULTILINE_OCTAL") Then - myInsideCert = TRUE - myUntrusted = TRUE - myData = "" - End If - If InstrRev(myLines(i), "***** BEGIN LICENSE BLOCK *****") Then - myInsideLicense = TRUE - End If - If (myInsideLicense = TRUE) Then - myStream.WriteText myLines(i) & vbLf - myLicenseText = myLicenseText & Mid(myLines(i), 2) & vbLf - End If - If InstrRev(myLines(i), "***** END LICENSE BLOCK *****") Then - myInsideLicense = FALSE - If (myAskLiF = TRUE) Then - If Not (6 = objShell.PopUp(myLicenseText & vbLf & _ - "Do you agree to the license shown above (required to proceed) ?",, _ - mySelf, vbQuestion + vbYesNo + vbDefaultButton1)) Then - myStream.Close - objFSO.DeleteFile myCaFile, TRUE - WScript.Quit 2 - End If - End If - End If -Next - -' To stop the UTF-8 BOM from being written the stream has to be copied and -' then saved as binary. -Dim myCopy -Set myCopy = CreateObject("ADODB.Stream") -myCopy.Type = adTypeBinary -myCopy.Open -myStream.Position = 3 ' Skip UTF-8 BOM -myStream.CopyTo myCopy -myCopy.SaveToFile myCaFile, adSaveCreateOverWrite -myCopy.Close -myStream.Close -Set myCopy = Nothing -Set myStream = Nothing - -' Done -objShell.PopUp "Done (" & myNumCerts & " CA certs processed, " & myNumSkipped & _ - " untrusted skipped).", 20, mySelf, vbInformation -WScript.Quit 0 - -Function ConvertBinaryToUTF8(arrBytes) - Dim objStream - Set objStream = CreateObject("ADODB.Stream") - objStream.Open - objStream.Type = adTypeBinary - objStream.Write arrBytes - objStream.Position = 0 - objStream.Type = adTypeText - objStream.Charset = "utf-8" - ConvertBinaryToUTF8 = objStream.ReadText - Set objStream = Nothing -End Function - -Function SaveBinaryData(filename, data) - Dim objStream - Set objStream = CreateObject("ADODB.Stream") - objStream.Type = adTypeBinary - objStream.Open - objStream.Write data - objStream.SaveToFile filename, adSaveCreateOverWrite - objStream.Close - Set objStream = Nothing -End Function - -Function RegExprFirst(SearchPattern, TheString) - Dim objRegExp, Matches ' create variables. - Set objRegExp = New RegExp ' create a regular expression. - objRegExp.Pattern = SearchPattern ' sets the search pattern. - objRegExp.IgnoreCase = TRUE ' set to ignores case. - objRegExp.Global = TRUE ' set to gloabal search. - Set Matches = objRegExp.Execute(TheString) ' do the search. - If (Matches.Count) Then - RegExprFirst = Matches(0).SubMatches(0) ' return first match. - Else - RegExprFirst = "" - End If - Set objRegExp = Nothing -End Function - -Function Base64Encode(inData) - Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - Dim cOut, sOut, lWrap, I - lWrap = Int(myWrapLe * 3 / 4) - - 'For each group of 3 bytes - For I = 1 To Len(inData) Step 3 - Dim nGroup, pOut, sGroup - - 'Create one long from this 3 bytes. - nGroup = &H10000 * Asc(Mid(inData, I, 1)) + _ - &H100 * MyASC(Mid(inData, I + 1, 1)) + _ - MyASC(Mid(inData, I + 2, 1)) - - 'Oct splits the long To 8 groups with 3 bits - nGroup = Oct(nGroup) - - 'Add leading zeros - nGroup = String(8 - Len(nGroup), "0") & nGroup - - 'Convert To base64 - pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) & _ - Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) & _ - Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) & _ - Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1) - - 'Add the part To OutPut string - sOut = sOut + pOut - - 'Add a new line For Each myWrapLe chars In dest - If (I < Len(inData) - 2) Then - If (I + 2) Mod lWrap = 0 Then sOut = sOut & vbLf - End If - Next - Select Case Len(inData) Mod 3 - Case 1: '8 bit final - sOut = Left(sOut, Len(sOut) - 2) & "==" - Case 2: '16 bit final - sOut = Left(sOut, Len(sOut) - 1) & "=" - End Select - Base64Encode = sOut -End Function - -Function MyASC(OneChar) - If OneChar = "" Then MyASC = 0 Else MyASC = Asc(OneChar) -End Function - -' Return the date in the same format as perl to match mk-ca-bundle.pl output: -' Wed Sep 7 03:12:05 2016 -Function ConvertDateToString(input) - Dim output - output = WeekDayName(WeekDay(input), TRUE) & " " & _ - MonthName(Month(input), TRUE) & " " - If (Len(Day(input)) = 1) Then - output = output & " " - End If - output = output & _ - Day(input) & " " & _ - FormatDateTime(input, vbShortTime) & ":" - If (Len(Second(input)) = 1) Then - output = output & "0" - End If - output = output & _ - Second(input) & " " & _ - Year(input) - ConvertDateToString = output -End Function - -' Convert local Date to UTC. Microsoft says: -' Use Win32_ComputerSystem CurrentTimeZone property, because it automatically -' adjusts the Time Zone bias for daylight saving time; Win32_Time Zone Bias -' property does not. -' https://msdn.microsoft.com/en-us/library/windows/desktop/ms696015.aspx -Function LocalDateToUTC(localdate) - Dim item, offset - For Each item In GetObject("winmgmts:").InstancesOf("Win32_ComputerSystem") - offset = item.CurrentTimeZone ' the offset in minutes - Next - If (offset < 0) Then - LocalDateToUTC = DateAdd("n", ABS(offset), localdate) - Else - LocalDateToUTC = DateAdd("n", -ABS(offset), localdate) - End If - 'objShell.PopUp LocalDateToUTC -End Function - -Function FileSHA256(filename) - Dim cmd, rval, tmpOut, tmpFh - if (myUseOpenSSL = TRUE) Then - tmpOut = objFSO.GetSpecialFolder(2).Path & "\" & objFSO.GetTempName - cmd = """" & myOpenSSL & """ dgst -r -sha256 -out """ & tmpOut & """ """ & filename & """" - rval = objShell.Run(cmd, 0, TRUE) - If Not (rval = 0) Then - MsgBox("Failed to get sha256 of """ & filename & """ with OpenSSL commandline!"), vbCritical, mySelf - objFSO.DeleteFile tmpOut, TRUE - WScript.Quit 3 - End If - Set tmpFh = objFSO.OpenTextFile(tmpOut, 1) - FileSHA256 = RegExprFirst("^([0-9a-f]{64}) .+", tmpFh.ReadAll) - tmpFh.Close - objFSO.DeleteFile tmpOut, TRUE - Else - FileSHA256 = "" - End If -End Function diff --git a/dep/cpr/opt/curl/lib/mprintf.c b/dep/cpr/opt/curl/lib/mprintf.c deleted file mode 100644 index d2d91d74387..00000000000 --- a/dep/cpr/opt/curl/lib/mprintf.c +++ /dev/null @@ -1,1173 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1999 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * - * Purpose: - * A merge of Bjorn Reese's format() function and Daniel's dsprintf() - * 1.0. A full blooded printf() clone with full support for $ - * everywhere (parameters, widths and precisions) including variabled - * sized parameters (like doubles, long longs, long doubles and even - * void * in 64-bit architectures). - * - * Current restrictions: - * - Max 128 parameters - * - No 'long double' support. - * - * If you ever want truly portable and good *printf() clones, the project that - * took on from here is named 'Trio' and you find more details on the trio web - * page at https://daniel.haxx.se/projects/trio/ - */ - -#include "curl_setup.h" -#include - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * If SIZEOF_SIZE_T has not been defined, default to the size of long. - */ - -#ifdef HAVE_LONGLONG -# define LONG_LONG_TYPE long long -# define HAVE_LONG_LONG_TYPE -#else -# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) -# define LONG_LONG_TYPE __int64 -# define HAVE_LONG_LONG_TYPE -# else -# undef LONG_LONG_TYPE -# undef HAVE_LONG_LONG_TYPE -# endif -#endif - -/* - * Non-ANSI integer extensions - */ - -#if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \ - (defined(__WATCOMC__) && defined(__386__)) || \ - (defined(__POCC__) && defined(_MSC_VER)) || \ - (defined(_WIN32_WCE)) || \ - (defined(__MINGW32__)) || \ - (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)) -# define MP_HAVE_INT_EXTENSIONS -#endif - -/* - * Max integer data types that mprintf.c is capable - */ - -#ifdef HAVE_LONG_LONG_TYPE -# define mp_intmax_t LONG_LONG_TYPE -# define mp_uintmax_t unsigned LONG_LONG_TYPE -#else -# define mp_intmax_t long -# define mp_uintmax_t unsigned long -#endif - -#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should - fit negative DBL_MAX (317 letters) */ -#define MAX_PARAMETERS 128 /* lame static limit */ - -#ifdef __AMIGA__ -# undef FORMAT_INT -#endif - -/* Lower-case digits. */ -static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - -/* Upper-case digits. */ -static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -#define OUTCHAR(x) \ - do{ \ - if(stream((unsigned char)(x), (FILE *)data) != -1) \ - done++; \ - else \ - return done; /* return immediately on failure */ \ - } WHILE_FALSE - -/* Data type to read from the arglist */ -typedef enum { - FORMAT_UNKNOWN = 0, - FORMAT_STRING, - FORMAT_PTR, - FORMAT_INT, - FORMAT_INTPTR, - FORMAT_LONG, - FORMAT_LONGLONG, - FORMAT_DOUBLE, - FORMAT_LONGDOUBLE, - FORMAT_WIDTH /* For internal use */ -} FormatType; - -/* conversion and display flags */ -enum { - FLAGS_NEW = 0, - FLAGS_SPACE = 1<<0, - FLAGS_SHOWSIGN = 1<<1, - FLAGS_LEFT = 1<<2, - FLAGS_ALT = 1<<3, - FLAGS_SHORT = 1<<4, - FLAGS_LONG = 1<<5, - FLAGS_LONGLONG = 1<<6, - FLAGS_LONGDOUBLE = 1<<7, - FLAGS_PAD_NIL = 1<<8, - FLAGS_UNSIGNED = 1<<9, - FLAGS_OCTAL = 1<<10, - FLAGS_HEX = 1<<11, - FLAGS_UPPER = 1<<12, - FLAGS_WIDTH = 1<<13, /* '*' or '*$' used */ - FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ - FLAGS_PREC = 1<<15, /* precision was specified */ - FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */ - FLAGS_CHAR = 1<<17, /* %c story */ - FLAGS_FLOATE = 1<<18, /* %e or %E */ - FLAGS_FLOATG = 1<<19 /* %g or %G */ -}; - -typedef struct { - FormatType type; - int flags; - long width; /* width OR width parameter number */ - long precision; /* precision OR precision parameter number */ - union { - char *str; - void *ptr; - union { - mp_intmax_t as_signed; - mp_uintmax_t as_unsigned; - } num; - double dnum; - } data; -} va_stack_t; - -struct nsprintf { - char *buffer; - size_t length; - size_t max; -}; - -struct asprintf { - char *buffer; /* allocated buffer */ - size_t len; /* length of string */ - size_t alloc; /* length of alloc */ - int fail; /* (!= 0) if an alloc has failed and thus - the output is not the complete data */ -}; - -static long dprintf_DollarString(char *input, char **end) -{ - int number = 0; - while(ISDIGIT(*input)) { - number *= 10; - number += *input-'0'; - input++; - } - if(number && ('$'==*input++)) { - *end = input; - return number; - } - return 0; -} - -static bool dprintf_IsQualifierNoDollar(const char *fmt) -{ -#if defined(MP_HAVE_INT_EXTENSIONS) - if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) { - return TRUE; - } -#endif - - switch(*fmt) { - case '-': case '+': case ' ': case '#': case '.': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case 'h': case 'l': case 'L': case 'z': case 'q': - case '*': case 'O': -#if defined(MP_HAVE_INT_EXTENSIONS) - case 'I': -#endif - return TRUE; - - default: - return FALSE; - } -} - -/****************************************************************** - * - * Pass 1: - * Create an index with the type of each parameter entry and its - * value (may vary in size) - * - * Returns zero on success. - * - ******************************************************************/ - -static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, - va_list arglist) -{ - char *fmt = (char *)format; - int param_num = 0; - long this_param; - long width; - long precision; - int flags; - long max_param = 0; - long i; - - while(*fmt) { - if(*fmt++ == '%') { - if(*fmt == '%') { - fmt++; - continue; /* while */ - } - - flags = FLAGS_NEW; - - /* Handle the positional case (N$) */ - - param_num++; - - this_param = dprintf_DollarString(fmt, &fmt); - if(0 == this_param) - /* we got no positional, get the next counter */ - this_param = param_num; - - if(this_param > max_param) - max_param = this_param; - - /* - * The parameter with number 'i' should be used. Next, we need - * to get SIZE and TYPE of the parameter. Add the information - * to our array. - */ - - width = 0; - precision = 0; - - /* Handle the flags */ - - while(dprintf_IsQualifierNoDollar(fmt)) { -#if defined(MP_HAVE_INT_EXTENSIONS) - if(!strncmp(fmt, "I32", 3)) { - flags |= FLAGS_LONG; - fmt += 3; - } - else if(!strncmp(fmt, "I64", 3)) { - flags |= FLAGS_LONGLONG; - fmt += 3; - } - else -#endif - - switch(*fmt++) { - case ' ': - flags |= FLAGS_SPACE; - break; - case '+': - flags |= FLAGS_SHOWSIGN; - break; - case '-': - flags |= FLAGS_LEFT; - flags &= ~FLAGS_PAD_NIL; - break; - case '#': - flags |= FLAGS_ALT; - break; - case '.': - if('*' == *fmt) { - /* The precision is picked from a specified parameter */ - - flags |= FLAGS_PRECPARAM; - fmt++; - param_num++; - - i = dprintf_DollarString(fmt, &fmt); - if(i) - precision = i; - else - precision = param_num; - - if(precision > max_param) - max_param = precision; - } - else { - flags |= FLAGS_PREC; - precision = strtol(fmt, &fmt, 10); - } - break; - case 'h': - flags |= FLAGS_SHORT; - break; -#if defined(MP_HAVE_INT_EXTENSIONS) - case 'I': -#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) - flags |= FLAGS_LONGLONG; -#else - flags |= FLAGS_LONG; -#endif - break; -#endif - case 'l': - if(flags & FLAGS_LONG) - flags |= FLAGS_LONGLONG; - else - flags |= FLAGS_LONG; - break; - case 'L': - flags |= FLAGS_LONGDOUBLE; - break; - case 'q': - flags |= FLAGS_LONGLONG; - break; - case 'z': - /* the code below generates a warning if -Wunreachable-code is - used */ -#if (SIZEOF_SIZE_T > SIZEOF_LONG) - flags |= FLAGS_LONGLONG; -#else - flags |= FLAGS_LONG; -#endif - break; - case 'O': -#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) - flags |= FLAGS_LONGLONG; -#else - flags |= FLAGS_LONG; -#endif - break; - case '0': - if(!(flags & FLAGS_LEFT)) - flags |= FLAGS_PAD_NIL; - /* FALLTHROUGH */ - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - flags |= FLAGS_WIDTH; - width = strtol(fmt-1, &fmt, 10); - break; - case '*': /* Special case */ - flags |= FLAGS_WIDTHPARAM; - param_num++; - - i = dprintf_DollarString(fmt, &fmt); - if(i) - width = i; - else - width = param_num; - if(width > max_param) - max_param = width; - break; - default: - break; - } - } /* switch */ - - /* Handle the specifier */ - - i = this_param - 1; - - if((i < 0) || (i >= MAX_PARAMETERS)) - /* out of allowed range */ - return 1; - - switch (*fmt) { - case 'S': - flags |= FLAGS_ALT; - /* FALLTHROUGH */ - case 's': - vto[i].type = FORMAT_STRING; - break; - case 'n': - vto[i].type = FORMAT_INTPTR; - break; - case 'p': - vto[i].type = FORMAT_PTR; - break; - case 'd': case 'i': - vto[i].type = FORMAT_INT; - break; - case 'u': - vto[i].type = FORMAT_INT; - flags |= FLAGS_UNSIGNED; - break; - case 'o': - vto[i].type = FORMAT_INT; - flags |= FLAGS_OCTAL; - break; - case 'x': - vto[i].type = FORMAT_INT; - flags |= FLAGS_HEX|FLAGS_UNSIGNED; - break; - case 'X': - vto[i].type = FORMAT_INT; - flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED; - break; - case 'c': - vto[i].type = FORMAT_INT; - flags |= FLAGS_CHAR; - break; - case 'f': - vto[i].type = FORMAT_DOUBLE; - break; - case 'e': - vto[i].type = FORMAT_DOUBLE; - flags |= FLAGS_FLOATE; - break; - case 'E': - vto[i].type = FORMAT_DOUBLE; - flags |= FLAGS_FLOATE|FLAGS_UPPER; - break; - case 'g': - vto[i].type = FORMAT_DOUBLE; - flags |= FLAGS_FLOATG; - break; - case 'G': - vto[i].type = FORMAT_DOUBLE; - flags |= FLAGS_FLOATG|FLAGS_UPPER; - break; - default: - vto[i].type = FORMAT_UNKNOWN; - break; - } /* switch */ - - vto[i].flags = flags; - vto[i].width = width; - vto[i].precision = precision; - - if(flags & FLAGS_WIDTHPARAM) { - /* we have the width specified from a parameter, so we make that - parameter's info setup properly */ - long k = width - 1; - vto[i].width = k; - vto[k].type = FORMAT_WIDTH; - vto[k].flags = FLAGS_NEW; - /* can't use width or precision of width! */ - vto[k].width = 0; - vto[k].precision = 0; - } - if(flags & FLAGS_PRECPARAM) { - /* we have the precision specified from a parameter, so we make that - parameter's info setup properly */ - long k = precision - 1; - vto[i].precision = k; - vto[k].type = FORMAT_WIDTH; - vto[k].flags = FLAGS_NEW; - /* can't use width or precision of width! */ - vto[k].width = 0; - vto[k].precision = 0; - } - *endpos++ = fmt + 1; /* end of this sequence */ - } - } - - /* Read the arg list parameters into our data list */ - for(i = 0; i$ sequence */ - param = dprintf_DollarString(f, &f); - - if(!param) - param = param_num; - else - --param; - - param_num++; /* increase this always to allow "%2$s %1$s %s" and then the - third %s will pick the 3rd argument */ - - p = &vto[param]; - - /* pick up the specified width */ - if(p->flags & FLAGS_WIDTHPARAM) { - width = (long)vto[p->width].data.num.as_signed; - param_num++; /* since the width is extracted from a parameter, we - must skip that to get to the next one properly */ - if(width < 0) { - /* "A negative field width is taken as a '-' flag followed by a - positive field width." */ - width = -width; - p->flags |= FLAGS_LEFT; - p->flags &= ~FLAGS_PAD_NIL; - } - } - else - width = p->width; - - /* pick up the specified precision */ - if(p->flags & FLAGS_PRECPARAM) { - prec = (long)vto[p->precision].data.num.as_signed; - param_num++; /* since the precision is extracted from a parameter, we - must skip that to get to the next one properly */ - if(prec < 0) - /* "A negative precision is taken as if the precision were - omitted." */ - prec = -1; - } - else if(p->flags & FLAGS_PREC) - prec = p->precision; - else - prec = -1; - - is_alt = (p->flags & FLAGS_ALT) ? 1 : 0; - - switch(p->type) { - case FORMAT_INT: - num = p->data.num.as_unsigned; - if(p->flags & FLAGS_CHAR) { - /* Character. */ - if(!(p->flags & FLAGS_LEFT)) - while(--width > 0) - OUTCHAR(' '); - OUTCHAR((char) num); - if(p->flags & FLAGS_LEFT) - while(--width > 0) - OUTCHAR(' '); - break; - } - if(p->flags & FLAGS_OCTAL) { - /* Octal unsigned integer. */ - base = 8; - goto unsigned_number; - } - else if(p->flags & FLAGS_HEX) { - /* Hexadecimal unsigned integer. */ - - digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; - base = 16; - goto unsigned_number; - } - else if(p->flags & FLAGS_UNSIGNED) { - /* Decimal unsigned integer. */ - base = 10; - goto unsigned_number; - } - - /* Decimal integer. */ - base = 10; - - is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0; - if(is_neg) { - /* signed_num might fail to hold absolute negative minimum by 1 */ - signed_num = p->data.num.as_signed + (mp_intmax_t)1; - signed_num = -signed_num; - num = (mp_uintmax_t)signed_num; - num += (mp_uintmax_t)1; - } - - goto number; - - unsigned_number: - /* Unsigned number of base BASE. */ - is_neg = 0; - - number: - /* Number of base BASE. */ - - /* Supply a default precision if none was given. */ - if(prec == -1) - prec = 1; - - /* Put the number in WORK. */ - w = workend; - while(num > 0) { - *w-- = digits[num % base]; - num /= base; - } - width -= (long)(workend - w); - prec -= (long)(workend - w); - - if(is_alt && base == 8 && prec <= 0) { - *w-- = '0'; - --width; - } - - if(prec > 0) { - width -= prec; - while(prec-- > 0) - *w-- = '0'; - } - - if(is_alt && base == 16) - width -= 2; - - if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) - --width; - - if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) - while(width-- > 0) - OUTCHAR(' '); - - if(is_neg) - OUTCHAR('-'); - else if(p->flags & FLAGS_SHOWSIGN) - OUTCHAR('+'); - else if(p->flags & FLAGS_SPACE) - OUTCHAR(' '); - - if(is_alt && base == 16) { - OUTCHAR('0'); - if(p->flags & FLAGS_UPPER) - OUTCHAR('X'); - else - OUTCHAR('x'); - } - - if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) - while(width-- > 0) - OUTCHAR('0'); - - /* Write the number. */ - while(++w <= workend) { - OUTCHAR(*w); - } - - if(p->flags & FLAGS_LEFT) - while(width-- > 0) - OUTCHAR(' '); - break; - - case FORMAT_STRING: - /* String. */ - { - static const char null[] = "(nil)"; - const char *str; - size_t len; - - str = (char *) p->data.str; - if(str == NULL) { - /* Write null[] if there's space. */ - if(prec == -1 || prec >= (long) sizeof(null) - 1) { - str = null; - len = sizeof(null) - 1; - /* Disable quotes around (nil) */ - p->flags &= (~FLAGS_ALT); - } - else { - str = ""; - len = 0; - } - } - else if(prec != -1) - len = (size_t)prec; - else - len = strlen(str); - - width -= (len > LONG_MAX) ? LONG_MAX : (long)len; - - if(p->flags & FLAGS_ALT) - OUTCHAR('"'); - - if(!(p->flags&FLAGS_LEFT)) - while(width-- > 0) - OUTCHAR(' '); - - while((len-- > 0) && *str) - OUTCHAR(*str++); - if(p->flags&FLAGS_LEFT) - while(width-- > 0) - OUTCHAR(' '); - - if(p->flags & FLAGS_ALT) - OUTCHAR('"'); - } - break; - - case FORMAT_PTR: - /* Generic pointer. */ - { - void *ptr; - ptr = (void *) p->data.ptr; - if(ptr != NULL) { - /* If the pointer is not NULL, write it as a %#x spec. */ - base = 16; - digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; - is_alt = 1; - num = (size_t) ptr; - is_neg = 0; - goto number; - } - else { - /* Write "(nil)" for a nil pointer. */ - static const char strnil[] = "(nil)"; - const char *point; - - width -= (long)(sizeof(strnil) - 1); - if(p->flags & FLAGS_LEFT) - while(width-- > 0) - OUTCHAR(' '); - for(point = strnil; *point != '\0'; ++point) - OUTCHAR(*point); - if(! (p->flags & FLAGS_LEFT)) - while(width-- > 0) - OUTCHAR(' '); - } - } - break; - - case FORMAT_DOUBLE: - { - char formatbuf[32]="%"; - char *fptr = &formatbuf[1]; - size_t left = sizeof(formatbuf)-strlen(formatbuf); - int len; - - width = -1; - if(p->flags & FLAGS_WIDTH) - width = p->width; - else if(p->flags & FLAGS_WIDTHPARAM) - width = (long)vto[p->width].data.num.as_signed; - - prec = -1; - if(p->flags & FLAGS_PREC) - prec = p->precision; - else if(p->flags & FLAGS_PRECPARAM) - prec = (long)vto[p->precision].data.num.as_signed; - - if(p->flags & FLAGS_LEFT) - *fptr++ = '-'; - if(p->flags & FLAGS_SHOWSIGN) - *fptr++ = '+'; - if(p->flags & FLAGS_SPACE) - *fptr++ = ' '; - if(p->flags & FLAGS_ALT) - *fptr++ = '#'; - - *fptr = 0; - - if(width >= 0) { - if(width >= (long)sizeof(work)) - width = sizeof(work)-1; - /* RECURSIVE USAGE */ - len = curl_msnprintf(fptr, left, "%ld", width); - fptr += len; - left -= len; - } - if(prec >= 0) { - /* for each digit in the integer part, we can have one less - precision */ - size_t maxprec = sizeof(work) - 2; - double val = p->data.dnum; - while(val >= 10.0) { - val /= 10; - maxprec--; - } - - if(prec > (long)maxprec) - prec = (long)maxprec-1; - /* RECURSIVE USAGE */ - len = curl_msnprintf(fptr, left, ".%ld", prec); - fptr += len; - } - if(p->flags & FLAGS_LONG) - *fptr++ = 'l'; - - if(p->flags & FLAGS_FLOATE) - *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e'); - else if(p->flags & FLAGS_FLOATG) - *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g'); - else - *fptr++ = 'f'; - - *fptr = 0; /* and a final zero termination */ - - /* NOTE NOTE NOTE!! Not all sprintf implementations return number of - output characters */ - (sprintf)(work, formatbuf, p->data.dnum); - DEBUGASSERT(strlen(work) <= sizeof(work)); - for(fptr = work; *fptr; fptr++) - OUTCHAR(*fptr); - } - break; - - case FORMAT_INTPTR: - /* Answer the count of characters written. */ -#ifdef HAVE_LONG_LONG_TYPE - if(p->flags & FLAGS_LONGLONG) - *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done; - else -#endif - if(p->flags & FLAGS_LONG) - *(long *) p->data.ptr = (long)done; - else if(!(p->flags & FLAGS_SHORT)) - *(int *) p->data.ptr = (int)done; - else - *(short *) p->data.ptr = (short)done; - break; - - default: - break; - } - f = *end++; /* goto end of %-code */ - - } - return done; -} - -/* fputc() look-alike */ -static int addbyter(int output, FILE *data) -{ - struct nsprintf *infop = (struct nsprintf *)data; - unsigned char outc = (unsigned char)output; - - if(infop->length < infop->max) { - /* only do this if we haven't reached max length yet */ - infop->buffer[0] = outc; /* store */ - infop->buffer++; /* increase pointer */ - infop->length++; /* we are now one byte larger */ - return outc; /* fputc() returns like this on success */ - } - return -1; -} - -int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, - va_list ap_save) -{ - int retcode; - struct nsprintf info; - - info.buffer = buffer; - info.length = 0; - info.max = maxlength; - - retcode = dprintf_formatf(&info, addbyter, format, ap_save); - if((retcode != -1) && info.max) { - /* we terminate this with a zero byte */ - if(info.max == info.length) - /* we're at maximum, scrap the last letter */ - info.buffer[-1] = 0; - else - info.buffer[0] = 0; - } - return retcode; -} - -int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) -{ - int retcode; - va_list ap_save; /* argument pointer */ - va_start(ap_save, format); - retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save); - va_end(ap_save); - return retcode; -} - -/* fputc() look-alike */ -static int alloc_addbyter(int output, FILE *data) -{ - struct asprintf *infop = (struct asprintf *)data; - unsigned char outc = (unsigned char)output; - - if(!infop->buffer) { - infop->buffer = malloc(32); - if(!infop->buffer) { - infop->fail = 1; - return -1; /* fail */ - } - infop->alloc = 32; - infop->len = 0; - } - else if(infop->len + 1 >= infop->alloc) { - char *newptr = NULL; - size_t newsize = infop->alloc*2; - - /* detect wrap-around or other overflow problems */ - if(newsize > infop->alloc) - newptr = realloc(infop->buffer, newsize); - - if(!newptr) { - infop->fail = 1; - return -1; /* fail */ - } - infop->buffer = newptr; - infop->alloc = newsize; - } - - infop->buffer[ infop->len ] = outc; - - infop->len++; - - return outc; /* fputc() returns like this on success */ -} - -char *curl_maprintf(const char *format, ...) -{ - va_list ap_save; /* argument pointer */ - int retcode; - struct asprintf info; - - info.buffer = NULL; - info.len = 0; - info.alloc = 0; - info.fail = 0; - - va_start(ap_save, format); - retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); - va_end(ap_save); - if((-1 == retcode) || info.fail) { - if(info.alloc) - free(info.buffer); - return NULL; - } - if(info.alloc) { - info.buffer[info.len] = 0; /* we terminate this with a zero byte */ - return info.buffer; - } - return strdup(""); -} - -char *curl_mvaprintf(const char *format, va_list ap_save) -{ - int retcode; - struct asprintf info; - - info.buffer = NULL; - info.len = 0; - info.alloc = 0; - info.fail = 0; - - retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); - if((-1 == retcode) || info.fail) { - if(info.alloc) - free(info.buffer); - return NULL; - } - - if(info.alloc) { - info.buffer[info.len] = 0; /* we terminate this with a zero byte */ - return info.buffer; - } - return strdup(""); -} - -static int storebuffer(int output, FILE *data) -{ - char **buffer = (char **)data; - unsigned char outc = (unsigned char)output; - **buffer = outc; - (*buffer)++; - return outc; /* act like fputc() ! */ -} - -int curl_msprintf(char *buffer, const char *format, ...) -{ - va_list ap_save; /* argument pointer */ - int retcode; - va_start(ap_save, format); - retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); - va_end(ap_save); - *buffer = 0; /* we terminate this with a zero byte */ - return retcode; -} - -int curl_mprintf(const char *format, ...) -{ - int retcode; - va_list ap_save; /* argument pointer */ - va_start(ap_save, format); - - retcode = dprintf_formatf(stdout, fputc, format, ap_save); - va_end(ap_save); - return retcode; -} - -int curl_mfprintf(FILE *whereto, const char *format, ...) -{ - int retcode; - va_list ap_save; /* argument pointer */ - va_start(ap_save, format); - retcode = dprintf_formatf(whereto, fputc, format, ap_save); - va_end(ap_save); - return retcode; -} - -int curl_mvsprintf(char *buffer, const char *format, va_list ap_save) -{ - int retcode; - retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); - *buffer = 0; /* we terminate this with a zero byte */ - return retcode; -} - -int curl_mvprintf(const char *format, va_list ap_save) -{ - return dprintf_formatf(stdout, fputc, format, ap_save); -} - -int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) -{ - return dprintf_formatf(whereto, fputc, format, ap_save); -} diff --git a/dep/cpr/opt/curl/lib/multi.c b/dep/cpr/opt/curl/lib/multi.c deleted file mode 100644 index 70aa6bcf987..00000000000 --- a/dep/cpr/opt/curl/lib/multi.c +++ /dev/null @@ -1,3142 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "urldata.h" -#include "transfer.h" -#include "url.h" -#include "connect.h" -#include "progress.h" -#include "easyif.h" -#include "share.h" -#include "multiif.h" -#include "sendf.h" -#include "timeval.h" -#include "http.h" -#include "select.h" -#include "warnless.h" -#include "speedcheck.h" -#include "conncache.h" -#include "multihandle.h" -#include "pipeline.h" -#include "sigpipe.h" -#include "vtls/vtls.h" -#include "connect.h" -#include "http_proxy.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* - CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97 - to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every - CURL handle takes 45-50 K memory, therefore this 3K are not significant. -*/ -#ifndef CURL_SOCKET_HASH_TABLE_SIZE -#define CURL_SOCKET_HASH_TABLE_SIZE 911 -#endif - -#define CURL_CONNECTION_HASH_SIZE 97 - -#define CURL_MULTI_HANDLE 0x000bab1e - -#define GOOD_MULTI_HANDLE(x) \ - ((x) && (x)->type == CURL_MULTI_HANDLE) - -static void singlesocket(struct Curl_multi *multi, - struct Curl_easy *data); -static int update_timer(struct Curl_multi *multi); - -static CURLMcode add_next_timeout(struct curltime now, - struct Curl_multi *multi, - struct Curl_easy *d); -static CURLMcode multi_timeout(struct Curl_multi *multi, - long *timeout_ms); - -#ifdef DEBUGBUILD -static const char * const statename[]={ - "INIT", - "CONNECT_PEND", - "CONNECT", - "WAITRESOLVE", - "WAITCONNECT", - "WAITPROXYCONNECT", - "SENDPROTOCONNECT", - "PROTOCONNECT", - "WAITDO", - "DO", - "DOING", - "DO_MORE", - "DO_DONE", - "WAITPERFORM", - "PERFORM", - "TOOFAST", - "DONE", - "COMPLETED", - "MSGSENT", -}; -#endif - -/* function pointer called once when switching TO a state */ -typedef void (*init_multistate_func)(struct Curl_easy *data); - -/* always use this function to change state, to make debugging easier */ -static void mstate(struct Curl_easy *data, CURLMstate state -#ifdef DEBUGBUILD - , int lineno -#endif -) -{ - CURLMstate oldstate = data->mstate; - static const init_multistate_func finit[CURLM_STATE_LAST] = { - NULL, - NULL, - Curl_init_CONNECT, /* CONNECT */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - Curl_connect_free /* DO */ - /* the rest is NULL too */ - }; - -#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) lineno; -#endif - - if(oldstate == state) - /* don't bother when the new state is the same as the old state */ - return; - - data->mstate = state; - -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - if(data->mstate >= CURLM_STATE_CONNECT_PEND && - data->mstate < CURLM_STATE_COMPLETED) { - long connection_id = -5000; - - if(data->easy_conn) - connection_id = data->easy_conn->connection_id; - - infof(data, - "STATE: %s => %s handle %p; line %d (connection #%ld)\n", - statename[oldstate], statename[data->mstate], - (void *)data, lineno, connection_id); - } -#endif - - if(state == CURLM_STATE_COMPLETED) - /* changing to COMPLETED means there's one less easy handle 'alive' */ - data->multi->num_alive--; - - /* if this state has an init-function, run it */ - if(finit[state]) - finit[state](data); -} - -#ifndef DEBUGBUILD -#define multistate(x,y) mstate(x,y) -#else -#define multistate(x,y) mstate(x,y, __LINE__) -#endif - -/* - * We add one of these structs to the sockhash for a particular socket - */ - -struct Curl_sh_entry { - struct Curl_easy *easy; - int action; /* what action READ/WRITE this socket waits for */ - curl_socket_t socket; /* mainly to ease debugging */ - void *socketp; /* settable by users with curl_multi_assign() */ -}; -/* bits for 'action' having no bits means this socket is not expecting any - action */ -#define SH_READ 1 -#define SH_WRITE 2 - -/* look up a given socket in the socket hash, skip invalid sockets */ -static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh, - curl_socket_t s) -{ - if(s != CURL_SOCKET_BAD) - /* only look for proper sockets */ - return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); - return NULL; -} - -/* make sure this socket is present in the hash for this handle */ -static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, - curl_socket_t s, - struct Curl_easy *data) -{ - struct Curl_sh_entry *there = sh_getentry(sh, s); - struct Curl_sh_entry *check; - - if(there) - /* it is present, return fine */ - return there; - - /* not present, add it */ - check = calloc(1, sizeof(struct Curl_sh_entry)); - if(!check) - return NULL; /* major failure */ - - check->easy = data; - check->socket = s; - - /* make/add new hash entry */ - if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { - free(check); - return NULL; /* major failure */ - } - - return check; /* things are good in sockhash land */ -} - - -/* delete the given socket + handle from the hash */ -static void sh_delentry(struct curl_hash *sh, curl_socket_t s) -{ - /* We remove the hash entry. This will end up in a call to - sh_freeentry(). */ - Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); -} - -/* - * free a sockhash entry - */ -static void sh_freeentry(void *freethis) -{ - struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis; - - free(p); -} - -static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) -{ - (void) k1_len; (void) k2_len; - - return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2)); -} - -static size_t hash_fd(void *key, size_t key_length, size_t slots_num) -{ - curl_socket_t fd = *((curl_socket_t *) key); - (void) key_length; - - return (fd % slots_num); -} - -/* - * sh_init() creates a new socket hash and returns the handle for it. - * - * Quote from README.multi_socket: - * - * "Some tests at 7000 and 9000 connections showed that the socket hash lookup - * is somewhat of a bottle neck. Its current implementation may be a bit too - * limiting. It simply has a fixed-size array, and on each entry in the array - * it has a linked list with entries. So the hash only checks which list to - * scan through. The code I had used so for used a list with merely 7 slots - * (as that is what the DNS hash uses) but with 7000 connections that would - * make an average of 1000 nodes in each list to run through. I upped that to - * 97 slots (I believe a prime is suitable) and noticed a significant speed - * increase. I need to reconsider the hash implementation or use a rather - * large default value like this. At 9000 connections I was still below 10us - * per call." - * - */ -static int sh_init(struct curl_hash *hash, int hashsize) -{ - return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare, - sh_freeentry); -} - -/* - * multi_addmsg() - * - * Called when a transfer is completed. Adds the given msg pointer to - * the list kept in the multi handle. - */ -static CURLMcode multi_addmsg(struct Curl_multi *multi, - struct Curl_message *msg) -{ - Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg, - &msg->list); - return CURLM_OK; -} - -/* - * multi_freeamsg() - * - * Callback used by the llist system when a single list entry is destroyed. - */ -static void multi_freeamsg(void *a, void *b) -{ - (void)a; - (void)b; -} - -struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ - int chashsize) /* connection hash */ -{ - struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi)); - - if(!multi) - return NULL; - - multi->type = CURL_MULTI_HANDLE; - - if(Curl_mk_dnscache(&multi->hostcache)) - goto error; - - if(sh_init(&multi->sockhash, hashsize)) - goto error; - - if(Curl_conncache_init(&multi->conn_cache, chashsize)) - goto error; - - Curl_llist_init(&multi->msglist, multi_freeamsg); - Curl_llist_init(&multi->pending, multi_freeamsg); - - /* allocate a new easy handle to use when closing cached connections */ - multi->closure_handle = curl_easy_init(); - if(!multi->closure_handle) - goto error; - - multi->closure_handle->multi = multi; - multi->closure_handle->state.conn_cache = &multi->conn_cache; - - multi->max_pipeline_length = 5; - - /* -1 means it not set by user, use the default value */ - multi->maxconnects = -1; - return multi; - - error: - - Curl_hash_destroy(&multi->sockhash); - Curl_hash_destroy(&multi->hostcache); - Curl_conncache_destroy(&multi->conn_cache); - Curl_close(multi->closure_handle); - multi->closure_handle = NULL; - Curl_llist_destroy(&multi->msglist, NULL); - Curl_llist_destroy(&multi->pending, NULL); - - free(multi); - return NULL; -} - -struct Curl_multi *curl_multi_init(void) -{ - return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE, - CURL_CONNECTION_HASH_SIZE); -} - -CURLMcode curl_multi_add_handle(struct Curl_multi *multi, - struct Curl_easy *data) -{ - /* First, make some basic checks that the CURLM handle is a good handle */ - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - /* Verify that we got a somewhat good easy handle too */ - if(!GOOD_EASY_HANDLE(data)) - return CURLM_BAD_EASY_HANDLE; - - /* Prevent users from adding same easy handle more than once and prevent - adding to more than one multi stack */ - if(data->multi) - return CURLM_ADDED_ALREADY; - - /* Initialize timeout list for this handle */ - Curl_llist_init(&data->state.timeoutlist, NULL); - - /* - * No failure allowed in this function beyond this point. And no - * modification of easy nor multi handle allowed before this except for - * potential multi's connection cache growing which won't be undone in this - * function no matter what. - */ - - /* set the easy handle */ - multistate(data, CURLM_STATE_INIT); - - if((data->set.global_dns_cache) && - (data->dns.hostcachetype != HCACHE_GLOBAL)) { - /* global dns cache was requested but still isn't */ - struct curl_hash *global = Curl_global_host_cache_init(); - if(global) { - /* only do this if the global cache init works */ - data->dns.hostcache = global; - data->dns.hostcachetype = HCACHE_GLOBAL; - } - } - /* for multi interface connections, we share DNS cache automatically if the - easy handle's one is currently not set. */ - else if(!data->dns.hostcache || - (data->dns.hostcachetype == HCACHE_NONE)) { - data->dns.hostcache = &multi->hostcache; - data->dns.hostcachetype = HCACHE_MULTI; - } - - /* Point to the multi's connection cache */ - data->state.conn_cache = &multi->conn_cache; - - /* This adds the new entry at the 'end' of the doubly-linked circular - list of Curl_easy structs to try and maintain a FIFO queue so - the pipelined requests are in order. */ - - /* We add this new entry last in the list. */ - - data->next = NULL; /* end of the line */ - if(multi->easyp) { - struct Curl_easy *last = multi->easylp; - last->next = data; - data->prev = last; - multi->easylp = data; /* the new last node */ - } - else { - /* first node, make prev NULL! */ - data->prev = NULL; - multi->easylp = multi->easyp = data; /* both first and last */ - } - - /* make the Curl_easy refer back to this multi handle */ - data->multi = multi; - - /* Set the timeout for this handle to expire really soon so that it will - be taken care of even when this handle is added in the midst of operation - when only the curl_multi_socket() API is used. During that flow, only - sockets that time-out or have actions will be dealt with. Since this - handle has no action yet, we make sure it times out to get things to - happen. */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); - - /* increase the node-counter */ - multi->num_easy++; - - /* increase the alive-counter */ - multi->num_alive++; - - /* A somewhat crude work-around for a little glitch in update_timer() that - happens if the lastcall time is set to the same time when the handle is - removed as when the next handle is added, as then the check in - update_timer() that prevents calling the application multiple times with - the same timer infor will not trigger and then the new handle's timeout - will not be notified to the app. - - The work-around is thus simply to clear the 'lastcall' variable to force - update_timer() to always trigger a callback to the app when a new easy - handle is added */ - memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); - - /* The closure handle only ever has default timeouts set. To improve the - state somewhat we clone the timeouts from each added handle so that the - closure handle always has the same timeouts as the most recently added - easy handle. */ - multi->closure_handle->set.timeout = data->set.timeout; - multi->closure_handle->set.server_response_timeout = - data->set.server_response_timeout; - - update_timer(multi); - return CURLM_OK; -} - -#if 0 -/* Debug-function, used like this: - * - * Curl_hash_print(multi->sockhash, debug_print_sock_hash); - * - * Enable the hash print function first by editing hash.c - */ -static void debug_print_sock_hash(void *p) -{ - struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; - - fprintf(stderr, " [easy %p/magic %x/socket %d]", - (void *)sh->data, sh->data->magic, (int)sh->socket); -} -#endif - -/* Mark the connection as 'idle', or close it if the cache is full. - Returns TRUE if the connection is kept, or FALSE if it was closed. */ -static bool -ConnectionDone(struct Curl_easy *data, struct connectdata *conn) -{ - /* data->multi->maxconnects can be negative, deal with it. */ - size_t maxconnects = - (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: - data->multi->maxconnects; - struct connectdata *conn_candidate = NULL; - - /* Mark the current connection as 'unused' */ - conn->inuse = FALSE; - - if(maxconnects > 0 && - data->state.conn_cache->num_connections > maxconnects) { - infof(data, "Connection cache is full, closing the oldest one.\n"); - - conn_candidate = Curl_oldest_idle_connection(data); - - if(conn_candidate) { - /* Set the connection's owner correctly */ - conn_candidate->data = data; - - /* the winner gets the honour of being disconnected */ - (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); - } - } - - return (conn_candidate == conn) ? FALSE : TRUE; -} - -static CURLcode multi_done(struct connectdata **connp, - CURLcode status, /* an error if this is called - after an error was detected */ - bool premature) -{ - CURLcode result; - struct connectdata *conn; - struct Curl_easy *data; - unsigned int i; - - DEBUGASSERT(*connp); - - conn = *connp; - data = conn->data; - - DEBUGF(infof(data, "multi_done\n")); - - if(data->state.done) - /* Stop if multi_done() has already been called */ - return CURLE_OK; - - Curl_getoff_all_pipelines(data, conn); - - /* Cleanup possible redirect junk */ - free(data->req.newurl); - data->req.newurl = NULL; - free(data->req.location); - data->req.location = NULL; - - switch(status) { - case CURLE_ABORTED_BY_CALLBACK: - case CURLE_READ_ERROR: - case CURLE_WRITE_ERROR: - /* When we're aborted due to a callback return code it basically have to - be counted as premature as there is trouble ahead if we don't. We have - many callbacks and protocols work differently, we could potentially do - this more fine-grained in the future. */ - premature = TRUE; - default: - break; - } - - /* this calls the protocol-specific function pointer previously set */ - if(conn->handler->done) - result = conn->handler->done(conn, status, premature); - else - result = status; - - if(CURLE_ABORTED_BY_CALLBACK != result) { - /* avoid this if we already aborted by callback to avoid this calling - another callback */ - CURLcode rc = Curl_pgrsDone(conn); - if(!result && rc) - result = CURLE_ABORTED_BY_CALLBACK; - } - - if(conn->send_pipe.size + conn->recv_pipe.size != 0 && - !data->set.reuse_forbid && - !conn->bits.close) { - /* Stop if pipeline is not empty and we do not have to close - connection. */ - data->easy_conn = NULL; - DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n")); - return CURLE_OK; - } - - data->state.done = TRUE; /* called just now! */ - Curl_resolver_cancel(conn); - - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ - conn->dns_entry = NULL; - } - - /* if the transfer was completed in a paused state there can be buffered - data left to free */ - for(i = 0; i < data->state.tempcount; i++) { - free(data->state.tempwrite[i].buf); - } - data->state.tempcount = 0; - - /* if data->set.reuse_forbid is TRUE, it means the libcurl client has - forced us to close this connection. This is ignored for requests taking - place in a NTLM authentication handshake - - if conn->bits.close is TRUE, it means that the connection should be - closed in spite of all our efforts to be nice, due to protocol - restrictions in our or the server's end - - if premature is TRUE, it means this connection was said to be DONE before - the entire request operation is complete and thus we can't know in what - state it is for re-using, so we're forced to close it. In a perfect world - we can add code that keep track of if we really must close it here or not, - but currently we have no such detail knowledge. - */ - - if((data->set.reuse_forbid -#if defined(USE_NTLM) - && !(conn->ntlm.state == NTLMSTATE_TYPE2 || - conn->proxyntlm.state == NTLMSTATE_TYPE2) -#endif - ) || conn->bits.close || premature) { - CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ - - /* If we had an error already, make sure we return that one. But - if we got a new error, return that. */ - if(!result && res2) - result = res2; - } - else { - /* the connection is no longer in use */ - if(ConnectionDone(data, conn)) { - /* remember the most recently used connection */ - data->state.lastconnect = conn; - - infof(data, "Connection #%ld to host %s left intact\n", - conn->connection_id, - conn->bits.socksproxy ? conn->socks_proxy.host.dispname : - conn->bits.httpproxy ? conn->http_proxy.host.dispname : - conn->bits.conn_to_host ? conn->conn_to_host.dispname : - conn->host.dispname); - } - else - data->state.lastconnect = NULL; - } - - *connp = NULL; /* to make the caller of this function better detect that - this was either closed or handed over to the connection - cache here, and therefore cannot be used from this point on - */ - Curl_free_request_state(data); - - return result; -} - -CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, - struct Curl_easy *data) -{ - struct Curl_easy *easy = data; - bool premature; - bool easy_owns_conn; - struct curl_llist_element *e; - - /* First, make some basic checks that the CURLM handle is a good handle */ - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - /* Verify that we got a somewhat good easy handle too */ - if(!GOOD_EASY_HANDLE(data)) - return CURLM_BAD_EASY_HANDLE; - - /* Prevent users from trying to remove same easy handle more than once */ - if(!data->multi) - return CURLM_OK; /* it is already removed so let's say it is fine! */ - - premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE; - easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ? - TRUE : FALSE; - - /* If the 'state' is not INIT or COMPLETED, we might need to do something - nice to put the easy_handle in a good known state when this returns. */ - if(premature) { - /* this handle is "alive" so we need to count down the total number of - alive connections when this is removed */ - multi->num_alive--; - - /* When this handle gets removed, other handles may be able to get the - connection */ - Curl_multi_process_pending_handles(multi); - } - - if(data->easy_conn && - data->mstate > CURLM_STATE_DO && - data->mstate < CURLM_STATE_COMPLETED) { - /* Set connection owner so that the DONE function closes it. We can - safely do this here since connection is killed. */ - data->easy_conn->data = easy; - /* If the handle is in a pipeline and has started sending off its - request but not received its response yet, we need to close - connection. */ - streamclose(data->easy_conn, "Removed with partial response"); - easy_owns_conn = TRUE; - } - - /* The timer must be shut down before data->multi is set to NULL, - else the timenode will remain in the splay tree after - curl_easy_cleanup is called. */ - Curl_expire_clear(data); - - if(data->dns.hostcachetype == HCACHE_MULTI) { - /* stop using the multi handle's DNS cache */ - data->dns.hostcache = NULL; - data->dns.hostcachetype = HCACHE_NONE; - } - - if(data->easy_conn) { - - /* we must call multi_done() here (if we still own the connection) so that - we don't leave a half-baked one around */ - if(easy_owns_conn) { - - /* multi_done() clears the conn->data field to lose the association - between the easy handle and the connection - - Note that this ignores the return code simply because there's - nothing really useful to do with it anyway! */ - (void)multi_done(&data->easy_conn, data->result, premature); - } - else - /* Clear connection pipelines, if multi_done above was not called */ - Curl_getoff_all_pipelines(data, data->easy_conn); - } - - Curl_wildcard_dtor(&data->wildcard); - - /* destroy the timeout list that is held in the easy handle, do this *after* - multi_done() as that may actually call Curl_expire that uses this */ - Curl_llist_destroy(&data->state.timeoutlist, NULL); - - /* as this was using a shared connection cache we clear the pointer to that - since we're not part of that multi handle anymore */ - data->state.conn_cache = NULL; - - /* change state without using multistate(), only to make singlesocket() do - what we want */ - data->mstate = CURLM_STATE_COMPLETED; - singlesocket(multi, easy); /* to let the application know what sockets that - vanish with this handle */ - - /* Remove the association between the connection and the handle */ - if(data->easy_conn) { - data->easy_conn->data = NULL; - data->easy_conn = NULL; - } - - data->multi = NULL; /* clear the association to this multi handle */ - - /* make sure there's no pending message in the queue sent from this easy - handle */ - - for(e = multi->msglist.head; e; e = e->next) { - struct Curl_message *msg = e->ptr; - - if(msg->extmsg.easy_handle == easy) { - Curl_llist_remove(&multi->msglist, e, NULL); - /* there can only be one from this specific handle */ - break; - } - } - - /* make the previous node point to our next */ - if(data->prev) - data->prev->next = data->next; - else - multi->easyp = data->next; /* point to first node */ - - /* make our next point to our previous node */ - if(data->next) - data->next->prev = data->prev; - else - multi->easylp = data->prev; /* point to last node */ - - /* NOTE NOTE NOTE - We do not touch the easy handle here! */ - multi->num_easy--; /* one less to care about now */ - - update_timer(multi); - return CURLM_OK; -} - -/* Return TRUE if the application asked for a certain set of pipelining */ -bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits) -{ - return (multi && (multi->pipelining & bits)) ? TRUE : FALSE; -} - -void Curl_multi_handlePipeBreak(struct Curl_easy *data) -{ - data->easy_conn = NULL; -} - -static int waitconnect_getsock(struct connectdata *conn, - curl_socket_t *sock, - int numsocks) -{ - int i; - int s = 0; - int rc = 0; - - if(!numsocks) - return GETSOCK_BLANK; - -#ifdef USE_SSL - if(CONNECT_FIRSTSOCKET_PROXY_SSL()) - return Curl_ssl_getsock(conn, sock, numsocks); -#endif - - for(i = 0; i<2; i++) { - if(conn->tempsock[i] != CURL_SOCKET_BAD) { - sock[s] = conn->tempsock[i]; - rc |= GETSOCK_WRITESOCK(s++); - } - } - - return rc; -} - -static int waitproxyconnect_getsock(struct connectdata *conn, - curl_socket_t *sock, - int numsocks) -{ - if(!numsocks) - return GETSOCK_BLANK; - - sock[0] = conn->sock[FIRSTSOCKET]; - - /* when we've sent a CONNECT to a proxy, we should rather wait for the - socket to become readable to be able to get the response headers */ - if(conn->connect_state) - return GETSOCK_READSOCK(0); - - return GETSOCK_WRITESOCK(0); -} - -static int domore_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - if(conn && conn->handler->domore_getsock) - return conn->handler->domore_getsock(conn, socks, numsocks); - return GETSOCK_BLANK; -} - -/* returns bitmapped flags for this handle and its sockets */ -static int multi_getsock(struct Curl_easy *data, - curl_socket_t *socks, /* points to numsocks number - of sockets */ - int numsocks) -{ - /* If the pipe broke, or if there's no connection left for this easy handle, - then we MUST bail out now with no bitmask set. The no connection case can - happen when this is called from curl_multi_remove_handle() => - singlesocket() => multi_getsock(). - */ - if(data->state.pipe_broke || !data->easy_conn) - return 0; - - if(data->mstate > CURLM_STATE_CONNECT && - data->mstate < CURLM_STATE_COMPLETED) { - /* Set up ownership correctly */ - data->easy_conn->data = data; - } - - switch(data->mstate) { - default: -#if 0 /* switch back on these cases to get the compiler to check for all enums - to be present */ - case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */ - case CURLM_STATE_COMPLETED: - case CURLM_STATE_MSGSENT: - case CURLM_STATE_INIT: - case CURLM_STATE_CONNECT: - case CURLM_STATE_WAITDO: - case CURLM_STATE_DONE: - case CURLM_STATE_LAST: - /* this will get called with CURLM_STATE_COMPLETED when a handle is - removed */ -#endif - return 0; - - case CURLM_STATE_WAITRESOLVE: - return Curl_resolver_getsock(data->easy_conn, socks, numsocks); - - case CURLM_STATE_PROTOCONNECT: - case CURLM_STATE_SENDPROTOCONNECT: - return Curl_protocol_getsock(data->easy_conn, socks, numsocks); - - case CURLM_STATE_DO: - case CURLM_STATE_DOING: - return Curl_doing_getsock(data->easy_conn, socks, numsocks); - - case CURLM_STATE_WAITPROXYCONNECT: - return waitproxyconnect_getsock(data->easy_conn, socks, numsocks); - - case CURLM_STATE_WAITCONNECT: - return waitconnect_getsock(data->easy_conn, socks, numsocks); - - case CURLM_STATE_DO_MORE: - return domore_getsock(data->easy_conn, socks, numsocks); - - case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch - to waiting for the same as the *PERFORM - states */ - case CURLM_STATE_PERFORM: - case CURLM_STATE_WAITPERFORM: - return Curl_single_getsock(data->easy_conn, socks, numsocks); - } - -} - -CURLMcode curl_multi_fdset(struct Curl_multi *multi, - fd_set *read_fd_set, fd_set *write_fd_set, - fd_set *exc_fd_set, int *max_fd) -{ - /* Scan through all the easy handles to get the file descriptors set. - Some easy handles may not have connected to the remote host yet, - and then we must make sure that is done. */ - struct Curl_easy *data; - int this_max_fd = -1; - curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; - int bitmap; - int i; - (void)exc_fd_set; /* not used */ - - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - data = multi->easyp; - while(data) { - bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); - - for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { - curl_socket_t s = CURL_SOCKET_BAD; - - if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) { - FD_SET(sockbunch[i], read_fd_set); - s = sockbunch[i]; - } - if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) { - FD_SET(sockbunch[i], write_fd_set); - s = sockbunch[i]; - } - if(s == CURL_SOCKET_BAD) - /* this socket is unused, break out of loop */ - break; - if((int)s > this_max_fd) - this_max_fd = (int)s; - } - - data = data->next; /* check next handle */ - } - - *max_fd = this_max_fd; - - return CURLM_OK; -} - -#define NUM_POLLS_ON_STACK 10 - -CURLMcode curl_multi_wait(struct Curl_multi *multi, - struct curl_waitfd extra_fds[], - unsigned int extra_nfds, - int timeout_ms, - int *ret) -{ - struct Curl_easy *data; - curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; - int bitmap; - unsigned int i; - unsigned int nfds = 0; - unsigned int curlfds; - struct pollfd *ufds = NULL; - bool ufds_malloc = FALSE; - long timeout_internal; - int retcode = 0; - struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; - - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - /* If the internally desired timeout is actually shorter than requested from - the outside, then use the shorter time! But only if the internal timer - is actually larger than -1! */ - (void)multi_timeout(multi, &timeout_internal); - if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms)) - timeout_ms = (int)timeout_internal; - - /* Count up how many fds we have from the multi handle */ - data = multi->easyp; - while(data) { - bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); - - for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { - curl_socket_t s = CURL_SOCKET_BAD; - - if(bitmap & GETSOCK_READSOCK(i)) { - ++nfds; - s = sockbunch[i]; - } - if(bitmap & GETSOCK_WRITESOCK(i)) { - ++nfds; - s = sockbunch[i]; - } - if(s == CURL_SOCKET_BAD) { - break; - } - } - - data = data->next; /* check next handle */ - } - - curlfds = nfds; /* number of internal file descriptors */ - nfds += extra_nfds; /* add the externally provided ones */ - - if(nfds) { - if(nfds > NUM_POLLS_ON_STACK) { - /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes - big, so at 2^29 sockets this value might wrap. When a process gets - the capability to actually handle over 500 million sockets this - calculation needs a integer overflow check. */ - ufds = malloc(nfds * sizeof(struct pollfd)); - if(!ufds) - return CURLM_OUT_OF_MEMORY; - ufds_malloc = TRUE; - } - else - ufds = &a_few_on_stack[0]; - } - nfds = 0; - - /* only do the second loop if we found descriptors in the first stage run - above */ - - if(curlfds) { - /* Add the curl handles to our pollfds first */ - data = multi->easyp; - while(data) { - bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); - - for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { - curl_socket_t s = CURL_SOCKET_BAD; - - if(bitmap & GETSOCK_READSOCK(i)) { - ufds[nfds].fd = sockbunch[i]; - ufds[nfds].events = POLLIN; - ++nfds; - s = sockbunch[i]; - } - if(bitmap & GETSOCK_WRITESOCK(i)) { - ufds[nfds].fd = sockbunch[i]; - ufds[nfds].events = POLLOUT; - ++nfds; - s = sockbunch[i]; - } - if(s == CURL_SOCKET_BAD) { - break; - } - } - - data = data->next; /* check next handle */ - } - } - - /* Add external file descriptions from poll-like struct curl_waitfd */ - for(i = 0; i < extra_nfds; i++) { - ufds[nfds].fd = extra_fds[i].fd; - ufds[nfds].events = 0; - if(extra_fds[i].events & CURL_WAIT_POLLIN) - ufds[nfds].events |= POLLIN; - if(extra_fds[i].events & CURL_WAIT_POLLPRI) - ufds[nfds].events |= POLLPRI; - if(extra_fds[i].events & CURL_WAIT_POLLOUT) - ufds[nfds].events |= POLLOUT; - ++nfds; - } - - if(nfds) { - int pollrc; - /* wait... */ - pollrc = Curl_poll(ufds, nfds, timeout_ms); - DEBUGF(infof(data, "Curl_poll(%d ds, %d ms) == %d\n", - nfds, timeout_ms, pollrc)); - - if(pollrc > 0) { - retcode = pollrc; - /* copy revents results from the poll to the curl_multi_wait poll - struct, the bit values of the actual underlying poll() implementation - may not be the same as the ones in the public libcurl API! */ - for(i = 0; i < extra_nfds; i++) { - unsigned short mask = 0; - unsigned r = ufds[curlfds + i].revents; - - if(r & POLLIN) - mask |= CURL_WAIT_POLLIN; - if(r & POLLOUT) - mask |= CURL_WAIT_POLLOUT; - if(r & POLLPRI) - mask |= CURL_WAIT_POLLPRI; - - extra_fds[i].revents = mask; - } - } - } - - if(ufds_malloc) - free(ufds); - if(ret) - *ret = retcode; - return CURLM_OK; -} - -/* - * Curl_multi_connchanged() is called to tell that there is a connection in - * this multi handle that has changed state (pipelining become possible, the - * number of allowed streams changed or similar), and a subsequent use of this - * multi handle should move CONNECT_PEND handles back to CONNECT to have them - * retry. - */ -void Curl_multi_connchanged(struct Curl_multi *multi) -{ - multi->recheckstate = TRUE; -} - -/* - * multi_ischanged() is called - * - * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND - * => CONNECT action. - * - * Set 'clear' to TRUE to have it also clear the state variable. - */ -static bool multi_ischanged(struct Curl_multi *multi, bool clear) -{ - bool retval = multi->recheckstate; - if(clear) - multi->recheckstate = FALSE; - return retval; -} - -CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, - struct Curl_easy *data, - struct connectdata *conn) -{ - CURLMcode rc; - - rc = curl_multi_add_handle(multi, data); - if(!rc) { - struct SingleRequest *k = &data->req; - - /* pass in NULL for 'conn' here since we don't want to init the - connection, only this transfer */ - Curl_init_do(data, NULL); - - /* take this handle to the perform state right away */ - multistate(data, CURLM_STATE_PERFORM); - data->easy_conn = conn; - k->keepon |= KEEP_RECV; /* setup to receive! */ - } - return rc; -} - -static CURLcode multi_reconnect_request(struct connectdata **connp) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = *connp; - struct Curl_easy *data = conn->data; - - /* This was a re-use of a connection and we got a write error in the - * DO-phase. Then we DISCONNECT this connection and have another attempt to - * CONNECT and then DO again! The retry cannot possibly find another - * connection to re-use, since we only keep one possible connection for - * each. */ - - infof(data, "Re-used connection seems dead, get a new one\n"); - - connclose(conn, "Reconnect dead connection"); /* enforce close */ - result = multi_done(&conn, result, FALSE); /* we are so done with this */ - - /* conn may no longer be a good pointer, clear it to avoid mistakes by - parent functions */ - *connp = NULL; - - /* - * We need to check for CURLE_SEND_ERROR here as well. This could happen - * when the request failed on a FTP connection and thus multi_done() itself - * tried to use the connection (again). - */ - if(!result || (CURLE_SEND_ERROR == result)) { - bool async; - bool protocol_done = TRUE; - - /* Now, redo the connect and get a new connection */ - result = Curl_connect(data, connp, &async, &protocol_done); - if(!result) { - /* We have connected or sent away a name resolve query fine */ - - conn = *connp; /* setup conn to again point to something nice */ - if(async) { - /* Now, if async is TRUE here, we need to wait for the name - to resolve */ - result = Curl_resolver_wait_resolv(conn, NULL); - if(result) - return result; - - /* Resolved, continue with the connection */ - result = Curl_async_resolved(conn, &protocol_done); - if(result) - return result; - } - } - } - - return result; -} - -/* - * do_complete is called when the DO actions are complete. - * - * We init chunking and trailer bits to their default values here immediately - * before receiving any header data for the current request in the pipeline. - */ -static void do_complete(struct connectdata *conn) -{ - conn->data->req.chunk = FALSE; - conn->data->req.maxfd = (conn->sockfd>conn->writesockfd? - conn->sockfd:conn->writesockfd) + 1; - Curl_pgrsTime(conn->data, TIMER_PRETRANSFER); -} - -static CURLcode multi_do(struct connectdata **connp, bool *done) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = *connp; - struct Curl_easy *data = conn->data; - - if(conn->handler->do_it) { - /* generic protocol-specific function pointer set in curl_connect() */ - result = conn->handler->do_it(conn, done); - - /* This was formerly done in transfer.c, but we better do it here */ - if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { - /* - * If the connection is using an easy handle, call reconnect - * to re-establish the connection. Otherwise, let the multi logic - * figure out how to re-establish the connection. - */ - if(!data->multi) { - result = multi_reconnect_request(connp); - - if(!result) { - /* ... finally back to actually retry the DO phase */ - conn = *connp; /* re-assign conn since multi_reconnect_request - creates a new connection */ - result = conn->handler->do_it(conn, done); - } - } - else - return result; - } - - if(!result && *done) - /* do_complete must be called after the protocol-specific DO function */ - do_complete(conn); - } - return result; -} - -/* - * multi_do_more() is called during the DO_MORE multi state. It is basically a - * second stage DO state which (wrongly) was introduced to support FTP's - * second connection. - * - * TODO: A future libcurl should be able to work away this state. - * - * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to - * DOING state there's more work to do! - */ - -static CURLcode multi_do_more(struct connectdata *conn, int *complete) -{ - CURLcode result = CURLE_OK; - - *complete = 0; - - if(conn->handler->do_more) - result = conn->handler->do_more(conn, complete); - - if(!result && (*complete == 1)) - /* do_complete must be called after the protocol-specific DO function */ - do_complete(conn); - - return result; -} - -static CURLMcode multi_runsingle(struct Curl_multi *multi, - struct curltime now, - struct Curl_easy *data) -{ - struct Curl_message *msg = NULL; - bool connected; - bool async; - bool protocol_connect = FALSE; - bool dophase_done = FALSE; - bool done = FALSE; - CURLMcode rc; - CURLcode result = CURLE_OK; - struct SingleRequest *k; - time_t timeout_ms; - time_t recv_timeout_ms; - time_t send_timeout_ms; - int control; - - if(!GOOD_EASY_HANDLE(data)) - return CURLM_BAD_EASY_HANDLE; - - do { - /* A "stream" here is a logical stream if the protocol can handle that - (HTTP/2), or the full connection for older protocols */ - bool stream_error = FALSE; - rc = CURLM_OK; - - /* Handle the case when the pipe breaks, i.e., the connection - we're using gets cleaned up and we're left with nothing. */ - if(data->state.pipe_broke) { - infof(data, "Pipe broke: handle %p, url = %s\n", - (void *)data, data->state.path); - - if(data->mstate < CURLM_STATE_COMPLETED) { - /* Head back to the CONNECT state */ - multistate(data, CURLM_STATE_CONNECT); - rc = CURLM_CALL_MULTI_PERFORM; - result = CURLE_OK; - } - - data->state.pipe_broke = FALSE; - data->easy_conn = NULL; - continue; - } - - if(!data->easy_conn && - data->mstate > CURLM_STATE_CONNECT && - data->mstate < CURLM_STATE_DONE) { - /* In all these states, the code will blindly access 'data->easy_conn' - so this is precaution that it isn't NULL. And it silences static - analyzers. */ - failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate); - return CURLM_INTERNAL_ERROR; - } - - if(multi_ischanged(multi, TRUE)) { - DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n")); - Curl_multi_process_pending_handles(multi); - } - - if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT && - data->mstate < CURLM_STATE_COMPLETED) - /* Make sure we set the connection's current owner */ - data->easy_conn->data = data; - - if(data->easy_conn && - (data->mstate >= CURLM_STATE_CONNECT) && - (data->mstate < CURLM_STATE_COMPLETED)) { - /* we need to wait for the connect state as only then is the start time - stored, but we must not check already completed handles */ - - timeout_ms = Curl_timeleft(data, &now, - (data->mstate <= CURLM_STATE_WAITDO)? - TRUE:FALSE); - - if(timeout_ms < 0) { - /* Handle timed out */ - if(data->mstate == CURLM_STATE_WAITRESOLVE) - failf(data, "Resolving timed out after %ld milliseconds", - Curl_tvdiff(now, data->progress.t_startsingle)); - else if(data->mstate == CURLM_STATE_WAITCONNECT) - failf(data, "Connection timed out after %ld milliseconds", - Curl_tvdiff(now, data->progress.t_startsingle)); - else { - k = &data->req; - if(k->size != -1) { - failf(data, "Operation timed out after %ld milliseconds with %" - CURL_FORMAT_CURL_OFF_T " out of %" - CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(now, data->progress.t_startsingle), - k->bytecount, k->size); - } - else { - failf(data, "Operation timed out after %ld milliseconds with %" - CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(now, data->progress.t_startsingle), - k->bytecount); - } - } - - /* Force connection closed if the connection has indeed been used */ - if(data->mstate > CURLM_STATE_DO) { - streamclose(data->easy_conn, "Disconnected with pending data"); - stream_error = TRUE; - } - result = CURLE_OPERATION_TIMEDOUT; - (void)multi_done(&data->easy_conn, result, TRUE); - /* Skip the statemachine and go directly to error handling section. */ - goto statemachine_end; - } - } - - switch(data->mstate) { - case CURLM_STATE_INIT: - /* init this transfer. */ - result = Curl_pretransfer(data); - - if(!result) { - /* after init, go CONNECT */ - multistate(data, CURLM_STATE_CONNECT); - Curl_pgrsTime(data, TIMER_STARTOP); - rc = CURLM_CALL_MULTI_PERFORM; - } - break; - - case CURLM_STATE_CONNECT_PEND: - /* We will stay here until there is a connection available. Then - we try again in the CURLM_STATE_CONNECT state. */ - break; - - case CURLM_STATE_CONNECT: - /* Connect. We want to get a connection identifier filled in. */ - Curl_pgrsTime(data, TIMER_STARTSINGLE); - result = Curl_connect(data, &data->easy_conn, - &async, &protocol_connect); - if(CURLE_NO_CONNECTION_AVAILABLE == result) { - /* There was no connection available. We will go to the pending - state and wait for an available connection. */ - multistate(data, CURLM_STATE_CONNECT_PEND); - - /* add this handle to the list of connect-pending handles */ - Curl_llist_insert_next(&multi->pending, multi->pending.tail, data, - &data->connect_queue); - result = CURLE_OK; - break; - } - - if(!result) { - /* Add this handle to the send or pend pipeline */ - result = Curl_add_handle_to_pipeline(data, data->easy_conn); - if(result) - stream_error = TRUE; - else { - if(async) - /* We're now waiting for an asynchronous name lookup */ - multistate(data, CURLM_STATE_WAITRESOLVE); - else { - /* after the connect has been sent off, go WAITCONNECT unless the - protocol connect is already done and we can go directly to - WAITDO or DO! */ - rc = CURLM_CALL_MULTI_PERFORM; - - if(protocol_connect) - multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? - CURLM_STATE_WAITDO:CURLM_STATE_DO); - else { -#ifndef CURL_DISABLE_HTTP - if(Curl_connect_ongoing(data->easy_conn)) - multistate(data, CURLM_STATE_WAITPROXYCONNECT); - else -#endif - multistate(data, CURLM_STATE_WAITCONNECT); - } - } - } - } - break; - - case CURLM_STATE_WAITRESOLVE: - /* awaiting an asynch name resolve to complete */ - { - struct Curl_dns_entry *dns = NULL; - struct connectdata *conn = data->easy_conn; - const char *hostname; - - if(conn->bits.httpproxy) - hostname = conn->http_proxy.host.name; - else if(conn->bits.conn_to_host) - hostname = conn->conn_to_host.name; - else - hostname = conn->host.name; - - /* check if we have the name resolved by now */ - dns = Curl_fetch_addr(conn, hostname, (int)conn->port); - - if(dns) { -#ifdef CURLRES_ASYNCH - conn->async.dns = dns; - conn->async.done = TRUE; -#endif - result = CURLE_OK; - infof(data, "Hostname '%s' was found in DNS cache\n", hostname); - } - - if(!dns) - result = Curl_resolver_is_resolved(data->easy_conn, &dns); - - /* Update sockets here, because the socket(s) may have been - closed and the application thus needs to be told, even if it - is likely that the same socket(s) will again be used further - down. If the name has not yet been resolved, it is likely - that new sockets have been opened in an attempt to contact - another resolver. */ - singlesocket(multi, data); - - if(dns) { - /* Perform the next step in the connection phase, and then move on - to the WAITCONNECT state */ - result = Curl_async_resolved(data->easy_conn, &protocol_connect); - - if(result) - /* if Curl_async_resolved() returns failure, the connection struct - is already freed and gone */ - data->easy_conn = NULL; /* no more connection */ - else { - /* call again please so that we get the next socket setup */ - rc = CURLM_CALL_MULTI_PERFORM; - if(protocol_connect) - multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? - CURLM_STATE_WAITDO:CURLM_STATE_DO); - else { -#ifndef CURL_DISABLE_HTTP - if(Curl_connect_ongoing(data->easy_conn)) - multistate(data, CURLM_STATE_WAITPROXYCONNECT); - else -#endif - multistate(data, CURLM_STATE_WAITCONNECT); - } - } - } - - if(result) { - /* failure detected */ - stream_error = TRUE; - break; - } - } - break; - -#ifndef CURL_DISABLE_HTTP - case CURLM_STATE_WAITPROXYCONNECT: - /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ - result = Curl_http_connect(data->easy_conn, &protocol_connect); - - if(data->easy_conn->bits.proxy_connect_closed) { - rc = CURLM_CALL_MULTI_PERFORM; - /* connect back to proxy again */ - result = CURLE_OK; - multi_done(&data->easy_conn, CURLE_OK, FALSE); - multistate(data, CURLM_STATE_CONNECT); - } - else if(!result) { - if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS || - data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) && - Curl_connect_complete(data->easy_conn)) { - rc = CURLM_CALL_MULTI_PERFORM; - /* initiate protocol connect phase */ - multistate(data, CURLM_STATE_SENDPROTOCONNECT); - } - } - break; -#endif - - case CURLM_STATE_WAITCONNECT: - /* awaiting a completion of an asynch TCP connect */ - result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected); - if(connected && !result) { -#ifndef CURL_DISABLE_HTTP - if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS && - !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) || - Curl_connect_ongoing(data->easy_conn)) { - multistate(data, CURLM_STATE_WAITPROXYCONNECT); - break; - } -#endif - rc = CURLM_CALL_MULTI_PERFORM; - multistate(data, data->easy_conn->bits.tunnel_proxy? - CURLM_STATE_WAITPROXYCONNECT: - CURLM_STATE_SENDPROTOCONNECT); - } - else if(result) { - /* failure detected */ - /* Just break, the cleaning up is handled all in one place */ - stream_error = TRUE; - break; - } - break; - - case CURLM_STATE_SENDPROTOCONNECT: - result = Curl_protocol_connect(data->easy_conn, &protocol_connect); - if(!protocol_connect) - /* switch to waiting state */ - multistate(data, CURLM_STATE_PROTOCONNECT); - else if(!result) { - /* protocol connect has completed, go WAITDO or DO */ - multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? - CURLM_STATE_WAITDO:CURLM_STATE_DO); - rc = CURLM_CALL_MULTI_PERFORM; - } - else if(result) { - /* failure detected */ - Curl_posttransfer(data); - multi_done(&data->easy_conn, result, TRUE); - stream_error = TRUE; - } - break; - - case CURLM_STATE_PROTOCONNECT: - /* protocol-specific connect phase */ - result = Curl_protocol_connecting(data->easy_conn, &protocol_connect); - if(!result && protocol_connect) { - /* after the connect has completed, go WAITDO or DO */ - multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? - CURLM_STATE_WAITDO:CURLM_STATE_DO); - rc = CURLM_CALL_MULTI_PERFORM; - } - else if(result) { - /* failure detected */ - Curl_posttransfer(data); - multi_done(&data->easy_conn, result, TRUE); - stream_error = TRUE; - } - break; - - case CURLM_STATE_WAITDO: - /* Wait for our turn to DO when we're pipelining requests */ - if(Curl_pipeline_checkget_write(data, data->easy_conn)) { - /* Grabbed the channel */ - multistate(data, CURLM_STATE_DO); - rc = CURLM_CALL_MULTI_PERFORM; - } - break; - - case CURLM_STATE_DO: - if(data->set.connect_only) { - /* keep connection open for application to use the socket */ - connkeep(data->easy_conn, "CONNECT_ONLY"); - multistate(data, CURLM_STATE_DONE); - result = CURLE_OK; - rc = CURLM_CALL_MULTI_PERFORM; - } - else { - /* Perform the protocol's DO action */ - result = multi_do(&data->easy_conn, &dophase_done); - - /* When multi_do() returns failure, data->easy_conn might be NULL! */ - - if(!result) { - if(!dophase_done) { - /* some steps needed for wildcard matching */ - if(data->set.wildcardmatch) { - struct WildcardData *wc = &data->wildcard; - if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) { - /* skip some states if it is important */ - multi_done(&data->easy_conn, CURLE_OK, FALSE); - multistate(data, CURLM_STATE_DONE); - rc = CURLM_CALL_MULTI_PERFORM; - break; - } - } - /* DO was not completed in one function call, we must continue - DOING... */ - multistate(data, CURLM_STATE_DOING); - rc = CURLM_OK; - } - - /* after DO, go DO_DONE... or DO_MORE */ - else if(data->easy_conn->bits.do_more) { - /* we're supposed to do more, but we need to sit down, relax - and wait a little while first */ - multistate(data, CURLM_STATE_DO_MORE); - rc = CURLM_OK; - } - else { - /* we're done with the DO, now DO_DONE */ - multistate(data, CURLM_STATE_DO_DONE); - rc = CURLM_CALL_MULTI_PERFORM; - } - } - else if((CURLE_SEND_ERROR == result) && - data->easy_conn->bits.reuse) { - /* - * In this situation, a connection that we were trying to use - * may have unexpectedly died. If possible, send the connection - * back to the CONNECT phase so we can try again. - */ - char *newurl = NULL; - followtype follow = FOLLOW_NONE; - CURLcode drc; - bool retry = FALSE; - - drc = Curl_retry_request(data->easy_conn, &newurl); - if(drc) { - /* a failure here pretty much implies an out of memory */ - result = drc; - stream_error = TRUE; - } - else - retry = (newurl)?TRUE:FALSE; - - Curl_posttransfer(data); - drc = multi_done(&data->easy_conn, result, FALSE); - - /* When set to retry the connection, we must to go back to - * the CONNECT state */ - if(retry) { - if(!drc || (drc == CURLE_SEND_ERROR)) { - follow = FOLLOW_RETRY; - drc = Curl_follow(data, newurl, follow); - if(!drc) { - multistate(data, CURLM_STATE_CONNECT); - rc = CURLM_CALL_MULTI_PERFORM; - result = CURLE_OK; - } - else { - /* Follow failed */ - result = drc; - } - } - else { - /* done didn't return OK or SEND_ERROR */ - result = drc; - } - } - else { - /* Have error handler disconnect conn if we can't retry */ - stream_error = TRUE; - } - free(newurl); - } - else { - /* failure detected */ - Curl_posttransfer(data); - if(data->easy_conn) - multi_done(&data->easy_conn, result, FALSE); - stream_error = TRUE; - } - } - break; - - case CURLM_STATE_DOING: - /* we continue DOING until the DO phase is complete */ - result = Curl_protocol_doing(data->easy_conn, - &dophase_done); - if(!result) { - if(dophase_done) { - /* after DO, go DO_DONE or DO_MORE */ - multistate(data, data->easy_conn->bits.do_more? - CURLM_STATE_DO_MORE: - CURLM_STATE_DO_DONE); - rc = CURLM_CALL_MULTI_PERFORM; - } /* dophase_done */ - } - else { - /* failure detected */ - Curl_posttransfer(data); - multi_done(&data->easy_conn, result, FALSE); - stream_error = TRUE; - } - break; - - case CURLM_STATE_DO_MORE: - /* - * When we are connected, DO MORE and then go DO_DONE - */ - result = multi_do_more(data->easy_conn, &control); - - /* No need to remove this handle from the send pipeline here since that - is done in multi_done() */ - if(!result) { - if(control) { - /* if positive, advance to DO_DONE - if negative, go back to DOING */ - multistate(data, control == 1? - CURLM_STATE_DO_DONE: - CURLM_STATE_DOING); - rc = CURLM_CALL_MULTI_PERFORM; - } - else - /* stay in DO_MORE */ - rc = CURLM_OK; - } - else { - /* failure detected */ - Curl_posttransfer(data); - multi_done(&data->easy_conn, result, FALSE); - stream_error = TRUE; - } - break; - - case CURLM_STATE_DO_DONE: - /* Move ourselves from the send to recv pipeline */ - Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn); - /* Check if we can move pending requests to send pipe */ - Curl_multi_process_pending_handles(multi); - - /* Only perform the transfer if there's a good socket to work with. - Having both BAD is a signal to skip immediately to DONE */ - if((data->easy_conn->sockfd != CURL_SOCKET_BAD) || - (data->easy_conn->writesockfd != CURL_SOCKET_BAD)) - multistate(data, CURLM_STATE_WAITPERFORM); - else - multistate(data, CURLM_STATE_DONE); - rc = CURLM_CALL_MULTI_PERFORM; - break; - - case CURLM_STATE_WAITPERFORM: - /* Wait for our turn to PERFORM */ - if(Curl_pipeline_checkget_read(data, data->easy_conn)) { - /* Grabbed the channel */ - multistate(data, CURLM_STATE_PERFORM); - rc = CURLM_CALL_MULTI_PERFORM; - } - break; - - case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */ - /* if both rates are within spec, resume transfer */ - if(Curl_pgrsUpdate(data->easy_conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else - result = Curl_speedcheck(data, now); - - if(!result) { - send_timeout_ms = 0; - if(data->set.max_send_speed > 0) - send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, - data->progress.ul_limit_size, - data->set.max_send_speed, - data->progress.ul_limit_start, - now); - - recv_timeout_ms = 0; - if(data->set.max_recv_speed > 0) - recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, - data->progress.dl_limit_size, - data->set.max_recv_speed, - data->progress.dl_limit_start, - now); - - if(send_timeout_ms <= 0 && recv_timeout_ms <= 0) - multistate(data, CURLM_STATE_PERFORM); - else if(send_timeout_ms >= recv_timeout_ms) - Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); - else - Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); - } - break; - - case CURLM_STATE_PERFORM: - { - char *newurl = NULL; - bool retry = FALSE; - bool comeback = FALSE; - - /* check if over send speed */ - send_timeout_ms = 0; - if(data->set.max_send_speed > 0) - send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, - data->progress.ul_limit_size, - data->set.max_send_speed, - data->progress.ul_limit_start, - now); - - /* check if over recv speed */ - recv_timeout_ms = 0; - if(data->set.max_recv_speed > 0) - recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, - data->progress.dl_limit_size, - data->set.max_recv_speed, - data->progress.dl_limit_start, - now); - - if(send_timeout_ms > 0 || recv_timeout_ms > 0) { - multistate(data, CURLM_STATE_TOOFAST); - if(send_timeout_ms >= recv_timeout_ms) - Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); - else - Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); - break; - } - - /* read/write data if it is ready to do so */ - result = Curl_readwrite(data->easy_conn, data, &done, &comeback); - - k = &data->req; - - if(!(k->keepon & KEEP_RECV)) - /* We're done receiving */ - Curl_pipeline_leave_read(data->easy_conn); - - if(!(k->keepon & KEEP_SEND)) - /* We're done sending */ - Curl_pipeline_leave_write(data->easy_conn); - - if(done || (result == CURLE_RECV_ERROR)) { - /* If CURLE_RECV_ERROR happens early enough, we assume it was a race - * condition and the server closed the re-used connection exactly when - * we wanted to use it, so figure out if that is indeed the case. - */ - CURLcode ret = Curl_retry_request(data->easy_conn, &newurl); - if(!ret) - retry = (newurl)?TRUE:FALSE; - - if(retry) { - /* if we are to retry, set the result to OK and consider the - request as done */ - result = CURLE_OK; - done = TRUE; - } - } - - if(result) { - /* - * The transfer phase returned error, we mark the connection to get - * closed to prevent being re-used. This is because we can't possibly - * know if the connection is in a good shape or not now. Unless it is - * a protocol which uses two "channels" like FTP, as then the error - * happened in the data connection. - */ - - if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) && - result != CURLE_HTTP2_STREAM) - streamclose(data->easy_conn, "Transfer returned error"); - - Curl_posttransfer(data); - multi_done(&data->easy_conn, result, TRUE); - } - else if(done) { - followtype follow = FOLLOW_NONE; - - /* call this even if the readwrite function returned error */ - Curl_posttransfer(data); - - /* we're no longer receiving */ - Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe); - - /* expire the new receiving pipeline head */ - if(data->easy_conn->recv_pipe.head) - Curl_expire(data->easy_conn->recv_pipe.head->ptr, 0, EXPIRE_RUN_NOW); - - /* Check if we can move pending requests to send pipe */ - Curl_multi_process_pending_handles(multi); - - /* When we follow redirects or is set to retry the connection, we must - to go back to the CONNECT state */ - if(data->req.newurl || retry) { - if(!retry) { - /* if the URL is a follow-location and not just a retried request - then figure out the URL here */ - free(newurl); - newurl = data->req.newurl; - data->req.newurl = NULL; - follow = FOLLOW_REDIR; - } - else - follow = FOLLOW_RETRY; - result = multi_done(&data->easy_conn, CURLE_OK, FALSE); - if(!result) { - result = Curl_follow(data, newurl, follow); - if(!result) { - multistate(data, CURLM_STATE_CONNECT); - rc = CURLM_CALL_MULTI_PERFORM; - } - } - } - else { - /* after the transfer is done, go DONE */ - - /* but first check to see if we got a location info even though we're - not following redirects */ - if(data->req.location) { - free(newurl); - newurl = data->req.location; - data->req.location = NULL; - result = Curl_follow(data, newurl, FOLLOW_FAKE); - if(result) - stream_error = TRUE; - } - - multistate(data, CURLM_STATE_DONE); - rc = CURLM_CALL_MULTI_PERFORM; - } - } - else if(comeback) - rc = CURLM_CALL_MULTI_PERFORM; - - free(newurl); - break; - } - - case CURLM_STATE_DONE: - /* this state is highly transient, so run another loop after this */ - rc = CURLM_CALL_MULTI_PERFORM; - - if(data->easy_conn) { - CURLcode res; - - /* Remove ourselves from the receive pipeline, if we are there. */ - Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe); - /* Check if we can move pending requests to send pipe */ - Curl_multi_process_pending_handles(multi); - - /* post-transfer command */ - res = multi_done(&data->easy_conn, result, FALSE); - - /* allow a previously set error code take precedence */ - if(!result) - result = res; - - /* - * If there are other handles on the pipeline, multi_done won't set - * easy_conn to NULL. In such a case, curl_multi_remove_handle() can - * access free'd data, if the connection is free'd and the handle - * removed before we perform the processing in CURLM_STATE_COMPLETED - */ - if(data->easy_conn) - data->easy_conn = NULL; - } - - if(data->set.wildcardmatch) { - if(data->wildcard.state != CURLWC_DONE) { - /* if a wildcard is set and we are not ending -> lets start again - with CURLM_STATE_INIT */ - multistate(data, CURLM_STATE_INIT); - break; - } - } - - /* after we have DONE what we're supposed to do, go COMPLETED, and - it doesn't matter what the multi_done() returned! */ - multistate(data, CURLM_STATE_COMPLETED); - break; - - case CURLM_STATE_COMPLETED: - /* this is a completed transfer, it is likely to still be connected */ - - /* This node should be delinked from the list now and we should post - an information message that we are complete. */ - - /* Important: reset the conn pointer so that we don't point to memory - that could be freed anytime */ - data->easy_conn = NULL; - - Curl_expire_clear(data); /* stop all timers */ - break; - - case CURLM_STATE_MSGSENT: - data->result = result; - return CURLM_OK; /* do nothing */ - - default: - return CURLM_INTERNAL_ERROR; - } - statemachine_end: - - if(data->mstate < CURLM_STATE_COMPLETED) { - if(result) { - /* - * If an error was returned, and we aren't in completed state now, - * then we go to completed and consider this transfer aborted. - */ - - /* NOTE: no attempt to disconnect connections must be made - in the case blocks above - cleanup happens only here */ - - data->state.pipe_broke = FALSE; - - /* Check if we can move pending requests to send pipe */ - Curl_multi_process_pending_handles(multi); - - if(data->easy_conn) { - /* if this has a connection, unsubscribe from the pipelines */ - Curl_pipeline_leave_write(data->easy_conn); - Curl_pipeline_leave_read(data->easy_conn); - Curl_removeHandleFromPipeline(data, &data->easy_conn->send_pipe); - Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe); - - if(stream_error) { - /* Don't attempt to send data over a connection that timed out */ - bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; - /* disconnect properly */ - Curl_disconnect(data->easy_conn, dead_connection); - - /* This is where we make sure that the easy_conn pointer is reset. - We don't have to do this in every case block above where a - failure is detected */ - data->easy_conn = NULL; - } - } - else if(data->mstate == CURLM_STATE_CONNECT) { - /* Curl_connect() failed */ - (void)Curl_posttransfer(data); - } - - multistate(data, CURLM_STATE_COMPLETED); - } - /* if there's still a connection to use, call the progress function */ - else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) { - /* aborted due to progress callback return code must close the - connection */ - result = CURLE_ABORTED_BY_CALLBACK; - streamclose(data->easy_conn, "Aborted by callback"); - - /* if not yet in DONE state, go there, otherwise COMPLETED */ - multistate(data, (data->mstate < CURLM_STATE_DONE)? - CURLM_STATE_DONE: CURLM_STATE_COMPLETED); - rc = CURLM_CALL_MULTI_PERFORM; - } - } - - if(CURLM_STATE_COMPLETED == data->mstate) { - /* now fill in the Curl_message with this info */ - msg = &data->msg; - - msg->extmsg.msg = CURLMSG_DONE; - msg->extmsg.easy_handle = data; - msg->extmsg.data.result = result; - - rc = multi_addmsg(multi, msg); - - multistate(data, CURLM_STATE_MSGSENT); - } - } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE)); - - data->result = result; - - - return rc; -} - - -CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) -{ - struct Curl_easy *data; - CURLMcode returncode = CURLM_OK; - struct Curl_tree *t; - struct curltime now = Curl_tvnow(); - - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - data = multi->easyp; - while(data) { - CURLMcode result; - SIGPIPE_VARIABLE(pipe_st); - - sigpipe_ignore(data, &pipe_st); - result = multi_runsingle(multi, now, data); - sigpipe_restore(&pipe_st); - - if(result) - returncode = result; - - data = data->next; /* operate on next handle */ - } - - /* - * Simply remove all expired timers from the splay since handles are dealt - * with unconditionally by this function and curl_multi_timeout() requires - * that already passed/handled expire times are removed from the splay. - * - * It is important that the 'now' value is set at the entry of this function - * and not for the current time as it may have ticked a little while since - * then and then we risk this loop to remove timers that actually have not - * been handled! - */ - do { - multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); - if(t) - /* the removed may have another timeout in queue */ - (void)add_next_timeout(now, multi, t->payload); - - } while(t); - - *running_handles = multi->num_alive; - - if(CURLM_OK >= returncode) - update_timer(multi); - - return returncode; -} - -static void close_all_connections(struct Curl_multi *multi) -{ - struct connectdata *conn; - - conn = Curl_conncache_find_first_connection(&multi->conn_cache); - while(conn) { - SIGPIPE_VARIABLE(pipe_st); - conn->data = multi->closure_handle; - - sigpipe_ignore(conn->data, &pipe_st); - conn->data->easy_conn = NULL; /* clear the easy handle's connection - pointer */ - /* This will remove the connection from the cache */ - connclose(conn, "kill all"); - (void)Curl_disconnect(conn, FALSE); - sigpipe_restore(&pipe_st); - - conn = Curl_conncache_find_first_connection(&multi->conn_cache); - } -} - -CURLMcode curl_multi_cleanup(struct Curl_multi *multi) -{ - struct Curl_easy *data; - struct Curl_easy *nextdata; - - if(GOOD_MULTI_HANDLE(multi)) { - bool restore_pipe = FALSE; - SIGPIPE_VARIABLE(pipe_st); - - multi->type = 0; /* not good anymore */ - - /* Close all the connections in the connection cache */ - close_all_connections(multi); - - if(multi->closure_handle) { - sigpipe_ignore(multi->closure_handle, &pipe_st); - restore_pipe = TRUE; - - multi->closure_handle->dns.hostcache = &multi->hostcache; - Curl_hostcache_clean(multi->closure_handle, - multi->closure_handle->dns.hostcache); - - Curl_close(multi->closure_handle); - } - - Curl_hash_destroy(&multi->sockhash); - Curl_conncache_destroy(&multi->conn_cache); - Curl_llist_destroy(&multi->msglist, NULL); - Curl_llist_destroy(&multi->pending, NULL); - - /* remove all easy handles */ - data = multi->easyp; - while(data) { - nextdata = data->next; - if(data->dns.hostcachetype == HCACHE_MULTI) { - /* clear out the usage of the shared DNS cache */ - Curl_hostcache_clean(data, data->dns.hostcache); - data->dns.hostcache = NULL; - data->dns.hostcachetype = HCACHE_NONE; - } - - /* Clear the pointer to the connection cache */ - data->state.conn_cache = NULL; - data->multi = NULL; /* clear the association */ - - data = nextdata; - } - - Curl_hash_destroy(&multi->hostcache); - - /* Free the blacklists by setting them to NULL */ - Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl); - Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl); - - free(multi); - if(restore_pipe) - sigpipe_restore(&pipe_st); - - return CURLM_OK; - } - return CURLM_BAD_HANDLE; -} - -/* - * curl_multi_info_read() - * - * This function is the primary way for a multi/multi_socket application to - * figure out if a transfer has ended. We MUST make this function as fast as - * possible as it will be polled frequently and we MUST NOT scan any lists in - * here to figure out things. We must scale fine to thousands of handles and - * beyond. The current design is fully O(1). - */ - -CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue) -{ - struct Curl_message *msg; - - *msgs_in_queue = 0; /* default to none */ - - if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(&multi->msglist)) { - /* there is one or more messages in the list */ - struct curl_llist_element *e; - - /* extract the head of the list to return */ - e = multi->msglist.head; - - msg = e->ptr; - - /* remove the extracted entry */ - Curl_llist_remove(&multi->msglist, e, NULL); - - *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist)); - - return &msg->extmsg; - } - return NULL; -} - -/* - * singlesocket() checks what sockets we deal with and their "action state" - * and if we have a different state in any of those sockets from last time we - * call the callback accordingly. - */ -static void singlesocket(struct Curl_multi *multi, - struct Curl_easy *data) -{ - curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; - int i; - struct Curl_sh_entry *entry; - curl_socket_t s; - int num; - unsigned int curraction; - - for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) - socks[i] = CURL_SOCKET_BAD; - - /* Fill in the 'current' struct with the state as it is now: what sockets to - supervise and for what actions */ - curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE); - - /* We have 0 .. N sockets already and we get to know about the 0 .. M - sockets we should have from now on. Detect the differences, remove no - longer supervised ones and add new ones */ - - /* walk over the sockets we got right now */ - for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) && - (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))); - i++) { - int action = CURL_POLL_NONE; - - s = socks[i]; - - /* get it from the hash */ - entry = sh_getentry(&multi->sockhash, s); - - if(curraction & GETSOCK_READSOCK(i)) - action |= CURL_POLL_IN; - if(curraction & GETSOCK_WRITESOCK(i)) - action |= CURL_POLL_OUT; - - if(entry) { - /* yeps, already present so check if it has the same action set */ - if(entry->action == action) - /* same, continue */ - continue; - } - else { - /* this is a socket we didn't have before, add it! */ - entry = sh_addentry(&multi->sockhash, s, data); - if(!entry) - /* fatal */ - return; - } - - /* we know (entry != NULL) at this point, see the logic above */ - if(multi->socket_cb) - multi->socket_cb(data, - s, - action, - multi->socket_userp, - entry->socketp); - - entry->action = action; /* store the current action state */ - } - - num = i; /* number of sockets */ - - /* when we've walked over all the sockets we should have right now, we must - make sure to detect sockets that are removed */ - for(i = 0; i< data->numsocks; i++) { - int j; - s = data->sockets[i]; - for(j = 0; jsockhash, s); - if(entry) { - /* this socket has been removed. Tell the app to remove it */ - bool remove_sock_from_hash = TRUE; - - /* check if the socket to be removed serves a connection which has - other easy-s in a pipeline. In this case the socket should not be - removed. */ - struct connectdata *easy_conn = data->easy_conn; - if(easy_conn) { - if(easy_conn->recv_pipe.size > 1) { - /* the handle should not be removed from the pipe yet */ - remove_sock_from_hash = FALSE; - - /* Update the sockhash entry to instead point to the next in line - for the recv_pipe, or the first (in case this particular easy - isn't already) */ - if(entry->easy == data) { - if(Curl_recvpipe_head(data, easy_conn)) - entry->easy = easy_conn->recv_pipe.head->next->ptr; - else - entry->easy = easy_conn->recv_pipe.head->ptr; - } - } - if(easy_conn->send_pipe.size > 1) { - /* the handle should not be removed from the pipe yet */ - remove_sock_from_hash = FALSE; - - /* Update the sockhash entry to instead point to the next in line - for the send_pipe, or the first (in case this particular easy - isn't already) */ - if(entry->easy == data) { - if(Curl_sendpipe_head(data, easy_conn)) - entry->easy = easy_conn->send_pipe.head->next->ptr; - else - entry->easy = easy_conn->send_pipe.head->ptr; - } - } - /* Don't worry about overwriting recv_pipe head with send_pipe_head, - when action will be asked on the socket (see multi_socket()), the - head of the correct pipe will be taken according to the - action. */ - } - - if(remove_sock_from_hash) { - /* in this case 'entry' is always non-NULL */ - if(multi->socket_cb) - multi->socket_cb(data, - s, - CURL_POLL_REMOVE, - multi->socket_userp, - entry->socketp); - sh_delentry(&multi->sockhash, s); - } - } /* if sockhash entry existed */ - } /* for loop over numsocks */ - - memcpy(data->sockets, socks, num*sizeof(curl_socket_t)); - data->numsocks = num; -} - -/* - * Curl_multi_closed() - * - * Used by the connect code to tell the multi_socket code that one of the - * sockets we were using is about to be closed. This function will then - * remove it from the sockethash for this handle to make the multi_socket API - * behave properly, especially for the case when libcurl will create another - * socket again and it gets the same file descriptor number. - */ - -void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) -{ - struct Curl_multi *multi = conn->data->multi; - if(multi) { - /* this is set if this connection is part of a handle that is added to - a multi handle, and only then this is necessary */ - struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); - - if(entry) { - if(multi->socket_cb) - multi->socket_cb(conn->data, s, CURL_POLL_REMOVE, - multi->socket_userp, - entry->socketp); - - /* now remove it from the socket hash */ - sh_delentry(&multi->sockhash, s); - } - } -} - -/* - * add_next_timeout() - * - * Each Curl_easy has a list of timeouts. The add_next_timeout() is called - * when it has just been removed from the splay tree because the timeout has - * expired. This function is then to advance in the list to pick the next - * timeout to use (skip the already expired ones) and add this node back to - * the splay tree again. - * - * The splay tree only has each sessionhandle as a single node and the nearest - * timeout is used to sort it on. - */ -static CURLMcode add_next_timeout(struct curltime now, - struct Curl_multi *multi, - struct Curl_easy *d) -{ - struct curltime *tv = &d->state.expiretime; - struct curl_llist *list = &d->state.timeoutlist; - struct curl_llist_element *e; - struct time_node *node = NULL; - - /* move over the timeout list for this specific handle and remove all - timeouts that are now passed tense and store the next pending - timeout in *tv */ - for(e = list->head; e;) { - struct curl_llist_element *n = e->next; - time_t diff; - node = (struct time_node *)e->ptr; - diff = curlx_tvdiff(node->time, now); - if(diff <= 0) - /* remove outdated entry */ - Curl_llist_remove(list, e, NULL); - else - /* the list is sorted so get out on the first mismatch */ - break; - e = n; - } - e = list->head; - if(!e) { - /* clear the expire times within the handles that we remove from the - splay tree */ - tv->tv_sec = 0; - tv->tv_usec = 0; - } - else { - /* copy the first entry to 'tv' */ - memcpy(tv, &node->time, sizeof(*tv)); - - /* Insert this node again into the splay. Keep the timer in the list in - case we need to recompute future timers. */ - multi->timetree = Curl_splayinsert(*tv, multi->timetree, - &d->state.timenode); - } - return CURLM_OK; -} - -static CURLMcode multi_socket(struct Curl_multi *multi, - bool checkall, - curl_socket_t s, - int ev_bitmask, - int *running_handles) -{ - CURLMcode result = CURLM_OK; - struct Curl_easy *data = NULL; - struct Curl_tree *t; - struct curltime now = Curl_tvnow(); - - if(checkall) { - /* *perform() deals with running_handles on its own */ - result = curl_multi_perform(multi, running_handles); - - /* walk through each easy handle and do the socket state change magic - and callbacks */ - if(result != CURLM_BAD_HANDLE) { - data = multi->easyp; - while(data) { - singlesocket(multi, data); - data = data->next; - } - } - - /* or should we fall-through and do the timer-based stuff? */ - return result; - } - if(s != CURL_SOCKET_TIMEOUT) { - - struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); - - if(!entry) - /* Unmatched socket, we can't act on it but we ignore this fact. In - real-world tests it has been proved that libevent can in fact give - the application actions even though the socket was just previously - asked to get removed, so thus we better survive stray socket actions - and just move on. */ - ; - else { - SIGPIPE_VARIABLE(pipe_st); - - data = entry->easy; - - if(data->magic != CURLEASY_MAGIC_NUMBER) - /* bad bad bad bad bad bad bad */ - return CURLM_INTERNAL_ERROR; - - /* If the pipeline is enabled, take the handle which is in the head of - the pipeline. If we should write into the socket, take the send_pipe - head. If we should read from the socket, take the recv_pipe head. */ - if(data->easy_conn) { - if((ev_bitmask & CURL_POLL_OUT) && - data->easy_conn->send_pipe.head) - data = data->easy_conn->send_pipe.head->ptr; - else if((ev_bitmask & CURL_POLL_IN) && - data->easy_conn->recv_pipe.head) - data = data->easy_conn->recv_pipe.head->ptr; - } - - if(data->easy_conn && - !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK)) - /* set socket event bitmask if they're not locked */ - data->easy_conn->cselect_bits = ev_bitmask; - - sigpipe_ignore(data, &pipe_st); - result = multi_runsingle(multi, now, data); - sigpipe_restore(&pipe_st); - - if(data->easy_conn && - !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK)) - /* clear the bitmask only if not locked */ - data->easy_conn->cselect_bits = 0; - - if(CURLM_OK >= result) - /* get the socket(s) and check if the state has been changed since - last */ - singlesocket(multi, data); - - /* Now we fall-through and do the timer-based stuff, since we don't want - to force the user to have to deal with timeouts as long as at least - one connection in fact has traffic. */ - - data = NULL; /* set data to NULL again to avoid calling - multi_runsingle() in case there's no need to */ - now = Curl_tvnow(); /* get a newer time since the multi_runsingle() loop - may have taken some time */ - } - } - else { - /* Asked to run due to time-out. Clear the 'lastcall' variable to force - update_timer() to trigger a callback to the app again even if the same - timeout is still the one to run after this call. That handles the case - when the application asks libcurl to run the timeout prematurely. */ - memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); - } - - /* - * The loop following here will go on as long as there are expire-times left - * to process in the splay and 'data' will be re-assigned for every expired - * handle we deal with. - */ - do { - /* the first loop lap 'data' can be NULL */ - if(data) { - SIGPIPE_VARIABLE(pipe_st); - - sigpipe_ignore(data, &pipe_st); - result = multi_runsingle(multi, now, data); - sigpipe_restore(&pipe_st); - - if(CURLM_OK >= result) - /* get the socket(s) and check if the state has been changed since - last */ - singlesocket(multi, data); - } - - /* Check if there's one (more) expired timer to deal with! This function - extracts a matching node if there is one */ - - multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); - if(t) { - data = t->payload; /* assign this for next loop */ - (void)add_next_timeout(now, multi, t->payload); - } - - } while(t); - - *running_handles = multi->num_alive; - return result; -} - -#undef curl_multi_setopt -CURLMcode curl_multi_setopt(struct Curl_multi *multi, - CURLMoption option, ...) -{ - CURLMcode res = CURLM_OK; - va_list param; - - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - va_start(param, option); - - switch(option) { - case CURLMOPT_SOCKETFUNCTION: - multi->socket_cb = va_arg(param, curl_socket_callback); - break; - case CURLMOPT_SOCKETDATA: - multi->socket_userp = va_arg(param, void *); - break; - case CURLMOPT_PUSHFUNCTION: - multi->push_cb = va_arg(param, curl_push_callback); - break; - case CURLMOPT_PUSHDATA: - multi->push_userp = va_arg(param, void *); - break; - case CURLMOPT_PIPELINING: - multi->pipelining = va_arg(param, long); - break; - case CURLMOPT_TIMERFUNCTION: - multi->timer_cb = va_arg(param, curl_multi_timer_callback); - break; - case CURLMOPT_TIMERDATA: - multi->timer_userp = va_arg(param, void *); - break; - case CURLMOPT_MAXCONNECTS: - multi->maxconnects = va_arg(param, long); - break; - case CURLMOPT_MAX_HOST_CONNECTIONS: - multi->max_host_connections = va_arg(param, long); - break; - case CURLMOPT_MAX_PIPELINE_LENGTH: - multi->max_pipeline_length = va_arg(param, long); - break; - case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: - multi->content_length_penalty_size = va_arg(param, long); - break; - case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: - multi->chunk_length_penalty_size = va_arg(param, long); - break; - case CURLMOPT_PIPELINING_SITE_BL: - res = Curl_pipeline_set_site_blacklist(va_arg(param, char **), - &multi->pipelining_site_bl); - break; - case CURLMOPT_PIPELINING_SERVER_BL: - res = Curl_pipeline_set_server_blacklist(va_arg(param, char **), - &multi->pipelining_server_bl); - break; - case CURLMOPT_MAX_TOTAL_CONNECTIONS: - multi->max_total_connections = va_arg(param, long); - break; - default: - res = CURLM_UNKNOWN_OPTION; - break; - } - va_end(param); - return res; -} - -/* we define curl_multi_socket() in the public multi.h header */ -#undef curl_multi_socket - -CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s, - int *running_handles) -{ - CURLMcode result = multi_socket(multi, FALSE, s, 0, running_handles); - if(CURLM_OK >= result) - update_timer(multi); - return result; -} - -CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s, - int ev_bitmask, int *running_handles) -{ - CURLMcode result = multi_socket(multi, FALSE, s, - ev_bitmask, running_handles); - if(CURLM_OK >= result) - update_timer(multi); - return result; -} - -CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles) - -{ - CURLMcode result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, - running_handles); - if(CURLM_OK >= result) - update_timer(multi); - return result; -} - -static CURLMcode multi_timeout(struct Curl_multi *multi, - long *timeout_ms) -{ - static struct curltime tv_zero = {0, 0}; - - if(multi->timetree) { - /* we have a tree of expire times */ - struct curltime now = Curl_tvnow(); - - /* splay the lowest to the bottom */ - multi->timetree = Curl_splay(tv_zero, multi->timetree); - - if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) { - /* some time left before expiration */ - *timeout_ms = (long)curlx_tvdiff(multi->timetree->key, now); - if(!*timeout_ms) - /* - * Since we only provide millisecond resolution on the returned value - * and the diff might be less than one millisecond here, we don't - * return zero as that may cause short bursts of busyloops on fast - * processors while the diff is still present but less than one - * millisecond! instead we return 1 until the time is ripe. - */ - *timeout_ms = 1; - } - else - /* 0 means immediately */ - *timeout_ms = 0; - } - else - *timeout_ms = -1; - - return CURLM_OK; -} - -CURLMcode curl_multi_timeout(struct Curl_multi *multi, - long *timeout_ms) -{ - /* First, make some basic checks that the CURLM handle is a good handle */ - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - return multi_timeout(multi, timeout_ms); -} - -/* - * Tell the application it should update its timers, if it subscribes to the - * update timer callback. - */ -static int update_timer(struct Curl_multi *multi) -{ - long timeout_ms; - - if(!multi->timer_cb) - return 0; - if(multi_timeout(multi, &timeout_ms)) { - return -1; - } - if(timeout_ms < 0) { - static const struct curltime none = {0, 0}; - if(Curl_splaycomparekeys(none, multi->timer_lastcall)) { - multi->timer_lastcall = none; - /* there's no timeout now but there was one previously, tell the app to - disable it */ - return multi->timer_cb(multi, -1, multi->timer_userp); - } - return 0; - } - - /* When multi_timeout() is done, multi->timetree points to the node with the - * timeout we got the (relative) time-out time for. We can thus easily check - * if this is the same (fixed) time as we got in a previous call and then - * avoid calling the callback again. */ - if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0) - return 0; - - multi->timer_lastcall = multi->timetree->key; - - return multi->timer_cb(multi, timeout_ms, multi->timer_userp); -} - -/* - * multi_deltimeout() - * - * Remove a given timestamp from the list of timeouts. - */ -static void -multi_deltimeout(struct Curl_easy *data, expire_id eid) -{ - struct curl_llist_element *e; - struct curl_llist *timeoutlist = &data->state.timeoutlist; - /* find and remove the specific node from the list */ - for(e = timeoutlist->head; e; e = e->next) { - struct time_node *n = (struct time_node *)e->ptr; - if(n->eid == eid) { - Curl_llist_remove(timeoutlist, e, NULL); - return; - } - } -} - -/* - * multi_addtimeout() - * - * Add a timestamp to the list of timeouts. Keep the list sorted so that head - * of list is always the timeout nearest in time. - * - */ -static CURLMcode -multi_addtimeout(struct Curl_easy *data, - struct curltime *stamp, - expire_id eid) -{ - struct curl_llist_element *e; - struct time_node *node; - struct curl_llist_element *prev = NULL; - size_t n; - struct curl_llist *timeoutlist = &data->state.timeoutlist; - - node = &data->state.expires[eid]; - - /* copy the timestamp and id */ - memcpy(&node->time, stamp, sizeof(*stamp)); - node->eid = eid; /* also marks it as in use */ - - n = Curl_llist_count(timeoutlist); - if(n) { - /* find the correct spot in the list */ - for(e = timeoutlist->head; e; e = e->next) { - struct time_node *check = (struct time_node *)e->ptr; - time_t diff = curlx_tvdiff(check->time, node->time); - if(diff > 0) - break; - prev = e; - } - - } - /* else - this is the first timeout on the list */ - - Curl_llist_insert_next(timeoutlist, prev, node, &node->list); - return CURLM_OK; -} - -/* - * Curl_expire() - * - * given a number of milliseconds from now to use to set the 'act before - * this'-time for the transfer, to be extracted by curl_multi_timeout() - * - * The timeout will be added to a queue of timeouts if it defines a moment in - * time that is later than the current head of queue. - * - * Expire replaces a former timeout using the same id if already set. - */ -void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id) -{ - struct Curl_multi *multi = data->multi; - struct curltime *nowp = &data->state.expiretime; - int rc; - struct curltime set; - - /* this is only interesting while there is still an associated multi struct - remaining! */ - if(!multi) - return; - - DEBUGASSERT(id < EXPIRE_LAST); - - set = Curl_tvnow(); - set.tv_sec += milli/1000; - set.tv_usec += (unsigned int)(milli%1000)*1000; - - if(set.tv_usec >= 1000000) { - set.tv_sec++; - set.tv_usec -= 1000000; - } - - /* Remove any timer with the same id just in case. */ - multi_deltimeout(data, id); - - /* Add it to the timer list. It must stay in the list until it has expired - in case we need to recompute the minimum timer later. */ - multi_addtimeout(data, &set, id); - - if(nowp->tv_sec || nowp->tv_usec) { - /* This means that the struct is added as a node in the splay tree. - Compare if the new time is earlier, and only remove-old/add-new if it - is. */ - time_t diff = curlx_tvdiff(set, *nowp); - - if(diff > 0) { - /* The current splay tree entry is sooner than this new expiry time. - We don't need to update our splay tree entry. */ - return; - } - - /* Since this is an updated time, we must remove the previous entry from - the splay tree first and then re-add the new value */ - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error removing splay node = %d\n", rc); - } - - /* Indicate that we are in the splay tree and insert the new timer expiry - value since it is our local minimum. */ - *nowp = set; - data->state.timenode.payload = data; - multi->timetree = Curl_splayinsert(*nowp, multi->timetree, - &data->state.timenode); -} - -/* - * Curl_expire_done() - * - * Removes the expire timer. Marks it as done. - * - */ -void Curl_expire_done(struct Curl_easy *data, expire_id id) -{ - /* remove the timer, if there */ - multi_deltimeout(data, id); -} - -/* - * Curl_expire_clear() - * - * Clear ALL timeout values for this handle. - */ -void Curl_expire_clear(struct Curl_easy *data) -{ - struct Curl_multi *multi = data->multi; - struct curltime *nowp = &data->state.expiretime; - int rc; - - /* this is only interesting while there is still an associated multi struct - remaining! */ - if(!multi) - return; - - if(nowp->tv_sec || nowp->tv_usec) { - /* Since this is an cleared time, we must remove the previous entry from - the splay tree */ - struct curl_llist *list = &data->state.timeoutlist; - - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error clearing splay node = %d\n", rc); - - /* flush the timeout list too */ - while(list->size > 0) { - Curl_llist_remove(list, list->tail, NULL); - } - -#ifdef DEBUGBUILD - infof(data, "Expire cleared\n"); -#endif - nowp->tv_sec = 0; - nowp->tv_usec = 0; - } -} - - - - -CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s, - void *hashp) -{ - struct Curl_sh_entry *there = NULL; - - there = sh_getentry(&multi->sockhash, s); - - if(!there) - return CURLM_BAD_SOCKET; - - there->socketp = hashp; - - return CURLM_OK; -} - -size_t Curl_multi_max_host_connections(struct Curl_multi *multi) -{ - return multi ? multi->max_host_connections : 0; -} - -size_t Curl_multi_max_total_connections(struct Curl_multi *multi) -{ - return multi ? multi->max_total_connections : 0; -} - -curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi) -{ - return multi ? multi->content_length_penalty_size : 0; -} - -curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi) -{ - return multi ? multi->chunk_length_penalty_size : 0; -} - -struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi) -{ - return &multi->pipelining_site_bl; -} - -struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi) -{ - return &multi->pipelining_server_bl; -} - -void Curl_multi_process_pending_handles(struct Curl_multi *multi) -{ - struct curl_llist_element *e = multi->pending.head; - - while(e) { - struct Curl_easy *data = e->ptr; - struct curl_llist_element *next = e->next; - - if(data->mstate == CURLM_STATE_CONNECT_PEND) { - multistate(data, CURLM_STATE_CONNECT); - - /* Remove this node from the list */ - Curl_llist_remove(&multi->pending, e, NULL); - - /* Make sure that the handle will be processed soonish. */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } - - e = next; /* operate on next handle */ - } -} - -#ifdef DEBUGBUILD -void Curl_multi_dump(struct Curl_multi *multi) -{ - struct Curl_easy *data; - int i; - fprintf(stderr, "* Multi status: %d handles, %d alive\n", - multi->num_easy, multi->num_alive); - for(data = multi->easyp; data; data = data->next) { - if(data->mstate < CURLM_STATE_COMPLETED) { - /* only display handles that are not completed */ - fprintf(stderr, "handle %p, state %s, %d sockets\n", - (void *)data, - statename[data->mstate], data->numsocks); - for(i = 0; i < data->numsocks; i++) { - curl_socket_t s = data->sockets[i]; - struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); - - fprintf(stderr, "%d ", (int)s); - if(!entry) { - fprintf(stderr, "INTERNAL CONFUSION\n"); - continue; - } - fprintf(stderr, "[%s %s] ", - entry->action&CURL_POLL_IN?"RECVING":"", - entry->action&CURL_POLL_OUT?"SENDING":""); - } - if(data->numsocks) - fprintf(stderr, "\n"); - } - } -} -#endif diff --git a/dep/cpr/opt/curl/lib/multihandle.h b/dep/cpr/opt/curl/lib/multihandle.h deleted file mode 100644 index 40575394702..00000000000 --- a/dep/cpr/opt/curl/lib/multihandle.h +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef HEADER_CURL_MULTIHANDLE_H -#define HEADER_CURL_MULTIHANDLE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "conncache.h" - -struct Curl_message { - struct curl_llist_element list; - /* the 'CURLMsg' is the part that is visible to the external user */ - struct CURLMsg extmsg; -}; - -/* NOTE: if you add a state here, add the name to the statename[] array as - well! -*/ -typedef enum { - CURLM_STATE_INIT, /* 0 - start in this state */ - CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */ - CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */ - CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */ - CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */ - CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting HTTPS proxy SSL initialization - to complete and/or proxy CONNECT to - finalize */ - CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */ - CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect - phase */ - CURLM_STATE_WAITDO, /* 8 - wait for our turn to send the request */ - CURLM_STATE_DO, /* 9 - start send off the request (part 1) */ - CURLM_STATE_DOING, /* 10 - sending off the request (part 1) */ - CURLM_STATE_DO_MORE, /* 11 - send off the request (part 2) */ - CURLM_STATE_DO_DONE, /* 12 - done sending off request */ - CURLM_STATE_WAITPERFORM, /* 13 - wait for our turn to read the response */ - CURLM_STATE_PERFORM, /* 14 - transfer data */ - CURLM_STATE_TOOFAST, /* 15 - wait because limit-rate exceeded */ - CURLM_STATE_DONE, /* 16 - post data transfer operation */ - CURLM_STATE_COMPLETED, /* 17 - operation complete */ - CURLM_STATE_MSGSENT, /* 18 - the operation complete message is sent */ - CURLM_STATE_LAST /* 19 - not a true state, never use this */ -} CURLMstate; - -/* we support N sockets per easy handle. Set the corresponding bit to what - action we should wait for */ -#define MAX_SOCKSPEREASYHANDLE 5 -#define GETSOCK_READABLE (0x00ff) -#define GETSOCK_WRITABLE (0xff00) - -#define CURLPIPE_ANY (CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX) - -/* This is the struct known as CURLM on the outside */ -struct Curl_multi { - /* First a simple identifier to easier detect if a user mix up - this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */ - long type; - - /* We have a doubly-linked circular list with easy handles */ - struct Curl_easy *easyp; - struct Curl_easy *easylp; /* last node */ - - int num_easy; /* amount of entries in the linked list above. */ - int num_alive; /* amount of easy handles that are added but have not yet - reached COMPLETE state */ - - struct curl_llist msglist; /* a list of messages from completed transfers */ - - struct curl_llist pending; /* Curl_easys that are in the - CURLM_STATE_CONNECT_PEND state */ - - /* callback function and user data pointer for the *socket() API */ - curl_socket_callback socket_cb; - void *socket_userp; - - /* callback function and user data pointer for server push */ - curl_push_callback push_cb; - void *push_userp; - - /* Hostname cache */ - struct curl_hash hostcache; - - /* timetree points to the splay-tree of time nodes to figure out expire - times of all currently set timers */ - struct Curl_tree *timetree; - - /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note - the pluralis form, there can be more than one easy handle waiting on the - same actual socket) */ - struct curl_hash sockhash; - - /* pipelining wanted bits (CURLPIPE*) */ - long pipelining; - - bool recheckstate; /* see Curl_multi_connchanged */ - - /* Shared connection cache (bundles)*/ - struct conncache conn_cache; - - /* This handle will be used for closing the cached connections in - curl_multi_cleanup() */ - struct Curl_easy *closure_handle; - - long maxconnects; /* if >0, a fixed limit of the maximum number of entries - we're allowed to grow the connection cache to */ - - long max_host_connections; /* if >0, a fixed limit of the maximum number - of connections per host */ - - long max_total_connections; /* if >0, a fixed limit of the maximum number - of connections in total */ - - long max_pipeline_length; /* if >0, maximum number of requests in a - pipeline */ - - long content_length_penalty_size; /* a connection with a - content-length bigger than - this is not considered - for pipelining */ - - long chunk_length_penalty_size; /* a connection with a chunk length - bigger than this is not - considered for pipelining */ - - struct curl_llist pipelining_site_bl; /* List of sites that are blacklisted - from pipelining */ - - struct curl_llist pipelining_server_bl; /* List of server types that are - blacklisted from pipelining */ - - /* timer callback and user data pointer for the *socket() API */ - curl_multi_timer_callback timer_cb; - void *timer_userp; - struct curltime timer_lastcall; /* the fixed time for the timeout for the - previous callback */ -}; - -#endif /* HEADER_CURL_MULTIHANDLE_H */ diff --git a/dep/cpr/opt/curl/lib/multiif.h b/dep/cpr/opt/curl/lib/multiif.h deleted file mode 100644 index a877571a00a..00000000000 --- a/dep/cpr/opt/curl/lib/multiif.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef HEADER_CURL_MULTIIF_H -#define HEADER_CURL_MULTIIF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Prototypes for library-wide functions provided by multi.c - */ - -void Curl_expire(struct Curl_easy *data, time_t milli, expire_id); -void Curl_expire_clear(struct Curl_easy *data); -void Curl_expire_done(struct Curl_easy *data, expire_id id); -bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits); -void Curl_multi_handlePipeBreak(struct Curl_easy *data); - -/* Internal version of curl_multi_init() accepts size parameters for the - socket and connection hashes */ -struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize); - -/* the write bits start at bit 16 for the *getsock() bitmap */ -#define GETSOCK_WRITEBITSTART 16 - -#define GETSOCK_BLANK 0 /* no bits set */ - -/* set the bit for the given sock number to make the bitmap for writable */ -#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x))) - -/* set the bit for the given sock number to make the bitmap for readable */ -#define GETSOCK_READSOCK(x) (1 << (x)) - -#ifdef DEBUGBUILD - /* - * Curl_multi_dump is not a stable public function, this is only meant to - * allow easier tracking of the internal handle's state and what sockets - * they use. Only for research and development DEBUGBUILD enabled builds. - */ -void Curl_multi_dump(struct Curl_multi *multi); -#endif - -void Curl_multi_process_pending_handles(struct Curl_multi *multi); - -/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */ -size_t Curl_multi_max_host_connections(struct Curl_multi *multi); - -/* Return the value of the CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE option */ -curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi); - -/* Return the value of the CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE option */ -curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi); - -/* Return the value of the CURLMOPT_PIPELINING_SITE_BL option */ -struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi); - -/* Return the value of the CURLMOPT_PIPELINING_SERVER_BL option */ -struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi); - -/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */ -size_t Curl_multi_max_total_connections(struct Curl_multi *multi); - -void Curl_multi_connchanged(struct Curl_multi *multi); - -/* - * Curl_multi_closed() - * - * Used by the connect code to tell the multi_socket code that one of the - * sockets we were using is about to be closed. This function will then - * remove it from the sockethash for this handle to make the multi_socket API - * behave properly, especially for the case when libcurl will create another - * socket again and it gets the same file descriptor number. - */ - -void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); - -/* - * Add a handle and move it into PERFORM state at once. For pushed streams. - */ -CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, - struct Curl_easy *data, - struct connectdata *conn); -#endif /* HEADER_CURL_MULTIIF_H */ diff --git a/dep/cpr/opt/curl/lib/netrc.c b/dep/cpr/opt/curl/lib/netrc.c deleted file mode 100644 index dbcc59ac930..00000000000 --- a/dep/cpr/opt/curl/lib/netrc.c +++ /dev/null @@ -1,205 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_PWD_H -#include -#endif - -#include -#include "netrc.h" -#include "strtok.h" -#include "strcase.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Get user and password from .netrc when given a machine name */ - -enum host_lookup_state { - NOTHING, - HOSTFOUND, /* the 'machine' keyword was found */ - HOSTVALID /* this is "our" machine! */ -}; - -/* - * @unittest: 1304 - * - * *loginp and *passwordp MUST be allocated if they aren't NULL when passed - * in. - */ -int Curl_parsenetrc(const char *host, - char **loginp, - char **passwordp, - char *netrcfile) -{ - FILE *file; - int retcode = 1; - int specific_login = (*loginp && **loginp != 0); - bool netrc_alloc = FALSE; - enum host_lookup_state state = NOTHING; - - char state_login = 0; /* Found a login keyword */ - char state_password = 0; /* Found a password keyword */ - int state_our_login = FALSE; /* With specific_login, found *our* login - name */ - -#define NETRC DOT_CHAR "netrc" - - if(!netrcfile) { - bool home_alloc = FALSE; - char *home = curl_getenv("HOME"); /* portable environment reader */ - if(home) { - home_alloc = TRUE; -#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) - } - else { - struct passwd pw, *pw_res; - char pwbuf[1024]; - if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) - && pw_res) { - home = strdup(pw.pw_dir); - if(!home) - return CURLE_OUT_OF_MEMORY; - home_alloc = TRUE; - } -#elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) - } - else { - struct passwd *pw; - pw = getpwuid(geteuid()); - if(pw) { - home = pw->pw_dir; - } -#endif - } - - if(!home) - return retcode; /* no home directory found (or possibly out of memory) */ - - netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC); - if(home_alloc) - free(home); - if(!netrcfile) { - return -1; - } - netrc_alloc = TRUE; - } - - file = fopen(netrcfile, FOPEN_READTEXT); - if(netrc_alloc) - free(netrcfile); - if(file) { - char *tok; - char *tok_buf; - bool done = FALSE; - char netrcbuffer[256]; - int netrcbuffsize = (int)sizeof(netrcbuffer); - - while(!done && fgets(netrcbuffer, netrcbuffsize, file)) { - tok = strtok_r(netrcbuffer, " \t\n", &tok_buf); - if(tok && *tok == '#') - /* treat an initial hash as a comment line */ - continue; - while(!done && tok) { - - if((*loginp && **loginp) && (*passwordp && **passwordp)) { - done = TRUE; - break; - } - - switch(state) { - case NOTHING: - if(strcasecompare("machine", tok)) { - /* the next tok is the machine name, this is in itself the - delimiter that starts the stuff entered for this machine, - after this we need to search for 'login' and - 'password'. */ - state = HOSTFOUND; - } - else if(strcasecompare("default", tok)) { - state = HOSTVALID; - retcode = 0; /* we did find our host */ - } - break; - case HOSTFOUND: - if(strcasecompare(host, tok)) { - /* and yes, this is our host! */ - state = HOSTVALID; - retcode = 0; /* we did find our host */ - } - else - /* not our host */ - state = NOTHING; - break; - case HOSTVALID: - /* we are now parsing sub-keywords concerning "our" host */ - if(state_login) { - if(specific_login) { - state_our_login = strcasecompare(*loginp, tok); - } - else { - free(*loginp); - *loginp = strdup(tok); - if(!*loginp) { - retcode = -1; /* allocation failed */ - goto out; - } - } - state_login = 0; - } - else if(state_password) { - if(state_our_login || !specific_login) { - free(*passwordp); - *passwordp = strdup(tok); - if(!*passwordp) { - retcode = -1; /* allocation failed */ - goto out; - } - } - state_password = 0; - } - else if(strcasecompare("login", tok)) - state_login = 1; - else if(strcasecompare("password", tok)) - state_password = 1; - else if(strcasecompare("machine", tok)) { - /* ok, there's machine here go => */ - state = HOSTFOUND; - state_our_login = FALSE; - } - break; - } /* switch (state) */ - - tok = strtok_r(NULL, " \t\n", &tok_buf); - } /* while(tok) */ - } /* while fgets() */ - - out: - fclose(file); - } - - return retcode; -} diff --git a/dep/cpr/opt/curl/lib/netrc.h b/dep/cpr/opt/curl/lib/netrc.h deleted file mode 100644 index d980166e6b3..00000000000 --- a/dep/cpr/opt/curl/lib/netrc.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef HEADER_CURL_NETRC_H -#define HEADER_CURL_NETRC_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ -int Curl_parsenetrc(const char *host, - char **loginp, - char **passwordp, - char *filename); - /* Assume: (*passwordp)[0]=0, host[0] != 0. - * If (*loginp)[0] = 0, search for login and password within a machine - * section in the netrc. - * If (*loginp)[0] != 0, search for password within machine and login. - */ - -#endif /* HEADER_CURL_NETRC_H */ diff --git a/dep/cpr/opt/curl/lib/non-ascii.c b/dep/cpr/opt/curl/lib/non-ascii.c deleted file mode 100644 index 92b2f8d7320..00000000000 --- a/dep/cpr/opt/curl/lib/non-ascii.c +++ /dev/null @@ -1,322 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef CURL_DOES_CONVERSIONS - -#include - -#include "non-ascii.h" -#include "formdata.h" -#include "sendf.h" -#include "urldata.h" - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -#ifdef HAVE_ICONV -#include -/* set default codesets for iconv */ -#ifndef CURL_ICONV_CODESET_OF_NETWORK -#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" -#endif -#ifndef CURL_ICONV_CODESET_FOR_UTF8 -#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" -#endif -#define ICONV_ERROR (size_t)-1 -#endif /* HAVE_ICONV */ - -/* - * Curl_convert_clone() returns a malloced copy of the source string (if - * returning CURLE_OK), with the data converted to network format. - */ -CURLcode Curl_convert_clone(struct Curl_easy *data, - const char *indata, - size_t insize, - char **outbuf) -{ - char *convbuf; - CURLcode result; - - convbuf = malloc(insize); - if(!convbuf) - return CURLE_OUT_OF_MEMORY; - - memcpy(convbuf, indata, insize); - result = Curl_convert_to_network(data, convbuf, insize); - if(result) { - free(convbuf); - return result; - } - - *outbuf = convbuf; /* return the converted buffer */ - - return CURLE_OK; -} - -/* - * Curl_convert_to_network() is an internal function for performing ASCII - * conversions on non-ASCII platforms. It convers the buffer _in place_. - */ -CURLcode Curl_convert_to_network(struct Curl_easy *data, - char *buffer, size_t length) -{ - if(data && data->set.convtonetwork) { - /* use translation callback */ - CURLcode result = data->set.convtonetwork(buffer, length); - if(result) { - failf(data, - "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s", - (int)result, curl_easy_strerror(result)); - } - - return result; - } - else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - iconv_t tmpcd = (iconv_t) -1; - iconv_t *cd = &tmpcd; - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes, rc; - - /* open an iconv conversion descriptor if necessary */ - if(data) - cd = &data->outbound_cd; - if(*cd == (iconv_t)-1) { - *cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - if(*cd == (iconv_t)-1) { - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST, - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(*cd, &input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if(!data) - iconv_close(tmpcd); - if((rc == ICONV_ERROR) || (in_bytes != 0)) { - failf(data, - "The Curl_convert_to_network iconv call failed with errno %i: %s", - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } -#else - failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -/* - * Curl_convert_from_network() is an internal function for performing ASCII - * conversions on non-ASCII platforms. It convers the buffer _in place_. - */ -CURLcode Curl_convert_from_network(struct Curl_easy *data, - char *buffer, size_t length) -{ - if(data && data->set.convfromnetwork) { - /* use translation callback */ - CURLcode result = data->set.convfromnetwork(buffer, length); - if(result) { - failf(data, - "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s", - (int)result, curl_easy_strerror(result)); - } - - return result; - } - else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - iconv_t tmpcd = (iconv_t) -1; - iconv_t *cd = &tmpcd; - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes, rc; - - /* open an iconv conversion descriptor if necessary */ - if(data) - cd = &data->inbound_cd; - if(*cd == (iconv_t)-1) { - *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - if(*cd == (iconv_t)-1) { - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK, - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(*cd, &input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if(!data) - iconv_close(tmpcd); - if((rc == ICONV_ERROR) || (in_bytes != 0)) { - failf(data, - "Curl_convert_from_network iconv call failed with errno %i: %s", - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } -#else - failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -/* - * Curl_convert_from_utf8() is an internal function for performing UTF-8 - * conversions on non-ASCII platforms. - */ -CURLcode Curl_convert_from_utf8(struct Curl_easy *data, - char *buffer, size_t length) -{ - if(data && data->set.convfromutf8) { - /* use translation callback */ - CURLcode result = data->set.convfromutf8(buffer, length); - if(result) { - failf(data, - "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s", - (int)result, curl_easy_strerror(result)); - } - - return result; - } - else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - iconv_t tmpcd = (iconv_t) -1; - iconv_t *cd = &tmpcd; - char *input_ptr; - char *output_ptr; - size_t in_bytes, out_bytes, rc; - - /* open an iconv conversion descriptor if necessary */ - if(data) - cd = &data->utf8_cd; - if(*cd == (iconv_t)-1) { - *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8); - if(*cd == (iconv_t)-1) { - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8, - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(*cd, &input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if(!data) - iconv_close(tmpcd); - if((rc == ICONV_ERROR) || (in_bytes != 0)) { - failf(data, - "The Curl_convert_from_utf8 iconv call failed with errno %i: %s", - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } - if(output_ptr < input_ptr) { - /* null terminate the now shorter output string */ - *output_ptr = 0x00; - } -#else - failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -/* - * Init conversion stuff for a Curl_easy - */ -void Curl_convert_init(struct Curl_easy *data) -{ -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - /* conversion descriptors for iconv calls */ - data->outbound_cd = (iconv_t)-1; - data->inbound_cd = (iconv_t)-1; - data->utf8_cd = (iconv_t)-1; -#else - (void)data; -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ -} - -/* - * Setup conversion stuff for a Curl_easy - */ -void Curl_convert_setup(struct Curl_easy *data) -{ - data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8); -} - -/* - * Close conversion stuff for a Curl_easy - */ - -void Curl_convert_close(struct Curl_easy *data) -{ -#ifdef HAVE_ICONV - /* close iconv conversion descriptors */ - if(data->inbound_cd != (iconv_t)-1) { - iconv_close(data->inbound_cd); - } - if(data->outbound_cd != (iconv_t)-1) { - iconv_close(data->outbound_cd); - } - if(data->utf8_cd != (iconv_t)-1) { - iconv_close(data->utf8_cd); - } -#else - (void)data; -#endif /* HAVE_ICONV */ -} - -#endif /* CURL_DOES_CONVERSIONS */ diff --git a/dep/cpr/opt/curl/lib/non-ascii.h b/dep/cpr/opt/curl/lib/non-ascii.h deleted file mode 100644 index 5fb5771e04a..00000000000 --- a/dep/cpr/opt/curl/lib/non-ascii.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef HEADER_CURL_NON_ASCII_H -#define HEADER_CURL_NON_ASCII_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifdef CURL_DOES_CONVERSIONS - -#include "urldata.h" - -/* - * Curl_convert_clone() returns a malloced copy of the source string (if - * returning CURLE_OK), with the data converted to network format. - * - * If no conversion was needed *outbuf may be NULL. - */ -CURLcode Curl_convert_clone(struct Curl_easy *data, - const char *indata, - size_t insize, - char **outbuf); - -void Curl_convert_init(struct Curl_easy *data); -void Curl_convert_setup(struct Curl_easy *data); -void Curl_convert_close(struct Curl_easy *data); - -CURLcode Curl_convert_to_network(struct Curl_easy *data, - char *buffer, size_t length); -CURLcode Curl_convert_from_network(struct Curl_easy *data, - char *buffer, size_t length); -CURLcode Curl_convert_from_utf8(struct Curl_easy *data, - char *buffer, size_t length); -#else -#define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK) -#define Curl_convert_init(x) Curl_nop_stmt -#define Curl_convert_setup(x) Curl_nop_stmt -#define Curl_convert_close(x) Curl_nop_stmt -#define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK) -#define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK) -#define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK) -#endif - -#endif /* HEADER_CURL_NON_ASCII_H */ diff --git a/dep/cpr/opt/curl/lib/nonblock.c b/dep/cpr/opt/curl/lib/nonblock.c deleted file mode 100644 index 5959281e543..00000000000 --- a/dep/cpr/opt/curl/lib/nonblock.c +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif - -#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#include "nonblock.h" - -/* - * curlx_nonblock() set the given socket to either blocking or non-blocking - * mode based on the 'nonblock' boolean argument. This function is highly - * portable. - */ -int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ - int nonblock /* TRUE or FALSE */) -{ -#if defined(USE_BLOCKING_SOCKETS) - - return 0; /* returns success */ - -#elif defined(HAVE_FCNTL_O_NONBLOCK) - - /* most recent unix versions */ - int flags; - flags = sfcntl(sockfd, F_GETFL, 0); - if(nonblock) - return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK); - return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); - -#elif defined(HAVE_IOCTL_FIONBIO) - - /* older unix versions */ - int flags = nonblock ? 1 : 0; - return ioctl(sockfd, FIONBIO, &flags); - -#elif defined(HAVE_IOCTLSOCKET_FIONBIO) - - /* Windows */ - unsigned long flags = nonblock ? 1UL : 0UL; - return ioctlsocket(sockfd, FIONBIO, &flags); - -#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) - - /* Amiga */ - long flags = nonblock ? 1L : 0L; - return IoctlSocket(sockfd, FIONBIO, (char *)&flags); - -#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) - - /* BeOS */ - long b = nonblock ? 1L : 0L; - return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); - -#else -# error "no non-blocking method was found/used/set" -#endif -} diff --git a/dep/cpr/opt/curl/lib/nonblock.h b/dep/cpr/opt/curl/lib/nonblock.h deleted file mode 100644 index 98cdc25ab9f..00000000000 --- a/dep/cpr/opt/curl/lib/nonblock.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef HEADER_CURL_NONBLOCK_H -#define HEADER_CURL_NONBLOCK_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include /* for curl_socket_t */ - -int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ - int nonblock /* TRUE or FALSE */); - -#endif /* HEADER_CURL_NONBLOCK_H */ - diff --git a/dep/cpr/opt/curl/lib/nwlib.c b/dep/cpr/opt/curl/lib/nwlib.c deleted file mode 100644 index 290cbe31f48..00000000000 --- a/dep/cpr/opt/curl/lib/nwlib.c +++ /dev/null @@ -1,327 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef NETWARE /* Novell NetWare */ - -#ifdef __NOVELL_LIBC__ -/* For native LibC-based NLM we need to register as a real lib. */ -#include -#include -#include -#include -#include - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -typedef struct -{ - int _errno; - void *twentybytes; -} libthreaddata_t; - -typedef struct -{ - int x; - int y; - int z; - void *tenbytes; - NXKey_t perthreadkey; /* if -1, no key obtained... */ - NXMutex_t *lock; -} libdata_t; - -int gLibId = -1; -void *gLibHandle = (void *) NULL; -rtag_t gAllocTag = (rtag_t) NULL; -NXMutex_t *gLibLock = (NXMutex_t *) NULL; - -/* internal library function prototypes... */ -int DisposeLibraryData(void *); -void DisposeThreadData(void *); -int GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata); - - -int _NonAppStart(void *NLMHandle, - void *errorScreen, - const char *cmdLine, - const char *loadDirPath, - size_t uninitializedDataLength, - void *NLMFileHandle, - int (*readRoutineP)(int conn, - void *fileHandle, size_t offset, - size_t nbytes, - size_t *bytesRead, - void *buffer), - size_t customDataOffset, - size_t customDataSize, - int messageCount, - const char **messages) -{ - NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); - -#ifndef __GNUC__ -#pragma unused(cmdLine) -#pragma unused(loadDirPath) -#pragma unused(uninitializedDataLength) -#pragma unused(NLMFileHandle) -#pragma unused(readRoutineP) -#pragma unused(customDataOffset) -#pragma unused(customDataSize) -#pragma unused(messageCount) -#pragma unused(messages) -#endif - - /* - * Here we process our command line, post errors (to the error screen), - * perform initializations and anything else we need to do before being able - * to accept calls into us. If we succeed, we return non-zero and the NetWare - * Loader will leave us up, otherwise we fail to load and get dumped. - */ - gAllocTag = AllocateResourceTag(NLMHandle, - " memory allocations", - AllocSignature); - - if(!gAllocTag) { - OutputToScreen(errorScreen, "Unable to allocate resource tag for " - "library memory allocations.\n"); - return -1; - } - - gLibId = register_library(DisposeLibraryData); - - if(gLibId < -1) { - OutputToScreen(errorScreen, "Unable to register library with kernel.\n"); - return -1; - } - - gLibHandle = NLMHandle; - - gLibLock = NXMutexAlloc(0, 0, &liblock); - - if(!gLibLock) { - OutputToScreen(errorScreen, "Unable to allocate library data lock.\n"); - return -1; - } - - return 0; -} - -/* - * Here we clean up any resources we allocated. Resource tags is a big part - * of what we created, but NetWare doesn't ask us to free those. - */ -void _NonAppStop(void) -{ - (void) unregister_library(gLibId); - NXMutexFree(gLibLock); -} - -/* - * This function cannot be the first in the file for if the file is linked - * first, then the check-unload function's offset will be nlmname.nlm+0 - * which is how to tell that there isn't one. When the check function is - * first in the linked objects, it is ambiguous. For this reason, we will - * put it inside this file after the stop function. - * - * Here we check to see if it's alright to ourselves to be unloaded. If not, - * we return a non-zero value. Right now, there isn't any reason not to allow - * it. - */ -int _NonAppCheckUnload(void) -{ - return 0; -} - -int GetOrSetUpData(int id, libdata_t **appData, - libthreaddata_t **threadData) -{ - int err; - libdata_t *app_data; - libthreaddata_t *thread_data; - NXKey_t key; - NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0); - - err = 0; - thread_data = (libthreaddata_t *) NULL; - - /* - * Attempt to get our data for the application calling us. This is where we - * store whatever application-specific information we need to carry in - * support of calling applications. - */ - app_data = (libdata_t *) get_app_data(id); - - if(!app_data) { - /* - * This application hasn't called us before; set up application AND - * per-thread data. Of course, just in case a thread from this same - * application is calling us simultaneously, we better lock our application - * data-creation mutex. We also need to recheck for data after we acquire - * the lock because WE might be that other thread that was too late to - * create the data and the first thread in will have created it. - */ - NXLock(gLibLock); - - app_data = (libdata_t *) get_app_data(id); - if(!app_data) { - app_data = malloc(sizeof(libdata_t)); - - if(app_data) { - memset(app_data, 0, sizeof(libdata_t)); - - app_data->tenbytes = malloc(10); - app_data->lock = NXMutexAlloc(0, 0, &liblock); - - if(!app_data->tenbytes || !app_data->lock) { - if(app_data->lock) - NXMutexFree(app_data->lock); - - free(app_data); - app_data = (libdata_t *) NULL; - err = ENOMEM; - } - - if(app_data) { - /* - * Here we burn in the application data that we were trying to get - * by calling get_app_data(). Next time we call the first function, - * we'll get this data we're just now setting. We also go on here to - * establish the per-thread data for the calling thread, something - * we'll have to do on each application thread the first time - * it calls us. - */ - err = set_app_data(gLibId, app_data); - - if(err) { - free(app_data); - app_data = (libdata_t *) NULL; - err = ENOMEM; - } - else { - /* create key for thread-specific data... */ - err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key); - - if(err) /* (no more keys left?) */ - key = -1; - - app_data->perthreadkey = key; - } - } - } - } - - NXUnlock(gLibLock); - } - - if(app_data) { - key = app_data->perthreadkey; - - if(key != -1 /* couldn't create a key? no thread data */ - && !(err = NXKeyGetValue(key, (void **) &thread_data)) - && !thread_data) { - /* - * Allocate the per-thread data for the calling thread. Regardless of - * whether there was already application data or not, this may be the - * first call by a new thread. The fact that we allocation 20 bytes on - * a pointer is not very important, this just helps to demonstrate that - * we can have arbitrarily complex per-thread data. - */ - thread_data = malloc(sizeof(libthreaddata_t)); - - if(thread_data) { - thread_data->_errno = 0; - thread_data->twentybytes = malloc(20); - - if(!thread_data->twentybytes) { - free(thread_data); - thread_data = (libthreaddata_t *) NULL; - err = ENOMEM; - } - - err = NXKeySetValue(key, thread_data); - if(err) { - free(thread_data->twentybytes); - free(thread_data); - thread_data = (libthreaddata_t *) NULL; - } - } - } - } - - if(appData) - *appData = app_data; - - if(threadData) - *threadData = thread_data; - - return err; -} - -int DisposeLibraryData(void *data) -{ - if(data) { - void *tenbytes = ((libdata_t *) data)->tenbytes; - - free(tenbytes); - free(data); - } - - return 0; -} - -void DisposeThreadData(void *data) -{ - if(data) { - void *twentybytes = ((libthreaddata_t *) data)->twentybytes; - - free(twentybytes); - free(data); - } -} - -#else /* __NOVELL_LIBC__ */ -/* For native CLib-based NLM seems we can do a bit more simple. */ -#include - -int main(void) -{ - /* initialize any globals here... */ - - /* do this if any global initializing was done - SynchronizeStart(); - */ - ExitThread(TSR_THREAD, 0); - return 0; -} - -#endif /* __NOVELL_LIBC__ */ - -#else /* NETWARE */ - -#ifdef __POCC__ -# pragma warn(disable:2024) /* Disable warning #2024: Empty input file */ -#endif - -#endif /* NETWARE */ diff --git a/dep/cpr/opt/curl/lib/nwos.c b/dep/cpr/opt/curl/lib/nwos.c deleted file mode 100644 index c6c22ccbbf0..00000000000 --- a/dep/cpr/opt/curl/lib/nwos.c +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef NETWARE /* Novell NetWare */ - -#ifdef __NOVELL_LIBC__ -/* For native LibC-based NLM we need to do nothing. */ -int netware_init(void) -{ - return 0; -} - -#else /* __NOVELL_LIBC__ */ - -/* For native CLib-based NLM we need to initialize the LONG namespace. */ -#include -#include -#include -/* Make the CLIB Ctx stuff link */ -#include -NETDB_DEFINE_CONTEXT -/* Make the CLIB Inet stuff link */ -#include -#include -NETINET_DEFINE_CONTEXT - -int netware_init(void) -{ - int rc = 0; - unsigned int myHandle = GetNLMHandle(); - /* import UnAugmentAsterisk dynamically for NW4.x compatibility */ - void (*pUnAugmentAsterisk)(int) = (void(*)(int)) - ImportSymbol(myHandle, "UnAugmentAsterisk"); - /* import UseAccurateCaseForPaths dynamically for NW3.x compatibility */ - void (*pUseAccurateCaseForPaths)(int) = (void(*)(int)) - ImportSymbol(myHandle, "UseAccurateCaseForPaths"); - if(pUnAugmentAsterisk) - pUnAugmentAsterisk(1); - if(pUseAccurateCaseForPaths) - pUseAccurateCaseForPaths(1); - UnimportSymbol(myHandle, "UnAugmentAsterisk"); - UnimportSymbol(myHandle, "UseAccurateCaseForPaths"); - /* set long name space */ - if((SetCurrentNameSpace(4) == 255)) { - rc = 1; - } - if((SetTargetNameSpace(4) == 255)) { - rc = rc + 2; - } - return rc; -} - -/* dummy function to satisfy newer prelude */ -int __init_environment(void) -{ - return 0; -} - -/* dummy function to satisfy newer prelude */ -int __deinit_environment(void) -{ - return 0; -} - -#endif /* __NOVELL_LIBC__ */ - -#endif /* NETWARE */ diff --git a/dep/cpr/opt/curl/lib/objnames-test08.sh b/dep/cpr/opt/curl/lib/objnames-test08.sh deleted file mode 100644 index 485975765c0..00000000000 --- a/dep/cpr/opt/curl/lib/objnames-test08.sh +++ /dev/null @@ -1,217 +0,0 @@ -#!/bin/sh -# *************************************************************************** -# * _ _ ____ _ -# * Project ___| | | | _ \| | -# * / __| | | | |_) | | -# * | (__| |_| | _ <| |___ -# * \___|\___/|_| \_\_____| -# * -# * Copyright (C) 2013, Daniel Stenberg, , et al. -# * -# * This software is licensed as described in the file COPYING, which -# * you should have received as part of this distribution. The terms -# * are also available at https://curl.haxx.se/docs/copyright.html. -# * -# * 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, under the terms of the COPYING file. -# * -# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# * KIND, either express or implied. -# * -# *************************************************************************** - -# -# This Bourne shell script file is used by test case 1222 to do -# unit testing of curl_8char_object_name() shell function which -# is defined in file objnames.inc and sourced by this file and -# any other shell script that may use it. -# - -# -# argument validation -# - -if test $# -eq 1; then - : -else - echo "Usage: ${0} srcdir" - exit 1 -fi - -if test -f "${1}/runtests.pl"; then - : -else - echo "${0}: Wrong srcdir" - exit 1 -fi - -srcdir=${1} - -if test -f "$srcdir/../lib/objnames.inc"; then - : -else - echo "$0: Missing objnames.inc" - exit 1 -fi - -# -# Some variables -# - -logdir=log -tstnum=1222 - -list_c=$logdir/${tstnum}_list_c -list_obj=$logdir/${tstnum}_list_obj -list_obj_c=$logdir/${tstnum}_list_obj_c -list_obj_uniq=$logdir/${tstnum}_list_obj_uniq - - -# -# Source curl_8char_object_name() function definition -# - -. $srcdir/../lib/objnames.inc - -# -# Some curl_8char_object_name() unit tests -# - -echo 'Testing curl_8char_object_name...' -echo "" - -argstr=123__678__ABC__FGH__KLM__PQRSTUV -expect=16AFKPQR -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123__678__ABC__FGH__KLM__PQ.S.UV -expect=16AFKPQ -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123__678__ABC..FGH..KLM..PQRSTUV -expect=16ABC -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123__678_.ABC._FGH__KLM__PQRSTUV -expect=16 -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123.567.90ABCDEFGHIJKLMNOPQRSTUV -expect=123 -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=1234567.90A.CDEFGHIJKLMNOPQRSTUV -expect=1234567 -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=1234567890.BCD.FGHIJKLMNOPQRSTUV -expect=12345678 -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=12=45-78+0AB.DE.GHIJKLMNOPQRSTUV -expect=1470AB -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=1234567890ABCDEFGHIJKLMNOPQRSTUV -expect=12345678 -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123_567_90A_CDE_GHIJKLMNOPQRSTUV -expect=159CGHIJ -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123_567_90A_CDEFGHIJKLMNOPQRSTUV -expect=159CDEFG -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123_567_90ABCDEFGHIJKLMNOPQRSTUV -expect=1590ABCD -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123_567890ABCDEFGHIJKLMNOPQRSTUV -expect=1567890A -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=1234567890ABCDEFGHIJKLMNOPQRSTUV -expect=12345678 -outstr=`curl_8char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -# -# Verify that generated object name is distinct for -# all *.c source files in lib and src subdirectories. -# - -ls $srcdir/../lib/*.c > $list_c -ls $srcdir/../src/*.c >> $list_c - -rm -f $list_obj - -for c_fname in `cat $list_c`; do - obj_name=`curl_8char_object_name $c_fname` - echo "$obj_name" >> $list_obj -done - -sort -u $list_obj > $list_obj_uniq - -cnt_c=`cat $list_c | wc -l` -cnt_u=`cat $list_obj_uniq | wc -l` - -echo "" -echo "" -echo "" -if test $cnt_c -eq $cnt_u; then - echo "8-characters-or-less generated object names are unique." - obj_name_clash="no" -else - echo "8-characters-or-less generated object names are clashing..." - obj_name_clash="yes" -fi - -if test $obj_name_clash = "yes"; then - # - # Show clashing object names and respective source file names - # - echo "" - paste $list_obj $list_c | sort > $list_obj_c - prev_match="no" - prev_line="unknown" - prev_obj_name="unknown" - while read this_line; do - obj_name=`echo "$this_line" | cut -f1` - if test "x$obj_name" = "x$prev_obj_name"; then - if test "x$prev_match" != "xyes"; then - echo "$prev_line" - echo "$this_line" - prev_match="yes" - else - echo "$this_line" - fi - else - prev_match="no" - fi - prev_line=$this_line - prev_obj_name=$obj_name - done < $list_obj_c -fi - -rm -f $list_c -rm -f $list_obj -rm -f $list_obj_c -rm -f $list_obj_uniq - -# end of objnames-test.sh diff --git a/dep/cpr/opt/curl/lib/objnames-test10.sh b/dep/cpr/opt/curl/lib/objnames-test10.sh deleted file mode 100644 index 62184b8640a..00000000000 --- a/dep/cpr/opt/curl/lib/objnames-test10.sh +++ /dev/null @@ -1,217 +0,0 @@ -#!/bin/sh -# *************************************************************************** -# * _ _ ____ _ -# * Project ___| | | | _ \| | -# * / __| | | | |_) | | -# * | (__| |_| | _ <| |___ -# * \___|\___/|_| \_\_____| -# * -# * Copyright (C) 2013, Daniel Stenberg, , et al. -# * -# * This software is licensed as described in the file COPYING, which -# * you should have received as part of this distribution. The terms -# * are also available at https://curl.haxx.se/docs/copyright.html. -# * -# * 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, under the terms of the COPYING file. -# * -# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# * KIND, either express or implied. -# * -# *************************************************************************** - -# -# This Bourne shell script file is used by test case 1221 to do -# unit testing of curl_10char_object_name() shell function which -# is defined in file objnames.inc and sourced by this file and -# any other shell script that may use it. -# - -# -# argument validation -# - -if test $# -eq 1; then - : -else - echo "Usage: ${0} srcdir" - exit 1 -fi - -if test -f "${1}/runtests.pl"; then - : -else - echo "${0}: Wrong srcdir" - exit 1 -fi - -srcdir=${1} - -if test -f "$srcdir/../lib/objnames.inc"; then - : -else - echo "$0: Missing objnames.inc" - exit 1 -fi - -# -# Some variables -# - -logdir=log -tstnum=1221 - -list_c=$logdir/${tstnum}_list_c -list_obj=$logdir/${tstnum}_list_obj -list_obj_c=$logdir/${tstnum}_list_obj_c -list_obj_uniq=$logdir/${tstnum}_list_obj_uniq - - -# -# Source curl_10char_object_name() function definition -# - -. $srcdir/../lib/objnames.inc - -# -# Some curl_10char_object_name() unit tests -# - -echo 'Testing curl_10char_object_name...' -echo "" - -argstr=123__678__ABC__FGH__KLM__PQRSTUV -expect=16AFKPQRST -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123__678__ABC__FGH__KLM__PQ.S.UV -expect=16AFKPQ -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123__678__ABC..FGH..KLM..PQRSTUV -expect=16ABC -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123__678_.ABC._FGH__KLM__PQRSTUV -expect=16 -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123.567.90ABCDEFGHIJKLMNOPQRSTUV -expect=123 -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=1234567.90A.CDEFGHIJKLMNOPQRSTUV -expect=1234567 -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=1234567890.BCD.FGHIJKLMNOPQRSTUV -expect=1234567890 -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=12=45-78+0AB.DE.GHIJKLMNOPQRSTUV -expect=1470AB -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=1234567890ABCDEFGHIJKLMNOPQRSTUV -expect=1234567890 -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123_567_90A_CDE_GHIJKLMNOPQRSTUV -expect=159CGHIJKL -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123_567_90A_CDEFGHIJKLMNOPQRSTUV -expect=159CDEFGHI -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123_567_90ABCDEFGHIJKLMNOPQRSTUV -expect=1590ABCDEF -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=123_567890ABCDEFGHIJKLMNOPQRSTUV -expect=1567890ABC -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -argstr=1234567890ABCDEFGHIJKLMNOPQRSTUV -expect=1234567890 -outstr=`curl_10char_object_name $argstr` -echo "result: $outstr expected: $expect input: $argstr" - -# -# Verify that generated object name is distinct for -# all *.c source files in lib and src subdirectories. -# - -ls $srcdir/../lib/*.c > $list_c -ls $srcdir/../src/*.c >> $list_c - -rm -f $list_obj - -for c_fname in `cat $list_c`; do - obj_name=`curl_10char_object_name $c_fname` - echo "$obj_name" >> $list_obj -done - -sort -u $list_obj > $list_obj_uniq - -cnt_c=`cat $list_c | wc -l` -cnt_u=`cat $list_obj_uniq | wc -l` - -echo "" -echo "" -echo "" -if test $cnt_c -eq $cnt_u; then - echo "10-characters-or-less generated object names are unique." - obj_name_clash="no" -else - echo "10-characters-or-less generated object names are clashing..." - obj_name_clash="yes" -fi - -if test $obj_name_clash = "yes"; then - # - # Show clashing object names and respective source file names - # - echo "" - paste $list_obj $list_c | sort > $list_obj_c - prev_match="no" - prev_line="unknown" - prev_obj_name="unknown" - while read this_line; do - obj_name=`echo "$this_line" | cut -f1` - if test "x$obj_name" = "x$prev_obj_name"; then - if test "x$prev_match" != "xyes"; then - echo "$prev_line" - echo "$this_line" - prev_match="yes" - else - echo "$this_line" - fi - else - prev_match="no" - fi - prev_line=$this_line - prev_obj_name=$obj_name - done < $list_obj_c -fi - -rm -f $list_c -rm -f $list_obj -rm -f $list_obj_c -rm -f $list_obj_uniq - -# end of objnames-test10.sh diff --git a/dep/cpr/opt/curl/lib/objnames.inc b/dep/cpr/opt/curl/lib/objnames.inc deleted file mode 100644 index 6a5b2a8378c..00000000000 --- a/dep/cpr/opt/curl/lib/objnames.inc +++ /dev/null @@ -1,107 +0,0 @@ -# *************************************************************************** -# * _ _ ____ _ -# * Project ___| | | | _ \| | -# * / __| | | | |_) | | -# * | (__| |_| | _ <| |___ -# * \___|\___/|_| \_\_____| -# * -# * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. -# * -# * This software is licensed as described in the file COPYING, which -# * you should have received as part of this distribution. The terms -# * are also available at https://curl.haxx.se/docs/copyright.html. -# * -# * 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, under the terms of the COPYING file. -# * -# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# * KIND, either express or implied. -# * -# *************************************************************************** - -# -# This file is sourced from curl/packages/OS400/initscript.sh and -# other Bourne shell scripts. Keep it as portable as possible. -# - -# -# curl_10char_object_name -# -# This shell function accepts a single string argument with unspecified -# length representing a (*.c) source file name and returns a string which -# is a transformation of given argument. -# -# The intended purpose of this function is to transliterate a (*.c) source -# file name that may be longer than 10 characters, or not, into a string -# with at most 10 characters which may be used as an OS/400 object name. -# -# This function might not be universally useful, nor we care about it. -# -# It is intended to be used with libcurl's (*.c) source file names, so -# dependency on libcurl's source file naming scheme is acceptable and -# good enough for its intended use. Specifically it makes use of the fact -# that libcurl's (*.c) source file names which may be longer than 10 chars -# are conformed with underscore '_' separated substrings, or separated by -# other character which does not belong to the [0-9], [a-z] or [A-Z] sets. -# -# This allows repeatable and automatic short object name generation with -# no need for a hardcoded mapping table. -# -# Transformation is done in the following way: -# -# 1) Leading directory components are removed. -# 2) Leftmost dot character and any other char following it are removed. -# 3) Lowercase characters are transliterated to uppercase. -# 4) Characters not in [A-Z] or [0-9] are transliterated to underscore '_'. -# 5) Every sequence of one or more underscores is replaced with a single one. -# 6) Five leftmost substrings which end in an underscore character are -# replaced by the first character of each substring, while retaining -# the rest of the string. -# 7) Finally the result is truncated to 10 characters. -# -# Resulting object name may be shorter than 10 characters. -# -# Test case 1221 does unit testng of this function and also verifies -# that it is possible to generate distinct short object names for all -# curl and libcurl *.c source file names. -# - -curl_10char_object_name() { - echo "${1}" | \ - sed -e 's:.*/::' \ - -e 's:[.].*::' \ - -e 'y:abcdefghijklmnopqrstuvwxyz:ABCDEFGHIJKLMNOPQRSTUVWXYZ:' \ - -e 's:[^ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_]:_:g' \ - -e 's:__*:_:g' \ - -e 's:\([^_]\)[^_]*_\(.*\):\1\2:' \ - -e 's:\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3:' \ - -e 's:\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4:' \ - -e 's:\([^_]\)\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4\5:' \ - -e 's:\([^_]\)\([^_]\)\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4\5\6:' \ - -e 's:^\(..........\).*:\1:' -} - -# -# curl_8char_object_name -# -# Same as curl_10char_object_name() description and details above, except -# that object name is limited to 8 charcters maximum. -# - -curl_8char_object_name() { - echo "${1}" | \ - sed -e 's:.*/::' \ - -e 's:[.].*::' \ - -e 'y:abcdefghijklmnopqrstuvwxyz:ABCDEFGHIJKLMNOPQRSTUVWXYZ:' \ - -e 's:[^ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_]:_:g' \ - -e 's:__*:_:g' \ - -e 's:\([^_]\)[^_]*_\(.*\):\1\2:' \ - -e 's:\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3:' \ - -e 's:\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4:' \ - -e 's:\([^_]\)\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4\5:' \ - -e 's:\([^_]\)\([^_]\)\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4\5\6:' \ - -e 's:^\(........\).*:\1:' -} - -# end of objectname.inc diff --git a/dep/cpr/opt/curl/lib/openldap.c b/dep/cpr/opt/curl/lib/openldap.c deleted file mode 100644 index f2944033b58..00000000000 --- a/dep/cpr/opt/curl/lib/openldap.c +++ /dev/null @@ -1,713 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010, 2017, Howard Chu, - * Copyright (C) 2011 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP) - -/* - * Notice that USE_OPENLDAP is only a source code selection switch. When - * libcurl is built with USE_OPENLDAP defined the libcurl source code that - * gets compiled is the code from openldap.c, otherwise the code that gets - * compiled is the code from ldap.c. - * - * When USE_OPENLDAP is defined a recent version of the OpenLDAP library - * might be required for compilation and runtime. In order to use ancient - * OpenLDAP library versions, USE_OPENLDAP shall not be defined. - */ - -#include - -#include "urldata.h" -#include -#include "sendf.h" -#include "vtls/vtls.h" -#include "transfer.h" -#include "curl_ldap.h" -#include "curl_base64.h" -#include "connect.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifndef _LDAP_PVT_H -extern int ldap_pvt_url_scheme2proto(const char *); -extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, - LDAP **ld); -#endif - -static CURLcode ldap_setup_connection(struct connectdata *conn); -static CURLcode ldap_do(struct connectdata *conn, bool *done); -static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool); -static CURLcode ldap_connect(struct connectdata *conn, bool *done); -static CURLcode ldap_connecting(struct connectdata *conn, bool *done); -static CURLcode ldap_disconnect(struct connectdata *conn, bool dead); - -static Curl_recv ldap_recv; - -/* - * LDAP protocol handler. - */ - -const struct Curl_handler Curl_handler_ldap = { - "LDAP", /* scheme */ - ldap_setup_connection, /* setup_connection */ - ldap_do, /* do_it */ - ldap_done, /* done */ - ZERO_NULL, /* do_more */ - ldap_connect, /* connect_it */ - ldap_connecting, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ldap_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_LDAP, /* defport */ - CURLPROTO_LDAP, /* protocol */ - PROTOPT_NONE /* flags */ -}; - -#ifdef USE_SSL -/* - * LDAPS protocol handler. - */ - -const struct Curl_handler Curl_handler_ldaps = { - "LDAPS", /* scheme */ - ldap_setup_connection, /* setup_connection */ - ldap_do, /* do_it */ - ldap_done, /* done */ - ZERO_NULL, /* do_more */ - ldap_connect, /* connect_it */ - ldap_connecting, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ldap_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_LDAPS, /* defport */ - CURLPROTO_LDAP, /* protocol */ - PROTOPT_SSL /* flags */ -}; -#endif - -static const char *url_errs[] = { - "success", - "out of memory", - "bad parameter", - "unrecognized scheme", - "unbalanced delimiter", - "bad URL", - "bad host or port", - "bad or missing attributes", - "bad or missing scope", - "bad or missing filter", - "bad or missing extensions" -}; - -typedef struct ldapconninfo { - LDAP *ld; - Curl_recv *recv; /* for stacking SSL handler */ - Curl_send *send; - int proto; - int msgid; - bool ssldone; - bool sslinst; - bool didbind; -} ldapconninfo; - -typedef struct ldapreqinfo { - int msgid; - int nument; -} ldapreqinfo; - -static CURLcode ldap_setup_connection(struct connectdata *conn) -{ - ldapconninfo *li; - LDAPURLDesc *lud; - struct Curl_easy *data = conn->data; - int rc, proto; - CURLcode status; - - rc = ldap_url_parse(data->change.url, &lud); - if(rc != LDAP_URL_SUCCESS) { - const char *msg = "url parsing problem"; - status = CURLE_URL_MALFORMAT; - if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { - if(rc == LDAP_URL_ERR_MEM) - status = CURLE_OUT_OF_MEMORY; - msg = url_errs[rc]; - } - failf(conn->data, "LDAP local: %s", msg); - return status; - } - proto = ldap_pvt_url_scheme2proto(lud->lud_scheme); - ldap_free_urldesc(lud); - - li = calloc(1, sizeof(ldapconninfo)); - if(!li) - return CURLE_OUT_OF_MEMORY; - li->proto = proto; - conn->proto.generic = li; - connkeep(conn, "OpenLDAP default"); - /* TODO: - * - provide option to choose SASL Binds instead of Simple - */ - return CURLE_OK; -} - -#ifdef USE_SSL -static Sockbuf_IO ldapsb_tls; -#endif - -static CURLcode ldap_connect(struct connectdata *conn, bool *done) -{ - ldapconninfo *li = conn->proto.generic; - struct Curl_easy *data = conn->data; - int rc, proto = LDAP_VERSION3; - char hosturl[1024]; - char *ptr; - - (void)done; - - strcpy(hosturl, "ldap"); - ptr = hosturl + 4; - if(conn->handler->flags & PROTOPT_SSL) - *ptr++ = 's'; - snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d", - conn->host.name, conn->remote_port); - - rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld); - if(rc) { - failf(data, "LDAP local: Cannot connect to %s, %s", - hosturl, ldap_err2string(rc)); - return CURLE_COULDNT_CONNECT; - } - - ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); - -#ifdef USE_SSL - if(conn->handler->flags & PROTOPT_SSL) { - CURLcode result; - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); - if(result) - return result; - } -#endif - - return CURLE_OK; -} - -static CURLcode ldap_connecting(struct connectdata *conn, bool *done) -{ - ldapconninfo *li = conn->proto.generic; - struct Curl_easy *data = conn->data; - LDAPMessage *msg = NULL; - struct timeval tv = {0, 1}, *tvp; - int rc, err; - char *info = NULL; - -#ifdef USE_SSL - if(conn->handler->flags & PROTOPT_SSL) { - /* Is the SSL handshake complete yet? */ - if(!li->ssldone) { - CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, - &li->ssldone); - if(result || !li->ssldone) - return result; - } - - /* Have we installed the libcurl SSL handlers into the sockbuf yet? */ - if(!li->sslinst) { - Sockbuf *sb; - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn); - li->sslinst = TRUE; - li->recv = conn->recv[FIRSTSOCKET]; - li->send = conn->send[FIRSTSOCKET]; - } - } -#endif - - tvp = &tv; - -retry: - if(!li->didbind) { - char *binddn; - struct berval passwd; - - if(conn->bits.user_passwd) { - binddn = conn->user; - passwd.bv_val = conn->passwd; - passwd.bv_len = strlen(passwd.bv_val); - } - else { - binddn = NULL; - passwd.bv_val = NULL; - passwd.bv_len = 0; - } - rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd, - NULL, NULL, &li->msgid); - if(rc) - return CURLE_LDAP_CANNOT_BIND; - li->didbind = TRUE; - if(tvp) - return CURLE_OK; - } - - rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg); - if(rc < 0) { - failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc)); - return CURLE_LDAP_CANNOT_BIND; - } - if(rc == 0) { - /* timed out */ - return CURLE_OK; - } - - rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1); - if(rc) { - failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc)); - return CURLE_LDAP_CANNOT_BIND; - } - - /* Try to fallback to LDAPv2? */ - if(err == LDAP_PROTOCOL_ERROR) { - int proto; - ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); - if(proto == LDAP_VERSION3) { - if(info) { - ldap_memfree(info); - info = NULL; - } - proto = LDAP_VERSION2; - ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); - li->didbind = FALSE; - goto retry; - } - } - - if(err) { - failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc), - info ? info : ""); - if(info) - ldap_memfree(info); - return CURLE_LOGIN_DENIED; - } - - if(info) - ldap_memfree(info); - conn->recv[FIRSTSOCKET] = ldap_recv; - *done = TRUE; - - return CURLE_OK; -} - -static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection) -{ - ldapconninfo *li = conn->proto.generic; - (void) dead_connection; - - if(li) { - if(li->ld) { - ldap_unbind_ext(li->ld, NULL, NULL); - li->ld = NULL; - } - conn->proto.generic = NULL; - free(li); - } - return CURLE_OK; -} - -static CURLcode ldap_do(struct connectdata *conn, bool *done) -{ - ldapconninfo *li = conn->proto.generic; - ldapreqinfo *lr; - CURLcode status = CURLE_OK; - int rc = 0; - LDAPURLDesc *ludp = NULL; - int msgid; - struct Curl_easy *data = conn->data; - - connkeep(conn, "OpenLDAP do"); - - infof(data, "LDAP local: %s\n", data->change.url); - - rc = ldap_url_parse(data->change.url, &ludp); - if(rc != LDAP_URL_SUCCESS) { - const char *msg = "url parsing problem"; - status = CURLE_URL_MALFORMAT; - if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { - if(rc == LDAP_URL_ERR_MEM) - status = CURLE_OUT_OF_MEMORY; - msg = url_errs[rc]; - } - failf(conn->data, "LDAP local: %s", msg); - return status; - } - - rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, 0, - NULL, NULL, NULL, 0, &msgid); - ldap_free_urldesc(ludp); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); - return CURLE_LDAP_SEARCH_FAILED; - } - lr = calloc(1, sizeof(ldapreqinfo)); - if(!lr) - return CURLE_OUT_OF_MEMORY; - lr->msgid = msgid; - data->req.protop = lr; - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); - *done = TRUE; - return CURLE_OK; -} - -static CURLcode ldap_done(struct connectdata *conn, CURLcode res, - bool premature) -{ - ldapreqinfo *lr = conn->data->req.protop; - - (void)res; - (void)premature; - - if(lr) { - /* if there was a search in progress, abandon it */ - if(lr->msgid) { - ldapconninfo *li = conn->proto.generic; - ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL); - lr->msgid = 0; - } - conn->data->req.protop = NULL; - free(lr); - } - - return CURLE_OK; -} - -static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, - size_t len, CURLcode *err) -{ - ldapconninfo *li = conn->proto.generic; - struct Curl_easy *data = conn->data; - ldapreqinfo *lr = data->req.protop; - int rc, ret; - LDAPMessage *msg = NULL; - LDAPMessage *ent; - BerElement *ber = NULL; - struct timeval tv = {0, 1}; - - (void)len; - (void)buf; - (void)sockindex; - - rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg); - if(rc < 0) { - failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc)); - *err = CURLE_RECV_ERROR; - return -1; - } - - *err = CURLE_AGAIN; - ret = -1; - - /* timed out */ - if(!msg) - return ret; - - for(ent = ldap_first_message(li->ld, msg); ent; - ent = ldap_next_message(li->ld, ent)) { - struct berval bv, *bvals, **bvp = &bvals; - int binary = 0, msgtype; - CURLcode writeerr; - - msgtype = ldap_msgtype(ent); - if(msgtype == LDAP_RES_SEARCH_RESULT) { - int code; - char *info = NULL; - rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0); - if(rc) { - failf(data, "LDAP local: search ldap_parse_result %s", - ldap_err2string(rc)); - *err = CURLE_LDAP_SEARCH_FAILED; - } - else if(code && code != LDAP_SIZELIMIT_EXCEEDED) { - failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc), - info ? info : ""); - *err = CURLE_LDAP_SEARCH_FAILED; - } - else { - /* successful */ - if(code == LDAP_SIZELIMIT_EXCEEDED) - infof(data, "There are more than %d entries\n", lr->nument); - data->req.size = data->req.bytecount; - *err = CURLE_OK; - ret = 0; - } - lr->msgid = 0; - ldap_memfree(info); - break; - } - else if(msgtype != LDAP_RES_SEARCH_ENTRY) - continue; - - lr->nument++; - rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv); - if(rc < 0) { - /* TODO: verify that this is really how this return code should be - handled */ - *err = CURLE_RECV_ERROR; - return -1; - } - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - if(writeerr) { - *err = writeerr; - return -1; - } - - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, - bv.bv_len); - if(writeerr) { - *err = writeerr; - return -1; - } - - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - data->req.bytecount += bv.bv_len + 5; - - for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp); - rc == LDAP_SUCCESS; - rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp)) { - int i; - - if(bv.bv_val == NULL) break; - - if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7)) - binary = 1; - else - binary = 0; - - for(i = 0; bvals[i].bv_val != NULL; i++) { - int binval = 0; - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, - bv.bv_len); - if(writeerr) { - *err = writeerr; - return -1; - } - - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - data->req.bytecount += bv.bv_len + 2; - - if(!binary) { - /* check for leading or trailing whitespace */ - if(ISSPACE(bvals[i].bv_val[0]) || - ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1])) - binval = 1; - else { - /* check for unprintable characters */ - unsigned int j; - for(j = 0; jreq.bytecount += 2; - if(val_b64_sz > 0) { - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, - val_b64_sz); - if(writeerr) { - *err = writeerr; - return -1; - } - free(val_b64); - data->req.bytecount += val_b64_sz; - } - } - else { - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val, - bvals[i].bv_len); - if(writeerr) { - *err = writeerr; - return -1; - } - - data->req.bytecount += bvals[i].bv_len + 1; - } - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); - if(writeerr) { - *err = writeerr; - return -1; - } - - data->req.bytecount++; - } - ber_memfree(bvals); - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); - if(writeerr) { - *err = writeerr; - return -1; - } - data->req.bytecount++; - } - writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); - if(writeerr) { - *err = writeerr; - return -1; - } - data->req.bytecount++; - ber_free(ber, 0); - } - ldap_msgfree(msg); - return ret; -} - -#ifdef USE_SSL -static int -ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg) -{ - sbiod->sbiod_pvt = arg; - return 0; -} - -static int -ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod) -{ - sbiod->sbiod_pvt = NULL; - return 0; -} - -/* We don't need to do anything because libcurl does it already */ -static int -ldapsb_tls_close(Sockbuf_IO_Desc *sbiod) -{ - (void)sbiod; - return 0; -} - -static int -ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg) -{ - (void)arg; - if(opt == LBER_SB_OPT_DATA_READY) { - struct connectdata *conn = sbiod->sbiod_pvt; - return Curl_ssl_data_pending(conn, FIRSTSOCKET); - } - return 0; -} - -static ber_slen_t -ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) -{ - struct connectdata *conn = sbiod->sbiod_pvt; - ldapconninfo *li = conn->proto.generic; - ber_slen_t ret; - CURLcode err = CURLE_RECV_ERROR; - - ret = li->recv(conn, FIRSTSOCKET, buf, len, &err); - if(ret < 0 && err == CURLE_AGAIN) { - SET_SOCKERRNO(EWOULDBLOCK); - } - return ret; -} - -static ber_slen_t -ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) -{ - struct connectdata *conn = sbiod->sbiod_pvt; - ldapconninfo *li = conn->proto.generic; - ber_slen_t ret; - CURLcode err = CURLE_SEND_ERROR; - - ret = li->send(conn, FIRSTSOCKET, buf, len, &err); - if(ret < 0 && err == CURLE_AGAIN) { - SET_SOCKERRNO(EWOULDBLOCK); - } - return ret; -} - -static Sockbuf_IO ldapsb_tls = -{ - ldapsb_tls_setup, - ldapsb_tls_remove, - ldapsb_tls_ctrl, - ldapsb_tls_read, - ldapsb_tls_write, - ldapsb_tls_close -}; -#endif /* USE_SSL */ - -#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */ diff --git a/dep/cpr/opt/curl/lib/parsedate.c b/dep/cpr/opt/curl/lib/parsedate.c deleted file mode 100644 index b82605bbe32..00000000000 --- a/dep/cpr/opt/curl/lib/parsedate.c +++ /dev/null @@ -1,585 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -/* - A brief summary of the date string formats this parser groks: - - RFC 2616 3.3.1 - - Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 - Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 - Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - - we support dates without week day name: - - 06 Nov 1994 08:49:37 GMT - 06-Nov-94 08:49:37 GMT - Nov 6 08:49:37 1994 - - without the time zone: - - 06 Nov 1994 08:49:37 - 06-Nov-94 08:49:37 - - weird order: - - 1994 Nov 6 08:49:37 (GNU date fails) - GMT 08:49:37 06-Nov-94 Sunday - 94 6 Nov 08:49:37 (GNU date fails) - - time left out: - - 1994 Nov 6 - 06-Nov-94 - Sun Nov 6 94 - - unusual separators: - - 1994.Nov.6 - Sun/Nov/6/94/GMT - - commonly used time zone names: - - Sun, 06 Nov 1994 08:49:37 CET - 06 Nov 1994 08:49:37 EST - - time zones specified using RFC822 style: - - Sun, 12 Sep 2004 15:05:58 -0700 - Sat, 11 Sep 2004 21:32:11 +0200 - - compact numerical date strings: - - 20040912 15:05:58 -0700 - 20040911 +0200 - -*/ - -#include "curl_setup.h" - -#ifdef HAVE_LIMITS_H -#include -#endif - -#include -#include "strcase.h" -#include "warnless.h" -#include "parsedate.h" - -const char * const Curl_wkday[] = -{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; -static const char * const weekday[] = -{ "Monday", "Tuesday", "Wednesday", "Thursday", - "Friday", "Saturday", "Sunday" }; -const char * const Curl_month[]= -{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - -struct tzinfo { - char name[5]; - int offset; /* +/- in minutes */ -}; - -/* - * parsedate() - * - * Returns: - * - * PARSEDATE_OK - a fine conversion - * PARSEDATE_FAIL - failed to convert - * PARSEDATE_LATER - time overflow at the far end of time_t - * PARSEDATE_SOONER - time underflow at the low end of time_t - */ - -static int parsedate(const char *date, time_t *output); - -#define PARSEDATE_OK 0 -#define PARSEDATE_FAIL -1 -#define PARSEDATE_LATER 1 -#define PARSEDATE_SOONER 2 - -/* Here's a bunch of frequently used time zone names. These were supported - by the old getdate parser. */ -#define tDAYZONE -60 /* offset for daylight savings time */ -static const struct tzinfo tz[]= { - {"GMT", 0}, /* Greenwich Mean */ - {"UTC", 0}, /* Universal (Coordinated) */ - {"WET", 0}, /* Western European */ - {"BST", 0 tDAYZONE}, /* British Summer */ - {"WAT", 60}, /* West Africa */ - {"AST", 240}, /* Atlantic Standard */ - {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */ - {"EST", 300}, /* Eastern Standard */ - {"EDT", 300 tDAYZONE}, /* Eastern Daylight */ - {"CST", 360}, /* Central Standard */ - {"CDT", 360 tDAYZONE}, /* Central Daylight */ - {"MST", 420}, /* Mountain Standard */ - {"MDT", 420 tDAYZONE}, /* Mountain Daylight */ - {"PST", 480}, /* Pacific Standard */ - {"PDT", 480 tDAYZONE}, /* Pacific Daylight */ - {"YST", 540}, /* Yukon Standard */ - {"YDT", 540 tDAYZONE}, /* Yukon Daylight */ - {"HST", 600}, /* Hawaii Standard */ - {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */ - {"CAT", 600}, /* Central Alaska */ - {"AHST", 600}, /* Alaska-Hawaii Standard */ - {"NT", 660}, /* Nome */ - {"IDLW", 720}, /* International Date Line West */ - {"CET", -60}, /* Central European */ - {"MET", -60}, /* Middle European */ - {"MEWT", -60}, /* Middle European Winter */ - {"MEST", -60 tDAYZONE}, /* Middle European Summer */ - {"CEST", -60 tDAYZONE}, /* Central European Summer */ - {"MESZ", -60 tDAYZONE}, /* Middle European Summer */ - {"FWT", -60}, /* French Winter */ - {"FST", -60 tDAYZONE}, /* French Summer */ - {"EET", -120}, /* Eastern Europe, USSR Zone 1 */ - {"WAST", -420}, /* West Australian Standard */ - {"WADT", -420 tDAYZONE}, /* West Australian Daylight */ - {"CCT", -480}, /* China Coast, USSR Zone 7 */ - {"JST", -540}, /* Japan Standard, USSR Zone 8 */ - {"EAST", -600}, /* Eastern Australian Standard */ - {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */ - {"GST", -600}, /* Guam Standard, USSR Zone 9 */ - {"NZT", -720}, /* New Zealand */ - {"NZST", -720}, /* New Zealand Standard */ - {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */ - {"IDLE", -720}, /* International Date Line East */ - /* Next up: Military timezone names. RFC822 allowed these, but (as noted in - RFC 1123) had their signs wrong. Here we use the correct signs to match - actual military usage. - */ - {"A", 1 * 60}, /* Alpha */ - {"B", 2 * 60}, /* Bravo */ - {"C", 3 * 60}, /* Charlie */ - {"D", 4 * 60}, /* Delta */ - {"E", 5 * 60}, /* Echo */ - {"F", 6 * 60}, /* Foxtrot */ - {"G", 7 * 60}, /* Golf */ - {"H", 8 * 60}, /* Hotel */ - {"I", 9 * 60}, /* India */ - /* "J", Juliet is not used as a timezone, to indicate the observer's local - time */ - {"K", 10 * 60}, /* Kilo */ - {"L", 11 * 60}, /* Lima */ - {"M", 12 * 60}, /* Mike */ - {"N", -1 * 60}, /* November */ - {"O", -2 * 60}, /* Oscar */ - {"P", -3 * 60}, /* Papa */ - {"Q", -4 * 60}, /* Quebec */ - {"R", -5 * 60}, /* Romeo */ - {"S", -6 * 60}, /* Sierra */ - {"T", -7 * 60}, /* Tango */ - {"U", -8 * 60}, /* Uniform */ - {"V", -9 * 60}, /* Victor */ - {"W", -10 * 60}, /* Whiskey */ - {"X", -11 * 60}, /* X-ray */ - {"Y", -12 * 60}, /* Yankee */ - {"Z", 0}, /* Zulu, zero meridian, a.k.a. UTC */ -}; - -/* returns: - -1 no day - 0 monday - 6 sunday -*/ - -static int checkday(const char *check, size_t len) -{ - int i; - const char * const *what; - bool found = FALSE; - if(len > 3) - what = &weekday[0]; - else - what = &Curl_wkday[0]; - for(i = 0; i<7; i++) { - if(strcasecompare(check, what[0])) { - found = TRUE; - break; - } - what++; - } - return found?i:-1; -} - -static int checkmonth(const char *check) -{ - int i; - const char * const *what; - bool found = FALSE; - - what = &Curl_month[0]; - for(i = 0; i<12; i++) { - if(strcasecompare(check, what[0])) { - found = TRUE; - break; - } - what++; - } - return found?i:-1; /* return the offset or -1, no real offset is -1 */ -} - -/* return the time zone offset between GMT and the input one, in number - of seconds or -1 if the timezone wasn't found/legal */ - -static int checktz(const char *check) -{ - unsigned int i; - const struct tzinfo *what; - bool found = FALSE; - - what = tz; - for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) { - if(strcasecompare(check, what->name)) { - found = TRUE; - break; - } - what++; - } - return found?what->offset*60:-1; -} - -static void skip(const char **date) -{ - /* skip everything that aren't letters or digits */ - while(**date && !ISALNUM(**date)) - (*date)++; -} - -enum assume { - DATE_MDAY, - DATE_YEAR, - DATE_TIME -}; - -/* this is a clone of 'struct tm' but with all fields we don't need or use - cut out */ -struct my_tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; -}; - -/* struct tm to time since epoch in GMT time zone. - * This is similar to the standard mktime function but for GMT only, and - * doesn't suffer from the various bugs and portability problems that - * some systems' implementations have. - */ -static time_t my_timegm(struct my_tm *tm) -{ - static const int month_days_cumulative [12] = - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - int month, year, leap_days; - - if(tm->tm_year < 70) - /* we don't support years before 1970 as they will cause this function - to return a negative value */ - return -1; - - year = tm->tm_year + 1900; - month = tm->tm_mon; - if(month < 0) { - year += (11 - month) / 12; - month = 11 - (11 - month) % 12; - } - else if(month >= 12) { - year -= month / 12; - month = month % 12; - } - - leap_days = year - (tm->tm_mon <= 1); - leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400) - - (1969 / 4) + (1969 / 100) - (1969 / 400)); - - return ((((time_t) (year - 1970) * 365 - + leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24 - + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec; -} - -/* - * parsedate() - * - * Returns: - * - * PARSEDATE_OK - a fine conversion - * PARSEDATE_FAIL - failed to convert - * PARSEDATE_LATER - time overflow at the far end of time_t - * PARSEDATE_SOONER - time underflow at the low end of time_t - */ - -static int parsedate(const char *date, time_t *output) -{ - time_t t = 0; - int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */ - int monnum = -1; /* month of the year number, 0-11 */ - int mdaynum = -1; /* day of month, 1 - 31 */ - int hournum = -1; - int minnum = -1; - int secnum = -1; - int yearnum = -1; - int tzoff = -1; - struct my_tm tm; - enum assume dignext = DATE_MDAY; - const char *indate = date; /* save the original pointer */ - int part = 0; /* max 6 parts */ - - while(*date && (part < 6)) { - bool found = FALSE; - - skip(&date); - - if(ISALPHA(*date)) { - /* a name coming up */ - char buf[32]=""; - size_t len; - if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz]", buf)) - len = strlen(buf); - else - len = 0; - - if(wdaynum == -1) { - wdaynum = checkday(buf, len); - if(wdaynum != -1) - found = TRUE; - } - if(!found && (monnum == -1)) { - monnum = checkmonth(buf); - if(monnum != -1) - found = TRUE; - } - - if(!found && (tzoff == -1)) { - /* this just must be a time zone string */ - tzoff = checktz(buf); - if(tzoff != -1) - found = TRUE; - } - - if(!found) - return PARSEDATE_FAIL; /* bad string */ - - date += len; - } - else if(ISDIGIT(*date)) { - /* a digit */ - int val; - char *end; - int len = 0; - if((secnum == -1) && - (3 == sscanf(date, "%02d:%02d:%02d%n", - &hournum, &minnum, &secnum, &len))) { - /* time stamp! */ - date += len; - } - else if((secnum == -1) && - (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) { - /* time stamp without seconds */ - date += len; - secnum = 0; - } - else { - long lval; - int error; - int old_errno; - - old_errno = errno; - errno = 0; - lval = strtol(date, &end, 10); - error = errno; - if(errno != old_errno) - errno = old_errno; - - if(error) - return PARSEDATE_FAIL; - -#if LONG_MAX != INT_MAX - if((lval > (long)INT_MAX) || (lval < (long)INT_MIN)) - return PARSEDATE_FAIL; -#endif - - val = curlx_sltosi(lval); - - if((tzoff == -1) && - ((end - date) == 4) && - (val <= 1400) && - (indate< date) && - ((date[-1] == '+' || date[-1] == '-'))) { - /* four digits and a value less than or equal to 1400 (to take into - account all sorts of funny time zone diffs) and it is preceded - with a plus or minus. This is a time zone indication. 1400 is - picked since +1300 is frequently used and +1400 is mentioned as - an edge number in the document "ISO C 200X Proposal: Timezone - Functions" at http://david.tribble.com/text/c0xtimezone.html If - anyone has a more authoritative source for the exact maximum time - zone offsets, please speak up! */ - found = TRUE; - tzoff = (val/100 * 60 + val%100)*60; - - /* the + and - prefix indicates the local time compared to GMT, - this we need ther reversed math to get what we want */ - tzoff = date[-1]=='+'?-tzoff:tzoff; - } - - if(((end - date) == 8) && - (yearnum == -1) && - (monnum == -1) && - (mdaynum == -1)) { - /* 8 digits, no year, month or day yet. This is YYYYMMDD */ - found = TRUE; - yearnum = val/10000; - monnum = (val%10000)/100-1; /* month is 0 - 11 */ - mdaynum = val%100; - } - - if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { - if((val > 0) && (val<32)) { - mdaynum = val; - found = TRUE; - } - dignext = DATE_YEAR; - } - - if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { - yearnum = val; - found = TRUE; - if(yearnum < 1900) { - if(yearnum > 70) - yearnum += 1900; - else - yearnum += 2000; - } - if(mdaynum == -1) - dignext = DATE_MDAY; - } - - if(!found) - return PARSEDATE_FAIL; - - date = end; - } - } - - part++; - } - - if(-1 == secnum) - secnum = minnum = hournum = 0; /* no time, make it zero */ - - if((-1 == mdaynum) || - (-1 == monnum) || - (-1 == yearnum)) - /* lacks vital info, fail */ - return PARSEDATE_FAIL; - -#if SIZEOF_TIME_T < 5 - /* 32 bit time_t can only hold dates to the beginning of 2038 */ - if(yearnum > 2037) { - *output = 0x7fffffff; - return PARSEDATE_LATER; - } -#endif - - if(yearnum < 1970) { - *output = 0; - return PARSEDATE_SOONER; - } - - if((mdaynum > 31) || (monnum > 11) || - (hournum > 23) || (minnum > 59) || (secnum > 60)) - return PARSEDATE_FAIL; /* clearly an illegal date */ - - tm.tm_sec = secnum; - tm.tm_min = minnum; - tm.tm_hour = hournum; - tm.tm_mday = mdaynum; - tm.tm_mon = monnum; - tm.tm_year = yearnum - 1900; - - /* my_timegm() returns a time_t. time_t is often 32 bits, even on many - architectures that feature 64 bit 'long'. - - Some systems have 64 bit time_t and deal with years beyond 2038. However, - even on some of the systems with 64 bit time_t mktime() returns -1 for - dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) - */ - t = my_timegm(&tm); - - /* time zone adjust (cast t to int to compare to negative one) */ - if(-1 != (int)t) { - - /* Add the time zone diff between local time zone and GMT. */ - long delta = (long)(tzoff!=-1?tzoff:0); - - if((delta>0) && (t > LONG_MAX - delta)) { - *output = 0x7fffffff; - return PARSEDATE_LATER; /* time_t overflow */ - } - - t += delta; - } - - *output = t; - - return PARSEDATE_OK; -} - -time_t curl_getdate(const char *p, const time_t *now) -{ - time_t parsed = -1; - int rc = parsedate(p, &parsed); - (void)now; /* legacy argument from the past that we ignore */ - - switch(rc) { - case PARSEDATE_OK: - case PARSEDATE_LATER: - case PARSEDATE_SOONER: - return parsed; - } - /* everything else is fail */ - return -1; -} - -/* - * Curl_gmtime() is a gmtime() replacement for portability. Do not use the - * gmtime_r() or gmtime() functions anywhere else but here. - * - */ - -CURLcode Curl_gmtime(time_t intime, struct tm *store) -{ - const struct tm *tm; -#ifdef HAVE_GMTIME_R - /* thread-safe version */ - tm = (struct tm *)gmtime_r(&intime, store); -#else - tm = gmtime(&intime); - if(tm) - *store = *tm; /* copy the pointed struct to the local copy */ -#endif - - if(!tm) - return CURLE_BAD_FUNCTION_ARGUMENT; - return CURLE_OK; -} diff --git a/dep/cpr/opt/curl/lib/parsedate.h b/dep/cpr/opt/curl/lib/parsedate.h deleted file mode 100644 index 2e59eb17c27..00000000000 --- a/dep/cpr/opt/curl/lib/parsedate.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef HEADER_CURL_PARSEDATE_H -#define HEADER_CURL_PARSEDATE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -extern const char * const Curl_wkday[7]; -extern const char * const Curl_month[12]; - -CURLcode Curl_gmtime(time_t intime, struct tm *store); - -#endif /* HEADER_CURL_PARSEDATE_H */ - diff --git a/dep/cpr/opt/curl/lib/pingpong.c b/dep/cpr/opt/curl/lib/pingpong.c deleted file mode 100644 index b8f214005f4..00000000000 --- a/dep/cpr/opt/curl/lib/pingpong.c +++ /dev/null @@ -1,513 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * 'pingpong' is for generic back-and-forth support functions used by FTP, - * IMAP, POP3, SMTP and whatever more that likes them. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "urldata.h" -#include "sendf.h" -#include "select.h" -#include "progress.h" -#include "speedcheck.h" -#include "pingpong.h" -#include "multiif.h" -#include "non-ascii.h" -#include "vtls/vtls.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifdef USE_PINGPONG - -/* Returns timeout in ms. 0 or negative number means the timeout has already - triggered */ -time_t Curl_pp_state_timeout(struct pingpong *pp) -{ - struct connectdata *conn = pp->conn; - struct Curl_easy *data = conn->data; - time_t timeout_ms; /* in milliseconds */ - time_t timeout2_ms; /* in milliseconds */ - long response_time = (data->set.server_response_timeout)? - data->set.server_response_timeout: pp->response_time; - - /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine - remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is - supposed to govern the response for any given server response, not for - the time from connect to the given server response. */ - - /* Without a requested timeout, we only wait 'response_time' seconds for the - full response to arrive before we bail out */ - timeout_ms = response_time - - Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */ - - if(data->set.timeout) { - /* if timeout is requested, find out how much remaining time we have */ - timeout2_ms = data->set.timeout - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ - - /* pick the lowest number */ - timeout_ms = CURLMIN(timeout_ms, timeout2_ms); - } - - return timeout_ms; -} - -/* - * Curl_pp_statemach() - */ -CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) -{ - struct connectdata *conn = pp->conn; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc; - time_t interval_ms; - time_t timeout_ms = Curl_pp_state_timeout(pp); - struct Curl_easy *data = conn->data; - CURLcode result = CURLE_OK; - - if(timeout_ms <= 0) { - failf(data, "server response timeout"); - return CURLE_OPERATION_TIMEDOUT; /* already too little time */ - } - - if(block) { - interval_ms = 1000; /* use 1 second timeout intervals */ - if(timeout_ms < interval_ms) - interval_ms = timeout_ms; - } - else - interval_ms = 0; /* immediate */ - - if(Curl_ssl_data_pending(conn, FIRSTSOCKET)) - rc = 1; - else if(Curl_pp_moredata(pp)) - /* We are receiving and there is data in the cache so just read it */ - rc = 1; - else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET)) - /* We are receiving and there is data ready in the SSL library */ - rc = 1; - else - rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ - CURL_SOCKET_BAD, - pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ - interval_ms); - - if(block) { - /* if we didn't wait, we don't have to spend time on this now */ - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else - result = Curl_speedcheck(data, Curl_tvnow()); - - if(result) - return result; - } - - if(rc == -1) { - failf(data, "select/poll error"); - result = CURLE_OUT_OF_MEMORY; - } - else if(rc) - result = pp->statemach_act(conn); - - return result; -} - -/* initialize stuff to prepare for reading a fresh new response */ -void Curl_pp_init(struct pingpong *pp) -{ - struct connectdata *conn = pp->conn; - pp->nread_resp = 0; - pp->linestart_resp = conn->data->state.buffer; - pp->pending_resp = TRUE; - pp->response = Curl_tvnow(); /* start response time-out now! */ -} - - - -/*********************************************************************** - * - * Curl_pp_vsendf() - * - * Send the formatted string as a command to a pingpong server. Note that - * the string should not have any CRLF appended, as this function will - * append the necessary things itself. - * - * made to never block - */ -CURLcode Curl_pp_vsendf(struct pingpong *pp, - const char *fmt, - va_list args) -{ - ssize_t bytes_written; - size_t write_len; - char *fmt_crlf; - char *s; - CURLcode result; - struct connectdata *conn = pp->conn; - struct Curl_easy *data = conn->data; - -#ifdef HAVE_GSSAPI - enum protection_level data_sec = conn->data_prot; -#endif - - DEBUGASSERT(pp->sendleft == 0); - DEBUGASSERT(pp->sendsize == 0); - DEBUGASSERT(pp->sendthis == NULL); - - fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */ - if(!fmt_crlf) - return CURLE_OUT_OF_MEMORY; - - s = vaprintf(fmt_crlf, args); /* trailing CRLF appended */ - free(fmt_crlf); - if(!s) - return CURLE_OUT_OF_MEMORY; - - bytes_written = 0; - write_len = strlen(s); - - Curl_pp_init(pp); - - result = Curl_convert_to_network(data, s, write_len); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(result) { - free(s); - return result; - } - -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CMD; -#endif - result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len, - &bytes_written); -#ifdef HAVE_GSSAPI - DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); - conn->data_prot = data_sec; -#endif - - if(result) { - free(s); - return result; - } - - if(conn->data->set.verbose) - Curl_debug(conn->data, CURLINFO_HEADER_OUT, - s, (size_t)bytes_written, conn); - - if(bytes_written != (ssize_t)write_len) { - /* the whole chunk was not sent, keep it around and adjust sizes */ - pp->sendthis = s; - pp->sendsize = write_len; - pp->sendleft = write_len - bytes_written; - } - else { - free(s); - pp->sendthis = NULL; - pp->sendleft = pp->sendsize = 0; - pp->response = Curl_tvnow(); - } - - return CURLE_OK; -} - - -/*********************************************************************** - * - * Curl_pp_sendf() - * - * Send the formatted string as a command to a pingpong server. Note that - * the string should not have any CRLF appended, as this function will - * append the necessary things itself. - * - * made to never block - */ -CURLcode Curl_pp_sendf(struct pingpong *pp, - const char *fmt, ...) -{ - CURLcode result; - va_list ap; - va_start(ap, fmt); - - result = Curl_pp_vsendf(pp, fmt, ap); - - va_end(ap); - - return result; -} - -/* - * Curl_pp_readresp() - * - * Reads a piece of a server response. - */ -CURLcode Curl_pp_readresp(curl_socket_t sockfd, - struct pingpong *pp, - int *code, /* return the server code if done */ - size_t *size) /* size of the response */ -{ - ssize_t perline; /* count bytes per line */ - bool keepon = TRUE; - ssize_t gotbytes; - char *ptr; - struct connectdata *conn = pp->conn; - struct Curl_easy *data = conn->data; - char * const buf = data->state.buffer; - CURLcode result = CURLE_OK; - - *code = 0; /* 0 for errors or not done */ - *size = 0; - - ptr = buf + pp->nread_resp; - - /* number of bytes in the current line, so far */ - perline = (ssize_t)(ptr-pp->linestart_resp); - - while((pp->nread_resp < (size_t)data->set.buffer_size) && - (keepon && !result)) { - - if(pp->cache) { - /* we had data in the "cache", copy that instead of doing an actual - * read - * - * pp->cache_size is cast to ssize_t here. This should be safe, because - * it would have been populated with something of size int to begin - * with, even though its datatype may be larger than an int. - */ - DEBUGASSERT((ptr + pp->cache_size) <= (buf + data->set.buffer_size + 1)); - memcpy(ptr, pp->cache, pp->cache_size); - gotbytes = (ssize_t)pp->cache_size; - free(pp->cache); /* free the cache */ - pp->cache = NULL; /* clear the pointer */ - pp->cache_size = 0; /* zero the size just in case */ - } - else { -#ifdef HAVE_GSSAPI - enum protection_level prot = conn->data_prot; - conn->data_prot = PROT_CLEAR; -#endif - DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <= - (buf + data->set.buffer_size + 1)); - result = Curl_read(conn, sockfd, ptr, - data->set.buffer_size - pp->nread_resp, - &gotbytes); -#ifdef HAVE_GSSAPI - DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); - conn->data_prot = prot; -#endif - if(result == CURLE_AGAIN) - return CURLE_OK; /* return */ - - if(!result && (gotbytes > 0)) - /* convert from the network encoding */ - result = Curl_convert_from_network(data, ptr, gotbytes); - /* Curl_convert_from_network calls failf if unsuccessful */ - - if(result) - /* Set outer result variable to this error. */ - keepon = FALSE; - } - - if(!keepon) - ; - else if(gotbytes <= 0) { - keepon = FALSE; - result = CURLE_RECV_ERROR; - failf(data, "response reading failed"); - } - else { - /* we got a whole chunk of data, which can be anything from one - * byte to a set of lines and possible just a piece of the last - * line */ - ssize_t i; - ssize_t clipamount = 0; - bool restart = FALSE; - - data->req.headerbytecount += (long)gotbytes; - - pp->nread_resp += gotbytes; - for(i = 0; i < gotbytes; ptr++, i++) { - perline++; - if(*ptr == '\n') { - /* a newline is CRLF in pp-talk, so the CR is ignored as - the line isn't really terminated until the LF comes */ - - /* output debug output if that is requested */ -#ifdef HAVE_GSSAPI - if(!conn->sec_complete) -#endif - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - pp->linestart_resp, (size_t)perline, conn); - - /* - * We pass all response-lines to the callback function registered - * for "headers". The response lines can be seen as a kind of - * headers. - */ - result = Curl_client_write(conn, CLIENTWRITE_HEADER, - pp->linestart_resp, perline); - if(result) - return result; - - if(pp->endofresp(conn, pp->linestart_resp, perline, code)) { - /* This is the end of the last line, copy the last line to the - start of the buffer and zero terminate, for old times sake */ - size_t n = ptr - pp->linestart_resp; - memmove(buf, pp->linestart_resp, n); - buf[n] = 0; /* zero terminate */ - keepon = FALSE; - pp->linestart_resp = ptr + 1; /* advance pointer */ - i++; /* skip this before getting out */ - - *size = pp->nread_resp; /* size of the response */ - pp->nread_resp = 0; /* restart */ - break; - } - perline = 0; /* line starts over here */ - pp->linestart_resp = ptr + 1; - } - } - - if(!keepon && (i != gotbytes)) { - /* We found the end of the response lines, but we didn't parse the - full chunk of data we have read from the server. We therefore need - to store the rest of the data to be checked on the next invoke as - it may actually contain another end of response already! */ - clipamount = gotbytes - i; - restart = TRUE; - DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing " - "server response left\n", - (int)clipamount)); - } - else if(keepon) { - - if((perline == gotbytes) && (gotbytes > data->set.buffer_size/2)) { - /* We got an excessive line without newlines and we need to deal - with it. We keep the first bytes of the line then we throw - away the rest. */ - infof(data, "Excessive server response line length received, " - "%zd bytes. Stripping\n", gotbytes); - restart = TRUE; - - /* we keep 40 bytes since all our pingpong protocols are only - interested in the first piece */ - clipamount = 40; - } - else if(pp->nread_resp > (size_t)data->set.buffer_size/2) { - /* We got a large chunk of data and there's potentially still - trailing data to take care of, so we put any such part in the - "cache", clear the buffer to make space and restart. */ - clipamount = perline; - restart = TRUE; - } - } - else if(i == gotbytes) - restart = TRUE; - - if(clipamount) { - pp->cache_size = clipamount; - pp->cache = malloc(pp->cache_size); - if(pp->cache) - memcpy(pp->cache, pp->linestart_resp, pp->cache_size); - else - return CURLE_OUT_OF_MEMORY; - } - if(restart) { - /* now reset a few variables to start over nicely from the start of - the big buffer */ - pp->nread_resp = 0; /* start over from scratch in the buffer */ - ptr = pp->linestart_resp = buf; - perline = 0; - } - - } /* there was data */ - - } /* while there's buffer left and loop is requested */ - - pp->pending_resp = FALSE; - - return result; -} - -int Curl_pp_getsock(struct pingpong *pp, - curl_socket_t *socks, - int numsocks) -{ - struct connectdata *conn = pp->conn; - - if(!numsocks) - return GETSOCK_BLANK; - - socks[0] = conn->sock[FIRSTSOCKET]; - - if(pp->sendleft) { - /* write mode */ - return GETSOCK_WRITESOCK(0); - } - - /* read mode */ - return GETSOCK_READSOCK(0); -} - -CURLcode Curl_pp_flushsend(struct pingpong *pp) -{ - /* we have a piece of a command still left to send */ - struct connectdata *conn = pp->conn; - ssize_t written; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - CURLcode result = Curl_write(conn, sock, pp->sendthis + pp->sendsize - - pp->sendleft, pp->sendleft, &written); - if(result) - return result; - - if(written != (ssize_t)pp->sendleft) { - /* only a fraction was sent */ - pp->sendleft -= written; - } - else { - free(pp->sendthis); - pp->sendthis = NULL; - pp->sendleft = pp->sendsize = 0; - pp->response = Curl_tvnow(); - } - return CURLE_OK; -} - -CURLcode Curl_pp_disconnect(struct pingpong *pp) -{ - free(pp->cache); - pp->cache = NULL; - return CURLE_OK; -} - -bool Curl_pp_moredata(struct pingpong *pp) -{ - return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ? - TRUE : FALSE; -} - -#endif diff --git a/dep/cpr/opt/curl/lib/pingpong.h b/dep/cpr/opt/curl/lib/pingpong.h deleted file mode 100644 index a2c8ff59216..00000000000 --- a/dep/cpr/opt/curl/lib/pingpong.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef HEADER_CURL_PINGPONG_H -#define HEADER_CURL_PINGPONG_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \ - !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP) -#define USE_PINGPONG -#endif - -/* forward-declaration, this is defined in urldata.h */ -struct connectdata; - -typedef enum { - FTPTRANSFER_BODY, /* yes do transfer a body */ - FTPTRANSFER_INFO, /* do still go through to get info/headers */ - FTPTRANSFER_NONE, /* don't get anything and don't get info */ - FTPTRANSFER_LAST /* end of list marker, never used */ -} curl_pp_transfer; - -/* - * 'pingpong' is the generic struct used for protocols doing server<->client - * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc. - * - * It holds response cache and non-blocking sending data. - */ -struct pingpong { - char *cache; /* data cache between getresponse()-calls */ - size_t cache_size; /* size of cache in bytes */ - size_t nread_resp; /* number of bytes currently read of a server response */ - char *linestart_resp; /* line start pointer for the server response - reader function */ - bool pending_resp; /* set TRUE when a server response is pending or in - progress, and is cleared once the last response is - read */ - char *sendthis; /* allocated pointer to a buffer that is to be sent to the - server */ - size_t sendleft; /* number of bytes left to send from the sendthis buffer */ - size_t sendsize; /* total size of the sendthis buffer */ - struct curltime response; /* set to Curl_tvnow() when a command has been sent - off, used to time-out response reading */ - long response_time; /* When no timeout is given, this is the amount of - milliseconds we await for a server response. */ - - struct connectdata *conn; /* points to the connectdata struct that this - belongs to */ - - /* Function pointers the protocols MUST implement and provide for the - pingpong layer to function */ - - CURLcode (*statemach_act)(struct connectdata *conn); - - bool (*endofresp)(struct connectdata *conn, char *ptr, size_t len, - int *code); -}; - -/* - * Curl_pp_statemach() - * - * called repeatedly until done. Set 'wait' to make it wait a while on the - * socket if there's no traffic. - */ -CURLcode Curl_pp_statemach(struct pingpong *pp, bool block); - -/* initialize stuff to prepare for reading a fresh new response */ -void Curl_pp_init(struct pingpong *pp); - -/* Returns timeout in ms. 0 or negative number means the timeout has already - triggered */ -time_t Curl_pp_state_timeout(struct pingpong *pp); - - -/*********************************************************************** - * - * Curl_pp_sendf() - * - * Send the formatted string as a command to a pingpong server. Note that - * the string should not have any CRLF appended, as this function will - * append the necessary things itself. - * - * made to never block - */ -CURLcode Curl_pp_sendf(struct pingpong *pp, - const char *fmt, ...); - -/*********************************************************************** - * - * Curl_pp_vsendf() - * - * Send the formatted string as a command to a pingpong server. Note that - * the string should not have any CRLF appended, as this function will - * append the necessary things itself. - * - * made to never block - */ -CURLcode Curl_pp_vsendf(struct pingpong *pp, - const char *fmt, - va_list args); - -/* - * Curl_pp_readresp() - * - * Reads a piece of a server response. - */ -CURLcode Curl_pp_readresp(curl_socket_t sockfd, - struct pingpong *pp, - int *code, /* return the server code if done */ - size_t *size); /* size of the response */ - - -CURLcode Curl_pp_flushsend(struct pingpong *pp); - -/* call this when a pingpong connection is disconnected */ -CURLcode Curl_pp_disconnect(struct pingpong *pp); - -int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks, - int numsocks); - - -/*********************************************************************** - * - * Curl_pp_moredata() - * - * Returns whether there are still more data in the cache and so a call - * to Curl_pp_readresp() will not block. - */ -bool Curl_pp_moredata(struct pingpong *pp); - -#endif /* HEADER_CURL_PINGPONG_H */ diff --git a/dep/cpr/opt/curl/lib/pipeline.c b/dep/cpr/opt/curl/lib/pipeline.c deleted file mode 100644 index 4d41b04139b..00000000000 --- a/dep/cpr/opt/curl/lib/pipeline.c +++ /dev/null @@ -1,403 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2013, Linus Nielsen Feltzing, - * Copyright (C) 2013 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "urldata.h" -#include "url.h" -#include "progress.h" -#include "multiif.h" -#include "pipeline.h" -#include "sendf.h" -#include "strcase.h" - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -struct site_blacklist_entry { - struct curl_llist_element list; - unsigned short port; - char hostname[1]; -}; - -static void site_blacklist_llist_dtor(void *user, void *element) -{ - struct site_blacklist_entry *entry = element; - (void)user; - free(entry); -} - -static void server_blacklist_llist_dtor(void *user, void *element) -{ - (void)user; - free(element); -} - -bool Curl_pipeline_penalized(struct Curl_easy *data, - struct connectdata *conn) -{ - if(data) { - bool penalized = FALSE; - curl_off_t penalty_size = - Curl_multi_content_length_penalty_size(data->multi); - curl_off_t chunk_penalty_size = - Curl_multi_chunk_length_penalty_size(data->multi); - curl_off_t recv_size = -2; /* Make it easy to spot in the log */ - - /* Find the head of the recv pipe, if any */ - if(conn->recv_pipe.head) { - struct Curl_easy *recv_handle = conn->recv_pipe.head->ptr; - - recv_size = recv_handle->req.size; - - if(penalty_size > 0 && recv_size > penalty_size) - penalized = TRUE; - } - - if(chunk_penalty_size > 0 && - (curl_off_t)conn->chunk.datasize > chunk_penalty_size) - penalized = TRUE; - - infof(data, "Conn: %ld (%p) Receive pipe weight: (%" - CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n", - conn->connection_id, (void *)conn, recv_size, - conn->chunk.datasize, penalized?"TRUE":"FALSE"); - return penalized; - } - return FALSE; -} - -static CURLcode addHandleToPipeline(struct Curl_easy *data, - struct curl_llist *pipeline) -{ - Curl_llist_insert_next(pipeline, pipeline->tail, data, - &data->pipeline_queue); - return CURLE_OK; -} - - -CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, - struct connectdata *conn) -{ - struct curl_llist_element *sendhead = conn->send_pipe.head; - struct curl_llist *pipeline; - CURLcode result; - - pipeline = &conn->send_pipe; - - result = addHandleToPipeline(handle, pipeline); - - if(pipeline == &conn->send_pipe && sendhead != conn->send_pipe.head) { - /* this is a new one as head, expire it */ - Curl_pipeline_leave_write(conn); /* not in use yet */ - Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW); - } - -#if 0 /* enable for pipeline debugging */ - print_pipeline(conn); -#endif - - return result; -} - -/* Move this transfer from the sending list to the receiving list. - - Pay special attention to the new sending list "leader" as it needs to get - checked to update what sockets it acts on. - -*/ -void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, - struct connectdata *conn) -{ - struct curl_llist_element *curr; - - curr = conn->send_pipe.head; - while(curr) { - if(curr->ptr == handle) { - Curl_llist_move(&conn->send_pipe, curr, - &conn->recv_pipe, conn->recv_pipe.tail); - - if(conn->send_pipe.head) { - /* Since there's a new easy handle at the start of the send pipeline, - set its timeout value to 1ms to make it trigger instantly */ - Curl_pipeline_leave_write(conn); /* not used now */ -#ifdef DEBUGBUILD - infof(conn->data, "%p is at send pipe head B!\n", - (void *)conn->send_pipe.head->ptr); -#endif - Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW); - } - - /* The receiver's list is not really interesting here since either this - handle is now first in the list and we'll deal with it soon, or - another handle is already first and thus is already taken care of */ - - break; /* we're done! */ - } - curr = curr->next; - } -} - -bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, - struct connectdata *conn) -{ - if(handle->multi) { - struct curl_llist *blacklist = - Curl_multi_pipelining_site_bl(handle->multi); - - if(blacklist) { - struct curl_llist_element *curr; - - curr = blacklist->head; - while(curr) { - struct site_blacklist_entry *site; - - site = curr->ptr; - if(strcasecompare(site->hostname, conn->host.name) && - site->port == conn->remote_port) { - infof(handle, "Site %s:%d is pipeline blacklisted\n", - conn->host.name, conn->remote_port); - return TRUE; - } - curr = curr->next; - } - } - } - return FALSE; -} - -CURLMcode Curl_pipeline_set_site_blacklist(char **sites, - struct curl_llist *list) -{ - /* Free the old list */ - if(list->size) - Curl_llist_destroy(list, NULL); - - if(sites) { - Curl_llist_init(list, (curl_llist_dtor) site_blacklist_llist_dtor); - - /* Parse the URLs and populate the list */ - while(*sites) { - char *port; - struct site_blacklist_entry *entry; - - entry = malloc(sizeof(struct site_blacklist_entry) + strlen(*sites)); - if(!entry) { - Curl_llist_destroy(list, NULL); - return CURLM_OUT_OF_MEMORY; - } - strcpy(entry->hostname, *sites); - - port = strchr(entry->hostname, ':'); - if(port) { - *port = '\0'; - port++; - entry->port = (unsigned short)strtol(port, NULL, 10); - } - else { - /* Default port number for HTTP */ - entry->port = 80; - } - - Curl_llist_insert_next(list, list->tail, entry, &entry->list); - sites++; - } - } - - return CURLM_OK; -} - -struct blacklist_node { - struct curl_llist_element list; - char server_name[1]; -}; - -bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, - char *server_name) -{ - if(handle->multi && server_name) { - struct curl_llist *list = - Curl_multi_pipelining_server_bl(handle->multi); - - struct curl_llist_element *e = list->head; - while(e) { - struct blacklist_node *bl = (struct blacklist_node *)e; - if(strncasecompare(bl->server_name, server_name, - strlen(bl->server_name))) { - infof(handle, "Server %s is blacklisted\n", server_name); - return TRUE; - } - e = e->next; - } - - DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name)); - } - return FALSE; -} - -CURLMcode Curl_pipeline_set_server_blacklist(char **servers, - struct curl_llist *list) -{ - /* Free the old list */ - if(list->size) - Curl_llist_destroy(list, NULL); - - if(servers) { - Curl_llist_init(list, (curl_llist_dtor) server_blacklist_llist_dtor); - - /* Parse the URLs and populate the list */ - while(*servers) { - struct blacklist_node *n; - size_t len = strlen(*servers); - - n = malloc(sizeof(struct blacklist_node) + len); - if(!n) { - Curl_llist_destroy(list, NULL); - return CURLM_OUT_OF_MEMORY; - } - strcpy(n->server_name, *servers); - - Curl_llist_insert_next(list, list->tail, n, &n->list); - servers++; - } - } - - - return CURLM_OK; -} - -static bool pipe_head(struct Curl_easy *data, - struct curl_llist *pipeline) -{ - if(pipeline) { - struct curl_llist_element *curr = pipeline->head; - if(curr) - return (curr->ptr == data) ? TRUE : FALSE; - } - return FALSE; -} - -/* returns TRUE if the given handle is head of the recv pipe */ -bool Curl_recvpipe_head(struct Curl_easy *data, - struct connectdata *conn) -{ - return pipe_head(data, &conn->recv_pipe); -} - -/* returns TRUE if the given handle is head of the send pipe */ -bool Curl_sendpipe_head(struct Curl_easy *data, - struct connectdata *conn) -{ - return pipe_head(data, &conn->send_pipe); -} - - -/* - * Check if the write channel is available and this handle as at the head, - * then grab the channel and return TRUE. - * - * If not available, return FALSE. - */ - -bool Curl_pipeline_checkget_write(struct Curl_easy *data, - struct connectdata *conn) -{ - if(conn->bits.multiplex) - /* when multiplexing, we can use it at once */ - return TRUE; - - if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) { - /* Grab the channel */ - conn->writechannel_inuse = TRUE; - return TRUE; - } - return FALSE; -} - - -/* - * Check if the read channel is available and this handle as at the head, then - * grab the channel and return TRUE. - * - * If not available, return FALSE. - */ - -bool Curl_pipeline_checkget_read(struct Curl_easy *data, - struct connectdata *conn) -{ - if(conn->bits.multiplex) - /* when multiplexing, we can use it at once */ - return TRUE; - - if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) { - /* Grab the channel */ - conn->readchannel_inuse = TRUE; - return TRUE; - } - return FALSE; -} - -/* - * The current user of the pipeline write channel gives it up. - */ -void Curl_pipeline_leave_write(struct connectdata *conn) -{ - conn->writechannel_inuse = FALSE; -} - -/* - * The current user of the pipeline read channel gives it up. - */ -void Curl_pipeline_leave_read(struct connectdata *conn) -{ - conn->readchannel_inuse = FALSE; -} - - -#if 0 -void print_pipeline(struct connectdata *conn) -{ - struct curl_llist_element *curr; - struct connectbundle *cb_ptr; - struct Curl_easy *data = conn->data; - - cb_ptr = conn->bundle; - - if(cb_ptr) { - curr = cb_ptr->conn_list->head; - while(curr) { - conn = curr->ptr; - infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n", - conn->connection_id, - (void *)conn, - conn->send_pipe->size, - conn->recv_pipe->size); - curr = curr->next; - } - } -} - -#endif diff --git a/dep/cpr/opt/curl/lib/pipeline.h b/dep/cpr/opt/curl/lib/pipeline.h deleted file mode 100644 index 413ba31a06c..00000000000 --- a/dep/cpr/opt/curl/lib/pipeline.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef HEADER_CURL_PIPELINE_H -#define HEADER_CURL_PIPELINE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2015 - 2017, Daniel Stenberg, , et al. - * Copyright (C) 2013 - 2014, Linus Nielsen Feltzing, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, - struct connectdata *conn); -void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, - struct connectdata *conn); -bool Curl_pipeline_penalized(struct Curl_easy *data, - struct connectdata *conn); - -bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, - struct connectdata *conn); - -CURLMcode Curl_pipeline_set_site_blacklist(char **sites, - struct curl_llist *list_ptr); - -bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, - char *server_name); - -CURLMcode Curl_pipeline_set_server_blacklist(char **servers, - struct curl_llist *list_ptr); - -bool Curl_pipeline_checkget_write(struct Curl_easy *data, - struct connectdata *conn); -bool Curl_pipeline_checkget_read(struct Curl_easy *data, - struct connectdata *conn); -void Curl_pipeline_leave_write(struct connectdata *conn); -void Curl_pipeline_leave_read(struct connectdata *conn); -bool Curl_recvpipe_head(struct Curl_easy *data, - struct connectdata *conn); -bool Curl_sendpipe_head(struct Curl_easy *data, - struct connectdata *conn); - -#endif /* HEADER_CURL_PIPELINE_H */ diff --git a/dep/cpr/opt/curl/lib/pop3.c b/dep/cpr/opt/curl/lib/pop3.c deleted file mode 100644 index 5792a4a6fd4..00000000000 --- a/dep/cpr/opt/curl/lib/pop3.c +++ /dev/null @@ -1,1537 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC1734 POP3 Authentication - * RFC1939 POP3 protocol - * RFC2195 CRAM-MD5 authentication - * RFC2384 POP URL Scheme - * RFC2449 POP3 Extension Mechanism - * RFC2595 Using TLS with IMAP, POP3 and ACAP - * RFC2831 DIGEST-MD5 authentication - * RFC4422 Simple Authentication and Security Layer (SASL) - * RFC4616 PLAIN authentication - * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism - * RFC5034 POP3 SASL Authentication Mechanism - * RFC6749 OAuth 2.0 Authorization Framework - * Draft LOGIN SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_POP3 - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_UTSNAME_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "progress.h" -#include "transfer.h" -#include "escape.h" -#include "http.h" /* for HTTP proxy tunnel stuff */ -#include "socks.h" -#include "pop3.h" -#include "strtoofft.h" -#include "strcase.h" -#include "vtls/vtls.h" -#include "connect.h" -#include "strerror.h" -#include "select.h" -#include "multiif.h" -#include "url.h" -#include "curl_sasl.h" -#include "curl_md5.h" -#include "warnless.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Local API functions */ -static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done); -static CURLcode pop3_do(struct connectdata *conn, bool *done); -static CURLcode pop3_done(struct connectdata *conn, CURLcode status, - bool premature); -static CURLcode pop3_connect(struct connectdata *conn, bool *done); -static CURLcode pop3_disconnect(struct connectdata *conn, bool dead); -static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done); -static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks); -static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done); -static CURLcode pop3_setup_connection(struct connectdata *conn); -static CURLcode pop3_parse_url_options(struct connectdata *conn); -static CURLcode pop3_parse_url_path(struct connectdata *conn); -static CURLcode pop3_parse_custom_request(struct connectdata *conn); -static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, - const char *initresp); -static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp); -static void pop3_get_message(char *buffer, char **outptr); - -/* - * POP3 protocol handler. - */ - -const struct Curl_handler Curl_handler_pop3 = { - "POP3", /* scheme */ - pop3_setup_connection, /* setup_connection */ - pop3_do, /* do_it */ - pop3_done, /* done */ - ZERO_NULL, /* do_more */ - pop3_connect, /* connect_it */ - pop3_multi_statemach, /* connecting */ - pop3_doing, /* doing */ - pop3_getsock, /* proto_getsock */ - pop3_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - pop3_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_POP3, /* defport */ - CURLPROTO_POP3, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ - PROTOPT_URLOPTIONS -}; - -#ifdef USE_SSL -/* - * POP3S protocol handler. - */ - -const struct Curl_handler Curl_handler_pop3s = { - "POP3S", /* scheme */ - pop3_setup_connection, /* setup_connection */ - pop3_do, /* do_it */ - pop3_done, /* done */ - ZERO_NULL, /* do_more */ - pop3_connect, /* connect_it */ - pop3_multi_statemach, /* connecting */ - pop3_doing, /* doing */ - pop3_getsock, /* proto_getsock */ - pop3_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - pop3_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_POP3S, /* defport */ - CURLPROTO_POP3S, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_SSL - | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ -}; -#endif - -/* SASL parameters for the pop3 protocol */ -static const struct SASLproto saslpop3 = { - "pop", /* The service name */ - '*', /* Code received when continuation is expected */ - '+', /* Code to receive upon authentication success */ - 255 - 8, /* Maximum initial response length (no max) */ - pop3_perform_auth, /* Send authentication command */ - pop3_continue_auth, /* Send authentication continuation */ - pop3_get_message /* Get SASL response message */ -}; - -#ifdef USE_SSL -static void pop3_to_pop3s(struct connectdata *conn) -{ - /* Change the connection handler */ - conn->handler = &Curl_handler_pop3s; - - /* Set the connection's upgraded to TLS flag */ - conn->tls_upgraded = TRUE; -} -#else -#define pop3_to_pop3s(x) Curl_nop_stmt -#endif - -/*********************************************************************** - * - * pop3_endofresp() - * - * Checks for an ending POP3 status code at the start of the given string, but - * also detects the APOP timestamp from the server greeting and various - * capabilities from the CAPA response including the supported authentication - * types and allowed SASL mechanisms. - */ -static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, - int *resp) -{ - struct pop3_conn *pop3c = &conn->proto.pop3c; - - /* Do we have an error response? */ - if(len >= 4 && !memcmp("-ERR", line, 4)) { - *resp = '-'; - - return TRUE; - } - - /* Are we processing CAPA command responses? */ - if(pop3c->state == POP3_CAPA) { - /* Do we have the terminating line? */ - if(len >= 1 && !memcmp(line, ".", 1)) - /* Treat the response as a success */ - *resp = '+'; - else - /* Treat the response as an untagged continuation */ - *resp = '*'; - - return TRUE; - } - - /* Do we have a success response? */ - if(len >= 3 && !memcmp("+OK", line, 3)) { - *resp = '+'; - - return TRUE; - } - - /* Do we have a continuation response? */ - if(len >= 1 && !memcmp("+", line, 1)) { - *resp = '*'; - - return TRUE; - } - - return FALSE; /* Nothing for us */ -} - -/*********************************************************************** - * - * pop3_get_message() - * - * Gets the authentication message from the response buffer. - */ -static void pop3_get_message(char *buffer, char **outptr) -{ - size_t len = 0; - char *message = NULL; - - /* Find the start of the message */ - for(message = buffer + 2; *message == ' ' || *message == '\t'; message++) - ; - - /* Find the end of the message */ - for(len = strlen(message); len--;) - if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && - message[len] != '\t') - break; - - /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } - - *outptr = message; -} - -/*********************************************************************** - * - * state() - * - * This is the ONLY way to change POP3 state! - */ -static void state(struct connectdata *conn, pop3state newstate) -{ - struct pop3_conn *pop3c = &conn->proto.pop3c; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ - static const char * const names[] = { - "STOP", - "SERVERGREET", - "CAPA", - "STARTTLS", - "UPGRADETLS", - "AUTH", - "APOP", - "USER", - "PASS", - "COMMAND", - "QUIT", - /* LAST */ - }; - - if(pop3c->state != newstate) - infof(conn->data, "POP3 %p state change from %s to %s\n", - (void *)pop3c, names[pop3c->state], names[newstate]); -#endif - - pop3c->state = newstate; -} - -/*********************************************************************** - * - * pop3_perform_capa() - * - * Sends the CAPA command in order to obtain a list of server side supported - * capabilities. - */ -static CURLcode pop3_perform_capa(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ - pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ - pop3c->tls_supported = FALSE; /* Clear the TLS capability */ - - /* Send the CAPA command */ - result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA"); - - if(!result) - state(conn, POP3_CAPA); - - return result; -} - -/*********************************************************************** - * - * pop3_perform_starttls() - * - * Sends the STLS command to start the upgrade to TLS. - */ -static CURLcode pop3_perform_starttls(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* Send the STLS command */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS"); - - if(!result) - state(conn, POP3_STARTTLS); - - return result; -} - -/*********************************************************************** - * - * pop3_perform_upgrade_tls() - * - * Performs the upgrade to TLS. - */ -static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - /* Start the SSL connection */ - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone); - - if(!result) { - if(pop3c->state != POP3_UPGRADETLS) - state(conn, POP3_UPGRADETLS); - - if(pop3c->ssldone) { - pop3_to_pop3s(conn); - result = pop3_perform_capa(conn); - } - } - - return result; -} - -/*********************************************************************** - * - * pop3_perform_user() - * - * Sends a clear text USER command to authenticate with. - */ -static CURLcode pop3_perform_user(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* Check we have a username and password to authenticate with and end the - connect phase if we don't */ - if(!conn->bits.user_passwd) { - state(conn, POP3_STOP); - - return result; - } - - /* Send the USER command */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s", - conn->user ? conn->user : ""); - if(!result) - state(conn, POP3_USER); - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/*********************************************************************** - * - * pop3_perform_apop() - * - * Sends an APOP command to authenticate with. - */ -static CURLcode pop3_perform_apop(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - size_t i; - MD5_context *ctxt; - unsigned char digest[MD5_DIGEST_LEN]; - char secret[2 * MD5_DIGEST_LEN + 1]; - - /* Check we have a username and password to authenticate with and end the - connect phase if we don't */ - if(!conn->bits.user_passwd) { - state(conn, POP3_STOP); - - return result; - } - - /* Create the digest */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp, - curlx_uztoui(strlen(pop3c->apoptimestamp))); - - Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd, - curlx_uztoui(strlen(conn->passwd))); - - /* Finalise the digest */ - Curl_MD5_final(ctxt, digest); - - /* Convert the calculated 16 octet digest into a 32 byte hex string */ - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&secret[2 * i], 3, "%02x", digest[i]); - - result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret); - - if(!result) - state(conn, POP3_APOP); - - return result; -} -#endif - -/*********************************************************************** - * - * pop3_perform_auth() - * - * Sends an AUTH command allowing the client to login with the given SASL - * authentication mechanism. - */ -static CURLcode pop3_perform_auth(struct connectdata *conn, - const char *mech, - const char *initresp) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - if(initresp) { /* AUTH ... */ - /* Send the AUTH command with the initial response */ - result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); - } - else { - /* Send the AUTH command */ - result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); - } - - return result; -} - -/*********************************************************************** - * - * pop3_continue_auth() - * - * Sends SASL continuation data or cancellation. - */ -static CURLcode pop3_continue_auth(struct connectdata *conn, - const char *resp) -{ - struct pop3_conn *pop3c = &conn->proto.pop3c; - - return Curl_pp_sendf(&pop3c->pp, "%s", resp); -} - -/*********************************************************************** - * - * pop3_perform_authentication() - * - * Initiates the authentication sequence, with the appropriate SASL - * authentication mechanism, falling back to APOP and clear text should a - * common mechanism not be available between the client and server. - */ -static CURLcode pop3_perform_authentication(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - saslprogress progress = SASL_IDLE; - - /* Check we have enough data to authenticate with and end the - connect phase if we don't */ - if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) { - state(conn, POP3_STOP); - return result; - } - - if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { - /* Calculate the SASL login details */ - result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); - - if(!result) - if(progress == SASL_INPROGRESS) - state(conn, POP3_AUTH); - } - - if(!result && progress == SASL_IDLE) { -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) - /* Perform APOP authentication */ - result = pop3_perform_apop(conn); - else -#endif - if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) - /* Perform clear text authentication */ - result = pop3_perform_user(conn); - else { - /* Other mechanisms not supported */ - infof(conn->data, "No known authentication mechanisms supported!\n"); - result = CURLE_LOGIN_DENIED; - } - } - - return result; -} - -/*********************************************************************** - * - * pop3_perform_command() - * - * Sends a POP3 based command. - */ -static CURLcode pop3_perform_command(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct POP3 *pop3 = data->req.protop; - const char *command = NULL; - - /* Calculate the default command */ - if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) { - command = "LIST"; - - if(pop3->id[0] != '\0') - /* Message specific LIST so skip the BODY transfer */ - pop3->transfer = FTPTRANSFER_INFO; - } - else - command = "RETR"; - - /* Send the command */ - if(pop3->id[0] != '\0') - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", - (pop3->custom && pop3->custom[0] != '\0' ? - pop3->custom : command), pop3->id); - else - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", - (pop3->custom && pop3->custom[0] != '\0' ? - pop3->custom : command)); - - if(!result) - state(conn, POP3_COMMAND); - - return result; -} - -/*********************************************************************** - * - * pop3_perform_quit() - * - * Performs the quit action prior to sclose() be called. - */ -static CURLcode pop3_perform_quit(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* Send the QUIT command */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT"); - - if(!result) - state(conn, POP3_QUIT); - - return result; -} - -/* For the initial server greeting */ -static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *line = data->state.buffer; - size_t len = strlen(line); - size_t i; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Got unexpected pop3-server response"); - result = CURLE_WEIRD_SERVER_REPLY; - } - else { - /* Does the server support APOP authentication? */ - if(len >= 4 && line[len - 2] == '>') { - /* Look for the APOP timestamp */ - for(i = 3; i < len - 2; ++i) { - if(line[i] == '<') { - /* Calculate the length of the timestamp */ - size_t timestamplen = len - 1 - i; - if(!timestamplen) - break; - - /* Allocate some memory for the timestamp */ - pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1); - - if(!pop3c->apoptimestamp) - break; - - /* Copy the timestamp */ - memcpy(pop3c->apoptimestamp, line + i, timestamplen); - pop3c->apoptimestamp[timestamplen] = '\0'; - - /* Store the APOP capability */ - pop3c->authtypes |= POP3_TYPE_APOP; - break; - } - } - } - - result = pop3_perform_capa(conn); - } - - return result; -} - -/* For CAPA responses */ -static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *line = data->state.buffer; - size_t len = strlen(line); - size_t wordlen; - - (void)instate; /* no use for this yet */ - - /* Do we have a untagged continuation response? */ - if(pop3code == '*') { - /* Does the server support the STLS capability? */ - if(len >= 4 && !memcmp(line, "STLS", 4)) - pop3c->tls_supported = TRUE; - - /* Does the server support clear text authentication? */ - else if(len >= 4 && !memcmp(line, "USER", 4)) - pop3c->authtypes |= POP3_TYPE_CLEARTEXT; - - /* Does the server support SASL based authentication? */ - else if(len >= 5 && !memcmp(line, "SASL ", 5)) { - pop3c->authtypes |= POP3_TYPE_SASL; - - /* Advance past the SASL keyword */ - line += 5; - len -= 5; - - /* Loop through the data line */ - for(;;) { - size_t llen; - unsigned int mechbit; - - while(len && - (*line == ' ' || *line == '\t' || - *line == '\r' || *line == '\n')) { - - line++; - len--; - } - - if(!len) - break; - - /* Extract the word */ - for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && - line[wordlen] != '\t' && line[wordlen] != '\r' && - line[wordlen] != '\n';) - wordlen++; - - /* Test the word for a matching authentication mechanism */ - mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); - if(mechbit && llen == wordlen) - pop3c->sasl.authmechs |= mechbit; - - line += wordlen; - len -= wordlen; - } - } - } - else if(pop3code == '+') { - if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested */ - if(pop3c->tls_supported) - /* Switch to TLS connection now */ - result = pop3_perform_starttls(conn); - else if(data->set.use_ssl == CURLUSESSL_TRY) - /* Fallback and carry on with authentication */ - result = pop3_perform_authentication(conn); - else { - failf(data, "STLS not supported."); - result = CURLE_USE_SSL_FAILED; - } - } - else - result = pop3_perform_authentication(conn); - } - else { - /* Clear text is supported when CAPA isn't recognised */ - pop3c->authtypes |= POP3_TYPE_CLEARTEXT; - - result = pop3_perform_authentication(conn); - } - - return result; -} - -/* For STARTTLS responses */ -static CURLcode pop3_state_starttls_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied"); - result = CURLE_USE_SSL_FAILED; - } - else - result = pop3_perform_authentication(conn); - } - else - result = pop3_perform_upgrade_tls(conn); - - return result; -} - -/* For SASL authentication responses */ -static CURLcode pop3_state_auth_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - saslprogress progress; - - (void)instate; /* no use for this yet */ - - result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress); - if(!result) - switch(progress) { - case SASL_DONE: - state(conn, POP3_STOP); /* Authenticated */ - break; - case SASL_IDLE: /* No mechanism left after cancellation */ -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) - /* Perform APOP authentication */ - result = pop3_perform_apop(conn); - else -#endif - if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) - /* Perform clear text authentication */ - result = pop3_perform_user(conn); - else { - failf(data, "Authentication cancelled"); - result = CURLE_LOGIN_DENIED; - } - break; - default: - break; - } - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For APOP responses */ -static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Authentication failed: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, POP3_STOP); - - return result; -} -#endif - -/* For USER responses */ -static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied. %c", pop3code); - result = CURLE_LOGIN_DENIED; - } - else - /* Send the PASS command */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", - conn->passwd ? conn->passwd : ""); - if(!result) - state(conn, POP3_PASS); - - return result; -} - -/* For PASS responses */ -static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied. %c", pop3code); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, POP3_STOP); - - return result; -} - -/* For command responses */ -static CURLcode pop3_state_command_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct POP3 *pop3 = data->req.protop; - struct pop3_conn *pop3c = &conn->proto.pop3c; - struct pingpong *pp = &pop3c->pp; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - state(conn, POP3_STOP); - return CURLE_RECV_ERROR; - } - - /* This 'OK' line ends with a CR LF pair which is the two first bytes of the - EOB string so count this is two matching bytes. This is necessary to make - the code detect the EOB if the only data than comes now is %2e CR LF like - when there is no body to return. */ - pop3c->eob = 2; - - /* But since this initial CR LF pair is not part of the actual body, we set - the strip counter here so that these bytes won't be delivered. */ - pop3c->strip = 2; - - if(pop3->transfer == FTPTRANSFER_BODY) { - /* POP3 download */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); - - if(pp->cache) { - /* The header "cache" contains a bunch of data that is actually body - content so send it as such. Note that there may even be additional - "headers" after the body */ - - if(!data->set.opt_no_body) { - result = Curl_pop3_write(conn, pp->cache, pp->cache_size); - if(result) - return result; - } - - /* Free the cache */ - Curl_safefree(pp->cache); - - /* Reset the cache size */ - pp->cache_size = 0; - } - } - - /* End of DO phase */ - state(conn, POP3_STOP); - - return result; -} - -static CURLcode pop3_statemach_act(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int pop3code; - struct pop3_conn *pop3c = &conn->proto.pop3c; - struct pingpong *pp = &pop3c->pp; - size_t nread = 0; - - /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */ - if(pop3c->state == POP3_UPGRADETLS) - return pop3_perform_upgrade_tls(conn); - - /* Flush any data that needs to be sent */ - if(pp->sendleft) - return Curl_pp_flushsend(pp); - - do { - /* Read the response from the server */ - result = Curl_pp_readresp(sock, pp, &pop3code, &nread); - if(result) - return result; - - if(!pop3code) - break; - - /* We have now received a full POP3 server response */ - switch(pop3c->state) { - case POP3_SERVERGREET: - result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); - break; - - case POP3_CAPA: - result = pop3_state_capa_resp(conn, pop3code, pop3c->state); - break; - - case POP3_STARTTLS: - result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH: - result = pop3_state_auth_resp(conn, pop3code, pop3c->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case POP3_APOP: - result = pop3_state_apop_resp(conn, pop3code, pop3c->state); - break; -#endif - - case POP3_USER: - result = pop3_state_user_resp(conn, pop3code, pop3c->state); - break; - - case POP3_PASS: - result = pop3_state_pass_resp(conn, pop3code, pop3c->state); - break; - - case POP3_COMMAND: - result = pop3_state_command_resp(conn, pop3code, pop3c->state); - break; - - case POP3_QUIT: - /* fallthrough, just stop! */ - default: - /* internal error */ - state(conn, POP3_STOP); - break; - } - } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp)); - - return result; -} - -/* Called repeatedly until done from multi.c */ -static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) { - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone); - if(result || !pop3c->ssldone) - return result; - } - - result = Curl_pp_statemach(&pop3c->pp, FALSE); - *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; - - return result; -} - -static CURLcode pop3_block_statemach(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - while(pop3c->state != POP3_STOP && !result) - result = Curl_pp_statemach(&pop3c->pp, TRUE); - - return result; -} - -/* Allocate and initialize the POP3 struct for the current Curl_easy if - required */ -static CURLcode pop3_init(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct POP3 *pop3; - - pop3 = data->req.protop = calloc(sizeof(struct POP3), 1); - if(!pop3) - result = CURLE_OUT_OF_MEMORY; - - return result; -} - -/* For the POP3 "protocol connect" and "doing" phases only */ -static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks) -{ - return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks); -} - -/*********************************************************************** - * - * pop3_connect() - * - * This function should do everything that is to be considered a part of the - * connection phase. - * - * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE if not. - */ -static CURLcode pop3_connect(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - struct pingpong *pp = &pop3c->pp; - - *done = FALSE; /* default to not done yet */ - - /* We always support persistent connections in POP3 */ - connkeep(conn, "POP3 default"); - - /* Set the default response time-out */ - pp->response_time = RESP_TIMEOUT; - pp->statemach_act = pop3_statemach_act; - pp->endofresp = pop3_endofresp; - pp->conn = conn; - - /* Set the default preferred authentication type and mechanism */ - pop3c->preftype = POP3_TYPE_ANY; - Curl_sasl_init(&pop3c->sasl, &saslpop3); - - /* Initialise the pingpong layer */ - Curl_pp_init(pp); - - /* Parse the URL options */ - result = pop3_parse_url_options(conn); - if(result) - return result; - - /* Start off waiting for the server greeting response */ - state(conn, POP3_SERVERGREET); - - result = pop3_multi_statemach(conn, done); - - return result; -} - -/*********************************************************************** - * - * pop3_done() - * - * The DONE function. This does what needs to be done after a single DO has - * performed. - * - * Input argument is already checked for validity. - */ -static CURLcode pop3_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct POP3 *pop3 = data->req.protop; - - (void)premature; - - if(!pop3) - return CURLE_OK; - - if(status) { - connclose(conn, "POP3 done with bad status"); - result = status; /* use the already set error code */ - } - - /* Cleanup our per-request based variables */ - Curl_safefree(pop3->id); - Curl_safefree(pop3->custom); - - /* Clear the transfer mode for the next request */ - pop3->transfer = FTPTRANSFER_BODY; - - return result; -} - -/*********************************************************************** - * - * pop3_perform() - * - * This is the actual DO function for POP3. Get a message/listing according to - * the options previously setup. - */ -static CURLcode pop3_perform(struct connectdata *conn, bool *connected, - bool *dophase_done) -{ - /* This is POP3 and no proxy */ - CURLcode result = CURLE_OK; - struct POP3 *pop3 = conn->data->req.protop; - - DEBUGF(infof(conn->data, "DO phase starts\n")); - - if(conn->data->set.opt_no_body) { - /* Requested no body means no transfer */ - pop3->transfer = FTPTRANSFER_INFO; - } - - *dophase_done = FALSE; /* not done yet */ - - /* Start the first command in the DO phase */ - result = pop3_perform_command(conn); - if(result) - return result; - - /* Run the state-machine */ - result = pop3_multi_statemach(conn, dophase_done); - - *connected = conn->bits.tcpconnect[FIRSTSOCKET]; - - if(*dophase_done) - DEBUGF(infof(conn->data, "DO phase is complete\n")); - - return result; -} - -/*********************************************************************** - * - * pop3_do() - * - * This function is registered as 'curl_do' function. It decodes the path - * parts etc as a wrapper to the actual DO function (pop3_perform). - * - * The input argument is already checked for validity. - */ -static CURLcode pop3_do(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - - *done = FALSE; /* default to false */ - - /* Parse the URL path */ - result = pop3_parse_url_path(conn); - if(result) - return result; - - /* Parse the custom request */ - result = pop3_parse_custom_request(conn); - if(result) - return result; - - result = pop3_regular_transfer(conn, done); - - return result; -} - -/*********************************************************************** - * - * pop3_disconnect() - * - * Disconnect from an POP3 server. Cleanup protocol-specific per-connection - * resources. BLOCKING. - */ -static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) -{ - struct pop3_conn *pop3c = &conn->proto.pop3c; - - /* We cannot send quit unconditionally. If this connection is stale or - bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. */ - - /* The POP3 session may or may not have been allocated/setup at this - point! */ - if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart) - if(!pop3_perform_quit(conn)) - (void)pop3_block_statemach(conn); /* ignore errors on QUIT */ - - /* Disconnect from the server */ - Curl_pp_disconnect(&pop3c->pp); - - /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, pop3c->sasl.authused); - - /* Cleanup our connection based variables */ - Curl_safefree(pop3c->apoptimestamp); - - return CURLE_OK; -} - -/* Call this when the DO phase has completed */ -static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) -{ - (void)conn; - (void)connected; - - return CURLE_OK; -} - -/* Called from multi.c while DOing */ -static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done) -{ - CURLcode result = pop3_multi_statemach(conn, dophase_done); - - if(result) - DEBUGF(infof(conn->data, "DO phase failed\n")); - else if(*dophase_done) { - result = pop3_dophase_done(conn, FALSE /* not connected */); - - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - - return result; -} - -/*********************************************************************** - * - * pop3_regular_transfer() - * - * The input argument is already checked for validity. - * - * Performs all commands done before a regular transfer between a local and a - * remote host. - */ -static CURLcode pop3_regular_transfer(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - bool connected = FALSE; - struct Curl_easy *data = conn->data; - - /* Make sure size is unknown at this point */ - data->req.size = -1; - - /* Set the progress data */ - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, -1); - Curl_pgrsSetDownloadSize(data, -1); - - /* Carry out the perform */ - result = pop3_perform(conn, &connected, dophase_done); - - /* Perform post DO phase operations if necessary */ - if(!result && *dophase_done) - result = pop3_dophase_done(conn, connected); - - return result; -} - -static CURLcode pop3_setup_connection(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - - /* Initialise the POP3 layer */ - CURLcode result = pop3_init(conn); - if(result) - return result; - - /* Clear the TLS upgraded flag */ - conn->tls_upgraded = FALSE; - data->state.path++; /* don't include the initial slash */ - - return CURLE_OK; -} - -/*********************************************************************** - * - * pop3_parse_url_options() - * - * Parse the URL login options. - */ -static CURLcode pop3_parse_url_options(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *ptr = conn->options; - - pop3c->sasl.resetprefs = TRUE; - - while(!result && ptr && *ptr) { - const char *key = ptr; - const char *value; - - while(*ptr && *ptr != '=') - ptr++; - - value = ptr + 1; - - while(*ptr && *ptr != ';') - ptr++; - - if(strncasecompare(key, "AUTH=", 5)) { - result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, - value, ptr - value); - - if(result && strncasecompare(value, "+APOP", ptr - value)) { - pop3c->preftype = POP3_TYPE_APOP; - pop3c->sasl.prefmech = SASL_AUTH_NONE; - result = CURLE_OK; - } - } - else - result = CURLE_URL_MALFORMAT; - - if(*ptr == ';') - ptr++; - } - - if(pop3c->preftype != POP3_TYPE_APOP) - switch(pop3c->sasl.prefmech) { - case SASL_AUTH_NONE: - pop3c->preftype = POP3_TYPE_NONE; - break; - case SASL_AUTH_DEFAULT: - pop3c->preftype = POP3_TYPE_ANY; - break; - default: - pop3c->preftype = POP3_TYPE_SASL; - break; - } - - return result; -} - -/*********************************************************************** - * - * pop3_parse_url_path() - * - * Parse the URL path into separate path components. - */ -static CURLcode pop3_parse_url_path(struct connectdata *conn) -{ - /* The POP3 struct is already initialised in pop3_connect() */ - struct Curl_easy *data = conn->data; - struct POP3 *pop3 = data->req.protop; - const char *path = data->state.path; - - /* URL decode the path for the message ID */ - return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE); -} - -/*********************************************************************** - * - * pop3_parse_custom_request() - * - * Parse the custom request. - */ -static CURLcode pop3_parse_custom_request(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct POP3 *pop3 = data->req.protop; - const char *custom = data->set.str[STRING_CUSTOMREQUEST]; - - /* URL decode the custom request */ - if(custom) - result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE); - - return result; -} - -/*********************************************************************** - * - * Curl_pop3_write() - * - * This function scans the body after the end-of-body and writes everything - * until the end is found. - */ -CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) -{ - /* This code could be made into a special function in the handler struct */ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SingleRequest *k = &data->req; - - struct pop3_conn *pop3c = &conn->proto.pop3c; - bool strip_dot = FALSE; - size_t last = 0; - size_t i; - - /* Search through the buffer looking for the end-of-body marker which is - 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches - the eob so the server will have prefixed it with an extra dot which we - need to strip out. Additionally the marker could of course be spread out - over 5 different data chunks. */ - for(i = 0; i < nread; i++) { - size_t prev = pop3c->eob; - - switch(str[i]) { - case 0x0d: - if(pop3c->eob == 0) { - pop3c->eob++; - - if(i) { - /* Write out the body part that didn't match */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], - i - last); - - if(result) - return result; - - last = i; - } - } - else if(pop3c->eob == 3) - pop3c->eob++; - else - /* If the character match wasn't at position 0 or 3 then restart the - pattern matching */ - pop3c->eob = 1; - break; - - case 0x0a: - if(pop3c->eob == 1 || pop3c->eob == 4) - pop3c->eob++; - else - /* If the character match wasn't at position 1 or 4 then start the - search again */ - pop3c->eob = 0; - break; - - case 0x2e: - if(pop3c->eob == 2) - pop3c->eob++; - else if(pop3c->eob == 3) { - /* We have an extra dot after the CRLF which we need to strip off */ - strip_dot = TRUE; - pop3c->eob = 0; - } - else - /* If the character match wasn't at position 2 then start the search - again */ - pop3c->eob = 0; - break; - - default: - pop3c->eob = 0; - break; - } - - /* Did we have a partial match which has subsequently failed? */ - if(prev && prev >= pop3c->eob) { - /* Strip can only be non-zero for the very first mismatch after CRLF - and then both prev and strip are equal and nothing will be output - below */ - while(prev && pop3c->strip) { - prev--; - pop3c->strip--; - } - - if(prev) { - /* If the partial match was the CRLF and dot then only write the CRLF - as the server would have inserted the dot */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, - strip_dot ? prev - 1 : prev); - - if(result) - return result; - - last = i; - strip_dot = FALSE; - } - } - } - - if(pop3c->eob == POP3_EOB_LEN) { - /* We have a full match so the transfer is done, however we must transfer - the CRLF at the start of the EOB as this is considered to be part of the - message as per RFC-1939, sect. 3 */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2); - - k->keepon &= ~KEEP_RECV; - pop3c->eob = 0; - - return result; - } - - if(pop3c->eob) - /* While EOB is matching nothing should be output */ - return CURLE_OK; - - if(nread - last) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], - nread - last); - } - - return result; -} - -#endif /* CURL_DISABLE_POP3 */ diff --git a/dep/cpr/opt/curl/lib/pop3.h b/dep/cpr/opt/curl/lib/pop3.h deleted file mode 100644 index a8e697cde2b..00000000000 --- a/dep/cpr/opt/curl/lib/pop3.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef HEADER_CURL_POP3_H -#define HEADER_CURL_POP3_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2009 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "pingpong.h" -#include "curl_sasl.h" - -/**************************************************************************** - * POP3 unique setup - ***************************************************************************/ -typedef enum { - POP3_STOP, /* do nothing state, stops the state machine */ - POP3_SERVERGREET, /* waiting for the initial greeting immediately after - a connect */ - POP3_CAPA, - POP3_STARTTLS, - POP3_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS - (multi mode only) */ - POP3_AUTH, - POP3_APOP, - POP3_USER, - POP3_PASS, - POP3_COMMAND, - POP3_QUIT, - POP3_LAST /* never used */ -} pop3state; - -/* This POP3 struct is used in the Curl_easy. All POP3 data that is - connection-oriented must be in pop3_conn to properly deal with the fact that - perhaps the Curl_easy is changed between the times the connection is - used. */ -struct POP3 { - curl_pp_transfer transfer; - char *id; /* Message ID */ - char *custom; /* Custom Request */ -}; - -/* pop3_conn is used for struct connection-oriented data in the connectdata - struct */ -struct pop3_conn { - struct pingpong pp; - pop3state state; /* Always use pop3.c:state() to change state! */ - bool ssldone; /* Is connect() over SSL done? */ - size_t eob; /* Number of bytes of the EOB (End Of Body) that - have been received so far */ - size_t strip; /* Number of bytes from the start to ignore as - non-body */ - struct SASL sasl; /* SASL-related storage */ - unsigned int authtypes; /* Accepted authentication types */ - unsigned int preftype; /* Preferred authentication type */ - char *apoptimestamp; /* APOP timestamp from the server greeting */ - bool tls_supported; /* StartTLS capability supported by server */ -}; - -extern const struct Curl_handler Curl_handler_pop3; -extern const struct Curl_handler Curl_handler_pop3s; - -/* Authentication type flags */ -#define POP3_TYPE_CLEARTEXT (1 << 0) -#define POP3_TYPE_APOP (1 << 1) -#define POP3_TYPE_SASL (1 << 2) - -/* Authentication type values */ -#define POP3_TYPE_NONE 0 -#define POP3_TYPE_ANY ~0U - -/* This is the 5-bytes End-Of-Body marker for POP3 */ -#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" -#define POP3_EOB_LEN 5 - -/* This function scans the body after the end-of-body and writes everything - * until the end is found */ -CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread); - -#endif /* HEADER_CURL_POP3_H */ diff --git a/dep/cpr/opt/curl/lib/progress.c b/dep/cpr/opt/curl/lib/progress.c deleted file mode 100644 index 00609d9ee6b..00000000000 --- a/dep/cpr/opt/curl/lib/progress.c +++ /dev/null @@ -1,577 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "urldata.h" -#include "sendf.h" -#include "progress.h" -#include "curl_printf.h" - -/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero - byte) */ -static void time2str(char *r, curl_off_t seconds) -{ - curl_off_t d, h, m, s; - if(seconds <= 0) { - strcpy(r, "--:--:--"); - return; - } - h = seconds / CURL_OFF_T_C(3600); - if(h <= CURL_OFF_T_C(99)) { - m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); - s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); - snprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T - ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); - } - else { - /* this equals to more than 99 hours, switch to a more suitable output - format to fit within the limits. */ - d = seconds / CURL_OFF_T_C(86400); - h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); - if(d <= CURL_OFF_T_C(999)) - snprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T - "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); - else - snprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); - } -} - -/* The point of this function would be to return a string of the input data, - but never longer than 5 columns (+ one zero byte). - Add suffix k, M, G when suitable... */ -static char *max5data(curl_off_t bytes, char *max5) -{ -#define ONE_KILOBYTE CURL_OFF_T_C(1024) -#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE) -#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE) -#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE) -#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) - - if(bytes < CURL_OFF_T_C(100000)) - snprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); - - else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); - - else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) - /* 'XX.XM' is good as long as we're less than 100 megs */ - snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" - CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, - (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); - -#if (CURL_SIZEOF_CURL_OFF_T > 4) - - else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) - /* 'XXXXM' is good until we're at 10000MB or above */ - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); - - else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) - /* 10000 MB - 100 GB, we show it as XX.XG */ - snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" - CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, - (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); - - else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) - /* up to 10000GB, display without decimal: XXXXG */ - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); - - else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) - /* up to 10000TB, display without decimal: XXXXT */ - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); - - else - /* up to 10000PB, display without decimal: XXXXP */ - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); - - /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number - can hold, but our data type is signed so 8192PB will be the maximum. */ - -#else - - else - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); - -#endif - - return max5; -} - -/* - - New proposed interface, 9th of February 2000: - - pgrsStartNow() - sets start time - pgrsSetDownloadSize(x) - known expected download size - pgrsSetUploadSize(x) - known expected upload size - pgrsSetDownloadCounter() - amount of data currently downloaded - pgrsSetUploadCounter() - amount of data currently uploaded - pgrsUpdate() - show progress - pgrsDone() - transfer complete - -*/ - -int Curl_pgrsDone(struct connectdata *conn) -{ - int rc; - struct Curl_easy *data = conn->data; - data->progress.lastshow = 0; - rc = Curl_pgrsUpdate(conn); /* the final (forced) update */ - if(rc) - return rc; - - if(!(data->progress.flags & PGRS_HIDE) && - !data->progress.callback) - /* only output if we don't use a progress callback and we're not - * hidden */ - fprintf(data->set.err, "\n"); - - data->progress.speeder_c = 0; /* reset the progress meter display */ - return 0; -} - -/* reset the known transfer sizes */ -void Curl_pgrsResetTransferSizes(struct Curl_easy *data) -{ - Curl_pgrsSetDownloadSize(data, -1); - Curl_pgrsSetUploadSize(data, -1); -} - -/* - * @unittest: 1399 - */ -void Curl_pgrsTime(struct Curl_easy *data, timerid timer) -{ - struct curltime now = Curl_tvnow(); - time_t *delta = NULL; - - switch(timer) { - default: - case TIMER_NONE: - /* mistake filter */ - break; - case TIMER_STARTOP: - /* This is set at the start of a transfer */ - data->progress.t_startop = now; - break; - case TIMER_STARTSINGLE: - /* This is set at the start of each single fetch */ - data->progress.t_startsingle = now; - data->progress.is_t_startransfer_set = false; - break; - case TIMER_STARTACCEPT: - data->progress.t_acceptdata = now; - break; - case TIMER_NAMELOOKUP: - delta = &data->progress.t_nslookup; - break; - case TIMER_CONNECT: - delta = &data->progress.t_connect; - break; - case TIMER_APPCONNECT: - delta = &data->progress.t_appconnect; - break; - case TIMER_PRETRANSFER: - delta = &data->progress.t_pretransfer; - break; - case TIMER_STARTTRANSFER: - delta = &data->progress.t_starttransfer; - /* prevent updating t_starttransfer unless: - * 1) this is the first time we're setting t_starttransfer - * 2) a redirect has occurred since the last time t_starttransfer was set - * This prevents repeated invocations of the function from incorrectly - * changing the t_starttransfer time. - */ - if(data->progress.is_t_startransfer_set) { - return; - } - else { - data->progress.is_t_startransfer_set = true; - break; - } - case TIMER_POSTRANSFER: - /* this is the normal end-of-transfer thing */ - break; - case TIMER_REDIRECT: - data->progress.t_redirect = Curl_tvdiff_us(now, data->progress.start); - break; - } - if(delta) { - time_t us = Curl_tvdiff_us(now, data->progress.t_startsingle); - if(!us) - us++; /* make sure at least one microsecond passed */ - *delta += us; - } -} - -void Curl_pgrsStartNow(struct Curl_easy *data) -{ - data->progress.speeder_c = 0; /* reset the progress meter display */ - data->progress.start = Curl_tvnow(); - data->progress.is_t_startransfer_set = false; - data->progress.ul_limit_start.tv_sec = 0; - data->progress.ul_limit_start.tv_usec = 0; - data->progress.dl_limit_start.tv_sec = 0; - data->progress.dl_limit_start.tv_usec = 0; - /* clear all bits except HIDE and HEADERS_OUT */ - data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; -} - -/* - * This is used to handle speed limits, calculating how much milliseconds we - * need to wait until we're back under the speed limit, if needed. - * - * The way it works is by having a "starting point" (time & amount of data - * transferred by then) used in the speed computation, to be used instead of - * the start of the transfer. This starting point is regularly moved as - * transfer goes on, to keep getting accurate values (instead of average over - * the entire transfer). - * - * This function takes the current amount of data transferred, the amount at - * the starting point, the limit (in bytes/s), the time of the starting point - * and the current time. - * - * Returns -1 if no waiting is needed (not enough data transferred since - * starting point yet), 0 when no waiting is needed but the starting point - * should be reset (to current), or the number of milliseconds to wait to get - * back under the speed limit. - */ -long Curl_pgrsLimitWaitTime(curl_off_t cursize, - curl_off_t startsize, - curl_off_t limit, - struct curltime start, - struct curltime now) -{ - curl_off_t size = cursize - startsize; - time_t minimum; - time_t actual; - - /* we don't have a starting point yet -- return 0 so it gets (re)set */ - if(start.tv_sec == 0 && start.tv_usec == 0) - return 0; - - /* not enough data yet */ - if(size < limit) - return -1; - - minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit); - actual = Curl_tvdiff(now, start); - - if(actual < minimum) - /* this is a conversion on some systems (64bit time_t => 32bit long) */ - return (long)(minimum - actual); - - return 0; -} - -void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) -{ - struct curltime now = Curl_tvnow(); - - data->progress.downloaded = size; - - /* download speed limit */ - if((data->set.max_recv_speed > 0) && - (Curl_pgrsLimitWaitTime(data->progress.downloaded, - data->progress.dl_limit_size, - data->set.max_recv_speed, - data->progress.dl_limit_start, - now) == 0)) { - data->progress.dl_limit_start = now; - data->progress.dl_limit_size = size; - } -} - -void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size) -{ - struct curltime now = Curl_tvnow(); - - data->progress.uploaded = size; - - /* upload speed limit */ - if((data->set.max_send_speed > 0) && - (Curl_pgrsLimitWaitTime(data->progress.uploaded, - data->progress.ul_limit_size, - data->set.max_send_speed, - data->progress.ul_limit_start, - now) == 0)) { - data->progress.ul_limit_start = now; - data->progress.ul_limit_size = size; - } -} - -void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size) -{ - if(size >= 0) { - data->progress.size_dl = size; - data->progress.flags |= PGRS_DL_SIZE_KNOWN; - } - else { - data->progress.size_dl = 0; - data->progress.flags &= ~PGRS_DL_SIZE_KNOWN; - } -} - -void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size) -{ - if(size >= 0) { - data->progress.size_ul = size; - data->progress.flags |= PGRS_UL_SIZE_KNOWN; - } - else { - data->progress.size_ul = 0; - data->progress.flags &= ~PGRS_UL_SIZE_KNOWN; - } -} - -/* - * Curl_pgrsUpdate() returns 0 for success or the value returned by the - * progress callback! - */ -int Curl_pgrsUpdate(struct connectdata *conn) -{ - struct curltime now; - int result; - char max5[6][10]; - curl_off_t dlpercen = 0; - curl_off_t ulpercen = 0; - curl_off_t total_percen = 0; - curl_off_t total_transfer; - curl_off_t total_expected_transfer; - curl_off_t timespent; - struct Curl_easy *data = conn->data; - int nowindex = data->progress.speeder_c% CURR_TIME; - int checkindex; - int countindex; /* amount of seconds stored in the speeder array */ - char time_left[10]; - char time_total[10]; - char time_spent[10]; - curl_off_t ulestimate = 0; - curl_off_t dlestimate = 0; - curl_off_t total_estimate; - bool shownow = FALSE; - - now = Curl_tvnow(); /* what time is it */ - - /* The time spent so far (from the start) */ - data->progress.timespent = Curl_tvdiff_us(now, data->progress.start); - timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */ - - /* The average download speed this far */ - data->progress.dlspeed = (curl_off_t) - (data->progress.downloaded/ - (timespent>0?timespent:1)); - - /* The average upload speed this far */ - data->progress.ulspeed = (curl_off_t) - (data->progress.uploaded/ - (timespent>0?timespent:1)); - - /* Calculations done at most once a second, unless end is reached */ - if(data->progress.lastshow != now.tv_sec) { - shownow = TRUE; - - data->progress.lastshow = now.tv_sec; - - /* Let's do the "current speed" thing, with the dl + ul speeds - combined. Store the speed at entry 'nowindex'. */ - data->progress.speeder[ nowindex ] = - data->progress.downloaded + data->progress.uploaded; - - /* remember the exact time for this moment */ - data->progress.speeder_time [ nowindex ] = now; - - /* advance our speeder_c counter, which is increased every time we get - here and we expect it to never wrap as 2^32 is a lot of seconds! */ - data->progress.speeder_c++; - - /* figure out how many index entries of data we have stored in our speeder - array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of - transfer. Imagine, after one second we have filled in two entries, - after two seconds we've filled in three entries etc. */ - countindex = ((data->progress.speeder_c >= CURR_TIME)? - CURR_TIME:data->progress.speeder_c) - 1; - - /* first of all, we don't do this if there's no counted seconds yet */ - if(countindex) { - time_t span_ms; - - /* Get the index position to compare with the 'nowindex' position. - Get the oldest entry possible. While we have less than CURR_TIME - entries, the first entry will remain the oldest. */ - checkindex = (data->progress.speeder_c >= CURR_TIME)? - data->progress.speeder_c%CURR_TIME:0; - - /* Figure out the exact time for the time span */ - span_ms = Curl_tvdiff(now, - data->progress.speeder_time[checkindex]); - if(0 == span_ms) - span_ms = 1; /* at least one millisecond MUST have passed */ - - /* Calculate the average speed the last 'span_ms' milliseconds */ - { - curl_off_t amount = data->progress.speeder[nowindex]- - data->progress.speeder[checkindex]; - - if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */) - /* the 'amount' value is bigger than would fit in 32 bits if - multiplied with 1000, so we use the double math for this */ - data->progress.current_speed = (curl_off_t) - ((double)amount/((double)span_ms/1000.0)); - else - /* the 'amount' value is small enough to fit within 32 bits even - when multiplied with 1000 */ - data->progress.current_speed = amount*CURL_OFF_T_C(1000)/span_ms; - } - } - else - /* the first second we use the average */ - data->progress.current_speed = - data->progress.ulspeed + data->progress.dlspeed; - - } /* Calculations end */ - - if(!(data->progress.flags & PGRS_HIDE)) { - /* progress meter has not been shut off */ - - if(data->set.fxferinfo) { - /* There's a callback set, call that */ - result = data->set.fxferinfo(data->set.progress_client, - data->progress.size_dl, - data->progress.downloaded, - data->progress.size_ul, - data->progress.uploaded); - if(result) - failf(data, "Callback aborted"); - return result; - } - if(data->set.fprogress) { - /* The older deprecated callback is set, call that */ - result = data->set.fprogress(data->set.progress_client, - (double)data->progress.size_dl, - (double)data->progress.downloaded, - (double)data->progress.size_ul, - (double)data->progress.uploaded); - if(result) - failf(data, "Callback aborted"); - return result; - } - - if(!shownow) - /* only show the internal progress meter once per second */ - return 0; - - /* If there's no external callback set, use internal code to show - progress */ - - if(!(data->progress.flags & PGRS_HEADERS_OUT)) { - if(data->state.resume_from) { - fprintf(data->set.err, - "** Resuming transfer from byte position %" - CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from); - } - fprintf(data->set.err, - " %% Total %% Received %% Xferd Average Speed " - "Time Time Time Current\n" - " Dload Upload " - "Total Spent Left Speed\n"); - data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */ - } - - /* Figure out the estimated time of arrival for the upload */ - if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && - (data->progress.ulspeed > CURL_OFF_T_C(0))) { - ulestimate = data->progress.size_ul / data->progress.ulspeed; - - if(data->progress.size_ul > CURL_OFF_T_C(10000)) - ulpercen = data->progress.uploaded / - (data->progress.size_ul/CURL_OFF_T_C(100)); - else if(data->progress.size_ul > CURL_OFF_T_C(0)) - ulpercen = (data->progress.uploaded*100) / - data->progress.size_ul; - } - - /* ... and the download */ - if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && - (data->progress.dlspeed > CURL_OFF_T_C(0))) { - dlestimate = data->progress.size_dl / data->progress.dlspeed; - - if(data->progress.size_dl > CURL_OFF_T_C(10000)) - dlpercen = data->progress.downloaded / - (data->progress.size_dl/CURL_OFF_T_C(100)); - else if(data->progress.size_dl > CURL_OFF_T_C(0)) - dlpercen = (data->progress.downloaded*100) / - data->progress.size_dl; - } - - /* Now figure out which of them is slower and use that one for the - total estimate! */ - total_estimate = ulestimate>dlestimate?ulestimate:dlestimate; - - /* create the three time strings */ - time2str(time_left, total_estimate > 0?(total_estimate - timespent):0); - time2str(time_total, total_estimate); - time2str(time_spent, timespent); - - /* Get the total amount of data expected to get transferred */ - total_expected_transfer = - (data->progress.flags & PGRS_UL_SIZE_KNOWN? - data->progress.size_ul:data->progress.uploaded)+ - (data->progress.flags & PGRS_DL_SIZE_KNOWN? - data->progress.size_dl:data->progress.downloaded); - - /* We have transferred this much so far */ - total_transfer = data->progress.downloaded + data->progress.uploaded; - - /* Get the percentage of data transferred so far */ - if(total_expected_transfer > CURL_OFF_T_C(10000)) - total_percen = total_transfer / - (total_expected_transfer/CURL_OFF_T_C(100)); - else if(total_expected_transfer > CURL_OFF_T_C(0)) - total_percen = (total_transfer*100) / total_expected_transfer; - - fprintf(data->set.err, - "\r" - "%3" CURL_FORMAT_CURL_OFF_T " %s " - "%3" CURL_FORMAT_CURL_OFF_T " %s " - "%3" CURL_FORMAT_CURL_OFF_T " %s %s %s %s %s %s %s", - total_percen, /* 3 letters */ /* total % */ - max5data(total_expected_transfer, max5[2]), /* total size */ - dlpercen, /* 3 letters */ /* rcvd % */ - max5data(data->progress.downloaded, max5[0]), /* rcvd size */ - ulpercen, /* 3 letters */ /* xfer % */ - max5data(data->progress.uploaded, max5[1]), /* xfer size */ - max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */ - max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */ - time_total, /* 8 letters */ /* total time */ - time_spent, /* 8 letters */ /* time spent */ - time_left, /* 8 letters */ /* time left */ - max5data(data->progress.current_speed, max5[5]) /* current speed */ - ); - - /* we flush the output stream to make it appear as soon as possible */ - fflush(data->set.err); - - } /* !(data->progress.flags & PGRS_HIDE) */ - - return 0; -} diff --git a/dep/cpr/opt/curl/lib/progress.h b/dep/cpr/opt/curl/lib/progress.h deleted file mode 100644 index 9333ab25c27..00000000000 --- a/dep/cpr/opt/curl/lib/progress.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef HEADER_CURL_PROGRESS_H -#define HEADER_CURL_PROGRESS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "timeval.h" - - -typedef enum { - TIMER_NONE, - TIMER_STARTOP, - TIMER_STARTSINGLE, - TIMER_NAMELOOKUP, - TIMER_CONNECT, - TIMER_APPCONNECT, - TIMER_PRETRANSFER, - TIMER_STARTTRANSFER, - TIMER_POSTRANSFER, - TIMER_STARTACCEPT, - TIMER_REDIRECT, - TIMER_LAST /* must be last */ -} timerid; - -int Curl_pgrsDone(struct connectdata *); -void Curl_pgrsStartNow(struct Curl_easy *data); -void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size); -void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size); -void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); -void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); -int Curl_pgrsUpdate(struct connectdata *); -void Curl_pgrsResetTransferSizes(struct Curl_easy *data); -void Curl_pgrsTime(struct Curl_easy *data, timerid timer); -long Curl_pgrsLimitWaitTime(curl_off_t cursize, - curl_off_t startsize, - curl_off_t limit, - struct curltime start, - struct curltime now); - -/* Don't show progress for sizes smaller than: */ -#define LEAST_SIZE_PROGRESS BUFSIZE - -#define PROGRESS_DOWNLOAD (1<<0) -#define PROGRESS_UPLOAD (1<<1) -#define PROGRESS_DOWN_AND_UP (PROGRESS_UPLOAD | PROGRESS_DOWNLOAD) - -#define PGRS_SHOW_DL (1<<0) -#define PGRS_SHOW_UL (1<<1) -#define PGRS_DONE_DL (1<<2) -#define PGRS_DONE_UL (1<<3) -#define PGRS_HIDE (1<<4) -#define PGRS_UL_SIZE_KNOWN (1<<5) -#define PGRS_DL_SIZE_KNOWN (1<<6) - -#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */ - - -#endif /* HEADER_CURL_PROGRESS_H */ - diff --git a/dep/cpr/opt/curl/lib/rand.c b/dep/cpr/opt/curl/lib/rand.c deleted file mode 100644 index 2713a0aa3e5..00000000000 --- a/dep/cpr/opt/curl/lib/rand.c +++ /dev/null @@ -1,179 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_FCNTL_H -#include -#endif - -#include -#include "vtls/vtls.h" -#include "sendf.h" -#include "rand.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) -{ - unsigned int r; - CURLcode result = CURLE_OK; - static unsigned int randseed; - static bool seeded = FALSE; - -#ifdef CURLDEBUG - char *force_entropy = getenv("CURL_ENTROPY"); - if(force_entropy) { - if(!seeded) { - unsigned int seed = 0; - size_t elen = strlen(force_entropy); - size_t clen = sizeof(seed); - size_t min = elen < clen ? elen : clen; - memcpy((char *)&seed, force_entropy, min); - randseed = ntohl(seed); - seeded = TRUE; - } - else - randseed++; - *rnd = randseed; - return CURLE_OK; - } -#endif - - /* data may be NULL! */ - result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd)); - if(result != CURLE_NOT_BUILT_IN) - /* only if there is no random function in the TLS backend do the non crypto - version, otherwise return result */ - return result; - - /* ---- non-cryptographic version following ---- */ - -#ifdef RANDOM_FILE - if(!seeded) { - /* if there's a random file to read a seed from, use it */ - int fd = open(RANDOM_FILE, O_RDONLY); - if(fd > -1) { - /* read random data into the randseed variable */ - ssize_t nread = read(fd, &randseed, sizeof(randseed)); - if(nread == sizeof(randseed)) - seeded = TRUE; - close(fd); - } - } -#endif - - if(!seeded) { - struct curltime now = curlx_tvnow(); - infof(data, "WARNING: Using weak random seed\n"); - randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; - randseed = randseed * 1103515245 + 12345; - randseed = randseed * 1103515245 + 12345; - randseed = randseed * 1103515245 + 12345; - seeded = TRUE; - } - - /* Return an unsigned 32-bit pseudo-random number. */ - r = randseed = randseed * 1103515245 + 12345; - *rnd = (r << 16) | ((r >> 16) & 0xFFFF); - return CURLE_OK; -} - -/* - * Curl_rand() stores 'num' number of random unsigned integers in the buffer - * 'rndptr' points to. - * - * If libcurl is built without TLS support or with a TLS backend that lacks a - * proper random API (Gskit, PolarSSL or mbedTLS), this function will use - * "weak" random. - * - * When built *with* TLS support and a backend that offers strong random, it - * will return error if it cannot provide strong random values. - * - * NOTE: 'data' may be passed in as NULL when coming from external API without - * easy handle! - * - */ - -CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num) -{ - CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; - - DEBUGASSERT(num > 0); - - while(num) { - unsigned int r; - size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int); - - result = randit(data, &r); - if(result) - return result; - - while(left) { - *rnd++ = (unsigned char)(r & 0xFF); - r >>= 8; - --num; - --left; - } - } - - return result; -} - -/* - * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random - * hexadecimal digits PLUS a zero terminating byte. It must be an odd number - * size. - */ - -CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, - size_t num) -{ - CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; - const char *hex = "0123456789abcdef"; - unsigned char buffer[128]; - unsigned char *bufp = buffer; - DEBUGASSERT(num > 1); - - if((num/2 >= sizeof(buffer)) || !(num&1)) - /* make sure it fits in the local buffer and that it is an odd number! */ - return CURLE_BAD_FUNCTION_ARGUMENT; - - num--; /* save one for zero termination */ - - result = Curl_rand(data, buffer, num/2); - if(result) - return result; - - while(num) { - *rnd++ = hex[(*bufp & 0xF0)>>4]; - *rnd++ = hex[*bufp & 0x0F]; - bufp++; - num -= 2; - } - *rnd = 0; - - return result; -} diff --git a/dep/cpr/opt/curl/lib/rand.h b/dep/cpr/opt/curl/lib/rand.h deleted file mode 100644 index c6fae35537c..00000000000 --- a/dep/cpr/opt/curl/lib/rand.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef HEADER_CURL_RAND_H -#define HEADER_CURL_RAND_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Curl_rand() stores 'num' number of random unsigned characters in the buffer - * 'rnd' points to. - * - * If libcurl is built without TLS support or with a TLS backend that lacks a - * proper random API (Gskit, PolarSSL or mbedTLS), this function will use - * "weak" random. - * - * When built *with* TLS support and a backend that offers strong random, it - * will return error if it cannot provide strong random values. - * - * NOTE: 'data' may be passed in as NULL when coming from external API without - * easy handle! - * - */ -CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num); - -/* Same as above but outputs only random lowercase hex characters. - Does NOT terminate.*/ -CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, - size_t num); - -#endif /* HEADER_CURL_RAND_H */ diff --git a/dep/cpr/opt/curl/lib/rtsp.c b/dep/cpr/opt/curl/lib/rtsp.c deleted file mode 100644 index 925da2c1a9b..00000000000 --- a/dep/cpr/opt/curl/lib/rtsp.c +++ /dev/null @@ -1,850 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_RTSP - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "multiif.h" -#include "http.h" -#include "url.h" -#include "progress.h" -#include "rtsp.h" -#include "strcase.h" -#include "select.h" -#include "connect.h" -#include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* - * TODO (general) - * -incoming server requests - * -server CSeq counter - * -digest authentication - * -connect thru proxy - * -pipelining? - */ - - -#define RTP_PKT_CHANNEL(p) ((int)((unsigned char)((p)[1]))) - -#define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \ - ((int)((unsigned char)((p)[3])))) - -/* protocol-specific functions set up to be called by the main engine */ -static CURLcode rtsp_do(struct connectdata *conn, bool *done); -static CURLcode rtsp_done(struct connectdata *conn, CURLcode, bool premature); -static CURLcode rtsp_connect(struct connectdata *conn, bool *done); -static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead); - -static int rtsp_getsock_do(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - -/* - * Parse and write out any available RTP data. - * - * nread: amount of data left after k->str. will be modified if RTP - * data is parsed and k->str is moved up - * readmore: whether or not the RTP parser needs more data right away - */ -static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, - struct connectdata *conn, - ssize_t *nread, - bool *readmore); - -static CURLcode rtsp_setup_connection(struct connectdata *conn); - -bool rtsp_connisdead(struct connectdata *check); -static unsigned int rtsp_conncheck(struct connectdata *check, - unsigned int checks_to_perform); - -/* this returns the socket to wait for in the DO and DOING state for the multi - interface and then we're always _sending_ a request and thus we wait for - the single socket to become writable only */ -static int rtsp_getsock_do(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - /* write mode */ - (void)numsocks; /* unused, we trust it to be at least 1 */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); -} - -static -CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len); - - -/* - * RTSP handler interface. - */ -const struct Curl_handler Curl_handler_rtsp = { - "RTSP", /* scheme */ - rtsp_setup_connection, /* setup_connection */ - rtsp_do, /* do_it */ - rtsp_done, /* done */ - ZERO_NULL, /* do_more */ - rtsp_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - rtsp_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - rtsp_disconnect, /* disconnect */ - rtsp_rtp_readwrite, /* readwrite */ - rtsp_conncheck, /* connection_check */ - PORT_RTSP, /* defport */ - CURLPROTO_RTSP, /* protocol */ - PROTOPT_NONE /* flags */ -}; - - -static CURLcode rtsp_setup_connection(struct connectdata *conn) -{ - struct RTSP *rtsp; - - conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP)); - if(!rtsp) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; -} - - -/* - * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not - * want to block the application forever while receiving a stream. Therefore, - * we cannot assume that an RTSP socket is dead just because it is readable. - * - * Instead, if it is readable, run Curl_connalive() to peek at the socket - * and distinguish between closed and data. - */ -bool rtsp_connisdead(struct connectdata *check) -{ - int sval; - bool ret_val = TRUE; - - sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0); - if(sval == 0) { - /* timeout */ - ret_val = FALSE; - } - else if(sval & CURL_CSELECT_ERR) { - /* socket is in an error state */ - ret_val = TRUE; - } - else if(sval & CURL_CSELECT_IN) { - /* readable with no error. could still be closed */ - ret_val = !Curl_connalive(check); - } - - return ret_val; -} - -/* - * Function to check on various aspects of a connection. - */ -static unsigned int rtsp_conncheck(struct connectdata *check, - unsigned int checks_to_perform) -{ - unsigned int ret_val = CONNRESULT_NONE; - - if(checks_to_perform & CONNCHECK_ISDEAD) { - if(rtsp_connisdead(check)) - ret_val |= CONNRESULT_DEAD; - } - - return ret_val; -} - - -static CURLcode rtsp_connect(struct connectdata *conn, bool *done) -{ - CURLcode httpStatus; - struct Curl_easy *data = conn->data; - - httpStatus = Curl_http_connect(conn, done); - - /* Initialize the CSeq if not already done */ - if(data->state.rtsp_next_client_CSeq == 0) - data->state.rtsp_next_client_CSeq = 1; - if(data->state.rtsp_next_server_CSeq == 0) - data->state.rtsp_next_server_CSeq = 1; - - conn->proto.rtspc.rtp_channel = -1; - - return httpStatus; -} - -static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead) -{ - (void) dead; - Curl_safefree(conn->proto.rtspc.rtp_buf); - return CURLE_OK; -} - - -static CURLcode rtsp_done(struct connectdata *conn, - CURLcode status, bool premature) -{ - struct Curl_easy *data = conn->data; - struct RTSP *rtsp = data->req.protop; - CURLcode httpStatus; - long CSeq_sent; - long CSeq_recv; - - /* Bypass HTTP empty-reply checks on receive */ - if(data->set.rtspreq == RTSPREQ_RECEIVE) - premature = TRUE; - - httpStatus = Curl_http_done(conn, status, premature); - - if(rtsp) { - /* Check the sequence numbers */ - CSeq_sent = rtsp->CSeq_sent; - CSeq_recv = rtsp->CSeq_recv; - if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) { - failf(data, - "The CSeq of this request %ld did not match the response %ld", - CSeq_sent, CSeq_recv); - return CURLE_RTSP_CSEQ_ERROR; - } - if(data->set.rtspreq == RTSPREQ_RECEIVE && - (conn->proto.rtspc.rtp_channel == -1)) { - infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv); - /* TODO CPC: Server -> Client logic here */ - } - } - - return httpStatus; -} - -static CURLcode rtsp_do(struct connectdata *conn, bool *done) -{ - struct Curl_easy *data = conn->data; - CURLcode result = CURLE_OK; - Curl_RtspReq rtspreq = data->set.rtspreq; - struct RTSP *rtsp = data->req.protop; - struct HTTP *http; - Curl_send_buffer *req_buffer; - curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */ - curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */ - - const char *p_request = NULL; - const char *p_session_id = NULL; - const char *p_accept = NULL; - const char *p_accept_encoding = NULL; - const char *p_range = NULL; - const char *p_referrer = NULL; - const char *p_stream_uri = NULL; - const char *p_transport = NULL; - const char *p_uagent = NULL; - const char *p_proxyuserpwd = NULL; - const char *p_userpwd = NULL; - - *done = TRUE; - - http = &(rtsp->http_wrapper); - /* Assert that no one has changed the RTSP struct in an evil way */ - DEBUGASSERT((void *)http == (void *)rtsp); - - rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq; - rtsp->CSeq_recv = 0; - - /* Setup the 'p_request' pointer to the proper p_request string - * Since all RTSP requests are included here, there is no need to - * support custom requests like HTTP. - **/ - data->set.opt_no_body = TRUE; /* most requests don't contain a body */ - switch(rtspreq) { - default: - failf(data, "Got invalid RTSP request"); - return CURLE_BAD_FUNCTION_ARGUMENT; - case RTSPREQ_OPTIONS: - p_request = "OPTIONS"; - break; - case RTSPREQ_DESCRIBE: - p_request = "DESCRIBE"; - data->set.opt_no_body = FALSE; - break; - case RTSPREQ_ANNOUNCE: - p_request = "ANNOUNCE"; - break; - case RTSPREQ_SETUP: - p_request = "SETUP"; - break; - case RTSPREQ_PLAY: - p_request = "PLAY"; - break; - case RTSPREQ_PAUSE: - p_request = "PAUSE"; - break; - case RTSPREQ_TEARDOWN: - p_request = "TEARDOWN"; - break; - case RTSPREQ_GET_PARAMETER: - /* GET_PARAMETER's no_body status is determined later */ - p_request = "GET_PARAMETER"; - data->set.opt_no_body = FALSE; - break; - case RTSPREQ_SET_PARAMETER: - p_request = "SET_PARAMETER"; - break; - case RTSPREQ_RECORD: - p_request = "RECORD"; - break; - case RTSPREQ_RECEIVE: - p_request = ""; - /* Treat interleaved RTP as body*/ - data->set.opt_no_body = FALSE; - break; - case RTSPREQ_LAST: - failf(data, "Got invalid RTSP request: RTSPREQ_LAST"); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - - if(rtspreq == RTSPREQ_RECEIVE) { - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, -1, NULL); - - return result; - } - - p_session_id = data->set.str[STRING_RTSP_SESSION_ID]; - if(!p_session_id && - (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) { - failf(data, "Refusing to issue an RTSP request [%s] without a session ID.", - p_request); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - - /* TODO: proxy? */ - - /* Stream URI. Default to server '*' if not specified */ - if(data->set.str[STRING_RTSP_STREAM_URI]) { - p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI]; - } - else { - p_stream_uri = "*"; - } - - /* Transport Header for SETUP requests */ - p_transport = Curl_checkheaders(conn, "Transport:"); - if(rtspreq == RTSPREQ_SETUP && !p_transport) { - /* New Transport: setting? */ - if(data->set.str[STRING_RTSP_TRANSPORT]) { - Curl_safefree(conn->allocptr.rtsp_transport); - - conn->allocptr.rtsp_transport = - aprintf("Transport: %s\r\n", - data->set.str[STRING_RTSP_TRANSPORT]); - if(!conn->allocptr.rtsp_transport) - return CURLE_OUT_OF_MEMORY; - } - else { - failf(data, - "Refusing to issue an RTSP SETUP without a Transport: header."); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - - p_transport = conn->allocptr.rtsp_transport; - } - - /* Accept Headers for DESCRIBE requests */ - if(rtspreq == RTSPREQ_DESCRIBE) { - /* Accept Header */ - p_accept = Curl_checkheaders(conn, "Accept:")? - NULL:"Accept: application/sdp\r\n"; - - /* Accept-Encoding header */ - if(!Curl_checkheaders(conn, "Accept-Encoding:") && - data->set.str[STRING_ENCODING]) { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = - aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); - - if(!conn->allocptr.accept_encoding) - return CURLE_OUT_OF_MEMORY; - - p_accept_encoding = conn->allocptr.accept_encoding; - } - } - - /* The User-Agent string might have been allocated in url.c already, because - it might have been used in the proxy connect, but if we have got a header - with the user-agent string specified, we erase the previously made string - here. */ - if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) { - Curl_safefree(conn->allocptr.uagent); - conn->allocptr.uagent = NULL; - } - else if(!Curl_checkheaders(conn, "User-Agent:") && - data->set.str[STRING_USERAGENT]) { - p_uagent = conn->allocptr.uagent; - } - - /* setup the authentication headers */ - result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE); - if(result) - return result; - - p_proxyuserpwd = conn->allocptr.proxyuserpwd; - p_userpwd = conn->allocptr.userpwd; - - /* Referrer */ - Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) - conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); - else - conn->allocptr.ref = NULL; - - p_referrer = conn->allocptr.ref; - - /* - * Range Header - * Only applies to PLAY, PAUSE, RECORD - * - * Go ahead and use the Range stuff supplied for HTTP - */ - if(data->state.use_range && - (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) { - - /* Check to see if there is a range set in the custom headers */ - if(!Curl_checkheaders(conn, "Range:") && data->state.range) { - Curl_safefree(conn->allocptr.rangeline); - conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range); - p_range = conn->allocptr.rangeline; - } - } - - /* - * Sanity check the custom headers - */ - if(Curl_checkheaders(conn, "CSeq:")) { - failf(data, "CSeq cannot be set as a custom header."); - return CURLE_RTSP_CSEQ_ERROR; - } - if(Curl_checkheaders(conn, "Session:")) { - failf(data, "Session ID cannot be set as a custom header."); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - - /* Initialize a dynamic send buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; - - result = - Curl_add_bufferf(req_buffer, - "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ - "CSeq: %ld\r\n", /* CSeq */ - p_request, p_stream_uri, rtsp->CSeq_sent); - if(result) - return result; - - /* - * Rather than do a normal alloc line, keep the session_id unformatted - * to make comparison easier - */ - if(p_session_id) { - result = Curl_add_bufferf(req_buffer, "Session: %s\r\n", p_session_id); - if(result) - return result; - } - - /* - * Shared HTTP-like options - */ - result = Curl_add_bufferf(req_buffer, - "%s" /* transport */ - "%s" /* accept */ - "%s" /* accept-encoding */ - "%s" /* range */ - "%s" /* referrer */ - "%s" /* user-agent */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - , - p_transport ? p_transport : "", - p_accept ? p_accept : "", - p_accept_encoding ? p_accept_encoding : "", - p_range ? p_range : "", - p_referrer ? p_referrer : "", - p_uagent ? p_uagent : "", - p_proxyuserpwd ? p_proxyuserpwd : "", - p_userpwd ? p_userpwd : ""); - - /* - * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM - * with basic and digest, it will be freed anyway by the next request - */ - Curl_safefree(conn->allocptr.userpwd); - conn->allocptr.userpwd = NULL; - - if(result) - return result; - - if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) { - result = Curl_add_timecondition(data, req_buffer); - if(result) - return result; - } - - result = Curl_add_custom_headers(conn, FALSE, req_buffer); - if(result) - return result; - - if(rtspreq == RTSPREQ_ANNOUNCE || - rtspreq == RTSPREQ_SET_PARAMETER || - rtspreq == RTSPREQ_GET_PARAMETER) { - - if(data->set.upload) { - putsize = data->state.infilesize; - data->set.httpreq = HTTPREQ_PUT; - - } - else { - postsize = (data->state.infilesize != -1)? - data->state.infilesize: - (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0); - data->set.httpreq = HTTPREQ_POST; - } - - if(putsize > 0 || postsize > 0) { - /* As stated in the http comments, it is probably not wise to - * actually set a custom Content-Length in the headers */ - if(!Curl_checkheaders(conn, "Content-Length:")) { - result = Curl_add_bufferf(req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", - (data->set.upload ? putsize : postsize)); - if(result) - return result; - } - - if(rtspreq == RTSPREQ_SET_PARAMETER || - rtspreq == RTSPREQ_GET_PARAMETER) { - if(!Curl_checkheaders(conn, "Content-Type:")) { - result = Curl_add_bufferf(req_buffer, - "Content-Type: text/parameters\r\n"); - if(result) - return result; - } - } - - if(rtspreq == RTSPREQ_ANNOUNCE) { - if(!Curl_checkheaders(conn, "Content-Type:")) { - result = Curl_add_bufferf(req_buffer, - "Content-Type: application/sdp\r\n"); - if(result) - return result; - } - } - - data->state.expect100header = FALSE; /* RTSP posts are simple/small */ - } - else if(rtspreq == RTSPREQ_GET_PARAMETER) { - /* Check for an empty GET_PARAMETER (heartbeat) request */ - data->set.httpreq = HTTPREQ_HEAD; - data->set.opt_no_body = TRUE; - } - } - - /* RTSP never allows chunked transfer */ - data->req.forbidchunk = TRUE; - /* Finish the request buffer */ - result = Curl_add_buffer(req_buffer, "\r\n", 2); - if(result) - return result; - - if(postsize > 0) { - result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); - if(result) - return result; - } - - /* issue the request */ - result = Curl_add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - if(result) { - failf(data, "Failed sending RTSP request"); - return result; - } - - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - putsize?FIRSTSOCKET:-1, - putsize?&http->writebytecount:NULL); - - /* Increment the CSeq on success */ - data->state.rtsp_next_client_CSeq++; - - if(http->writebytecount) { - /* if a request-body has been sent off, we make sure this progress is - noted properly */ - Curl_pgrsSetUploadCounter(data, http->writebytecount); - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - } - - return result; -} - - -static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, - struct connectdata *conn, - ssize_t *nread, - bool *readmore) { - struct SingleRequest *k = &data->req; - struct rtsp_conn *rtspc = &(conn->proto.rtspc); - - char *rtp; /* moving pointer to rtp data */ - ssize_t rtp_dataleft; /* how much data left to parse in this round */ - char *scratch; - CURLcode result; - - if(rtspc->rtp_buf) { - /* There was some leftover data the last time. Merge buffers */ - char *newptr = Curl_saferealloc(rtspc->rtp_buf, - rtspc->rtp_bufsize + *nread); - if(!newptr) { - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; - return CURLE_OUT_OF_MEMORY; - } - rtspc->rtp_buf = newptr; - memcpy(rtspc->rtp_buf + rtspc->rtp_bufsize, k->str, *nread); - rtspc->rtp_bufsize += *nread; - rtp = rtspc->rtp_buf; - rtp_dataleft = rtspc->rtp_bufsize; - } - else { - /* Just parse the request buffer directly */ - rtp = k->str; - rtp_dataleft = *nread; - } - - while((rtp_dataleft > 0) && - (rtp[0] == '$')) { - if(rtp_dataleft > 4) { - int rtp_length; - - /* Parse the header */ - /* The channel identifier immediately follows and is 1 byte */ - rtspc->rtp_channel = RTP_PKT_CHANNEL(rtp); - - /* The length is two bytes */ - rtp_length = RTP_PKT_LENGTH(rtp); - - if(rtp_dataleft < rtp_length + 4) { - /* Need more - incomplete payload*/ - *readmore = TRUE; - break; - } - /* We have the full RTP interleaved packet - * Write out the header including the leading '$' */ - DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n", - rtspc->rtp_channel, rtp_length)); - result = rtp_client_write(conn, &rtp[0], rtp_length + 4); - if(result) { - failf(data, "Got an error writing an RTP packet"); - *readmore = FALSE; - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; - return result; - } - - /* Move forward in the buffer */ - rtp_dataleft -= rtp_length + 4; - rtp += rtp_length + 4; - - if(data->set.rtspreq == RTSPREQ_RECEIVE) { - /* If we are in a passive receive, give control back - * to the app as often as we can. - */ - k->keepon &= ~KEEP_RECV; - } - } - else { - /* Need more - incomplete header */ - *readmore = TRUE; - break; - } - } - - if(rtp_dataleft != 0 && rtp[0] == '$') { - DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft, - *readmore ? "(READMORE)" : "")); - - /* Store the incomplete RTP packet for a "rewind" */ - scratch = malloc(rtp_dataleft); - if(!scratch) { - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; - return CURLE_OUT_OF_MEMORY; - } - memcpy(scratch, rtp, rtp_dataleft); - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = scratch; - rtspc->rtp_bufsize = rtp_dataleft; - - /* As far as the transfer is concerned, this data is consumed */ - *nread = 0; - return CURLE_OK; - } - /* Fix up k->str to point just after the last RTP packet */ - k->str += *nread - rtp_dataleft; - - /* either all of the data has been read or... - * rtp now points at the next byte to parse - */ - if(rtp_dataleft > 0) - DEBUGASSERT(k->str[0] == rtp[0]); - - DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */ - - *nread = rtp_dataleft; - - /* If we get here, we have finished with the leftover/merge buffer */ - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; - - return CURLE_OK; -} - -static -CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len) -{ - struct Curl_easy *data = conn->data; - size_t wrote; - curl_write_callback writeit; - void *user_ptr; - - if(len == 0) { - failf(data, "Cannot write a 0 size RTP packet."); - return CURLE_WRITE_ERROR; - } - - /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that - function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP - data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA - pointer to write out the RTP data. */ - if(data->set.fwrite_rtp) { - writeit = data->set.fwrite_rtp; - user_ptr = data->set.rtp_out; - } - else - { - writeit = data->set.fwrite_func; - user_ptr = data->set.out; - } - - wrote = writeit(ptr, 1, len, user_ptr); - - if(CURL_WRITEFUNC_PAUSE == wrote) { - failf(data, "Cannot pause RTP"); - return CURLE_WRITE_ERROR; - } - - if(wrote != len) { - failf(data, "Failed writing RTP data"); - return CURLE_WRITE_ERROR; - } - - return CURLE_OK; -} - -CURLcode Curl_rtsp_parseheader(struct connectdata *conn, - char *header) -{ - struct Curl_easy *data = conn->data; - long CSeq = 0; - - if(checkprefix("CSeq:", header)) { - /* Store the received CSeq. Match is verified in rtsp_done */ - int nc = sscanf(&header[4], ": %ld", &CSeq); - if(nc == 1) { - struct RTSP *rtsp = data->req.protop; - rtsp->CSeq_recv = CSeq; /* mark the request */ - data->state.rtsp_CSeq_recv = CSeq; /* update the handle */ - } - else { - failf(data, "Unable to read the CSeq header: [%s]", header); - return CURLE_RTSP_CSEQ_ERROR; - } - } - else if(checkprefix("Session:", header)) { - char *start; - - /* Find the first non-space letter */ - start = header + 8; - while(*start && ISSPACE(*start)) - start++; - - if(!*start) { - failf(data, "Got a blank Session ID"); - } - else if(data->set.str[STRING_RTSP_SESSION_ID]) { - /* If the Session ID is set, then compare */ - if(strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], - strlen(data->set.str[STRING_RTSP_SESSION_ID])) != 0) { - failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]", - start, data->set.str[STRING_RTSP_SESSION_ID]); - return CURLE_RTSP_SESSION_ERROR; - } - } - else { - /* If the Session ID is not set, and we find it in a response, then set - * it. - * - * Allow any non whitespace content, up to the field separator or end of - * line. RFC 2326 isn't 100% clear on the session ID and for example - * gstreamer does url-encoded session ID's not covered by the standard. - */ - char *end = start; - while(*end && *end != ';' && !ISSPACE(*end)) - end++; - - /* Copy the id substring into a new buffer */ - data->set.str[STRING_RTSP_SESSION_ID] = malloc(end - start + 1); - if(data->set.str[STRING_RTSP_SESSION_ID] == NULL) - return CURLE_OUT_OF_MEMORY; - memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, end - start); - (data->set.str[STRING_RTSP_SESSION_ID])[end - start] = '\0'; - } - } - return CURLE_OK; -} - -#endif /* CURL_DISABLE_RTSP */ diff --git a/dep/cpr/opt/curl/lib/rtsp.h b/dep/cpr/opt/curl/lib/rtsp.h deleted file mode 100644 index 8375a5317a2..00000000000 --- a/dep/cpr/opt/curl/lib/rtsp.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef HEADER_CURL_RTSP_H -#define HEADER_CURL_RTSP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#ifndef CURL_DISABLE_RTSP - -extern const struct Curl_handler Curl_handler_rtsp; - -CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header); - -#else -/* disabled */ -#define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN - -#endif /* CURL_DISABLE_RTSP */ - -/* - * RTSP Connection data - * - * Currently, only used for tracking incomplete RTP data reads - */ -struct rtsp_conn { - char *rtp_buf; - ssize_t rtp_bufsize; - int rtp_channel; -}; - -/**************************************************************************** - * RTSP unique setup - ***************************************************************************/ -struct RTSP { - /* - * http_wrapper MUST be the first element of this structure for the wrap - * logic to work. In this way, we get a cheap polymorphism because - * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec - * - * HTTP functions can safely treat this as an HTTP struct, but RTSP aware - * functions can also index into the later elements. - */ - struct HTTP http_wrapper; /*wrap HTTP to do the heavy lifting */ - - long CSeq_sent; /* CSeq of this request */ - long CSeq_recv; /* CSeq received */ -}; - - -#endif /* HEADER_CURL_RTSP_H */ - diff --git a/dep/cpr/opt/curl/lib/security.c b/dep/cpr/opt/curl/lib/security.c deleted file mode 100644 index 9b989681f3a..00000000000 --- a/dep/cpr/opt/curl/lib/security.c +++ /dev/null @@ -1,588 +0,0 @@ -/* This source code was modified by Martin Hedenfalk for - * use in Curl. His latest changes were done 2000-09-18. - * - * It has since been patched and modified a lot by Daniel Stenberg - * to make it better applied to curl conditions, and to make - * it not use globals, pollute name space and more. This source code awaits a - * rewrite to work around the paragraph 2 in the BSD licenses as explained - * below. - * - * Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * - * Copyright (C) 2001 - 2015, Daniel Stenberg, , et al. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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 "curl_setup.h" - -#ifndef CURL_DISABLE_FTP -#ifdef HAVE_GSSAPI - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_LIMITS_H -#include -#endif - -#include "urldata.h" -#include "curl_base64.h" -#include "curl_memory.h" -#include "curl_sec.h" -#include "ftp.h" -#include "sendf.h" -#include "strcase.h" -#include "warnless.h" -#include "strdup.h" -/* The last #include file should be: */ -#include "memdebug.h" - -static const struct { - enum protection_level level; - const char *name; -} level_names[] = { - { PROT_CLEAR, "clear" }, - { PROT_SAFE, "safe" }, - { PROT_CONFIDENTIAL, "confidential" }, - { PROT_PRIVATE, "private" } -}; - -static enum protection_level -name_to_level(const char *name) -{ - int i; - for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++) - if(checkprefix(name, level_names[i].name)) - return level_names[i].level; - return PROT_NONE; -} - -/* Convert a protocol |level| to its char representation. - We take an int to catch programming mistakes. */ -static char level_to_char(int level) -{ - switch(level) { - case PROT_CLEAR: - return 'C'; - case PROT_SAFE: - return 'S'; - case PROT_CONFIDENTIAL: - return 'E'; - case PROT_PRIVATE: - return 'P'; - case PROT_CMD: - /* Fall through */ - default: - /* Those 2 cases should not be reached! */ - break; - } - DEBUGASSERT(0); - /* Default to the most secure alternative. */ - return 'P'; -} - -/* Send an FTP command defined by |message| and the optional arguments. The - function returns the ftp_code. If an error occurs, -1 is returned. */ -static int ftp_send_command(struct connectdata *conn, const char *message, ...) -{ - int ftp_code; - ssize_t nread = 0; - va_list args; - char print_buffer[50]; - - va_start(args, message); - vsnprintf(print_buffer, sizeof(print_buffer), message, args); - va_end(args); - - if(Curl_ftpsend(conn, print_buffer)) { - ftp_code = -1; - } - else { - if(Curl_GetFTPResponse(&nread, conn, &ftp_code)) - ftp_code = -1; - } - - (void)nread; /* Unused */ - return ftp_code; -} - -/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode - saying whether an error occurred or CURLE_OK if |len| was read. */ -static CURLcode -socket_read(curl_socket_t fd, void *to, size_t len) -{ - char *to_p = to; - CURLcode result; - ssize_t nread; - - while(len > 0) { - result = Curl_read_plain(fd, to_p, len, &nread); - if(!result) { - len -= nread; - to_p += nread; - } - else { - /* FIXME: We are doing a busy wait */ - if(result == CURLE_AGAIN) - continue; - return result; - } - } - return CURLE_OK; -} - - -/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a - CURLcode saying whether an error occurred or CURLE_OK if |len| was - written. */ -static CURLcode -socket_write(struct connectdata *conn, curl_socket_t fd, const void *to, - size_t len) -{ - const char *to_p = to; - CURLcode result; - ssize_t written; - - while(len > 0) { - result = Curl_write_plain(conn, fd, to_p, len, &written); - if(!result) { - len -= written; - to_p += written; - } - else { - /* FIXME: We are doing a busy wait */ - if(result == CURLE_AGAIN) - continue; - return result; - } - } - return CURLE_OK; -} - -static CURLcode read_data(struct connectdata *conn, - curl_socket_t fd, - struct krb5buffer *buf) -{ - int len; - void *tmp = NULL; - CURLcode result; - - result = socket_read(fd, &len, sizeof(len)); - if(result) - return result; - - if(len) { - /* only realloc if there was a length */ - len = ntohl(len); - tmp = Curl_saferealloc(buf->data, len); - } - if(tmp == NULL) - return CURLE_OUT_OF_MEMORY; - - buf->data = tmp; - result = socket_read(fd, buf->data, len); - if(result) - return result; - buf->size = conn->mech->decode(conn->app_data, buf->data, len, - conn->data_prot, conn); - buf->index = 0; - return CURLE_OK; -} - -static size_t -buffer_read(struct krb5buffer *buf, void *data, size_t len) -{ - if(buf->size - buf->index < len) - len = buf->size - buf->index; - memcpy(data, (char *)buf->data + buf->index, len); - buf->index += len; - return len; -} - -/* Matches Curl_recv signature */ -static ssize_t sec_recv(struct connectdata *conn, int sockindex, - char *buffer, size_t len, CURLcode *err) -{ - size_t bytes_read; - size_t total_read = 0; - curl_socket_t fd = conn->sock[sockindex]; - - *err = CURLE_OK; - - /* Handle clear text response. */ - if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) - return read(fd, buffer, len); - - if(conn->in_buffer.eof_flag) { - conn->in_buffer.eof_flag = 0; - return 0; - } - - bytes_read = buffer_read(&conn->in_buffer, buffer, len); - len -= bytes_read; - total_read += bytes_read; - buffer += bytes_read; - - while(len > 0) { - if(read_data(conn, fd, &conn->in_buffer)) - return -1; - if(conn->in_buffer.size == 0) { - if(bytes_read > 0) - conn->in_buffer.eof_flag = 1; - return bytes_read; - } - bytes_read = buffer_read(&conn->in_buffer, buffer, len); - len -= bytes_read; - total_read += bytes_read; - buffer += bytes_read; - } - /* FIXME: Check for overflow */ - return total_read; -} - -/* Send |length| bytes from |from| to the |fd| socket taking care of encoding - and negociating with the server. |from| can be NULL. */ -/* FIXME: We don't check for errors nor report any! */ -static void do_sec_send(struct connectdata *conn, curl_socket_t fd, - const char *from, int length) -{ - int bytes, htonl_bytes; /* 32-bit integers for htonl */ - char *buffer = NULL; - char *cmd_buffer; - size_t cmd_size = 0; - CURLcode error; - enum protection_level prot_level = conn->data_prot; - bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE; - - DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); - - if(iscmd) { - if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5)) - prot_level = PROT_PRIVATE; - else - prot_level = conn->command_prot; - } - bytes = conn->mech->encode(conn->app_data, from, length, prot_level, - (void **)&buffer); - if(!buffer || bytes <= 0) - return; /* error */ - - if(iscmd) { - error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes), - &cmd_buffer, &cmd_size); - if(error) { - free(buffer); - return; /* error */ - } - if(cmd_size > 0) { - static const char *enc = "ENC "; - static const char *mic = "MIC "; - if(prot_level == PROT_PRIVATE) - socket_write(conn, fd, enc, 4); - else - socket_write(conn, fd, mic, 4); - - socket_write(conn, fd, cmd_buffer, cmd_size); - socket_write(conn, fd, "\r\n", 2); - infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic, - cmd_buffer); - free(cmd_buffer); - } - } - else { - htonl_bytes = htonl(bytes); - socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes)); - socket_write(conn, fd, buffer, curlx_sitouz(bytes)); - } - free(buffer); -} - -static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd, - const char *buffer, size_t length) -{ - ssize_t tx = 0, len = conn->buffer_size; - - len -= conn->mech->overhead(conn->app_data, conn->data_prot, - curlx_sztosi(len)); - if(len <= 0) - len = length; - while(length) { - if(length < (size_t)len) - len = length; - - do_sec_send(conn, fd, buffer, curlx_sztosi(len)); - length -= len; - buffer += len; - tx += len; - } - return tx; -} - -/* Matches Curl_send signature */ -static ssize_t sec_send(struct connectdata *conn, int sockindex, - const void *buffer, size_t len, CURLcode *err) -{ - curl_socket_t fd = conn->sock[sockindex]; - *err = CURLE_OK; - return sec_write(conn, fd, buffer, len); -} - -int Curl_sec_read_msg(struct connectdata *conn, char *buffer, - enum protection_level level) -{ - /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an - int */ - int decoded_len; - char *buf; - int ret_code = 0; - size_t decoded_sz = 0; - CURLcode error; - - if(!conn->mech) - /* not inititalized, return error */ - return -1; - - DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - - error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); - if(error || decoded_sz == 0) - return -1; - - if(decoded_sz > (size_t)INT_MAX) { - free(buf); - return -1; - } - decoded_len = curlx_uztosi(decoded_sz); - - decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len, - level, conn); - if(decoded_len <= 0) { - free(buf); - return -1; - } - - if(conn->data->set.verbose) { - buf[decoded_len] = '\n'; - Curl_debug(conn->data, CURLINFO_HEADER_IN, buf, decoded_len + 1, conn); - } - - buf[decoded_len] = '\0'; - if(decoded_len <= 3) - /* suspiciously short */ - return 0; - - if(buf[3] != '-') - /* safe to ignore return code */ - (void)sscanf(buf, "%d", &ret_code); - - if(buf[decoded_len - 1] == '\n') - buf[decoded_len - 1] = '\0'; - /* FIXME: Is |buffer| length always greater than |decoded_len|? */ - strcpy(buffer, buf); - free(buf); - return ret_code; -} - -/* FIXME: The error code returned here is never checked. */ -static int sec_set_protection_level(struct connectdata *conn) -{ - int code; - char *pbsz; - static unsigned int buffer_size = 1 << 20; /* 1048576 */ - enum protection_level level = conn->request_data_prot; - - DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - - if(!conn->sec_complete) { - infof(conn->data, "Trying to change the protection level after the" - "completion of the data exchange.\n"); - return -1; - } - - /* Bail out if we try to set up the same level */ - if(conn->data_prot == level) - return 0; - - if(level) { - code = ftp_send_command(conn, "PBSZ %u", buffer_size); - if(code < 0) - return -1; - - if(code/100 != 2) { - failf(conn->data, "Failed to set the protection's buffer size."); - return -1; - } - conn->buffer_size = buffer_size; - - pbsz = strstr(conn->data->state.buffer, "PBSZ="); - if(pbsz) { - /* ignore return code, use default value if it fails */ - (void)sscanf(pbsz, "PBSZ=%u", &buffer_size); - if(buffer_size < conn->buffer_size) - conn->buffer_size = buffer_size; - } - } - - /* Now try to negiociate the protection level. */ - code = ftp_send_command(conn, "PROT %c", level_to_char(level)); - - if(code < 0) - return -1; - - if(code/100 != 2) { - failf(conn->data, "Failed to set the protection level."); - return -1; - } - - conn->data_prot = level; - if(level == PROT_PRIVATE) - conn->command_prot = level; - - return 0; -} - -int -Curl_sec_request_prot(struct connectdata *conn, const char *level) -{ - enum protection_level l = name_to_level(level); - if(l == PROT_NONE) - return -1; - DEBUGASSERT(l > PROT_NONE && l < PROT_LAST); - conn->request_data_prot = l; - return 0; -} - -static CURLcode choose_mech(struct connectdata *conn) -{ - int ret; - struct Curl_easy *data = conn->data; - void *tmp_allocation; - const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; - - tmp_allocation = realloc(conn->app_data, mech->size); - if(tmp_allocation == NULL) { - failf(data, "Failed realloc of size %u", mech->size); - mech = NULL; - return CURLE_OUT_OF_MEMORY; - } - conn->app_data = tmp_allocation; - - if(mech->init) { - ret = mech->init(conn->app_data); - if(ret) { - infof(data, "Failed initialization for %s. Skipping it.\n", - mech->name); - return CURLE_FAILED_INIT; - } - } - - infof(data, "Trying mechanism %s...\n", mech->name); - ret = ftp_send_command(conn, "AUTH %s", mech->name); - if(ret < 0) - /* FIXME: This error is too generic but it is OK for now. */ - return CURLE_COULDNT_CONNECT; - - if(ret/100 != 3) { - switch(ret) { - case 504: - infof(data, "Mechanism %s is not supported by the server (server " - "returned ftp code: 504).\n", mech->name); - break; - case 534: - infof(data, "Mechanism %s was rejected by the server (server returned " - "ftp code: 534).\n", mech->name); - break; - default: - if(ret/100 == 5) { - infof(data, "server does not support the security extensions\n"); - return CURLE_USE_SSL_FAILED; - } - break; - } - return CURLE_LOGIN_DENIED; - } - - /* Authenticate */ - ret = mech->auth(conn->app_data, conn); - - if(ret != AUTH_CONTINUE) { - if(ret != AUTH_OK) { - /* Mechanism has dumped the error to stderr, don't error here. */ - return -1; - } - DEBUGASSERT(ret == AUTH_OK); - - conn->mech = mech; - conn->sec_complete = 1; - conn->recv[FIRSTSOCKET] = sec_recv; - conn->send[FIRSTSOCKET] = sec_send; - conn->recv[SECONDARYSOCKET] = sec_recv; - conn->send[SECONDARYSOCKET] = sec_send; - conn->command_prot = PROT_SAFE; - /* Set the requested protection level */ - /* BLOCKING */ - (void)sec_set_protection_level(conn); - } - - return CURLE_OK; -} - -CURLcode -Curl_sec_login(struct connectdata *conn) -{ - return choose_mech(conn); -} - - -void -Curl_sec_end(struct connectdata *conn) -{ - if(conn->mech != NULL && conn->mech->end) - conn->mech->end(conn->app_data); - free(conn->app_data); - conn->app_data = NULL; - if(conn->in_buffer.data) { - free(conn->in_buffer.data); - conn->in_buffer.data = NULL; - conn->in_buffer.size = 0; - conn->in_buffer.index = 0; - /* FIXME: Is this really needed? */ - conn->in_buffer.eof_flag = 0; - } - conn->sec_complete = 0; - conn->data_prot = PROT_CLEAR; - conn->mech = NULL; -} - -#endif /* HAVE_GSSAPI */ - -#endif /* CURL_DISABLE_FTP */ diff --git a/dep/cpr/opt/curl/lib/select.c b/dep/cpr/opt/curl/lib/select.c deleted file mode 100644 index f6fecaf5132..00000000000 --- a/dep/cpr/opt/curl/lib/select.c +++ /dev/null @@ -1,583 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) -#error "We can't compile without select() or poll() support." -#endif - -#if defined(__BEOS__) && !defined(__HAIKU__) -/* BeOS has FD_SET defined in socket.h */ -#include -#endif - -#ifdef MSDOS -#include /* delay() */ -#endif - -#ifdef __VXWORKS__ -#include /* bzero() in FD_SET */ -#endif - -#include - -#include "urldata.h" -#include "connect.h" -#include "select.h" -#include "warnless.h" - -/* Convenience local macros */ -#define ELAPSED_MS() (int)curlx_tvdiff(curlx_tvnow(), initial_tv) - -int Curl_ack_eintr = 0; -#define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR) - -/* - * Internal function used for waiting a specific amount of ms - * in Curl_socket_check() and Curl_poll() when no file descriptor - * is provided to wait on, just being used to delay execution. - * WinSock select() and poll() timeout mechanisms need a valid - * socket descriptor in a not null file descriptor set to work. - * Waiting indefinitely with this function is not allowed, a - * zero or negative timeout value will return immediately. - * Timeout resolution, accuracy, as well as maximum supported - * value is system dependent, neither factor is a citical issue - * for the intended use of this function in the library. - * - * Return values: - * -1 = system call error, invalid timeout value, or interrupted - * 0 = specified timeout has elapsed - */ -int Curl_wait_ms(int timeout_ms) -{ -#if !defined(MSDOS) && !defined(USE_WINSOCK) -#ifndef HAVE_POLL_FINE - struct timeval pending_tv; -#endif - struct curltime initial_tv; - int pending_ms; - int error; -#endif - int r = 0; - - if(!timeout_ms) - return 0; - if(timeout_ms < 0) { - SET_SOCKERRNO(EINVAL); - return -1; - } -#if defined(MSDOS) - delay(timeout_ms); -#elif defined(USE_WINSOCK) - Sleep(timeout_ms); -#else - pending_ms = timeout_ms; - initial_tv = curlx_tvnow(); - do { -#if defined(HAVE_POLL_FINE) - r = poll(NULL, 0, pending_ms); -#else - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - r = select(0, NULL, NULL, NULL, &pending_tv); -#endif /* HAVE_POLL_FINE */ - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - pending_ms = timeout_ms - ELAPSED_MS(); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } while(r == -1); -#endif /* USE_WINSOCK */ - if(r) - r = -1; - return r; -} - -/* - * Wait for read or write events on a set of file descriptors. It uses poll() - * when a fine poll() is available, in order to avoid limits with FD_SETSIZE, - * otherwise select() is used. An error is returned if select() is being used - * and a file descriptor is too large for FD_SETSIZE. - * - * A negative timeout value makes this function wait indefinitely, - * unless no valid file descriptor is given, when this happens the - * negative timeout is ignored and the function times out immediately. - * - * Return values: - * -1 = system call error or fd >= FD_SETSIZE - * 0 = timeout - * [bitmask] = action as described below - * - * CURL_CSELECT_IN - first socket is readable - * CURL_CSELECT_IN2 - second socket is readable - * CURL_CSELECT_OUT - write socket is writable - * CURL_CSELECT_ERR - an error condition occurred - */ -int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ - curl_socket_t readfd1, - curl_socket_t writefd, /* socket to write to */ - time_t timeout_ms) /* milliseconds to wait */ -{ -#ifdef HAVE_POLL_FINE - struct pollfd pfd[3]; - int num; -#else - struct timeval pending_tv; - struct timeval *ptimeout; - fd_set fds_read; - fd_set fds_write; - fd_set fds_err; - curl_socket_t maxfd; -#endif - struct curltime initial_tv = {0, 0}; - int pending_ms = 0; - int error; - int r; - int ret; - -#if SIZEOF_TIME_T != SIZEOF_INT - /* wrap-around precaution */ - if(timeout_ms >= INT_MAX) - timeout_ms = INT_MAX; -#endif - - if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && - (writefd == CURL_SOCKET_BAD)) { - /* no sockets, just wait */ - r = Curl_wait_ms((int)timeout_ms); - return r; - } - - /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed - time in this function does not need to be measured. This happens - when function is called with a zero timeout or a negative timeout - value indicating a blocking call should be performed. */ - - if(timeout_ms > 0) { - pending_ms = (int)timeout_ms; - initial_tv = curlx_tvnow(); - } - -#ifdef HAVE_POLL_FINE - - num = 0; - if(readfd0 != CURL_SOCKET_BAD) { - pfd[num].fd = readfd0; - pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; - pfd[num].revents = 0; - num++; - } - if(readfd1 != CURL_SOCKET_BAD) { - pfd[num].fd = readfd1; - pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; - pfd[num].revents = 0; - num++; - } - if(writefd != CURL_SOCKET_BAD) { - pfd[num].fd = writefd; - pfd[num].events = POLLWRNORM|POLLOUT; - pfd[num].revents = 0; - num++; - } - - do { - if(timeout_ms < 0) - pending_ms = -1; - else if(!timeout_ms) - pending_ms = 0; - r = poll(pfd, num, pending_ms); - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - ELAPSED_MS()); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } - } while(r == -1); - - if(r < 0) - return -1; - if(r == 0) - return 0; - - ret = 0; - num = 0; - if(readfd0 != CURL_SOCKET_BAD) { - if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) - ret |= CURL_CSELECT_IN; - if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) - ret |= CURL_CSELECT_ERR; - num++; - } - if(readfd1 != CURL_SOCKET_BAD) { - if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) - ret |= CURL_CSELECT_IN2; - if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) - ret |= CURL_CSELECT_ERR; - num++; - } - if(writefd != CURL_SOCKET_BAD) { - if(pfd[num].revents & (POLLWRNORM|POLLOUT)) - ret |= CURL_CSELECT_OUT; - if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL)) - ret |= CURL_CSELECT_ERR; - } - - return ret; - -#else /* HAVE_POLL_FINE */ - - FD_ZERO(&fds_err); - maxfd = (curl_socket_t)-1; - - FD_ZERO(&fds_read); - if(readfd0 != CURL_SOCKET_BAD) { - VERIFY_SOCK(readfd0); - FD_SET(readfd0, &fds_read); - FD_SET(readfd0, &fds_err); - maxfd = readfd0; - } - if(readfd1 != CURL_SOCKET_BAD) { - VERIFY_SOCK(readfd1); - FD_SET(readfd1, &fds_read); - FD_SET(readfd1, &fds_err); - if(readfd1 > maxfd) - maxfd = readfd1; - } - - FD_ZERO(&fds_write); - if(writefd != CURL_SOCKET_BAD) { - VERIFY_SOCK(writefd); - FD_SET(writefd, &fds_write); - FD_SET(writefd, &fds_err); - if(writefd > maxfd) - maxfd = writefd; - } - - ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; - - do { - if(timeout_ms > 0) { - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - } - else if(!timeout_ms) { - pending_tv.tv_sec = 0; - pending_tv.tv_usec = 0; - } - - /* WinSock select() must not be called with an fd_set that contains zero - fd flags, or it will return WSAEINVAL. But, it also can't be called - with no fd_sets at all! From the documentation: - - Any two of the parameters, readfds, writefds, or exceptfds, can be - given as null. At least one must be non-null, and any non-null - descriptor set must contain at least one handle to a socket. - - We know that we have at least one bit set in at least two fd_sets in - this case, but we may have no bits set in either fds_read or fd_write, - so check for that and handle it. Luckily, with WinSock, we can _also_ - ask how many bits are set on an fd_set. - - It is unclear why WinSock doesn't just handle this for us instead of - calling this an error. - - Note also that WinSock ignores the first argument, so we don't worry - about the fact that maxfd is computed incorrectly with WinSock (since - curl_socket_t is unsigned in such cases and thus -1 is the largest - value). - */ -#ifdef USE_WINSOCK - r = select((int)maxfd + 1, - fds_read.fd_count ? &fds_read : NULL, - fds_write.fd_count ? &fds_write : NULL, - &fds_err, ptimeout); -#else - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); -#endif - - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - ELAPSED_MS()); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } - } while(r == -1); - - if(r < 0) - return -1; - if(r == 0) - return 0; - - ret = 0; - if(readfd0 != CURL_SOCKET_BAD) { - if(FD_ISSET(readfd0, &fds_read)) - ret |= CURL_CSELECT_IN; - if(FD_ISSET(readfd0, &fds_err)) - ret |= CURL_CSELECT_ERR; - } - if(readfd1 != CURL_SOCKET_BAD) { - if(FD_ISSET(readfd1, &fds_read)) - ret |= CURL_CSELECT_IN2; - if(FD_ISSET(readfd1, &fds_err)) - ret |= CURL_CSELECT_ERR; - } - if(writefd != CURL_SOCKET_BAD) { - if(FD_ISSET(writefd, &fds_write)) - ret |= CURL_CSELECT_OUT; - if(FD_ISSET(writefd, &fds_err)) - ret |= CURL_CSELECT_ERR; - } - - return ret; - -#endif /* HAVE_POLL_FINE */ - -} - -/* - * This is a wrapper around poll(). If poll() does not exist, then - * select() is used instead. An error is returned if select() is - * being used and a file descriptor is too large for FD_SETSIZE. - * A negative timeout value makes this function wait indefinitely, - * unless no valid file descriptor is given, when this happens the - * negative timeout is ignored and the function times out immediately. - * - * Return values: - * -1 = system call error or fd >= FD_SETSIZE - * 0 = timeout - * N = number of structures with non zero revent fields - */ -int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) -{ -#ifndef HAVE_POLL_FINE - struct timeval pending_tv; - struct timeval *ptimeout; - fd_set fds_read; - fd_set fds_write; - fd_set fds_err; - curl_socket_t maxfd; -#endif - struct curltime initial_tv = {0, 0}; - bool fds_none = TRUE; - unsigned int i; - int pending_ms = 0; - int error; - int r; - - if(ufds) { - for(i = 0; i < nfds; i++) { - if(ufds[i].fd != CURL_SOCKET_BAD) { - fds_none = FALSE; - break; - } - } - } - if(fds_none) { - r = Curl_wait_ms(timeout_ms); - return r; - } - - /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed - time in this function does not need to be measured. This happens - when function is called with a zero timeout or a negative timeout - value indicating a blocking call should be performed. */ - - if(timeout_ms > 0) { - pending_ms = timeout_ms; - initial_tv = curlx_tvnow(); - } - -#ifdef HAVE_POLL_FINE - - do { - if(timeout_ms < 0) - pending_ms = -1; - else if(!timeout_ms) - pending_ms = 0; - r = poll(ufds, nfds, pending_ms); - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - ELAPSED_MS()); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } - } while(r == -1); - - if(r < 0) - return -1; - if(r == 0) - return 0; - - for(i = 0; i < nfds; i++) { - if(ufds[i].fd == CURL_SOCKET_BAD) - continue; - if(ufds[i].revents & POLLHUP) - ufds[i].revents |= POLLIN; - if(ufds[i].revents & POLLERR) - ufds[i].revents |= (POLLIN|POLLOUT); - } - -#else /* HAVE_POLL_FINE */ - - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_ZERO(&fds_err); - maxfd = (curl_socket_t)-1; - - for(i = 0; i < nfds; i++) { - ufds[i].revents = 0; - if(ufds[i].fd == CURL_SOCKET_BAD) - continue; - VERIFY_SOCK(ufds[i].fd); - if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI| - POLLRDNORM|POLLWRNORM|POLLRDBAND)) { - if(ufds[i].fd > maxfd) - maxfd = ufds[i].fd; - if(ufds[i].events & (POLLRDNORM|POLLIN)) - FD_SET(ufds[i].fd, &fds_read); - if(ufds[i].events & (POLLWRNORM|POLLOUT)) - FD_SET(ufds[i].fd, &fds_write); - if(ufds[i].events & (POLLRDBAND|POLLPRI)) - FD_SET(ufds[i].fd, &fds_err); - } - } - -#ifdef USE_WINSOCK - /* WinSock select() can't handle zero events. See the comment about this in - Curl_check_socket(). */ - if(fds_read.fd_count == 0 && fds_write.fd_count == 0 - && fds_err.fd_count == 0) { - r = Curl_wait_ms(timeout_ms); - return r; - } -#endif - - ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; - - do { - if(timeout_ms > 0) { - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - } - else if(!timeout_ms) { - pending_tv.tv_sec = 0; - pending_tv.tv_usec = 0; - } - -#ifdef USE_WINSOCK - r = select((int)maxfd + 1, - /* WinSock select() can't handle fd_sets with zero bits set, so - don't give it such arguments. See the comment about this in - Curl_check_socket(). - */ - fds_read.fd_count ? &fds_read : NULL, - fds_write.fd_count ? &fds_write : NULL, - fds_err.fd_count ? &fds_err : NULL, ptimeout); -#else - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); -#endif - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - if(timeout_ms > 0) { - pending_ms = timeout_ms - ELAPSED_MS(); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } - } while(r == -1); - - if(r < 0) - return -1; - if(r == 0) - return 0; - - r = 0; - for(i = 0; i < nfds; i++) { - ufds[i].revents = 0; - if(ufds[i].fd == CURL_SOCKET_BAD) - continue; - if(FD_ISSET(ufds[i].fd, &fds_read)) - ufds[i].revents |= POLLIN; - if(FD_ISSET(ufds[i].fd, &fds_write)) - ufds[i].revents |= POLLOUT; - if(FD_ISSET(ufds[i].fd, &fds_err)) - ufds[i].revents |= POLLPRI; - if(ufds[i].revents != 0) - r++; - } - -#endif /* HAVE_POLL_FINE */ - - return r; -} - -#ifdef TPF -/* - * This is a replacement for select() on the TPF platform. - * It is used whenever libcurl calls select(). - * The call below to tpf_process_signals() is required because - * TPF's select calls are not signal interruptible. - * - * Return values are the same as select's. - */ -int tpf_select_libcurl(int maxfds, fd_set *reads, fd_set *writes, - fd_set *excepts, struct timeval *tv) -{ - int rc; - - rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv); - tpf_process_signals(); - return rc; -} -#endif /* TPF */ diff --git a/dep/cpr/opt/curl/lib/select.h b/dep/cpr/opt/curl/lib/select.h deleted file mode 100644 index 4351786c395..00000000000 --- a/dep/cpr/opt/curl/lib/select.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef HEADER_CURL_SELECT_H -#define HEADER_CURL_SELECT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_POLL_H -#include -#elif defined(HAVE_SYS_POLL_H) -#include -#endif - -/* - * Definition of pollfd struct and constants for platforms lacking them. - */ - -#if !defined(HAVE_STRUCT_POLLFD) && \ - !defined(HAVE_SYS_POLL_H) && \ - !defined(HAVE_POLL_H) && \ - !defined(POLLIN) - -#define POLLIN 0x01 -#define POLLPRI 0x02 -#define POLLOUT 0x04 -#define POLLERR 0x08 -#define POLLHUP 0x10 -#define POLLNVAL 0x20 - -struct pollfd -{ - curl_socket_t fd; - short events; - short revents; -}; - -#endif - -#ifndef POLLRDNORM -#define POLLRDNORM POLLIN -#endif - -#ifndef POLLWRNORM -#define POLLWRNORM POLLOUT -#endif - -#ifndef POLLRDBAND -#define POLLRDBAND POLLPRI -#endif - -/* there are three CSELECT defines that are defined in the public header that - are exposed to users, but this *IN2 bit is only ever used internally and - therefore defined here */ -#define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1) - -int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, - curl_socket_t writefd, - time_t timeout_ms); - -#define SOCKET_READABLE(x,z) \ - Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z) -#define SOCKET_WRITABLE(x,z) \ - Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z) - -int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); - -/* On non-DOS and non-Winsock platforms, when Curl_ack_eintr is set, - * EINTR condition is honored and function might exit early without - * awaiting full timeout. Otherwise EINTR will be ignored and full - * timeout will elapse. */ -extern int Curl_ack_eintr; - -int Curl_wait_ms(int timeout_ms); - -#ifdef TPF -int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, - fd_set* excepts, struct timeval* tv); -#endif - -/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which - unfortunately makes it impossible for us to easily check if they're valid -*/ -#if defined(USE_WINSOCK) || defined(TPF) -#define VALID_SOCK(x) 1 -#define VERIFY_SOCK(x) Curl_nop_stmt -#else -#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) -#define VERIFY_SOCK(x) do { \ - if(!VALID_SOCK(x)) { \ - SET_SOCKERRNO(EINVAL); \ - return -1; \ - } \ -} WHILE_FALSE -#endif - -#endif /* HEADER_CURL_SELECT_H */ - diff --git a/dep/cpr/opt/curl/lib/sendf.c b/dep/cpr/opt/curl/lib/sendf.c deleted file mode 100644 index 7564cb3d095..00000000000 --- a/dep/cpr/opt/curl/lib/sendf.c +++ /dev/null @@ -1,855 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "urldata.h" -#include "sendf.h" -#include "connect.h" -#include "vtls/vtls.h" -#include "ssh.h" -#include "multiif.h" -#include "non-ascii.h" -#include "strerror.h" -#include "select.h" -#include "strdup.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifdef CURL_DO_LINEEND_CONV -/* - * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF - * (\n), with special processing for CRLF sequences that are split between two - * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new - * size of the data is returned. - */ -static size_t convert_lineends(struct Curl_easy *data, - char *startPtr, size_t size) -{ - char *inPtr, *outPtr; - - /* sanity check */ - if((startPtr == NULL) || (size < 1)) { - return size; - } - - if(data->state.prev_block_had_trailing_cr) { - /* The previous block of incoming data - had a trailing CR, which was turned into a LF. */ - if(*startPtr == '\n') { - /* This block of incoming data starts with the - previous block's LF so get rid of it */ - memmove(startPtr, startPtr + 1, size-1); - size--; - /* and it wasn't a bare CR but a CRLF conversion instead */ - data->state.crlf_conversions++; - } - data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */ - } - - /* find 1st CR, if any */ - inPtr = outPtr = memchr(startPtr, '\r', size); - if(inPtr) { - /* at least one CR, now look for CRLF */ - while(inPtr < (startPtr + size-1)) { - /* note that it's size-1, so we'll never look past the last byte */ - if(memcmp(inPtr, "\r\n", 2) == 0) { - /* CRLF found, bump past the CR and copy the NL */ - inPtr++; - *outPtr = *inPtr; - /* keep track of how many CRLFs we converted */ - data->state.crlf_conversions++; - } - else { - if(*inPtr == '\r') { - /* lone CR, move LF instead */ - *outPtr = '\n'; - } - else { - /* not a CRLF nor a CR, just copy whatever it is */ - *outPtr = *inPtr; - } - } - outPtr++; - inPtr++; - } /* end of while loop */ - - if(inPtr < startPtr + size) { - /* handle last byte */ - if(*inPtr == '\r') { - /* deal with a CR at the end of the buffer */ - *outPtr = '\n'; /* copy a NL instead */ - /* note that a CRLF might be split across two blocks */ - data->state.prev_block_had_trailing_cr = TRUE; - } - else { - /* copy last byte */ - *outPtr = *inPtr; - } - outPtr++; - } - if(outPtr < startPtr + size) - /* tidy up by null terminating the now shorter data */ - *outPtr = '\0'; - - return (outPtr - startPtr); - } - return size; -} -#endif /* CURL_DO_LINEEND_CONV */ - -#ifdef USE_RECV_BEFORE_SEND_WORKAROUND -bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex) -{ - struct postponed_data * const psnd = &(conn->postponed[sockindex]); - return psnd->buffer && psnd->allocated_size && - psnd->recv_size > psnd->recv_processed; -} - -static void pre_receive_plain(struct connectdata *conn, int num) -{ - const curl_socket_t sockfd = conn->sock[num]; - struct postponed_data * const psnd = &(conn->postponed[num]); - size_t bytestorecv = psnd->allocated_size - psnd->recv_size; - /* WinSock will destroy unread received data if send() is - failed. - To avoid lossage of received data, recv() must be - performed before every send() if any incoming data is - available. However, skip this, if buffer is already full. */ - if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 && - conn->recv[num] == Curl_recv_plain && - (!psnd->buffer || bytestorecv)) { - const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD, - CURL_SOCKET_BAD, 0); - if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) { - /* Have some incoming data */ - if(!psnd->buffer) { - /* Use buffer double default size for intermediate buffer */ - psnd->allocated_size = 2 * conn->data->set.buffer_size; - psnd->buffer = malloc(psnd->allocated_size); - psnd->recv_size = 0; - psnd->recv_processed = 0; -#ifdef DEBUGBUILD - psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */ -#endif /* DEBUGBUILD */ - bytestorecv = psnd->allocated_size; - } - if(psnd->buffer) { - ssize_t recvedbytes; - DEBUGASSERT(psnd->bindsock == sockfd); - recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size, - bytestorecv); - if(recvedbytes > 0) - psnd->recv_size += recvedbytes; - } - else - psnd->allocated_size = 0; - } - } -} - -static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf, - size_t len) -{ - struct postponed_data * const psnd = &(conn->postponed[num]); - size_t copysize; - if(!psnd->buffer) - return 0; - - DEBUGASSERT(psnd->allocated_size > 0); - DEBUGASSERT(psnd->recv_size <= psnd->allocated_size); - DEBUGASSERT(psnd->recv_processed <= psnd->recv_size); - /* Check and process data that already received and storied in internal - intermediate buffer */ - if(psnd->recv_size > psnd->recv_processed) { - DEBUGASSERT(psnd->bindsock == conn->sock[num]); - copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed); - memcpy(buf, psnd->buffer + psnd->recv_processed, copysize); - psnd->recv_processed += copysize; - } - else - copysize = 0; /* buffer was allocated, but nothing was received */ - - /* Free intermediate buffer if it has no unprocessed data */ - if(psnd->recv_processed == psnd->recv_size) { - free(psnd->buffer); - psnd->buffer = NULL; - psnd->allocated_size = 0; - psnd->recv_size = 0; - psnd->recv_processed = 0; -#ifdef DEBUGBUILD - psnd->bindsock = CURL_SOCKET_BAD; -#endif /* DEBUGBUILD */ - } - return (ssize_t)copysize; -} -#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ -/* Use "do-nothing" macros instead of functions when workaround not used */ -bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex) -{ - (void)conn; - (void)sockindex; - return false; -} -#define pre_receive_plain(c,n) do {} WHILE_FALSE -#define get_pre_recved(c,n,b,l) 0 -#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ - -/* Curl_infof() is for info message along the way */ - -void Curl_infof(struct Curl_easy *data, const char *fmt, ...) -{ - if(data && data->set.verbose) { - va_list ap; - size_t len; - char print_buffer[2048 + 1]; - va_start(ap, fmt); - vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap); - va_end(ap); - len = strlen(print_buffer); - Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL); - } -} - -/* Curl_failf() is for messages stating why we failed. - * The message SHALL NOT include any LF or CR. - */ - -void Curl_failf(struct Curl_easy *data, const char *fmt, ...) -{ - va_list ap; - size_t len; - char error[CURL_ERROR_SIZE + 2]; - va_start(ap, fmt); - - vsnprintf(error, CURL_ERROR_SIZE, fmt, ap); - len = strlen(error); - - if(data->set.errorbuffer && !data->state.errorbuf) { - strcpy(data->set.errorbuffer, error); - data->state.errorbuf = TRUE; /* wrote error string */ - } - if(data->set.verbose) { - error[len] = '\n'; - error[++len] = '\0'; - Curl_debug(data, CURLINFO_TEXT, error, len, NULL); - } - - va_end(ap); -} - -/* Curl_sendf() sends formatted data to the server */ -CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, - const char *fmt, ...) -{ - struct Curl_easy *data = conn->data; - ssize_t bytes_written; - size_t write_len; - CURLcode result = CURLE_OK; - char *s; - char *sptr; - va_list ap; - va_start(ap, fmt); - s = vaprintf(fmt, ap); /* returns an allocated string */ - va_end(ap); - if(!s) - return CURLE_OUT_OF_MEMORY; /* failure */ - - bytes_written = 0; - write_len = strlen(s); - sptr = s; - - for(;;) { - /* Write the buffer to the socket */ - result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written); - - if(result) - break; - - if(data->set.verbose) - Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn); - - if((size_t)bytes_written != write_len) { - /* if not all was written at once, we must advance the pointer, decrease - the size left and try again! */ - write_len -= bytes_written; - sptr += bytes_written; - } - else - break; - } - - free(s); /* free the output string */ - - return result; -} - -/* - * Curl_write() is an internal write function that sends data to the - * server. Works with plain sockets, SCP, SSL or kerberos. - * - * If the write would block (CURLE_AGAIN), we return CURLE_OK and - * (*written == 0). Otherwise we return regular CURLcode value. - */ -CURLcode Curl_write(struct connectdata *conn, - curl_socket_t sockfd, - const void *mem, - size_t len, - ssize_t *written) -{ - ssize_t bytes_written; - CURLcode result = CURLE_OK; - int num = (sockfd == conn->sock[SECONDARYSOCKET]); - - bytes_written = conn->send[num](conn, num, mem, len, &result); - - *written = bytes_written; - if(bytes_written >= 0) - /* we completely ignore the curlcode value when subzero is not returned */ - return CURLE_OK; - - /* handle CURLE_AGAIN or a send failure */ - switch(result) { - case CURLE_AGAIN: - *written = 0; - return CURLE_OK; - - case CURLE_OK: - /* general send failure */ - return CURLE_SEND_ERROR; - - default: - /* we got a specific curlcode, forward it */ - return result; - } -} - -ssize_t Curl_send_plain(struct connectdata *conn, int num, - const void *mem, size_t len, CURLcode *code) -{ - curl_socket_t sockfd = conn->sock[num]; - ssize_t bytes_written; - /* WinSock will destroy unread received data if send() is - failed. - To avoid lossage of received data, recv() must be - performed before every send() if any incoming data is - available. */ - pre_receive_plain(conn, num); - -#ifdef MSG_FASTOPEN /* Linux */ - if(conn->bits.tcp_fastopen) { - bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN, - conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen); - conn->bits.tcp_fastopen = FALSE; - } - else -#endif - bytes_written = swrite(sockfd, mem, len); - - *code = CURLE_OK; - if(-1 == bytes_written) { - int err = SOCKERRNO; - - if( -#ifdef WSAEWOULDBLOCK - /* This is how Windows does it */ - (WSAEWOULDBLOCK == err) -#else - /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned - due to its inability to send off data without blocking. We therefor - treat both error codes the same here */ - (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) || - (EINPROGRESS == err) -#endif - ) { - /* this is just a case of EWOULDBLOCK */ - bytes_written = 0; - *code = CURLE_AGAIN; - } - else { - failf(conn->data, "Send failure: %s", - Curl_strerror(conn, err)); - conn->data->state.os_errno = err; - *code = CURLE_SEND_ERROR; - } - } - return bytes_written; -} - -/* - * Curl_write_plain() is an internal write function that sends data to the - * server using plain sockets only. Otherwise meant to have the exact same - * proto as Curl_write() - */ -CURLcode Curl_write_plain(struct connectdata *conn, - curl_socket_t sockfd, - const void *mem, - size_t len, - ssize_t *written) -{ - ssize_t bytes_written; - CURLcode result; - int num = (sockfd == conn->sock[SECONDARYSOCKET]); - - bytes_written = Curl_send_plain(conn, num, mem, len, &result); - - *written = bytes_written; - - return result; -} - -ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, - size_t len, CURLcode *code) -{ - curl_socket_t sockfd = conn->sock[num]; - ssize_t nread; - /* Check and return data that already received and storied in internal - intermediate buffer */ - nread = get_pre_recved(conn, num, buf, len); - if(nread > 0) { - *code = CURLE_OK; - return nread; - } - - nread = sread(sockfd, buf, len); - - *code = CURLE_OK; - if(-1 == nread) { - int err = SOCKERRNO; - - if( -#ifdef WSAEWOULDBLOCK - /* This is how Windows does it */ - (WSAEWOULDBLOCK == err) -#else - /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned - due to its inability to send off data without blocking. We therefor - treat both error codes the same here */ - (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) -#endif - ) { - /* this is just a case of EWOULDBLOCK */ - *code = CURLE_AGAIN; - } - else { - failf(conn->data, "Recv failure: %s", - Curl_strerror(conn, err)); - conn->data->state.os_errno = err; - *code = CURLE_RECV_ERROR; - } - } - return nread; -} - -static CURLcode pausewrite(struct Curl_easy *data, - int type, /* what type of data */ - const char *ptr, - size_t len) -{ - /* signalled to pause sending on this connection, but since we have data - we want to send we need to dup it to save a copy for when the sending - is again enabled */ - struct SingleRequest *k = &data->req; - struct UrlState *s = &data->state; - char *dupl; - unsigned int i; - bool newtype = TRUE; - - if(s->tempcount) { - for(i = 0; i< s->tempcount; i++) { - if(s->tempwrite[i].type == type) { - /* data for this type exists */ - newtype = FALSE; - break; - } - } - DEBUGASSERT(i < 3); - } - else - i = 0; - - if(!newtype) { - /* append new data to old data */ - - /* figure out the new size of the data to save */ - size_t newlen = len + s->tempwrite[i].len; - /* allocate the new memory area */ - char *newptr = realloc(s->tempwrite[i].buf, newlen); - if(!newptr) - return CURLE_OUT_OF_MEMORY; - /* copy the new data to the end of the new area */ - memcpy(newptr + s->tempwrite[i].len, ptr, len); - - /* update the pointer and the size */ - s->tempwrite[i].buf = newptr; - s->tempwrite[i].len = newlen; - } - else { - dupl = Curl_memdup(ptr, len); - if(!dupl) - return CURLE_OUT_OF_MEMORY; - - /* store this information in the state struct for later use */ - s->tempwrite[i].buf = dupl; - s->tempwrite[i].len = len; - s->tempwrite[i].type = type; - - if(newtype) - s->tempcount++; - } - - /* mark the connection as RECV paused */ - k->keepon |= KEEP_RECV_PAUSE; - - DEBUGF(infof(data, "Paused %zu bytes in buffer for type %02x\n", - len, type)); - - return CURLE_OK; -} - - -/* Curl_client_chop_write() writes chunks of data not larger than - * CURL_MAX_WRITE_SIZE via client write callback(s) and - * takes care of pause requests from the callbacks. - */ -CURLcode Curl_client_chop_write(struct connectdata *conn, - int type, - char *ptr, - size_t len) -{ - struct Curl_easy *data = conn->data; - curl_write_callback writeheader = NULL; - curl_write_callback writebody = NULL; - - if(!len) - return CURLE_OK; - - /* If reading is paused, append this data to the already held data for this - type. */ - if(data->req.keepon & KEEP_RECV_PAUSE) - return pausewrite(data, type, ptr, len); - - /* Determine the callback(s) to use. */ - if(type & CLIENTWRITE_BODY) - writebody = data->set.fwrite_func; - if((type & CLIENTWRITE_HEADER) && - (data->set.fwrite_header || data->set.writeheader)) { - /* - * Write headers to the same callback or to the especially setup - * header callback function (added after version 7.7.1). - */ - writeheader = - data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func; - } - - /* Chop data, write chunks. */ - while(len) { - size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE; - - if(writebody) { - size_t wrote = writebody(ptr, 1, chunklen, data->set.out); - - if(CURL_WRITEFUNC_PAUSE == wrote) { - if(conn->handler->flags & PROTOPT_NONETWORK) { - /* Protocols that work without network cannot be paused. This is - actually only FILE:// just now, and it can't pause since the - transfer isn't done using the "normal" procedure. */ - failf(data, "Write callback asked for PAUSE when not supported!"); - return CURLE_WRITE_ERROR; - } - return pausewrite(data, type, ptr, len); - } - if(wrote != chunklen) { - failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen); - return CURLE_WRITE_ERROR; - } - } - - if(writeheader) { - size_t wrote = writeheader(ptr, 1, chunklen, data->set.writeheader); - - if(CURL_WRITEFUNC_PAUSE == wrote) - /* here we pass in the HEADER bit only since if this was body as well - then it was passed already and clearly that didn't trigger the - pause, so this is saved for later with the HEADER bit only */ - return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); - - if(wrote != chunklen) { - failf(data, "Failed writing header"); - return CURLE_WRITE_ERROR; - } - } - - ptr += chunklen; - len -= chunklen; - } - - return CURLE_OK; -} - - -/* Curl_client_write() sends data to the write callback(s) - - The bit pattern defines to what "streams" to write to. Body and/or header. - The defines are in sendf.h of course. - - If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the - local character encoding. This is a problem and should be changed in - the future to leave the original data alone. - */ -CURLcode Curl_client_write(struct connectdata *conn, - int type, - char *ptr, - size_t len) -{ - struct Curl_easy *data = conn->data; - - if(0 == len) - len = strlen(ptr); - - DEBUGASSERT(type <= 3); - - /* FTP data may need conversion. */ - if((type & CLIENTWRITE_BODY) && - (conn->handler->protocol & PROTO_FAMILY_FTP) && - conn->proto.ftpc.transfertype == 'A') { - /* convert from the network encoding */ - CURLcode result = Curl_convert_from_network(data, ptr, len); - /* Curl_convert_from_network calls failf if unsuccessful */ - if(result) - return result; - -#ifdef CURL_DO_LINEEND_CONV - /* convert end-of-line markers */ - len = convert_lineends(data, ptr, len); -#endif /* CURL_DO_LINEEND_CONV */ - } - - return Curl_client_chop_write(conn, type, ptr, len); -} - -CURLcode Curl_read_plain(curl_socket_t sockfd, - char *buf, - size_t bytesfromsocket, - ssize_t *n) -{ - ssize_t nread = sread(sockfd, buf, bytesfromsocket); - - if(-1 == nread) { - int err = SOCKERRNO; - int return_error; -#ifdef USE_WINSOCK - return_error = WSAEWOULDBLOCK == err; -#else - return_error = EWOULDBLOCK == err || EAGAIN == err || EINTR == err; -#endif - if(return_error) - return CURLE_AGAIN; - return CURLE_RECV_ERROR; - } - - /* we only return number of bytes read when we return OK */ - *n = nread; - return CURLE_OK; -} - -/* - * Internal read-from-socket function. This is meant to deal with plain - * sockets, SSL sockets and kerberos sockets. - * - * Returns a regular CURLcode value. - */ -CURLcode Curl_read(struct connectdata *conn, /* connection data */ - curl_socket_t sockfd, /* read from this socket */ - char *buf, /* store read data here */ - size_t sizerequested, /* max amount to read */ - ssize_t *n) /* amount bytes read */ -{ - CURLcode result = CURLE_RECV_ERROR; - ssize_t nread = 0; - size_t bytesfromsocket = 0; - char *buffertofill = NULL; - struct Curl_easy *data = conn->data; - - /* if HTTP/1 pipelining is both wanted and possible */ - bool pipelining = Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) && - (conn->bundle->multiuse == BUNDLE_PIPELINING); - - /* Set 'num' to 0 or 1, depending on which socket that has been sent here. - If it is the second socket, we set num to 1. Otherwise to 0. This lets - us use the correct ssl handle. */ - int num = (sockfd == conn->sock[SECONDARYSOCKET]); - - *n = 0; /* reset amount to zero */ - - /* If session can pipeline, check connection buffer */ - if(pipelining) { - size_t bytestocopy = CURLMIN(conn->buf_len - conn->read_pos, - sizerequested); - - /* Copy from our master buffer first if we have some unread data there*/ - if(bytestocopy > 0) { - memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy); - conn->read_pos += bytestocopy; - conn->bits.stream_was_rewound = FALSE; - - *n = (ssize_t)bytestocopy; - return CURLE_OK; - } - /* If we come here, it means that there is no data to read from the buffer, - * so we read from the socket */ - bytesfromsocket = CURLMIN(sizerequested, MASTERBUF_SIZE); - buffertofill = conn->master_buffer; - } - else { - bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size); - buffertofill = buf; - } - - nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result); - if(nread < 0) - return result; - - if(pipelining) { - memcpy(buf, conn->master_buffer, nread); - conn->buf_len = nread; - conn->read_pos = nread; - } - - *n += nread; - - return CURLE_OK; -} - -/* return 0 on success */ -static int showit(struct Curl_easy *data, curl_infotype type, - char *ptr, size_t size) -{ - static const char s_infotype[CURLINFO_END][3] = { - "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; - int rc = 0; - -#ifdef CURL_DOES_CONVERSIONS - char *buf = NULL; - size_t conv_size = 0; - - switch(type) { - case CURLINFO_HEADER_OUT: - buf = Curl_memdup(ptr, size); - if(!buf) - return 1; - conv_size = size; - - /* Special processing is needed for this block if it - * contains both headers and data (separated by CRLFCRLF). - * We want to convert just the headers, leaving the data as-is. - */ - if(size > 4) { - size_t i; - for(i = 0; i < size-4; i++) { - if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) { - /* convert everything through this CRLFCRLF but no further */ - conv_size = i + 4; - break; - } - } - } - - Curl_convert_from_network(data, buf, conv_size); - /* Curl_convert_from_network calls failf if unsuccessful */ - /* we might as well continue even if it fails... */ - ptr = buf; /* switch pointer to use my buffer instead */ - break; - default: - /* leave everything else as-is */ - break; - } -#endif /* CURL_DOES_CONVERSIONS */ - - if(data->set.fdebug) - rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata); - else { - switch(type) { - case CURLINFO_TEXT: - case CURLINFO_HEADER_OUT: - case CURLINFO_HEADER_IN: - fwrite(s_infotype[type], 2, 1, data->set.err); - fwrite(ptr, size, 1, data->set.err); -#ifdef CURL_DOES_CONVERSIONS - if(size != conv_size) { - /* we had untranslated data so we need an explicit newline */ - fwrite("\n", 1, 1, data->set.err); - } -#endif - break; - default: /* nada */ - break; - } - } -#ifdef CURL_DOES_CONVERSIONS - free(buf); -#endif - return rc; -} - -int Curl_debug(struct Curl_easy *data, curl_infotype type, - char *ptr, size_t size, - struct connectdata *conn) -{ - int rc; - if(data->set.printhost && conn && conn->host.dispname) { - char buffer[160]; - const char *t = NULL; - const char *w = "Data"; - switch(type) { - case CURLINFO_HEADER_IN: - w = "Header"; - /* FALLTHROUGH */ - case CURLINFO_DATA_IN: - t = "from"; - break; - case CURLINFO_HEADER_OUT: - w = "Header"; - /* FALLTHROUGH */ - case CURLINFO_DATA_OUT: - t = "to"; - break; - default: - break; - } - - if(t) { - snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t, - conn->host.dispname); - rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer)); - if(rc) - return rc; - } - } - rc = showit(data, type, ptr, size); - return rc; -} diff --git a/dep/cpr/opt/curl/lib/sendf.h b/dep/cpr/opt/curl/lib/sendf.h deleted file mode 100644 index fbe4f99c87e..00000000000 --- a/dep/cpr/opt/curl/lib/sendf.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef HEADER_CURL_SENDF_H -#define HEADER_CURL_SENDF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *, - const char *fmt, ...); -void Curl_infof(struct Curl_easy *, const char *fmt, ...); -void Curl_failf(struct Curl_easy *, const char *fmt, ...); - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - -#if defined(HAVE_VARIADIC_MACROS_C99) -#define infof(...) Curl_nop_stmt -#elif defined(HAVE_VARIADIC_MACROS_GCC) -#define infof(x...) Curl_nop_stmt -#else -#define infof (void) -#endif - -#else /* CURL_DISABLE_VERBOSE_STRINGS */ - -#define infof Curl_infof - -#endif /* CURL_DISABLE_VERBOSE_STRINGS */ - -#define failf Curl_failf - -#define CLIENTWRITE_BODY (1<<0) -#define CLIENTWRITE_HEADER (1<<1) -#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) - -CURLcode Curl_client_chop_write(struct connectdata *conn, int type, char *ptr, - size_t len) WARN_UNUSED_RESULT; -CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, - size_t len) WARN_UNUSED_RESULT; - -bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex); - -/* internal read-function, does plain socket only */ -CURLcode Curl_read_plain(curl_socket_t sockfd, - char *buf, - size_t bytesfromsocket, - ssize_t *n); - -ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, - size_t len, CURLcode *code); -ssize_t Curl_send_plain(struct connectdata *conn, int num, - const void *mem, size_t len, CURLcode *code); - -/* internal read-function, does plain socket, SSL and krb4 */ -CURLcode Curl_read(struct connectdata *conn, curl_socket_t sockfd, - char *buf, size_t buffersize, - ssize_t *n); -/* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */ -CURLcode Curl_write(struct connectdata *conn, - curl_socket_t sockfd, - const void *mem, size_t len, - ssize_t *written); - -/* internal write-function, does plain sockets ONLY */ -CURLcode Curl_write_plain(struct connectdata *conn, - curl_socket_t sockfd, - const void *mem, size_t len, - ssize_t *written); - -/* the function used to output verbose information */ -int Curl_debug(struct Curl_easy *handle, curl_infotype type, - char *data, size_t size, - struct connectdata *conn); - - -#endif /* HEADER_CURL_SENDF_H */ diff --git a/dep/cpr/opt/curl/lib/setup-os400.h b/dep/cpr/opt/curl/lib/setup-os400.h deleted file mode 100644 index a3c2a7bdc99..00000000000 --- a/dep/cpr/opt/curl/lib/setup-os400.h +++ /dev/null @@ -1,223 +0,0 @@ -#ifndef HEADER_CURL_SETUP_OS400_H -#define HEADER_CURL_SETUP_OS400_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - - -/* OS/400 netdb.h does not define NI_MAXHOST. */ -#define NI_MAXHOST 1025 - -/* OS/400 netdb.h does not define NI_MAXSERV. */ -#define NI_MAXSERV 32 - -/* No OS/400 header file defines u_int32_t. */ -typedef unsigned long u_int32_t; - - -/* System API wrapper prototypes & definitions to support ASCII parameters. */ - -#include -#include -#include -#include -#include - -extern int Curl_getaddrinfo_a(const char *nodename, - const char *servname, - const struct addrinfo *hints, - struct addrinfo **res); -#define getaddrinfo Curl_getaddrinfo_a - - -extern int Curl_getnameinfo_a(const struct sockaddr *sa, - curl_socklen_t salen, - char *nodename, curl_socklen_t nodenamelen, - char *servname, curl_socklen_t servnamelen, - int flags); -#define getnameinfo Curl_getnameinfo_a - - -/* GSKit wrappers. */ - -extern int Curl_gsk_environment_open(gsk_handle * my_env_handle); -#define gsk_environment_open Curl_gsk_environment_open - -extern int Curl_gsk_secure_soc_open(gsk_handle my_env_handle, - gsk_handle * my_session_handle); -#define gsk_secure_soc_open Curl_gsk_secure_soc_open - -extern int Curl_gsk_environment_close(gsk_handle * my_env_handle); -#define gsk_environment_close Curl_gsk_environment_close - -extern int Curl_gsk_secure_soc_close(gsk_handle * my_session_handle); -#define gsk_secure_soc_close Curl_gsk_secure_soc_close - -extern int Curl_gsk_environment_init(gsk_handle my_env_handle); -#define gsk_environment_init Curl_gsk_environment_init - -extern int Curl_gsk_secure_soc_init(gsk_handle my_session_handle); -#define gsk_secure_soc_init Curl_gsk_secure_soc_init - -extern int Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle, - GSK_BUF_ID bufID, - const char *buffer, - int bufSize); -#define gsk_attribute_set_buffer Curl_gsk_attribute_set_buffer_a - -extern int Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle, - GSK_ENUM_ID enumID, - GSK_ENUM_VALUE enumValue); -#define gsk_attribute_set_enum Curl_gsk_attribute_set_enum - -extern int Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle, - GSK_NUM_ID numID, - int numValue); -#define gsk_attribute_set_numeric_value Curl_gsk_attribute_set_numeric_value - -extern int Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle, - GSK_CALLBACK_ID callBackID, - void *callBackAreaPtr); -#define gsk_attribute_set_callback Curl_gsk_attribute_set_callback - -extern int Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle, - GSK_BUF_ID bufID, - const char **buffer, - int *bufSize); -#define gsk_attribute_get_buffer Curl_gsk_attribute_get_buffer_a - -extern int Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle, - GSK_ENUM_ID enumID, - GSK_ENUM_VALUE *enumValue); -#define gsk_attribute_get_enum Curl_gsk_attribute_get_enum - -extern int Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle, - GSK_NUM_ID numID, - int *numValue); -#define gsk_attribute_get_numeric_value Curl_gsk_attribute_get_numeric_value - -extern int Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle, - GSK_CERT_ID certID, - const gsk_cert_data_elem **certDataElem, - int *certDataElementCount); -#define gsk_attribute_get_cert_info Curl_gsk_attribute_get_cert_info - -extern int Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, - GSK_MISC_ID miscID); -#define gsk_secure_soc_misc Curl_gsk_secure_soc_misc - -extern int Curl_gsk_secure_soc_read(gsk_handle my_session_handle, - char *readBuffer, - int readBufSize, int *amtRead); -#define gsk_secure_soc_read Curl_gsk_secure_soc_read - -extern int Curl_gsk_secure_soc_write(gsk_handle my_session_handle, - char *writeBuffer, - int writeBufSize, int *amtWritten); -#define gsk_secure_soc_write Curl_gsk_secure_soc_write - -extern const char * Curl_gsk_strerror_a(int gsk_return_value); -#define gsk_strerror Curl_gsk_strerror_a - -extern int Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle, - int IOCompletionPort, - Qso_OverlappedIO_t * communicationsArea); -#define gsk_secure_soc_startInit Curl_gsk_secure_soc_startInit - - -/* GSSAPI wrappers. */ - -extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status, - gss_buffer_t in_name, - gss_OID in_name_type, - gss_name_t * out_name); -#define gss_import_name Curl_gss_import_name_a - - -extern OM_uint32 Curl_gss_display_status_a(OM_uint32 * minor_status, - OM_uint32 status_value, - int status_type, gss_OID mech_type, - gss_msg_ctx_t * message_context, - gss_buffer_t status_string); -#define gss_display_status Curl_gss_display_status_a - - -extern OM_uint32 Curl_gss_init_sec_context_a(OM_uint32 * minor_status, - gss_cred_id_t cred_handle, - gss_ctx_id_t * context_handle, - gss_name_t target_name, - gss_OID mech_type, - gss_flags_t req_flags, - OM_uint32 time_req, - gss_channel_bindings_t - input_chan_bindings, - gss_buffer_t input_token, - gss_OID * actual_mech_type, - gss_buffer_t output_token, - gss_flags_t * ret_flags, - OM_uint32 * time_rec); -#define gss_init_sec_context Curl_gss_init_sec_context_a - - -extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status, - gss_ctx_id_t * context_handle, - gss_buffer_t output_token); -#define gss_delete_sec_context Curl_gss_delete_sec_context_a - - -/* LDAP wrappers. */ - -#define BerValue struct berval - -#define ldap_url_parse ldap_url_parse_utf8 -#define ldap_init Curl_ldap_init_a -#define ldap_simple_bind_s Curl_ldap_simple_bind_s_a -#define ldap_search_s Curl_ldap_search_s_a -#define ldap_get_values_len Curl_ldap_get_values_len_a -#define ldap_err2string Curl_ldap_err2string_a -#define ldap_get_dn Curl_ldap_get_dn_a -#define ldap_first_attribute Curl_ldap_first_attribute_a -#define ldap_next_attribute Curl_ldap_next_attribute_a - -/* Some socket functions must be wrapped to process textual addresses - like AF_UNIX. */ - -extern int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen); -extern int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen); -extern int Curl_os400_sendto(int sd, char *buffer, int buflen, int flags, - struct sockaddr * dstaddr, int addrlen); -extern int Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags, - struct sockaddr *fromaddr, int *addrlen); - -#define connect Curl_os400_connect -#define bind Curl_os400_bind -#define sendto Curl_os400_sendto -#define recvfrom Curl_os400_recvfrom - -#ifdef HAVE_LIBZ -#define zlibVersion Curl_os400_zlibVersion -#define inflateInit_ Curl_os400_inflateInit_ -#define inflateInit2_ Curl_os400_inflateInit2_ -#define inflate Curl_os400_inflate -#define inflateEnd Curl_os400_inflateEnd -#endif - -#endif /* HEADER_CURL_SETUP_OS400_H */ diff --git a/dep/cpr/opt/curl/lib/setup-vms.h b/dep/cpr/opt/curl/lib/setup-vms.h deleted file mode 100644 index 6c454aee682..00000000000 --- a/dep/cpr/opt/curl/lib/setup-vms.h +++ /dev/null @@ -1,443 +0,0 @@ -#ifndef HEADER_CURL_SETUP_VMS_H -#define HEADER_CURL_SETUP_VMS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* */ -/* JEM, 12/30/12, VMS now generates config.h, so only define wrappers for */ -/* getenv(), getpwuid() and provide is_vms_shell() */ -/* Also need upper case symbols for system services, and */ -/* OpenSSL, and some Kerberos image */ - -#ifdef __DECC -#pragma message save -#pragma message disable dollarid -#endif - -/* Hide the stuff we are overriding */ -#define getenv decc_getenv -#ifdef __DECC -# if __INITIAL_POINTER_SIZE != 64 -# define getpwuid decc_getpwuid -# endif -#endif -#include -char *decc$getenv(const char *__name); -#include - -#include -#include - -#undef getenv -#undef getpwuid -#define getenv vms_getenv -#define getpwuid vms_getpwuid - -/* VAX needs these in upper case when compiling exact case */ -#define sys$assign SYS$ASSIGN -#define sys$dassgn SYS$DASSGN -#define sys$qiow SYS$QIOW - -#ifdef __DECC -# if __INITIAL_POINTER_SIZE -# pragma __pointer_size __save -# endif -#endif - -#if __USE_LONG_GID_T -# define decc_getpwuid DECC$__LONG_GID_GETPWUID -#else -# if __INITIAL_POINTER_SIZE -# define decc_getpwuid decc$__32_getpwuid -# else -# define decc_getpwuid decc$getpwuid -# endif -#endif - - struct passwd * decc_getpwuid(uid_t uid); - -#ifdef __DECC -# if __INITIAL_POINTER_SIZE == 32 -/* Translate the path, but only if the path is a VMS file specification */ -/* The translation is usually only needed for older versions of VMS */ -static char *vms_translate_path(const char *path) -{ - char *unix_path; - char *test_str; - - /* See if the result is in VMS format, if not, we are done */ - /* Assume that this is a PATH, not just some data */ - test_str = strpbrk(path, ":[<^"); - if(test_str == NULL) { - return (char *)path; - } - - unix_path = decc$translate_vms(path); - - if((int)unix_path <= 0) { - /* We can not translate it, so return the original string */ - return (char *)path; - } -} -# else - /* VMS translate path is actually not needed on the current 64 bit */ - /* VMS platforms, so instead of figuring out the pointer settings */ - /* Change it to a noop */ -# define vms_translate_path(__path) __path -# endif -#endif - -#ifdef __DECC -# if __INITIAL_POINTER_SIZE -# pragma __pointer_size __restore -# endif -#endif - -static char *vms_getenv(const char *envvar) -{ - char *result; - char *vms_path; - - /* first use the DECC getenv() function */ - result = decc$getenv(envvar); - if(result == NULL) { - return result; - } - - vms_path = result; - result = vms_translate_path(vms_path); - - /* note that if you backport this to use VAX C RTL, that the VAX C RTL */ - /* may do a malloc(2048) for each call to getenv(), so you will need */ - /* to add a free(vms_path) */ - /* Do not do a free() for DEC C RTL builds, which should be used for */ - /* VMS 5.5-2 and later, even if using GCC */ - - return result; -} - - -static struct passwd vms_passwd_cache; - -static struct passwd * vms_getpwuid(uid_t uid) -{ - struct passwd * my_passwd; - -/* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */ -#ifdef __DECC -# if __INITIAL_POINTER_SIZE - __char_ptr32 unix_path; -# else - char *unix_path; -# endif -#else - char *unix_path; -#endif - - my_passwd = decc_getpwuid(uid); - if(my_passwd == NULL) { - return my_passwd; - } - - unix_path = vms_translate_path(my_passwd->pw_dir); - - if((long)unix_path <= 0) { - /* We can not translate it, so return the original string */ - return my_passwd; - } - - /* If no changes needed just return it */ - if(unix_path == my_passwd->pw_dir) { - return my_passwd; - } - - /* Need to copy the structure returned */ - /* Since curl is only using pw_dir, no need to fix up */ - /* the pw_shell when running under Bash */ - vms_passwd_cache.pw_name = my_passwd->pw_name; - vms_passwd_cache.pw_uid = my_passwd->pw_uid; - vms_passwd_cache.pw_gid = my_passwd->pw_uid; - vms_passwd_cache.pw_dir = unix_path; - vms_passwd_cache.pw_shell = my_passwd->pw_shell; - - return &vms_passwd_cache; -} - -#ifdef __DECC -#pragma message restore -#endif - -/* Bug - VMS OpenSSL and Kerberos universal symbols are in uppercase only */ -/* VMS libraries should have universal symbols in exact and uppercase */ - -#define ASN1_INTEGER_get ASN1_INTEGER_GET -#define ASN1_STRING_data ASN1_STRING_DATA -#define ASN1_STRING_length ASN1_STRING_LENGTH -#define ASN1_STRING_print ASN1_STRING_PRINT -#define ASN1_STRING_to_UTF8 ASN1_STRING_TO_UTF8 -#define ASN1_STRING_type ASN1_STRING_TYPE -#define BIO_ctrl BIO_CTRL -#define BIO_free BIO_FREE -#define BIO_new BIO_NEW -#define BIO_s_mem BIO_S_MEM -#define BN_bn2bin BN_BN2BIN -#define BN_num_bits BN_NUM_BITS -#define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA -#define CRYPTO_free CRYPTO_FREE -#define CRYPTO_malloc CRYPTO_MALLOC -#define CONF_modules_load_file CONF_MODULES_LOAD_FILE -#ifdef __VAX -# ifdef VMS_OLD_SSL - /* Ancient OpenSSL on VAX/VMS missing this constant */ -# define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10 -# undef CONF_modules_load_file - static int CONF_modules_load_file(const char *filename, - const char *appname, - unsigned long flags) { - return 1; - } -# endif -#endif -#define DES_ecb_encrypt DES_ECB_ENCRYPT -#define DES_set_key DES_SET_KEY -#define DES_set_odd_parity DES_SET_ODD_PARITY -#define ENGINE_ctrl ENGINE_CTRL -#define ENGINE_ctrl_cmd ENGINE_CTRL_CMD -#define ENGINE_finish ENGINE_FINISH -#define ENGINE_free ENGINE_FREE -#define ENGINE_get_first ENGINE_GET_FIRST -#define ENGINE_get_id ENGINE_GET_ID -#define ENGINE_get_next ENGINE_GET_NEXT -#define ENGINE_init ENGINE_INIT -#define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES -#define ENGINE_load_private_key ENGINE_LOAD_PRIVATE_KEY -#define ENGINE_set_default ENGINE_SET_DEFAULT -#define ERR_clear_error ERR_CLEAR_ERROR -#define ERR_error_string ERR_ERROR_STRING -#define ERR_error_string_n ERR_ERROR_STRING_N -#define ERR_free_strings ERR_FREE_STRINGS -#define ERR_get_error ERR_GET_ERROR -#define ERR_peek_error ERR_PEEK_ERROR -#define ERR_remove_state ERR_REMOVE_STATE -#define EVP_PKEY_copy_parameters EVP_PKEY_COPY_PARAMETERS -#define EVP_PKEY_free EVP_PKEY_FREE -#define EVP_cleanup EVP_CLEANUP -#define GENERAL_NAMES_free GENERAL_NAMES_FREE -#define i2d_X509_PUBKEY I2D_X509_PUBKEY -#define MD4_Final MD4_FINAL -#define MD4_Init MD4_INIT -#define MD4_Update MD4_UPDATE -#define MD5_Final MD5_FINAL -#define MD5_Init MD5_INIT -#define MD5_Update MD5_UPDATE -#define OPENSSL_add_all_algo_noconf OPENSSL_ADD_ALL_ALGO_NOCONF -#ifndef __VAX -#define OPENSSL_load_builtin_modules OPENSSL_LOAD_BUILTIN_MODULES -#endif -#define PEM_read_X509 PEM_READ_X509 -#define PEM_write_bio_X509 PEM_WRITE_BIO_X509 -#define PKCS12_PBE_add PKCS12_PBE_ADD -#define PKCS12_free PKCS12_FREE -#define PKCS12_parse PKCS12_PARSE -#define RAND_add RAND_ADD -#define RAND_bytes RAND_BYTES -#define RAND_egd RAND_EGD -#define RAND_file_name RAND_FILE_NAME -#define RAND_load_file RAND_LOAD_FILE -#define RAND_status RAND_STATUS -#define SSL_CIPHER_get_name SSL_CIPHER_GET_NAME -#define SSL_CTX_add_client_CA SSL_CTX_ADD_CLIENT_CA -#define SSL_CTX_callback_ctrl SSL_CTX_CALLBACK_CTRL -#define SSL_CTX_check_private_key SSL_CTX_CHECK_PRIVATE_KEY -#define SSL_CTX_ctrl SSL_CTX_CTRL -#define SSL_CTX_free SSL_CTX_FREE -#define SSL_CTX_get_cert_store SSL_CTX_GET_CERT_STORE -#define SSL_CTX_load_verify_locations SSL_CTX_LOAD_VERIFY_LOCATIONS -#define SSL_CTX_new SSL_CTX_NEW -#define SSL_CTX_set_cipher_list SSL_CTX_SET_CIPHER_LIST -#define SSL_CTX_set_def_passwd_cb_ud SSL_CTX_SET_DEF_PASSWD_CB_UD -#define SSL_CTX_set_default_passwd_cb SSL_CTX_SET_DEFAULT_PASSWD_CB -#define SSL_CTX_set_msg_callback SSL_CTX_SET_MSG_CALLBACK -#define SSL_CTX_set_verify SSL_CTX_SET_VERIFY -#define SSL_CTX_use_PrivateKey SSL_CTX_USE_PRIVATEKEY -#define SSL_CTX_use_PrivateKey_file SSL_CTX_USE_PRIVATEKEY_FILE -#define SSL_CTX_use_cert_chain_file SSL_CTX_USE_CERT_CHAIN_FILE -#define SSL_CTX_use_certificate SSL_CTX_USE_CERTIFICATE -#define SSL_CTX_use_certificate_file SSL_CTX_USE_CERTIFICATE_FILE -#define SSL_SESSION_free SSL_SESSION_FREE -#define SSL_connect SSL_CONNECT -#define SSL_free SSL_FREE -#define SSL_get1_session SSL_GET1_SESSION -#define SSL_get_certificate SSL_GET_CERTIFICATE -#define SSL_get_current_cipher SSL_GET_CURRENT_CIPHER -#define SSL_get_error SSL_GET_ERROR -#define SSL_get_peer_cert_chain SSL_GET_PEER_CERT_CHAIN -#define SSL_get_peer_certificate SSL_GET_PEER_CERTIFICATE -#define SSL_get_privatekey SSL_GET_PRIVATEKEY -#define SSL_get_session SSL_GET_SESSION -#define SSL_get_shutdown SSL_GET_SHUTDOWN -#define SSL_get_verify_result SSL_GET_VERIFY_RESULT -#define SSL_library_init SSL_LIBRARY_INIT -#define SSL_load_error_strings SSL_LOAD_ERROR_STRINGS -#define SSL_new SSL_NEW -#define SSL_peek SSL_PEEK -#define SSL_pending SSL_PENDING -#define SSL_read SSL_READ -#define SSL_set_connect_state SSL_SET_CONNECT_STATE -#define SSL_set_fd SSL_SET_FD -#define SSL_set_session SSL_SET_SESSION -#define SSL_shutdown SSL_SHUTDOWN -#define SSL_version SSL_VERSION -#define SSL_write SSL_WRITE -#define SSLeay SSLEAY -#define SSLv23_client_method SSLV23_CLIENT_METHOD -#define SSLv3_client_method SSLV3_CLIENT_METHOD -#define TLSv1_client_method TLSV1_CLIENT_METHOD -#define UI_create_method UI_CREATE_METHOD -#define UI_destroy_method UI_DESTROY_METHOD -#define UI_get0_user_data UI_GET0_USER_DATA -#define UI_get_input_flags UI_GET_INPUT_FLAGS -#define UI_get_string_type UI_GET_STRING_TYPE -#define UI_create_method UI_CREATE_METHOD -#define UI_destroy_method UI_DESTROY_METHOD -#define UI_method_get_closer UI_METHOD_GET_CLOSER -#define UI_method_get_opener UI_METHOD_GET_OPENER -#define UI_method_get_reader UI_METHOD_GET_READER -#define UI_method_get_writer UI_METHOD_GET_WRITER -#define UI_method_set_closer UI_METHOD_SET_CLOSER -#define UI_method_set_opener UI_METHOD_SET_OPENER -#define UI_method_set_reader UI_METHOD_SET_READER -#define UI_method_set_writer UI_METHOD_SET_WRITER -#define UI_OpenSSL UI_OPENSSL -#define UI_set_result UI_SET_RESULT -#define X509V3_EXT_print X509V3_EXT_PRINT -#define X509_EXTENSION_get_critical X509_EXTENSION_GET_CRITICAL -#define X509_EXTENSION_get_data X509_EXTENSION_GET_DATA -#define X509_EXTENSION_get_object X509_EXTENSION_GET_OBJECT -#define X509_LOOKUP_file X509_LOOKUP_FILE -#define X509_NAME_ENTRY_get_data X509_NAME_ENTRY_GET_DATA -#define X509_NAME_get_entry X509_NAME_GET_ENTRY -#define X509_NAME_get_index_by_NID X509_NAME_GET_INDEX_BY_NID -#define X509_NAME_print_ex X509_NAME_PRINT_EX -#define X509_STORE_CTX_get_current_cert X509_STORE_CTX_GET_CURRENT_CERT -#define X509_STORE_add_lookup X509_STORE_ADD_LOOKUP -#define X509_STORE_set_flags X509_STORE_SET_FLAGS -#define X509_check_issued X509_CHECK_ISSUED -#define X509_free X509_FREE -#define X509_get_ext_d2i X509_GET_EXT_D2I -#define X509_get_issuer_name X509_GET_ISSUER_NAME -#define X509_get_pubkey X509_GET_PUBKEY -#define X509_get_serialNumber X509_GET_SERIALNUMBER -#define X509_get_subject_name X509_GET_SUBJECT_NAME -#define X509_load_crl_file X509_LOAD_CRL_FILE -#define X509_verify_cert_error_string X509_VERIFY_CERT_ERROR_STRING -#define d2i_PKCS12_fp D2I_PKCS12_FP -#define i2t_ASN1_OBJECT I2T_ASN1_OBJECT -#define sk_num SK_NUM -#define sk_pop SK_POP -#define sk_pop_free SK_POP_FREE -#define sk_value SK_VALUE -#ifdef __VAX -#define OPENSSL_NO_SHA256 -#endif -#define SHA256_Final SHA256_FINAL -#define SHA256_Init SHA256_INIT -#define SHA256_Update SHA256_UPDATE - -#define USE_UPPERCASE_GSSAPI 1 -#define gss_seal GSS_SEAL -#define gss_unseal GSS_UNSEAL - -#define USE_UPPERCASE_KRBAPI 1 - -/* AI_NUMERICHOST needed for IP V6 support in Curl */ -#ifdef HAVE_NETDB_H -#include -#ifndef AI_NUMERICHOST -#ifdef ENABLE_IPV6 -#undef ENABLE_IPV6 -#endif -#endif -#endif - -/* VAX symbols are always in uppercase */ -#ifdef __VAX -#define inflate INFLATE -#define inflateEnd INFLATEEND -#define inflateInit2_ INFLATEINIT2_ -#define inflateInit_ INFLATEINIT_ -#define zlibVersion ZLIBVERSION -#endif - -/* Older VAX OpenSSL port defines these as Macros */ -/* Need to include the headers first and then redefine */ -/* that way a newer port will also work if some one has one */ -#ifdef __VAX - -# if (OPENSSL_VERSION_NUMBER < 0x00907001L) -# define des_set_odd_parity DES_SET_ODD_PARITY -# define des_set_key DES_SET_KEY -# define des_ecb_encrypt DES_ECB_ENCRYPT - -# endif -# include -# ifndef OpenSSL_add_all_algorithms -# define OpenSSL_add_all_algorithms OPENSSL_ADD_ALL_ALGORITHMS - void OPENSSL_ADD_ALL_ALGORITHMS(void); -# endif - - /* Curl defines these to lower case and VAX needs them in upper case */ - /* So we need static routines */ -# if (OPENSSL_VERSION_NUMBER < 0x00907001L) - -# undef des_set_odd_parity -# undef DES_set_odd_parity -# undef des_set_key -# undef DES_set_key -# undef des_ecb_encrypt -# undef DES_ecb_encrypt - - static void des_set_odd_parity(des_cblock *key) { - DES_SET_ODD_PARITY(key); - } - - static int des_set_key(const_des_cblock *key, - des_key_schedule schedule) { - return DES_SET_KEY(key, schedule); - } - - static void des_ecb_encrypt(const_des_cblock *input, - des_cblock *output, - des_key_schedule ks, int enc) { - DES_ECB_ENCRYPT(input, output, ks, enc); - } -#endif -/* Need this to stop a macro redefinition error */ -#if OPENSSL_VERSION_NUMBER < 0x00907000L -# ifdef X509_STORE_set_flags -# undef X509_STORE_set_flags -# define X509_STORE_set_flags(x,y) Curl_nop_stmt -# endif -#endif -#endif - -#endif /* HEADER_CURL_SETUP_VMS_H */ diff --git a/dep/cpr/opt/curl/lib/share.c b/dep/cpr/opt/curl/lib/share.c deleted file mode 100644 index 5b3957fcfb1..00000000000 --- a/dep/cpr/opt/curl/lib/share.c +++ /dev/null @@ -1,244 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include -#include "urldata.h" -#include "share.h" -#include "vtls/vtls.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -struct Curl_share * -curl_share_init(void) -{ - struct Curl_share *share = calloc(1, sizeof(struct Curl_share)); - if(share) { - share->specifier |= (1<hostcache)) { - free(share); - return NULL; - } - } - - return share; -} - -#undef curl_share_setopt -CURLSHcode -curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) -{ - va_list param; - int type; - curl_lock_function lockfunc; - curl_unlock_function unlockfunc; - void *ptr; - CURLSHcode res = CURLSHE_OK; - - if(share->dirty) - /* don't allow setting options while one or more handles are already - using this share */ - return CURLSHE_IN_USE; - - va_start(param, option); - - switch(option) { - case CURLSHOPT_SHARE: - /* this is a type this share will share */ - type = va_arg(param, int); - share->specifier |= (1<cookies) { - share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE); - if(!share->cookies) - res = CURLSHE_NOMEM; - } -#else /* CURL_DISABLE_HTTP */ - res = CURLSHE_NOT_BUILT_IN; -#endif - break; - - case CURL_LOCK_DATA_SSL_SESSION: -#ifdef USE_SSL - if(!share->sslsession) { - share->max_ssl_sessions = 8; - share->sslsession = calloc(share->max_ssl_sessions, - sizeof(struct curl_ssl_session)); - share->sessionage = 0; - if(!share->sslsession) - res = CURLSHE_NOMEM; - } -#else - res = CURLSHE_NOT_BUILT_IN; -#endif - break; - - case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */ - break; - - default: - res = CURLSHE_BAD_OPTION; - } - break; - - case CURLSHOPT_UNSHARE: - /* this is a type this share will no longer share */ - type = va_arg(param, int); - share->specifier &= ~(1<cookies) { - Curl_cookie_cleanup(share->cookies); - share->cookies = NULL; - } -#else /* CURL_DISABLE_HTTP */ - res = CURLSHE_NOT_BUILT_IN; -#endif - break; - - case CURL_LOCK_DATA_SSL_SESSION: -#ifdef USE_SSL - Curl_safefree(share->sslsession); -#else - res = CURLSHE_NOT_BUILT_IN; -#endif - break; - - case CURL_LOCK_DATA_CONNECT: - break; - - default: - res = CURLSHE_BAD_OPTION; - break; - } - break; - - case CURLSHOPT_LOCKFUNC: - lockfunc = va_arg(param, curl_lock_function); - share->lockfunc = lockfunc; - break; - - case CURLSHOPT_UNLOCKFUNC: - unlockfunc = va_arg(param, curl_unlock_function); - share->unlockfunc = unlockfunc; - break; - - case CURLSHOPT_USERDATA: - ptr = va_arg(param, void *); - share->clientdata = ptr; - break; - - default: - res = CURLSHE_BAD_OPTION; - break; - } - - va_end(param); - - return res; -} - -CURLSHcode -curl_share_cleanup(struct Curl_share *share) -{ - if(share == NULL) - return CURLSHE_INVALID; - - if(share->lockfunc) - share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE, - share->clientdata); - - if(share->dirty) { - if(share->unlockfunc) - share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); - return CURLSHE_IN_USE; - } - - Curl_hash_destroy(&share->hostcache); - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - Curl_cookie_cleanup(share->cookies); -#endif - -#ifdef USE_SSL - if(share->sslsession) { - size_t i; - for(i = 0; i < share->max_ssl_sessions; i++) - Curl_ssl_kill_session(&(share->sslsession[i])); - free(share->sslsession); - } -#endif - - if(share->unlockfunc) - share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); - free(share); - - return CURLSHE_OK; -} - - -CURLSHcode -Curl_share_lock(struct Curl_easy *data, curl_lock_data type, - curl_lock_access accesstype) -{ - struct Curl_share *share = data->share; - - if(share == NULL) - return CURLSHE_INVALID; - - if(share->specifier & (1<lockfunc) /* only call this if set! */ - share->lockfunc(data, type, accesstype, share->clientdata); - } - /* else if we don't share this, pretend successful lock */ - - return CURLSHE_OK; -} - -CURLSHcode -Curl_share_unlock(struct Curl_easy *data, curl_lock_data type) -{ - struct Curl_share *share = data->share; - - if(share == NULL) - return CURLSHE_INVALID; - - if(share->specifier & (1<unlockfunc) /* only call this if set! */ - share->unlockfunc (data, type, share->clientdata); - } - - return CURLSHE_OK; -} diff --git a/dep/cpr/opt/curl/lib/share.h b/dep/cpr/opt/curl/lib/share.h deleted file mode 100644 index c039a16cb7f..00000000000 --- a/dep/cpr/opt/curl/lib/share.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef HEADER_CURL_SHARE_H -#define HEADER_CURL_SHARE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" -#include -#include "cookie.h" -#include "urldata.h" - -/* SalfordC says "A structure member may not be volatile". Hence: - */ -#ifdef __SALFORDC__ -#define CURL_VOLATILE -#else -#define CURL_VOLATILE volatile -#endif - -/* this struct is libcurl-private, don't export details */ -struct Curl_share { - unsigned int specifier; - CURL_VOLATILE unsigned int dirty; - - curl_lock_function lockfunc; - curl_unlock_function unlockfunc; - void *clientdata; - - struct curl_hash hostcache; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - struct CookieInfo *cookies; -#endif - - struct curl_ssl_session *sslsession; - size_t max_ssl_sessions; - long sessionage; -}; - -CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data, - curl_lock_access); -CURLSHcode Curl_share_unlock(struct Curl_easy *, curl_lock_data); - -#endif /* HEADER_CURL_SHARE_H */ diff --git a/dep/cpr/opt/curl/lib/sigpipe.h b/dep/cpr/opt/curl/lib/sigpipe.h deleted file mode 100644 index 800f9d3b4dd..00000000000 --- a/dep/cpr/opt/curl/lib/sigpipe.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef HEADER_CURL_SIGPIPE_H -#define HEADER_CURL_SIGPIPE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && defined(USE_OPENSSL) -#include - -struct sigpipe_ignore { - struct sigaction old_pipe_act; - bool no_signal; -}; - -#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x - -/* - * sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl - * internals, and then sigpipe_restore() will restore the situation when we - * return from libcurl again. - */ -static void sigpipe_ignore(struct Curl_easy *data, - struct sigpipe_ignore *ig) -{ - /* get a local copy of no_signal because the Curl_easy might not be - around when we restore */ - ig->no_signal = data->set.no_signal; - if(!data->set.no_signal) { - struct sigaction action; - /* first, extract the existing situation */ - memset(&ig->old_pipe_act, 0, sizeof(struct sigaction)); - sigaction(SIGPIPE, NULL, &ig->old_pipe_act); - action = ig->old_pipe_act; - /* ignore this signal */ - action.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &action, NULL); - } -} - -/* - * sigpipe_restore() puts back the outside world's opinion of signal handler - * and SIGPIPE handling. It MUST only be called after a corresponding - * sigpipe_ignore() was used. - */ -static void sigpipe_restore(struct sigpipe_ignore *ig) -{ - if(!ig->no_signal) - /* restore the outside state */ - sigaction(SIGPIPE, &ig->old_pipe_act, NULL); -} - -#else -/* for systems without sigaction */ -#define sigpipe_ignore(x,y) Curl_nop_stmt -#define sigpipe_restore(x) Curl_nop_stmt -#define SIGPIPE_VARIABLE(x) -#endif - -#endif /* HEADER_CURL_SIGPIPE_H */ diff --git a/dep/cpr/opt/curl/lib/slist.c b/dep/cpr/opt/curl/lib/slist.c deleted file mode 100644 index e5adc0e71a7..00000000000 --- a/dep/cpr/opt/curl/lib/slist.c +++ /dev/null @@ -1,145 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "slist.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* returns last node in linked list */ -static struct curl_slist *slist_get_last(struct curl_slist *list) -{ - struct curl_slist *item; - - /* if caller passed us a NULL, return now */ - if(!list) - return NULL; - - /* loop through to find the last item */ - item = list; - while(item->next) { - item = item->next; - } - return item; -} - -/* - * Curl_slist_append_nodup() appends a string to the linked list. Rather than - * copying the string in dynamic storage, it takes its ownership. The string - * should have been malloc()ated. Curl_slist_append_nodup always returns - * the address of the first record, so that you can use this function as an - * initialization function as well as an append function. - * If an error occurs, NULL is returned and the string argument is NOT - * released. - */ -struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data) -{ - struct curl_slist *last; - struct curl_slist *new_item; - - DEBUGASSERT(data); - - new_item = malloc(sizeof(struct curl_slist)); - if(!new_item) - return NULL; - - new_item->next = NULL; - new_item->data = data; - - /* if this is the first item, then new_item *is* the list */ - if(!list) - return new_item; - - last = slist_get_last(list); - last->next = new_item; - return list; -} - -/* - * curl_slist_append() appends a string to the linked list. It always returns - * the address of the first record, so that you can use this function as an - * initialization function as well as an append function. If you find this - * bothersome, then simply create a separate _init function and call it - * appropriately from within the program. - */ -struct curl_slist *curl_slist_append(struct curl_slist *list, - const char *data) -{ - char *dupdata = strdup(data); - - if(!dupdata) - return NULL; - - list = Curl_slist_append_nodup(list, dupdata); - if(!list) - free(dupdata); - - return list; -} - -/* - * Curl_slist_duplicate() duplicates a linked list. It always returns the - * address of the first record of the cloned list or NULL in case of an - * error (or if the input list was NULL). - */ -struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist) -{ - struct curl_slist *outlist = NULL; - struct curl_slist *tmp; - - while(inlist) { - tmp = curl_slist_append(outlist, inlist->data); - - if(!tmp) { - curl_slist_free_all(outlist); - return NULL; - } - - outlist = tmp; - inlist = inlist->next; - } - return outlist; -} - -/* be nice and clean up resources */ -void curl_slist_free_all(struct curl_slist *list) -{ - struct curl_slist *next; - struct curl_slist *item; - - if(!list) - return; - - item = list; - do { - next = item->next; - Curl_safefree(item->data); - free(item); - item = next; - } while(next); -} - diff --git a/dep/cpr/opt/curl/lib/slist.h b/dep/cpr/opt/curl/lib/slist.h deleted file mode 100644 index b3f498c35fc..00000000000 --- a/dep/cpr/opt/curl/lib/slist.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef HEADER_CURL_SLIST_H -#define HEADER_CURL_SLIST_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Curl_slist_duplicate() duplicates a linked list. It always returns the - * address of the first record of the cloned list or NULL in case of an - * error (or if the input list was NULL). - */ -struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist); - -/* - * Curl_slist_append_nodup() takes ownership of the given string and appends - * it to the list. - */ -struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, - char *data); - -#endif /* HEADER_CURL_SLIST_H */ - diff --git a/dep/cpr/opt/curl/lib/smb.c b/dep/cpr/opt/curl/lib/smb.c deleted file mode 100644 index 13dfd514b42..00000000000 --- a/dep/cpr/opt/curl/lib/smb.c +++ /dev/null @@ -1,1005 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014, Bill Nagel , Exacq Technologies - * Copyright (C) 2016-2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ - (CURL_SIZEOF_CURL_OFF_T > 4) - -#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) - -#define BUILDING_CURL_SMB_C - -#ifdef HAVE_PROCESS_H -#include -#ifdef CURL_WINDOWS_APP -#define getpid GetCurrentProcessId -#elif !defined(MSDOS) -#define getpid _getpid -#endif -#endif - -#include "smb.h" -#include "urldata.h" -#include "sendf.h" -#include "multiif.h" -#include "connect.h" -#include "progress.h" -#include "transfer.h" -#include "vtls/vtls.h" -#include "curl_ntlm_core.h" -#include "escape.h" -#include "curl_endian.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* Local API functions */ -static CURLcode smb_setup_connection(struct connectdata *conn); -static CURLcode smb_connect(struct connectdata *conn, bool *done); -static CURLcode smb_connection_state(struct connectdata *conn, bool *done); -static CURLcode smb_request_state(struct connectdata *conn, bool *done); -static CURLcode smb_done(struct connectdata *conn, CURLcode status, - bool premature); -static CURLcode smb_disconnect(struct connectdata *conn, bool dead); -static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks); -static CURLcode smb_parse_url_path(struct connectdata *conn); - -/* - * SMB handler interface - */ -const struct Curl_handler Curl_handler_smb = { - "SMB", /* scheme */ - smb_setup_connection, /* setup_connection */ - ZERO_NULL, /* do_it */ - smb_done, /* done */ - ZERO_NULL, /* do_more */ - smb_connect, /* connect_it */ - smb_connection_state, /* connecting */ - smb_request_state, /* doing */ - smb_getsock, /* proto_getsock */ - smb_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - smb_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_SMB, /* defport */ - CURLPROTO_SMB, /* protocol */ - PROTOPT_NONE /* flags */ -}; - -#ifdef USE_SSL -/* - * SMBS handler interface - */ -const struct Curl_handler Curl_handler_smbs = { - "SMBS", /* scheme */ - smb_setup_connection, /* setup_connection */ - ZERO_NULL, /* do_it */ - smb_done, /* done */ - ZERO_NULL, /* do_more */ - smb_connect, /* connect_it */ - smb_connection_state, /* connecting */ - smb_request_state, /* doing */ - smb_getsock, /* proto_getsock */ - smb_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - smb_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_SMBS, /* defport */ - CURLPROTO_SMBS, /* protocol */ - PROTOPT_SSL /* flags */ -}; -#endif - -#define MAX_PAYLOAD_SIZE 0x8000 -#define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) -#define CLIENTNAME "curl" -#define SERVICENAME "?????" - -/* Append a string to an SMB message */ -#define MSGCAT(str) \ - strcpy(p, (str)); \ - p += strlen(str); - -/* Append a null-terminated string to an SMB message */ -#define MSGCATNULL(str) \ - strcpy(p, (str)); \ - p += strlen(str) + 1; - -/* SMB is mostly little endian */ -#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ - defined(__OS400__) -static unsigned short smb_swap16(unsigned short x) -{ - return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); -} - -static unsigned int smb_swap32(unsigned int x) -{ - return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | - ((x >> 24) & 0xff); -} - -#ifdef HAVE_LONGLONG -static unsigned long long smb_swap64(unsigned long long x) -{ - return ((unsigned long long) smb_swap32((unsigned int) x) << 32) | - smb_swap32((unsigned int) (x >> 32)); -} -#else -static unsigned __int64 smb_swap64(unsigned __int64 x) -{ - return ((unsigned __int64) smb_swap32((unsigned int) x) << 32) | - smb_swap32((unsigned int) (x >> 32)); -} -#endif -#else -# define smb_swap16(x) (x) -# define smb_swap32(x) (x) -# define smb_swap64(x) (x) -#endif - -/* SMB request state */ -enum smb_req_state { - SMB_REQUESTING, - SMB_TREE_CONNECT, - SMB_OPEN, - SMB_DOWNLOAD, - SMB_UPLOAD, - SMB_CLOSE, - SMB_TREE_DISCONNECT, - SMB_DONE -}; - -/* SMB request data */ -struct smb_request { - enum smb_req_state state; - char *share; - char *path; - unsigned short tid; /* Even if we connect to the same tree as another */ - unsigned short fid; /* request, the tid will be different */ - CURLcode result; -}; - -static void conn_state(struct connectdata *conn, enum smb_conn_state newstate) -{ - struct smb_conn *smb = &conn->proto.smbc; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* For debug purposes */ - static const char * const names[] = { - "SMB_NOT_CONNECTED", - "SMB_CONNECTING", - "SMB_NEGOTIATE", - "SMB_SETUP", - "SMB_CONNECTED", - /* LAST */ - }; - - if(smb->state != newstate) - infof(conn->data, "SMB conn %p state change from %s to %s\n", - (void *)smb, names[smb->state], names[newstate]); -#endif - - smb->state = newstate; -} - -static void request_state(struct connectdata *conn, - enum smb_req_state newstate) -{ - struct smb_request *req = conn->data->req.protop; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* For debug purposes */ - static const char * const names[] = { - "SMB_REQUESTING", - "SMB_TREE_CONNECT", - "SMB_OPEN", - "SMB_DOWNLOAD", - "SMB_UPLOAD", - "SMB_CLOSE", - "SMB_TREE_DISCONNECT", - "SMB_DONE", - /* LAST */ - }; - - if(req->state != newstate) - infof(conn->data, "SMB request %p state change from %s to %s\n", - (void *)req, names[req->state], names[newstate]); -#endif - - req->state = newstate; -} - -static CURLcode smb_setup_connection(struct connectdata *conn) -{ - struct smb_request *req; - - /* Initialize the request state */ - conn->data->req.protop = req = calloc(1, sizeof(struct smb_request)); - if(!req) - return CURLE_OUT_OF_MEMORY; - - /* Parse the URL path */ - return smb_parse_url_path(conn); -} - -static CURLcode smb_connect(struct connectdata *conn, bool *done) -{ - struct smb_conn *smbc = &conn->proto.smbc; - char *slash; - - (void) done; - - /* Check we have a username and password to authenticate with */ - if(!conn->bits.user_passwd) - return CURLE_LOGIN_DENIED; - - /* Initialize the connection state */ - memset(smbc, 0, sizeof(*smbc)); - smbc->state = SMB_CONNECTING; - smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); - if(!smbc->recv_buf) - return CURLE_OUT_OF_MEMORY; - - /* Multiple requests are allowed with this connection */ - connkeep(conn, "SMB default"); - - /* Parse the username, domain, and password */ - slash = strchr(conn->user, '/'); - if(!slash) - slash = strchr(conn->user, '\\'); - - if(slash) { - smbc->user = slash + 1; - smbc->domain = strdup(conn->user); - if(!smbc->domain) - return CURLE_OUT_OF_MEMORY; - smbc->domain[slash - conn->user] = 0; - } - else { - smbc->user = conn->user; - smbc->domain = strdup(conn->host.name); - if(!smbc->domain) - return CURLE_OUT_OF_MEMORY; - } - - return CURLE_OK; -} - -static CURLcode smb_recv_message(struct connectdata *conn, void **msg) -{ - struct smb_conn *smbc = &conn->proto.smbc; - char *buf = smbc->recv_buf; - ssize_t bytes_read; - size_t nbt_size; - size_t msg_size; - size_t len = MAX_MESSAGE_SIZE - smbc->got; - CURLcode result; - - result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read); - if(result) - return result; - - if(!bytes_read) - return CURLE_OK; - - smbc->got += bytes_read; - - /* Check for a 32-bit nbt header */ - if(smbc->got < sizeof(unsigned int)) - return CURLE_OK; - - nbt_size = Curl_read16_be((const unsigned char *) - (buf + sizeof(unsigned short))) + - sizeof(unsigned int); - if(smbc->got < nbt_size) - return CURLE_OK; - - msg_size = sizeof(struct smb_header); - if(nbt_size >= msg_size + 1) { - /* Add the word count */ - msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); - if(nbt_size >= msg_size + sizeof(unsigned short)) { - /* Add the byte count */ - msg_size += sizeof(unsigned short) + - Curl_read16_le((const unsigned char *)&buf[msg_size]); - if(nbt_size < msg_size) - return CURLE_READ_ERROR; - } - } - - *msg = buf; - - return CURLE_OK; -} - -static void smb_pop_message(struct connectdata *conn) -{ - struct smb_conn *smbc = &conn->proto.smbc; - - smbc->got = 0; -} - -static void smb_format_message(struct connectdata *conn, struct smb_header *h, - unsigned char cmd, size_t len) -{ - struct smb_conn *smbc = &conn->proto.smbc; - struct smb_request *req = conn->data->req.protop; - unsigned int pid; - - memset(h, 0, sizeof(*h)); - h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) + - len)); - memcpy((char *)h->magic, "\xffSMB", 4); - h->command = cmd; - h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES; - h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME); - h->uid = smb_swap16(smbc->uid); - h->tid = smb_swap16(req->tid); - pid = getpid(); - h->pid_high = smb_swap16((unsigned short)(pid >> 16)); - h->pid = smb_swap16((unsigned short) pid); -} - -static CURLcode smb_send(struct connectdata *conn, ssize_t len, - size_t upload_size) -{ - struct smb_conn *smbc = &conn->proto.smbc; - ssize_t bytes_written; - CURLcode result; - - result = Curl_write(conn, FIRSTSOCKET, conn->data->state.uploadbuffer, - len, &bytes_written); - if(result) - return result; - - if(bytes_written != len) { - smbc->send_size = len; - smbc->sent = bytes_written; - } - - smbc->upload_size = upload_size; - - return CURLE_OK; -} - -static CURLcode smb_flush(struct connectdata *conn) -{ - struct smb_conn *smbc = &conn->proto.smbc; - ssize_t bytes_written; - ssize_t len = smbc->send_size - smbc->sent; - CURLcode result; - - if(!smbc->send_size) - return CURLE_OK; - - result = Curl_write(conn, FIRSTSOCKET, - conn->data->state.uploadbuffer + smbc->sent, - len, &bytes_written); - if(result) - return result; - - if(bytes_written != len) - smbc->sent += bytes_written; - else - smbc->send_size = 0; - - return CURLE_OK; -} - -static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd, - const void *msg, size_t msg_len) -{ - smb_format_message(conn, (struct smb_header *)conn->data->state.uploadbuffer, - cmd, msg_len); - memcpy(conn->data->state.uploadbuffer + sizeof(struct smb_header), - msg, msg_len); - - return smb_send(conn, sizeof(struct smb_header) + msg_len, 0); -} - -static CURLcode smb_send_negotiate(struct connectdata *conn) -{ - const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; - - return smb_send_message(conn, SMB_COM_NEGOTIATE, msg, 15); -} - -static CURLcode smb_send_setup(struct connectdata *conn) -{ - struct smb_conn *smbc = &conn->proto.smbc; - struct smb_setup msg; - char *p = msg.bytes; - unsigned char lm_hash[21]; - unsigned char lm[24]; - unsigned char nt_hash[21]; - unsigned char nt[24]; - - size_t byte_count = sizeof(lm) + sizeof(nt); - byte_count += strlen(smbc->user) + strlen(smbc->domain); - byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ - if(byte_count > sizeof(msg.bytes)) - return CURLE_FILESIZE_EXCEEDED; - - Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash); - Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); -#ifdef USE_NTRESPONSES - Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash); - Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); -#else - memset(nt, 0, sizeof(nt)); -#endif - - memset(&msg, 0, sizeof(msg)); - msg.word_count = SMB_WC_SETUP_ANDX; - msg.andx.command = SMB_COM_NO_ANDX_COMMAND; - msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE); - msg.max_mpx_count = smb_swap16(1); - msg.vc_number = smb_swap16(1); - msg.session_key = smb_swap32(smbc->session_key); - msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES); - msg.lengths[0] = smb_swap16(sizeof(lm)); - msg.lengths[1] = smb_swap16(sizeof(nt)); - memcpy(p, lm, sizeof(lm)); - p += sizeof(lm); - memcpy(p, nt, sizeof(nt)); - p += sizeof(nt); - MSGCATNULL(smbc->user); - MSGCATNULL(smbc->domain); - MSGCATNULL(OS); - MSGCATNULL(CLIENTNAME); - byte_count = p - msg.bytes; - msg.byte_count = smb_swap16((unsigned short)byte_count); - - return smb_send_message(conn, SMB_COM_SETUP_ANDX, &msg, - sizeof(msg) - sizeof(msg.bytes) + byte_count); -} - -static CURLcode smb_send_tree_connect(struct connectdata *conn) -{ - struct smb_request *req = conn->data->req.protop; - struct smb_tree_connect msg; - char *p = msg.bytes; - - size_t byte_count = strlen(conn->host.name) + strlen(req->share); - byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ - if(byte_count > sizeof(msg.bytes)) - return CURLE_FILESIZE_EXCEEDED; - - memset(&msg, 0, sizeof(msg)); - msg.word_count = SMB_WC_TREE_CONNECT_ANDX; - msg.andx.command = SMB_COM_NO_ANDX_COMMAND; - msg.pw_len = 0; - MSGCAT("\\\\"); - MSGCAT(conn->host.name); - MSGCAT("\\"); - MSGCATNULL(req->share); - MSGCATNULL(SERVICENAME); /* Match any type of service */ - byte_count = p - msg.bytes; - msg.byte_count = smb_swap16((unsigned short)byte_count); - - return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg, - sizeof(msg) - sizeof(msg.bytes) + byte_count); -} - -static CURLcode smb_send_open(struct connectdata *conn) -{ - struct smb_request *req = conn->data->req.protop; - struct smb_nt_create msg; - size_t byte_count; - - if((strlen(req->path) + 1) > sizeof(msg.bytes)) - return CURLE_FILESIZE_EXCEEDED; - - memset(&msg, 0, sizeof(msg)); - msg.word_count = SMB_WC_NT_CREATE_ANDX; - msg.andx.command = SMB_COM_NO_ANDX_COMMAND; - byte_count = strlen(req->path); - msg.name_length = smb_swap16((unsigned short)byte_count); - msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); - if(conn->data->set.upload) { - msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); - msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); - } - else { - msg.access = smb_swap32(SMB_GENERIC_READ); - msg.create_disposition = smb_swap32(SMB_FILE_OPEN); - } - msg.byte_count = smb_swap16((unsigned short) ++byte_count); - strcpy(msg.bytes, req->path); - - return smb_send_message(conn, SMB_COM_NT_CREATE_ANDX, &msg, - sizeof(msg) - sizeof(msg.bytes) + byte_count); -} - -static CURLcode smb_send_close(struct connectdata *conn) -{ - struct smb_request *req = conn->data->req.protop; - struct smb_close msg; - - memset(&msg, 0, sizeof(msg)); - msg.word_count = SMB_WC_CLOSE; - msg.fid = smb_swap16(req->fid); - - return smb_send_message(conn, SMB_COM_CLOSE, &msg, sizeof(msg)); -} - -static CURLcode smb_send_tree_disconnect(struct connectdata *conn) -{ - struct smb_tree_disconnect msg; - - memset(&msg, 0, sizeof(msg)); - - return smb_send_message(conn, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg)); -} - -static CURLcode smb_send_read(struct connectdata *conn) -{ - struct smb_request *req = conn->data->req.protop; - curl_off_t offset = conn->data->req.offset; - struct smb_read msg; - - memset(&msg, 0, sizeof(msg)); - msg.word_count = SMB_WC_READ_ANDX; - msg.andx.command = SMB_COM_NO_ANDX_COMMAND; - msg.fid = smb_swap16(req->fid); - msg.offset = smb_swap32((unsigned int) offset); - msg.offset_high = smb_swap32((unsigned int) (offset >> 32)); - msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE); - msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE); - - return smb_send_message(conn, SMB_COM_READ_ANDX, &msg, sizeof(msg)); -} - -static CURLcode smb_send_write(struct connectdata *conn) -{ - struct smb_write *msg = (struct smb_write *)conn->data->state.uploadbuffer; - struct smb_request *req = conn->data->req.protop; - curl_off_t offset = conn->data->req.offset; - - curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount; - if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */ - upload_size = MAX_PAYLOAD_SIZE - 1; - - memset(msg, 0, sizeof(*msg)); - msg->word_count = SMB_WC_WRITE_ANDX; - msg->andx.command = SMB_COM_NO_ANDX_COMMAND; - msg->fid = smb_swap16(req->fid); - msg->offset = smb_swap32((unsigned int) offset); - msg->offset_high = smb_swap32((unsigned int) (offset >> 32)); - msg->data_length = smb_swap16((unsigned short) upload_size); - msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int)); - msg->byte_count = smb_swap16((unsigned short) (upload_size + 1)); - - smb_format_message(conn, &msg->h, SMB_COM_WRITE_ANDX, - sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size); - - return smb_send(conn, sizeof(*msg), (size_t) upload_size); -} - -static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg) -{ - struct smb_conn *smbc = &conn->proto.smbc; - CURLcode result; - - /* Check if there is data in the transfer buffer */ - if(!smbc->send_size && smbc->upload_size) { - int nread = smbc->upload_size > UPLOAD_BUFSIZE ? UPLOAD_BUFSIZE : - (int) smbc->upload_size; - conn->data->req.upload_fromhere = conn->data->state.uploadbuffer; - result = Curl_fillreadbuffer(conn, nread, &nread); - if(result && result != CURLE_AGAIN) - return result; - if(!nread) - return CURLE_OK; - - smbc->upload_size -= nread; - smbc->send_size = nread; - smbc->sent = 0; - } - - /* Check if there is data to send */ - if(smbc->send_size) { - result = smb_flush(conn); - if(result) - return result; - } - - /* Check if there is still data to be sent */ - if(smbc->send_size || smbc->upload_size) - return CURLE_AGAIN; - - return smb_recv_message(conn, msg); -} - -static CURLcode smb_connection_state(struct connectdata *conn, bool *done) -{ - struct smb_conn *smbc = &conn->proto.smbc; - struct smb_negotiate_response *nrsp; - struct smb_header *h; - CURLcode result; - void *msg = NULL; - - if(smbc->state == SMB_CONNECTING) { -#ifdef USE_SSL - if((conn->handler->flags & PROTOPT_SSL)) { - bool ssl_done; - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done); - if(result && result != CURLE_AGAIN) - return result; - if(!ssl_done) - return CURLE_OK; - } -#endif - - result = smb_send_negotiate(conn); - if(result) { - connclose(conn, "SMB: failed to send negotiate message"); - return result; - } - - conn_state(conn, SMB_NEGOTIATE); - } - - /* Send the previous message and check for a response */ - result = smb_send_and_recv(conn, &msg); - if(result && result != CURLE_AGAIN) { - connclose(conn, "SMB: failed to communicate"); - return result; - } - - if(!msg) - return CURLE_OK; - - h = msg; - - switch(smbc->state) { - case SMB_NEGOTIATE: - if(h->status || smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) { - connclose(conn, "SMB: negotiation failed"); - return CURLE_COULDNT_CONNECT; - } - nrsp = msg; - memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge)); - smbc->session_key = smb_swap32(nrsp->session_key); - result = smb_send_setup(conn); - if(result) { - connclose(conn, "SMB: failed to send setup message"); - return result; - } - conn_state(conn, SMB_SETUP); - break; - - case SMB_SETUP: - if(h->status) { - connclose(conn, "SMB: authentication failed"); - return CURLE_LOGIN_DENIED; - } - smbc->uid = smb_swap16(h->uid); - conn_state(conn, SMB_CONNECTED); - *done = true; - break; - - default: - smb_pop_message(conn); - return CURLE_OK; /* ignore */ - } - - smb_pop_message(conn); - - return CURLE_OK; -} - -/* - * Convert a timestamp from the Windows world (100 nsec units from - * 1 Jan 1601) to Posix time. - */ -static void get_posix_time(long *_out, const void *_in) -{ -#ifdef HAVE_LONGLONG - long long timestamp = *(long long *) _in; -#else - unsigned __int64 timestamp = *(unsigned __int64 *) _in; -#endif - - timestamp -= 116444736000000000ULL; - timestamp /= 10000000; - *_out = (long) timestamp; -} - -static CURLcode smb_request_state(struct connectdata *conn, bool *done) -{ - struct smb_request *req = conn->data->req.protop; - struct smb_header *h; - struct smb_conn *smbc = &conn->proto.smbc; - enum smb_req_state next_state = SMB_DONE; - unsigned short len; - unsigned short off; - CURLcode result; - void *msg = NULL; - const struct smb_nt_create_response *smb_m; - - /* Start the request */ - if(req->state == SMB_REQUESTING) { - result = smb_send_tree_connect(conn); - if(result) { - connclose(conn, "SMB: failed to send tree connect message"); - return result; - } - - request_state(conn, SMB_TREE_CONNECT); - } - - /* Send the previous message and check for a response */ - result = smb_send_and_recv(conn, &msg); - if(result && result != CURLE_AGAIN) { - connclose(conn, "SMB: failed to communicate"); - return result; - } - - if(!msg) - return CURLE_OK; - - h = msg; - - switch(req->state) { - case SMB_TREE_CONNECT: - if(h->status) { - req->result = CURLE_REMOTE_FILE_NOT_FOUND; - if(h->status == smb_swap32(SMB_ERR_NOACCESS)) - req->result = CURLE_REMOTE_ACCESS_DENIED; - break; - } - req->tid = smb_swap16(h->tid); - next_state = SMB_OPEN; - break; - - case SMB_OPEN: - if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { - req->result = CURLE_REMOTE_FILE_NOT_FOUND; - next_state = SMB_TREE_DISCONNECT; - break; - } - smb_m = (const struct smb_nt_create_response*) msg; - req->fid = smb_swap16(smb_m->fid); - conn->data->req.offset = 0; - if(conn->data->set.upload) { - conn->data->req.size = conn->data->state.infilesize; - Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); - next_state = SMB_UPLOAD; - } - else { - smb_m = (const struct smb_nt_create_response*) msg; - conn->data->req.size = smb_swap64(smb_m->end_of_file); - Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size); - if(conn->data->set.get_filetime) - get_posix_time(&conn->data->info.filetime, &smb_m->last_change_time); - next_state = SMB_DOWNLOAD; - } - break; - - case SMB_DOWNLOAD: - if(h->status || smbc->got < sizeof(struct smb_header) + 14) { - req->result = CURLE_RECV_ERROR; - next_state = SMB_CLOSE; - break; - } - len = Curl_read16_le(((const unsigned char *) msg) + - sizeof(struct smb_header) + 11); - off = Curl_read16_le(((const unsigned char *) msg) + - sizeof(struct smb_header) + 13); - if(len > 0) { - if(off + sizeof(unsigned int) + len > smbc->got) { - failf(conn->data, "Invalid input packet"); - result = CURLE_RECV_ERROR; - } - else - result = Curl_client_write(conn, CLIENTWRITE_BODY, - (char *)msg + off + sizeof(unsigned int), - len); - if(result) { - req->result = result; - next_state = SMB_CLOSE; - break; - } - } - conn->data->req.bytecount += len; - conn->data->req.offset += len; - Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount); - next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; - break; - - case SMB_UPLOAD: - if(h->status || smbc->got < sizeof(struct smb_header) + 6) { - req->result = CURLE_UPLOAD_FAILED; - next_state = SMB_CLOSE; - break; - } - len = Curl_read16_le(((const unsigned char *) msg) + - sizeof(struct smb_header) + 5); - conn->data->req.bytecount += len; - conn->data->req.offset += len; - Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount); - if(conn->data->req.bytecount >= conn->data->req.size) - next_state = SMB_CLOSE; - else - next_state = SMB_UPLOAD; - break; - - case SMB_CLOSE: - /* We don't care if the close failed, proceed to tree disconnect anyway */ - next_state = SMB_TREE_DISCONNECT; - break; - - case SMB_TREE_DISCONNECT: - next_state = SMB_DONE; - break; - - default: - smb_pop_message(conn); - return CURLE_OK; /* ignore */ - } - - smb_pop_message(conn); - - switch(next_state) { - case SMB_OPEN: - result = smb_send_open(conn); - break; - - case SMB_DOWNLOAD: - result = smb_send_read(conn); - break; - - case SMB_UPLOAD: - result = smb_send_write(conn); - break; - - case SMB_CLOSE: - result = smb_send_close(conn); - break; - - case SMB_TREE_DISCONNECT: - result = smb_send_tree_disconnect(conn); - break; - - case SMB_DONE: - result = req->result; - *done = true; - break; - - default: - break; - } - - if(result) { - connclose(conn, "SMB: failed to send message"); - return result; - } - - request_state(conn, next_state); - - return CURLE_OK; -} - -static CURLcode smb_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - struct smb_request *req = conn->data->req.protop; - - (void) premature; - - Curl_safefree(req->share); - Curl_safefree(conn->data->req.protop); - - return status; -} - -static CURLcode smb_disconnect(struct connectdata *conn, bool dead) -{ - struct smb_conn *smbc = &conn->proto.smbc; - struct smb_request *req = conn->data->req.protop; - - (void) dead; - - Curl_safefree(smbc->domain); - Curl_safefree(smbc->recv_buf); - - /* smb_done is not always called, so cleanup the request */ - if(req) { - Curl_safefree(req->share); - } - - return CURLE_OK; -} - -static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks) -{ - struct smb_conn *smbc = &conn->proto.smbc; - - if(!numsocks) - return GETSOCK_BLANK; - - socks[0] = conn->sock[FIRSTSOCKET]; - - if(smbc->send_size || smbc->upload_size) - return GETSOCK_WRITESOCK(0); - - return GETSOCK_READSOCK(0); -} - -static CURLcode smb_parse_url_path(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct smb_request *req = data->req.protop; - char *path; - char *slash; - - /* URL decode the path */ - result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE); - if(result) - return result; - - /* Parse the path for the share */ - req->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); - if(!req->share) { - free(path); - - return CURLE_OUT_OF_MEMORY; - } - - slash = strchr(req->share, '/'); - if(!slash) - slash = strchr(req->share, '\\'); - - /* The share must be present */ - if(!slash) { - free(path); - - return CURLE_URL_MALFORMAT; - } - - /* Parse the path for the file path converting any forward slashes into - backslashes */ - *slash++ = 0; - req->path = slash; - for(; *slash; slash++) { - if(*slash == '/') - *slash = '\\'; - } - - free(path); - - return CURLE_OK; -} - -#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ - -#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ diff --git a/dep/cpr/opt/curl/lib/smb.h b/dep/cpr/opt/curl/lib/smb.h deleted file mode 100644 index 1a4f66e5a89..00000000000 --- a/dep/cpr/opt/curl/lib/smb.h +++ /dev/null @@ -1,271 +0,0 @@ -#ifndef HEADER_CURL_SMB_H -#define HEADER_CURL_SMB_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014, Bill Nagel , Exacq Technologies - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -enum smb_conn_state { - SMB_NOT_CONNECTED = 0, - SMB_CONNECTING, - SMB_NEGOTIATE, - SMB_SETUP, - SMB_CONNECTED -}; - -struct smb_conn { - enum smb_conn_state state; - char *user; - char *domain; - unsigned char challenge[8]; - unsigned int session_key; - unsigned short uid; - char *recv_buf; - size_t upload_size; - size_t send_size; - size_t sent; - size_t got; -}; - -/* - * Definitions for SMB protocol data structures - */ -#ifdef BUILDING_CURL_SMB_C - -#if defined(_MSC_VER) || defined(__ILEC400__) -# define PACK -# pragma pack(push) -# pragma pack(1) -#elif defined(__GNUC__) -# define PACK __attribute__((packed)) -#else -# define PACK -#endif - -#define SMB_COM_CLOSE 0x04 -#define SMB_COM_READ_ANDX 0x2e -#define SMB_COM_WRITE_ANDX 0x2f -#define SMB_COM_TREE_DISCONNECT 0x71 -#define SMB_COM_NEGOTIATE 0x72 -#define SMB_COM_SETUP_ANDX 0x73 -#define SMB_COM_TREE_CONNECT_ANDX 0x75 -#define SMB_COM_NT_CREATE_ANDX 0xa2 -#define SMB_COM_NO_ANDX_COMMAND 0xff - -#define SMB_WC_CLOSE 0x03 -#define SMB_WC_READ_ANDX 0x0c -#define SMB_WC_WRITE_ANDX 0x0e -#define SMB_WC_SETUP_ANDX 0x0d -#define SMB_WC_TREE_CONNECT_ANDX 0x04 -#define SMB_WC_NT_CREATE_ANDX 0x18 - -#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 -#define SMB_FLAGS_CASELESS_PATHNAMES 0x08 -#define SMB_FLAGS2_UNICODE_STRINGS 0x8000 -#define SMB_FLAGS2_IS_LONG_NAME 0x0040 -#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 - -#define SMB_CAP_LARGE_FILES 0x08 -#define SMB_GENERIC_WRITE 0x40000000 -#define SMB_GENERIC_READ 0x80000000 -#define SMB_FILE_SHARE_ALL 0x07 -#define SMB_FILE_OPEN 0x01 -#define SMB_FILE_OVERWRITE_IF 0x05 - -#define SMB_ERR_NOACCESS 0x00050001 - -struct smb_header { - unsigned char nbt_type; - unsigned char nbt_flags; - unsigned short nbt_length; - unsigned char magic[4]; - unsigned char command; - unsigned int status; - unsigned char flags; - unsigned short flags2; - unsigned short pid_high; - unsigned char signature[8]; - unsigned short pad; - unsigned short tid; - unsigned short pid; - unsigned short uid; - unsigned short mid; -} PACK; - -struct smb_negotiate_response { - struct smb_header h; - unsigned char word_count; - unsigned short dialect_index; - unsigned char security_mode; - unsigned short max_mpx_count; - unsigned short max_number_vcs; - unsigned int max_buffer_size; - unsigned int max_raw_size; - unsigned int session_key; - unsigned int capabilities; - unsigned int system_time_low; - unsigned int system_time_high; - unsigned short server_time_zone; - unsigned char encryption_key_length; - unsigned short byte_count; - char bytes[1]; -} PACK; - -struct andx { - unsigned char command; - unsigned char pad; - unsigned short offset; -} PACK; - -struct smb_setup { - unsigned char word_count; - struct andx andx; - unsigned short max_buffer_size; - unsigned short max_mpx_count; - unsigned short vc_number; - unsigned int session_key; - unsigned short lengths[2]; - unsigned int pad; - unsigned int capabilities; - unsigned short byte_count; - char bytes[1024]; -} PACK; - -struct smb_tree_connect { - unsigned char word_count; - struct andx andx; - unsigned short flags; - unsigned short pw_len; - unsigned short byte_count; - char bytes[1024]; -} PACK; - -struct smb_nt_create { - unsigned char word_count; - struct andx andx; - unsigned char pad; - unsigned short name_length; - unsigned int flags; - unsigned int root_fid; - unsigned int access; -#ifdef HAVE_LONGLONG - unsigned long long allocation_size; -#else - unsigned __int64 allocation_size; -#endif - unsigned int ext_file_attributes; - unsigned int share_access; - unsigned int create_disposition; - unsigned int create_options; - unsigned int impersonation_level; - unsigned char security_flags; - unsigned short byte_count; - char bytes[1024]; -} PACK; - -struct smb_nt_create_response { - struct smb_header h; - unsigned char word_count; - struct andx andx; - unsigned char op_lock_level; - unsigned short fid; - unsigned int create_disposition; -#ifdef HAVE_LONGLONG - unsigned long long create_time; - unsigned long long last_access_time; - unsigned long long last_write_time; - unsigned long long last_change_time; -#else - unsigned __int64 create_time; - unsigned __int64 last_access_time; - unsigned __int64 last_write_time; - unsigned __int64 last_change_time; -#endif - unsigned int ext_file_attributes; -#ifdef HAVE_LONGLONG - unsigned long long allocation_size; - unsigned long long end_of_file; -#else - unsigned __int64 allocation_size; - unsigned __int64 end_of_file; -#endif -} PACK; - -struct smb_read { - unsigned char word_count; - struct andx andx; - unsigned short fid; - unsigned int offset; - unsigned short max_bytes; - unsigned short min_bytes; - unsigned int timeout; - unsigned short remaining; - unsigned int offset_high; - unsigned short byte_count; -} PACK; - -struct smb_write { - struct smb_header h; - unsigned char word_count; - struct andx andx; - unsigned short fid; - unsigned int offset; - unsigned int timeout; - unsigned short write_mode; - unsigned short remaining; - unsigned short pad; - unsigned short data_length; - unsigned short data_offset; - unsigned int offset_high; - unsigned short byte_count; - unsigned char pad2; -} PACK; - -struct smb_close { - unsigned char word_count; - unsigned short fid; - unsigned int last_mtime; - unsigned short byte_count; -} PACK; - -struct smb_tree_disconnect { - unsigned char word_count; - unsigned short byte_count; -} PACK; - -#if defined(_MSC_VER) || defined(__ILEC400__) -# pragma pack(pop) -#endif - -#endif /* BUILDING_CURL_SMB_C */ - -#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ - (CURL_SIZEOF_CURL_OFF_T > 4) - -#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) - -extern const struct Curl_handler Curl_handler_smb; -extern const struct Curl_handler Curl_handler_smbs; - -#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ - -#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ - -#endif /* HEADER_CURL_SMB_H */ diff --git a/dep/cpr/opt/curl/lib/smtp.c b/dep/cpr/opt/curl/lib/smtp.c deleted file mode 100644 index de2dd335633..00000000000 --- a/dep/cpr/opt/curl/lib/smtp.c +++ /dev/null @@ -1,1633 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC1870 SMTP Service Extension for Message Size - * RFC2195 CRAM-MD5 authentication - * RFC2831 DIGEST-MD5 authentication - * RFC3207 SMTP over TLS - * RFC4422 Simple Authentication and Security Layer (SASL) - * RFC4616 PLAIN authentication - * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism - * RFC4954 SMTP Authentication - * RFC5321 SMTP protocol - * RFC6749 OAuth 2.0 Authorization Framework - * Draft SMTP URL Interface - * Draft LOGIN SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_SMTP - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_UTSNAME_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "progress.h" -#include "transfer.h" -#include "escape.h" -#include "http.h" /* for HTTP proxy tunnel stuff */ -#include "mime.h" -#include "socks.h" -#include "smtp.h" -#include "strtoofft.h" -#include "strcase.h" -#include "vtls/vtls.h" -#include "connect.h" -#include "strerror.h" -#include "select.h" -#include "multiif.h" -#include "url.h" -#include "curl_gethostname.h" -#include "curl_sasl.h" -#include "warnless.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Local API functions */ -static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done); -static CURLcode smtp_do(struct connectdata *conn, bool *done); -static CURLcode smtp_done(struct connectdata *conn, CURLcode status, - bool premature); -static CURLcode smtp_connect(struct connectdata *conn, bool *done); -static CURLcode smtp_disconnect(struct connectdata *conn, bool dead); -static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done); -static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks); -static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done); -static CURLcode smtp_setup_connection(struct connectdata *conn); -static CURLcode smtp_parse_url_options(struct connectdata *conn); -static CURLcode smtp_parse_url_path(struct connectdata *conn); -static CURLcode smtp_parse_custom_request(struct connectdata *conn); -static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, - const char *initresp); -static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); -static void smtp_get_message(char *buffer, char **outptr); - -/* - * SMTP protocol handler. - */ - -const struct Curl_handler Curl_handler_smtp = { - "SMTP", /* scheme */ - smtp_setup_connection, /* setup_connection */ - smtp_do, /* do_it */ - smtp_done, /* done */ - ZERO_NULL, /* do_more */ - smtp_connect, /* connect_it */ - smtp_multi_statemach, /* connecting */ - smtp_doing, /* doing */ - smtp_getsock, /* proto_getsock */ - smtp_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - smtp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_SMTP, /* defport */ - CURLPROTO_SMTP, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ - PROTOPT_URLOPTIONS -}; - -#ifdef USE_SSL -/* - * SMTPS protocol handler. - */ - -const struct Curl_handler Curl_handler_smtps = { - "SMTPS", /* scheme */ - smtp_setup_connection, /* setup_connection */ - smtp_do, /* do_it */ - smtp_done, /* done */ - ZERO_NULL, /* do_more */ - smtp_connect, /* connect_it */ - smtp_multi_statemach, /* connecting */ - smtp_doing, /* doing */ - smtp_getsock, /* proto_getsock */ - smtp_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - smtp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_SMTPS, /* defport */ - CURLPROTO_SMTPS, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_SSL - | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ -}; -#endif - -/* SASL parameters for the smtp protocol */ -static const struct SASLproto saslsmtp = { - "smtp", /* The service name */ - 334, /* Code received when continuation is expected */ - 235, /* Code to receive upon authentication success */ - 512 - 8, /* Maximum initial response length (no max) */ - smtp_perform_auth, /* Send authentication command */ - smtp_continue_auth, /* Send authentication continuation */ - smtp_get_message /* Get SASL response message */ -}; - -#ifdef USE_SSL -static void smtp_to_smtps(struct connectdata *conn) -{ - /* Change the connection handler */ - conn->handler = &Curl_handler_smtps; - - /* Set the connection's upgraded to TLS flag */ - conn->tls_upgraded = TRUE; -} -#else -#define smtp_to_smtps(x) Curl_nop_stmt -#endif - -/*********************************************************************** - * - * smtp_endofresp() - * - * Checks for an ending SMTP status code at the start of the given string, but - * also detects various capabilities from the EHLO response including the - * supported authentication mechanisms. - */ -static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len, - int *resp) -{ - struct smtp_conn *smtpc = &conn->proto.smtpc; - bool result = FALSE; - - /* Nothing for us */ - if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2])) - return FALSE; - - /* Do we have a command response? This should be the response code followed - by a space and optionally some text as per RFC-5321 and as outlined in - Section 4. Examples of RFC-4954 but some e-mail servers ignore this and - only send the response code instead as per Section 4.2. */ - if(line[3] == ' ' || len == 5) { - result = TRUE; - *resp = curlx_sltosi(strtol(line, NULL, 10)); - - /* Make sure real server never sends internal value */ - if(*resp == 1) - *resp = 0; - } - /* Do we have a multiline (continuation) response? */ - else if(line[3] == '-' && - (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) { - result = TRUE; - *resp = 1; /* Internal response code */ - } - - return result; -} - -/*********************************************************************** - * - * smtp_get_message() - * - * Gets the authentication message from the response buffer. - */ -static void smtp_get_message(char *buffer, char **outptr) -{ - size_t len = 0; - char *message = NULL; - - /* Find the start of the message */ - for(message = buffer + 4; *message == ' ' || *message == '\t'; message++) - ; - - /* Find the end of the message */ - for(len = strlen(message); len--;) - if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && - message[len] != '\t') - break; - - /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } - - *outptr = message; -} - -/*********************************************************************** - * - * state() - * - * This is the ONLY way to change SMTP state! - */ -static void state(struct connectdata *conn, smtpstate newstate) -{ - struct smtp_conn *smtpc = &conn->proto.smtpc; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ - static const char * const names[] = { - "STOP", - "SERVERGREET", - "EHLO", - "HELO", - "STARTTLS", - "UPGRADETLS", - "AUTH", - "COMMAND", - "MAIL", - "RCPT", - "DATA", - "POSTDATA", - "QUIT", - /* LAST */ - }; - - if(smtpc->state != newstate) - infof(conn->data, "SMTP %p state change from %s to %s\n", - (void *)smtpc, names[smtpc->state], names[newstate]); -#endif - - smtpc->state = newstate; -} - -/*********************************************************************** - * - * smtp_perform_ehlo() - * - * Sends the EHLO command to not only initialise communication with the ESMTP - * server but to also obtain a list of server side supported capabilities. - */ -static CURLcode smtp_perform_ehlo(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */ - smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism - used for esmtp connections */ - smtpc->tls_supported = FALSE; /* Clear the TLS capability */ - smtpc->auth_supported = FALSE; /* Clear the AUTH capability */ - - /* Send the EHLO command */ - result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); - - if(!result) - state(conn, SMTP_EHLO); - - return result; -} - -/*********************************************************************** - * - * smtp_perform_helo() - * - * Sends the HELO command to initialise communication with the SMTP server. - */ -static CURLcode smtp_perform_helo(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used - in smtp connections */ - - /* Send the HELO command */ - result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); - - if(!result) - state(conn, SMTP_HELO); - - return result; -} - -/*********************************************************************** - * - * smtp_perform_starttls() - * - * Sends the STLS command to start the upgrade to TLS. - */ -static CURLcode smtp_perform_starttls(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* Send the STARTTLS command */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS"); - - if(!result) - state(conn, SMTP_STARTTLS); - - return result; -} - -/*********************************************************************** - * - * smtp_perform_upgrade_tls() - * - * Performs the upgrade to TLS. - */ -static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - /* Start the SSL connection */ - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone); - - if(!result) { - if(smtpc->state != SMTP_UPGRADETLS) - state(conn, SMTP_UPGRADETLS); - - if(smtpc->ssldone) { - smtp_to_smtps(conn); - result = smtp_perform_ehlo(conn); - } - } - - return result; -} - -/*********************************************************************** - * - * smtp_perform_auth() - * - * Sends an AUTH command allowing the client to login with the given SASL - * authentication mechanism. - */ -static CURLcode smtp_perform_auth(struct connectdata *conn, - const char *mech, - const char *initresp) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - if(initresp) { /* AUTH ... */ - /* Send the AUTH command with the initial response */ - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - } - else { - /* Send the AUTH command */ - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); - } - - return result; -} - -/*********************************************************************** - * - * smtp_continue_auth() - * - * Sends SASL continuation data or cancellation. - */ -static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp) -{ - struct smtp_conn *smtpc = &conn->proto.smtpc; - - return Curl_pp_sendf(&smtpc->pp, "%s", resp); -} - -/*********************************************************************** - * - * smtp_perform_authentication() - * - * Initiates the authentication sequence, with the appropriate SASL - * authentication mechanism. - */ -static CURLcode smtp_perform_authentication(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - saslprogress progress; - - /* Check we have enough data to authenticate with, and the - server supports authentiation, and end the connect phase if not */ - if(!smtpc->auth_supported || - !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { - state(conn, SMTP_STOP); - return result; - } - - /* Calculate the SASL login details */ - result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress); - - if(!result) { - if(progress == SASL_INPROGRESS) - state(conn, SMTP_AUTH); - else { - /* Other mechanisms not supported */ - infof(conn->data, "No known authentication mechanisms supported!\n"); - result = CURLE_LOGIN_DENIED; - } - } - - return result; -} - -/*********************************************************************** - * - * smtp_perform_command() - * - * Sends a SMTP based command. - */ -static CURLcode smtp_perform_command(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SMTP *smtp = data->req.protop; - - /* Send the command */ - if(smtp->rcpt) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s", - smtp->custom && smtp->custom[0] != '\0' ? - smtp->custom : "VRFY", - smtp->rcpt->data); - else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", - smtp->custom && smtp->custom[0] != '\0' ? - smtp->custom : "HELP"); - - if(!result) - state(conn, SMTP_COMMAND); - - return result; -} - -/*********************************************************************** - * - * smtp_perform_mail() - * - * Sends an MAIL command to initiate the upload of a message. - */ -static CURLcode smtp_perform_mail(struct connectdata *conn) -{ - char *from = NULL; - char *auth = NULL; - char *size = NULL; - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - /* Calculate the FROM parameter */ - if(!data->set.str[STRING_MAIL_FROM]) - /* Null reverse-path, RFC-5321, sect. 3.6.3 */ - from = strdup("<>"); - else if(data->set.str[STRING_MAIL_FROM][0] == '<') - from = aprintf("%s", data->set.str[STRING_MAIL_FROM]); - else - from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]); - - if(!from) - return CURLE_OUT_OF_MEMORY; - - /* Calculate the optional AUTH parameter */ - if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) { - if(data->set.str[STRING_MAIL_AUTH][0] != '\0') - auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]); - else - /* Empty AUTH, RFC-2554, sect. 5 */ - auth = strdup("<>"); - - if(!auth) { - free(from); - - return CURLE_OUT_OF_MEMORY; - } - } - - /* Prepare the mime data if some. */ - if(data->set.mimepost.kind != MIMEKIND_NONE) { - /* Use the whole structure as data. */ - data->set.mimepost.flags &= ~MIME_BODY_ONLY; - - /* Add external headers and mime version. */ - curl_mime_headers(&data->set.mimepost, data->set.headers, 0); - result = Curl_mime_prepare_headers(&data->set.mimepost, NULL, - NULL, MIMESTRATEGY_MAIL); - - if(!result) - if(!Curl_checkheaders(conn, "Mime-Version")) - result = Curl_mime_add_header(&data->set.mimepost.curlheaders, - "Mime-Version: 1.0"); - - /* Make sure we will read the entire mime structure. */ - if(!result) - result = Curl_mime_rewind(&data->set.mimepost); - - if(result) { - free(from); - free(auth); - return result; - } - - data->state.infilesize = Curl_mime_size(&data->set.mimepost); - - /* Read from mime structure. */ - data->state.fread_func = (curl_read_callback) Curl_mime_read; - data->state.in = (void *) &data->set.mimepost; - } - - /* Calculate the optional SIZE parameter */ - if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) { - size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize); - - if(!size) { - free(from); - free(auth); - - return CURLE_OUT_OF_MEMORY; - } - } - - /* Send the MAIL command */ - if(!auth && !size) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, - "MAIL FROM:%s", from); - else if(auth && !size) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, - "MAIL FROM:%s AUTH=%s", from, auth); - else if(auth && size) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, - "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size); - else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, - "MAIL FROM:%s SIZE=%s", from, size); - - free(from); - free(auth); - free(size); - - if(!result) - state(conn, SMTP_MAIL); - - return result; -} - -/*********************************************************************** - * - * smtp_perform_rcpt_to() - * - * Sends a RCPT TO command for a given recipient as part of the message upload - * process. - */ -static CURLcode smtp_perform_rcpt_to(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SMTP *smtp = data->req.protop; - - /* Send the RCPT TO command */ - if(smtp->rcpt->data[0] == '<') - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s", - smtp->rcpt->data); - else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", - smtp->rcpt->data); - if(!result) - state(conn, SMTP_RCPT); - - return result; -} - -/*********************************************************************** - * - * smtp_perform_quit() - * - * Performs the quit action prior to sclose() being called. - */ -static CURLcode smtp_perform_quit(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* Send the QUIT command */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT"); - - if(!result) - state(conn, SMTP_QUIT); - - return result; -} - -/* For the initial server greeting */ -static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode/100 != 2) { - failf(data, "Got unexpected smtp-server response: %d", smtpcode); - result = CURLE_WEIRD_SERVER_REPLY; - } - else - result = smtp_perform_ehlo(conn); - - return result; -} - -/* For STARTTLS responses */ -static CURLcode smtp_state_starttls_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 220) { - if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied, code %d", smtpcode); - result = CURLE_USE_SSL_FAILED; - } - else - result = smtp_perform_authentication(conn); - } - else - result = smtp_perform_upgrade_tls(conn); - - return result; -} - -/* For EHLO responses */ -static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *line = data->state.buffer; - size_t len = strlen(line); - size_t wordlen; - - (void)instate; /* no use for this yet */ - - if(smtpcode/100 != 2 && smtpcode != 1) { - if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) - result = smtp_perform_helo(conn); - else { - failf(data, "Remote access denied: %d", smtpcode); - result = CURLE_REMOTE_ACCESS_DENIED; - } - } - else { - line += 4; - len -= 4; - - /* Does the server support the STARTTLS capability? */ - if(len >= 8 && !memcmp(line, "STARTTLS", 8)) - smtpc->tls_supported = TRUE; - - /* Does the server support the SIZE capability? */ - else if(len >= 4 && !memcmp(line, "SIZE", 4)) - smtpc->size_supported = TRUE; - - /* Does the server support authentication? */ - else if(len >= 5 && !memcmp(line, "AUTH ", 5)) { - smtpc->auth_supported = TRUE; - - /* Advance past the AUTH keyword */ - line += 5; - len -= 5; - - /* Loop through the data line */ - for(;;) { - size_t llen; - unsigned int mechbit; - - while(len && - (*line == ' ' || *line == '\t' || - *line == '\r' || *line == '\n')) { - - line++; - len--; - } - - if(!len) - break; - - /* Extract the word */ - for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && - line[wordlen] != '\t' && line[wordlen] != '\r' && - line[wordlen] != '\n';) - wordlen++; - - /* Test the word for a matching authentication mechanism */ - mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); - if(mechbit && llen == wordlen) - smtpc->sasl.authmechs |= mechbit; - - line += wordlen; - len -= wordlen; - } - } - - if(smtpcode != 1) { - if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested */ - if(smtpc->tls_supported) - /* Switch to TLS connection now */ - result = smtp_perform_starttls(conn); - else if(data->set.use_ssl == CURLUSESSL_TRY) - /* Fallback and carry on with authentication */ - result = smtp_perform_authentication(conn); - else { - failf(data, "STARTTLS not supported."); - result = CURLE_USE_SSL_FAILED; - } - } - else - result = smtp_perform_authentication(conn); - } - } - - return result; -} - -/* For HELO responses */ -static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode/100 != 2) { - failf(data, "Remote access denied: %d", smtpcode); - result = CURLE_REMOTE_ACCESS_DENIED; - } - else - /* End of connect phase */ - state(conn, SMTP_STOP); - - return result; -} - -/* For SASL authentication responses */ -static CURLcode smtp_state_auth_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - saslprogress progress; - - (void)instate; /* no use for this yet */ - - result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress); - if(!result) - switch(progress) { - case SASL_DONE: - state(conn, SMTP_STOP); /* Authenticated */ - break; - case SASL_IDLE: /* No mechanism left after cancellation */ - failf(data, "Authentication cancelled"); - result = CURLE_LOGIN_DENIED; - break; - default: - break; - } - - return result; -} - -/* For command responses */ -static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SMTP *smtp = data->req.protop; - char *line = data->state.buffer; - size_t len = strlen(line); - - (void)instate; /* no use for this yet */ - - if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) || - (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) { - failf(data, "Command failed: %d", smtpcode); - result = CURLE_RECV_ERROR; - } - else { - /* Temporarily add the LF character back and send as body to the client */ - if(!data->set.opt_no_body) { - line[len] = '\n'; - result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); - line[len] = '\0'; - } - - if(smtpcode != 1) { - if(smtp->rcpt) { - smtp->rcpt = smtp->rcpt->next; - - if(smtp->rcpt) { - /* Send the next command */ - result = smtp_perform_command(conn); - } - else - /* End of DO phase */ - state(conn, SMTP_STOP); - } - else - /* End of DO phase */ - state(conn, SMTP_STOP); - } - } - - return result; -} - -/* For MAIL responses */ -static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode/100 != 2) { - failf(data, "MAIL failed: %d", smtpcode); - result = CURLE_SEND_ERROR; - } - else - /* Start the RCPT TO command */ - result = smtp_perform_rcpt_to(conn); - - return result; -} - -/* For RCPT responses */ -static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SMTP *smtp = data->req.protop; - - (void)instate; /* no use for this yet */ - - if(smtpcode/100 != 2) { - failf(data, "RCPT failed: %d", smtpcode); - result = CURLE_SEND_ERROR; - } - else { - smtp->rcpt = smtp->rcpt->next; - - if(smtp->rcpt) - /* Send the next RCPT TO command */ - result = smtp_perform_rcpt_to(conn); - else { - /* Send the DATA command */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA"); - - if(!result) - state(conn, SMTP_DATA); - } - } - - return result; -} - -/* For DATA response */ -static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 354) { - failf(data, "DATA failed: %d", smtpcode); - result = CURLE_SEND_ERROR; - } - else { - /* Set the progress upload size */ - Curl_pgrsSetUploadSize(data, data->state.infilesize); - - /* SMTP upload */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); - - /* End of DO phase */ - state(conn, SMTP_STOP); - } - - return result; -} - -/* For POSTDATA responses, which are received after the entire DATA - part has been sent to the server */ -static CURLcode smtp_state_postdata_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 250) - result = CURLE_RECV_ERROR; - - /* End of DONE phase */ - state(conn, SMTP_STOP); - - return result; -} - -static CURLcode smtp_statemach_act(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct Curl_easy *data = conn->data; - int smtpcode; - struct smtp_conn *smtpc = &conn->proto.smtpc; - struct pingpong *pp = &smtpc->pp; - size_t nread = 0; - - /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */ - if(smtpc->state == SMTP_UPGRADETLS) - return smtp_perform_upgrade_tls(conn); - - /* Flush any data that needs to be sent */ - if(pp->sendleft) - return Curl_pp_flushsend(pp); - - do { - /* Read the response from the server */ - result = Curl_pp_readresp(sock, pp, &smtpcode, &nread); - if(result) - return result; - - /* Store the latest response for later retrieval if necessary */ - if(smtpc->state != SMTP_QUIT && smtpcode != 1) - data->info.httpcode = smtpcode; - - if(!smtpcode) - break; - - /* We have now received a full SMTP server response */ - switch(smtpc->state) { - case SMTP_SERVERGREET: - result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_EHLO: - result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_HELO: - result = smtp_state_helo_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_STARTTLS: - result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH: - result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_COMMAND: - result = smtp_state_command_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_MAIL: - result = smtp_state_mail_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_RCPT: - result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_DATA: - result = smtp_state_data_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_POSTDATA: - result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_QUIT: - /* fallthrough, just stop! */ - default: - /* internal error */ - state(conn, SMTP_STOP); - break; - } - } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp)); - - return result; -} - -/* Called repeatedly until done from multi.c */ -static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) { - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone); - if(result || !smtpc->ssldone) - return result; - } - - result = Curl_pp_statemach(&smtpc->pp, FALSE); - *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; - - return result; -} - -static CURLcode smtp_block_statemach(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - while(smtpc->state != SMTP_STOP && !result) - result = Curl_pp_statemach(&smtpc->pp, TRUE); - - return result; -} - -/* Allocate and initialize the SMTP struct for the current Curl_easy if - required */ -static CURLcode smtp_init(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SMTP *smtp; - - smtp = data->req.protop = calloc(sizeof(struct SMTP), 1); - if(!smtp) - result = CURLE_OUT_OF_MEMORY; - - return result; -} - -/* For the SMTP "protocol connect" and "doing" phases only */ -static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks) -{ - return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks); -} - -/*********************************************************************** - * - * smtp_connect() - * - * This function should do everything that is to be considered a part of - * the connection phase. - * - * The variable pointed to by 'done' will be TRUE if the protocol-layer - * connect phase is done when this function returns, or FALSE if not. - */ -static CURLcode smtp_connect(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - struct pingpong *pp = &smtpc->pp; - - *done = FALSE; /* default to not done yet */ - - /* We always support persistent connections in SMTP */ - connkeep(conn, "SMTP default"); - - /* Set the default response time-out */ - pp->response_time = RESP_TIMEOUT; - pp->statemach_act = smtp_statemach_act; - pp->endofresp = smtp_endofresp; - pp->conn = conn; - - /* Initialize the SASL storage */ - Curl_sasl_init(&smtpc->sasl, &saslsmtp); - - /* Initialise the pingpong layer */ - Curl_pp_init(pp); - - /* Parse the URL options */ - result = smtp_parse_url_options(conn); - if(result) - return result; - - /* Parse the URL path */ - result = smtp_parse_url_path(conn); - if(result) - return result; - - /* Start off waiting for the server greeting response */ - state(conn, SMTP_SERVERGREET); - - result = smtp_multi_statemach(conn, done); - - return result; -} - -/*********************************************************************** - * - * smtp_done() - * - * The DONE function. This does what needs to be done after a single DO has - * performed. - * - * Input argument is already checked for validity. - */ -static CURLcode smtp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SMTP *smtp = data->req.protop; - struct pingpong *pp = &conn->proto.smtpc.pp; - char *eob; - ssize_t len; - ssize_t bytes_written; - - (void)premature; - - if(!smtp || !pp->conn) - return CURLE_OK; - - if(status) { - connclose(conn, "SMTP done with bad status"); /* marked for closure */ - result = status; /* use the already set error code */ - } - else if(!data->set.connect_only && data->set.mail_rcpt && - (data->set.upload || data->set.mimepost.kind)) { - /* Calculate the EOB taking into account any terminating CRLF from the - previous line of the email or the CRLF of the DATA command when there - is "no mail data". RFC-5321, sect. 4.1.1.4. - - Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to - fail when using a different pointer following a previous write, that - returned CURLE_AGAIN, we duplicate the EOB now rather than when the - bytes written doesn't equal len. */ - if(smtp->trailing_crlf || !conn->data->state.infilesize) { - eob = strdup(SMTP_EOB + 2); - len = SMTP_EOB_LEN - 2; - } - else { - eob = strdup(SMTP_EOB); - len = SMTP_EOB_LEN; - } - - if(!eob) - return CURLE_OUT_OF_MEMORY; - - /* Send the end of block data */ - result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written); - if(result) { - free(eob); - return result; - } - - if(bytes_written != len) { - /* The whole chunk was not sent so keep it around and adjust the - pingpong structure accordingly */ - pp->sendthis = eob; - pp->sendsize = len; - pp->sendleft = len - bytes_written; - } - else { - /* Successfully sent so adjust the response timeout relative to now */ - pp->response = Curl_tvnow(); - - free(eob); - } - - state(conn, SMTP_POSTDATA); - - /* Run the state-machine - - TODO: when the multi interface is used, this _really_ should be using - the smtp_multi_statemach function but we have no general support for - non-blocking DONE operations! - */ - result = smtp_block_statemach(conn); - } - - /* Cleanup our per-request based variables */ - Curl_safefree(smtp->custom); - - /* Clear the transfer mode for the next request */ - smtp->transfer = FTPTRANSFER_BODY; - - return result; -} - -/*********************************************************************** - * - * smtp_perform() - * - * This is the actual DO function for SMTP. Transfer a mail, send a command - * or get some data according to the options previously setup. - */ -static CURLcode smtp_perform(struct connectdata *conn, bool *connected, - bool *dophase_done) -{ - /* This is SMTP and no proxy */ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SMTP *smtp = data->req.protop; - - DEBUGF(infof(conn->data, "DO phase starts\n")); - - if(data->set.opt_no_body) { - /* Requested no body means no transfer */ - smtp->transfer = FTPTRANSFER_INFO; - } - - *dophase_done = FALSE; /* not done yet */ - - /* Store the first recipient (or NULL if not specified) */ - smtp->rcpt = data->set.mail_rcpt; - - /* Start the first command in the DO phase */ - if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt) - /* MAIL transfer */ - result = smtp_perform_mail(conn); - else - /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */ - result = smtp_perform_command(conn); - - if(result) - return result; - - /* Run the state-machine */ - result = smtp_multi_statemach(conn, dophase_done); - - *connected = conn->bits.tcpconnect[FIRSTSOCKET]; - - if(*dophase_done) - DEBUGF(infof(conn->data, "DO phase is complete\n")); - - return result; -} - -/*********************************************************************** - * - * smtp_do() - * - * This function is registered as 'curl_do' function. It decodes the path - * parts etc as a wrapper to the actual DO function (smtp_perform). - * - * The input argument is already checked for validity. - */ -static CURLcode smtp_do(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - - *done = FALSE; /* default to false */ - - /* Parse the custom request */ - result = smtp_parse_custom_request(conn); - if(result) - return result; - - result = smtp_regular_transfer(conn, done); - - return result; -} - -/*********************************************************************** - * - * smtp_disconnect() - * - * Disconnect from an SMTP server. Cleanup protocol-specific per-connection - * resources. BLOCKING. - */ -static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) -{ - struct smtp_conn *smtpc = &conn->proto.smtpc; - - /* We cannot send quit unconditionally. If this connection is stale or - bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. */ - - /* The SMTP session may or may not have been allocated/setup at this - point! */ - if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart) - if(!smtp_perform_quit(conn)) - (void)smtp_block_statemach(conn); /* ignore errors on QUIT */ - - /* Disconnect from the server */ - Curl_pp_disconnect(&smtpc->pp); - - /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, smtpc->sasl.authused); - - /* Cleanup our connection based variables */ - Curl_safefree(smtpc->domain); - - return CURLE_OK; -} - -/* Call this when the DO phase has completed */ -static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected) -{ - struct SMTP *smtp = conn->data->req.protop; - - (void)connected; - - if(smtp->transfer != FTPTRANSFER_BODY) - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - return CURLE_OK; -} - -/* Called from multi.c while DOing */ -static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done) -{ - CURLcode result = smtp_multi_statemach(conn, dophase_done); - - if(result) - DEBUGF(infof(conn->data, "DO phase failed\n")); - else if(*dophase_done) { - result = smtp_dophase_done(conn, FALSE /* not connected */); - - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - - return result; -} - -/*********************************************************************** - * - * smtp_regular_transfer() - * - * The input argument is already checked for validity. - * - * Performs all commands done before a regular transfer between a local and a - * remote host. - */ -static CURLcode smtp_regular_transfer(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - bool connected = FALSE; - struct Curl_easy *data = conn->data; - - /* Make sure size is unknown at this point */ - data->req.size = -1; - - /* Set the progress data */ - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, -1); - Curl_pgrsSetDownloadSize(data, -1); - - /* Carry out the perform */ - result = smtp_perform(conn, &connected, dophase_done); - - /* Perform post DO phase operations if necessary */ - if(!result && *dophase_done) - result = smtp_dophase_done(conn, connected); - - return result; -} - -static CURLcode smtp_setup_connection(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - CURLcode result; - - /* Clear the TLS upgraded flag */ - conn->tls_upgraded = FALSE; - - /* Initialise the SMTP layer */ - result = smtp_init(conn); - if(result) - return result; - - data->state.path++; /* don't include the initial slash */ - - return CURLE_OK; -} - -/*********************************************************************** - * - * smtp_parse_url_options() - * - * Parse the URL login options. - */ -static CURLcode smtp_parse_url_options(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *ptr = conn->options; - - smtpc->sasl.resetprefs = TRUE; - - while(!result && ptr && *ptr) { - const char *key = ptr; - const char *value; - - while(*ptr && *ptr != '=') - ptr++; - - value = ptr + 1; - - while(*ptr && *ptr != ';') - ptr++; - - if(strncasecompare(key, "AUTH=", 5)) - result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, - value, ptr - value); - else - result = CURLE_URL_MALFORMAT; - - if(*ptr == ';') - ptr++; - } - - return result; -} - -/*********************************************************************** - * - * smtp_parse_url_path() - * - * Parse the URL path into separate path components. - */ -static CURLcode smtp_parse_url_path(struct connectdata *conn) -{ - /* The SMTP struct is already initialised in smtp_connect() */ - struct Curl_easy *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *path = data->state.path; - char localhost[HOSTNAME_MAX + 1]; - - /* Calculate the path if necessary */ - if(!*path) { - if(!Curl_gethostname(localhost, sizeof(localhost))) - path = localhost; - else - path = "localhost"; - } - - /* URL decode the path and use it as the domain in our EHLO */ - return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); -} - -/*********************************************************************** - * - * smtp_parse_custom_request() - * - * Parse the custom request. - */ -static CURLcode smtp_parse_custom_request(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SMTP *smtp = data->req.protop; - const char *custom = data->set.str[STRING_CUSTOMREQUEST]; - - /* URL decode the custom request */ - if(custom) - result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE); - - return result; -} - -CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) -{ - /* When sending a SMTP payload we must detect CRLF. sequences making sure - they are sent as CRLF.. instead, as a . on the beginning of a line will - be deleted by the server when not part of an EOB terminator and a - genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of - data by the server - */ - ssize_t i; - ssize_t si; - struct Curl_easy *data = conn->data; - struct SMTP *smtp = data->req.protop; - char *scratch = data->state.scratch; - char *newscratch = NULL; - char *oldscratch = NULL; - size_t eob_sent; - - /* Do we need to allocate a scratch buffer? */ - if(!scratch || data->set.crlf) { - oldscratch = scratch; - - scratch = newscratch = malloc(2 * data->set.buffer_size); - if(!newscratch) { - failf(data, "Failed to alloc scratch buffer!"); - - return CURLE_OUT_OF_MEMORY; - } - } - - /* Have we already sent part of the EOB? */ - eob_sent = smtp->eob; - - /* This loop can be improved by some kind of Boyer-Moore style of - approach but that is saved for later... */ - for(i = 0, si = 0; i < nread; i++) { - if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) { - smtp->eob++; - - /* Is the EOB potentially the terminating CRLF? */ - if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob) - smtp->trailing_crlf = TRUE; - else - smtp->trailing_crlf = FALSE; - } - else if(smtp->eob) { - /* A previous substring matched so output that first */ - memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); - si += smtp->eob - eob_sent; - - /* Then compare the first byte */ - if(SMTP_EOB[0] == data->req.upload_fromhere[i]) - smtp->eob = 1; - else - smtp->eob = 0; - - eob_sent = 0; - - /* Reset the trailing CRLF flag as there was more data */ - smtp->trailing_crlf = FALSE; - } - - /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */ - if(SMTP_EOB_FIND_LEN == smtp->eob) { - /* Copy the replacement data to the target buffer */ - memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent], - SMTP_EOB_REPL_LEN - eob_sent); - si += SMTP_EOB_REPL_LEN - eob_sent; - smtp->eob = 0; - eob_sent = 0; - } - else if(!smtp->eob) - scratch[si++] = data->req.upload_fromhere[i]; - } - - if(smtp->eob - eob_sent) { - /* A substring matched before processing ended so output that now */ - memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); - si += smtp->eob - eob_sent; - } - - /* Only use the new buffer if we replaced something */ - if(si != nread) { - /* Upload from the new (replaced) buffer instead */ - data->req.upload_fromhere = scratch; - - /* Save the buffer so it can be freed later */ - data->state.scratch = scratch; - - /* Free the old scratch buffer */ - free(oldscratch); - - /* Set the new amount too */ - data->req.upload_present = si; - } - else - free(newscratch); - - return CURLE_OK; -} - -#endif /* CURL_DISABLE_SMTP */ diff --git a/dep/cpr/opt/curl/lib/smtp.h b/dep/cpr/opt/curl/lib/smtp.h deleted file mode 100644 index b67340a40cc..00000000000 --- a/dep/cpr/opt/curl/lib/smtp.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef HEADER_CURL_SMTP_H -#define HEADER_CURL_SMTP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2009 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "pingpong.h" -#include "curl_sasl.h" - -/**************************************************************************** - * SMTP unique setup - ***************************************************************************/ -typedef enum { - SMTP_STOP, /* do nothing state, stops the state machine */ - SMTP_SERVERGREET, /* waiting for the initial greeting immediately after - a connect */ - SMTP_EHLO, - SMTP_HELO, - SMTP_STARTTLS, - SMTP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS - (multi mode only) */ - SMTP_AUTH, - SMTP_COMMAND, /* VRFY, EXPN, NOOP, RSET and HELP */ - SMTP_MAIL, /* MAIL FROM */ - SMTP_RCPT, /* RCPT TO */ - SMTP_DATA, - SMTP_POSTDATA, - SMTP_QUIT, - SMTP_LAST /* never used */ -} smtpstate; - -/* This SMTP struct is used in the Curl_easy. All SMTP data that is - connection-oriented must be in smtp_conn to properly deal with the fact that - perhaps the Curl_easy is changed between the times the connection is - used. */ -struct SMTP { - curl_pp_transfer transfer; - char *custom; /* Custom Request */ - struct curl_slist *rcpt; /* Recipient list */ - size_t eob; /* Number of bytes of the EOB (End Of Body) that - have been received so far */ - bool trailing_crlf; /* Specifies if the tailing CRLF is present */ -}; - -/* smtp_conn is used for struct connection-oriented data in the connectdata - struct */ -struct smtp_conn { - struct pingpong pp; - smtpstate state; /* Always use smtp.c:state() to change state! */ - bool ssldone; /* Is connect() over SSL done? */ - char *domain; /* Client address/name to send in the EHLO */ - struct SASL sasl; /* SASL-related storage */ - bool tls_supported; /* StartTLS capability supported by server */ - bool size_supported; /* If server supports SIZE extension according to - RFC 1870 */ - bool auth_supported; /* AUTH capability supported by server */ -}; - -extern const struct Curl_handler Curl_handler_smtp; -extern const struct Curl_handler Curl_handler_smtps; - -/* this is the 5-bytes End-Of-Body marker for SMTP */ -#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a" -#define SMTP_EOB_LEN 5 -#define SMTP_EOB_FIND_LEN 3 - -/* if found in data, replace it with this string instead */ -#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e" -#define SMTP_EOB_REPL_LEN 4 - -CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread); - -#endif /* HEADER_CURL_SMTP_H */ diff --git a/dep/cpr/opt/curl/lib/sockaddr.h b/dep/cpr/opt/curl/lib/sockaddr.h deleted file mode 100644 index 95ba4c3c97c..00000000000 --- a/dep/cpr/opt/curl/lib/sockaddr.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef HEADER_CURL_SOCKADDR_H -#define HEADER_CURL_SOCKADDR_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -struct Curl_sockaddr_storage { - union { - struct sockaddr sa; - struct sockaddr_in sa_in; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 sa_in6; -#endif -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE - struct sockaddr_storage sa_stor; -#else - char cbuf[256]; /* this should be big enough to fit a lot */ -#endif - } buffer; -}; - -#endif /* HEADER_CURL_SOCKADDR_H */ - diff --git a/dep/cpr/opt/curl/lib/socks.c b/dep/cpr/opt/curl/lib/socks.c deleted file mode 100644 index e64cb98d41d..00000000000 --- a/dep/cpr/opt/curl/lib/socks.c +++ /dev/null @@ -1,792 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_PROXY) - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "select.h" -#include "connect.h" -#include "timeval.h" -#include "socks.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * Helper read-from-socket functions. Does the same as Curl_read() but it - * blocks until all bytes amount of buffersize will be read. No more, no less. - * - * This is STUPID BLOCKING behaviour which we frown upon, but right now this - * is what we have... - */ -int Curl_blockread_all(struct connectdata *conn, /* connection data */ - curl_socket_t sockfd, /* read from this socket */ - char *buf, /* store read data here */ - ssize_t buffersize, /* max amount to read */ - ssize_t *n) /* amount bytes read */ -{ - ssize_t nread; - ssize_t allread = 0; - int result; - time_t timeleft; - *n = 0; - for(;;) { - timeleft = Curl_timeleft(conn->data, NULL, TRUE); - if(timeleft < 0) { - /* we already got the timeout */ - result = CURLE_OPERATION_TIMEDOUT; - break; - } - if(SOCKET_READABLE(sockfd, timeleft) <= 0) { - result = ~CURLE_OK; - break; - } - result = Curl_read_plain(sockfd, buf, buffersize, &nread); - if(CURLE_AGAIN == result) - continue; - if(result) - break; - - if(buffersize == nread) { - allread += nread; - *n = allread; - result = CURLE_OK; - break; - } - if(!nread) { - result = ~CURLE_OK; - break; - } - - buffersize -= nread; - buf += nread; - allread += nread; - } - return result; -} - -/* -* This function logs in to a SOCKS4 proxy and sends the specifics to the final -* destination server. -* -* Reference : -* http://socks.permeo.com/protocol/socks4.protocol -* -* Note : -* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" -* Nonsupport "Identification Protocol (RFC1413)" -*/ -CURLcode Curl_SOCKS4(const char *proxy_user, - const char *hostname, - int remote_port, - int sockindex, - struct connectdata *conn) -{ - const bool protocol4a = - (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE; -#define SOCKS4REQLEN 262 - unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user - id */ - int result; - CURLcode code; - curl_socket_t sock = conn->sock[sockindex]; - struct Curl_easy *data = conn->data; - - if(Curl_timeleft(data, NULL, TRUE) < 0) { - /* time-out, bail out, go home */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(conn->bits.httpproxy) - infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n", - protocol4a ? "a" : "", hostname, remote_port); - - (void)curlx_nonblock(sock, FALSE); - - infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port); - - /* - * Compose socks4 request - * - * Request format - * - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * | VN | CD | DSTPORT | DSTIP | USERID |NULL| - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * # of bytes: 1 1 2 4 variable 1 - */ - - socksreq[0] = 4; /* version (SOCKS4) */ - socksreq[1] = 1; /* connect */ - socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */ - socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */ - - /* DNS resolve only for SOCKS4, not SOCKS4a */ - if(!protocol4a) { - struct Curl_dns_entry *dns; - Curl_addrinfo *hp = NULL; - int rc; - - rc = Curl_resolv(conn, hostname, remote_port, &dns); - - if(rc == CURLRESOLV_ERROR) - return CURLE_COULDNT_RESOLVE_PROXY; - - if(rc == CURLRESOLV_PENDING) - /* ignores the return code, but 'dns' remains NULL on failure */ - (void)Curl_resolver_wait_resolv(conn, &dns); - - /* - * We cannot use 'hostent' as a struct that Curl_resolv() returns. It - * returns a Curl_addrinfo pointer that may not always look the same. - */ - if(dns) - hp = dns->addr; - if(hp) { - char buf[64]; - Curl_printable_address(hp, buf, sizeof(buf)); - - if(hp->ai_family == AF_INET) { - struct sockaddr_in *saddr_in; - - saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; - socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0]; - socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1]; - socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2]; - socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3]; - - infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf); - } - else { - hp = NULL; /* fail! */ - - failf(data, "SOCKS4 connection to %s not supported\n", buf); - } - - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ - } - if(!hp) { - failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", - hostname); - return CURLE_COULDNT_RESOLVE_HOST; - } - } - - /* - * This is currently not supporting "Identification Protocol (RFC1413)". - */ - socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ - if(proxy_user) { - size_t plen = strlen(proxy_user); - if(plen >= sizeof(socksreq) - 8) { - failf(data, "Too long SOCKS proxy name, can't use!\n"); - return CURLE_COULDNT_CONNECT; - } - /* copy the proxy name WITH trailing zero */ - memcpy(socksreq + 8, proxy_user, plen + 1); - } - - /* - * Make connection - */ - { - ssize_t actualread; - ssize_t written; - ssize_t hostnamelen = 0; - int packetsize = 9 + - (int)strlen((char *)socksreq + 8); /* size including NUL */ - - /* If SOCKS4a, set special invalid IP address 0.0.0.x */ - if(protocol4a) { - socksreq[4] = 0; - socksreq[5] = 0; - socksreq[6] = 0; - socksreq[7] = 1; - /* If still enough room in buffer, also append hostname */ - hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */ - if(packetsize + hostnamelen <= SOCKS4REQLEN) - strcpy((char *)socksreq + packetsize, hostname); - else - hostnamelen = 0; /* Flag: hostname did not fit in buffer */ - } - - /* Send request */ - code = Curl_write_plain(conn, sock, (char *)socksreq, - packetsize + hostnamelen, - &written); - if(code || (written != packetsize + hostnamelen)) { - failf(data, "Failed to send SOCKS4 connect request."); - return CURLE_COULDNT_CONNECT; - } - if(protocol4a && hostnamelen == 0) { - /* SOCKS4a with very long hostname - send that name separately */ - hostnamelen = (ssize_t)strlen(hostname) + 1; - code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen, - &written); - if(code || (written != hostnamelen)) { - failf(data, "Failed to send SOCKS4 connect request."); - return CURLE_COULDNT_CONNECT; - } - } - - packetsize = 8; /* receive data size */ - - /* Receive response */ - result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread); - if(result || (actualread != packetsize)) { - failf(data, "Failed to receive SOCKS4 connect request ack."); - return CURLE_COULDNT_CONNECT; - } - - /* - * Response format - * - * +----+----+----+----+----+----+----+----+ - * | VN | CD | DSTPORT | DSTIP | - * +----+----+----+----+----+----+----+----+ - * # of bytes: 1 1 2 4 - * - * VN is the version of the reply code and should be 0. CD is the result - * code with one of the following values: - * - * 90: request granted - * 91: request rejected or failed - * 92: request rejected because SOCKS server cannot connect to - * identd on the client - * 93: request rejected because the client program and identd - * report different user-ids - */ - - /* wrong version ? */ - if(socksreq[0] != 0) { - failf(data, - "SOCKS4 reply has wrong version, version should be 4."); - return CURLE_COULDNT_CONNECT; - } - - /* Result */ - switch(socksreq[1]) { - case 90: - infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":""); - break; - case 91: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected or failed.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; - case 92: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected because SOCKS server cannot connect to " - "identd on the client.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; - case 93: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected because the client program and identd " - "report different user-ids.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; - default: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", Unknown.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; - } - } - - (void)curlx_nonblock(sock, TRUE); - - return CURLE_OK; /* Proxy was successful! */ -} - -/* - * This function logs in to a SOCKS5 proxy and sends the specifics to the final - * destination server. - */ -CURLcode Curl_SOCKS5(const char *proxy_user, - const char *proxy_password, - const char *hostname, - int remote_port, - int sockindex, - struct connectdata *conn) -{ - /* - According to the RFC1928, section "6. Replies". This is what a SOCK5 - replies: - - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ - - Where: - - o VER protocol version: X'05' - o REP Reply field: - o X'00' succeeded - */ - - unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ - int idx; - ssize_t actualread; - ssize_t written; - int result; - CURLcode code; - curl_socket_t sock = conn->sock[sockindex]; - struct Curl_easy *data = conn->data; - time_t timeout; - bool socks5_resolve_local = - (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; - const size_t hostname_len = strlen(hostname); - ssize_t len = 0; - const unsigned long auth = data->set.socks5auth; - bool allow_gssapi = FALSE; - - if(conn->bits.httpproxy) - infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n", - hostname, remote_port); - - /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ - if(!socks5_resolve_local && hostname_len > 255) { - infof(conn->data, "SOCKS5: server resolving disabled for hostnames of " - "length > 255 [actual len=%zu]\n", hostname_len); - socks5_resolve_local = TRUE; - } - - /* get timeout */ - timeout = Curl_timeleft(data, NULL, TRUE); - - if(timeout < 0) { - /* time-out, bail out, go home */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - (void)curlx_nonblock(sock, TRUE); - - /* wait until socket gets connected */ - result = SOCKET_WRITABLE(sock, timeout); - - if(-1 == result) { - failf(conn->data, "SOCKS5: no connection here"); - return CURLE_COULDNT_CONNECT; - } - if(0 == result) { - failf(conn->data, "SOCKS5: connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(result & CURL_CSELECT_ERR) { - failf(conn->data, "SOCKS5: error occurred during connection"); - return CURLE_COULDNT_CONNECT; - } - - if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) - infof(conn->data, - "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n", - auth); - if(!(auth & CURLAUTH_BASIC)) - /* disable username/password auth */ - proxy_user = NULL; -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(auth & CURLAUTH_GSSAPI) - allow_gssapi = TRUE; -#endif - - idx = 0; - socksreq[idx++] = 5; /* version */ - idx++; /* reserve for the number of authentication methods */ - socksreq[idx++] = 0; /* no authentication */ - if(allow_gssapi) - socksreq[idx++] = 1; /* GSS-API */ - if(proxy_user) - socksreq[idx++] = 2; /* username/password */ - /* write the number of authentication methods */ - socksreq[1] = (unsigned char) (idx - 2); - - (void)curlx_nonblock(sock, FALSE); - - infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port); - - code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), - &written); - if(code || (written != (2 + (int)socksreq[1]))) { - failf(data, "Unable to send initial SOCKS5 request."); - return CURLE_COULDNT_CONNECT; - } - - (void)curlx_nonblock(sock, TRUE); - - result = SOCKET_READABLE(sock, timeout); - - if(-1 == result) { - failf(conn->data, "SOCKS5 nothing to read"); - return CURLE_COULDNT_CONNECT; - } - if(0 == result) { - failf(conn->data, "SOCKS5 read timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(result & CURL_CSELECT_ERR) { - failf(conn->data, "SOCKS5 read error occurred"); - return CURLE_RECV_ERROR; - } - - (void)curlx_nonblock(sock, FALSE); - - result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); - if(result || (actualread != 2)) { - failf(data, "Unable to receive initial SOCKS5 response."); - return CURLE_COULDNT_CONNECT; - } - - if(socksreq[0] != 5) { - failf(data, "Received invalid version in initial SOCKS5 response."); - return CURLE_COULDNT_CONNECT; - } - if(socksreq[1] == 0) { - /* Nothing to do, no authentication needed */ - ; - } -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - else if(allow_gssapi && (socksreq[1] == 1)) { - code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn); - if(code) { - failf(data, "Unable to negotiate SOCKS5 GSS-API context."); - return CURLE_COULDNT_CONNECT; - } - } -#endif - else if(socksreq[1] == 2) { - /* Needs user name and password */ - size_t proxy_user_len, proxy_password_len; - if(proxy_user && proxy_password) { - proxy_user_len = strlen(proxy_user); - proxy_password_len = strlen(proxy_password); - } - else { - proxy_user_len = 0; - proxy_password_len = 0; - } - - /* username/password request looks like - * +----+------+----------+------+----------+ - * |VER | ULEN | UNAME | PLEN | PASSWD | - * +----+------+----------+------+----------+ - * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | - * +----+------+----------+------+----------+ - */ - len = 0; - socksreq[len++] = 1; /* username/pw subnegotiation version */ - socksreq[len++] = (unsigned char) proxy_user_len; - if(proxy_user && proxy_user_len) - memcpy(socksreq + len, proxy_user, proxy_user_len); - len += proxy_user_len; - socksreq[len++] = (unsigned char) proxy_password_len; - if(proxy_password && proxy_password_len) - memcpy(socksreq + len, proxy_password, proxy_password_len); - len += proxy_password_len; - - code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written); - if(code || (len != written)) { - failf(data, "Failed to send SOCKS5 sub-negotiation request."); - return CURLE_COULDNT_CONNECT; - } - - result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); - if(result || (actualread != 2)) { - failf(data, "Unable to receive SOCKS5 sub-negotiation response."); - return CURLE_COULDNT_CONNECT; - } - - /* ignore the first (VER) byte */ - if(socksreq[1] != 0) { /* status */ - failf(data, "User was rejected by the SOCKS5 server (%d %d).", - socksreq[0], socksreq[1]); - return CURLE_COULDNT_CONNECT; - } - - /* Everything is good so far, user was authenticated! */ - } - else { - /* error */ - if(!allow_gssapi && (socksreq[1] == 1)) { - failf(data, - "SOCKS5 GSSAPI per-message authentication is not supported."); - return CURLE_COULDNT_CONNECT; - } - if(socksreq[1] == 255) { - if(!proxy_user || !*proxy_user) { - failf(data, - "No authentication method was acceptable. (It is quite likely" - " that the SOCKS5 server wanted a username/password, since none" - " was supplied to the server on this connection.)"); - } - else { - failf(data, "No authentication method was acceptable."); - } - return CURLE_COULDNT_CONNECT; - } - else { - failf(data, - "Undocumented SOCKS5 mode attempted to be used by server."); - return CURLE_COULDNT_CONNECT; - } - } - - /* Authentication is complete, now specify destination to the proxy */ - len = 0; - socksreq[len++] = 5; /* version (SOCKS5) */ - socksreq[len++] = 1; /* connect */ - socksreq[len++] = 0; /* must be zero */ - - if(!socks5_resolve_local) { - socksreq[len++] = 3; /* ATYP: domain name = 3 */ - socksreq[len++] = (char) hostname_len; /* address length */ - memcpy(&socksreq[len], hostname, hostname_len); /* address str w/o NULL */ - len += hostname_len; - } - else { - struct Curl_dns_entry *dns; - Curl_addrinfo *hp = NULL; - int rc = Curl_resolv(conn, hostname, remote_port, &dns); - - if(rc == CURLRESOLV_ERROR) - return CURLE_COULDNT_RESOLVE_HOST; - - if(rc == CURLRESOLV_PENDING) { - /* this requires that we're in "wait for resolve" state */ - code = Curl_resolver_wait_resolv(conn, &dns); - if(code) - return code; - } - - /* - * We cannot use 'hostent' as a struct that Curl_resolv() returns. It - * returns a Curl_addrinfo pointer that may not always look the same. - */ - if(dns) - hp = dns->addr; - if(hp) { - int i; - char buf[64]; - Curl_printable_address(hp, buf, sizeof(buf)); - - if(hp->ai_family == AF_INET) { - struct sockaddr_in *saddr_in; - socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ - - saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; - for(i = 0; i < 4; i++) { - socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; - } - - infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", buf); - } -#ifdef ENABLE_IPV6 - else if(hp->ai_family == AF_INET6) { - struct sockaddr_in6 *saddr_in6; - socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ - - saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; - for(i = 0; i < 16; i++) { - socksreq[len++] = - ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; - } - - infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", buf); - } -#endif - else { - hp = NULL; /* fail! */ - - failf(data, "SOCKS5 connection to %s not supported\n", buf); - } - - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ - } - if(!hp) { - failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", - hostname); - return CURLE_COULDNT_RESOLVE_HOST; - } - } - - socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */ - socksreq[len++] = (unsigned char)(remote_port & 0xff); /* PORT LSB */ - -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 GSS-API protection not yet implemented."); - } - else -#endif - code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written); - - if(code || (len != written)) { - failf(data, "Failed to send SOCKS5 connect request."); - return CURLE_COULDNT_CONNECT; - } - - len = 10; /* minimum packet size is 10 */ - -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 GSS-API protection not yet implemented."); - } - else -#endif - result = Curl_blockread_all(conn, sock, (char *)socksreq, - len, &actualread); - - if(result || (len != actualread)) { - failf(data, "Failed to receive SOCKS5 connect request ack."); - return CURLE_COULDNT_CONNECT; - } - - if(socksreq[0] != 5) { /* version */ - failf(data, - "SOCKS5 reply has wrong version, version should be 5."); - return CURLE_COULDNT_CONNECT; - } - - /* Fix: in general, returned BND.ADDR is variable length parameter by RFC - 1928, so the reply packet should be read until the end to avoid errors at - subsequent protocol level. - - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ - - ATYP: - o IP v4 address: X'01', BND.ADDR = 4 byte - o domain name: X'03', BND.ADDR = [ 1 byte length, string ] - o IP v6 address: X'04', BND.ADDR = 16 byte - */ - - /* Calculate real packet size */ - if(socksreq[3] == 3) { - /* domain name */ - int addrlen = (int) socksreq[4]; - len = 5 + addrlen + 2; - } - else if(socksreq[3] == 4) { - /* IPv6 */ - len = 4 + 16 + 2; - } - - /* At this point we already read first 10 bytes */ -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(!conn->socks5_gssapi_enctype) { - /* decrypt_gssapi_blockread already read the whole packet */ -#endif - if(len > 10) { - result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], - len - 10, &actualread); - if(result || ((len - 10) != actualread)) { - failf(data, "Failed to receive SOCKS5 connect request ack."); - return CURLE_COULDNT_CONNECT; - } - } -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - } -#endif - - if(socksreq[1] != 0) { /* Anything besides 0 is an error */ - if(socksreq[3] == 1) { - failf(data, - "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[8] << 8) | - (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - else if(socksreq[3] == 3) { - unsigned char port_upper = (unsigned char)socksreq[len - 2]; - socksreq[len - 2] = 0; - failf(data, - "Can't complete SOCKS5 connection to %s:%d. (%d)", - (char *)&socksreq[5], - ((port_upper << 8) | - (unsigned char)socksreq[len - 1]), - (unsigned char)socksreq[1]); - socksreq[len - 2] = port_upper; - } - else if(socksreq[3] == 4) { - failf(data, - "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:" - "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned char)socksreq[8], (unsigned char)socksreq[9], - (unsigned char)socksreq[10], (unsigned char)socksreq[11], - (unsigned char)socksreq[12], (unsigned char)socksreq[13], - (unsigned char)socksreq[14], (unsigned char)socksreq[15], - (unsigned char)socksreq[16], (unsigned char)socksreq[17], - (unsigned char)socksreq[18], (unsigned char)socksreq[19], - (((unsigned char)socksreq[20] << 8) | - (unsigned char)socksreq[21]), - (unsigned char)socksreq[1]); - } - return CURLE_COULDNT_CONNECT; - } - infof(data, "SOCKS5 request granted.\n"); - - (void)curlx_nonblock(sock, TRUE); - return CURLE_OK; /* Proxy was successful! */ -} - -#endif /* CURL_DISABLE_PROXY */ - diff --git a/dep/cpr/opt/curl/lib/socks.h b/dep/cpr/opt/curl/lib/socks.h deleted file mode 100644 index 348707e74d4..00000000000 --- a/dep/cpr/opt/curl/lib/socks.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef HEADER_CURL_SOCKS_H -#define HEADER_CURL_SOCKS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef CURL_DISABLE_PROXY -#define Curl_SOCKS4(a,b,c,d,e) CURLE_NOT_BUILT_IN -#define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN -#else -/* - * Helper read-from-socket functions. Does the same as Curl_read() but it - * blocks until all bytes amount of buffersize will be read. No more, no less. - * - * This is STUPID BLOCKING behaviour which we frown upon, but right now this - * is what we have... - */ -int Curl_blockread_all(struct connectdata *conn, - curl_socket_t sockfd, - char *buf, - ssize_t buffersize, - ssize_t *n); - -/* - * This function logs in to a SOCKS4(a) proxy and sends the specifics to the - * final destination server. - */ -CURLcode Curl_SOCKS4(const char *proxy_name, - const char *hostname, - int remote_port, - int sockindex, - struct connectdata *conn); - -/* - * This function logs in to a SOCKS5 proxy and sends the specifics to the - * final destination server. - */ -CURLcode Curl_SOCKS5(const char *proxy_name, - const char *proxy_password, - const char *hostname, - int remote_port, - int sockindex, - struct connectdata *conn); - -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) -/* - * This function handles the SOCKS5 GSS-API negotiation and initialisation - */ -CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, - struct connectdata *conn); -#endif - -#endif /* CURL_DISABLE_PROXY */ - -#endif /* HEADER_CURL_SOCKS_H */ - diff --git a/dep/cpr/opt/curl/lib/socks_gssapi.c b/dep/cpr/opt/curl/lib/socks_gssapi.c deleted file mode 100644 index 96948ac4ba2..00000000000 --- a/dep/cpr/opt/curl/lib/socks_gssapi.c +++ /dev/null @@ -1,527 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2009, Markus Moeller, - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY) - -#include "curl_gssapi.h" -#include "urldata.h" -#include "sendf.h" -#include "connect.h" -#include "timeval.h" -#include "socks.h" -#include "warnless.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; - -/* - * Helper GSS-API error functions. - */ -static int check_gss_err(struct Curl_easy *data, - OM_uint32 major_status, - OM_uint32 minor_status, - const char *function) -{ - if(GSS_ERROR(major_status)) { - OM_uint32 maj_stat, min_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - char buf[1024]; - size_t len; - - len = 0; - msg_ctx = 0; - while(!msg_ctx) { - /* convert major status code (GSS-API error) to text */ - maj_stat = gss_display_status(&min_stat, major_status, - GSS_C_GSS_CODE, - GSS_C_NULL_OID, - &msg_ctx, &status_string); - if(maj_stat == GSS_S_COMPLETE) { - if(sizeof(buf) > len + status_string.length + 1) { - strcpy(buf + len, (char *) status_string.value); - len += status_string.length; - } - gss_release_buffer(&min_stat, &status_string); - break; - } - gss_release_buffer(&min_stat, &status_string); - } - if(sizeof(buf) > len + 3) { - strcpy(buf + len, ".\n"); - len += 2; - } - msg_ctx = 0; - while(!msg_ctx) { - /* convert minor status code (underlying routine error) to text */ - maj_stat = gss_display_status(&min_stat, minor_status, - GSS_C_MECH_CODE, - GSS_C_NULL_OID, - &msg_ctx, &status_string); - if(maj_stat == GSS_S_COMPLETE) { - if(sizeof(buf) > len + status_string.length) - strcpy(buf + len, (char *) status_string.value); - gss_release_buffer(&min_stat, &status_string); - break; - } - gss_release_buffer(&min_stat, &status_string); - } - failf(data, "GSS-API error: %s failed:\n%s", function, buf); - return 1; - } - - return 0; -} - -CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, - struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - curl_socket_t sock = conn->sock[sockindex]; - CURLcode code; - ssize_t actualread; - ssize_t written; - int result; - OM_uint32 gss_major_status, gss_minor_status, gss_status; - OM_uint32 gss_ret_flags; - int gss_conf_state, gss_enc; - gss_buffer_desc service = GSS_C_EMPTY_BUFFER; - gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc* gss_token = GSS_C_NO_BUFFER; - gss_name_t server = GSS_C_NO_NAME; - gss_name_t gss_client_name = GSS_C_NO_NAME; - unsigned short us_length; - char *user = NULL; - unsigned char socksreq[4]; /* room for GSS-API exchange header only */ - const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? - data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; - const size_t serviceptr_length = strlen(serviceptr); - - /* GSS-API request looks like - * +----+------+-----+----------------+ - * |VER | MTYP | LEN | TOKEN | - * +----+------+----------------------+ - * | 1 | 1 | 2 | up to 2^16 - 1 | - * +----+------+-----+----------------+ - */ - - /* prepare service name */ - if(strchr(serviceptr, '/')) { - service.length = serviceptr_length; - service.value = malloc(service.length); - if(!service.value) - return CURLE_OUT_OF_MEMORY; - memcpy(service.value, serviceptr, service.length); - - gss_major_status = gss_import_name(&gss_minor_status, &service, - (gss_OID) GSS_C_NULL_OID, &server); - } - else { - service.value = malloc(serviceptr_length + - strlen(conn->socks_proxy.host.name) + 2); - if(!service.value) - return CURLE_OUT_OF_MEMORY; - service.length = serviceptr_length + - strlen(conn->socks_proxy.host.name) + 1; - snprintf(service.value, service.length + 1, "%s@%s", - serviceptr, conn->socks_proxy.host.name); - - gss_major_status = gss_import_name(&gss_minor_status, &service, - GSS_C_NT_HOSTBASED_SERVICE, &server); - } - - gss_release_buffer(&gss_status, &service); /* clear allocated memory */ - - if(check_gss_err(data, gss_major_status, - gss_minor_status, "gss_import_name()")) { - failf(data, "Failed to create service name."); - gss_release_name(&gss_status, &server); - return CURLE_COULDNT_CONNECT; - } - - /* As long as we need to keep sending some context info, and there's no */ - /* errors, keep sending it... */ - for(;;) { - gss_major_status = Curl_gss_init_sec_context(data, - &gss_minor_status, - &gss_context, - server, - &Curl_krb5_mech_oid, - NULL, - gss_token, - &gss_send_token, - TRUE, - &gss_ret_flags); - - if(gss_token != GSS_C_NO_BUFFER) - gss_release_buffer(&gss_status, &gss_recv_token); - if(check_gss_err(data, gss_major_status, - gss_minor_status, "gss_init_sec_context")) { - gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); - gss_release_buffer(&gss_status, &gss_send_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - failf(data, "Failed to initial GSS-API token."); - return CURLE_COULDNT_CONNECT; - } - - if(gss_send_token.length != 0) { - socksreq[0] = 1; /* GSS-API subnegotiation version */ - socksreq[1] = 1; /* authentication message type */ - us_length = htons((short)gss_send_token.length); - memcpy(socksreq + 2, &us_length, sizeof(short)); - - code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if(code || (4 != written)) { - failf(data, "Failed to send GSS-API authentication request."); - gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); - gss_release_buffer(&gss_status, &gss_send_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - code = Curl_write_plain(conn, sock, (char *)gss_send_token.value, - gss_send_token.length, &written); - - if(code || ((ssize_t)gss_send_token.length != written)) { - failf(data, "Failed to send GSS-API authentication token."); - gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); - gss_release_buffer(&gss_status, &gss_send_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - } - - gss_release_buffer(&gss_status, &gss_send_token); - gss_release_buffer(&gss_status, &gss_recv_token); - if(gss_major_status != GSS_S_CONTINUE_NEEDED) break; - - /* analyse response */ - - /* GSS-API response looks like - * +----+------+-----+----------------+ - * |VER | MTYP | LEN | TOKEN | - * +----+------+----------------------+ - * | 1 | 1 | 2 | up to 2^16 - 1 | - * +----+------+-----+----------------+ - */ - - result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); - if(result || (actualread != 4)) { - failf(data, "Failed to receive GSS-API authentication response."); - gss_release_name(&gss_status, &server); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - /* ignore the first (VER) byte */ - if(socksreq[1] == 255) { /* status / message type */ - failf(data, "User was rejected by the SOCKS5 server (%d %d).", - socksreq[0], socksreq[1]); - gss_release_name(&gss_status, &server); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - if(socksreq[1] != 1) { /* status / messgae type */ - failf(data, "Invalid GSS-API authentication response type (%d %d).", - socksreq[0], socksreq[1]); - gss_release_name(&gss_status, &server); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - memcpy(&us_length, socksreq + 2, sizeof(short)); - us_length = ntohs(us_length); - - gss_recv_token.length = us_length; - gss_recv_token.value = malloc(us_length); - if(!gss_recv_token.value) { - failf(data, - "Could not allocate memory for GSS-API authentication " - "response token."); - gss_release_name(&gss_status, &server); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_OUT_OF_MEMORY; - } - - result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, &actualread); - - if(result || (actualread != us_length)) { - failf(data, "Failed to receive GSS-API authentication token."); - gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - gss_token = &gss_recv_token; - } - - gss_release_name(&gss_status, &server); - - /* Everything is good so far, user was authenticated! */ - gss_major_status = gss_inquire_context(&gss_minor_status, gss_context, - &gss_client_name, NULL, NULL, NULL, - NULL, NULL, NULL); - if(check_gss_err(data, gss_major_status, - gss_minor_status, "gss_inquire_context")) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); - gss_release_name(&gss_status, &gss_client_name); - failf(data, "Failed to determine user name."); - return CURLE_COULDNT_CONNECT; - } - gss_major_status = gss_display_name(&gss_minor_status, gss_client_name, - &gss_send_token, NULL); - if(check_gss_err(data, gss_major_status, - gss_minor_status, "gss_display_name")) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); - gss_release_name(&gss_status, &gss_client_name); - gss_release_buffer(&gss_status, &gss_send_token); - failf(data, "Failed to determine user name."); - return CURLE_COULDNT_CONNECT; - } - user = malloc(gss_send_token.length + 1); - if(!user) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); - gss_release_name(&gss_status, &gss_client_name); - gss_release_buffer(&gss_status, &gss_send_token); - return CURLE_OUT_OF_MEMORY; - } - - memcpy(user, gss_send_token.value, gss_send_token.length); - user[gss_send_token.length] = '\0'; - gss_release_name(&gss_status, &gss_client_name); - gss_release_buffer(&gss_status, &gss_send_token); - infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user); - free(user); - user = NULL; - - /* Do encryption */ - socksreq[0] = 1; /* GSS-API subnegotiation version */ - socksreq[1] = 2; /* encryption message type */ - - gss_enc = 0; /* no data protection */ - /* do confidentiality protection if supported */ - if(gss_ret_flags & GSS_C_CONF_FLAG) - gss_enc = 2; - /* else do integrity protection */ - else if(gss_ret_flags & GSS_C_INTEG_FLAG) - gss_enc = 1; - - infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", - (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality")); - /* force for the moment to no data protection */ - gss_enc = 0; - /* - * Sending the encryption type in clear seems wrong. It should be - * protected with gss_seal()/gss_wrap(). See RFC1961 extract below - * The NEC reference implementations on which this is based is - * therefore at fault - * - * +------+------+------+.......................+ - * + ver | mtyp | len | token | - * +------+------+------+.......................+ - * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | - * +------+------+------+.......................+ - * - * Where: - * - * - "ver" is the protocol version number, here 1 to represent the - * first version of the SOCKS/GSS-API protocol - * - * - "mtyp" is the message type, here 2 to represent a protection - * -level negotiation message - * - * - "len" is the length of the "token" field in octets - * - * - "token" is the GSS-API encapsulated protection level - * - * The token is produced by encapsulating an octet containing the - * required protection level using gss_seal()/gss_wrap() with conf_req - * set to FALSE. The token is verified using gss_unseal()/ - * gss_unwrap(). - * - */ - if(data->set.socks5_gssapi_nec) { - us_length = htons((short)1); - memcpy(socksreq + 2, &us_length, sizeof(short)); - } - else { - gss_send_token.length = 1; - gss_send_token.value = malloc(1); - if(!gss_send_token.value) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_OUT_OF_MEMORY; - } - memcpy(gss_send_token.value, &gss_enc, 1); - - gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0, - GSS_C_QOP_DEFAULT, &gss_send_token, - &gss_conf_state, &gss_w_token); - - if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) { - gss_release_buffer(&gss_status, &gss_send_token); - gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - failf(data, "Failed to wrap GSS-API encryption value into token."); - return CURLE_COULDNT_CONNECT; - } - gss_release_buffer(&gss_status, &gss_send_token); - - us_length = htons((short)gss_w_token.length); - memcpy(socksreq + 2, &us_length, sizeof(short)); - } - - code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if(code || (4 != written)) { - failf(data, "Failed to send GSS-API encryption request."); - gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - if(data->set.socks5_gssapi_nec) { - memcpy(socksreq, &gss_enc, 1); - code = Curl_write_plain(conn, sock, socksreq, 1, &written); - if(code || ( 1 != written)) { - failf(data, "Failed to send GSS-API encryption type."); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - } - else { - code = Curl_write_plain(conn, sock, (char *)gss_w_token.value, - gss_w_token.length, &written); - if(code || ((ssize_t)gss_w_token.length != written)) { - failf(data, "Failed to send GSS-API encryption type."); - gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - gss_release_buffer(&gss_status, &gss_w_token); - } - - result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); - if(result || (actualread != 4)) { - failf(data, "Failed to receive GSS-API encryption response."); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - /* ignore the first (VER) byte */ - if(socksreq[1] == 255) { /* status / message type */ - failf(data, "User was rejected by the SOCKS5 server (%d %d).", - socksreq[0], socksreq[1]); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - if(socksreq[1] != 2) { /* status / messgae type */ - failf(data, "Invalid GSS-API encryption response type (%d %d).", - socksreq[0], socksreq[1]); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - memcpy(&us_length, socksreq + 2, sizeof(short)); - us_length = ntohs(us_length); - - gss_recv_token.length = us_length; - gss_recv_token.value = malloc(gss_recv_token.length); - if(!gss_recv_token.value) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_OUT_OF_MEMORY; - } - result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, &actualread); - - if(result || (actualread != us_length)) { - failf(data, "Failed to receive GSS-API encryptrion type."); - gss_release_buffer(&gss_status, &gss_recv_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - if(!data->set.socks5_gssapi_nec) { - gss_major_status = gss_unwrap(&gss_minor_status, gss_context, - &gss_recv_token, &gss_w_token, - 0, GSS_C_QOP_DEFAULT); - - if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) { - gss_release_buffer(&gss_status, &gss_recv_token); - gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - failf(data, "Failed to unwrap GSS-API encryption value into token."); - return CURLE_COULDNT_CONNECT; - } - gss_release_buffer(&gss_status, &gss_recv_token); - - if(gss_w_token.length != 1) { - failf(data, "Invalid GSS-API encryption response length (%d).", - gss_w_token.length); - gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - memcpy(socksreq, gss_w_token.value, gss_w_token.length); - gss_release_buffer(&gss_status, &gss_w_token); - } - else { - if(gss_recv_token.length != 1) { - failf(data, "Invalid GSS-API encryption response length (%d).", - gss_recv_token.length); - gss_release_buffer(&gss_status, &gss_recv_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); - return CURLE_COULDNT_CONNECT; - } - - memcpy(socksreq, gss_recv_token.value, gss_recv_token.length); - gss_release_buffer(&gss_status, &gss_recv_token); - } - - infof(data, "SOCKS5 access with%s protection granted.\n", - (socksreq[0] == 0)?"out GSS-API data": - ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); - - conn->socks5_gssapi_enctype = socksreq[0]; - if(socksreq[0] == 0) - gss_delete_sec_context(&gss_status, &gss_context, NULL); - - return CURLE_OK; -} - -#endif /* HAVE_GSSAPI && !CURL_DISABLE_PROXY */ diff --git a/dep/cpr/opt/curl/lib/socks_sspi.c b/dep/cpr/opt/curl/lib/socks_sspi.c deleted file mode 100644 index 34699d37427..00000000000 --- a/dep/cpr/opt/curl/lib/socks_sspi.c +++ /dev/null @@ -1,605 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * Copyright (C) 2009, 2011, Markus Moeller, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY) - -#include "urldata.h" -#include "sendf.h" -#include "connect.h" -#include "strerror.h" -#include "timeval.h" -#include "socks.h" -#include "curl_sspi.h" -#include "curl_multibyte.h" -#include "warnless.h" -#include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Helper sspi error functions. - */ -static int check_sspi_err(struct connectdata *conn, - SECURITY_STATUS status, - const char *function) -{ - if(status != SEC_E_OK && - status != SEC_I_COMPLETE_AND_CONTINUE && - status != SEC_I_COMPLETE_NEEDED && - status != SEC_I_CONTINUE_NEEDED) { - failf(conn->data, "SSPI error: %s failed: %s", function, - Curl_sspi_strerror(conn, status)); - return 1; - } - return 0; -} - -/* This is the SSPI-using version of this function */ -CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, - struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - curl_socket_t sock = conn->sock[sockindex]; - CURLcode code; - ssize_t actualread; - ssize_t written; - int result; - /* Needs GSS-API authentication */ - SECURITY_STATUS status; - unsigned long sspi_ret_flags = 0; - unsigned char gss_enc; - SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; - SecBufferDesc input_desc, output_desc, wrap_desc; - SecPkgContext_Sizes sspi_sizes; - CredHandle cred_handle; - CtxtHandle sspi_context; - PCtxtHandle context_handle = NULL; - SecPkgCredentials_Names names; - TimeStamp expiry; - char *service_name = NULL; - unsigned short us_length; - unsigned long qop; - unsigned char socksreq[4]; /* room for GSS-API exchange header only */ - const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? - data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; - const size_t service_length = strlen(service); - - /* GSS-API request looks like - * +----+------+-----+----------------+ - * |VER | MTYP | LEN | TOKEN | - * +----+------+----------------------+ - * | 1 | 1 | 2 | up to 2^16 - 1 | - * +----+------+-----+----------------+ - */ - - /* prepare service name */ - if(strchr(service, '/')) { - service_name = strdup(service); - if(!service_name) - return CURLE_OUT_OF_MEMORY; - } - else { - service_name = malloc(service_length + - strlen(conn->socks_proxy.host.name) + 2); - if(!service_name) - return CURLE_OUT_OF_MEMORY; - snprintf(service_name, service_length + - strlen(conn->socks_proxy.host.name) + 2, "%s/%s", - service, conn->socks_proxy.host.name); - } - - input_desc.cBuffers = 1; - input_desc.pBuffers = &sspi_recv_token; - input_desc.ulVersion = SECBUFFER_VERSION; - - sspi_recv_token.BufferType = SECBUFFER_TOKEN; - sspi_recv_token.cbBuffer = 0; - sspi_recv_token.pvBuffer = NULL; - - output_desc.cBuffers = 1; - output_desc.pBuffers = &sspi_send_token; - output_desc.ulVersion = SECBUFFER_VERSION; - - sspi_send_token.BufferType = SECBUFFER_TOKEN; - sspi_send_token.cbBuffer = 0; - sspi_send_token.pvBuffer = NULL; - - wrap_desc.cBuffers = 3; - wrap_desc.pBuffers = sspi_w_token; - wrap_desc.ulVersion = SECBUFFER_VERSION; - - cred_handle.dwLower = 0; - cred_handle.dwUpper = 0; - - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT("Kerberos"), - SECPKG_CRED_OUTBOUND, - NULL, - NULL, - NULL, - NULL, - &cred_handle, - &expiry); - - if(check_sspi_err(conn, status, "AcquireCredentialsHandle")) { - failf(data, "Failed to acquire credentials."); - free(service_name); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - return CURLE_COULDNT_CONNECT; - } - - /* As long as we need to keep sending some context info, and there's no */ - /* errors, keep sending it... */ - for(;;) { - TCHAR *sname; - - sname = Curl_convert_UTF8_to_tchar(service_name); - if(!sname) - return CURLE_OUT_OF_MEMORY; - - status = s_pSecFn->InitializeSecurityContext(&cred_handle, - context_handle, - sname, - ISC_REQ_MUTUAL_AUTH | - ISC_REQ_ALLOCATE_MEMORY | - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT, - 0, - SECURITY_NATIVE_DREP, - &input_desc, - 0, - &sspi_context, - &output_desc, - &sspi_ret_flags, - &expiry); - - Curl_unicodefree(sname); - - if(sspi_recv_token.pvBuffer) { - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - sspi_recv_token.pvBuffer = NULL; - sspi_recv_token.cbBuffer = 0; - } - - if(check_sspi_err(conn, status, "InitializeSecurityContext")) { - free(service_name); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - s_pSecFn->DeleteSecurityContext(&sspi_context); - if(sspi_recv_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - failf(data, "Failed to initialise security context."); - return CURLE_COULDNT_CONNECT; - } - - if(sspi_send_token.cbBuffer != 0) { - socksreq[0] = 1; /* GSS-API subnegotiation version */ - socksreq[1] = 1; /* authentication message type */ - us_length = htons((short)sspi_send_token.cbBuffer); - memcpy(socksreq + 2, &us_length, sizeof(short)); - - code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if(code || (4 != written)) { - failf(data, "Failed to send SSPI authentication request."); - free(service_name); - if(sspi_send_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - if(sspi_recv_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, - sspi_send_token.cbBuffer, &written); - if(code || (sspi_send_token.cbBuffer != (size_t)written)) { - failf(data, "Failed to send SSPI authentication token."); - free(service_name); - if(sspi_send_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - if(sspi_recv_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - } - - if(sspi_send_token.pvBuffer) { - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - sspi_send_token.pvBuffer = NULL; - } - sspi_send_token.cbBuffer = 0; - - if(sspi_recv_token.pvBuffer) { - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - sspi_recv_token.pvBuffer = NULL; - } - sspi_recv_token.cbBuffer = 0; - - if(status != SEC_I_CONTINUE_NEEDED) - break; - - /* analyse response */ - - /* GSS-API response looks like - * +----+------+-----+----------------+ - * |VER | MTYP | LEN | TOKEN | - * +----+------+----------------------+ - * | 1 | 1 | 2 | up to 2^16 - 1 | - * +----+------+-----+----------------+ - */ - - result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); - if(result || (actualread != 4)) { - failf(data, "Failed to receive SSPI authentication response."); - free(service_name); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - /* ignore the first (VER) byte */ - if(socksreq[1] == 255) { /* status / message type */ - failf(data, "User was rejected by the SOCKS5 server (%u %u).", - (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - free(service_name); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - if(socksreq[1] != 1) { /* status / messgae type */ - failf(data, "Invalid SSPI authentication response type (%u %u).", - (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - free(service_name); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - memcpy(&us_length, socksreq + 2, sizeof(short)); - us_length = ntohs(us_length); - - sspi_recv_token.cbBuffer = us_length; - sspi_recv_token.pvBuffer = malloc(us_length); - - if(!sspi_recv_token.pvBuffer) { - free(service_name); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; - } - result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer, - sspi_recv_token.cbBuffer, &actualread); - - if(result || (actualread != us_length)) { - failf(data, "Failed to receive SSPI authentication token."); - free(service_name); - if(sspi_recv_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - context_handle = &sspi_context; - } - - free(service_name); - - /* Everything is good so far, user was authenticated! */ - status = s_pSecFn->QueryCredentialsAttributes(&cred_handle, - SECPKG_CRED_ATTR_NAMES, - &names); - s_pSecFn->FreeCredentialsHandle(&cred_handle); - if(check_sspi_err(conn, status, "QueryCredentialAttributes")) { - s_pSecFn->DeleteSecurityContext(&sspi_context); - s_pSecFn->FreeContextBuffer(names.sUserName); - failf(data, "Failed to determine user name."); - return CURLE_COULDNT_CONNECT; - } - infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n", - names.sUserName); - s_pSecFn->FreeContextBuffer(names.sUserName); - - /* Do encryption */ - socksreq[0] = 1; /* GSS-API subnegotiation version */ - socksreq[1] = 2; /* encryption message type */ - - gss_enc = 0; /* no data protection */ - /* do confidentiality protection if supported */ - if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) - gss_enc = 2; - /* else do integrity protection */ - else if(sspi_ret_flags & ISC_REQ_INTEGRITY) - gss_enc = 1; - - infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", - (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") ); - /* force to no data protection, avoid encryption/decryption for now */ - gss_enc = 0; - /* - * Sending the encryption type in clear seems wrong. It should be - * protected with gss_seal()/gss_wrap(). See RFC1961 extract below - * The NEC reference implementations on which this is based is - * therefore at fault - * - * +------+------+------+.......................+ - * + ver | mtyp | len | token | - * +------+------+------+.......................+ - * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | - * +------+------+------+.......................+ - * - * Where: - * - * - "ver" is the protocol version number, here 1 to represent the - * first version of the SOCKS/GSS-API protocol - * - * - "mtyp" is the message type, here 2 to represent a protection - * -level negotiation message - * - * - "len" is the length of the "token" field in octets - * - * - "token" is the GSS-API encapsulated protection level - * - * The token is produced by encapsulating an octet containing the - * required protection level using gss_seal()/gss_wrap() with conf_req - * set to FALSE. The token is verified using gss_unseal()/ - * gss_unwrap(). - * - */ - - if(data->set.socks5_gssapi_nec) { - us_length = htons((short)1); - memcpy(socksreq + 2, &us_length, sizeof(short)); - } - else { - status = s_pSecFn->QueryContextAttributes(&sspi_context, - SECPKG_ATTR_SIZES, - &sspi_sizes); - if(check_sspi_err(conn, status, "QueryContextAttributes")) { - s_pSecFn->DeleteSecurityContext(&sspi_context); - failf(data, "Failed to query security context attributes."); - return CURLE_COULDNT_CONNECT; - } - - sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; - sspi_w_token[0].BufferType = SECBUFFER_TOKEN; - sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); - - if(!sspi_w_token[0].pvBuffer) { - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; - } - - sspi_w_token[1].cbBuffer = 1; - sspi_w_token[1].pvBuffer = malloc(1); - if(!sspi_w_token[1].pvBuffer) { - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; - } - - memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); - sspi_w_token[2].BufferType = SECBUFFER_PADDING; - sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; - sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); - if(!sspi_w_token[2].pvBuffer) { - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; - } - status = s_pSecFn->EncryptMessage(&sspi_context, - KERB_WRAP_NO_ENCRYPT, - &wrap_desc, - 0); - if(check_sspi_err(conn, status, "EncryptMessage")) { - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - failf(data, "Failed to query security context attributes."); - return CURLE_COULDNT_CONNECT; - } - sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer - + sspi_w_token[1].cbBuffer - + sspi_w_token[2].cbBuffer; - sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); - if(!sspi_send_token.pvBuffer) { - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; - } - - memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer); - memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, - sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); - memcpy((PUCHAR) sspi_send_token.pvBuffer - + sspi_w_token[0].cbBuffer - + sspi_w_token[1].cbBuffer, - sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); - - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - sspi_w_token[0].pvBuffer = NULL; - sspi_w_token[0].cbBuffer = 0; - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - sspi_w_token[1].pvBuffer = NULL; - sspi_w_token[1].cbBuffer = 0; - s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); - sspi_w_token[2].pvBuffer = NULL; - sspi_w_token[2].cbBuffer = 0; - - us_length = htons((short)sspi_send_token.cbBuffer); - memcpy(socksreq + 2, &us_length, sizeof(short)); - } - - code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if(code || (4 != written)) { - failf(data, "Failed to send SSPI encryption request."); - if(sspi_send_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - if(data->set.socks5_gssapi_nec) { - memcpy(socksreq, &gss_enc, 1); - code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written); - if(code || (1 != written)) { - failf(data, "Failed to send SSPI encryption type."); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - } - else { - code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, - sspi_send_token.cbBuffer, &written); - if(code || (sspi_send_token.cbBuffer != (size_t)written)) { - failf(data, "Failed to send SSPI encryption type."); - if(sspi_send_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - if(sspi_send_token.pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - } - - result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); - if(result || (actualread != 4)) { - failf(data, "Failed to receive SSPI encryption response."); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - /* ignore the first (VER) byte */ - if(socksreq[1] == 255) { /* status / message type */ - failf(data, "User was rejected by the SOCKS5 server (%u %u).", - (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - if(socksreq[1] != 2) { /* status / message type */ - failf(data, "Invalid SSPI encryption response type (%u %u).", - (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - memcpy(&us_length, socksreq + 2, sizeof(short)); - us_length = ntohs(us_length); - - sspi_w_token[0].cbBuffer = us_length; - sspi_w_token[0].pvBuffer = malloc(us_length); - if(!sspi_w_token[0].pvBuffer) { - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; - } - - result = Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer, &actualread); - - if(result || (actualread != us_length)) { - failf(data, "Failed to receive SSPI encryption type."); - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - - if(!data->set.socks5_gssapi_nec) { - wrap_desc.cBuffers = 2; - sspi_w_token[0].BufferType = SECBUFFER_STREAM; - sspi_w_token[1].BufferType = SECBUFFER_DATA; - sspi_w_token[1].cbBuffer = 0; - sspi_w_token[1].pvBuffer = NULL; - - status = s_pSecFn->DecryptMessage(&sspi_context, - &wrap_desc, - 0, - &qop); - - if(check_sspi_err(conn, status, "DecryptMessage")) { - if(sspi_w_token[0].pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - if(sspi_w_token[1].pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - failf(data, "Failed to query security context attributes."); - return CURLE_COULDNT_CONNECT; - } - - if(sspi_w_token[1].cbBuffer != 1) { - failf(data, "Invalid SSPI encryption response length (%lu).", - (unsigned long)sspi_w_token[1].cbBuffer); - if(sspi_w_token[0].pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - if(sspi_w_token[1].pvBuffer) - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - - memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - } - else { - if(sspi_w_token[0].cbBuffer != 1) { - failf(data, "Invalid SSPI encryption response length (%lu).", - (unsigned long)sspi_w_token[0].cbBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; - } - memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - } - - infof(data, "SOCKS5 access with%s protection granted.\n", - (socksreq[0] == 0)?"out GSS-API data": - ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); - - /* For later use if encryption is required - conn->socks5_gssapi_enctype = socksreq[0]; - if(socksreq[0] != 0) - conn->socks5_sspi_context = sspi_context; - else { - s_pSecFn->DeleteSecurityContext(&sspi_context); - conn->socks5_sspi_context = sspi_context; - } - */ - return CURLE_OK; -} -#endif diff --git a/dep/cpr/opt/curl/lib/speedcheck.c b/dep/cpr/opt/curl/lib/speedcheck.c deleted file mode 100644 index fe669f11a6f..00000000000 --- a/dep/cpr/opt/curl/lib/speedcheck.c +++ /dev/null @@ -1,73 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include -#include "urldata.h" -#include "sendf.h" -#include "multiif.h" -#include "speedcheck.h" - -void Curl_speedinit(struct Curl_easy *data) -{ - memset(&data->state.keeps_speed, 0, sizeof(struct curltime)); -} - -/* - * @unittest: 1606 - */ -CURLcode Curl_speedcheck(struct Curl_easy *data, - struct curltime now) -{ - if((data->progress.current_speed >= 0) && data->set.low_speed_time) { - if(data->progress.current_speed < data->set.low_speed_limit) { - if(!data->state.keeps_speed.tv_sec) - /* under the limit at this very moment */ - data->state.keeps_speed = now; - else { - /* how long has it been under the limit */ - time_t howlong = Curl_tvdiff(now, data->state.keeps_speed); - - if(howlong >= data->set.low_speed_time * 1000) { - /* too long */ - failf(data, - "Operation too slow. " - "Less than %ld bytes/sec transferred the last %ld seconds", - data->set.low_speed_limit, - data->set.low_speed_time); - return CURLE_OPERATION_TIMEDOUT; - } - } - } - else - /* faster right now */ - data->state.keeps_speed.tv_sec = 0; - } - - if(data->set.low_speed_limit) - /* if low speed limit is enabled, set the expire timer to make this - connection's speed get checked again in a second */ - Curl_expire(data, 1000, EXPIRE_SPEEDCHECK); - - return CURLE_OK; -} diff --git a/dep/cpr/opt/curl/lib/speedcheck.h b/dep/cpr/opt/curl/lib/speedcheck.h deleted file mode 100644 index 5c2dc9a226f..00000000000 --- a/dep/cpr/opt/curl/lib/speedcheck.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef HEADER_CURL_SPEEDCHECK_H -#define HEADER_CURL_SPEEDCHECK_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "timeval.h" - -void Curl_speedinit(struct Curl_easy *data); -CURLcode Curl_speedcheck(struct Curl_easy *data, - struct curltime now); - -#endif /* HEADER_CURL_SPEEDCHECK_H */ diff --git a/dep/cpr/opt/curl/lib/splay.c b/dep/cpr/opt/curl/lib/splay.c deleted file mode 100644 index 69af446eb58..00000000000 --- a/dep/cpr/opt/curl/lib/splay.c +++ /dev/null @@ -1,278 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1997 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "splay.h" - -/* - * This macro compares two node keys i and j and returns: - * - * negative value: when i is smaller than j - * zero : when i is equal to j - * positive when : when i is larger than j - */ -#define compare(i,j) Curl_splaycomparekeys((i),(j)) - -/* - * Splay using the key i (which may or may not be in the tree.) The starting - * root is t. - */ -struct Curl_tree *Curl_splay(struct curltime i, - struct Curl_tree *t) -{ - struct Curl_tree N, *l, *r, *y; - long comp; - - if(t == NULL) - return t; - N.smaller = N.larger = NULL; - l = r = &N; - - for(;;) { - comp = compare(i, t->key); - if(comp < 0) { - if(t->smaller == NULL) - break; - if(compare(i, t->smaller->key) < 0) { - y = t->smaller; /* rotate smaller */ - t->smaller = y->larger; - y->larger = t; - t = y; - if(t->smaller == NULL) - break; - } - r->smaller = t; /* link smaller */ - r = t; - t = t->smaller; - } - else if(comp > 0) { - if(t->larger == NULL) - break; - if(compare(i, t->larger->key) > 0) { - y = t->larger; /* rotate larger */ - t->larger = y->smaller; - y->smaller = t; - t = y; - if(t->larger == NULL) - break; - } - l->larger = t; /* link larger */ - l = t; - t = t->larger; - } - else - break; - } - - l->larger = t->smaller; /* assemble */ - r->smaller = t->larger; - t->smaller = N.larger; - t->larger = N.smaller; - - return t; -} - -/* Insert key i into the tree t. Return a pointer to the resulting tree or - * NULL if something went wrong. - * - * @unittest: 1309 - */ -struct Curl_tree *Curl_splayinsert(struct curltime i, - struct Curl_tree *t, - struct Curl_tree *node) -{ - static const struct curltime KEY_NOTUSED = { - (time_t)-1, (unsigned int)-1 - }; /* will *NEVER* appear */ - - if(node == NULL) - return t; - - if(t != NULL) { - t = Curl_splay(i, t); - if(compare(i, t->key) == 0) { - /* There already exists a node in the tree with the very same key. Build - a doubly-linked circular list of nodes. We add the new 'node' struct - to the end of this list. */ - - node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED - to quickly identify this node as a subnode */ - node->samen = t; - node->samep = t->samep; - t->samep->samen = node; - t->samep = node; - - return t; /* the root node always stays the same */ - } - } - - if(t == NULL) { - node->smaller = node->larger = NULL; - } - else if(compare(i, t->key) < 0) { - node->smaller = t->smaller; - node->larger = t; - t->smaller = NULL; - - } - else { - node->larger = t->larger; - node->smaller = t; - t->larger = NULL; - } - node->key = i; - - /* no identical nodes (yet), we are the only one in the list of nodes */ - node->samen = node; - node->samep = node; - return node; -} - -/* Finds and deletes the best-fit node from the tree. Return a pointer to the - resulting tree. best-fit means the smallest node if it is not larger than - the key */ -struct Curl_tree *Curl_splaygetbest(struct curltime i, - struct Curl_tree *t, - struct Curl_tree **removed) -{ - static struct curltime tv_zero = {0, 0}; - struct Curl_tree *x; - - if(!t) { - *removed = NULL; /* none removed since there was no root */ - return NULL; - } - - /* find smallest */ - t = Curl_splay(tv_zero, t); - if(compare(i, t->key) < 0) { - /* even the smallest is too big */ - *removed = NULL; - return t; - } - - /* FIRST! Check if there is a list with identical keys */ - x = t->samen; - if(x != t) { - /* there is, pick one from the list */ - - /* 'x' is the new root node */ - - x->key = t->key; - x->larger = t->larger; - x->smaller = t->smaller; - x->samep = t->samep; - t->samep->samen = x; - - *removed = t; - return x; /* new root */ - } - - /* we splayed the tree to the smallest element, there is no smaller */ - x = t->larger; - *removed = t; - - return x; -} - - -/* Deletes the very node we point out from the tree if it's there. Stores a - * pointer to the new resulting tree in 'newroot'. - * - * Returns zero on success and non-zero on errors! TODO: document error codes. - * When returning error, it does not touch the 'newroot' pointer. - * - * NOTE: when the last node of the tree is removed, there's no tree left so - * 'newroot' will be made to point to NULL. - * - * @unittest: 1309 - */ -int Curl_splayremovebyaddr(struct Curl_tree *t, - struct Curl_tree *removenode, - struct Curl_tree **newroot) -{ - static const struct curltime KEY_NOTUSED = { - (time_t)-1, (unsigned int)-1 - }; /* will *NEVER* appear */ - struct Curl_tree *x; - - if(!t || !removenode) - return 1; - - if(compare(KEY_NOTUSED, removenode->key) == 0) { - /* Key set to NOTUSED means it is a subnode within a 'same' linked list - and thus we can unlink it easily. */ - if(removenode->samen == removenode) - /* A non-subnode should never be set to KEY_NOTUSED */ - return 3; - - removenode->samep->samen = removenode->samen; - removenode->samen->samep = removenode->samep; - - /* Ensures that double-remove gets caught. */ - removenode->samen = removenode; - - *newroot = t; /* return the same root */ - return 0; - } - - t = Curl_splay(removenode->key, t); - - /* First make sure that we got the same root node as the one we want - to remove, as otherwise we might be trying to remove a node that - isn't actually in the tree. - - We cannot just compare the keys here as a double remove in quick - succession of a node with key != KEY_NOTUSED && same != NULL - could return the same key but a different node. */ - if(t != removenode) - return 2; - - /* Check if there is a list with identical sizes, as then we're trying to - remove the root node of a list of nodes with identical keys. */ - x = t->samen; - if(x != t) { - /* 'x' is the new root node, we just make it use the root node's - smaller/larger links */ - - x->key = t->key; - x->larger = t->larger; - x->smaller = t->smaller; - x->samep = t->samep; - t->samep->samen = x; - } - else { - /* Remove the root node */ - if(t->smaller == NULL) - x = t->larger; - else { - x = Curl_splay(removenode->key, t->smaller); - x->larger = t->larger; - } - } - - *newroot = x; /* store new root pointer */ - - return 0; -} - diff --git a/dep/cpr/opt/curl/lib/splay.h b/dep/cpr/opt/curl/lib/splay.h deleted file mode 100644 index 4612ec271f0..00000000000 --- a/dep/cpr/opt/curl/lib/splay.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef HEADER_CURL_SPLAY_H -#define HEADER_CURL_SPLAY_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1997 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" -#include "timeval.h" - -struct Curl_tree { - struct Curl_tree *smaller; /* smaller node */ - struct Curl_tree *larger; /* larger node */ - struct Curl_tree *samen; /* points to the next node with identical key */ - struct Curl_tree *samep; /* points to the prev node with identical key */ - struct curltime key; /* this node's "sort" key */ - void *payload; /* data the splay code doesn't care about */ -}; - -struct Curl_tree *Curl_splay(struct curltime i, - struct Curl_tree *t); - -struct Curl_tree *Curl_splayinsert(struct curltime key, - struct Curl_tree *t, - struct Curl_tree *newnode); - -#if 0 -struct Curl_tree *Curl_splayremove(struct curltime key, - struct Curl_tree *t, - struct Curl_tree **removed); -#endif - -struct Curl_tree *Curl_splaygetbest(struct curltime key, - struct Curl_tree *t, - struct Curl_tree **removed); - -int Curl_splayremovebyaddr(struct Curl_tree *t, - struct Curl_tree *removenode, - struct Curl_tree **newroot); - -#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \ - ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \ - ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \ - ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0)))) - -#ifdef DEBUGBUILD -void Curl_splayprint(struct Curl_tree * t, int d, char output); -#else -#define Curl_splayprint(x,y,z) Curl_nop_stmt -#endif - -#endif /* HEADER_CURL_SPLAY_H */ diff --git a/dep/cpr/opt/curl/lib/ssh.c b/dep/cpr/opt/curl/lib/ssh.c deleted file mode 100644 index 5406bf073d1..00000000000 --- a/dep/cpr/opt/curl/lib/ssh.c +++ /dev/null @@ -1,3463 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* #define CURL_LIBSSH2_DEBUG */ - -#include "curl_setup.h" - -#ifdef USE_LIBSSH2 - -#ifdef HAVE_LIMITS_H -# include -#endif - -#include -#include - -#ifdef HAVE_FCNTL_H -#include -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_UTSNAME_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "progress.h" -#include "transfer.h" -#include "escape.h" -#include "http.h" /* for HTTP proxy tunnel stuff */ -#include "ssh.h" -#include "url.h" -#include "speedcheck.h" -#include "getinfo.h" -#include "strdup.h" -#include "strcase.h" -#include "vtls/vtls.h" -#include "connect.h" -#include "strerror.h" -#include "inet_ntop.h" -#include "parsedate.h" /* for the week day and month names */ -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "strtoofft.h" -#include "multiif.h" -#include "select.h" -#include "warnless.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifdef WIN32 -# undef PATH_MAX -# define PATH_MAX MAX_PATH -# ifndef R_OK -# define R_OK 4 -# endif -#endif - -#ifndef PATH_MAX -#define PATH_MAX 1024 /* just an extra precaution since there are systems that - have their definition hidden well */ -#endif - -#if LIBSSH2_VERSION_NUM >= 0x010206 -/* libssh2_sftp_statvfs and friends were added in 1.2.6 */ -#define HAS_STATVFS_SUPPORT 1 -#endif - -#define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s)) - -#define sftp_libssh2_realpath(s,p,t,m) \ - libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \ - (t), (m), LIBSSH2_SFTP_REALPATH) - - -/* Local functions: */ -static const char *sftp_libssh2_strerror(int err); -static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); -static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); -static LIBSSH2_FREE_FUNC(my_libssh2_free); - -static CURLcode get_pathname(const char **cpp, char **path); - -static CURLcode ssh_connect(struct connectdata *conn, bool *done); -static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done); -static CURLcode ssh_do(struct connectdata *conn, bool *done); - -static CURLcode ssh_getworkingpath(struct connectdata *conn, - char *homedir, /* when SFTP is used */ - char **path); - -static CURLcode scp_done(struct connectdata *conn, - CURLcode, bool premature); -static CURLcode scp_doing(struct connectdata *conn, - bool *dophase_done); -static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection); - -static CURLcode sftp_done(struct connectdata *conn, - CURLcode, bool premature); -static CURLcode sftp_doing(struct connectdata *conn, - bool *dophase_done); -static CURLcode sftp_disconnect(struct connectdata *conn, bool dead); -static -CURLcode sftp_perform(struct connectdata *conn, - bool *connected, - bool *dophase_done); - -static int ssh_getsock(struct connectdata *conn, - curl_socket_t *sock, /* points to numsocks number - of sockets */ - int numsocks); - -static int ssh_perform_getsock(const struct connectdata *conn, - curl_socket_t *sock, /* points to numsocks - number of sockets */ - int numsocks); - -static CURLcode ssh_setup_connection(struct connectdata *conn); - -/* - * SCP protocol handler. - */ - -const struct Curl_handler Curl_handler_scp = { - "SCP", /* scheme */ - ssh_setup_connection, /* setup_connection */ - ssh_do, /* do_it */ - scp_done, /* done */ - ZERO_NULL, /* do_more */ - ssh_connect, /* connect_it */ - ssh_multi_statemach, /* connecting */ - scp_doing, /* doing */ - ssh_getsock, /* proto_getsock */ - ssh_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ssh_perform_getsock, /* perform_getsock */ - scp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_SSH, /* defport */ - CURLPROTO_SCP, /* protocol */ - PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION - | PROTOPT_NOURLQUERY /* flags */ -}; - - -/* - * SFTP protocol handler. - */ - -const struct Curl_handler Curl_handler_sftp = { - "SFTP", /* scheme */ - ssh_setup_connection, /* setup_connection */ - ssh_do, /* do_it */ - sftp_done, /* done */ - ZERO_NULL, /* do_more */ - ssh_connect, /* connect_it */ - ssh_multi_statemach, /* connecting */ - sftp_doing, /* doing */ - ssh_getsock, /* proto_getsock */ - ssh_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ssh_perform_getsock, /* perform_getsock */ - sftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_SSH, /* defport */ - CURLPROTO_SFTP, /* protocol */ - PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION - | PROTOPT_NOURLQUERY /* flags */ -}; - -static void -kbd_callback(const char *name, int name_len, const char *instruction, - int instruction_len, int num_prompts, - const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, - LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, - void **abstract) -{ - struct connectdata *conn = (struct connectdata *)*abstract; - -#ifdef CURL_LIBSSH2_DEBUG - fprintf(stderr, "name=%s\n", name); - fprintf(stderr, "name_len=%d\n", name_len); - fprintf(stderr, "instruction=%s\n", instruction); - fprintf(stderr, "instruction_len=%d\n", instruction_len); - fprintf(stderr, "num_prompts=%d\n", num_prompts); -#else - (void)name; - (void)name_len; - (void)instruction; - (void)instruction_len; -#endif /* CURL_LIBSSH2_DEBUG */ - if(num_prompts == 1) { - responses[0].text = strdup(conn->passwd); - responses[0].length = curlx_uztoui(strlen(conn->passwd)); - } - (void)prompts; - (void)abstract; -} /* kbd_callback */ - -static CURLcode sftp_libssh2_error_to_CURLE(int err) -{ - switch(err) { - case LIBSSH2_FX_OK: - return CURLE_OK; - - case LIBSSH2_FX_NO_SUCH_FILE: - case LIBSSH2_FX_NO_SUCH_PATH: - return CURLE_REMOTE_FILE_NOT_FOUND; - - case LIBSSH2_FX_PERMISSION_DENIED: - case LIBSSH2_FX_WRITE_PROTECT: - case LIBSSH2_FX_LOCK_CONFlICT: - return CURLE_REMOTE_ACCESS_DENIED; - - case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: - case LIBSSH2_FX_QUOTA_EXCEEDED: - return CURLE_REMOTE_DISK_FULL; - - case LIBSSH2_FX_FILE_ALREADY_EXISTS: - return CURLE_REMOTE_FILE_EXISTS; - - case LIBSSH2_FX_DIR_NOT_EMPTY: - return CURLE_QUOTE_ERROR; - - default: - break; - } - - return CURLE_SSH; -} - -static CURLcode libssh2_session_error_to_CURLE(int err) -{ - switch(err) { - /* Ordered by order of appearance in libssh2.h */ - case LIBSSH2_ERROR_NONE: - return CURLE_OK; - - case LIBSSH2_ERROR_SOCKET_NONE: - return CURLE_COULDNT_CONNECT; - - case LIBSSH2_ERROR_ALLOC: - return CURLE_OUT_OF_MEMORY; - - case LIBSSH2_ERROR_SOCKET_SEND: - return CURLE_SEND_ERROR; - - case LIBSSH2_ERROR_HOSTKEY_INIT: - case LIBSSH2_ERROR_HOSTKEY_SIGN: - case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED: - case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED: - return CURLE_PEER_FAILED_VERIFICATION; - - case LIBSSH2_ERROR_PASSWORD_EXPIRED: - return CURLE_LOGIN_DENIED; - - case LIBSSH2_ERROR_SOCKET_TIMEOUT: - case LIBSSH2_ERROR_TIMEOUT: - return CURLE_OPERATION_TIMEDOUT; - - case LIBSSH2_ERROR_EAGAIN: - return CURLE_AGAIN; - } - - /* TODO: map some more of the libssh2 errors to the more appropriate CURLcode - error code, and possibly add a few new SSH-related one. We must however - not return or even depend on libssh2 errors in the public libcurl API */ - - return CURLE_SSH; -} - -static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc) -{ - (void)abstract; /* arg not used */ - return malloc(count); -} - -static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc) -{ - (void)abstract; /* arg not used */ - return realloc(ptr, count); -} - -static LIBSSH2_FREE_FUNC(my_libssh2_free) -{ - (void)abstract; /* arg not used */ - if(ptr) /* ssh2 agent sometimes call free with null ptr */ - free(ptr); -} - -/* - * SSH State machine related code - */ -/* This is the ONLY way to change SSH state! */ -static void state(struct connectdata *conn, sshstate nowstate) -{ - struct ssh_conn *sshc = &conn->proto.sshc; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ - static const char * const names[] = { - "SSH_STOP", - "SSH_INIT", - "SSH_S_STARTUP", - "SSH_HOSTKEY", - "SSH_AUTHLIST", - "SSH_AUTH_PKEY_INIT", - "SSH_AUTH_PKEY", - "SSH_AUTH_PASS_INIT", - "SSH_AUTH_PASS", - "SSH_AUTH_AGENT_INIT", - "SSH_AUTH_AGENT_LIST", - "SSH_AUTH_AGENT", - "SSH_AUTH_HOST_INIT", - "SSH_AUTH_HOST", - "SSH_AUTH_KEY_INIT", - "SSH_AUTH_KEY", - "SSH_AUTH_DONE", - "SSH_SFTP_INIT", - "SSH_SFTP_REALPATH", - "SSH_SFTP_QUOTE_INIT", - "SSH_SFTP_POSTQUOTE_INIT", - "SSH_SFTP_QUOTE", - "SSH_SFTP_NEXT_QUOTE", - "SSH_SFTP_QUOTE_STAT", - "SSH_SFTP_QUOTE_SETSTAT", - "SSH_SFTP_QUOTE_SYMLINK", - "SSH_SFTP_QUOTE_MKDIR", - "SSH_SFTP_QUOTE_RENAME", - "SSH_SFTP_QUOTE_RMDIR", - "SSH_SFTP_QUOTE_UNLINK", - "SSH_SFTP_QUOTE_STATVFS", - "SSH_SFTP_GETINFO", - "SSH_SFTP_FILETIME", - "SSH_SFTP_TRANS_INIT", - "SSH_SFTP_UPLOAD_INIT", - "SSH_SFTP_CREATE_DIRS_INIT", - "SSH_SFTP_CREATE_DIRS", - "SSH_SFTP_CREATE_DIRS_MKDIR", - "SSH_SFTP_READDIR_INIT", - "SSH_SFTP_READDIR", - "SSH_SFTP_READDIR_LINK", - "SSH_SFTP_READDIR_BOTTOM", - "SSH_SFTP_READDIR_DONE", - "SSH_SFTP_DOWNLOAD_INIT", - "SSH_SFTP_DOWNLOAD_STAT", - "SSH_SFTP_CLOSE", - "SSH_SFTP_SHUTDOWN", - "SSH_SCP_TRANS_INIT", - "SSH_SCP_UPLOAD_INIT", - "SSH_SCP_DOWNLOAD_INIT", - "SSH_SCP_DONE", - "SSH_SCP_SEND_EOF", - "SSH_SCP_WAIT_EOF", - "SSH_SCP_WAIT_CLOSE", - "SSH_SCP_CHANNEL_FREE", - "SSH_SESSION_DISCONNECT", - "SSH_SESSION_FREE", - "QUIT" - }; - - if(sshc->state != nowstate) { - infof(conn->data, "SFTP %p state change from %s to %s\n", - (void *)sshc, names[sshc->state], names[nowstate]); - } -#endif - - sshc->state = nowstate; -} - -/* figure out the path to work with in this particular request */ -static CURLcode ssh_getworkingpath(struct connectdata *conn, - char *homedir, /* when SFTP is used */ - char **path) /* returns the allocated - real path to work with */ -{ - struct Curl_easy *data = conn->data; - char *real_path = NULL; - char *working_path; - size_t working_path_len; - CURLcode result = - Curl_urldecode(data, data->state.path, 0, &working_path, - &working_path_len, FALSE); - if(result) - return result; - - /* Check for /~/, indicating relative to the user's home directory */ - if(conn->handler->protocol & CURLPROTO_SCP) { - real_path = malloc(working_path_len + 1); - if(real_path == NULL) { - free(working_path); - return CURLE_OUT_OF_MEMORY; - } - if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) - /* It is referenced to the home directory, so strip the leading '/~/' */ - memcpy(real_path, working_path + 3, 4 + working_path_len-3); - else - memcpy(real_path, working_path, 1 + working_path_len); - } - else if(conn->handler->protocol & CURLPROTO_SFTP) { - if((working_path_len > 1) && (working_path[1] == '~')) { - size_t homelen = strlen(homedir); - real_path = malloc(homelen + working_path_len + 1); - if(real_path == NULL) { - free(working_path); - return CURLE_OUT_OF_MEMORY; - } - /* It is referenced to the home directory, so strip the - leading '/' */ - memcpy(real_path, homedir, homelen); - real_path[homelen] = '/'; - real_path[homelen + 1] = '\0'; - if(working_path_len > 3) { - memcpy(real_path + homelen + 1, working_path + 3, - 1 + working_path_len -3); - } - } - else { - real_path = malloc(working_path_len + 1); - if(real_path == NULL) { - free(working_path); - return CURLE_OUT_OF_MEMORY; - } - memcpy(real_path, working_path, 1 + working_path_len); - } - } - - free(working_path); - - /* store the pointer for the caller to receive */ - *path = real_path; - - return CURLE_OK; -} - -#ifdef HAVE_LIBSSH2_KNOWNHOST_API -static int sshkeycallback(struct Curl_easy *easy, - const struct curl_khkey *knownkey, /* known */ - const struct curl_khkey *foundkey, /* found */ - enum curl_khmatch match, - void *clientp) -{ - (void)easy; - (void)knownkey; - (void)foundkey; - (void)clientp; - - /* we only allow perfect matches, and we reject everything else */ - return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE; -} -#endif - -/* - * Earlier libssh2 versions didn't have the ability to seek to 64bit positions - * with 32bit size_t. - */ -#ifdef HAVE_LIBSSH2_SFTP_SEEK64 -#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y) -#else -#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y) -#endif - -/* - * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit - * architectures so we check of the necessary function is present. - */ -#ifndef HAVE_LIBSSH2_SCP_SEND64 -#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0) -#else -#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \ - (libssh2_uint64_t)d, 0, 0) -#endif - -/* - * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64. - */ -#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE -#define libssh2_session_startup(x,y) libssh2_session_handshake(x,y) -#endif - -static CURLcode ssh_knownhost(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - -#ifdef HAVE_LIBSSH2_KNOWNHOST_API - struct Curl_easy *data = conn->data; - - if(data->set.str[STRING_SSH_KNOWNHOSTS]) { - /* we're asked to verify the host against a file */ - struct ssh_conn *sshc = &conn->proto.sshc; - int rc; - int keytype; - size_t keylen; - const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, - &keylen, &keytype); - int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE; - int keybit = 0; - - if(remotekey) { - /* - * A subject to figure out is what host name we need to pass in here. - * What host name does OpenSSH store in its file if an IDN name is - * used? - */ - struct libssh2_knownhost *host; - enum curl_khmatch keymatch; - curl_sshkeycallback func = - data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback; - struct curl_khkey knownkey; - struct curl_khkey *knownkeyp = NULL; - struct curl_khkey foundkey; - - keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? - LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS; - -#ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP - keycheck = libssh2_knownhost_checkp(sshc->kh, - conn->host.name, - (conn->remote_port != PORT_SSH)? - conn->remote_port:-1, - remotekey, keylen, - LIBSSH2_KNOWNHOST_TYPE_PLAIN| - LIBSSH2_KNOWNHOST_KEYENC_RAW| - keybit, - &host); -#else - keycheck = libssh2_knownhost_check(sshc->kh, - conn->host.name, - remotekey, keylen, - LIBSSH2_KNOWNHOST_TYPE_PLAIN| - LIBSSH2_KNOWNHOST_KEYENC_RAW| - keybit, - &host); -#endif - - infof(data, "SSH host check: %d, key: %s\n", keycheck, - (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)? - host->key:""); - - /* setup 'knownkey' */ - if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { - knownkey.key = host->key; - knownkey.len = 0; - knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? - CURLKHTYPE_RSA : CURLKHTYPE_DSS; - knownkeyp = &knownkey; - } - - /* setup 'foundkey' */ - foundkey.key = remotekey; - foundkey.len = keylen; - foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? - CURLKHTYPE_RSA : CURLKHTYPE_DSS; - - /* - * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the - * curl_khmatch enum are ever modified, we need to introduce a - * translation table here! - */ - keymatch = (enum curl_khmatch)keycheck; - - /* Ask the callback how to behave */ - rc = func(data, knownkeyp, /* from the knownhosts file */ - &foundkey, /* from the remote host */ - keymatch, data->set.ssh_keyfunc_userp); - } - else - /* no remotekey means failure! */ - rc = CURLKHSTAT_REJECT; - - switch(rc) { - default: /* unknown return codes will equal reject */ - /* FALLTHROUGH */ - case CURLKHSTAT_REJECT: - state(conn, SSH_SESSION_FREE); - /* FALLTHROUGH */ - case CURLKHSTAT_DEFER: - /* DEFER means bail out but keep the SSH_HOSTKEY state */ - result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; - break; - case CURLKHSTAT_FINE: - case CURLKHSTAT_FINE_ADD_TO_FILE: - /* proceed */ - if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) { - /* the found host+key didn't match but has been told to be fine - anyway so we add it in memory */ - int addrc = libssh2_knownhost_add(sshc->kh, - conn->host.name, NULL, - remotekey, keylen, - LIBSSH2_KNOWNHOST_TYPE_PLAIN| - LIBSSH2_KNOWNHOST_KEYENC_RAW| - keybit, NULL); - if(addrc) - infof(data, "Warning adding the known host %s failed!\n", - conn->host.name); - else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) { - /* now we write the entire in-memory list of known hosts to the - known_hosts file */ - int wrc = - libssh2_knownhost_writefile(sshc->kh, - data->set.str[STRING_SSH_KNOWNHOSTS], - LIBSSH2_KNOWNHOST_FILE_OPENSSH); - if(wrc) { - infof(data, "Warning, writing %s failed!\n", - data->set.str[STRING_SSH_KNOWNHOSTS]); - } - } - } - break; - } - } -#else /* HAVE_LIBSSH2_KNOWNHOST_API */ - (void)conn; -#endif - return result; -} - -static CURLcode ssh_check_fingerprint(struct connectdata *conn) -{ - struct ssh_conn *sshc = &conn->proto.sshc; - struct Curl_easy *data = conn->data; - const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; - char md5buffer[33]; - int i; - - const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session, - LIBSSH2_HOSTKEY_HASH_MD5); - - if(fingerprint) { - /* The fingerprint points to static storage (!), don't free() it. */ - for(i = 0; i < 16; i++) - snprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); - infof(data, "SSH MD5 fingerprint: %s\n", md5buffer); - } - - /* Before we authenticate we check the hostkey's MD5 fingerprint - * against a known fingerprint, if available. - */ - if(pubkey_md5 && strlen(pubkey_md5) == 32) { - if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) { - if(fingerprint) - failf(data, - "Denied establishing ssh session: mismatch md5 fingerprint. " - "Remote %s is not equal to %s", md5buffer, pubkey_md5); - else - failf(data, - "Denied establishing ssh session: md5 fingerprint not available"); - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; - return sshc->actualcode; - } - infof(data, "MD5 checksum match!\n"); - /* as we already matched, we skip the check for known hosts */ - return CURLE_OK; - } - return ssh_knownhost(conn); -} - -/* - * ssh_statemach_act() runs the SSH state machine as far as it can without - * blocking and without reaching the end. The data the pointer 'block' points - * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN - * meaning it wants to be called again when the socket is ready - */ - -static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct SSHPROTO *sftp_scp = data->req.protop; - struct ssh_conn *sshc = &conn->proto.sshc; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - char *new_readdir_line; - int rc = LIBSSH2_ERROR_NONE; - int err; - int seekerr = CURL_SEEKFUNC_OK; - *block = 0; /* we're not blocking by default */ - - do { - - switch(sshc->state) { - case SSH_INIT: - sshc->secondCreateDirs = 0; - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_OK; - - /* Set libssh2 to non-blocking, since everything internally is - non-blocking */ - libssh2_session_set_blocking(sshc->ssh_session, 0); - - state(conn, SSH_S_STARTUP); - /* fall-through */ - - case SSH_S_STARTUP: - rc = libssh2_session_startup(sshc->ssh_session, (int)sock); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc) { - failf(data, "Failure establishing ssh session"); - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_FAILED_INIT; - break; - } - - state(conn, SSH_HOSTKEY); - - /* fall-through */ - case SSH_HOSTKEY: - /* - * Before we authenticate we should check the hostkey's fingerprint - * against our known hosts. How that is handled (reading from file, - * whatever) is up to us. - */ - result = ssh_check_fingerprint(conn); - if(!result) - state(conn, SSH_AUTHLIST); - /* ssh_check_fingerprint sets state appropriately on error */ - break; - - case SSH_AUTHLIST: - /* - * Figure out authentication methods - * NB: As soon as we have provided a username to an openssh server we - * must never change it later. Thus, always specify the correct username - * here, even though the libssh2 docs kind of indicate that it should be - * possible to get a 'generic' list (not user-specific) of authentication - * methods, presumably with a blank username. That won't work in my - * experience. - * So always specify it here. - */ - sshc->authlist = libssh2_userauth_list(sshc->ssh_session, - conn->user, - curlx_uztoui(strlen(conn->user))); - - if(!sshc->authlist) { - if(libssh2_userauth_authenticated(sshc->ssh_session)) { - sshc->authed = TRUE; - infof(data, "SSH user accepted with no authentication\n"); - state(conn, SSH_AUTH_DONE); - break; - } - err = libssh2_session_last_errno(sshc->ssh_session); - if(err == LIBSSH2_ERROR_EAGAIN) - rc = LIBSSH2_ERROR_EAGAIN; - else { - state(conn, SSH_SESSION_FREE); - sshc->actualcode = libssh2_session_error_to_CURLE(err); - } - break; - } - infof(data, "SSH authentication methods available: %s\n", - sshc->authlist); - - state(conn, SSH_AUTH_PKEY_INIT); - break; - - case SSH_AUTH_PKEY_INIT: - /* - * Check the supported auth types in the order I feel is most secure - * with the requested type of authentication - */ - sshc->authed = FALSE; - - if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) && - (strstr(sshc->authlist, "publickey") != NULL)) { - char *home = NULL; - bool out_of_memory = FALSE; - - sshc->rsa_pub = sshc->rsa = NULL; - - /* To ponder about: should really the lib be messing about with the - HOME environment variable etc? */ - home = curl_getenv("HOME"); - - if(data->set.str[STRING_SSH_PRIVATE_KEY]) - sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]); - else { - /* If no private key file is specified, try some common paths. */ - if(home) { - /* Try ~/.ssh first. */ - sshc->rsa = aprintf("%s/.ssh/id_rsa", home); - if(!sshc->rsa) - out_of_memory = TRUE; - else if(access(sshc->rsa, R_OK) != 0) { - Curl_safefree(sshc->rsa); - sshc->rsa = aprintf("%s/.ssh/id_dsa", home); - if(!sshc->rsa) - out_of_memory = TRUE; - else if(access(sshc->rsa, R_OK) != 0) { - Curl_safefree(sshc->rsa); - } - } - } - if(!out_of_memory && !sshc->rsa) { - /* Nothing found; try the current dir. */ - sshc->rsa = strdup("id_rsa"); - if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { - Curl_safefree(sshc->rsa); - sshc->rsa = strdup("id_dsa"); - if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { - Curl_safefree(sshc->rsa); - /* Out of guesses. Set to the empty string to avoid - * surprising info messages. */ - sshc->rsa = strdup(""); - } - } - } - } - - /* - * Unless the user explicitly specifies a public key file, let - * libssh2 extract the public key from the private key file. - * This is done by simply passing sshc->rsa_pub = NULL. - */ - if(data->set.str[STRING_SSH_PUBLIC_KEY] - /* treat empty string the same way as NULL */ - && data->set.str[STRING_SSH_PUBLIC_KEY][0]) { - sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); - if(!sshc->rsa_pub) - out_of_memory = TRUE; - } - - if(out_of_memory || sshc->rsa == NULL) { - free(home); - Curl_safefree(sshc->rsa); - Curl_safefree(sshc->rsa_pub); - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - - sshc->passphrase = data->set.ssl.key_passwd; - if(!sshc->passphrase) - sshc->passphrase = ""; - - free(home); - - if(sshc->rsa_pub) - infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); - infof(data, "Using SSH private key file '%s'\n", sshc->rsa); - - state(conn, SSH_AUTH_PKEY); - } - else { - state(conn, SSH_AUTH_PASS_INIT); - } - break; - - case SSH_AUTH_PKEY: - /* The function below checks if the files exists, no need to stat() here. - */ - rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session, - conn->user, - curlx_uztoui( - strlen(conn->user)), - sshc->rsa_pub, - sshc->rsa, sshc->passphrase); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - - Curl_safefree(sshc->rsa_pub); - Curl_safefree(sshc->rsa); - - if(rc == 0) { - sshc->authed = TRUE; - infof(data, "Initialized SSH public key authentication\n"); - state(conn, SSH_AUTH_DONE); - } - else { - char *err_msg; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "SSH public key authentication failed: %s\n", err_msg); - state(conn, SSH_AUTH_PASS_INIT); - rc = 0; /* clear rc and continue */ - } - break; - - case SSH_AUTH_PASS_INIT: - if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) && - (strstr(sshc->authlist, "password") != NULL)) { - state(conn, SSH_AUTH_PASS); - } - else { - state(conn, SSH_AUTH_HOST_INIT); - rc = 0; /* clear rc and continue */ - } - break; - - case SSH_AUTH_PASS: - rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user, - curlx_uztoui(strlen(conn->user)), - conn->passwd, - curlx_uztoui(strlen(conn->passwd)), - NULL); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc == 0) { - sshc->authed = TRUE; - infof(data, "Initialized password authentication\n"); - state(conn, SSH_AUTH_DONE); - } - else { - state(conn, SSH_AUTH_HOST_INIT); - rc = 0; /* clear rc and continue */ - } - break; - - case SSH_AUTH_HOST_INIT: - if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) && - (strstr(sshc->authlist, "hostbased") != NULL)) { - state(conn, SSH_AUTH_HOST); - } - else { - state(conn, SSH_AUTH_AGENT_INIT); - } - break; - - case SSH_AUTH_HOST: - state(conn, SSH_AUTH_AGENT_INIT); - break; - - case SSH_AUTH_AGENT_INIT: -#ifdef HAVE_LIBSSH2_AGENT_API - if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT) - && (strstr(sshc->authlist, "publickey") != NULL)) { - - /* Connect to the ssh-agent */ - /* The agent could be shared by a curl thread i believe - but nothing obvious as keys can be added/removed at any time */ - if(!sshc->ssh_agent) { - sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session); - if(!sshc->ssh_agent) { - infof(data, "Could not create agent object\n"); - - state(conn, SSH_AUTH_KEY_INIT); - break; - } - } - - rc = libssh2_agent_connect(sshc->ssh_agent); - if(rc == LIBSSH2_ERROR_EAGAIN) - break; - if(rc < 0) { - infof(data, "Failure connecting to agent\n"); - state(conn, SSH_AUTH_KEY_INIT); - rc = 0; /* clear rc and continue */ - } - else { - state(conn, SSH_AUTH_AGENT_LIST); - } - } - else -#endif /* HAVE_LIBSSH2_AGENT_API */ - state(conn, SSH_AUTH_KEY_INIT); - break; - - case SSH_AUTH_AGENT_LIST: -#ifdef HAVE_LIBSSH2_AGENT_API - rc = libssh2_agent_list_identities(sshc->ssh_agent); - - if(rc == LIBSSH2_ERROR_EAGAIN) - break; - if(rc < 0) { - infof(data, "Failure requesting identities to agent\n"); - state(conn, SSH_AUTH_KEY_INIT); - rc = 0; /* clear rc and continue */ - } - else { - state(conn, SSH_AUTH_AGENT); - sshc->sshagent_prev_identity = NULL; - } -#endif - break; - - case SSH_AUTH_AGENT: -#ifdef HAVE_LIBSSH2_AGENT_API - /* as prev_identity evolves only after an identity user auth finished we - can safely request it again as long as EAGAIN is returned here or by - libssh2_agent_userauth */ - rc = libssh2_agent_get_identity(sshc->ssh_agent, - &sshc->sshagent_identity, - sshc->sshagent_prev_identity); - if(rc == LIBSSH2_ERROR_EAGAIN) - break; - - if(rc == 0) { - rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user, - sshc->sshagent_identity); - - if(rc < 0) { - if(rc != LIBSSH2_ERROR_EAGAIN) - /* tried and failed? go to next identity */ - sshc->sshagent_prev_identity = sshc->sshagent_identity; - else - break; - } - } - - if(rc < 0) - infof(data, "Failure requesting identities to agent\n"); - else if(rc == 1) - infof(data, "No identity would match\n"); - - if(rc == LIBSSH2_ERROR_NONE) { - sshc->authed = TRUE; - infof(data, "Agent based authentication successful\n"); - state(conn, SSH_AUTH_DONE); - } - else { - state(conn, SSH_AUTH_KEY_INIT); - rc = 0; /* clear rc and continue */ - } -#endif - break; - - case SSH_AUTH_KEY_INIT: - if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) - && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) { - state(conn, SSH_AUTH_KEY); - } - else { - state(conn, SSH_AUTH_DONE); - } - break; - - case SSH_AUTH_KEY: - /* Authentication failed. Continue with keyboard-interactive now. */ - rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session, - conn->user, - curlx_uztoui( - strlen(conn->user)), - &kbd_callback); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc == 0) { - sshc->authed = TRUE; - infof(data, "Initialized keyboard interactive authentication\n"); - } - state(conn, SSH_AUTH_DONE); - break; - - case SSH_AUTH_DONE: - if(!sshc->authed) { - failf(data, "Authentication failure"); - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_LOGIN_DENIED; - break; - } - - /* - * At this point we have an authenticated ssh session. - */ - infof(data, "Authentication complete\n"); - - Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */ - - conn->sockfd = sock; - conn->writesockfd = CURL_SOCKET_BAD; - - if(conn->handler->protocol == CURLPROTO_SFTP) { - state(conn, SSH_SFTP_INIT); - break; - } - infof(data, "SSH CONNECT phase done\n"); - state(conn, SSH_STOP); - break; - - case SSH_SFTP_INIT: - /* - * Start the libssh2 sftp session - */ - sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session); - if(!sshc->sftp_session) { - char *err_msg; - if(libssh2_session_last_errno(sshc->ssh_session) == - LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } - - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - failf(data, "Failure initializing sftp session: %s", err_msg); - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_FAILED_INIT; - break; - } - state(conn, SSH_SFTP_REALPATH); - break; - - case SSH_SFTP_REALPATH: - { - char tempHome[PATH_MAX]; - - /* - * Get the "home" directory - */ - rc = sftp_libssh2_realpath(sshc->sftp_session, ".", - tempHome, PATH_MAX-1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc > 0) { - /* It seems that this string is not always NULL terminated */ - tempHome[rc] = '\0'; - sshc->homedir = strdup(tempHome); - if(!sshc->homedir) { - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - conn->data->state.most_recent_ftp_entrypath = sshc->homedir; - } - else { - /* Return the error type */ - err = sftp_libssh2_last_error(sshc->sftp_session); - if(err) - result = sftp_libssh2_error_to_CURLE(err); - else - /* in this case, the error wasn't in the SFTP level but for example - a time-out or similar */ - result = CURLE_SSH; - sshc->actualcode = result; - DEBUGF(infof(data, "error = %d makes libcurl = %d\n", - err, (int)result)); - state(conn, SSH_STOP); - break; - } - } - /* This is the last step in the SFTP connect phase. Do note that while - we get the homedir here, we get the "workingpath" in the DO action - since the homedir will remain the same between request but the - working path will not. */ - DEBUGF(infof(data, "SSH CONNECT phase done\n")); - state(conn, SSH_STOP); - break; - - case SSH_SFTP_QUOTE_INIT: - - result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path); - if(result) { - sshc->actualcode = result; - state(conn, SSH_STOP); - break; - } - - if(data->set.quote) { - infof(data, "Sending quote commands\n"); - sshc->quote_item = data->set.quote; - state(conn, SSH_SFTP_QUOTE); - } - else { - state(conn, SSH_SFTP_GETINFO); - } - break; - - case SSH_SFTP_POSTQUOTE_INIT: - if(data->set.postquote) { - infof(data, "Sending quote commands\n"); - sshc->quote_item = data->set.postquote; - state(conn, SSH_SFTP_QUOTE); - } - else { - state(conn, SSH_STOP); - } - break; - - case SSH_SFTP_QUOTE: - /* Send any quote commands */ - { - const char *cp; - - /* - * Support some of the "FTP" commands - */ - char *cmd = sshc->quote_item->data; - sshc->acceptfail = FALSE; - - /* if a command starts with an asterisk, which a legal SFTP command never - can, the command will be allowed to fail without it causing any - aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ - - if(cmd[0] == '*') { - cmd++; - sshc->acceptfail = TRUE; - } - - if(strcasecompare("pwd", cmd)) { - /* output debug output if that is requested */ - char *tmp = aprintf("257 \"%s\" is current directory.\n", - sftp_scp->path); - if(!tmp) { - result = CURLE_OUT_OF_MEMORY; - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - break; - } - if(data->set.verbose) { - Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn); - Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn); - } - /* this sends an FTP-like "header" to the header callback so that the - current directory can be read very similar to how it is read when - using ordinary FTP. */ - result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); - free(tmp); - if(result) { - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - } - else - state(conn, SSH_SFTP_NEXT_QUOTE); - break; - } - if(cmd) { - /* - * the arguments following the command must be separated from the - * command with a space so we can check for it unconditionally - */ - cp = strchr(cmd, ' '); - if(cp == NULL) { - failf(data, "Syntax error in SFTP command. Supply parameter(s)!"); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - - /* - * also, every command takes at least one argument so we get that - * first argument right now - */ - result = get_pathname(&cp, &sshc->quote_path1); - if(result) { - if(result == CURLE_OUT_OF_MEMORY) - failf(data, "Out of memory"); - else - failf(data, "Syntax error: Bad first parameter"); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - break; - } - - /* - * SFTP is a binary protocol, so we don't send text commands - * to the server. Instead, we scan for commands used by - * OpenSSH's sftp program and call the appropriate libssh2 - * functions. - */ - if(strncasecompare(cmd, "chgrp ", 6) || - strncasecompare(cmd, "chmod ", 6) || - strncasecompare(cmd, "chown ", 6) ) { - /* attribute change */ - - /* sshc->quote_path1 contains the mode to set */ - /* get the destination */ - result = get_pathname(&cp, &sshc->quote_path2); - if(result) { - if(result == CURLE_OUT_OF_MEMORY) - failf(data, "Out of memory"); - else - failf(data, "Syntax error in chgrp/chmod/chown: " - "Bad second parameter"); - Curl_safefree(sshc->quote_path1); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - break; - } - memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); - state(conn, SSH_SFTP_QUOTE_STAT); - break; - } - if(strncasecompare(cmd, "ln ", 3) || - strncasecompare(cmd, "symlink ", 8)) { - /* symbolic linking */ - /* sshc->quote_path1 is the source */ - /* get the destination */ - result = get_pathname(&cp, &sshc->quote_path2); - if(result) { - if(result == CURLE_OUT_OF_MEMORY) - failf(data, "Out of memory"); - else - failf(data, - "Syntax error in ln/symlink: Bad second parameter"); - Curl_safefree(sshc->quote_path1); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - break; - } - state(conn, SSH_SFTP_QUOTE_SYMLINK); - break; - } - else if(strncasecompare(cmd, "mkdir ", 6)) { - /* create dir */ - state(conn, SSH_SFTP_QUOTE_MKDIR); - break; - } - else if(strncasecompare(cmd, "rename ", 7)) { - /* rename file */ - /* first param is the source path */ - /* second param is the dest. path */ - result = get_pathname(&cp, &sshc->quote_path2); - if(result) { - if(result == CURLE_OUT_OF_MEMORY) - failf(data, "Out of memory"); - else - failf(data, "Syntax error in rename: Bad second parameter"); - Curl_safefree(sshc->quote_path1); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - break; - } - state(conn, SSH_SFTP_QUOTE_RENAME); - break; - } - else if(strncasecompare(cmd, "rmdir ", 6)) { - /* delete dir */ - state(conn, SSH_SFTP_QUOTE_RMDIR); - break; - } - else if(strncasecompare(cmd, "rm ", 3)) { - state(conn, SSH_SFTP_QUOTE_UNLINK); - break; - } -#ifdef HAS_STATVFS_SUPPORT - else if(strncasecompare(cmd, "statvfs ", 8)) { - state(conn, SSH_SFTP_QUOTE_STATVFS); - break; - } -#endif - - failf(data, "Unknown SFTP command"); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - } - if(!sshc->quote_item) { - state(conn, SSH_SFTP_GETINFO); - } - break; - - case SSH_SFTP_NEXT_QUOTE: - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - - sshc->quote_item = sshc->quote_item->next; - - if(sshc->quote_item) { - state(conn, SSH_SFTP_QUOTE); - } - else { - if(sshc->nextstate != SSH_NO_STATE) { - state(conn, sshc->nextstate); - sshc->nextstate = SSH_NO_STATE; - } - else { - state(conn, SSH_SFTP_GETINFO); - } - } - break; - - case SSH_SFTP_QUOTE_STAT: - { - char *cmd = sshc->quote_item->data; - sshc->acceptfail = FALSE; - - /* if a command starts with an asterisk, which a legal SFTP command never - can, the command will be allowed to fail without it causing any - aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ - - if(cmd[0] == '*') { - cmd++; - sshc->acceptfail = TRUE; - } - - if(!strncasecompare(cmd, "chmod", 5)) { - /* Since chown and chgrp only set owner OR group but libssh2 wants to - * set them both at once, we need to obtain the current ownership - * first. This takes an extra protocol round trip. - */ - rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, - curlx_uztoui(strlen(sshc->quote_path2)), - LIBSSH2_SFTP_STAT, - &sshc->quote_attrs); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc != 0 && !sshc->acceptfail) { /* get those attributes */ - err = sftp_libssh2_last_error(sshc->sftp_session); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Attempt to get SFTP stats failed: %s", - sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - } - - /* Now set the new attributes... */ - if(strncasecompare(cmd, "chgrp", 5)) { - sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); - sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; - if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: chgrp gid not a number"); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - } - else if(strncasecompare(cmd, "chmod", 5)) { - sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); - sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; - /* permissions are octal */ - if(sshc->quote_attrs.permissions == 0 && - !ISDIGIT(sshc->quote_path1[0])) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: chmod permissions not a number"); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - } - else if(strncasecompare(cmd, "chown", 5)) { - sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); - sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; - if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: chown uid not a number"); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - } - - /* Now send the completed structure... */ - state(conn, SSH_SFTP_QUOTE_SETSTAT); - break; - } - - case SSH_SFTP_QUOTE_SETSTAT: - rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, - curlx_uztoui(strlen(sshc->quote_path2)), - LIBSSH2_SFTP_SETSTAT, - &sshc->quote_attrs); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Attempt to set SFTP stats failed: %s", - sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - state(conn, SSH_SFTP_NEXT_QUOTE); - break; - - case SSH_SFTP_QUOTE_SYMLINK: - rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1, - curlx_uztoui(strlen(sshc->quote_path1)), - sshc->quote_path2, - curlx_uztoui(strlen(sshc->quote_path2)), - LIBSSH2_SFTP_SYMLINK); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "symlink command failed: %s", - sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - state(conn, SSH_SFTP_NEXT_QUOTE); - break; - - case SSH_SFTP_QUOTE_MKDIR: - rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1, - curlx_uztoui(strlen(sshc->quote_path1)), - data->set.new_directory_perms); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); - Curl_safefree(sshc->quote_path1); - failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - state(conn, SSH_SFTP_NEXT_QUOTE); - break; - - case SSH_SFTP_QUOTE_RENAME: - rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1, - curlx_uztoui(strlen(sshc->quote_path1)), - sshc->quote_path2, - curlx_uztoui(strlen(sshc->quote_path2)), - LIBSSH2_SFTP_RENAME_OVERWRITE | - LIBSSH2_SFTP_RENAME_ATOMIC | - LIBSSH2_SFTP_RENAME_NATIVE); - - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "rename command failed: %s", sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - state(conn, SSH_SFTP_NEXT_QUOTE); - break; - - case SSH_SFTP_QUOTE_RMDIR: - rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1, - curlx_uztoui(strlen(sshc->quote_path1))); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); - Curl_safefree(sshc->quote_path1); - failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - state(conn, SSH_SFTP_NEXT_QUOTE); - break; - - case SSH_SFTP_QUOTE_UNLINK: - rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1, - curlx_uztoui(strlen(sshc->quote_path1))); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); - Curl_safefree(sshc->quote_path1); - failf(data, "rm command failed: %s", sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - state(conn, SSH_SFTP_NEXT_QUOTE); - break; - -#ifdef HAS_STATVFS_SUPPORT - case SSH_SFTP_QUOTE_STATVFS: - { - LIBSSH2_SFTP_STATVFS statvfs; - rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1, - curlx_uztoui(strlen(sshc->quote_path1)), - &statvfs); - - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); - Curl_safefree(sshc->quote_path1); - failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - else if(rc == 0) { - char *tmp = aprintf("statvfs:\n" - "f_bsize: %llu\n" "f_frsize: %llu\n" - "f_blocks: %llu\n" "f_bfree: %llu\n" - "f_bavail: %llu\n" "f_files: %llu\n" - "f_ffree: %llu\n" "f_favail: %llu\n" - "f_fsid: %llu\n" "f_flag: %llu\n" - "f_namemax: %llu\n", - statvfs.f_bsize, statvfs.f_frsize, - statvfs.f_blocks, statvfs.f_bfree, - statvfs.f_bavail, statvfs.f_files, - statvfs.f_ffree, statvfs.f_favail, - statvfs.f_fsid, statvfs.f_flag, - statvfs.f_namemax); - if(!tmp) { - result = CURLE_OUT_OF_MEMORY; - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - break; - } - - result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); - free(tmp); - if(result) { - state(conn, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - } - } - state(conn, SSH_SFTP_NEXT_QUOTE); - break; - } -#endif - case SSH_SFTP_GETINFO: - { - if(data->set.get_filetime) { - state(conn, SSH_SFTP_FILETIME); - } - else { - state(conn, SSH_SFTP_TRANS_INIT); - } - break; - } - - case SSH_SFTP_FILETIME: - { - LIBSSH2_SFTP_ATTRIBUTES attrs; - - rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, - curlx_uztoui(strlen(sftp_scp->path)), - LIBSSH2_SFTP_STAT, &attrs); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc == 0) { - data->info.filetime = (long)attrs.mtime; - } - - state(conn, SSH_SFTP_TRANS_INIT); - break; - } - - case SSH_SFTP_TRANS_INIT: - if(data->set.upload) - state(conn, SSH_SFTP_UPLOAD_INIT); - else { - if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') - state(conn, SSH_SFTP_READDIR_INIT); - else - state(conn, SSH_SFTP_DOWNLOAD_INIT); - } - break; - - case SSH_SFTP_UPLOAD_INIT: - { - unsigned long flags; - /* - * NOTE!!! libssh2 requires that the destination path is a full path - * that includes the destination file and name OR ends in a "/" - * If this is not done the destination file will be named the - * same name as the last directory in the path. - */ - - if(data->state.resume_from != 0) { - LIBSSH2_SFTP_ATTRIBUTES attrs; - if(data->state.resume_from < 0) { - rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, - curlx_uztoui(strlen(sftp_scp->path)), - LIBSSH2_SFTP_STAT, &attrs); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc) { - data->state.resume_from = 0; - } - else { - curl_off_t size = attrs.filesize; - if(size < 0) { - failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); - return CURLE_BAD_DOWNLOAD_RESUME; - } - data->state.resume_from = attrs.filesize; - } - } - } - - if(data->set.ftp_append) - /* Try to open for append, but create if nonexisting */ - flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND; - else if(data->state.resume_from > 0) - /* If we have restart position then open for append */ - flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND; - else - /* Clear file before writing (normal behaviour) */ - flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC; - - sshc->sftp_handle = - libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, - curlx_uztoui(strlen(sftp_scp->path)), - flags, data->set.new_file_perms, - LIBSSH2_SFTP_OPENFILE); - - if(!sshc->sftp_handle) { - rc = libssh2_session_last_errno(sshc->ssh_session); - - if(LIBSSH2_ERROR_EAGAIN == rc) - break; - - if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc) - /* only when there was an SFTP protocol error can we extract - the sftp error! */ - err = sftp_libssh2_last_error(sshc->sftp_session); - else - err = -1; /* not an sftp error at all */ - - if(sshc->secondCreateDirs) { - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = err>= LIBSSH2_FX_OK? - sftp_libssh2_error_to_CURLE(err):CURLE_SSH; - failf(data, "Creating the dir/file failed: %s", - sftp_libssh2_strerror(err)); - break; - } - if(((err == LIBSSH2_FX_NO_SUCH_FILE) || - (err == LIBSSH2_FX_FAILURE) || - (err == LIBSSH2_FX_NO_SUCH_PATH)) && - (data->set.ftp_create_missing_dirs && - (strlen(sftp_scp->path) > 1))) { - /* try to create the path remotely */ - rc = 0; /* clear rc and continue */ - sshc->secondCreateDirs = 1; - state(conn, SSH_SFTP_CREATE_DIRS_INIT); - break; - } - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = err>= LIBSSH2_FX_OK? - sftp_libssh2_error_to_CURLE(err):CURLE_SSH; - if(!sshc->actualcode) { - /* Sometimes, for some reason libssh2_sftp_last_error() returns - zero even though libssh2_sftp_open() failed previously! We need - to work around that! */ - sshc->actualcode = CURLE_SSH; - err = -1; - } - failf(data, "Upload failed: %s (%d/%d)", - err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error", - err, rc); - break; - } - - /* If we have a restart point then we need to seek to the correct - position. */ - if(data->state.resume_from > 0) { - /* Let's read off the proper amount of bytes from the input. */ - if(conn->seek_func) { - seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, - SEEK_SET); - } - - if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed = 0; - - if(seekerr != CURL_SEEKFUNC_CANTSEEK) { - failf(data, "Could not seek stream"); - return CURLE_FTP_COULDNT_USE_REST; - } - /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ - do { - size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : - curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, - readthisamountnow, data->state.in); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Failed to read data"); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed < data->state.resume_from); - } - - /* now, decrease the size of the read */ - if(data->state.infilesize > 0) { - data->state.infilesize -= data->state.resume_from; - data->req.size = data->state.infilesize; - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - - SFTP_SEEK(sshc->sftp_handle, data->state.resume_from); - } - if(data->state.infilesize > 0) { - data->req.size = data->state.infilesize; - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - /* upload data */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); - - /* not set by Curl_setup_transfer to preserve keepon bits */ - conn->sockfd = conn->writesockfd; - - if(result) { - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = result; - } - else { - /* store this original bitmask setup to use later on if we can't - figure out a "real" bitmask */ - sshc->orig_waitfor = data->req.keepon; - - /* we want to use the _sending_ function even when the socket turns - out readable as the underlying libssh2 sftp send function will deal - with both accordingly */ - conn->cselect_bits = CURL_CSELECT_OUT; - - /* since we don't really wait for anything at this point, we want the - state machine to move on as soon as possible so we set a very short - timeout here */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); - - state(conn, SSH_STOP); - } - break; - } - - case SSH_SFTP_CREATE_DIRS_INIT: - if(strlen(sftp_scp->path) > 1) { - sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */ - state(conn, SSH_SFTP_CREATE_DIRS); - } - else { - state(conn, SSH_SFTP_UPLOAD_INIT); - } - break; - - case SSH_SFTP_CREATE_DIRS: - sshc->slash_pos = strchr(sshc->slash_pos, '/'); - if(sshc->slash_pos) { - *sshc->slash_pos = 0; - - infof(data, "Creating directory '%s'\n", sftp_scp->path); - state(conn, SSH_SFTP_CREATE_DIRS_MKDIR); - break; - } - state(conn, SSH_SFTP_UPLOAD_INIT); - break; - - case SSH_SFTP_CREATE_DIRS_MKDIR: - /* 'mode' - parameter is preliminary - default to 0644 */ - rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path, - curlx_uztoui(strlen(sftp_scp->path)), - data->set.new_directory_perms); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - *sshc->slash_pos = '/'; - ++sshc->slash_pos; - if(rc < 0) { - /* - * Abort if failure wasn't that the dir already exists or the - * permission was denied (creation might succeed further down the - * path) - retry on unspecific FAILURE also - */ - err = sftp_libssh2_last_error(sshc->sftp_session); - if((err != LIBSSH2_FX_FILE_ALREADY_EXISTS) && - (err != LIBSSH2_FX_FAILURE) && - (err != LIBSSH2_FX_PERMISSION_DENIED)) { - result = sftp_libssh2_error_to_CURLE(err); - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = result?result:CURLE_SSH; - break; - } - rc = 0; /* clear rc and continue */ - } - state(conn, SSH_SFTP_CREATE_DIRS); - break; - - case SSH_SFTP_READDIR_INIT: - Curl_pgrsSetDownloadSize(data, -1); - if(data->set.opt_no_body) { - state(conn, SSH_STOP); - break; - } - - /* - * This is a directory that we are trying to get, so produce a directory - * listing - */ - sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, - sftp_scp->path, - curlx_uztoui( - strlen(sftp_scp->path)), - 0, 0, LIBSSH2_SFTP_OPENDIR); - if(!sshc->sftp_handle) { - if(libssh2_session_last_errno(sshc->ssh_session) == - LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } - err = sftp_libssh2_last_error(sshc->sftp_session); - failf(data, "Could not open directory for reading: %s", - sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - result = sftp_libssh2_error_to_CURLE(err); - sshc->actualcode = result?result:CURLE_SSH; - break; - } - sshc->readdir_filename = malloc(PATH_MAX + 1); - if(!sshc->readdir_filename) { - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - sshc->readdir_longentry = malloc(PATH_MAX + 1); - if(!sshc->readdir_longentry) { - Curl_safefree(sshc->readdir_filename); - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - state(conn, SSH_SFTP_READDIR); - break; - - case SSH_SFTP_READDIR: - sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle, - sshc->readdir_filename, - PATH_MAX, - sshc->readdir_longentry, - PATH_MAX, - &sshc->readdir_attrs); - if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } - if(sshc->readdir_len > 0) { - sshc->readdir_filename[sshc->readdir_len] = '\0'; - - if(data->set.ftp_list_only) { - char *tmpLine; - - tmpLine = aprintf("%s\n", sshc->readdir_filename); - if(tmpLine == NULL) { - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - result = Curl_client_write(conn, CLIENTWRITE_BODY, - tmpLine, sshc->readdir_len + 1); - free(tmpLine); - - if(result) { - state(conn, SSH_STOP); - break; - } - /* since this counts what we send to the client, we include the - newline in this counter */ - data->req.bytecount += sshc->readdir_len + 1; - - /* output debug output if that is requested */ - if(data->set.verbose) { - Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename, - sshc->readdir_len, conn); - } - } - else { - sshc->readdir_currLen = (int)strlen(sshc->readdir_longentry); - sshc->readdir_totalLen = 80 + sshc->readdir_currLen; - sshc->readdir_line = calloc(sshc->readdir_totalLen, 1); - if(!sshc->readdir_line) { - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - - memcpy(sshc->readdir_line, sshc->readdir_longentry, - sshc->readdir_currLen); - if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && - ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFLNK)) { - sshc->readdir_linkPath = malloc(PATH_MAX + 1); - if(sshc->readdir_linkPath == NULL) { - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - - snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path, - sshc->readdir_filename); - state(conn, SSH_SFTP_READDIR_LINK); - break; - } - state(conn, SSH_SFTP_READDIR_BOTTOM); - break; - } - } - else if(sshc->readdir_len == 0) { - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - state(conn, SSH_SFTP_READDIR_DONE); - break; - } - else if(sshc->readdir_len <= 0) { - err = sftp_libssh2_last_error(sshc->sftp_session); - result = sftp_libssh2_error_to_CURLE(err); - sshc->actualcode = result?result:CURLE_SSH; - failf(data, "Could not open remote file for reading: %s :: %d", - sftp_libssh2_strerror(err), - libssh2_session_last_errno(sshc->ssh_session)); - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - state(conn, SSH_SFTP_CLOSE); - break; - } - break; - - case SSH_SFTP_READDIR_LINK: - sshc->readdir_len = - libssh2_sftp_symlink_ex(sshc->sftp_session, - sshc->readdir_linkPath, - curlx_uztoui(strlen(sshc->readdir_linkPath)), - sshc->readdir_filename, - PATH_MAX, LIBSSH2_SFTP_READLINK); - if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } - Curl_safefree(sshc->readdir_linkPath); - - /* get room for the filename and extra output */ - sshc->readdir_totalLen += 4 + sshc->readdir_len; - new_readdir_line = Curl_saferealloc(sshc->readdir_line, - sshc->readdir_totalLen); - if(!new_readdir_line) { - sshc->readdir_line = NULL; - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - sshc->readdir_line = new_readdir_line; - - sshc->readdir_currLen += snprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, - " -> %s", - sshc->readdir_filename); - - state(conn, SSH_SFTP_READDIR_BOTTOM); - break; - - case SSH_SFTP_READDIR_BOTTOM: - sshc->readdir_currLen += snprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, "\n"); - result = Curl_client_write(conn, CLIENTWRITE_BODY, - sshc->readdir_line, - sshc->readdir_currLen); - - if(!result) { - - /* output debug output if that is requested */ - if(data->set.verbose) { - Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line, - sshc->readdir_currLen, conn); - } - data->req.bytecount += sshc->readdir_currLen; - } - Curl_safefree(sshc->readdir_line); - if(result) { - state(conn, SSH_STOP); - } - else - state(conn, SSH_SFTP_READDIR); - break; - - case SSH_SFTP_READDIR_DONE: - if(libssh2_sftp_closedir(sshc->sftp_handle) == - LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } - sshc->sftp_handle = NULL; - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - state(conn, SSH_STOP); - break; - - case SSH_SFTP_DOWNLOAD_INIT: - /* - * Work on getting the specified file - */ - sshc->sftp_handle = - libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, - curlx_uztoui(strlen(sftp_scp->path)), - LIBSSH2_FXF_READ, data->set.new_file_perms, - LIBSSH2_SFTP_OPENFILE); - if(!sshc->sftp_handle) { - if(libssh2_session_last_errno(sshc->ssh_session) == - LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } - err = sftp_libssh2_last_error(sshc->sftp_session); - failf(data, "Could not open remote file for reading: %s", - sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - result = sftp_libssh2_error_to_CURLE(err); - sshc->actualcode = result?result:CURLE_SSH; - break; - } - state(conn, SSH_SFTP_DOWNLOAD_STAT); - break; - - case SSH_SFTP_DOWNLOAD_STAT: - { - LIBSSH2_SFTP_ATTRIBUTES attrs; - - rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, - curlx_uztoui(strlen(sftp_scp->path)), - LIBSSH2_SFTP_STAT, &attrs); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc || - !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) || - (attrs.filesize == 0)) { - /* - * libssh2_sftp_open() didn't return an error, so maybe the server - * just doesn't support stat() - * OR the server doesn't return a file size with a stat() - * OR file size is 0 - */ - data->req.size = -1; - data->req.maxdownload = -1; - Curl_pgrsSetDownloadSize(data, -1); - } - else { - curl_off_t size = attrs.filesize; - - if(size < 0) { - failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); - return CURLE_BAD_DOWNLOAD_RESUME; - } - if(conn->data->state.use_range) { - curl_off_t from, to; - char *ptr; - char *ptr2; - CURLofft to_t; - CURLofft from_t; - - from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from); - if(from_t == CURL_OFFT_FLOW) - return CURLE_RANGE_ERROR; - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) - ptr++; - to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); - if(to_t == CURL_OFFT_FLOW) - return CURLE_RANGE_ERROR; - if((to_t == CURL_OFFT_INVAL) /* no "to" value given */ - || (to >= size)) { - to = size - 1; - } - if(from_t) { - /* from is relative to end of file */ - from = size - to; - to = size - 1; - } - if(from > size) { - failf(data, "Offset (%" - CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" - CURL_FORMAT_CURL_OFF_T ")", from, attrs.filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - if(from > to) { - from = to; - size = 0; - } - else { - size = to - from + 1; - } - - SFTP_SEEK(conn->proto.sshc.sftp_handle, from); - } - data->req.size = size; - data->req.maxdownload = size; - Curl_pgrsSetDownloadSize(data, size); - } - - /* We can resume if we can seek to the resume position */ - if(data->state.resume_from) { - if(data->state.resume_from < 0) { - /* We're supposed to download the last abs(from) bytes */ - if((curl_off_t)attrs.filesize < -data->state.resume_from) { - failf(data, "Offset (%" - CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" - CURL_FORMAT_CURL_OFF_T ")", - data->state.resume_from, attrs.filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - /* download from where? */ - data->state.resume_from += attrs.filesize; - } - else { - if((curl_off_t)attrs.filesize < data->state.resume_from) { - failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T - ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", - data->state.resume_from, attrs.filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - } - /* Does a completed file need to be seeked and started or closed ? */ - /* Now store the number of bytes we are expected to download */ - data->req.size = attrs.filesize - data->state.resume_from; - data->req.maxdownload = attrs.filesize - data->state.resume_from; - Curl_pgrsSetDownloadSize(data, - attrs.filesize - data->state.resume_from); - SFTP_SEEK(sshc->sftp_handle, data->state.resume_from); - } - } - - /* Setup the actual download */ - if(data->req.size == 0) { - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - infof(data, "File already completely downloaded\n"); - state(conn, SSH_STOP); - break; - } - Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size, - FALSE, NULL, -1, NULL); - - /* not set by Curl_setup_transfer to preserve keepon bits */ - conn->writesockfd = conn->sockfd; - - /* we want to use the _receiving_ function even when the socket turns - out writableable as the underlying libssh2 recv function will deal - with both accordingly */ - conn->cselect_bits = CURL_CSELECT_IN; - - if(result) { - /* this should never occur; the close state should be entered - at the time the error occurs */ - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = result; - } - else { - state(conn, SSH_STOP); - } - break; - - case SSH_SFTP_CLOSE: - if(sshc->sftp_handle) { - rc = libssh2_sftp_close(sshc->sftp_handle); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc < 0) { - infof(data, "Failed to close libssh2 file\n"); - } - sshc->sftp_handle = NULL; - } - if(sftp_scp) - Curl_safefree(sftp_scp->path); - - DEBUGF(infof(data, "SFTP DONE done\n")); - - /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT - After nextstate is executed, the control should come back to - SSH_SFTP_CLOSE to pass the correct result back */ - if(sshc->nextstate != SSH_NO_STATE && - sshc->nextstate != SSH_SFTP_CLOSE) { - state(conn, sshc->nextstate); - sshc->nextstate = SSH_SFTP_CLOSE; - } - else { - state(conn, SSH_STOP); - result = sshc->actualcode; - } - break; - - case SSH_SFTP_SHUTDOWN: - /* during times we get here due to a broken transfer and then the - sftp_handle might not have been taken down so make sure that is done - before we proceed */ - - if(sshc->sftp_handle) { - rc = libssh2_sftp_close(sshc->sftp_handle); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc < 0) { - infof(data, "Failed to close libssh2 file\n"); - } - sshc->sftp_handle = NULL; - } - if(sshc->sftp_session) { - rc = libssh2_sftp_shutdown(sshc->sftp_session); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc < 0) { - infof(data, "Failed to stop libssh2 sftp subsystem\n"); - } - sshc->sftp_session = NULL; - } - - Curl_safefree(sshc->homedir); - conn->data->state.most_recent_ftp_entrypath = NULL; - - state(conn, SSH_SESSION_DISCONNECT); - break; - - case SSH_SCP_TRANS_INIT: - result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path); - if(result) { - sshc->actualcode = result; - state(conn, SSH_STOP); - break; - } - - if(data->set.upload) { - if(data->state.infilesize < 0) { - failf(data, "SCP requires a known file size for upload"); - sshc->actualcode = CURLE_UPLOAD_FAILED; - state(conn, SSH_SCP_CHANNEL_FREE); - break; - } - state(conn, SSH_SCP_UPLOAD_INIT); - } - else { - state(conn, SSH_SCP_DOWNLOAD_INIT); - } - break; - - case SSH_SCP_UPLOAD_INIT: - /* - * libssh2 requires that the destination path is a full path that - * includes the destination file and name OR ends in a "/" . If this is - * not done the destination file will be named the same name as the last - * directory in the path. - */ - sshc->ssh_channel = - SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms, - data->state.infilesize); - if(!sshc->ssh_channel) { - int ssh_err; - char *err_msg; - - if(libssh2_session_last_errno(sshc->ssh_session) == - LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } - - ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0)); - failf(conn->data, "%s", err_msg); - state(conn, SSH_SCP_CHANNEL_FREE); - sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); - break; - } - - /* upload data */ - Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL, - FIRSTSOCKET, NULL); - - /* not set by Curl_setup_transfer to preserve keepon bits */ - conn->sockfd = conn->writesockfd; - - if(result) { - state(conn, SSH_SCP_CHANNEL_FREE); - sshc->actualcode = result; - } - else { - /* store this original bitmask setup to use later on if we can't - figure out a "real" bitmask */ - sshc->orig_waitfor = data->req.keepon; - - /* we want to use the _sending_ function even when the socket turns - out readable as the underlying libssh2 scp send function will deal - with both accordingly */ - conn->cselect_bits = CURL_CSELECT_OUT; - - state(conn, SSH_STOP); - } - break; - - case SSH_SCP_DOWNLOAD_INIT: - { - curl_off_t bytecount; - - /* - * We must check the remote file; if it is a directory no values will - * be set in sb - */ - - /* - * If support for >2GB files exists, use it. - */ - - /* get a fresh new channel from the ssh layer */ -#if LIBSSH2_VERSION_NUM < 0x010700 - struct stat sb; - memset(&sb, 0, sizeof(struct stat)); - sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session, - sftp_scp->path, &sb); -#else - libssh2_struct_stat sb; - memset(&sb, 0, sizeof(libssh2_struct_stat)); - sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, - sftp_scp->path, &sb); -#endif - - if(!sshc->ssh_channel) { - int ssh_err; - char *err_msg; - - if(libssh2_session_last_errno(sshc->ssh_session) == - LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } - - - ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0)); - failf(conn->data, "%s", err_msg); - state(conn, SSH_SCP_CHANNEL_FREE); - sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); - break; - } - - /* download data */ - bytecount = (curl_off_t)sb.st_size; - data->req.maxdownload = (curl_off_t)sb.st_size; - Curl_setup_transfer(conn, FIRSTSOCKET, bytecount, FALSE, NULL, -1, NULL); - - /* not set by Curl_setup_transfer to preserve keepon bits */ - conn->writesockfd = conn->sockfd; - - /* we want to use the _receiving_ function even when the socket turns - out writableable as the underlying libssh2 recv function will deal - with both accordingly */ - conn->cselect_bits = CURL_CSELECT_IN; - - if(result) { - state(conn, SSH_SCP_CHANNEL_FREE); - sshc->actualcode = result; - } - else - state(conn, SSH_STOP); - } - break; - - case SSH_SCP_DONE: - if(data->set.upload) - state(conn, SSH_SCP_SEND_EOF); - else - state(conn, SSH_SCP_CHANNEL_FREE); - break; - - case SSH_SCP_SEND_EOF: - if(sshc->ssh_channel) { - rc = libssh2_channel_send_eof(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc) { - infof(data, "Failed to send libssh2 channel EOF\n"); - } - } - state(conn, SSH_SCP_WAIT_EOF); - break; - - case SSH_SCP_WAIT_EOF: - if(sshc->ssh_channel) { - rc = libssh2_channel_wait_eof(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc) { - infof(data, "Failed to get channel EOF: %d\n", rc); - } - } - state(conn, SSH_SCP_WAIT_CLOSE); - break; - - case SSH_SCP_WAIT_CLOSE: - if(sshc->ssh_channel) { - rc = libssh2_channel_wait_closed(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc) { - infof(data, "Channel failed to close: %d\n", rc); - } - } - state(conn, SSH_SCP_CHANNEL_FREE); - break; - - case SSH_SCP_CHANNEL_FREE: - if(sshc->ssh_channel) { - rc = libssh2_channel_free(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc < 0) { - infof(data, "Failed to free libssh2 scp subsystem\n"); - } - sshc->ssh_channel = NULL; - } - DEBUGF(infof(data, "SCP DONE phase complete\n")); -#if 0 /* PREV */ - state(conn, SSH_SESSION_DISCONNECT); -#endif - state(conn, SSH_STOP); - result = sshc->actualcode; - break; - - case SSH_SESSION_DISCONNECT: - /* during weird times when we've been prematurely aborted, the channel - is still alive when we reach this state and we MUST kill the channel - properly first */ - if(sshc->ssh_channel) { - rc = libssh2_channel_free(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc < 0) { - infof(data, "Failed to free libssh2 scp subsystem\n"); - } - sshc->ssh_channel = NULL; - } - - if(sshc->ssh_session) { - rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown"); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc < 0) { - infof(data, "Failed to disconnect libssh2 session\n"); - } - } - - Curl_safefree(sshc->homedir); - conn->data->state.most_recent_ftp_entrypath = NULL; - - state(conn, SSH_SESSION_FREE); - break; - - case SSH_SESSION_FREE: -#ifdef HAVE_LIBSSH2_KNOWNHOST_API - if(sshc->kh) { - libssh2_knownhost_free(sshc->kh); - sshc->kh = NULL; - } -#endif - -#ifdef HAVE_LIBSSH2_AGENT_API - if(sshc->ssh_agent) { - rc = libssh2_agent_disconnect(sshc->ssh_agent); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc < 0) { - infof(data, "Failed to disconnect from libssh2 agent\n"); - } - libssh2_agent_free(sshc->ssh_agent); - sshc->ssh_agent = NULL; - - /* NB: there is no need to free identities, they are part of internal - agent stuff */ - sshc->sshagent_identity = NULL; - sshc->sshagent_prev_identity = NULL; - } -#endif - - if(sshc->ssh_session) { - rc = libssh2_session_free(sshc->ssh_session); - if(rc == LIBSSH2_ERROR_EAGAIN) { - break; - } - if(rc < 0) { - infof(data, "Failed to free libssh2 session\n"); - } - sshc->ssh_session = NULL; - } - - /* worst-case scenario cleanup */ - - DEBUGASSERT(sshc->ssh_session == NULL); - DEBUGASSERT(sshc->ssh_channel == NULL); - DEBUGASSERT(sshc->sftp_session == NULL); - DEBUGASSERT(sshc->sftp_handle == NULL); -#ifdef HAVE_LIBSSH2_KNOWNHOST_API - DEBUGASSERT(sshc->kh == NULL); -#endif -#ifdef HAVE_LIBSSH2_AGENT_API - DEBUGASSERT(sshc->ssh_agent == NULL); -#endif - - Curl_safefree(sshc->rsa_pub); - Curl_safefree(sshc->rsa); - - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - - Curl_safefree(sshc->homedir); - - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - Curl_safefree(sshc->readdir_line); - Curl_safefree(sshc->readdir_linkPath); - - /* the code we are about to return */ - result = sshc->actualcode; - - memset(sshc, 0, sizeof(struct ssh_conn)); - - connclose(conn, "SSH session free"); - sshc->state = SSH_SESSION_FREE; /* current */ - sshc->nextstate = SSH_NO_STATE; - state(conn, SSH_STOP); - break; - - case SSH_QUIT: - /* fallthrough, just stop! */ - default: - /* internal error */ - sshc->nextstate = SSH_NO_STATE; - state(conn, SSH_STOP); - break; - } - - } while(!rc && (sshc->state != SSH_STOP)); - - if(rc == LIBSSH2_ERROR_EAGAIN) { - /* we would block, we need to wait for the socket to be ready (in the - right direction too)! */ - *block = TRUE; - } - - return result; -} - -/* called by the multi interface to figure out what socket(s) to wait for and - for what actions in the DO_DONE, PERFORM and WAITPERFORM states */ -static int ssh_perform_getsock(const struct connectdata *conn, - curl_socket_t *sock, /* points to numsocks - number of sockets */ - int numsocks) -{ -#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION - int bitmap = GETSOCK_BLANK; - (void)numsocks; - - sock[0] = conn->sock[FIRSTSOCKET]; - - if(conn->waitfor & KEEP_RECV) - bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); - - if(conn->waitfor & KEEP_SEND) - bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); - - return bitmap; -#else - /* if we don't know the direction we can use the generic *_getsock() - function even for the protocol_connect and doing states */ - return Curl_single_getsock(conn, sock, numsocks); -#endif -} - -/* Generic function called by the multi interface to figure out what socket(s) - to wait for and for what actions during the DOING and PROTOCONNECT states*/ -static int ssh_getsock(struct connectdata *conn, - curl_socket_t *sock, /* points to numsocks number - of sockets */ - int numsocks) -{ -#ifndef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION - (void)conn; - (void)sock; - (void)numsocks; - /* if we don't know any direction we can just play along as we used to and - not provide any sensible info */ - return GETSOCK_BLANK; -#else - /* if we know the direction we can use the generic *_getsock() function even - for the protocol_connect and doing states */ - return ssh_perform_getsock(conn, sock, numsocks); -#endif -} - -#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION -/* - * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this - * function is used to figure out in what direction and stores this info so - * that the multi interface can take advantage of it. Make sure to call this - * function in all cases so that when it _doesn't_ return EAGAIN we can - * restore the default wait bits. - */ -static void ssh_block2waitfor(struct connectdata *conn, bool block) -{ - struct ssh_conn *sshc = &conn->proto.sshc; - int dir = 0; - if(block) { - dir = libssh2_session_block_directions(sshc->ssh_session); - if(dir) { - /* translate the libssh2 define bits into our own bit defines */ - conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) | - ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0); - } - } - if(!dir) - /* It didn't block or libssh2 didn't reveal in which direction, put back - the original set */ - conn->waitfor = sshc->orig_waitfor; -} -#else - /* no libssh2 directional support so we simply don't know */ -#define ssh_block2waitfor(x,y) Curl_nop_stmt -#endif - -/* called repeatedly until done from multi.c */ -static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done) -{ - struct ssh_conn *sshc = &conn->proto.sshc; - CURLcode result = CURLE_OK; - bool block; /* we store the status and use that to provide a ssh_getsock() - implementation */ - - result = ssh_statemach_act(conn, &block); - *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; - ssh_block2waitfor(conn, block); - - return result; -} - -static CURLcode ssh_block_statemach(struct connectdata *conn, - bool disconnect) -{ - struct ssh_conn *sshc = &conn->proto.sshc; - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - while((sshc->state != SSH_STOP) && !result) { - bool block; - time_t left = 1000; - struct curltime now = Curl_tvnow(); - - result = ssh_statemach_act(conn, &block); - if(result) - break; - - if(!disconnect) { - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - - result = Curl_speedcheck(data, now); - if(result) - break; - - left = Curl_timeleft(data, NULL, FALSE); - if(left < 0) { - failf(data, "Operation timed out"); - return CURLE_OPERATION_TIMEDOUT; - } - } - -#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION - if(!result && block) { - int dir = libssh2_session_block_directions(sshc->ssh_session); - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - curl_socket_t fd_read = CURL_SOCKET_BAD; - curl_socket_t fd_write = CURL_SOCKET_BAD; - if(LIBSSH2_SESSION_BLOCK_INBOUND & dir) - fd_read = sock; - if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) - fd_write = sock; - /* wait for the socket to become ready */ - (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, - left>1000?1000:left); /* ignore result */ - } -#endif - - } - - return result; -} - -/* - * SSH setup and connection - */ -static CURLcode ssh_setup_connection(struct connectdata *conn) -{ - struct SSHPROTO *ssh; - - conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO)); - if(!ssh) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; -} - -static Curl_recv scp_recv, sftp_recv; -static Curl_send scp_send, sftp_send; - -/* - * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to - * do protocol-specific actions at connect-time. - */ -static CURLcode ssh_connect(struct connectdata *conn, bool *done) -{ -#ifdef CURL_LIBSSH2_DEBUG - curl_socket_t sock; -#endif - struct ssh_conn *ssh; - CURLcode result; - struct Curl_easy *data = conn->data; - - /* initialize per-handle data if not already */ - if(!data->req.protop) - ssh_setup_connection(conn); - - /* We default to persistent connections. We set this already in this connect - function to make the re-use checks properly be able to check this bit. */ - connkeep(conn, "SSH default"); - - if(conn->handler->protocol & CURLPROTO_SCP) { - conn->recv[FIRSTSOCKET] = scp_recv; - conn->send[FIRSTSOCKET] = scp_send; - } - else { - conn->recv[FIRSTSOCKET] = sftp_recv; - conn->send[FIRSTSOCKET] = sftp_send; - } - ssh = &conn->proto.sshc; - -#ifdef CURL_LIBSSH2_DEBUG - if(conn->user) { - infof(data, "User: %s\n", conn->user); - } - if(conn->passwd) { - infof(data, "Password: %s\n", conn->passwd); - } - sock = conn->sock[FIRSTSOCKET]; -#endif /* CURL_LIBSSH2_DEBUG */ - - ssh->ssh_session = libssh2_session_init_ex(my_libssh2_malloc, - my_libssh2_free, - my_libssh2_realloc, conn); - if(ssh->ssh_session == NULL) { - failf(data, "Failure initialising ssh session"); - return CURLE_FAILED_INIT; - } - - if(data->set.ssh_compression) { -#if LIBSSH2_VERSION_NUM >= 0x010208 - if(libssh2_session_flag(ssh->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0) -#endif - infof(data, "Failed to enable compression for ssh session\n"); - } - -#ifdef HAVE_LIBSSH2_KNOWNHOST_API - if(data->set.str[STRING_SSH_KNOWNHOSTS]) { - int rc; - ssh->kh = libssh2_knownhost_init(ssh->ssh_session); - if(!ssh->kh) { - /* eeek. TODO: free the ssh_session! */ - return CURLE_FAILED_INIT; - } - - /* read all known hosts from there */ - rc = libssh2_knownhost_readfile(ssh->kh, - data->set.str[STRING_SSH_KNOWNHOSTS], - LIBSSH2_KNOWNHOST_FILE_OPENSSH); - if(rc < 0) - infof(data, "Failed to read known hosts from %s\n", - data->set.str[STRING_SSH_KNOWNHOSTS]); - } -#endif /* HAVE_LIBSSH2_KNOWNHOST_API */ - -#ifdef CURL_LIBSSH2_DEBUG - libssh2_trace(ssh->ssh_session, ~0); - infof(data, "SSH socket: %d\n", (int)sock); -#endif /* CURL_LIBSSH2_DEBUG */ - - state(conn, SSH_INIT); - - result = ssh_multi_statemach(conn, done); - - return result; -} - -/* - *********************************************************************** - * - * scp_perform() - * - * This is the actual DO function for SCP. Get a file according to - * the options previously setup. - */ - -static -CURLcode scp_perform(struct connectdata *conn, - bool *connected, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - - DEBUGF(infof(conn->data, "DO phase starts\n")); - - *dophase_done = FALSE; /* not done yet */ - - /* start the first command in the DO phase */ - state(conn, SSH_SCP_TRANS_INIT); - - /* run the state-machine */ - result = ssh_multi_statemach(conn, dophase_done); - - *connected = conn->bits.tcpconnect[FIRSTSOCKET]; - - if(*dophase_done) { - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - - return result; -} - -/* called from multi.c while DOing */ -static CURLcode scp_doing(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result; - result = ssh_multi_statemach(conn, dophase_done); - - if(*dophase_done) { - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - return result; -} - -/* - * The DO function is generic for both protocols. There was previously two - * separate ones but this way means less duplicated code. - */ - -static CURLcode ssh_do(struct connectdata *conn, bool *done) -{ - CURLcode result; - bool connected = 0; - struct Curl_easy *data = conn->data; - struct ssh_conn *sshc = &conn->proto.sshc; - - *done = FALSE; /* default to false */ - - data->req.size = -1; /* make sure this is unknown at this point */ - - sshc->actualcode = CURLE_OK; /* reset error code */ - sshc->secondCreateDirs = 0; /* reset the create dir attempt state - variable */ - - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, -1); - Curl_pgrsSetDownloadSize(data, -1); - - if(conn->handler->protocol & CURLPROTO_SCP) - result = scp_perform(conn, &connected, done); - else - result = sftp_perform(conn, &connected, done); - - return result; -} - -/* BLOCKING, but the function is using the state machine so the only reason - this is still blocking is that the multi interface code has no support for - disconnecting operations that takes a while */ -static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection) -{ - CURLcode result = CURLE_OK; - struct ssh_conn *ssh = &conn->proto.sshc; - (void) dead_connection; - - if(ssh->ssh_session) { - /* only if there's a session still around to use! */ - - state(conn, SSH_SESSION_DISCONNECT); - - result = ssh_block_statemach(conn, TRUE); - } - - return result; -} - -/* generic done function for both SCP and SFTP called from their specific - done functions */ -static CURLcode ssh_done(struct connectdata *conn, CURLcode status) -{ - CURLcode result = CURLE_OK; - struct SSHPROTO *sftp_scp = conn->data->req.protop; - - if(!status) { - /* run the state-machine - - TODO: when the multi interface is used, this _really_ should be using - the ssh_multi_statemach function but we have no general support for - non-blocking DONE operations! - */ - result = ssh_block_statemach(conn, FALSE); - } - else - result = status; - - if(sftp_scp) - Curl_safefree(sftp_scp->path); - if(Curl_pgrsDone(conn)) - return CURLE_ABORTED_BY_CALLBACK; - - conn->data->req.keepon = 0; /* clear all bits */ - return result; -} - - -static CURLcode scp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - (void)premature; /* not used */ - - if(!status) - state(conn, SSH_SCP_DONE); - - return ssh_done(conn, status); - -} - -static ssize_t scp_send(struct connectdata *conn, int sockindex, - const void *mem, size_t len, CURLcode *err) -{ - ssize_t nwrite; - (void)sockindex; /* we only support SCP on the fixed known primary socket */ - - /* libssh2_channel_write() returns int! */ - nwrite = (ssize_t) - libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len); - - ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); - - if(nwrite == LIBSSH2_ERROR_EAGAIN) { - *err = CURLE_AGAIN; - nwrite = 0; - } - else if(nwrite < LIBSSH2_ERROR_NONE) { - *err = libssh2_session_error_to_CURLE((int)nwrite); - nwrite = -1; - } - - return nwrite; -} - -static ssize_t scp_recv(struct connectdata *conn, int sockindex, - char *mem, size_t len, CURLcode *err) -{ - ssize_t nread; - (void)sockindex; /* we only support SCP on the fixed known primary socket */ - - /* libssh2_channel_read() returns int */ - nread = (ssize_t) - libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len); - - ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); - if(nread == LIBSSH2_ERROR_EAGAIN) { - *err = CURLE_AGAIN; - nread = -1; - } - - return nread; -} - -/* - * =============== SFTP =============== - */ - -/* - *********************************************************************** - * - * sftp_perform() - * - * This is the actual DO function for SFTP. Get a file/directory according to - * the options previously setup. - */ - -static -CURLcode sftp_perform(struct connectdata *conn, - bool *connected, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - - DEBUGF(infof(conn->data, "DO phase starts\n")); - - *dophase_done = FALSE; /* not done yet */ - - /* start the first command in the DO phase */ - state(conn, SSH_SFTP_QUOTE_INIT); - - /* run the state-machine */ - result = ssh_multi_statemach(conn, dophase_done); - - *connected = conn->bits.tcpconnect[FIRSTSOCKET]; - - if(*dophase_done) { - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - - return result; -} - -/* called from multi.c while DOing */ -static CURLcode sftp_doing(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result = ssh_multi_statemach(conn, dophase_done); - - if(*dophase_done) { - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - return result; -} - -/* BLOCKING, but the function is using the state machine so the only reason - this is still blocking is that the multi interface code has no support for - disconnecting operations that takes a while */ -static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection) -{ - CURLcode result = CURLE_OK; - (void) dead_connection; - - DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n")); - - if(conn->proto.sshc.ssh_session) { - /* only if there's a session still around to use! */ - state(conn, SSH_SFTP_SHUTDOWN); - result = ssh_block_statemach(conn, TRUE); - } - - DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n")); - - return result; - -} - -static CURLcode sftp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - struct ssh_conn *sshc = &conn->proto.sshc; - - if(!status) { - /* Post quote commands are executed after the SFTP_CLOSE state to avoid - errors that could happen due to open file handles during POSTQUOTE - operation */ - if(!status && !premature && conn->data->set.postquote) { - sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; - state(conn, SSH_SFTP_CLOSE); - } - else - state(conn, SSH_SFTP_CLOSE); - } - return ssh_done(conn, status); -} - -/* return number of sent bytes */ -static ssize_t sftp_send(struct connectdata *conn, int sockindex, - const void *mem, size_t len, CURLcode *err) -{ - ssize_t nwrite; /* libssh2_sftp_write() used to return size_t in 0.14 - but is changed to ssize_t in 0.15. These days we don't - support libssh2 0.15*/ - (void)sockindex; - - nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len); - - ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); - - if(nwrite == LIBSSH2_ERROR_EAGAIN) { - *err = CURLE_AGAIN; - nwrite = 0; - } - else if(nwrite < LIBSSH2_ERROR_NONE) { - *err = libssh2_session_error_to_CURLE((int)nwrite); - nwrite = -1; - } - - return nwrite; -} - -/* - * Return number of received (decrypted) bytes - * or <0 on error - */ -static ssize_t sftp_recv(struct connectdata *conn, int sockindex, - char *mem, size_t len, CURLcode *err) -{ - ssize_t nread; - (void)sockindex; - - nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len); - - ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); - - if(nread == LIBSSH2_ERROR_EAGAIN) { - *err = CURLE_AGAIN; - nread = -1; - - } - else if(nread < 0) { - *err = libssh2_session_error_to_CURLE((int)nread); - } - return nread; -} - -/* The get_pathname() function is being borrowed from OpenSSH sftp.c - version 4.6p1. */ -/* - * Copyright (c) 2001-2004 Damien Miller - * - * 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. - */ -static CURLcode -get_pathname(const char **cpp, char **path) -{ - const char *cp = *cpp, *end; - char quot; - unsigned int i, j; - static const char WHITESPACE[] = " \t\r\n"; - - cp += strspn(cp, WHITESPACE); - if(!*cp) { - *cpp = cp; - *path = NULL; - return CURLE_QUOTE_ERROR; - } - - *path = malloc(strlen(cp) + 1); - if(*path == NULL) - return CURLE_OUT_OF_MEMORY; - - /* Check for quoted filenames */ - if(*cp == '\"' || *cp == '\'') { - quot = *cp++; - - /* Search for terminating quote, unescape some chars */ - for(i = j = 0; i <= strlen(cp); i++) { - if(cp[i] == quot) { /* Found quote */ - i++; - (*path)[j] = '\0'; - break; - } - if(cp[i] == '\0') { /* End of string */ - /*error("Unterminated quote");*/ - goto fail; - } - if(cp[i] == '\\') { /* Escaped characters */ - i++; - if(cp[i] != '\'' && cp[i] != '\"' && - cp[i] != '\\') { - /*error("Bad escaped character '\\%c'", - cp[i]);*/ - goto fail; - } - } - (*path)[j++] = cp[i]; - } - - if(j == 0) { - /*error("Empty quotes");*/ - goto fail; - } - *cpp = cp + i + strspn(cp + i, WHITESPACE); - } - else { - /* Read to end of filename */ - end = strpbrk(cp, WHITESPACE); - if(end == NULL) - end = strchr(cp, '\0'); - *cpp = end + strspn(end, WHITESPACE); - - memcpy(*path, cp, end - cp); - (*path)[end - cp] = '\0'; - } - return CURLE_OK; - - fail: - Curl_safefree(*path); - return CURLE_QUOTE_ERROR; -} - - -static const char *sftp_libssh2_strerror(int err) -{ - switch(err) { - case LIBSSH2_FX_NO_SUCH_FILE: - return "No such file or directory"; - - case LIBSSH2_FX_PERMISSION_DENIED: - return "Permission denied"; - - case LIBSSH2_FX_FAILURE: - return "Operation failed"; - - case LIBSSH2_FX_BAD_MESSAGE: - return "Bad message from SFTP server"; - - case LIBSSH2_FX_NO_CONNECTION: - return "Not connected to SFTP server"; - - case LIBSSH2_FX_CONNECTION_LOST: - return "Connection to SFTP server lost"; - - case LIBSSH2_FX_OP_UNSUPPORTED: - return "Operation not supported by SFTP server"; - - case LIBSSH2_FX_INVALID_HANDLE: - return "Invalid handle"; - - case LIBSSH2_FX_NO_SUCH_PATH: - return "No such file or directory"; - - case LIBSSH2_FX_FILE_ALREADY_EXISTS: - return "File already exists"; - - case LIBSSH2_FX_WRITE_PROTECT: - return "File is write protected"; - - case LIBSSH2_FX_NO_MEDIA: - return "No media"; - - case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: - return "Disk full"; - - case LIBSSH2_FX_QUOTA_EXCEEDED: - return "User quota exceeded"; - - case LIBSSH2_FX_UNKNOWN_PRINCIPLE: - return "Unknown principle"; - - case LIBSSH2_FX_LOCK_CONFlICT: - return "File lock conflict"; - - case LIBSSH2_FX_DIR_NOT_EMPTY: - return "Directory not empty"; - - case LIBSSH2_FX_NOT_A_DIRECTORY: - return "Not a directory"; - - case LIBSSH2_FX_INVALID_FILENAME: - return "Invalid filename"; - - case LIBSSH2_FX_LINK_LOOP: - return "Link points to itself"; - } - return "Unknown error in libssh2"; -} - -#endif /* USE_LIBSSH2 */ diff --git a/dep/cpr/opt/curl/lib/ssh.h b/dep/cpr/opt/curl/lib/ssh.h deleted file mode 100644 index b350dcf3a56..00000000000 --- a/dep/cpr/opt/curl/lib/ssh.h +++ /dev/null @@ -1,198 +0,0 @@ -#ifndef HEADER_CURL_SSH_H -#define HEADER_CURL_SSH_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_LIBSSH2_H -#include -#include -#endif /* HAVE_LIBSSH2_H */ - -/**************************************************************************** - * SSH unique setup - ***************************************************************************/ -typedef enum { - SSH_NO_STATE = -1, /* Used for "nextState" so say there is none */ - SSH_STOP = 0, /* do nothing state, stops the state machine */ - - SSH_INIT, /* First state in SSH-CONNECT */ - SSH_S_STARTUP, /* Session startup */ - SSH_HOSTKEY, /* verify hostkey */ - SSH_AUTHLIST, - SSH_AUTH_PKEY_INIT, - SSH_AUTH_PKEY, - SSH_AUTH_PASS_INIT, - SSH_AUTH_PASS, - SSH_AUTH_AGENT_INIT, /* initialize then wait for connection to agent */ - SSH_AUTH_AGENT_LIST, /* ask for list then wait for entire list to come */ - SSH_AUTH_AGENT, /* attempt one key at a time */ - SSH_AUTH_HOST_INIT, - SSH_AUTH_HOST, - SSH_AUTH_KEY_INIT, - SSH_AUTH_KEY, - SSH_AUTH_DONE, - SSH_SFTP_INIT, - SSH_SFTP_REALPATH, /* Last state in SSH-CONNECT */ - - SSH_SFTP_QUOTE_INIT, /* First state in SFTP-DO */ - SSH_SFTP_POSTQUOTE_INIT, /* (Possibly) First state in SFTP-DONE */ - SSH_SFTP_QUOTE, - SSH_SFTP_NEXT_QUOTE, - SSH_SFTP_QUOTE_STAT, - SSH_SFTP_QUOTE_SETSTAT, - SSH_SFTP_QUOTE_SYMLINK, - SSH_SFTP_QUOTE_MKDIR, - SSH_SFTP_QUOTE_RENAME, - SSH_SFTP_QUOTE_RMDIR, - SSH_SFTP_QUOTE_UNLINK, - SSH_SFTP_QUOTE_STATVFS, - SSH_SFTP_GETINFO, - SSH_SFTP_FILETIME, - SSH_SFTP_TRANS_INIT, - SSH_SFTP_UPLOAD_INIT, - SSH_SFTP_CREATE_DIRS_INIT, - SSH_SFTP_CREATE_DIRS, - SSH_SFTP_CREATE_DIRS_MKDIR, - SSH_SFTP_READDIR_INIT, - SSH_SFTP_READDIR, - SSH_SFTP_READDIR_LINK, - SSH_SFTP_READDIR_BOTTOM, - SSH_SFTP_READDIR_DONE, - SSH_SFTP_DOWNLOAD_INIT, - SSH_SFTP_DOWNLOAD_STAT, /* Last state in SFTP-DO */ - SSH_SFTP_CLOSE, /* Last state in SFTP-DONE */ - SSH_SFTP_SHUTDOWN, /* First state in SFTP-DISCONNECT */ - SSH_SCP_TRANS_INIT, /* First state in SCP-DO */ - SSH_SCP_UPLOAD_INIT, - SSH_SCP_DOWNLOAD_INIT, - SSH_SCP_DONE, - SSH_SCP_SEND_EOF, - SSH_SCP_WAIT_EOF, - SSH_SCP_WAIT_CLOSE, - SSH_SCP_CHANNEL_FREE, /* Last state in SCP-DONE */ - SSH_SESSION_DISCONNECT, /* First state in SCP-DISCONNECT */ - SSH_SESSION_FREE, /* Last state in SCP/SFTP-DISCONNECT */ - SSH_QUIT, - SSH_LAST /* never used */ -} sshstate; - -/* this struct is used in the HandleData struct which is part of the - Curl_easy, which means this is used on a per-easy handle basis. - Everything that is strictly related to a connection is banned from this - struct. */ -struct SSHPROTO { - char *path; /* the path we operate on */ -}; - -/* ssh_conn is used for struct connection-oriented data in the connectdata - struct */ -struct ssh_conn { - const char *authlist; /* List of auth. methods, managed by libssh2 */ -#ifdef USE_LIBSSH2 - const char *passphrase; /* pass-phrase to use */ - char *rsa_pub; /* path name */ - char *rsa; /* path name */ - bool authed; /* the connection has been authenticated fine */ - sshstate state; /* always use ssh.c:state() to change state! */ - sshstate nextstate; /* the state to goto after stopping */ - CURLcode actualcode; /* the actual error code */ - struct curl_slist *quote_item; /* for the quote option */ - char *quote_path1; /* two generic pointers for the QUOTE stuff */ - char *quote_path2; - LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */ - bool acceptfail; /* used by the SFTP_QUOTE (continue if - quote command fails) */ - char *homedir; /* when doing SFTP we figure out home dir in the - connect phase */ - - /* Here's a set of struct members used by the SFTP_READDIR state */ - LIBSSH2_SFTP_ATTRIBUTES readdir_attrs; - char *readdir_filename; - char *readdir_longentry; - int readdir_len, readdir_totalLen, readdir_currLen; - char *readdir_line; - char *readdir_linkPath; - /* end of READDIR stuff */ - - int secondCreateDirs; /* counter use by the code to see if the - second attempt has been made to change - to/create a directory */ - char *slash_pos; /* used by the SFTP_CREATE_DIRS state */ - LIBSSH2_SESSION *ssh_session; /* Secure Shell session */ - LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */ - LIBSSH2_SFTP *sftp_session; /* SFTP handle */ - LIBSSH2_SFTP_HANDLE *sftp_handle; - int orig_waitfor; /* default READ/WRITE bits wait for */ - -#ifdef HAVE_LIBSSH2_AGENT_API - LIBSSH2_AGENT *ssh_agent; /* proxy to ssh-agent/pageant */ - struct libssh2_agent_publickey *sshagent_identity, - *sshagent_prev_identity; -#endif - - /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h - header */ -#ifdef HAVE_LIBSSH2_KNOWNHOST_API - LIBSSH2_KNOWNHOSTS *kh; -#endif -#endif /* USE_LIBSSH2 */ -}; - -#ifdef USE_LIBSSH2 - -/* Feature detection based on version numbers to better work with - non-configure platforms */ - -#if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000) -# error "SCP/SFTP protocols require libssh2 0.16 or later" -#endif - -#if LIBSSH2_VERSION_NUM >= 0x010000 -#define HAVE_LIBSSH2_SFTP_SEEK64 1 -#endif - -#if LIBSSH2_VERSION_NUM >= 0x010100 -#define HAVE_LIBSSH2_VERSION 1 -#endif - -#if LIBSSH2_VERSION_NUM >= 0x010205 -#define HAVE_LIBSSH2_INIT 1 -#define HAVE_LIBSSH2_EXIT 1 -#endif - -#if LIBSSH2_VERSION_NUM >= 0x010206 -#define HAVE_LIBSSH2_KNOWNHOST_CHECKP 1 -#define HAVE_LIBSSH2_SCP_SEND64 1 -#endif - -#if LIBSSH2_VERSION_NUM >= 0x010208 -#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1 -#endif - -extern const struct Curl_handler Curl_handler_scp; -extern const struct Curl_handler Curl_handler_sftp; - -#endif /* USE_LIBSSH2 */ - -#endif /* HEADER_CURL_SSH_H */ diff --git a/dep/cpr/opt/curl/lib/strcase.c b/dep/cpr/opt/curl/lib/strcase.c deleted file mode 100644 index 24bcca93270..00000000000 --- a/dep/cpr/opt/curl/lib/strcase.c +++ /dev/null @@ -1,177 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "strcase.h" - -/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because - its behavior is altered by the current locale. */ -char Curl_raw_toupper(char in) -{ -#if !defined(CURL_DOES_CONVERSIONS) - if(in >= 'a' && in <= 'z') - return (char)('A' + in - 'a'); -#else - switch(in) { - case 'a': - return 'A'; - case 'b': - return 'B'; - case 'c': - return 'C'; - case 'd': - return 'D'; - case 'e': - return 'E'; - case 'f': - return 'F'; - case 'g': - return 'G'; - case 'h': - return 'H'; - case 'i': - return 'I'; - case 'j': - return 'J'; - case 'k': - return 'K'; - case 'l': - return 'L'; - case 'm': - return 'M'; - case 'n': - return 'N'; - case 'o': - return 'O'; - case 'p': - return 'P'; - case 'q': - return 'Q'; - case 'r': - return 'R'; - case 's': - return 'S'; - case 't': - return 'T'; - case 'u': - return 'U'; - case 'v': - return 'V'; - case 'w': - return 'W'; - case 'x': - return 'X'; - case 'y': - return 'Y'; - case 'z': - return 'Z'; - } -#endif - - return in; -} - -/* - * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is - * meant to be locale independent and only compare strings we know are safe - * for this. See - * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some - * further explanation to why this function is necessary. - * - * The function is capable of comparing a-z case insensitively even for - * non-ascii. - * - * @unittest: 1301 - */ - -int Curl_strcasecompare(const char *first, const char *second) -{ - while(*first && *second) { - if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) - /* get out of the loop as soon as they don't match */ - break; - first++; - second++; - } - /* we do the comparison here (possibly again), just to make sure that if the - loop above is skipped because one of the strings reached zero, we must not - return this as a successful match */ - return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); -} - -int Curl_safe_strcasecompare(const char *first, const char *second) -{ - if(first && second) - /* both pointers point to something then compare them */ - return Curl_strcasecompare(first, second); - - /* if both pointers are NULL then treat them as equal */ - return (NULL == first && NULL == second); -} - -/* - * @unittest: 1301 - */ -int Curl_strncasecompare(const char *first, const char *second, size_t max) -{ - while(*first && *second && max) { - if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { - break; - } - max--; - first++; - second++; - } - if(0 == max) - return 1; /* they are equal this far */ - - return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); -} - -/* Copy an upper case version of the string from src to dest. The - * strings may overlap. No more than n characters of the string are copied - * (including any NUL) and the destination string will NOT be - * NUL-terminated if that limit is reached. - */ -void Curl_strntoupper(char *dest, const char *src, size_t n) -{ - if(n < 1) - return; - - do { - *dest++ = Curl_raw_toupper(*src); - } while(*src++ && --n); -} - -/* --- public functions --- */ - -int curl_strequal(const char *first, const char *second) -{ - return Curl_strcasecompare(first, second); -} -int curl_strnequal(const char *first, const char *second, size_t max) -{ - return Curl_strncasecompare(first, second, max); -} diff --git a/dep/cpr/opt/curl/lib/strcase.h b/dep/cpr/opt/curl/lib/strcase.h deleted file mode 100644 index ea2abc8b600..00000000000 --- a/dep/cpr/opt/curl/lib/strcase.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef HEADER_CURL_STRCASE_H -#define HEADER_CURL_STRCASE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -/* - * Only "raw" case insensitive strings. This is meant to be locale independent - * and only compare strings we know are safe for this. - * - * The function is capable of comparing a-z case insensitively even for - * non-ascii. - */ - -#define strcasecompare(a,b) Curl_strcasecompare(a,b) -#define strncasecompare(a,b,c) Curl_strncasecompare(a,b,c) - -int Curl_strcasecompare(const char *first, const char *second); -int Curl_safe_strcasecompare(const char *first, const char *second); -int Curl_strncasecompare(const char *first, const char *second, size_t max); - -char Curl_raw_toupper(char in); - -/* checkprefix() is a shorter version of the above, used when the first - argument is zero-byte terminated */ -#define checkprefix(a,b) curl_strnequal(a,b,strlen(a)) - -void Curl_strntoupper(char *dest, const char *src, size_t n); -char Curl_raw_toupper(char in); - -#endif /* HEADER_CURL_STRCASE_H */ diff --git a/dep/cpr/opt/curl/lib/strdup.c b/dep/cpr/opt/curl/lib/strdup.c deleted file mode 100644 index 19cb044162e..00000000000 --- a/dep/cpr/opt/curl/lib/strdup.c +++ /dev/null @@ -1,100 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "strdup.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -#ifndef HAVE_STRDUP -char *curlx_strdup(const char *str) -{ - size_t len; - char *newstr; - - if(!str) - return (char *)NULL; - - len = strlen(str); - - if(len >= ((size_t)-1) / sizeof(char)) - return (char *)NULL; - - newstr = malloc((len + 1)*sizeof(char)); - if(!newstr) - return (char *)NULL; - - memcpy(newstr, str, (len + 1)*sizeof(char)); - - return newstr; - -} -#endif - -/*************************************************************************** - * - * Curl_memdup(source, length) - * - * Copies the 'source' data to a newly allocated buffer (that is - * returned). Copies 'length' bytes. - * - * Returns the new pointer or NULL on failure. - * - ***************************************************************************/ -void *Curl_memdup(const void *src, size_t length) -{ - void *buffer = malloc(length); - if(!buffer) - return NULL; /* fail */ - - memcpy(buffer, src, length); - - return buffer; -} - -/*************************************************************************** - * - * Curl_saferealloc(ptr, size) - * - * Does a normal realloc(), but will free the data pointer if the realloc - * fails. If 'size' is zero, it will free the data and return a failure. - * - * This convenience function is provided and used to help us avoid a common - * mistake pattern when we could pass in a zero, catch the NULL return and end - * up free'ing the memory twice. - * - * Returns the new pointer or NULL on failure. - * - ***************************************************************************/ -void *Curl_saferealloc(void *ptr, size_t size) -{ - void *datap = realloc(ptr, size); - if(size && !datap) - /* only free 'ptr' if size was non-zero */ - free(ptr); - return datap; -} diff --git a/dep/cpr/opt/curl/lib/strdup.h b/dep/cpr/opt/curl/lib/strdup.h deleted file mode 100644 index ae3d5d01153..00000000000 --- a/dep/cpr/opt/curl/lib/strdup.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef HEADER_CURL_STRDUP_H -#define HEADER_CURL_STRDUP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifndef HAVE_STRDUP -extern char *curlx_strdup(const char *str); -#endif -void *Curl_memdup(const void *src, size_t buffer_length); -void *Curl_saferealloc(void *ptr, size_t size); - -#endif /* HEADER_CURL_STRDUP_H */ diff --git a/dep/cpr/opt/curl/lib/strerror.c b/dep/cpr/opt/curl/lib/strerror.c deleted file mode 100644 index 83a96dda195..00000000000 --- a/dep/cpr/opt/curl/lib/strerror.c +++ /dev/null @@ -1,1103 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2004 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_STRERROR_R -# if (!defined(HAVE_POSIX_STRERROR_R) && \ - !defined(HAVE_GLIBC_STRERROR_R) && \ - !defined(HAVE_VXWORKS_STRERROR_R)) || \ - (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \ - (defined(HAVE_GLIBC_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \ - (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)) -# error "strerror_r MUST be either POSIX, glibc or vxworks-style" -# endif -#endif - -#include - -#ifdef USE_LIBIDN2 -#include -#endif - -#ifdef USE_WINDOWS_SSPI -#include "curl_sspi.h" -#endif - -#include "strerror.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#if defined(WIN32) || defined(_WIN32_WCE) -#define PRESERVE_WINDOWS_ERROR_CODE -#endif - -const char * -curl_easy_strerror(CURLcode error) -{ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch(error) { - case CURLE_OK: - return "No error"; - - case CURLE_UNSUPPORTED_PROTOCOL: - return "Unsupported protocol"; - - case CURLE_FAILED_INIT: - return "Failed initialization"; - - case CURLE_URL_MALFORMAT: - return "URL using bad/illegal format or missing URL"; - - case CURLE_NOT_BUILT_IN: - return "A requested feature, protocol or option was not found built-in in" - " this libcurl due to a build-time decision."; - - case CURLE_COULDNT_RESOLVE_PROXY: - return "Couldn't resolve proxy name"; - - case CURLE_COULDNT_RESOLVE_HOST: - return "Couldn't resolve host name"; - - case CURLE_COULDNT_CONNECT: - return "Couldn't connect to server"; - - case CURLE_WEIRD_SERVER_REPLY: - return "Weird server reply"; - - case CURLE_REMOTE_ACCESS_DENIED: - return "Access denied to remote resource"; - - case CURLE_FTP_ACCEPT_FAILED: - return "FTP: The server failed to connect to data port"; - - case CURLE_FTP_ACCEPT_TIMEOUT: - return "FTP: Accepting server connect has timed out"; - - case CURLE_FTP_PRET_FAILED: - return "FTP: The server did not accept the PRET command."; - - case CURLE_FTP_WEIRD_PASS_REPLY: - return "FTP: unknown PASS reply"; - - case CURLE_FTP_WEIRD_PASV_REPLY: - return "FTP: unknown PASV reply"; - - case CURLE_FTP_WEIRD_227_FORMAT: - return "FTP: unknown 227 response format"; - - case CURLE_FTP_CANT_GET_HOST: - return "FTP: can't figure out the host in the PASV response"; - - case CURLE_HTTP2: - return "Error in the HTTP2 framing layer"; - - case CURLE_FTP_COULDNT_SET_TYPE: - return "FTP: couldn't set file type"; - - case CURLE_PARTIAL_FILE: - return "Transferred a partial file"; - - case CURLE_FTP_COULDNT_RETR_FILE: - return "FTP: couldn't retrieve (RETR failed) the specified file"; - - case CURLE_QUOTE_ERROR: - return "Quote command returned error"; - - case CURLE_HTTP_RETURNED_ERROR: - return "HTTP response code said error"; - - case CURLE_WRITE_ERROR: - return "Failed writing received data to disk/application"; - - case CURLE_UPLOAD_FAILED: - return "Upload failed (at start/before it took off)"; - - case CURLE_READ_ERROR: - return "Failed to open/read local data from file/application"; - - case CURLE_OUT_OF_MEMORY: - return "Out of memory"; - - case CURLE_OPERATION_TIMEDOUT: - return "Timeout was reached"; - - case CURLE_FTP_PORT_FAILED: - return "FTP: command PORT failed"; - - case CURLE_FTP_COULDNT_USE_REST: - return "FTP: command REST failed"; - - case CURLE_RANGE_ERROR: - return "Requested range was not delivered by the server"; - - case CURLE_HTTP_POST_ERROR: - return "Internal problem setting up the POST"; - - case CURLE_SSL_CONNECT_ERROR: - return "SSL connect error"; - - case CURLE_BAD_DOWNLOAD_RESUME: - return "Couldn't resume download"; - - case CURLE_FILE_COULDNT_READ_FILE: - return "Couldn't read a file:// file"; - - case CURLE_LDAP_CANNOT_BIND: - return "LDAP: cannot bind"; - - case CURLE_LDAP_SEARCH_FAILED: - return "LDAP: search failed"; - - case CURLE_FUNCTION_NOT_FOUND: - return "A required function in the library was not found"; - - case CURLE_ABORTED_BY_CALLBACK: - return "Operation was aborted by an application callback"; - - case CURLE_BAD_FUNCTION_ARGUMENT: - return "A libcurl function was given a bad argument"; - - case CURLE_INTERFACE_FAILED: - return "Failed binding local connection end"; - - case CURLE_TOO_MANY_REDIRECTS : - return "Number of redirects hit maximum amount"; - - case CURLE_UNKNOWN_OPTION: - return "An unknown option was passed in to libcurl"; - - case CURLE_TELNET_OPTION_SYNTAX : - return "Malformed telnet option"; - - case CURLE_PEER_FAILED_VERIFICATION: - return "SSL peer certificate or SSH remote key was not OK"; - - case CURLE_GOT_NOTHING: - return "Server returned nothing (no headers, no data)"; - - case CURLE_SSL_ENGINE_NOTFOUND: - return "SSL crypto engine not found"; - - case CURLE_SSL_ENGINE_SETFAILED: - return "Can not set SSL crypto engine as default"; - - case CURLE_SSL_ENGINE_INITFAILED: - return "Failed to initialise SSL crypto engine"; - - case CURLE_SEND_ERROR: - return "Failed sending data to the peer"; - - case CURLE_RECV_ERROR: - return "Failure when receiving data from the peer"; - - case CURLE_SSL_CERTPROBLEM: - return "Problem with the local SSL certificate"; - - case CURLE_SSL_CIPHER: - return "Couldn't use specified SSL cipher"; - - case CURLE_SSL_CACERT: - return "Peer certificate cannot be authenticated with given CA " - "certificates"; - - case CURLE_SSL_CACERT_BADFILE: - return "Problem with the SSL CA cert (path? access rights?)"; - - case CURLE_BAD_CONTENT_ENCODING: - return "Unrecognized or bad HTTP Content or Transfer-Encoding"; - - case CURLE_LDAP_INVALID_URL: - return "Invalid LDAP URL"; - - case CURLE_FILESIZE_EXCEEDED: - return "Maximum file size exceeded"; - - case CURLE_USE_SSL_FAILED: - return "Requested SSL level failed"; - - case CURLE_SSL_SHUTDOWN_FAILED: - return "Failed to shut down the SSL connection"; - - case CURLE_SSL_CRL_BADFILE: - return "Failed to load CRL file (path? access rights?, format?)"; - - case CURLE_SSL_ISSUER_ERROR: - return "Issuer check against peer certificate failed"; - - case CURLE_SEND_FAIL_REWIND: - return "Send failed since rewinding of the data stream failed"; - - case CURLE_LOGIN_DENIED: - return "Login denied"; - - case CURLE_TFTP_NOTFOUND: - return "TFTP: File Not Found"; - - case CURLE_TFTP_PERM: - return "TFTP: Access Violation"; - - case CURLE_REMOTE_DISK_FULL: - return "Disk full or allocation exceeded"; - - case CURLE_TFTP_ILLEGAL: - return "TFTP: Illegal operation"; - - case CURLE_TFTP_UNKNOWNID: - return "TFTP: Unknown transfer ID"; - - case CURLE_REMOTE_FILE_EXISTS: - return "Remote file already exists"; - - case CURLE_TFTP_NOSUCHUSER: - return "TFTP: No such user"; - - case CURLE_CONV_FAILED: - return "Conversion failed"; - - case CURLE_CONV_REQD: - return "Caller must register CURLOPT_CONV_ callback options"; - - case CURLE_REMOTE_FILE_NOT_FOUND: - return "Remote file not found"; - - case CURLE_SSH: - return "Error in the SSH layer"; - - case CURLE_AGAIN: - return "Socket not ready for send/recv"; - - case CURLE_RTSP_CSEQ_ERROR: - return "RTSP CSeq mismatch or invalid CSeq"; - - case CURLE_RTSP_SESSION_ERROR: - return "RTSP session error"; - - case CURLE_FTP_BAD_FILE_LIST: - return "Unable to parse FTP file list"; - - case CURLE_CHUNK_FAILED: - return "Chunk callback failed"; - - case CURLE_NO_CONNECTION_AVAILABLE: - return "The max connection limit is reached"; - - case CURLE_SSL_PINNEDPUBKEYNOTMATCH: - return "SSL public key does not match pinned public key"; - - case CURLE_SSL_INVALIDCERTSTATUS: - return "SSL server certificate status verification FAILED"; - - case CURLE_HTTP2_STREAM: - return "Stream error in the HTTP/2 framing layer"; - - /* error codes not used by current libcurl */ - case CURLE_OBSOLETE20: - case CURLE_OBSOLETE24: - case CURLE_OBSOLETE29: - case CURLE_OBSOLETE32: - case CURLE_OBSOLETE40: - case CURLE_OBSOLETE44: - case CURLE_OBSOLETE46: - case CURLE_OBSOLETE50: - case CURLE_OBSOLETE57: - case CURL_LAST: - break; - } - /* - * By using a switch, gcc -Wall will complain about enum values - * which do not appear, helping keep this function up-to-date. - * By using gcc -Wall -Werror, you can't forget. - * - * A table would not have the same benefit. Most compilers will - * generate code very similar to a table in any case, so there - * is little performance gain from a table. And something is broken - * for the user's application, anyways, so does it matter how fast - * it _doesn't_ work? - * - * The line number for the error will be near this comment, which - * is why it is here, and not at the start of the switch. - */ - return "Unknown error"; -#else - if(!error) - return "No error"; - else - return "Error"; -#endif -} - -const char * -curl_multi_strerror(CURLMcode error) -{ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch(error) { - case CURLM_CALL_MULTI_PERFORM: - return "Please call curl_multi_perform() soon"; - - case CURLM_OK: - return "No error"; - - case CURLM_BAD_HANDLE: - return "Invalid multi handle"; - - case CURLM_BAD_EASY_HANDLE: - return "Invalid easy handle"; - - case CURLM_OUT_OF_MEMORY: - return "Out of memory"; - - case CURLM_INTERNAL_ERROR: - return "Internal error"; - - case CURLM_BAD_SOCKET: - return "Invalid socket argument"; - - case CURLM_UNKNOWN_OPTION: - return "Unknown option"; - - case CURLM_ADDED_ALREADY: - return "The easy handle is already added to a multi handle"; - - case CURLM_LAST: - break; - } - - return "Unknown error"; -#else - if(error == CURLM_OK) - return "No error"; - else - return "Error"; -#endif -} - -const char * -curl_share_strerror(CURLSHcode error) -{ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch(error) { - case CURLSHE_OK: - return "No error"; - - case CURLSHE_BAD_OPTION: - return "Unknown share option"; - - case CURLSHE_IN_USE: - return "Share currently in use"; - - case CURLSHE_INVALID: - return "Invalid share handle"; - - case CURLSHE_NOMEM: - return "Out of memory"; - - case CURLSHE_NOT_BUILT_IN: - return "Feature not enabled in this library"; - - case CURLSHE_LAST: - break; - } - - return "CURLSHcode unknown"; -#else - if(error == CURLSHE_OK) - return "No error"; - else - return "Error"; -#endif -} - -#ifdef USE_WINSOCK - -/* This function handles most / all (?) Winsock errors curl is able to produce. - */ -static const char * -get_winsock_error (int err, char *buf, size_t len) -{ -#ifdef PRESERVE_WINDOWS_ERROR_CODE - DWORD old_win_err = GetLastError(); -#endif - int old_errno = errno; - const char *p; - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch(err) { - case WSAEINTR: - p = "Call interrupted"; - break; - case WSAEBADF: - p = "Bad file"; - break; - case WSAEACCES: - p = "Bad access"; - break; - case WSAEFAULT: - p = "Bad argument"; - break; - case WSAEINVAL: - p = "Invalid arguments"; - break; - case WSAEMFILE: - p = "Out of file descriptors"; - break; - case WSAEWOULDBLOCK: - p = "Call would block"; - break; - case WSAEINPROGRESS: - case WSAEALREADY: - p = "Blocking call in progress"; - break; - case WSAENOTSOCK: - p = "Descriptor is not a socket"; - break; - case WSAEDESTADDRREQ: - p = "Need destination address"; - break; - case WSAEMSGSIZE: - p = "Bad message size"; - break; - case WSAEPROTOTYPE: - p = "Bad protocol"; - break; - case WSAENOPROTOOPT: - p = "Protocol option is unsupported"; - break; - case WSAEPROTONOSUPPORT: - p = "Protocol is unsupported"; - break; - case WSAESOCKTNOSUPPORT: - p = "Socket is unsupported"; - break; - case WSAEOPNOTSUPP: - p = "Operation not supported"; - break; - case WSAEAFNOSUPPORT: - p = "Address family not supported"; - break; - case WSAEPFNOSUPPORT: - p = "Protocol family not supported"; - break; - case WSAEADDRINUSE: - p = "Address already in use"; - break; - case WSAEADDRNOTAVAIL: - p = "Address not available"; - break; - case WSAENETDOWN: - p = "Network down"; - break; - case WSAENETUNREACH: - p = "Network unreachable"; - break; - case WSAENETRESET: - p = "Network has been reset"; - break; - case WSAECONNABORTED: - p = "Connection was aborted"; - break; - case WSAECONNRESET: - p = "Connection was reset"; - break; - case WSAENOBUFS: - p = "No buffer space"; - break; - case WSAEISCONN: - p = "Socket is already connected"; - break; - case WSAENOTCONN: - p = "Socket is not connected"; - break; - case WSAESHUTDOWN: - p = "Socket has been shut down"; - break; - case WSAETOOMANYREFS: - p = "Too many references"; - break; - case WSAETIMEDOUT: - p = "Timed out"; - break; - case WSAECONNREFUSED: - p = "Connection refused"; - break; - case WSAELOOP: - p = "Loop??"; - break; - case WSAENAMETOOLONG: - p = "Name too long"; - break; - case WSAEHOSTDOWN: - p = "Host down"; - break; - case WSAEHOSTUNREACH: - p = "Host unreachable"; - break; - case WSAENOTEMPTY: - p = "Not empty"; - break; - case WSAEPROCLIM: - p = "Process limit reached"; - break; - case WSAEUSERS: - p = "Too many users"; - break; - case WSAEDQUOT: - p = "Bad quota"; - break; - case WSAESTALE: - p = "Something is stale"; - break; - case WSAEREMOTE: - p = "Remote error"; - break; -#ifdef WSAEDISCON /* missing in SalfordC! */ - case WSAEDISCON: - p = "Disconnected"; - break; -#endif - /* Extended Winsock errors */ - case WSASYSNOTREADY: - p = "Winsock library is not ready"; - break; - case WSANOTINITIALISED: - p = "Winsock library not initialised"; - break; - case WSAVERNOTSUPPORTED: - p = "Winsock version not supported"; - break; - - /* getXbyY() errors (already handled in herrmsg): - * Authoritative Answer: Host not found */ - case WSAHOST_NOT_FOUND: - p = "Host not found"; - break; - - /* Non-Authoritative: Host not found, or SERVERFAIL */ - case WSATRY_AGAIN: - p = "Host not found, try again"; - break; - - /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ - case WSANO_RECOVERY: - p = "Unrecoverable error in call to nameserver"; - break; - - /* Valid name, no data record of requested type */ - case WSANO_DATA: - p = "No data record of requested type"; - break; - - default: - return NULL; - } -#else - if(!err) - return NULL; - else - p = "error"; -#endif - strncpy(buf, p, len); - buf [len-1] = '\0'; - - if(errno != old_errno) - errno = old_errno; - -#ifdef PRESERVE_WINDOWS_ERROR_CODE - if(old_win_err != GetLastError()) - SetLastError(old_win_err); -#endif - - return buf; -} -#endif /* USE_WINSOCK */ - -/* - * Our thread-safe and smart strerror() replacement. - * - * The 'err' argument passed in to this function MUST be a true errno number - * as reported on this system. We do no range checking on the number before - * we pass it to the "number-to-message" conversion function and there might - * be systems that don't do proper range checking in there themselves. - * - * We don't do range checking (on systems other than Windows) since there is - * no good reliable and portable way to do it. - */ -const char *Curl_strerror(struct connectdata *conn, int err) -{ -#ifdef PRESERVE_WINDOWS_ERROR_CODE - DWORD old_win_err = GetLastError(); -#endif - int old_errno = errno; - char *buf, *p; - size_t max; - - DEBUGASSERT(conn); - DEBUGASSERT(err >= 0); - - buf = conn->syserr_buf; - max = sizeof(conn->syserr_buf)-1; - *buf = '\0'; - -#ifdef USE_WINSOCK - -#ifdef _WIN32_WCE - { - wchar_t wbuf[256]; - wbuf[0] = L'\0'; - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, - LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL); - wcstombs(buf, wbuf, max); - } -#else - /* 'sys_nerr' is the maximum errno number, it is not widely portable */ - if(err >= 0 && err < sys_nerr) - strncpy(buf, strerror(err), max); - else { - if(!get_winsock_error(err, buf, max) && - !FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, - LANG_NEUTRAL, buf, (DWORD)max, NULL)) - snprintf(buf, max, "Unknown error %d (%#x)", err, err); - } -#endif - -#else /* not USE_WINSOCK coming up */ - -#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R) - /* - * The POSIX-style strerror_r() may set errno to ERANGE if insufficient - * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated - * message string, or EINVAL if 'errnum' is not a valid error number. - */ - if(0 != strerror_r(err, buf, max)) { - if('\0' == buf[0]) - snprintf(buf, max, "Unknown error %d", err); - } -#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) - /* - * The glibc-style strerror_r() only *might* use the buffer we pass to - * the function, but it always returns the error message as a pointer, - * so we must copy that string unconditionally (if non-NULL). - */ - { - char buffer[256]; - char *msg = strerror_r(err, buffer, sizeof(buffer)); - if(msg) - strncpy(buf, msg, max); - else - snprintf(buf, max, "Unknown error %d", err); - } -#elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R) - /* - * The vxworks-style strerror_r() does use the buffer we pass to the function. - * The buffer size should be at least NAME_MAX (256) - */ - { - char buffer[256]; - if(OK == strerror_r(err, buffer)) - strncpy(buf, buffer, max); - else - snprintf(buf, max, "Unknown error %d", err); - } -#else - { - char *msg = strerror(err); - if(msg) - strncpy(buf, msg, max); - else - snprintf(buf, max, "Unknown error %d", err); - } -#endif - -#endif /* end of ! USE_WINSOCK */ - - buf[max] = '\0'; /* make sure the string is zero terminated */ - - /* strip trailing '\r\n' or '\n'. */ - p = strrchr(buf, '\n'); - if(p && (p - buf) >= 2) - *p = '\0'; - p = strrchr(buf, '\r'); - if(p && (p - buf) >= 1) - *p = '\0'; - - if(errno != old_errno) - errno = old_errno; - -#ifdef PRESERVE_WINDOWS_ERROR_CODE - if(old_win_err != GetLastError()) - SetLastError(old_win_err); -#endif - - return buf; -} - -#ifdef USE_WINDOWS_SSPI -const char *Curl_sspi_strerror (struct connectdata *conn, int err) -{ -#ifdef PRESERVE_WINDOWS_ERROR_CODE - DWORD old_win_err = GetLastError(); -#endif - int old_errno = errno; - const char *txt; - char *outbuf; - size_t outmax; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - char txtbuf[80]; - char msgbuf[sizeof(conn->syserr_buf)]; - char *p, *str, *msg = NULL; - bool msg_formatted = FALSE; -#endif - - DEBUGASSERT(conn); - - outbuf = conn->syserr_buf; - outmax = sizeof(conn->syserr_buf)-1; - *outbuf = '\0'; - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - - switch(err) { - case SEC_E_OK: - txt = "No error"; - break; - case CRYPT_E_REVOKED: - txt = "CRYPT_E_REVOKED"; - break; - case SEC_E_ALGORITHM_MISMATCH: - txt = "SEC_E_ALGORITHM_MISMATCH"; - break; - case SEC_E_BAD_BINDINGS: - txt = "SEC_E_BAD_BINDINGS"; - break; - case SEC_E_BAD_PKGID: - txt = "SEC_E_BAD_PKGID"; - break; - case SEC_E_BUFFER_TOO_SMALL: - txt = "SEC_E_BUFFER_TOO_SMALL"; - break; - case SEC_E_CANNOT_INSTALL: - txt = "SEC_E_CANNOT_INSTALL"; - break; - case SEC_E_CANNOT_PACK: - txt = "SEC_E_CANNOT_PACK"; - break; - case SEC_E_CERT_EXPIRED: - txt = "SEC_E_CERT_EXPIRED"; - break; - case SEC_E_CERT_UNKNOWN: - txt = "SEC_E_CERT_UNKNOWN"; - break; - case SEC_E_CERT_WRONG_USAGE: - txt = "SEC_E_CERT_WRONG_USAGE"; - break; - case SEC_E_CONTEXT_EXPIRED: - txt = "SEC_E_CONTEXT_EXPIRED"; - break; - case SEC_E_CROSSREALM_DELEGATION_FAILURE: - txt = "SEC_E_CROSSREALM_DELEGATION_FAILURE"; - break; - case SEC_E_CRYPTO_SYSTEM_INVALID: - txt = "SEC_E_CRYPTO_SYSTEM_INVALID"; - break; - case SEC_E_DECRYPT_FAILURE: - txt = "SEC_E_DECRYPT_FAILURE"; - break; - case SEC_E_DELEGATION_POLICY: - txt = "SEC_E_DELEGATION_POLICY"; - break; - case SEC_E_DELEGATION_REQUIRED: - txt = "SEC_E_DELEGATION_REQUIRED"; - break; - case SEC_E_DOWNGRADE_DETECTED: - txt = "SEC_E_DOWNGRADE_DETECTED"; - break; - case SEC_E_ENCRYPT_FAILURE: - txt = "SEC_E_ENCRYPT_FAILURE"; - break; - case SEC_E_ILLEGAL_MESSAGE: - txt = "SEC_E_ILLEGAL_MESSAGE"; - break; - case SEC_E_INCOMPLETE_CREDENTIALS: - txt = "SEC_E_INCOMPLETE_CREDENTIALS"; - break; - case SEC_E_INCOMPLETE_MESSAGE: - txt = "SEC_E_INCOMPLETE_MESSAGE"; - break; - case SEC_E_INSUFFICIENT_MEMORY: - txt = "SEC_E_INSUFFICIENT_MEMORY"; - break; - case SEC_E_INTERNAL_ERROR: - txt = "SEC_E_INTERNAL_ERROR"; - break; - case SEC_E_INVALID_HANDLE: - txt = "SEC_E_INVALID_HANDLE"; - break; - case SEC_E_INVALID_PARAMETER: - txt = "SEC_E_INVALID_PARAMETER"; - break; - case SEC_E_INVALID_TOKEN: - txt = "SEC_E_INVALID_TOKEN"; - break; - case SEC_E_ISSUING_CA_UNTRUSTED: - txt = "SEC_E_ISSUING_CA_UNTRUSTED"; - break; - case SEC_E_ISSUING_CA_UNTRUSTED_KDC: - txt = "SEC_E_ISSUING_CA_UNTRUSTED_KDC"; - break; - case SEC_E_KDC_CERT_EXPIRED: - txt = "SEC_E_KDC_CERT_EXPIRED"; - break; - case SEC_E_KDC_CERT_REVOKED: - txt = "SEC_E_KDC_CERT_REVOKED"; - break; - case SEC_E_KDC_INVALID_REQUEST: - txt = "SEC_E_KDC_INVALID_REQUEST"; - break; - case SEC_E_KDC_UNABLE_TO_REFER: - txt = "SEC_E_KDC_UNABLE_TO_REFER"; - break; - case SEC_E_KDC_UNKNOWN_ETYPE: - txt = "SEC_E_KDC_UNKNOWN_ETYPE"; - break; - case SEC_E_LOGON_DENIED: - txt = "SEC_E_LOGON_DENIED"; - break; - case SEC_E_MAX_REFERRALS_EXCEEDED: - txt = "SEC_E_MAX_REFERRALS_EXCEEDED"; - break; - case SEC_E_MESSAGE_ALTERED: - txt = "SEC_E_MESSAGE_ALTERED"; - break; - case SEC_E_MULTIPLE_ACCOUNTS: - txt = "SEC_E_MULTIPLE_ACCOUNTS"; - break; - case SEC_E_MUST_BE_KDC: - txt = "SEC_E_MUST_BE_KDC"; - break; - case SEC_E_NOT_OWNER: - txt = "SEC_E_NOT_OWNER"; - break; - case SEC_E_NO_AUTHENTICATING_AUTHORITY: - txt = "SEC_E_NO_AUTHENTICATING_AUTHORITY"; - break; - case SEC_E_NO_CREDENTIALS: - txt = "SEC_E_NO_CREDENTIALS"; - break; - case SEC_E_NO_IMPERSONATION: - txt = "SEC_E_NO_IMPERSONATION"; - break; - case SEC_E_NO_IP_ADDRESSES: - txt = "SEC_E_NO_IP_ADDRESSES"; - break; - case SEC_E_NO_KERB_KEY: - txt = "SEC_E_NO_KERB_KEY"; - break; - case SEC_E_NO_PA_DATA: - txt = "SEC_E_NO_PA_DATA"; - break; - case SEC_E_NO_S4U_PROT_SUPPORT: - txt = "SEC_E_NO_S4U_PROT_SUPPORT"; - break; - case SEC_E_NO_TGT_REPLY: - txt = "SEC_E_NO_TGT_REPLY"; - break; - case SEC_E_OUT_OF_SEQUENCE: - txt = "SEC_E_OUT_OF_SEQUENCE"; - break; - case SEC_E_PKINIT_CLIENT_FAILURE: - txt = "SEC_E_PKINIT_CLIENT_FAILURE"; - break; - case SEC_E_PKINIT_NAME_MISMATCH: - txt = "SEC_E_PKINIT_NAME_MISMATCH"; - break; - case SEC_E_POLICY_NLTM_ONLY: - txt = "SEC_E_POLICY_NLTM_ONLY"; - break; - case SEC_E_QOP_NOT_SUPPORTED: - txt = "SEC_E_QOP_NOT_SUPPORTED"; - break; - case SEC_E_REVOCATION_OFFLINE_C: - txt = "SEC_E_REVOCATION_OFFLINE_C"; - break; - case SEC_E_REVOCATION_OFFLINE_KDC: - txt = "SEC_E_REVOCATION_OFFLINE_KDC"; - break; - case SEC_E_SECPKG_NOT_FOUND: - txt = "SEC_E_SECPKG_NOT_FOUND"; - break; - case SEC_E_SECURITY_QOS_FAILED: - txt = "SEC_E_SECURITY_QOS_FAILED"; - break; - case SEC_E_SHUTDOWN_IN_PROGRESS: - txt = "SEC_E_SHUTDOWN_IN_PROGRESS"; - break; - case SEC_E_SMARTCARD_CERT_EXPIRED: - txt = "SEC_E_SMARTCARD_CERT_EXPIRED"; - break; - case SEC_E_SMARTCARD_CERT_REVOKED: - txt = "SEC_E_SMARTCARD_CERT_REVOKED"; - break; - case SEC_E_SMARTCARD_LOGON_REQUIRED: - txt = "SEC_E_SMARTCARD_LOGON_REQUIRED"; - break; - case SEC_E_STRONG_CRYPTO_NOT_SUPPORTED: - txt = "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED"; - break; - case SEC_E_TARGET_UNKNOWN: - txt = "SEC_E_TARGET_UNKNOWN"; - break; - case SEC_E_TIME_SKEW: - txt = "SEC_E_TIME_SKEW"; - break; - case SEC_E_TOO_MANY_PRINCIPALS: - txt = "SEC_E_TOO_MANY_PRINCIPALS"; - break; - case SEC_E_UNFINISHED_CONTEXT_DELETED: - txt = "SEC_E_UNFINISHED_CONTEXT_DELETED"; - break; - case SEC_E_UNKNOWN_CREDENTIALS: - txt = "SEC_E_UNKNOWN_CREDENTIALS"; - break; - case SEC_E_UNSUPPORTED_FUNCTION: - txt = "SEC_E_UNSUPPORTED_FUNCTION"; - break; - case SEC_E_UNSUPPORTED_PREAUTH: - txt = "SEC_E_UNSUPPORTED_PREAUTH"; - break; - case SEC_E_UNTRUSTED_ROOT: - txt = "SEC_E_UNTRUSTED_ROOT"; - break; - case SEC_E_WRONG_CREDENTIAL_HANDLE: - txt = "SEC_E_WRONG_CREDENTIAL_HANDLE"; - break; - case SEC_E_WRONG_PRINCIPAL: - txt = "SEC_E_WRONG_PRINCIPAL"; - break; - case SEC_I_COMPLETE_AND_CONTINUE: - txt = "SEC_I_COMPLETE_AND_CONTINUE"; - break; - case SEC_I_COMPLETE_NEEDED: - txt = "SEC_I_COMPLETE_NEEDED"; - break; - case SEC_I_CONTEXT_EXPIRED: - txt = "SEC_I_CONTEXT_EXPIRED"; - break; - case SEC_I_CONTINUE_NEEDED: - txt = "SEC_I_CONTINUE_NEEDED"; - break; - case SEC_I_INCOMPLETE_CREDENTIALS: - txt = "SEC_I_INCOMPLETE_CREDENTIALS"; - break; - case SEC_I_LOCAL_LOGON: - txt = "SEC_I_LOCAL_LOGON"; - break; - case SEC_I_NO_LSA_CONTEXT: - txt = "SEC_I_NO_LSA_CONTEXT"; - break; - case SEC_I_RENEGOTIATE: - txt = "SEC_I_RENEGOTIATE"; - break; - case SEC_I_SIGNATURE_NEEDED: - txt = "SEC_I_SIGNATURE_NEEDED"; - break; - default: - txt = "Unknown error"; - } - - if(err == SEC_E_OK) - strncpy(outbuf, txt, outmax); - else if(err == SEC_E_ILLEGAL_MESSAGE) - snprintf(outbuf, outmax, - "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs " - "when a fatal SSL/TLS alert is received (e.g. handshake failed). " - "More detail may be available in the Windows System event log.", - err); - else { - str = txtbuf; - snprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err); - txtbuf[sizeof(txtbuf)-1] = '\0'; - -#ifdef _WIN32_WCE - { - wchar_t wbuf[256]; - wbuf[0] = L'\0'; - - if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, LANG_NEUTRAL, - wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) { - wcstombs(msgbuf, wbuf, sizeof(msgbuf)-1); - msg_formatted = TRUE; - } - } -#else - if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, LANG_NEUTRAL, - msgbuf, sizeof(msgbuf)-1, NULL)) { - msg_formatted = TRUE; - } -#endif - if(msg_formatted) { - msgbuf[sizeof(msgbuf)-1] = '\0'; - /* strip trailing '\r\n' or '\n' */ - p = strrchr(msgbuf, '\n'); - if(p && (p - msgbuf) >= 2) - *p = '\0'; - p = strrchr(msgbuf, '\r'); - if(p && (p - msgbuf) >= 1) - *p = '\0'; - msg = msgbuf; - } - if(msg) - snprintf(outbuf, outmax, "%s - %s", str, msg); - else - strncpy(outbuf, str, outmax); - } - -#else - - if(err == SEC_E_OK) - txt = "No error"; - else - txt = "Error"; - - strncpy(outbuf, txt, outmax); - -#endif - - outbuf[outmax] = '\0'; - - if(errno != old_errno) - errno = old_errno; - -#ifdef PRESERVE_WINDOWS_ERROR_CODE - if(old_win_err != GetLastError()) - SetLastError(old_win_err); -#endif - - return outbuf; -} -#endif /* USE_WINDOWS_SSPI */ diff --git a/dep/cpr/opt/curl/lib/strerror.h b/dep/cpr/opt/curl/lib/strerror.h deleted file mode 100644 index 627273eb267..00000000000 --- a/dep/cpr/opt/curl/lib/strerror.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HEADER_CURL_STRERROR_H -#define HEADER_CURL_STRERROR_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "urldata.h" - -const char *Curl_strerror (struct connectdata *conn, int err); - -#ifdef USE_LIBIDN2 -const char *Curl_idn_strerror (struct connectdata *conn, int err); -#endif - -#ifdef USE_WINDOWS_SSPI -const char *Curl_sspi_strerror (struct connectdata *conn, int err); -#endif - -#endif /* HEADER_CURL_STRERROR_H */ diff --git a/dep/cpr/opt/curl/lib/strtok.c b/dep/cpr/opt/curl/lib/strtok.c deleted file mode 100644 index 460eb87e51c..00000000000 --- a/dep/cpr/opt/curl/lib/strtok.c +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef HAVE_STRTOK_R -#include - -#include "strtok.h" - -char * -Curl_strtok_r(char *ptr, const char *sep, char **end) -{ - if(!ptr) - /* we got NULL input so then we get our last position instead */ - ptr = *end; - - /* pass all letters that are including in the separator string */ - while(*ptr && strchr(sep, *ptr)) - ++ptr; - - if(*ptr) { - /* so this is where the next piece of string starts */ - char *start = ptr; - - /* set the end pointer to the first byte after the start */ - *end = start + 1; - - /* scan through the string to find where it ends, it ends on a - null byte or a character that exists in the separator string */ - while(**end && !strchr(sep, **end)) - ++*end; - - if(**end) { - /* the end is not a null byte */ - **end = '\0'; /* zero terminate it! */ - ++*end; /* advance the last pointer to beyond the null byte */ - } - - return start; /* return the position where the string starts */ - } - - /* we ended up on a null byte, there are no more strings to find! */ - return NULL; -} - -#endif /* this was only compiled if strtok_r wasn't present */ diff --git a/dep/cpr/opt/curl/lib/strtok.h b/dep/cpr/opt/curl/lib/strtok.h deleted file mode 100644 index 90b831eb67d..00000000000 --- a/dep/cpr/opt/curl/lib/strtok.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef HEADER_CURL_STRTOK_H -#define HEADER_CURL_STRTOK_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" -#include - -#ifndef HAVE_STRTOK_R -char *Curl_strtok_r(char *s, const char *delim, char **last); -#define strtok_r Curl_strtok_r -#else -#include -#endif - -#endif /* HEADER_CURL_STRTOK_H */ diff --git a/dep/cpr/opt/curl/lib/strtoofft.c b/dep/cpr/opt/curl/lib/strtoofft.c deleted file mode 100644 index 807fc545499..00000000000 --- a/dep/cpr/opt/curl/lib/strtoofft.c +++ /dev/null @@ -1,241 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include -#include "curl_setup.h" - -#include "strtoofft.h" - -/* - * NOTE: - * - * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we - * could use in case strtoll() doesn't exist... See - * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html - */ - -#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) -# ifdef HAVE_STRTOLL -# define strtooff strtoll -# else -# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64) -# if defined(_SAL_VERSION) - _Check_return_ _CRTIMP __int64 __cdecl _strtoi64( - _In_z_ const char *_String, - _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix); -# else - _CRTIMP __int64 __cdecl _strtoi64(const char *_String, - char **_EndPtr, int _Radix); -# endif -# define strtooff _strtoi64 -# else -# define PRIVATE_STRTOOFF 1 -# endif -# endif -#else -# define strtooff strtol -#endif - -#ifdef PRIVATE_STRTOOFF - -/* Range tests can be used for alphanum decoding if characters are consecutive, - like in ASCII. Else an array is scanned. Determine this condition now. */ - -#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25 - -#define NO_RANGE_TEST - -static const char valchars[] = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -#endif - -static int get_char(char c, int base); - -/** - * Custom version of the strtooff function. This extracts a curl_off_t - * value from the given input string and returns it. - */ -static curl_off_t strtooff(const char *nptr, char **endptr, int base) -{ - char *end; - int is_negative = 0; - int overflow; - int i; - curl_off_t value = 0; - curl_off_t newval; - - /* Skip leading whitespace. */ - end = (char *)nptr; - while(ISSPACE(end[0])) { - end++; - } - - /* Handle the sign, if any. */ - if(end[0] == '-') { - is_negative = 1; - end++; - } - else if(end[0] == '+') { - end++; - } - else if(end[0] == '\0') { - /* We had nothing but perhaps some whitespace -- there was no number. */ - if(endptr) { - *endptr = end; - } - return 0; - } - - /* Handle special beginnings, if present and allowed. */ - if(end[0] == '0' && end[1] == 'x') { - if(base == 16 || base == 0) { - end += 2; - base = 16; - } - } - else if(end[0] == '0') { - if(base == 8 || base == 0) { - end++; - base = 8; - } - } - - /* Matching strtol, if the base is 0 and it doesn't look like - * the number is octal or hex, we assume it's base 10. - */ - if(base == 0) { - base = 10; - } - - /* Loop handling digits. */ - value = 0; - overflow = 0; - for(i = get_char(end[0], base); - i != -1; - end++, i = get_char(end[0], base)) { - newval = base * value + i; - if(newval < value) { - /* We've overflowed. */ - overflow = 1; - break; - } - else - value = newval; - } - - if(!overflow) { - if(is_negative) { - /* Fix the sign. */ - value *= -1; - } - } - else { - if(is_negative) - value = CURL_OFF_T_MIN; - else - value = CURL_OFF_T_MAX; - - errno = ERANGE; - } - - if(endptr) - *endptr = end; - - return value; -} - -/** - * Returns the value of c in the given base, or -1 if c cannot - * be interpreted properly in that base (i.e., is out of range, - * is a null, etc.). - * - * @param c the character to interpret according to base - * @param base the base in which to interpret c - * - * @return the value of c in base, or -1 if c isn't in range - */ -static int get_char(char c, int base) -{ -#ifndef NO_RANGE_TEST - int value = -1; - if(c <= '9' && c >= '0') { - value = c - '0'; - } - else if(c <= 'Z' && c >= 'A') { - value = c - 'A' + 10; - } - else if(c <= 'z' && c >= 'a') { - value = c - 'a' + 10; - } -#else - const char *cp; - int value; - - cp = memchr(valchars, c, 10 + 26 + 26); - - if(!cp) - return -1; - - value = cp - valchars; - - if(value >= 10 + 26) - value -= 26; /* Lowercase. */ -#endif - - if(value >= base) { - value = -1; - } - - return value; -} -#endif /* Only present if we need strtoll, but don't have it. */ - -/* - * Parse a *positive* up to 64 bit number written in ascii. - */ -CURLofft curlx_strtoofft(const char *str, char **endp, int base, - curl_off_t *num) -{ - char *end; - curl_off_t number; - errno = 0; - *num = 0; /* clear by default */ - while(str && *str && ISSPACE(*str)) - str++; - if('-' == *str) { - if(endp) - *endp = (char *)str; /* didn't actually move */ - return CURL_OFFT_INVAL; /* nothing parsed */ - } - number = strtooff(str, &end, base); - if(endp) - *endp = end; - if(errno == ERANGE) - /* overflow/underflow */ - return CURL_OFFT_FLOW; - else if(str == end) - /* nothing parsed */ - return CURL_OFFT_INVAL; - - *num = number; - return CURL_OFFT_OK; -} diff --git a/dep/cpr/opt/curl/lib/strtoofft.h b/dep/cpr/opt/curl/lib/strtoofft.h deleted file mode 100644 index 244411a8700..00000000000 --- a/dep/cpr/opt/curl/lib/strtoofft.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef HEADER_CURL_STRTOOFFT_H -#define HEADER_CURL_STRTOOFFT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -/* - * Determine which string to integral data type conversion function we use - * to implement string conversion to our curl_off_t integral data type. - * - * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use - * an underlying data type which might be 'long', 'int64_t', 'long long' or - * '__int64' and more remotely other data types. - * - * On systems where the size of curl_off_t is greater than the size of 'long' - * the conversion function to use is strtoll() if it is available, otherwise, - * we emulate its functionality with our own clone. - * - * On systems where the size of curl_off_t is smaller or equal than the size - * of 'long' the conversion function to use is strtol(). - */ - -#if (SIZEOF_CURL_OFF_T == 4) -# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF) -#else - /* assume CURL_SIZEOF_CURL_OFF_T == 8 */ -# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) -#endif -#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1)) - -typedef enum { - CURL_OFFT_OK, /* parsed fine */ - CURL_OFFT_FLOW, /* over or underflow */ - CURL_OFFT_INVAL /* nothing was parsed */ -} CURLofft; - -CURLofft curlx_strtoofft(const char *str, char **endp, int base, - curl_off_t *num); - -#endif /* HEADER_CURL_STRTOOFFT_H */ diff --git a/dep/cpr/opt/curl/lib/system_win32.c b/dep/cpr/opt/curl/lib/system_win32.c deleted file mode 100644 index cfbbf327976..00000000000 --- a/dep/cpr/opt/curl/lib/system_win32.c +++ /dev/null @@ -1,329 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2016 - 2017, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(WIN32) - -#include -#include "system_win32.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ - defined(USE_WINSOCK)) - - -#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH) -#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 -#endif - -#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32) -#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 -#endif - -/* We use our own typedef here since some headers might lack these */ -typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); - -/* See function definitions in winbase.h */ -#ifdef UNICODE -# ifdef _WIN32_WCE -# define LOADLIBARYEX L"LoadLibraryExW" -# else -# define LOADLIBARYEX "LoadLibraryExW" -# endif -#else -# define LOADLIBARYEX "LoadLibraryExA" -#endif - -#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ - -/* - * Curl_verify_windows_version() - * - * This is used to verify if we are running on a specific windows version. - * - * Parameters: - * - * majorVersion [in] - The major version number. - * minorVersion [in] - The minor version number. - * platform [in] - The optional platform identifier. - * condition [in] - The test condition used to specifier whether we are - * checking a version less then, equal to or greater than - * what is specified in the major and minor version - * numbers. - * - * Returns TRUE if matched; otherwise FALSE. - */ -bool Curl_verify_windows_version(const unsigned int majorVersion, - const unsigned int minorVersion, - const PlatformIdentifier platform, - const VersionCondition condition) -{ - bool matched = FALSE; - -#if defined(CURL_WINDOWS_APP) - /* We have no way to determine the Windows version from Windows apps, - so let's assume we're running on the target Windows version. */ - const WORD fullVersion = MAKEWORD(minorVersion, majorVersion); - const WORD targetVersion = (WORD)_WIN32_WINNT; - - switch(condition) { - case VERSION_LESS_THAN: - matched = targetVersion < fullVersion; - break; - - case VERSION_LESS_THAN_EQUAL: - matched = targetVersion <= fullVersion; - break; - - case VERSION_EQUAL: - matched = targetVersion == fullVersion; - break; - - case VERSION_GREATER_THAN_EQUAL: - matched = targetVersion >= fullVersion; - break; - - case VERSION_GREATER_THAN: - matched = targetVersion > fullVersion; - break; - } - - if(matched && (platform == PLATFORM_WINDOWS)) { - /* we're always running on PLATFORM_WINNT */ - matched = FALSE; - } -#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ - (_WIN32_WINNT < _WIN32_WINNT_WIN2K) - OSVERSIONINFO osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - - /* Find out Windows version */ - if(GetVersionEx(&osver)) { - /* Verify the Operating System version number */ - switch(condition) { - case VERSION_LESS_THAN: - if(osver.dwMajorVersion < majorVersion || - (osver.dwMajorVersion == majorVersion && - osver.dwMinorVersion < minorVersion)) - matched = TRUE; - break; - - case VERSION_LESS_THAN_EQUAL: - if(osver.dwMajorVersion <= majorVersion && - osver.dwMinorVersion <= minorVersion) - matched = TRUE; - break; - - case VERSION_EQUAL: - if(osver.dwMajorVersion == majorVersion && - osver.dwMinorVersion == minorVersion) - matched = TRUE; - break; - - case VERSION_GREATER_THAN_EQUAL: - if(osver.dwMajorVersion >= majorVersion && - osver.dwMinorVersion >= minorVersion) - matched = TRUE; - break; - - case VERSION_GREATER_THAN: - if(osver.dwMajorVersion > majorVersion || - (osver.dwMajorVersion == majorVersion && - osver.dwMinorVersion > minorVersion)) - matched = TRUE; - break; - } - - /* Verify the platform identifier (if necessary) */ - if(matched) { - switch(platform) { - case PLATFORM_WINDOWS: - if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) - matched = FALSE; - break; - - case PLATFORM_WINNT: - if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT) - matched = FALSE; - - default: /* like platform == PLATFORM_DONT_CARE */ - break; - } - } - } -#else - ULONGLONG cm = 0; - OSVERSIONINFOEX osver; - BYTE majorCondition; - BYTE minorCondition; - BYTE spMajorCondition; - BYTE spMinorCondition; - - switch(condition) { - case VERSION_LESS_THAN: - majorCondition = VER_LESS; - minorCondition = VER_LESS; - spMajorCondition = VER_LESS_EQUAL; - spMinorCondition = VER_LESS_EQUAL; - break; - - case VERSION_LESS_THAN_EQUAL: - majorCondition = VER_LESS_EQUAL; - minorCondition = VER_LESS_EQUAL; - spMajorCondition = VER_LESS_EQUAL; - spMinorCondition = VER_LESS_EQUAL; - break; - - case VERSION_EQUAL: - majorCondition = VER_EQUAL; - minorCondition = VER_EQUAL; - spMajorCondition = VER_GREATER_EQUAL; - spMinorCondition = VER_GREATER_EQUAL; - break; - - case VERSION_GREATER_THAN_EQUAL: - majorCondition = VER_GREATER_EQUAL; - minorCondition = VER_GREATER_EQUAL; - spMajorCondition = VER_GREATER_EQUAL; - spMinorCondition = VER_GREATER_EQUAL; - break; - - case VERSION_GREATER_THAN: - majorCondition = VER_GREATER; - minorCondition = VER_GREATER; - spMajorCondition = VER_GREATER_EQUAL; - spMinorCondition = VER_GREATER_EQUAL; - break; - - default: - return FALSE; - } - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - osver.dwMajorVersion = majorVersion; - osver.dwMinorVersion = minorVersion; - if(platform == PLATFORM_WINDOWS) - osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; - else if(platform == PLATFORM_WINNT) - osver.dwPlatformId = VER_PLATFORM_WIN32_NT; - - cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition); - cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition); - if(platform != PLATFORM_DONT_CARE) - cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); - - if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), - cm)) - matched = TRUE; -#endif - - return matched; -} - -#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ - defined(USE_WINSOCK)) - -/* - * Curl_load_library() - * - * This is used to dynamically load DLLs using the most secure method available - * for the version of Windows that we are running on. - * - * Parameters: - * - * filename [in] - The filename or full path of the DLL to load. If only the - * filename is passed then the DLL will be loaded from the - * Windows system directory. - * - * Returns the handle of the module on success; otherwise NULL. - */ -HMODULE Curl_load_library(LPCTSTR filename) -{ - HMODULE hModule = NULL; - LOADLIBRARYEX_FN pLoadLibraryEx = NULL; - - /* Get a handle to kernel32 so we can access it's functions at runtime */ - HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32")); - if(!hKernel32) - return NULL; - - /* Attempt to find LoadLibraryEx() which is only available on Windows 2000 - and above */ - pLoadLibraryEx = (LOADLIBRARYEX_FN) GetProcAddress(hKernel32, LOADLIBARYEX); - - /* Detect if there's already a path in the filename and load the library if - there is. Note: Both back slashes and forward slashes have been supported - since the earlier days of DOS at an API level although they are not - supported by command prompt */ - if(_tcspbrk(filename, TEXT("\\/"))) { - /** !checksrc! disable BANNEDFUNC 1 **/ - hModule = pLoadLibraryEx ? - pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : - LoadLibrary(filename); - } - /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only - supported on Windows Vista, Windows Server 2008, Windows 7 and Windows - Server 2008 R2 with this patch or natively on Windows 8 and above */ - else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) { - /* Load the DLL from the Windows system directory */ - hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - } - else { - /* Attempt to get the Windows system path */ - UINT systemdirlen = GetSystemDirectory(NULL, 0); - if(systemdirlen) { - /* Allocate space for the full DLL path (Room for the null terminator - is included in systemdirlen) */ - size_t filenamelen = _tcslen(filename); - TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen)); - if(path && GetSystemDirectory(path, systemdirlen)) { - /* Calculate the full DLL path */ - _tcscpy(path + _tcslen(path), TEXT("\\")); - _tcscpy(path + _tcslen(path), filename); - - /* Load the DLL from the Windows system directory */ - /** !checksrc! disable BANNEDFUNC 1 **/ - hModule = pLoadLibraryEx ? - pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : - LoadLibrary(path); - - } - free(path); - } - } - - return hModule; -} - -#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ - -#endif /* WIN32 */ diff --git a/dep/cpr/opt/curl/lib/system_win32.h b/dep/cpr/opt/curl/lib/system_win32.h deleted file mode 100644 index 1e772856b23..00000000000 --- a/dep/cpr/opt/curl/lib/system_win32.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef HEADER_CURL_SYSTEM_WIN32_H -#define HEADER_CURL_SYSTEM_WIN32_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2016, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(WIN32) - -/* Version condition */ -typedef enum { - VERSION_LESS_THAN, - VERSION_LESS_THAN_EQUAL, - VERSION_EQUAL, - VERSION_GREATER_THAN_EQUAL, - VERSION_GREATER_THAN -} VersionCondition; - -/* Platform identifier */ -typedef enum { - PLATFORM_DONT_CARE, - PLATFORM_WINDOWS, - PLATFORM_WINNT -} PlatformIdentifier; - -/* This is used to verify if we are running on a specific windows version */ -bool Curl_verify_windows_version(const unsigned int majorVersion, - const unsigned int minorVersion, - const PlatformIdentifier platform, - const VersionCondition condition); - -#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ - defined(USE_WINSOCK)) - -/* This is used to dynamically load DLLs */ -HMODULE Curl_load_library(LPCTSTR filename); - -#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ - -#endif /* WIN32 */ - -#endif /* HEADER_CURL_SYSTEM_WIN32_H */ diff --git a/dep/cpr/opt/curl/lib/telnet.c b/dep/cpr/opt/curl/lib/telnet.c deleted file mode 100644 index a7bed3da1f0..00000000000 --- a/dep/cpr/opt/curl/lib/telnet.c +++ /dev/null @@ -1,1700 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_TELNET - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "telnet.h" -#include "connect.h" -#include "progress.h" -#include "system_win32.h" - -#define TELOPTS -#define TELCMDS - -#include "arpa_telnet.h" -#include "select.h" -#include "strcase.h" -#include "warnless.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#define SUBBUFSIZE 512 - -#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer -#define CURL_SB_TERM(x) \ - do { \ - x->subend = x->subpointer; \ - CURL_SB_CLEAR(x); \ - } WHILE_FALSE -#define CURL_SB_ACCUM(x,c) \ - do { \ - if(x->subpointer < (x->subbuffer + sizeof x->subbuffer)) \ - *x->subpointer++ = (c); \ - } WHILE_FALSE - -#define CURL_SB_GET(x) ((*x->subpointer++)&0xff) -#define CURL_SB_LEN(x) (x->subend - x->subpointer) - -/* For posterity: -#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff) -#define CURL_SB_EOF(x) (x->subpointer >= x->subend) */ - -#ifdef CURL_DISABLE_VERBOSE_STRINGS -#define printoption(a,b,c,d) Curl_nop_stmt -#endif - -#ifdef USE_WINSOCK -typedef FARPROC WSOCK2_FUNC; -static CURLcode check_wsock2(struct Curl_easy *data); -#endif - -static -CURLcode telrcv(struct connectdata *, - const unsigned char *inbuf, /* Data received from socket */ - ssize_t count); /* Number of bytes received */ - -#ifndef CURL_DISABLE_VERBOSE_STRINGS -static void printoption(struct Curl_easy *data, - const char *direction, - int cmd, int option); -#endif - -static void negotiate(struct connectdata *); -static void send_negotiation(struct connectdata *, int cmd, int option); -static void set_local_option(struct connectdata *, int cmd, int option); -static void set_remote_option(struct connectdata *, int cmd, int option); - -static void printsub(struct Curl_easy *data, - int direction, unsigned char *pointer, - size_t length); -static void suboption(struct connectdata *); -static void sendsuboption(struct connectdata *conn, int option); - -static CURLcode telnet_do(struct connectdata *conn, bool *done); -static CURLcode telnet_done(struct connectdata *conn, - CURLcode, bool premature); -static CURLcode send_telnet_data(struct connectdata *conn, - char *buffer, ssize_t nread); - -/* For negotiation compliant to RFC 1143 */ -#define CURL_NO 0 -#define CURL_YES 1 -#define CURL_WANTYES 2 -#define CURL_WANTNO 3 - -#define CURL_EMPTY 0 -#define CURL_OPPOSITE 1 - -/* - * Telnet receiver states for fsm - */ -typedef enum -{ - CURL_TS_DATA = 0, - CURL_TS_IAC, - CURL_TS_WILL, - CURL_TS_WONT, - CURL_TS_DO, - CURL_TS_DONT, - CURL_TS_CR, - CURL_TS_SB, /* sub-option collection */ - CURL_TS_SE /* looking for sub-option end */ -} TelnetReceive; - -struct TELNET { - int please_negotiate; - int already_negotiated; - int us[256]; - int usq[256]; - int us_preferred[256]; - int him[256]; - int himq[256]; - int him_preferred[256]; - int subnegotiation[256]; - char subopt_ttype[32]; /* Set with suboption TTYPE */ - char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */ - unsigned short subopt_wsx; /* Set with suboption NAWS */ - unsigned short subopt_wsy; /* Set with suboption NAWS */ - struct curl_slist *telnet_vars; /* Environment variables */ - - /* suboptions */ - unsigned char subbuffer[SUBBUFSIZE]; - unsigned char *subpointer, *subend; /* buffer for sub-options */ - - TelnetReceive telrcv_state; -}; - - -/* - * TELNET protocol handler. - */ - -const struct Curl_handler Curl_handler_telnet = { - "TELNET", /* scheme */ - ZERO_NULL, /* setup_connection */ - telnet_do, /* do_it */ - telnet_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_TELNET, /* defport */ - CURLPROTO_TELNET, /* protocol */ - PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ -}; - - -#ifdef USE_WINSOCK -static CURLcode -check_wsock2(struct Curl_easy *data) -{ - int err; - WORD wVersionRequested; - WSADATA wsaData; - - DEBUGASSERT(data); - - /* telnet requires at least WinSock 2.0 so ask for it. */ - wVersionRequested = MAKEWORD(2, 0); - - err = WSAStartup(wVersionRequested, &wsaData); - - /* We must've called this once already, so this call */ - /* should always succeed. But, just in case... */ - if(err != 0) { - failf(data,"WSAStartup failed (%d)",err); - return CURLE_FAILED_INIT; - } - - /* We have to have a WSACleanup call for every successful */ - /* WSAStartup call. */ - WSACleanup(); - - /* Check that our version is supported */ - if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || - HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) { - /* Our version isn't supported */ - failf(data, "insufficient winsock version to support " - "telnet"); - return CURLE_FAILED_INIT; - } - - /* Our version is supported */ - return CURLE_OK; -} -#endif - -static -CURLcode init_telnet(struct connectdata *conn) -{ - struct TELNET *tn; - - tn = calloc(1, sizeof(struct TELNET)); - if(!tn) - return CURLE_OUT_OF_MEMORY; - - conn->data->req.protop = tn; /* make us known */ - - tn->telrcv_state = CURL_TS_DATA; - - /* Init suboptions */ - CURL_SB_CLEAR(tn); - - /* Set the options we want by default */ - tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES; - tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES; - - /* To be compliant with previous releases of libcurl - we enable this option by default. This behaviour - can be changed thanks to the "BINARY" option in - CURLOPT_TELNETOPTIONS - */ - tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; - tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; - - /* We must allow the server to echo what we sent - but it is not necessary to request the server - to do so (it might forces the server to close - the connection). Hence, we ignore ECHO in the - negotiate function - */ - tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES; - - /* Set the subnegotiation fields to send information - just after negotiation passed (do/will) - - Default values are (0,0) initialized by calloc. - According to the RFC1013 it is valid: - A value equal to zero is acceptable for the width (or height), - and means that no character width (or height) is being sent. - In this case, the width (or height) that will be assumed by the - Telnet server is operating system specific (it will probably be - based upon the terminal type information that may have been sent - using the TERMINAL TYPE Telnet option). */ - tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES; - return CURLE_OK; -} - -static void negotiate(struct connectdata *conn) -{ - int i; - struct TELNET *tn = (struct TELNET *) conn->data->req.protop; - - for(i = 0; i < CURL_NTELOPTS; i++) { - if(i == CURL_TELOPT_ECHO) - continue; - - if(tn->us_preferred[i] == CURL_YES) - set_local_option(conn, i, CURL_YES); - - if(tn->him_preferred[i] == CURL_YES) - set_remote_option(conn, i, CURL_YES); - } -} - -#ifndef CURL_DISABLE_VERBOSE_STRINGS -static void printoption(struct Curl_easy *data, - const char *direction, int cmd, int option) -{ - const char *fmt; - const char *opt; - - if(data->set.verbose) { - if(cmd == CURL_IAC) { - if(CURL_TELCMD_OK(option)) - infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option)); - else - infof(data, "%s IAC %d\n", direction, option); - } - else { - fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" : - (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0; - if(fmt) { - if(CURL_TELOPT_OK(option)) - opt = CURL_TELOPT(option); - else if(option == CURL_TELOPT_EXOPL) - opt = "EXOPL"; - else - opt = NULL; - - if(opt) - infof(data, "%s %s %s\n", direction, fmt, opt); - else - infof(data, "%s %s %d\n", direction, fmt, option); - } - else - infof(data, "%s %d %d\n", direction, cmd, option); - } - } -} -#endif - -static void send_negotiation(struct connectdata *conn, int cmd, int option) -{ - unsigned char buf[3]; - ssize_t bytes_written; - int err; - struct Curl_easy *data = conn->data; - - buf[0] = CURL_IAC; - buf[1] = (unsigned char)cmd; - buf[2] = (unsigned char)option; - - bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3); - if(bytes_written < 0) { - err = SOCKERRNO; - failf(data,"Sending data failed (%d)",err); - } - - printoption(conn->data, "SENT", cmd, option); -} - -static -void set_remote_option(struct connectdata *conn, int option, int newstate) -{ - struct TELNET *tn = (struct TELNET *)conn->data->req.protop; - if(newstate == CURL_YES) { - switch(tn->him[option]) { - case CURL_NO: - tn->him[option] = CURL_WANTYES; - send_negotiation(conn, CURL_DO, option); - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->himq[option]) { - case CURL_EMPTY: - /* Already negotiating for CURL_YES, queue the request */ - tn->himq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - /* Error: already queued an enable request */ - break; - } - break; - - case CURL_WANTYES: - switch(tn->himq[option]) { - case CURL_EMPTY: - /* Error: already negotiating for enable */ - break; - case CURL_OPPOSITE: - tn->himq[option] = CURL_EMPTY; - break; - } - break; - } - } - else { /* NO */ - switch(tn->him[option]) { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->him[option] = CURL_WANTNO; - send_negotiation(conn, CURL_DONT, option); - break; - - case CURL_WANTNO: - switch(tn->himq[option]) { - case CURL_EMPTY: - /* Already negotiating for NO */ - break; - case CURL_OPPOSITE: - tn->himq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->himq[option]) { - case CURL_EMPTY: - tn->himq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - break; - } - break; - } - } -} - -static -void rec_will(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->req.protop; - switch(tn->him[option]) { - case CURL_NO: - if(tn->him_preferred[option] == CURL_YES) { - tn->him[option] = CURL_YES; - send_negotiation(conn, CURL_DO, option); - } - else - send_negotiation(conn, CURL_DONT, option); - - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->himq[option]) { - case CURL_EMPTY: - /* Error: DONT answered by WILL */ - tn->him[option] = CURL_NO; - break; - case CURL_OPPOSITE: - /* Error: DONT answered by WILL */ - tn->him[option] = CURL_YES; - tn->himq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->himq[option]) { - case CURL_EMPTY: - tn->him[option] = CURL_YES; - break; - case CURL_OPPOSITE: - tn->him[option] = CURL_WANTNO; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_DONT, option); - break; - } - break; - } -} - -static -void rec_wont(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->req.protop; - switch(tn->him[option]) { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->him[option] = CURL_NO; - send_negotiation(conn, CURL_DONT, option); - break; - - case CURL_WANTNO: - switch(tn->himq[option]) { - case CURL_EMPTY: - tn->him[option] = CURL_NO; - break; - - case CURL_OPPOSITE: - tn->him[option] = CURL_WANTYES; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_DO, option); - break; - } - break; - - case CURL_WANTYES: - switch(tn->himq[option]) { - case CURL_EMPTY: - tn->him[option] = CURL_NO; - break; - case CURL_OPPOSITE: - tn->him[option] = CURL_NO; - tn->himq[option] = CURL_EMPTY; - break; - } - break; - } -} - -static void -set_local_option(struct connectdata *conn, int option, int newstate) -{ - struct TELNET *tn = (struct TELNET *)conn->data->req.protop; - if(newstate == CURL_YES) { - switch(tn->us[option]) { - case CURL_NO: - tn->us[option] = CURL_WANTYES; - send_negotiation(conn, CURL_WILL, option); - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->usq[option]) { - case CURL_EMPTY: - /* Already negotiating for CURL_YES, queue the request */ - tn->usq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - /* Error: already queued an enable request */ - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) { - case CURL_EMPTY: - /* Error: already negotiating for enable */ - break; - case CURL_OPPOSITE: - tn->usq[option] = CURL_EMPTY; - break; - } - break; - } - } - else { /* NO */ - switch(tn->us[option]) { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->us[option] = CURL_WANTNO; - send_negotiation(conn, CURL_WONT, option); - break; - - case CURL_WANTNO: - switch(tn->usq[option]) { - case CURL_EMPTY: - /* Already negotiating for NO */ - break; - case CURL_OPPOSITE: - tn->usq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) { - case CURL_EMPTY: - tn->usq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - break; - } - break; - } - } -} - -static -void rec_do(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->req.protop; - switch(tn->us[option]) { - case CURL_NO: - if(tn->us_preferred[option] == CURL_YES) { - tn->us[option] = CURL_YES; - send_negotiation(conn, CURL_WILL, option); - if(tn->subnegotiation[option] == CURL_YES) - /* transmission of data option */ - sendsuboption(conn, option); - } - else if(tn->subnegotiation[option] == CURL_YES) { - /* send information to achieve this option*/ - tn->us[option] = CURL_YES; - send_negotiation(conn, CURL_WILL, option); - sendsuboption(conn, option); - } - else - send_negotiation(conn, CURL_WONT, option); - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->usq[option]) { - case CURL_EMPTY: - /* Error: DONT answered by WILL */ - tn->us[option] = CURL_NO; - break; - case CURL_OPPOSITE: - /* Error: DONT answered by WILL */ - tn->us[option] = CURL_YES; - tn->usq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) { - case CURL_EMPTY: - tn->us[option] = CURL_YES; - if(tn->subnegotiation[option] == CURL_YES) { - /* transmission of data option */ - sendsuboption(conn, option); - } - break; - case CURL_OPPOSITE: - tn->us[option] = CURL_WANTNO; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_WONT, option); - break; - } - break; - } -} - -static -void rec_dont(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->req.protop; - switch(tn->us[option]) { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->us[option] = CURL_NO; - send_negotiation(conn, CURL_WONT, option); - break; - - case CURL_WANTNO: - switch(tn->usq[option]) { - case CURL_EMPTY: - tn->us[option] = CURL_NO; - break; - - case CURL_OPPOSITE: - tn->us[option] = CURL_WANTYES; - tn->usq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_WILL, option); - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) { - case CURL_EMPTY: - tn->us[option] = CURL_NO; - break; - case CURL_OPPOSITE: - tn->us[option] = CURL_NO; - tn->usq[option] = CURL_EMPTY; - break; - } - break; - } -} - - -static void printsub(struct Curl_easy *data, - int direction, /* '<' or '>' */ - unsigned char *pointer, /* where suboption data is */ - size_t length) /* length of suboption data */ -{ - unsigned int i = 0; - - if(data->set.verbose) { - if(direction) { - infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); - if(length >= 3) { - int j; - - i = pointer[length-2]; - j = pointer[length-1]; - - if(i != CURL_IAC || j != CURL_SE) { - infof(data, "(terminated by "); - if(CURL_TELOPT_OK(i)) - infof(data, "%s ", CURL_TELOPT(i)); - else if(CURL_TELCMD_OK(i)) - infof(data, "%s ", CURL_TELCMD(i)); - else - infof(data, "%u ", i); - if(CURL_TELOPT_OK(j)) - infof(data, "%s", CURL_TELOPT(j)); - else if(CURL_TELCMD_OK(j)) - infof(data, "%s", CURL_TELCMD(j)); - else - infof(data, "%d", j); - infof(data, ", not IAC SE!) "); - } - } - length -= 2; - } - if(length < 1) { - infof(data, "(Empty suboption?)"); - return; - } - - if(CURL_TELOPT_OK(pointer[0])) { - switch(pointer[0]) { - case CURL_TELOPT_TTYPE: - case CURL_TELOPT_XDISPLOC: - case CURL_TELOPT_NEW_ENVIRON: - case CURL_TELOPT_NAWS: - infof(data, "%s", CURL_TELOPT(pointer[0])); - break; - default: - infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); - break; - } - } - else - infof(data, "%d (unknown)", pointer[i]); - - switch(pointer[0]) { - case CURL_TELOPT_NAWS: - if(length > 4) - infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2], - (pointer[3]<<8) | pointer[4]); - break; - default: - switch(pointer[1]) { - case CURL_TELQUAL_IS: - infof(data, " IS"); - break; - case CURL_TELQUAL_SEND: - infof(data, " SEND"); - break; - case CURL_TELQUAL_INFO: - infof(data, " INFO/REPLY"); - break; - case CURL_TELQUAL_NAME: - infof(data, " NAME"); - break; - } - - switch(pointer[0]) { - case CURL_TELOPT_TTYPE: - case CURL_TELOPT_XDISPLOC: - pointer[length] = 0; - infof(data, " \"%s\"", &pointer[2]); - break; - case CURL_TELOPT_NEW_ENVIRON: - if(pointer[1] == CURL_TELQUAL_IS) { - infof(data, " "); - for(i = 3; i < length; i++) { - switch(pointer[i]) { - case CURL_NEW_ENV_VAR: - infof(data, ", "); - break; - case CURL_NEW_ENV_VALUE: - infof(data, " = "); - break; - default: - infof(data, "%c", pointer[i]); - break; - } - } - } - break; - default: - for(i = 2; i < length; i++) - infof(data, " %.2x", pointer[i]); - break; - } - } - if(direction) - infof(data, "\n"); - } -} - -static CURLcode check_telnet_options(struct connectdata *conn) -{ - struct curl_slist *head; - struct curl_slist *beg; - char option_keyword[128] = ""; - char option_arg[256] = ""; - struct Curl_easy *data = conn->data; - struct TELNET *tn = (struct TELNET *)conn->data->req.protop; - CURLcode result = CURLE_OK; - int binary_option; - - /* Add the user name as an environment variable if it - was given on the command line */ - if(conn->bits.user_passwd) { - snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); - beg = curl_slist_append(tn->telnet_vars, option_arg); - if(!beg) { - curl_slist_free_all(tn->telnet_vars); - tn->telnet_vars = NULL; - return CURLE_OUT_OF_MEMORY; - } - tn->telnet_vars = beg; - tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; - } - - for(head = data->set.telnet_options; head; head = head->next) { - if(sscanf(head->data, "%127[^= ]%*[ =]%255s", - option_keyword, option_arg) == 2) { - - /* Terminal type */ - if(strcasecompare(option_keyword, "TTYPE")) { - strncpy(tn->subopt_ttype, option_arg, 31); - tn->subopt_ttype[31] = 0; /* String termination */ - tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; - continue; - } - - /* Display variable */ - if(strcasecompare(option_keyword, "XDISPLOC")) { - strncpy(tn->subopt_xdisploc, option_arg, 127); - tn->subopt_xdisploc[127] = 0; /* String termination */ - tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; - continue; - } - - /* Environment variable */ - if(strcasecompare(option_keyword, "NEW_ENV")) { - beg = curl_slist_append(tn->telnet_vars, option_arg); - if(!beg) { - result = CURLE_OUT_OF_MEMORY; - break; - } - tn->telnet_vars = beg; - tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; - continue; - } - - /* Window Size */ - if(strcasecompare(option_keyword, "WS")) { - if(sscanf(option_arg, "%hu%*[xX]%hu", - &tn->subopt_wsx, &tn->subopt_wsy) == 2) - tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; - else { - failf(data, "Syntax error in telnet option: %s", head->data); - result = CURLE_TELNET_OPTION_SYNTAX; - break; - } - continue; - } - - /* To take care or not of the 8th bit in data exchange */ - if(strcasecompare(option_keyword, "BINARY")) { - binary_option = atoi(option_arg); - if(binary_option != 1) { - tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; - tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; - } - continue; - } - - failf(data, "Unknown telnet option %s", head->data); - result = CURLE_UNKNOWN_OPTION; - break; - } - failf(data, "Syntax error in telnet option: %s", head->data); - result = CURLE_TELNET_OPTION_SYNTAX; - break; - } - - if(result) { - curl_slist_free_all(tn->telnet_vars); - tn->telnet_vars = NULL; - } - - return result; -} - -/* - * suboption() - * - * Look at the sub-option buffer, and try to be helpful to the other - * side. - */ - -static void suboption(struct connectdata *conn) -{ - struct curl_slist *v; - unsigned char temp[2048]; - ssize_t bytes_written; - size_t len; - size_t tmplen; - int err; - char varname[128] = ""; - char varval[128] = ""; - struct Curl_easy *data = conn->data; - struct TELNET *tn = (struct TELNET *)data->req.protop; - - printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); - switch(CURL_SB_GET(tn)) { - case CURL_TELOPT_TTYPE: - len = strlen(tn->subopt_ttype) + 4 + 2; - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, - CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); - bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); - if(bytes_written < 0) { - err = SOCKERRNO; - failf(data,"Sending data failed (%d)",err); - } - printsub(data, '>', &temp[2], len-2); - break; - case CURL_TELOPT_XDISPLOC: - len = strlen(tn->subopt_xdisploc) + 4 + 2; - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, - CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); - bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); - if(bytes_written < 0) { - err = SOCKERRNO; - failf(data,"Sending data failed (%d)",err); - } - printsub(data, '>', &temp[2], len-2); - break; - case CURL_TELOPT_NEW_ENVIRON: - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, - CURL_TELQUAL_IS); - len = 4; - - for(v = tn->telnet_vars; v; v = v->next) { - tmplen = (strlen(v->data) + 1); - /* Add the variable only if it fits */ - if(len + tmplen < (int)sizeof(temp)-6) { - if(sscanf(v->data, "%127[^,],%127s", varname, varval)) { - snprintf((char *)&temp[len], sizeof(temp) - len, - "%c%s%c%s", CURL_NEW_ENV_VAR, varname, - CURL_NEW_ENV_VALUE, varval); - len += tmplen; - } - } - } - snprintf((char *)&temp[len], sizeof(temp) - len, - "%c%c", CURL_IAC, CURL_SE); - len += 2; - bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); - if(bytes_written < 0) { - err = SOCKERRNO; - failf(data,"Sending data failed (%d)",err); - } - printsub(data, '>', &temp[2], len-2); - break; - } - return; -} - - -/* - * sendsuboption() - * - * Send suboption information to the server side. - */ - -static void sendsuboption(struct connectdata *conn, int option) -{ - ssize_t bytes_written; - int err; - unsigned short x, y; - unsigned char *uc1, *uc2; - - struct Curl_easy *data = conn->data; - struct TELNET *tn = (struct TELNET *)data->req.protop; - - switch(option) { - case CURL_TELOPT_NAWS: - /* We prepare data to be sent */ - CURL_SB_CLEAR(tn); - CURL_SB_ACCUM(tn, CURL_IAC); - CURL_SB_ACCUM(tn, CURL_SB); - CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS); - /* We must deal either with litte or big endian processors */ - /* Window size must be sent according to the 'network order' */ - x = htons(tn->subopt_wsx); - y = htons(tn->subopt_wsy); - uc1 = (unsigned char *)&x; - uc2 = (unsigned char *)&y; - CURL_SB_ACCUM(tn, uc1[0]); - CURL_SB_ACCUM(tn, uc1[1]); - CURL_SB_ACCUM(tn, uc2[0]); - CURL_SB_ACCUM(tn, uc2[1]); - - CURL_SB_ACCUM(tn, CURL_IAC); - CURL_SB_ACCUM(tn, CURL_SE); - CURL_SB_TERM(tn); - /* data suboption is now ready */ - - printsub(data, '>', (unsigned char *)tn->subbuffer + 2, - CURL_SB_LEN(tn)-2); - - /* we send the header of the suboption... */ - bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3); - if(bytes_written < 0) { - err = SOCKERRNO; - failf(data, "Sending data failed (%d)", err); - } - /* ... then the window size with the send_telnet_data() function - to deal with 0xFF cases ... */ - send_telnet_data(conn, (char *)tn->subbuffer + 3, 4); - /* ... and the footer */ - bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2); - if(bytes_written < 0) { - err = SOCKERRNO; - failf(data, "Sending data failed (%d)", err); - } - break; - } -} - - -static -CURLcode telrcv(struct connectdata *conn, - const unsigned char *inbuf, /* Data received from socket */ - ssize_t count) /* Number of bytes received */ -{ - unsigned char c; - CURLcode result; - int in = 0; - int startwrite = -1; - struct Curl_easy *data = conn->data; - struct TELNET *tn = (struct TELNET *)data->req.protop; - -#define startskipping() \ - if(startwrite >= 0) { \ - result = Curl_client_write(conn, \ - CLIENTWRITE_BODY, \ - (char *)&inbuf[startwrite], \ - in-startwrite); \ - if(result) \ - return result; \ - } \ - startwrite = -1 - -#define writebyte() \ - if(startwrite < 0) \ - startwrite = in - -#define bufferflush() startskipping() - - while(count--) { - c = inbuf[in]; - - switch(tn->telrcv_state) { - case CURL_TS_CR: - tn->telrcv_state = CURL_TS_DATA; - if(c == '\0') { - startskipping(); - break; /* Ignore \0 after CR */ - } - writebyte(); - break; - - case CURL_TS_DATA: - if(c == CURL_IAC) { - tn->telrcv_state = CURL_TS_IAC; - startskipping(); - break; - } - else if(c == '\r') - tn->telrcv_state = CURL_TS_CR; - writebyte(); - break; - - case CURL_TS_IAC: - process_iac: - DEBUGASSERT(startwrite < 0); - switch(c) { - case CURL_WILL: - tn->telrcv_state = CURL_TS_WILL; - break; - case CURL_WONT: - tn->telrcv_state = CURL_TS_WONT; - break; - case CURL_DO: - tn->telrcv_state = CURL_TS_DO; - break; - case CURL_DONT: - tn->telrcv_state = CURL_TS_DONT; - break; - case CURL_SB: - CURL_SB_CLEAR(tn); - tn->telrcv_state = CURL_TS_SB; - break; - case CURL_IAC: - tn->telrcv_state = CURL_TS_DATA; - writebyte(); - break; - case CURL_DM: - case CURL_NOP: - case CURL_GA: - default: - tn->telrcv_state = CURL_TS_DATA; - printoption(data, "RCVD", CURL_IAC, c); - break; - } - break; - - case CURL_TS_WILL: - printoption(data, "RCVD", CURL_WILL, c); - tn->please_negotiate = 1; - rec_will(conn, c); - tn->telrcv_state = CURL_TS_DATA; - break; - - case CURL_TS_WONT: - printoption(data, "RCVD", CURL_WONT, c); - tn->please_negotiate = 1; - rec_wont(conn, c); - tn->telrcv_state = CURL_TS_DATA; - break; - - case CURL_TS_DO: - printoption(data, "RCVD", CURL_DO, c); - tn->please_negotiate = 1; - rec_do(conn, c); - tn->telrcv_state = CURL_TS_DATA; - break; - - case CURL_TS_DONT: - printoption(data, "RCVD", CURL_DONT, c); - tn->please_negotiate = 1; - rec_dont(conn, c); - tn->telrcv_state = CURL_TS_DATA; - break; - - case CURL_TS_SB: - if(c == CURL_IAC) - tn->telrcv_state = CURL_TS_SE; - else - CURL_SB_ACCUM(tn, c); - break; - - case CURL_TS_SE: - if(c != CURL_SE) { - if(c != CURL_IAC) { - /* - * This is an error. We only expect to get "IAC IAC" or "IAC SE". - * Several things may have happened. An IAC was not doubled, the - * IAC SE was left off, or another option got inserted into the - * suboption are all possibilities. If we assume that the IAC was - * not doubled, and really the IAC SE was left off, we could get - * into an infinite loop here. So, instead, we terminate the - * suboption, and process the partial suboption if we can. - */ - CURL_SB_ACCUM(tn, CURL_IAC); - CURL_SB_ACCUM(tn, c); - tn->subpointer -= 2; - CURL_SB_TERM(tn); - - printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); - suboption(conn); /* handle sub-option */ - tn->telrcv_state = CURL_TS_IAC; - goto process_iac; - } - CURL_SB_ACCUM(tn, c); - tn->telrcv_state = CURL_TS_SB; - } - else - { - CURL_SB_ACCUM(tn, CURL_IAC); - CURL_SB_ACCUM(tn, CURL_SE); - tn->subpointer -= 2; - CURL_SB_TERM(tn); - suboption(conn); /* handle sub-option */ - tn->telrcv_state = CURL_TS_DATA; - } - break; - } - ++in; - } - bufferflush(); - return CURLE_OK; -} - -/* Escape and send a telnet data block */ -static CURLcode send_telnet_data(struct connectdata *conn, - char *buffer, ssize_t nread) -{ - ssize_t escapes, i, j, outlen; - unsigned char *outbuf = NULL; - CURLcode result = CURLE_OK; - ssize_t bytes_written, total_written; - - /* Determine size of new buffer after escaping */ - escapes = 0; - for(i = 0; i < nread; i++) - if((unsigned char)buffer[i] == CURL_IAC) - escapes++; - outlen = nread + escapes; - - if(outlen == nread) - outbuf = (unsigned char *)buffer; - else { - outbuf = malloc(nread + escapes + 1); - if(!outbuf) - return CURLE_OUT_OF_MEMORY; - - j = 0; - for(i = 0; i < nread; i++) { - outbuf[j++] = buffer[i]; - if((unsigned char)buffer[i] == CURL_IAC) - outbuf[j++] = CURL_IAC; - } - outbuf[j] = '\0'; - } - - total_written = 0; - while(!result && total_written < outlen) { - /* Make sure socket is writable to avoid EWOULDBLOCK condition */ - struct pollfd pfd[1]; - pfd[0].fd = conn->sock[FIRSTSOCKET]; - pfd[0].events = POLLOUT; - switch(Curl_poll(pfd, 1, -1)) { - case -1: /* error, abort writing */ - case 0: /* timeout (will never happen) */ - result = CURLE_SEND_ERROR; - break; - default: /* write! */ - bytes_written = 0; - result = Curl_write(conn, conn->sock[FIRSTSOCKET], - outbuf + total_written, - outlen - total_written, - &bytes_written); - total_written += bytes_written; - break; - } - } - - /* Free malloc copy if escaped */ - if(outbuf != (unsigned char *)buffer) - free(outbuf); - - return result; -} - -static CURLcode telnet_done(struct connectdata *conn, - CURLcode status, bool premature) -{ - struct TELNET *tn = (struct TELNET *)conn->data->req.protop; - (void)status; /* unused */ - (void)premature; /* not used */ - - if(!tn) - return CURLE_OK; - - curl_slist_free_all(tn->telnet_vars); - tn->telnet_vars = NULL; - - Curl_safefree(conn->data->req.protop); - - return CURLE_OK; -} - -static CURLcode telnet_do(struct connectdata *conn, bool *done) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; -#ifdef USE_WINSOCK - HMODULE wsock2; - WSOCK2_FUNC close_event_func; - WSOCK2_FUNC create_event_func; - WSOCK2_FUNC event_select_func; - WSOCK2_FUNC enum_netevents_func; - WSAEVENT event_handle; - WSANETWORKEVENTS events; - HANDLE stdin_handle; - HANDLE objs[2]; - DWORD obj_count; - DWORD wait_timeout; - DWORD waitret; - DWORD readfile_read; - int err; -#else - int interval_ms; - struct pollfd pfd[2]; - int poll_cnt; - curl_off_t total_dl = 0; - curl_off_t total_ul = 0; -#endif - ssize_t nread; - struct curltime now; - bool keepon = TRUE; - char *buf = data->state.buffer; - struct TELNET *tn; - - *done = TRUE; /* unconditionally */ - - result = init_telnet(conn); - if(result) - return result; - - tn = (struct TELNET *)data->req.protop; - - result = check_telnet_options(conn); - if(result) - return result; - -#ifdef USE_WINSOCK - /* - ** This functionality only works with WinSock >= 2.0. So, - ** make sure we have it. - */ - result = check_wsock2(data); - if(result) - return result; - - /* OK, so we have WinSock 2.0. We need to dynamically */ - /* load ws2_32.dll and get the function pointers we need. */ - wsock2 = Curl_load_library(TEXT("WS2_32.DLL")); - if(wsock2 == NULL) { - failf(data, "failed to load WS2_32.DLL (%u)", GetLastError()); - return CURLE_FAILED_INIT; - } - - /* Grab a pointer to WSACreateEvent */ - create_event_func = GetProcAddress(wsock2, "WSACreateEvent"); - if(create_event_func == NULL) { - failf(data, "failed to find WSACreateEvent function (%u)", GetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* And WSACloseEvent */ - close_event_func = GetProcAddress(wsock2, "WSACloseEvent"); - if(close_event_func == NULL) { - failf(data, "failed to find WSACloseEvent function (%u)", GetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* And WSAEventSelect */ - event_select_func = GetProcAddress(wsock2, "WSAEventSelect"); - if(event_select_func == NULL) { - failf(data, "failed to find WSAEventSelect function (%u)", GetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* And WSAEnumNetworkEvents */ - enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents"); - if(enum_netevents_func == NULL) { - failf(data, "failed to find WSAEnumNetworkEvents function (%u)", - GetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* We want to wait for both stdin and the socket. Since - ** the select() function in winsock only works on sockets - ** we have to use the WaitForMultipleObjects() call. - */ - - /* First, create a sockets event object */ - event_handle = (WSAEVENT)create_event_func(); - if(event_handle == WSA_INVALID_EVENT) { - failf(data, "WSACreateEvent failed (%d)", SOCKERRNO); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* Tell winsock what events we want to listen to */ - if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == - SOCKET_ERROR) { - close_event_func(event_handle); - FreeLibrary(wsock2); - return CURLE_OK; - } - - /* The get the Windows file handle for stdin */ - stdin_handle = GetStdHandle(STD_INPUT_HANDLE); - - /* Create the list of objects to wait for */ - objs[0] = event_handle; - objs[1] = stdin_handle; - - /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, - else use the old WaitForMultipleObjects() way */ - if(GetFileType(stdin_handle) == FILE_TYPE_PIPE || - data->set.is_fread_set) { - /* Don't wait for stdin_handle, just wait for event_handle */ - obj_count = 1; - /* Check stdin_handle per 100 milliseconds */ - wait_timeout = 100; - } - else { - obj_count = 2; - wait_timeout = 1000; - } - - /* Keep on listening and act on events */ - while(keepon) { - const DWORD buf_size = (DWORD)data->set.buffer_size; - waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout); - switch(waitret) { - case WAIT_TIMEOUT: - { - for(;;) { - if(data->set.is_fread_set) { - size_t n; - /* read from user-supplied method */ - n = data->state.fread_func(buf, 1, buf_size, data->state.in); - if(n == CURL_READFUNC_ABORT) { - keepon = FALSE; - result = CURLE_READ_ERROR; - break; - } - - if(n == CURL_READFUNC_PAUSE) - break; - - if(n == 0) /* no bytes */ - break; - - readfile_read = (DWORD)n; /* fall thru with number of bytes read */ - } - else { - /* read from stdin */ - if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, - &readfile_read, NULL)) { - keepon = FALSE; - result = CURLE_READ_ERROR; - break; - } - - if(!readfile_read) - break; - - if(!ReadFile(stdin_handle, buf, buf_size, - &readfile_read, NULL)) { - keepon = FALSE; - result = CURLE_READ_ERROR; - break; - } - } - - result = send_telnet_data(conn, buf, readfile_read); - if(result) { - keepon = FALSE; - break; - } - } - } - break; - - case WAIT_OBJECT_0 + 1: - { - if(!ReadFile(stdin_handle, buf, buf_size, - &readfile_read, NULL)) { - keepon = FALSE; - result = CURLE_READ_ERROR; - break; - } - - result = send_telnet_data(conn, buf, readfile_read); - if(result) { - keepon = FALSE; - break; - } - } - break; - - case WAIT_OBJECT_0: - - events.lNetworkEvents = 0; - if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) { - err = SOCKERRNO; - if(err != EINPROGRESS) { - infof(data, "WSAEnumNetworkEvents failed (%d)", err); - keepon = FALSE; - result = CURLE_READ_ERROR; - } - break; - } - if(events.lNetworkEvents & FD_READ) { - /* read data from network */ - result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread); - /* read would've blocked. Loop again */ - if(result == CURLE_AGAIN) - break; - /* returned not-zero, this an error */ - else if(result) { - keepon = FALSE; - break; - } - /* returned zero but actually received 0 or less here, - the server closed the connection and we bail out */ - else if(nread <= 0) { - keepon = FALSE; - break; - } - - result = telrcv(conn, (unsigned char *) buf, nread); - if(result) { - keepon = FALSE; - break; - } - - /* Negotiate if the peer has started negotiating, - otherwise don't. We don't want to speak telnet with - non-telnet servers, like POP or SMTP. */ - if(tn->please_negotiate && !tn->already_negotiated) { - negotiate(conn); - tn->already_negotiated = 1; - } - } - if(events.lNetworkEvents & FD_CLOSE) { - keepon = FALSE; - } - break; - - } - - if(data->set.timeout) { - now = Curl_tvnow(); - if(Curl_tvdiff(now, conn->created) >= data->set.timeout) { - failf(data, "Time-out"); - result = CURLE_OPERATION_TIMEDOUT; - keepon = FALSE; - } - } - } - - /* We called WSACreateEvent, so call WSACloseEvent */ - if(!close_event_func(event_handle)) { - infof(data, "WSACloseEvent failed (%d)", SOCKERRNO); - } - - /* "Forget" pointers into the library we're about to free */ - create_event_func = NULL; - close_event_func = NULL; - event_select_func = NULL; - enum_netevents_func = NULL; - - /* We called LoadLibrary, so call FreeLibrary */ - if(!FreeLibrary(wsock2)) - infof(data, "FreeLibrary(wsock2) failed (%u)", GetLastError()); -#else - pfd[0].fd = sockfd; - pfd[0].events = POLLIN; - - if(data->set.is_fread_set) { - poll_cnt = 1; - interval_ms = 100; /* poll user-supplied read function */ - } - else { - /* really using fread, so infile is a FILE* */ - pfd[1].fd = fileno((FILE *)data->state.in); - pfd[1].events = POLLIN; - poll_cnt = 2; - interval_ms = 1 * 1000; - } - - while(keepon) { - switch(Curl_poll(pfd, poll_cnt, interval_ms)) { - case -1: /* error, stop reading */ - keepon = FALSE; - continue; - case 0: /* timeout */ - pfd[0].revents = 0; - pfd[1].revents = 0; - /* fall through */ - default: /* read! */ - if(pfd[0].revents & POLLIN) { - /* read data from network */ - result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread); - /* read would've blocked. Loop again */ - if(result == CURLE_AGAIN) - break; - /* returned not-zero, this an error */ - if(result) { - keepon = FALSE; - break; - } - /* returned zero but actually received 0 or less here, - the server closed the connection and we bail out */ - else if(nread <= 0) { - keepon = FALSE; - break; - } - - total_dl += nread; - Curl_pgrsSetDownloadCounter(data, total_dl); - result = telrcv(conn, (unsigned char *)buf, nread); - if(result) { - keepon = FALSE; - break; - } - - /* Negotiate if the peer has started negotiating, - otherwise don't. We don't want to speak telnet with - non-telnet servers, like POP or SMTP. */ - if(tn->please_negotiate && !tn->already_negotiated) { - negotiate(conn); - tn->already_negotiated = 1; - } - } - - nread = 0; - if(poll_cnt == 2) { - if(pfd[1].revents & POLLIN) { /* read from in file */ - nread = read(pfd[1].fd, buf, data->set.buffer_size); - } - } - else { - /* read from user-supplied method */ - nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size, - data->state.in); - if(nread == CURL_READFUNC_ABORT) { - keepon = FALSE; - break; - } - if(nread == CURL_READFUNC_PAUSE) - break; - } - - if(nread > 0) { - result = send_telnet_data(conn, buf, nread); - if(result) { - keepon = FALSE; - break; - } - total_ul += nread; - Curl_pgrsSetUploadCounter(data, total_ul); - } - else if(nread < 0) - keepon = FALSE; - - break; - } /* poll switch statement */ - - if(data->set.timeout) { - now = Curl_tvnow(); - if(Curl_tvdiff(now, conn->created) >= data->set.timeout) { - failf(data, "Time-out"); - result = CURLE_OPERATION_TIMEDOUT; - keepon = FALSE; - } - } - - if(Curl_pgrsUpdate(conn)) { - result = CURLE_ABORTED_BY_CALLBACK; - break; - } - } -#endif - /* mark this as "no further transfer wanted" */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - return result; -} -#endif diff --git a/dep/cpr/opt/curl/lib/telnet.h b/dep/cpr/opt/curl/lib/telnet.h deleted file mode 100644 index 419a399b7b9..00000000000 --- a/dep/cpr/opt/curl/lib/telnet.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef HEADER_CURL_TELNET_H -#define HEADER_CURL_TELNET_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#ifndef CURL_DISABLE_TELNET -extern const struct Curl_handler Curl_handler_telnet; -#endif - -#endif /* HEADER_CURL_TELNET_H */ - diff --git a/dep/cpr/opt/curl/lib/tftp.c b/dep/cpr/opt/curl/lib/tftp.c deleted file mode 100644 index 4e599fd2729..00000000000 --- a/dep/cpr/opt/curl/lib/tftp.c +++ /dev/null @@ -1,1403 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_TFTP - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "tftp.h" -#include "progress.h" -#include "connect.h" -#include "strerror.h" -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "multiif.h" -#include "url.h" -#include "strcase.h" -#include "speedcheck.h" -#include "select.h" -#include "escape.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* RFC2348 allows the block size to be negotiated */ -#define TFTP_BLKSIZE_DEFAULT 512 -#define TFTP_BLKSIZE_MIN 8 -#define TFTP_BLKSIZE_MAX 65464 -#define TFTP_OPTION_BLKSIZE "blksize" - -/* from RFC2349: */ -#define TFTP_OPTION_TSIZE "tsize" -#define TFTP_OPTION_INTERVAL "timeout" - -typedef enum { - TFTP_MODE_NETASCII = 0, - TFTP_MODE_OCTET -} tftp_mode_t; - -typedef enum { - TFTP_STATE_START = 0, - TFTP_STATE_RX, - TFTP_STATE_TX, - TFTP_STATE_FIN -} tftp_state_t; - -typedef enum { - TFTP_EVENT_NONE = -1, - TFTP_EVENT_INIT = 0, - TFTP_EVENT_RRQ = 1, - TFTP_EVENT_WRQ = 2, - TFTP_EVENT_DATA = 3, - TFTP_EVENT_ACK = 4, - TFTP_EVENT_ERROR = 5, - TFTP_EVENT_OACK = 6, - TFTP_EVENT_TIMEOUT -} tftp_event_t; - -typedef enum { - TFTP_ERR_UNDEF = 0, - TFTP_ERR_NOTFOUND, - TFTP_ERR_PERM, - TFTP_ERR_DISKFULL, - TFTP_ERR_ILLEGAL, - TFTP_ERR_UNKNOWNID, - TFTP_ERR_EXISTS, - TFTP_ERR_NOSUCHUSER, /* This will never be triggered by this code */ - - /* The remaining error codes are internal to curl */ - TFTP_ERR_NONE = -100, - TFTP_ERR_TIMEOUT, - TFTP_ERR_NORESPONSE -} tftp_error_t; - -typedef struct tftp_packet { - unsigned char *data; -} tftp_packet_t; - -typedef struct tftp_state_data { - tftp_state_t state; - tftp_mode_t mode; - tftp_error_t error; - tftp_event_t event; - struct connectdata *conn; - curl_socket_t sockfd; - int retries; - int retry_time; - int retry_max; - time_t start_time; - time_t max_time; - time_t rx_time; - unsigned short block; - struct Curl_sockaddr_storage local_addr; - struct Curl_sockaddr_storage remote_addr; - curl_socklen_t remote_addrlen; - int rbytes; - int sbytes; - int blksize; - int requested_blksize; - tftp_packet_t rpacket; - tftp_packet_t spacket; -} tftp_state_data_t; - - -/* Forward declarations */ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event); -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event); -static CURLcode tftp_connect(struct connectdata *conn, bool *done); -static CURLcode tftp_disconnect(struct connectdata *conn, - bool dead_connection); -static CURLcode tftp_do(struct connectdata *conn, bool *done); -static CURLcode tftp_done(struct connectdata *conn, - CURLcode, bool premature); -static CURLcode tftp_setup_connection(struct connectdata * conn); -static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done); -static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done); -static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks); -static CURLcode tftp_translate_code(tftp_error_t error); - - -/* - * TFTP protocol handler. - */ - -const struct Curl_handler Curl_handler_tftp = { - "TFTP", /* scheme */ - tftp_setup_connection, /* setup_connection */ - tftp_do, /* do_it */ - tftp_done, /* done */ - ZERO_NULL, /* do_more */ - tftp_connect, /* connect_it */ - tftp_multi_statemach, /* connecting */ - tftp_doing, /* doing */ - tftp_getsock, /* proto_getsock */ - tftp_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - tftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - PORT_TFTP, /* defport */ - CURLPROTO_TFTP, /* protocol */ - PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ -}; - -/********************************************************** - * - * tftp_set_timeouts - - * - * Set timeouts based on state machine state. - * Use user provided connect timeouts until DATA or ACK - * packet is received, then use user-provided transfer timeouts - * - * - **********************************************************/ -static CURLcode tftp_set_timeouts(tftp_state_data_t *state) -{ - time_t maxtime, timeout; - time_t timeout_ms; - bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE; - - time(&state->start_time); - - /* Compute drop-dead time */ - timeout_ms = Curl_timeleft(state->conn->data, NULL, start); - - if(timeout_ms < 0) { - /* time-out, bail out, go home */ - failf(state->conn->data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(start) { - - maxtime = (time_t)(timeout_ms + 500) / 1000; - state->max_time = state->start_time + maxtime; - - /* Set per-block timeout to total */ - timeout = maxtime; - - /* Average restart after 5 seconds */ - state->retry_max = (int)timeout/5; - - if(state->retry_max < 1) - /* avoid division by zero below */ - state->retry_max = 1; - - /* Compute the re-start interval to suit the timeout */ - state->retry_time = (int)timeout/state->retry_max; - if(state->retry_time<1) - state->retry_time = 1; - - } - else { - if(timeout_ms > 0) - maxtime = (time_t)(timeout_ms + 500) / 1000; - else - maxtime = 3600; - - state->max_time = state->start_time + maxtime; - - /* Set per-block timeout to total */ - timeout = maxtime; - - /* Average reposting an ACK after 5 seconds */ - state->retry_max = (int)timeout/5; - } - /* But bound the total number */ - if(state->retry_max<3) - state->retry_max = 3; - - if(state->retry_max>50) - state->retry_max = 50; - - /* Compute the re-ACK interval to suit the timeout */ - state->retry_time = (int)(timeout/state->retry_max); - if(state->retry_time<1) - state->retry_time = 1; - - infof(state->conn->data, - "set timeouts for state %d; Total %ld, retry %d maxtry %d\n", - (int)state->state, (long)(state->max_time-state->start_time), - state->retry_time, state->retry_max); - - /* init RX time */ - time(&state->rx_time); - - return CURLE_OK; -} - -/********************************************************** - * - * tftp_set_send_first - * - * Event handler for the START state - * - **********************************************************/ - -static void setpacketevent(tftp_packet_t *packet, unsigned short num) -{ - packet->data[0] = (unsigned char)(num >> 8); - packet->data[1] = (unsigned char)(num & 0xff); -} - - -static void setpacketblock(tftp_packet_t *packet, unsigned short num) -{ - packet->data[2] = (unsigned char)(num >> 8); - packet->data[3] = (unsigned char)(num & 0xff); -} - -static unsigned short getrpacketevent(const tftp_packet_t *packet) -{ - return (unsigned short)((packet->data[0] << 8) | packet->data[1]); -} - -static unsigned short getrpacketblock(const tftp_packet_t *packet) -{ - return (unsigned short)((packet->data[2] << 8) | packet->data[3]); -} - -static size_t Curl_strnlen(const char *string, size_t maxlen) -{ - const char *end = memchr(string, '\0', maxlen); - return end ? (size_t) (end - string) : maxlen; -} - -static const char *tftp_option_get(const char *buf, size_t len, - const char **option, const char **value) -{ - size_t loc; - - loc = Curl_strnlen(buf, len); - loc++; /* NULL term */ - - if(loc >= len) - return NULL; - *option = buf; - - loc += Curl_strnlen(buf + loc, len-loc); - loc++; /* NULL term */ - - if(loc > len) - return NULL; - *value = &buf[strlen(*option) + 1]; - - return &buf[loc]; -} - -static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, - const char *ptr, int len) -{ - const char *tmp = ptr; - struct Curl_easy *data = state->conn->data; - - /* if OACK doesn't contain blksize option, the default (512) must be used */ - state->blksize = TFTP_BLKSIZE_DEFAULT; - - while(tmp < ptr + len) { - const char *option, *value; - - tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value); - if(tmp == NULL) { - failf(data, "Malformed ACK packet, rejecting"); - return CURLE_TFTP_ILLEGAL; - } - - infof(data, "got option=(%s) value=(%s)\n", option, value); - - if(checkprefix(option, TFTP_OPTION_BLKSIZE)) { - long blksize; - - blksize = strtol(value, NULL, 10); - - if(!blksize) { - failf(data, "invalid blocksize value in OACK packet"); - return CURLE_TFTP_ILLEGAL; - } - if(blksize > TFTP_BLKSIZE_MAX) { - failf(data, "%s (%d)", "blksize is larger than max supported", - TFTP_BLKSIZE_MAX); - return CURLE_TFTP_ILLEGAL; - } - else if(blksize < TFTP_BLKSIZE_MIN) { - failf(data, "%s (%d)", "blksize is smaller than min supported", - TFTP_BLKSIZE_MIN); - return CURLE_TFTP_ILLEGAL; - } - else if(blksize > state->requested_blksize) { - /* could realloc pkt buffers here, but the spec doesn't call out - * support for the server requesting a bigger blksize than the client - * requests */ - failf(data, "%s (%ld)", - "server requested blksize larger than allocated", blksize); - return CURLE_TFTP_ILLEGAL; - } - - state->blksize = (int)blksize; - infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK", - state->blksize, "requested", state->requested_blksize); - } - else if(checkprefix(option, TFTP_OPTION_TSIZE)) { - long tsize = 0; - - tsize = strtol(value, NULL, 10); - infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize); - - /* tsize should be ignored on upload: Who cares about the size of the - remote file? */ - if(!data->set.upload) { - if(!tsize) { - failf(data, "invalid tsize -:%s:- value in OACK packet", value); - return CURLE_TFTP_ILLEGAL; - } - Curl_pgrsSetDownloadSize(data, tsize); - } - } - } - - return CURLE_OK; -} - -static size_t tftp_option_add(tftp_state_data_t *state, size_t csize, - char *buf, const char *option) -{ - if(( strlen(option) + csize + 1) > (size_t)state->blksize) - return 0; - strcpy(buf, option); - return strlen(option) + 1; -} - -static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, - tftp_event_t event) -{ - CURLcode result; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - struct Curl_easy *data = state->conn->data; - - infof(data, "%s\n", "Connected for transmit"); -#endif - state->state = TFTP_STATE_TX; - result = tftp_set_timeouts(state); - if(result) - return result; - return tftp_tx(state, event); -} - -static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, - tftp_event_t event) -{ - CURLcode result; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - struct Curl_easy *data = state->conn->data; - - infof(data, "%s\n", "Connected for receive"); -#endif - state->state = TFTP_STATE_RX; - result = tftp_set_timeouts(state); - if(result) - return result; - return tftp_rx(state, event); -} - -static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) -{ - size_t sbytes; - ssize_t senddata; - const char *mode = "octet"; - char *filename; - char buf[64]; - struct Curl_easy *data = state->conn->data; - CURLcode result = CURLE_OK; - - /* Set ascii mode if -B flag was used */ - if(data->set.prefer_ascii) - mode = "netascii"; - - switch(event) { - - case TFTP_EVENT_INIT: /* Send the first packet out */ - case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */ - /* Increment the retry counter, quit if over the limit */ - state->retries++; - if(state->retries>state->retry_max) { - state->error = TFTP_ERR_NORESPONSE; - state->state = TFTP_STATE_FIN; - return result; - } - - if(data->set.upload) { - /* If we are uploading, send an WRQ */ - setpacketevent(&state->spacket, TFTP_EVENT_WRQ); - state->conn->data->req.upload_fromhere = - (char *)state->spacket.data + 4; - if(data->state.infilesize != -1) - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - else { - /* If we are downloading, send an RRQ */ - setpacketevent(&state->spacket, TFTP_EVENT_RRQ); - } - /* As RFC3617 describes the separator slash is not actually part of the - file name so we skip the always-present first letter of the path - string. */ - result = Curl_urldecode(data, &state->conn->data->state.path[1], 0, - &filename, NULL, FALSE); - if(result) - return result; - - if(strlen(filename) > (state->blksize - strlen(mode) - 4)) { - failf(data, "TFTP file name too long\n"); - free(filename); - return CURLE_TFTP_ILLEGAL; /* too long file name field */ - } - - snprintf((char *)state->spacket.data + 2, - state->blksize, - "%s%c%s%c", filename, '\0', mode, '\0'); - sbytes = 4 + strlen(filename) + strlen(mode); - - /* optional addition of TFTP options */ - if(!data->set.tftp_no_options) { - /* add tsize option */ - if(data->set.upload && (data->state.infilesize != -1)) - snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, - data->state.infilesize); - else - strcpy(buf, "0"); /* the destination is large enough */ - - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data + sbytes, - TFTP_OPTION_TSIZE); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data + sbytes, buf); - /* add blksize option */ - snprintf(buf, sizeof(buf), "%d", state->requested_blksize); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data + sbytes, - TFTP_OPTION_BLKSIZE); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data + sbytes, buf); - - /* add timeout option */ - snprintf(buf, sizeof(buf), "%d", state->retry_time); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data + sbytes, - TFTP_OPTION_INTERVAL); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data + sbytes, buf); - } - - /* the typecase for the 3rd argument is mostly for systems that do - not have a size_t argument, like older unixes that want an 'int' */ - senddata = sendto(state->sockfd, (void *)state->spacket.data, - (SEND_TYPE_ARG3)sbytes, 0, - state->conn->ip_addr->ai_addr, - state->conn->ip_addr->ai_addrlen); - if(senddata != (ssize_t)sbytes) { - failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - } - free(filename); - break; - - case TFTP_EVENT_OACK: - if(data->set.upload) { - result = tftp_connect_for_tx(state, event); - } - else { - result = tftp_connect_for_rx(state, event); - } - break; - - case TFTP_EVENT_ACK: /* Connected for transmit */ - result = tftp_connect_for_tx(state, event); - break; - - case TFTP_EVENT_DATA: /* Connected for receive */ - result = tftp_connect_for_rx(state, event); - break; - - case TFTP_EVENT_ERROR: - state->state = TFTP_STATE_FIN; - break; - - default: - failf(state->conn->data, "tftp_send_first: internal error"); - break; - } - - return result; -} - -/* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit - boundary */ -#define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff) - -/********************************************************** - * - * tftp_rx - * - * Event handler for the RX state - * - **********************************************************/ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) -{ - ssize_t sbytes; - int rblock; - struct Curl_easy *data = state->conn->data; - - switch(event) { - - case TFTP_EVENT_DATA: - /* Is this the block we expect? */ - rblock = getrpacketblock(&state->rpacket); - if(NEXT_BLOCKNUM(state->block) == rblock) { - /* This is the expected block. Reset counters and ACK it. */ - state->retries = 0; - } - else if(state->block == rblock) { - /* This is the last recently received block again. Log it and ACK it - again. */ - infof(data, "Received last DATA packet block %d again.\n", rblock); - } - else { - /* totally unexpected, just log it */ - infof(data, - "Received unexpected DATA packet block %d, expecting block %d\n", - rblock, NEXT_BLOCKNUM(state->block)); - break; - } - - /* ACK this block. */ - state->block = (unsigned short)rblock; - setpacketevent(&state->spacket, TFTP_EVENT_ACK); - setpacketblock(&state->spacket, state->block); - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - if(sbytes < 0) { - failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - return CURLE_SEND_ERROR; - } - - /* Check if completed (That is, a less than full packet is received) */ - if(state->rbytes < (ssize_t)state->blksize + 4) { - state->state = TFTP_STATE_FIN; - } - else { - state->state = TFTP_STATE_RX; - } - time(&state->rx_time); - break; - - case TFTP_EVENT_OACK: - /* ACK option acknowledgement so we can move on to data */ - state->block = 0; - state->retries = 0; - setpacketevent(&state->spacket, TFTP_EVENT_ACK); - setpacketblock(&state->spacket, state->block); - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - if(sbytes < 0) { - failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - return CURLE_SEND_ERROR; - } - - /* we're ready to RX data */ - state->state = TFTP_STATE_RX; - time(&state->rx_time); - break; - - case TFTP_EVENT_TIMEOUT: - /* Increment the retry count and fail if over the limit */ - state->retries++; - infof(data, - "Timeout waiting for block %d ACK. Retries = %d\n", - NEXT_BLOCKNUM(state->block), state->retries); - if(state->retries > state->retry_max) { - state->error = TFTP_ERR_TIMEOUT; - state->state = TFTP_STATE_FIN; - } - else { - /* Resend the previous ACK */ - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - if(sbytes<0) { - failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - return CURLE_SEND_ERROR; - } - } - break; - - case TFTP_EVENT_ERROR: - setpacketevent(&state->spacket, TFTP_EVENT_ERROR); - setpacketblock(&state->spacket, state->block); - (void)sendto(state->sockfd, (void *)state->spacket.data, - 4, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* don't bother with the return code, but if the socket is still up we - * should be a good TFTP client and let the server know we're done */ - state->state = TFTP_STATE_FIN; - break; - - default: - failf(data, "%s", "tftp_rx: internal error"); - return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for - this */ - } - return CURLE_OK; -} - -/********************************************************** - * - * tftp_tx - * - * Event handler for the TX state - * - **********************************************************/ -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) -{ - struct Curl_easy *data = state->conn->data; - ssize_t sbytes; - int rblock; - CURLcode result = CURLE_OK; - struct SingleRequest *k = &data->req; - int cb; /* Bytes currently read */ - - switch(event) { - - case TFTP_EVENT_ACK: - case TFTP_EVENT_OACK: - if(event == TFTP_EVENT_ACK) { - /* Ack the packet */ - rblock = getrpacketblock(&state->rpacket); - - if(rblock != state->block && - /* There's a bug in tftpd-hpa that causes it to send us an ack for - * 65535 when the block number wraps to 0. So when we're expecting - * 0, also accept 65535. See - * http://syslinux.zytor.com/archives/2010-September/015253.html - * */ - !(state->block == 0 && rblock == 65535)) { - /* This isn't the expected block. Log it and up the retry counter */ - infof(data, "Received ACK for block %d, expecting %d\n", - rblock, state->block); - state->retries++; - /* Bail out if over the maximum */ - if(state->retries>state->retry_max) { - failf(data, "tftp_tx: giving up waiting for block %d ack", - state->block); - result = CURLE_SEND_ERROR; - } - else { - /* Re-send the data packet */ - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4 + state->sbytes, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* Check all sbytes were sent */ - if(sbytes<0) { - failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - result = CURLE_SEND_ERROR; - } - } - - return result; - } - /* This is the expected packet. Reset the counters and send the next - block */ - time(&state->rx_time); - state->block++; - } - else - state->block = 1; /* first data block is 1 when using OACK */ - - state->retries = 0; - setpacketevent(&state->spacket, TFTP_EVENT_DATA); - setpacketblock(&state->spacket, state->block); - if(state->block > 1 && state->sbytes < (int)state->blksize) { - state->state = TFTP_STATE_FIN; - return CURLE_OK; - } - - /* TFTP considers data block size < 512 bytes as an end of session. So - * in some cases we must wait for additional data to build full (512 bytes) - * data block. - * */ - state->sbytes = 0; - state->conn->data->req.upload_fromhere = (char *)state->spacket.data + 4; - do { - result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes, - &cb); - if(result) - return result; - state->sbytes += cb; - state->conn->data->req.upload_fromhere += cb; - } while(state->sbytes < state->blksize && cb != 0); - - sbytes = sendto(state->sockfd, (void *) state->spacket.data, - 4 + state->sbytes, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* Check all sbytes were sent */ - if(sbytes<0) { - failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - return CURLE_SEND_ERROR; - } - /* Update the progress meter */ - k->writebytecount += state->sbytes; - Curl_pgrsSetUploadCounter(data, k->writebytecount); - break; - - case TFTP_EVENT_TIMEOUT: - /* Increment the retry counter and log the timeout */ - state->retries++; - infof(data, "Timeout waiting for block %d ACK. " - " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries); - /* Decide if we've had enough */ - if(state->retries > state->retry_max) { - state->error = TFTP_ERR_TIMEOUT; - state->state = TFTP_STATE_FIN; - } - else { - /* Re-send the data packet */ - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4 + state->sbytes, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* Check all sbytes were sent */ - if(sbytes<0) { - failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - return CURLE_SEND_ERROR; - } - /* since this was a re-send, we remain at the still byte position */ - Curl_pgrsSetUploadCounter(data, k->writebytecount); - } - break; - - case TFTP_EVENT_ERROR: - state->state = TFTP_STATE_FIN; - setpacketevent(&state->spacket, TFTP_EVENT_ERROR); - setpacketblock(&state->spacket, state->block); - (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* don't bother with the return code, but if the socket is still up we - * should be a good TFTP client and let the server know we're done */ - state->state = TFTP_STATE_FIN; - break; - - default: - failf(data, "tftp_tx: internal error, event: %i", (int)(event)); - break; - } - - return result; -} - -/********************************************************** - * - * tftp_translate_code - * - * Translate internal error codes to CURL error codes - * - **********************************************************/ -static CURLcode tftp_translate_code(tftp_error_t error) -{ - CURLcode result = CURLE_OK; - - if(error != TFTP_ERR_NONE) { - switch(error) { - case TFTP_ERR_NOTFOUND: - result = CURLE_TFTP_NOTFOUND; - break; - case TFTP_ERR_PERM: - result = CURLE_TFTP_PERM; - break; - case TFTP_ERR_DISKFULL: - result = CURLE_REMOTE_DISK_FULL; - break; - case TFTP_ERR_UNDEF: - case TFTP_ERR_ILLEGAL: - result = CURLE_TFTP_ILLEGAL; - break; - case TFTP_ERR_UNKNOWNID: - result = CURLE_TFTP_UNKNOWNID; - break; - case TFTP_ERR_EXISTS: - result = CURLE_REMOTE_FILE_EXISTS; - break; - case TFTP_ERR_NOSUCHUSER: - result = CURLE_TFTP_NOSUCHUSER; - break; - case TFTP_ERR_TIMEOUT: - result = CURLE_OPERATION_TIMEDOUT; - break; - case TFTP_ERR_NORESPONSE: - result = CURLE_COULDNT_CONNECT; - break; - default: - result = CURLE_ABORTED_BY_CALLBACK; - break; - } - } - else - result = CURLE_OK; - - return result; -} - -/********************************************************** - * - * tftp_state_machine - * - * The tftp state machine event dispatcher - * - **********************************************************/ -static CURLcode tftp_state_machine(tftp_state_data_t *state, - tftp_event_t event) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = state->conn->data; - - switch(state->state) { - case TFTP_STATE_START: - DEBUGF(infof(data, "TFTP_STATE_START\n")); - result = tftp_send_first(state, event); - break; - case TFTP_STATE_RX: - DEBUGF(infof(data, "TFTP_STATE_RX\n")); - result = tftp_rx(state, event); - break; - case TFTP_STATE_TX: - DEBUGF(infof(data, "TFTP_STATE_TX\n")); - result = tftp_tx(state, event); - break; - case TFTP_STATE_FIN: - infof(data, "%s\n", "TFTP finished"); - break; - default: - DEBUGF(infof(data, "STATE: %d\n", state->state)); - failf(data, "%s", "Internal state machine error"); - result = CURLE_TFTP_ILLEGAL; - break; - } - - return result; -} - -/********************************************************** - * - * tftp_disconnect - * - * The disconnect callback - * - **********************************************************/ -static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection) -{ - tftp_state_data_t *state = conn->proto.tftpc; - (void) dead_connection; - - /* done, free dynamically allocated pkt buffers */ - if(state) { - Curl_safefree(state->rpacket.data); - Curl_safefree(state->spacket.data); - free(state); - } - - return CURLE_OK; -} - -/********************************************************** - * - * tftp_connect - * - * The connect callback - * - **********************************************************/ -static CURLcode tftp_connect(struct connectdata *conn, bool *done) -{ - tftp_state_data_t *state; - int blksize, rc; - - blksize = TFTP_BLKSIZE_DEFAULT; - - state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t)); - if(!state) - return CURLE_OUT_OF_MEMORY; - - /* alloc pkt buffers based on specified blksize */ - if(conn->data->set.tftp_blksize) { - blksize = (int)conn->data->set.tftp_blksize; - if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN) - return CURLE_TFTP_ILLEGAL; - } - - if(!state->rpacket.data) { - state->rpacket.data = calloc(1, blksize + 2 + 2); - - if(!state->rpacket.data) - return CURLE_OUT_OF_MEMORY; - } - - if(!state->spacket.data) { - state->spacket.data = calloc(1, blksize + 2 + 2); - - if(!state->spacket.data) - return CURLE_OUT_OF_MEMORY; - } - - /* we don't keep TFTP connections up basically because there's none or very - * little gain for UDP */ - connclose(conn, "TFTP"); - - state->conn = conn; - state->sockfd = state->conn->sock[FIRSTSOCKET]; - state->state = TFTP_STATE_START; - state->error = TFTP_ERR_NONE; - state->blksize = TFTP_BLKSIZE_DEFAULT; - state->requested_blksize = blksize; - - ((struct sockaddr *)&state->local_addr)->sa_family = - (unsigned short)(conn->ip_addr->ai_family); - - tftp_set_timeouts(state); - - if(!conn->bits.bound) { - /* If not already bound, bind to any interface, random UDP port. If it is - * reused or a custom local port was desired, this has already been done! - * - * We once used the size of the local_addr struct as the third argument - * for bind() to better work with IPv6 or whatever size the struct could - * have, but we learned that at least Tru64, AIX and IRIX *requires* the - * size of that argument to match the exact size of a 'sockaddr_in' struct - * when running IPv4-only. - * - * Therefore we use the size from the address we connected to, which we - * assume uses the same IP version and thus hopefully this works for both - * IPv4 and IPv6... - */ - rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr, - conn->ip_addr->ai_addrlen); - if(rc) { - failf(conn->data, "bind() failed; %s", - Curl_strerror(conn, SOCKERRNO)); - return CURLE_COULDNT_CONNECT; - } - conn->bits.bound = TRUE; - } - - Curl_pgrsStartNow(conn->data); - - *done = TRUE; - - return CURLE_OK; -} - -/********************************************************** - * - * tftp_done - * - * The done callback - * - **********************************************************/ -static CURLcode tftp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - CURLcode result = CURLE_OK; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; - - (void)status; /* unused */ - (void)premature; /* not used */ - - if(Curl_pgrsDone(conn)) - return CURLE_ABORTED_BY_CALLBACK; - - /* If we have encountered an error */ - if(state) - result = tftp_translate_code(state->error); - - return result; -} - -/********************************************************** - * - * tftp_getsock - * - * The getsock callback - * - **********************************************************/ -static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks) -{ - if(!numsocks) - return GETSOCK_BLANK; - - socks[0] = conn->sock[FIRSTSOCKET]; - - return GETSOCK_READSOCK(0); -} - -/********************************************************** - * - * tftp_receive_packet - * - * Called once select fires and data is ready on the socket - * - **********************************************************/ -static CURLcode tftp_receive_packet(struct connectdata *conn) -{ - struct Curl_sockaddr_storage fromaddr; - curl_socklen_t fromlen; - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; - struct SingleRequest *k = &data->req; - - /* Receive the packet */ - fromlen = sizeof(fromaddr); - state->rbytes = (int)recvfrom(state->sockfd, - (void *)state->rpacket.data, - state->blksize + 4, - 0, - (struct sockaddr *)&fromaddr, - &fromlen); - if(state->remote_addrlen == 0) { - memcpy(&state->remote_addr, &fromaddr, fromlen); - state->remote_addrlen = fromlen; - } - - /* Sanity check packet length */ - if(state->rbytes < 4) { - failf(data, "Received too short packet"); - /* Not a timeout, but how best to handle it? */ - state->event = TFTP_EVENT_TIMEOUT; - } - else { - /* The event is given by the TFTP packet time */ - unsigned short event = getrpacketevent(&state->rpacket); - state->event = (tftp_event_t)event; - - switch(state->event) { - case TFTP_EVENT_DATA: - /* Don't pass to the client empty or retransmitted packets */ - if(state->rbytes > 4 && - (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, - (char *)state->rpacket.data + 4, - state->rbytes-4); - if(result) { - tftp_state_machine(state, TFTP_EVENT_ERROR); - return result; - } - k->bytecount += state->rbytes-4; - Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount); - } - break; - case TFTP_EVENT_ERROR: - { - unsigned short error = getrpacketblock(&state->rpacket); - state->error = (tftp_error_t)error; - infof(data, "%s\n", (const char *)state->rpacket.data + 4); - break; - } - case TFTP_EVENT_ACK: - break; - case TFTP_EVENT_OACK: - result = tftp_parse_option_ack(state, - (const char *)state->rpacket.data + 2, - state->rbytes-2); - if(result) - return result; - break; - case TFTP_EVENT_RRQ: - case TFTP_EVENT_WRQ: - default: - failf(data, "%s", "Internal error: Unexpected packet"); - break; - } - - /* Update the progress meter */ - if(Curl_pgrsUpdate(conn)) { - tftp_state_machine(state, TFTP_EVENT_ERROR); - return CURLE_ABORTED_BY_CALLBACK; - } - } - return result; -} - -/********************************************************** - * - * tftp_state_timeout - * - * Check if timeouts have been reached - * - **********************************************************/ -static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) -{ - time_t current; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; - - if(event) - *event = TFTP_EVENT_NONE; - - time(¤t); - if(current > state->max_time) { - DEBUGF(infof(conn->data, "timeout: %ld > %ld\n", - (long)current, (long)state->max_time)); - state->error = TFTP_ERR_TIMEOUT; - state->state = TFTP_STATE_FIN; - return 0; - } - if(current > state->rx_time + state->retry_time) { - if(event) - *event = TFTP_EVENT_TIMEOUT; - time(&state->rx_time); /* update even though we received nothing */ - } - - /* there's a typecast below here since 'time_t' may in fact be larger than - 'long', but we estimate that a 'long' will still be able to hold number - of seconds even if "only" 32 bit */ - return (long)(state->max_time - current); -} - -/********************************************************** - * - * tftp_multi_statemach - * - * Handle single RX socket event and return - * - **********************************************************/ -static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) -{ - int rc; - tftp_event_t event; - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; - long timeout_ms = tftp_state_timeout(conn, &event); - - *done = FALSE; - - if(timeout_ms <= 0) { - failf(data, "TFTP response timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - if(event != TFTP_EVENT_NONE) { - result = tftp_state_machine(state, event); - if(result) - return result; - *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; - if(*done) - /* Tell curl we're done */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - } - else { - /* no timeouts to handle, check our socket */ - rc = SOCKET_READABLE(state->sockfd, 0); - - if(rc == -1) { - /* bail out */ - int error = SOCKERRNO; - failf(data, "%s", Curl_strerror(conn, error)); - state->event = TFTP_EVENT_ERROR; - } - else if(rc != 0) { - result = tftp_receive_packet(conn); - if(result) - return result; - result = tftp_state_machine(state, state->event); - if(result) - return result; - *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; - if(*done) - /* Tell curl we're done */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - } - /* if rc == 0, then select() timed out */ - } - - return result; -} - -/********************************************************** - * - * tftp_doing - * - * Called from multi.c while DOing - * - **********************************************************/ -static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done) -{ - CURLcode result; - result = tftp_multi_statemach(conn, dophase_done); - - if(*dophase_done) { - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - else if(!result) { - /* The multi code doesn't have this logic for the DOING state so we - provide it for TFTP since it may do the entire transfer in this - state. */ - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else - result = Curl_speedcheck(conn->data, Curl_tvnow()); - } - return result; -} - -/********************************************************** - * - * tftp_peform - * - * Entry point for transfer from tftp_do, sarts state mach - * - **********************************************************/ -static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) -{ - CURLcode result = CURLE_OK; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; - - *dophase_done = FALSE; - - result = tftp_state_machine(state, TFTP_EVENT_INIT); - - if((state->state == TFTP_STATE_FIN) || result) - return result; - - tftp_multi_statemach(conn, dophase_done); - - if(*dophase_done) - DEBUGF(infof(conn->data, "DO phase is complete\n")); - - return result; -} - - -/********************************************************** - * - * tftp_do - * - * The do callback - * - * This callback initiates the TFTP transfer - * - **********************************************************/ - -static CURLcode tftp_do(struct connectdata *conn, bool *done) -{ - tftp_state_data_t *state; - CURLcode result; - - *done = FALSE; - - if(!conn->proto.tftpc) { - result = tftp_connect(conn, done); - if(result) - return result; - } - - state = (tftp_state_data_t *)conn->proto.tftpc; - if(!state) - return CURLE_TFTP_ILLEGAL; - - result = tftp_perform(conn, done); - - /* If tftp_perform() returned an error, use that for return code. If it - was OK, see if tftp_translate_code() has an error. */ - if(!result) - /* If we have encountered an internal tftp error, translate it. */ - result = tftp_translate_code(state->error); - - return result; -} - -static CURLcode tftp_setup_connection(struct connectdata * conn) -{ - struct Curl_easy *data = conn->data; - char *type; - char command; - - conn->socktype = SOCK_DGRAM; /* UDP datagram based */ - - /* TFTP URLs support an extension like ";mode=" that - * we'll try to get now! */ - type = strstr(data->state.path, ";mode="); - - if(!type) - type = strstr(conn->host.rawalloc, ";mode="); - - if(type) { - *type = 0; /* it was in the middle of the hostname */ - command = Curl_raw_toupper(type[6]); - - switch(command) { - case 'A': /* ASCII mode */ - case 'N': /* NETASCII mode */ - data->set.prefer_ascii = TRUE; - break; - - case 'O': /* octet mode */ - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->set.prefer_ascii = FALSE; - break; - } - } - - return CURLE_OK; -} -#endif diff --git a/dep/cpr/opt/curl/lib/tftp.h b/dep/cpr/opt/curl/lib/tftp.h deleted file mode 100644 index c2325b2327c..00000000000 --- a/dep/cpr/opt/curl/lib/tftp.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef HEADER_CURL_TFTP_H -#define HEADER_CURL_TFTP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#ifndef CURL_DISABLE_TFTP -extern const struct Curl_handler Curl_handler_tftp; -#endif - -#endif /* HEADER_CURL_TFTP_H */ - diff --git a/dep/cpr/opt/curl/lib/timeval.c b/dep/cpr/opt/curl/lib/timeval.c deleted file mode 100644 index d7207b3a2af..00000000000 --- a/dep/cpr/opt/curl/lib/timeval.c +++ /dev/null @@ -1,162 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "timeval.h" - -#if defined(WIN32) && !defined(MSDOS) - -struct curltime curlx_tvnow(void) -{ - /* - ** GetTickCount() is available on _all_ Windows versions from W95 up - ** to nowadays. Returns milliseconds elapsed since last system boot, - ** increases monotonically and wraps once 49.7 days have elapsed. - */ - struct curltime now; -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ - (_WIN32_WINNT < _WIN32_WINNT_VISTA) - DWORD milliseconds = GetTickCount(); - now.tv_sec = milliseconds / 1000; - now.tv_usec = (milliseconds % 1000) * 1000; -#else - ULONGLONG milliseconds = GetTickCount64(); - now.tv_sec = (time_t) (milliseconds / 1000); - now.tv_usec = (unsigned int) (milliseconds % 1000) * 1000; -#endif - - return now; -} - -#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) - -struct curltime curlx_tvnow(void) -{ - /* - ** clock_gettime() is granted to be increased monotonically when the - ** monotonic clock is queried. Time starting point is unspecified, it - ** could be the system start-up time, the Epoch, or something else, - ** in any case the time starting point does not change once that the - ** system has started up. - */ - struct timeval now; - struct curltime cnow; - struct timespec tsnow; - if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) { - cnow.tv_sec = tsnow.tv_sec; - cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000); - } - /* - ** Even when the configure process has truly detected monotonic clock - ** availability, it might happen that it is not actually available at - ** run-time. When this occurs simply fallback to other time source. - */ -#ifdef HAVE_GETTIMEOFDAY - else { - (void)gettimeofday(&now, NULL); - cnow.tv_sec = now.tv_sec; - cnow.tv_usec = (unsigned int)now.tv_usec; - } -#else - else { - cnow.tv_sec = time(NULL); - cnow.tv_usec = 0; - } -#endif - return cnow; -} - -#elif defined(HAVE_GETTIMEOFDAY) - -struct curltime curlx_tvnow(void) -{ - /* - ** gettimeofday() is not granted to be increased monotonically, due to - ** clock drifting and external source time synchronization it can jump - ** forward or backward in time. - */ - struct timeval now; - struct curltime ret; - (void)gettimeofday(&now, NULL); - ret.tv_sec = now.tv_sec; - ret.tv_usec = now.tv_usec; - return ret; -} - -#else - -struct curltime curlx_tvnow(void) -{ - /* - ** time() returns the value of time in seconds since the Epoch. - */ - struct curltime now; - now.tv_sec = time(NULL); - now.tv_usec = 0; - return now; -} - -#endif - -/* - * Make sure that the first argument is the more recent time, as otherwise - * we'll get a weird negative time-diff back... - * - * Returns: the time difference in number of milliseconds. For large diffs it - * returns 0x7fffffff on 32bit time_t systems. - * - * @unittest: 1323 - */ -time_t curlx_tvdiff(struct curltime newer, struct curltime older) -{ -#if SIZEOF_TIME_T < 8 - /* for 32bit time_t systems, add a precaution to avoid overflow for really - big time differences */ - time_t diff = newer.tv_sec-older.tv_sec; - if(diff >= (0x7fffffff/1000)) - return 0x7fffffff; -#endif - return (newer.tv_sec-older.tv_sec)*1000+ - (int)(newer.tv_usec-older.tv_usec)/1000; -} - -/* - * Make sure that the first argument is the more recent time, as otherwise - * we'll get a weird negative time-diff back... - * - * Returns: the time difference in number of microseconds. For too large diffs - * it returns max value. - */ -time_t Curl_tvdiff_us(struct curltime newer, struct curltime older) -{ - time_t diff = newer.tv_sec-older.tv_sec; -#if SIZEOF_TIME_T < 8 - /* for 32bit time_t systems */ - if(diff >= (0x7fffffff/1000000)) - return 0x7fffffff; -#else - /* for 64bit time_t systems */ - if(diff >= (0x7fffffffffffffffLL/1000000)) - return 0x7fffffffffffffffLL; -#endif - return (newer.tv_sec-older.tv_sec)*1000000+ - (int)(newer.tv_usec-older.tv_usec); -} diff --git a/dep/cpr/opt/curl/lib/timeval.h b/dep/cpr/opt/curl/lib/timeval.h deleted file mode 100644 index 1ee4b304490..00000000000 --- a/dep/cpr/opt/curl/lib/timeval.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef HEADER_CURL_TIMEVAL_H -#define HEADER_CURL_TIMEVAL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * CAUTION: this header is designed to work when included by the app-side - * as well as the library. Do not mix with library internals! - */ - -#include "curl_setup.h" - -struct curltime { - time_t tv_sec; /* seconds */ - unsigned int tv_usec; /* microseconds */ -}; - -struct curltime curlx_tvnow(void); - -/* - * Make sure that the first argument (t1) is the more recent time and t2 is - * the older time, as otherwise you get a weird negative time-diff back... - * - * Returns: the time difference in number of milliseconds. - */ -time_t curlx_tvdiff(struct curltime t1, struct curltime t2); - -/* - * Make sure that the first argument (t1) is the more recent time and t2 is - * the older time, as otherwise you get a weird negative time-diff back... - * - * Returns: the time difference in number of microseconds. - */ -time_t Curl_tvdiff_us(struct curltime newer, struct curltime older); - -/* These two defines below exist to provide the older API for library - internals only. */ -#define Curl_tvnow() curlx_tvnow() -#define Curl_tvdiff(x,y) curlx_tvdiff(x,y) - -#endif /* HEADER_CURL_TIMEVAL_H */ - diff --git a/dep/cpr/opt/curl/lib/transfer.c b/dep/cpr/opt/curl/lib/transfer.c deleted file mode 100644 index 8e66d0d80ed..00000000000 --- a/dep/cpr/opt/curl/lib/transfer.c +++ /dev/null @@ -1,2070 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" -#include "strtoofft.h" - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_SIGNAL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#ifndef HAVE_SOCKET -#error "We can't compile without socket() support!" -#endif - -#include "urldata.h" -#include -#include "netrc.h" - -#include "content_encoding.h" -#include "hostip.h" -#include "transfer.h" -#include "sendf.h" -#include "speedcheck.h" -#include "progress.h" -#include "http.h" -#include "url.h" -#include "getinfo.h" -#include "vtls/vtls.h" -#include "select.h" -#include "multiif.h" -#include "connect.h" -#include "non-ascii.h" -#include "http2.h" -#include "mime.h" -#include "strcase.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ - !defined(CURL_DISABLE_IMAP) -/* - * checkheaders() checks the linked list of custom headers for a - * particular header (prefix). - * - * Returns a pointer to the first matching header or NULL if none matched. - */ -char *Curl_checkheaders(const struct connectdata *conn, - const char *thisheader) -{ - struct curl_slist *head; - size_t thislen = strlen(thisheader); - struct Curl_easy *data = conn->data; - - for(head = data->set.headers; head; head = head->next) { - if(strncasecompare(head->data, thisheader, thislen)) - return head->data; - } - - return NULL; -} -#endif - -/* - * This function will call the read callback to fill our buffer with data - * to upload. - */ -CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) -{ - struct Curl_easy *data = conn->data; - size_t buffersize = (size_t)bytes; - int nread; -#ifdef CURL_DOES_CONVERSIONS - bool sending_http_headers = FALSE; - - if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { - const struct HTTP *http = data->req.protop; - - if(http->sending == HTTPSEND_REQUEST) - /* We're sending the HTTP request headers, not the data. - Remember that so we don't re-translate them into garbage. */ - sending_http_headers = TRUE; - } -#endif - - if(data->req.upload_chunky) { - /* if chunked Transfer-Encoding */ - buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */ - data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */ - } - - /* this function returns a size_t, so we typecast to int to prevent warnings - with picky compilers */ - nread = (int)data->state.fread_func(data->req.upload_fromhere, 1, - buffersize, data->state.in); - - if(nread == CURL_READFUNC_ABORT) { - failf(data, "operation aborted by callback"); - *nreadp = 0; - return CURLE_ABORTED_BY_CALLBACK; - } - if(nread == CURL_READFUNC_PAUSE) { - struct SingleRequest *k = &data->req; - - if(conn->handler->flags & PROTOPT_NONETWORK) { - /* protocols that work without network cannot be paused. This is - actually only FILE:// just now, and it can't pause since the transfer - isn't done using the "normal" procedure. */ - failf(data, "Read callback asked for PAUSE when not supported!"); - return CURLE_READ_ERROR; - } - - /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ - k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ - if(data->req.upload_chunky) { - /* Back out the preallocation done above */ - data->req.upload_fromhere -= (8 + 2); - } - *nreadp = 0; - - return CURLE_OK; /* nothing was read */ - } - else if((size_t)nread > buffersize) { - /* the read function returned a too large value */ - *nreadp = 0; - failf(data, "read function returned funny value"); - return CURLE_READ_ERROR; - } - - if(!data->req.forbidchunk && data->req.upload_chunky) { - /* if chunked Transfer-Encoding - * build chunk: - * - * CRLF - * CRLF - */ - /* On non-ASCII platforms the may or may not be - translated based on set.prefer_ascii while the protocol - portion must always be translated to the network encoding. - To further complicate matters, line end conversion might be - done later on, so we need to prevent CRLFs from becoming - CRCRLFs if that's the case. To do this we use bare LFs - here, knowing they'll become CRLFs later on. - */ - - char hexbuffer[11]; - const char *endofline_native; - const char *endofline_network; - int hexlen; - - if( -#ifdef CURL_DO_LINEEND_CONV - (data->set.prefer_ascii) || -#endif - (data->set.crlf)) { - /* \n will become \r\n later on */ - endofline_native = "\n"; - endofline_network = "\x0a"; - } - else { - endofline_native = "\r\n"; - endofline_network = "\x0d\x0a"; - } - hexlen = snprintf(hexbuffer, sizeof(hexbuffer), - "%x%s", nread, endofline_native); - - /* move buffer pointer */ - data->req.upload_fromhere -= hexlen; - nread += hexlen; - - /* copy the prefix to the buffer, leaving out the NUL */ - memcpy(data->req.upload_fromhere, hexbuffer, hexlen); - - /* always append ASCII CRLF to the data */ - memcpy(data->req.upload_fromhere + nread, - endofline_network, - strlen(endofline_network)); - -#ifdef CURL_DOES_CONVERSIONS - { - CURLcode result; - int length; - if(data->set.prefer_ascii) - /* translate the protocol and data */ - length = nread; - else - /* just translate the protocol portion */ - length = (int)strlen(hexbuffer); - result = Curl_convert_to_network(data, data->req.upload_fromhere, - length); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(result) - return result; - } -#endif /* CURL_DOES_CONVERSIONS */ - - if((nread - hexlen) == 0) - /* mark this as done once this chunk is transferred */ - data->req.upload_done = TRUE; - - nread += (int)strlen(endofline_native); /* for the added end of line */ - } -#ifdef CURL_DOES_CONVERSIONS - else if((data->set.prefer_ascii) && (!sending_http_headers)) { - CURLcode result; - result = Curl_convert_to_network(data, data->req.upload_fromhere, nread); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(result) - return result; - } -#endif /* CURL_DOES_CONVERSIONS */ - - *nreadp = nread; - - return CURLE_OK; -} - - -/* - * Curl_readrewind() rewinds the read stream. This is typically used for HTTP - * POST/PUT with multi-pass authentication when a sending was denied and a - * resend is necessary. - */ -CURLcode Curl_readrewind(struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - curl_mimepart *mimepart = &data->set.mimepost; - - conn->bits.rewindaftersend = FALSE; /* we rewind now */ - - /* explicitly switch off sending data on this connection now since we are - about to restart a new transfer and thus we want to avoid inadvertently - sending more data on the existing connection until the next transfer - starts */ - data->req.keepon &= ~KEEP_SEND; - - /* We have sent away data. If not using CURLOPT_POSTFIELDS or - CURLOPT_HTTPPOST, call app to rewind - */ - if(conn->handler->protocol & PROTO_FAMILY_HTTP) { - struct HTTP *http = data->req.protop; - - if(http->sendit) - mimepart = http->sendit; - } - if(data->set.postfields) - ; /* do nothing */ - else if(data->set.httpreq == HTTPREQ_POST_MIME || - data->set.httpreq == HTTPREQ_POST_FORM) { - if(Curl_mime_rewind(mimepart)) { - failf(data, "Cannot rewind mime/post data"); - return CURLE_SEND_FAIL_REWIND; - } - } - else { - if(data->set.seek_func) { - int err; - - err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET); - if(err) { - failf(data, "seek callback returned error %d", (int)err); - return CURLE_SEND_FAIL_REWIND; - } - } - else if(data->set.ioctl_func) { - curlioerr err; - - err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD, - data->set.ioctl_client); - infof(data, "the ioctl callback returned %d\n", (int)err); - - if(err) { - /* FIXME: convert to a human readable error message */ - failf(data, "ioctl callback returned error %d", (int)err); - return CURLE_SEND_FAIL_REWIND; - } - } - else { - /* If no CURLOPT_READFUNCTION is used, we know that we operate on a - given FILE * stream and we can actually attempt to rewind that - ourselves with fseek() */ - if(data->state.fread_func == (curl_read_callback)fread) { - if(-1 != fseek(data->state.in, 0, SEEK_SET)) - /* successful rewind */ - return CURLE_OK; - } - - /* no callback set or failure above, makes us fail at once */ - failf(data, "necessary data rewind wasn't possible"); - return CURLE_SEND_FAIL_REWIND; - } - } - return CURLE_OK; -} - -static int data_pending(const struct connectdata *conn) -{ - /* in the case of libssh2, we can never be really sure that we have emptied - its internal buffers so we MUST always try until we get EAGAIN back */ - return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) || -#if defined(USE_NGHTTP2) - Curl_ssl_data_pending(conn, FIRSTSOCKET) || - /* For HTTP/2, we may read up everything including responde body - with header fields in Curl_http_readwrite_headers. If no - content-length is provided, curl waits for the connection - close, which we emulate it using conn->proto.httpc.closed = - TRUE. The thing is if we read everything, then http2_recv won't - be called and we cannot signal the HTTP/2 stream has closed. As - a workaround, we return nonzero here to call http2_recv. */ - ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20); -#else - Curl_ssl_data_pending(conn, FIRSTSOCKET); -#endif -} - -static void read_rewind(struct connectdata *conn, - size_t thismuch) -{ - DEBUGASSERT(conn->read_pos >= thismuch); - - conn->read_pos -= thismuch; - conn->bits.stream_was_rewound = TRUE; - -#ifdef DEBUGBUILD - { - char buf[512 + 1]; - size_t show; - - show = CURLMIN(conn->buf_len - conn->read_pos, sizeof(buf)-1); - if(conn->master_buffer) { - memcpy(buf, conn->master_buffer + conn->read_pos, show); - buf[show] = '\0'; - } - else { - buf[0] = '\0'; - } - - DEBUGF(infof(conn->data, - "Buffer after stream rewind (read_pos = %zu): [%s]\n", - conn->read_pos, buf)); - } -#endif -} - -/* - * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the - * remote document with the time provided by CURLOPT_TIMEVAL - */ -bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) -{ - if((timeofdoc == 0) || (data->set.timevalue == 0)) - return TRUE; - - switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: - default: - if(timeofdoc <= data->set.timevalue) { - infof(data, - "The requested document is not new enough\n"); - data->info.timecond = TRUE; - return FALSE; - } - break; - case CURL_TIMECOND_IFUNMODSINCE: - if(timeofdoc >= data->set.timevalue) { - infof(data, - "The requested document is not old enough\n"); - data->info.timecond = TRUE; - return FALSE; - } - break; - } - - return TRUE; -} - -/* - * Go ahead and do a read if we have a readable socket or if - * the stream was rewound (in which case we have data in a - * buffer) - * - * return '*comeback' TRUE if we didn't properly drain the socket so this - * function should get called again without select() or similar in between! - */ -static CURLcode readwrite_data(struct Curl_easy *data, - struct connectdata *conn, - struct SingleRequest *k, - int *didwhat, bool *done, - bool *comeback) -{ - CURLcode result = CURLE_OK; - ssize_t nread; /* number of bytes read */ - size_t excess = 0; /* excess bytes read */ - bool is_empty_data = FALSE; - bool readmore = FALSE; /* used by RTP to signal for more data */ - int maxloops = 100; - - *done = FALSE; - *comeback = FALSE; - - /* This is where we loop until we have read everything there is to - read or we get a CURLE_AGAIN */ - do { - size_t buffersize = data->set.buffer_size; - size_t bytestoread = buffersize; - - if( -#if defined(USE_NGHTTP2) - /* For HTTP/2, read data without caring about the content - length. This is safe because body in HTTP/2 is always - segmented thanks to its framing layer. Meanwhile, we have to - call Curl_read to ensure that http2_handle_stream_close is - called when we read all incoming bytes for a particular - stream. */ - !((conn->handler->protocol & PROTO_FAMILY_HTTP) && - conn->httpversion == 20) && -#endif - k->size != -1 && !k->header) { - /* make sure we don't read "too much" if we can help it since we - might be pipelining and then someone else might want to read what - follows! */ - curl_off_t totalleft = k->size - k->bytecount; - if(totalleft < (curl_off_t)bytestoread) - bytestoread = (size_t)totalleft; - } - - if(bytestoread) { - /* receive data from the network! */ - result = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread); - - /* read would've blocked */ - if(CURLE_AGAIN == result) - break; /* get out of loop */ - - if(result>0) - return result; - } - else { - /* read nothing but since we wanted nothing we consider this an OK - situation to proceed from */ - DEBUGF(infof(data, "readwrite_data: we're done!\n")); - nread = 0; - } - - if((k->bytecount == 0) && (k->writebytecount == 0)) { - Curl_pgrsTime(data, TIMER_STARTTRANSFER); - if(k->exp100 > EXP100_SEND_DATA) - /* set time stamp to compare with when waiting for the 100 */ - k->start100 = Curl_tvnow(); - } - - *didwhat |= KEEP_RECV; - /* indicates data of zero size, i.e. empty file */ - is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE; - - /* NUL terminate, allowing string ops to be used */ - if(0 < nread || is_empty_data) { - k->buf[nread] = 0; - } - else if(0 >= nread) { - /* if we receive 0 or less here, the server closed the connection - and we bail out from this! */ - DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n")); - k->keepon &= ~KEEP_RECV; - break; - } - - /* Default buffer to use when we write the buffer, it may be changed - in the flow below before the actual storing is done. */ - k->str = k->buf; - - if(conn->handler->readwrite) { - result = conn->handler->readwrite(data, conn, &nread, &readmore); - if(result) - return result; - if(readmore) - break; - } - -#ifndef CURL_DISABLE_HTTP - /* Since this is a two-state thing, we check if we are parsing - headers at the moment or not. */ - if(k->header) { - /* we are in parse-the-header-mode */ - bool stop_reading = FALSE; - result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading); - if(result) - return result; - - if(conn->handler->readwrite && - (k->maxdownload <= 0 && nread > 0)) { - result = conn->handler->readwrite(data, conn, &nread, &readmore); - if(result) - return result; - if(readmore) - break; - } - - if(stop_reading) { - /* We've stopped dealing with input, get out of the do-while loop */ - - if(nread > 0) { - if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { - infof(data, - "Rewinding stream by : %zd" - " bytes on url %s (zero-length body)\n", - nread, data->state.path); - read_rewind(conn, (size_t)nread); - } - else { - infof(data, - "Excess found in a non pipelined read:" - " excess = %zd" - " url = %s (zero-length body)\n", - nread, data->state.path); - } - } - - break; - } - } -#endif /* CURL_DISABLE_HTTP */ - - - /* This is not an 'else if' since it may be a rest from the header - parsing, where the beginning of the buffer is headers and the end - is non-headers. */ - if(k->str && !k->header && (nread > 0 || is_empty_data)) { - - if(data->set.opt_no_body) { - /* data arrives although we want none, bail out */ - streamclose(conn, "ignoring body"); - *done = TRUE; - return CURLE_WEIRD_SERVER_REPLY; - } - -#ifndef CURL_DISABLE_HTTP - if(0 == k->bodywrites && !is_empty_data) { - /* These checks are only made the first time we are about to - write a piece of the body */ - if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { - /* HTTP-only checks */ - - if(data->req.newurl) { - if(conn->bits.close) { - /* Abort after the headers if "follow Location" is set - and we're set to close anyway. */ - k->keepon &= ~KEEP_RECV; - *done = TRUE; - return CURLE_OK; - } - /* We have a new url to load, but since we want to be able - to re-use this connection properly, we read the full - response in "ignore more" */ - k->ignorebody = TRUE; - infof(data, "Ignoring the response-body\n"); - } - if(data->state.resume_from && !k->content_range && - (data->set.httpreq == HTTPREQ_GET) && - !k->ignorebody) { - - if(k->size == data->state.resume_from) { - /* The resume point is at the end of file, consider this fine - even if it doesn't allow resume from here. */ - infof(data, "The entire document is already downloaded"); - connclose(conn, "already downloaded"); - /* Abort download */ - k->keepon &= ~KEEP_RECV; - *done = TRUE; - return CURLE_OK; - } - - /* we wanted to resume a download, although the server doesn't - * seem to support this and we did this with a GET (if it - * wasn't a GET we did a POST or PUT resume) */ - failf(data, "HTTP server doesn't seem to support " - "byte ranges. Cannot resume."); - return CURLE_RANGE_ERROR; - } - - if(data->set.timecondition && !data->state.range) { - /* A time condition has been set AND no ranges have been - requested. This seems to be what chapter 13.3.4 of - RFC 2616 defines to be the correct action for a - HTTP/1.1 client */ - - if(!Curl_meets_timecondition(data, k->timeofdoc)) { - *done = TRUE; - /* We're simulating a http 304 from server so we return - what should have been returned from the server */ - data->info.httpcode = 304; - infof(data, "Simulate a HTTP 304 response!\n"); - /* we abort the transfer before it is completed == we ruin the - re-use ability. Close the connection */ - connclose(conn, "Simulated 304 handling"); - return CURLE_OK; - } - } /* we have a time condition */ - - } /* this is HTTP or RTSP */ - } /* this is the first time we write a body part */ -#endif /* CURL_DISABLE_HTTP */ - - k->bodywrites++; - - /* pass data to the debug function before it gets "dechunked" */ - if(data->set.verbose) { - if(k->badheader) { - Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff, - (size_t)k->hbuflen, conn); - if(k->badheader == HEADER_PARTHEADER) - Curl_debug(data, CURLINFO_DATA_IN, - k->str, (size_t)nread, conn); - } - else - Curl_debug(data, CURLINFO_DATA_IN, - k->str, (size_t)nread, conn); - } - -#ifndef CURL_DISABLE_HTTP - if(k->chunk) { - /* - * Here comes a chunked transfer flying and we need to decode this - * properly. While the name says read, this function both reads - * and writes away the data. The returned 'nread' holds the number - * of actual data it wrote to the client. - */ - - CHUNKcode res = - Curl_httpchunk_read(conn, k->str, nread, &nread); - - if(CHUNKE_OK < res) { - if(CHUNKE_WRITE_ERROR == res) { - failf(data, "Failed writing data"); - return CURLE_WRITE_ERROR; - } - failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res)); - return CURLE_RECV_ERROR; - } - if(CHUNKE_STOP == res) { - size_t dataleft; - /* we're done reading chunks! */ - k->keepon &= ~KEEP_RECV; /* read no more */ - - /* There are now possibly N number of bytes at the end of the - str buffer that weren't written to the client. - - We DO care about this data if we are pipelining. - Push it back to be read on the next pass. */ - - dataleft = conn->chunk.dataleft; - if(dataleft != 0) { - infof(conn->data, "Leftovers after chunking: %zu bytes\n", - dataleft); - if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { - /* only attempt the rewind if we truly are pipelining */ - infof(conn->data, "Rewinding %zu bytes\n",dataleft); - read_rewind(conn, dataleft); - } - } - } - /* If it returned OK, we just keep going */ - } -#endif /* CURL_DISABLE_HTTP */ - - /* Account for body content stored in the header buffer */ - if(k->badheader && !k->ignorebody) { - DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n", - k->hbuflen)); - k->bytecount += k->hbuflen; - } - - if((-1 != k->maxdownload) && - (k->bytecount + nread >= k->maxdownload)) { - - excess = (size_t)(k->bytecount + nread - k->maxdownload); - if(excess > 0 && !k->ignorebody) { - if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { - infof(data, - "Rewinding stream by : %zu" - " bytes on url %s (size = %" CURL_FORMAT_CURL_OFF_T - ", maxdownload = %" CURL_FORMAT_CURL_OFF_T - ", bytecount = %" CURL_FORMAT_CURL_OFF_T ", nread = %zd)\n", - excess, data->state.path, - k->size, k->maxdownload, k->bytecount, nread); - read_rewind(conn, excess); - } - else { - infof(data, - "Excess found in a non pipelined read:" - " excess = %zu" - ", size = %" CURL_FORMAT_CURL_OFF_T - ", maxdownload = %" CURL_FORMAT_CURL_OFF_T - ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n", - excess, k->size, k->maxdownload, k->bytecount); - } - } - - nread = (ssize_t) (k->maxdownload - k->bytecount); - if(nread < 0) /* this should be unusual */ - nread = 0; - - k->keepon &= ~KEEP_RECV; /* we're done reading */ - } - - k->bytecount += nread; - - Curl_pgrsSetDownloadCounter(data, k->bytecount); - - if(!k->chunk && (nread || k->badheader || is_empty_data)) { - /* If this is chunky transfer, it was already written */ - - if(k->badheader && !k->ignorebody) { - /* we parsed a piece of data wrongly assuming it was a header - and now we output it as body instead */ - - /* Don't let excess data pollute body writes */ - if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload) - result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, - k->hbuflen); - else - result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, - (size_t)k->maxdownload); - - if(result) - return result; - } - if(k->badheader < HEADER_ALLBAD) { - /* This switch handles various content encodings. If there's an - error here, be sure to check over the almost identical code - in http_chunks.c. - Make sure that ALL_CONTENT_ENCODINGS contains all the - encodings handled here. */ -#ifdef HAVE_LIBZ - switch(conn->data->set.http_ce_skip ? - IDENTITY : k->auto_decoding) { - case IDENTITY: -#endif - /* This is the default when the server sends no - Content-Encoding header. See Curl_readwrite_init; the - memset() call initializes k->auto_decoding to zero. */ - if(!k->ignorebody) { - -#ifndef CURL_DISABLE_POP3 - if(conn->handler->protocol&PROTO_FAMILY_POP3) - result = Curl_pop3_write(conn, k->str, nread); - else -#endif /* CURL_DISABLE_POP3 */ - - result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str, - nread); - } -#ifdef HAVE_LIBZ - break; - - case DEFLATE: - /* Assume CLIENTWRITE_BODY; headers are not encoded. */ - if(!k->ignorebody) - result = Curl_unencode_deflate_write(conn, k, nread); - break; - - case GZIP: - /* Assume CLIENTWRITE_BODY; headers are not encoded. */ - if(!k->ignorebody) - result = Curl_unencode_gzip_write(conn, k, nread); - break; - - default: - failf(data, "Unrecognized content encoding type. " - "libcurl understands `identity', `deflate' and `gzip' " - "content encodings."); - result = CURLE_BAD_CONTENT_ENCODING; - break; - } -#endif - } - k->badheader = HEADER_NORMAL; /* taken care of now */ - - if(result) - return result; - } - - } /* if(!header and data to read) */ - - if(conn->handler->readwrite && - (excess > 0 && !conn->bits.stream_was_rewound)) { - /* Parse the excess data */ - k->str += nread; - nread = (ssize_t)excess; - - result = conn->handler->readwrite(data, conn, &nread, &readmore); - if(result) - return result; - - if(readmore) - k->keepon |= KEEP_RECV; /* we're not done reading */ - break; - } - - if(is_empty_data) { - /* if we received nothing, the server closed the connection and we - are done */ - k->keepon &= ~KEEP_RECV; - } - - } while(data_pending(conn) && maxloops--); - - if(maxloops <= 0) { - /* we mark it as read-again-please */ - conn->cselect_bits = CURL_CSELECT_IN; - *comeback = TRUE; - } - - if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && - conn->bits.close) { - /* When we've read the entire thing and the close bit is set, the server - may now close the connection. If there's now any kind of sending going - on from our side, we need to stop that immediately. */ - infof(data, "we are done reading and this is set to close, stop send\n"); - k->keepon &= ~KEEP_SEND; /* no writing anymore either */ - } - - return CURLE_OK; -} - -static CURLcode done_sending(struct connectdata *conn, - struct SingleRequest *k) -{ - k->keepon &= ~KEEP_SEND; /* we're done writing */ - - Curl_http2_done_sending(conn); - - if(conn->bits.rewindaftersend) { - CURLcode result = Curl_readrewind(conn); - if(result) - return result; - } - return CURLE_OK; -} - - -/* - * Send data to upload to the server, when the socket is writable. - */ -static CURLcode readwrite_upload(struct Curl_easy *data, - struct connectdata *conn, - int *didwhat) -{ - ssize_t i, si; - ssize_t bytes_written; - CURLcode result; - ssize_t nread; /* number of bytes read */ - bool sending_http_headers = FALSE; - struct SingleRequest *k = &data->req; - - if((k->bytecount == 0) && (k->writebytecount == 0)) - Curl_pgrsTime(data, TIMER_STARTTRANSFER); - - *didwhat |= KEEP_SEND; - - do { - - /* only read more data if there's no upload data already - present in the upload buffer */ - if(0 == k->upload_present) { - /* init the "upload from here" pointer */ - k->upload_fromhere = data->state.uploadbuffer; - - if(!k->upload_done) { - /* HTTP pollution, this should be written nicer to become more - protocol agnostic. */ - int fillcount; - struct HTTP *http = k->protop; - - if((k->exp100 == EXP100_SENDING_REQUEST) && - (http->sending == HTTPSEND_BODY)) { - /* If this call is to send body data, we must take some action: - We have sent off the full HTTP 1.1 request, and we shall now - go into the Expect: 100 state and await such a header */ - k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */ - k->keepon &= ~KEEP_SEND; /* disable writing */ - k->start100 = Curl_tvnow(); /* timeout count starts now */ - *didwhat &= ~KEEP_SEND; /* we didn't write anything actually */ - - /* set a timeout for the multi interface */ - Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); - break; - } - - if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { - if(http->sending == HTTPSEND_REQUEST) - /* We're sending the HTTP request headers, not the data. - Remember that so we don't change the line endings. */ - sending_http_headers = TRUE; - else - sending_http_headers = FALSE; - } - - result = Curl_fillreadbuffer(conn, UPLOAD_BUFSIZE, &fillcount); - if(result) - return result; - - nread = (ssize_t)fillcount; - } - else - nread = 0; /* we're done uploading/reading */ - - if(!nread && (k->keepon & KEEP_SEND_PAUSE)) { - /* this is a paused transfer */ - break; - } - if(nread <= 0) { - result = done_sending(conn, k); - if(result) - return result; - break; - } - - /* store number of bytes available for upload */ - k->upload_present = nread; - - /* convert LF to CRLF if so asked */ - if((!sending_http_headers) && ( -#ifdef CURL_DO_LINEEND_CONV - /* always convert if we're FTPing in ASCII mode */ - (data->set.prefer_ascii) || -#endif - (data->set.crlf))) { - /* Do we need to allocate a scratch buffer? */ - if(!data->state.scratch) { - data->state.scratch = malloc(2 * data->set.buffer_size); - if(!data->state.scratch) { - failf(data, "Failed to alloc scratch buffer!"); - - return CURLE_OUT_OF_MEMORY; - } - } - - /* - * ASCII/EBCDIC Note: This is presumably a text (not binary) - * transfer so the data should already be in ASCII. - * That means the hex values for ASCII CR (0x0d) & LF (0x0a) - * must be used instead of the escape sequences \r & \n. - */ - for(i = 0, si = 0; i < nread; i++, si++) { - if(k->upload_fromhere[i] == 0x0a) { - data->state.scratch[si++] = 0x0d; - data->state.scratch[si] = 0x0a; - if(!data->set.crlf) { - /* we're here only because FTP is in ASCII mode... - bump infilesize for the LF we just added */ - if(data->state.infilesize != -1) - data->state.infilesize++; - } - } - else - data->state.scratch[si] = k->upload_fromhere[i]; - } - - if(si != nread) { - /* only perform the special operation if we really did replace - anything */ - nread = si; - - /* upload from the new (replaced) buffer instead */ - k->upload_fromhere = data->state.scratch; - - /* set the new amount too */ - k->upload_present = nread; - } - } - -#ifndef CURL_DISABLE_SMTP - if(conn->handler->protocol & PROTO_FAMILY_SMTP) { - result = Curl_smtp_escape_eob(conn, nread); - if(result) - return result; - } -#endif /* CURL_DISABLE_SMTP */ - } /* if 0 == k->upload_present */ - else { - /* We have a partial buffer left from a previous "round". Use - that instead of reading more data */ - } - - /* write to socket (send away data) */ - result = Curl_write(conn, - conn->writesockfd, /* socket to send to */ - k->upload_fromhere, /* buffer pointer */ - k->upload_present, /* buffer size */ - &bytes_written); /* actually sent */ - - if(result) - return result; - - if(data->set.verbose) - /* show the data before we change the pointer upload_fromhere */ - Curl_debug(data, CURLINFO_DATA_OUT, k->upload_fromhere, - (size_t)bytes_written, conn); - - k->writebytecount += bytes_written; - - if(k->writebytecount == data->state.infilesize) { - /* we have sent all data we were supposed to */ - k->upload_done = TRUE; - infof(data, "We are completely uploaded and fine\n"); - } - - if(k->upload_present != bytes_written) { - /* we only wrote a part of the buffer (if anything), deal with it! */ - - /* store the amount of bytes left in the buffer to write */ - k->upload_present -= bytes_written; - - /* advance the pointer where to find the buffer when the next send - is to happen */ - k->upload_fromhere += bytes_written; - } - else { - /* we've uploaded that buffer now */ - k->upload_fromhere = data->state.uploadbuffer; - k->upload_present = 0; /* no more bytes left */ - - if(k->upload_done) { - result = done_sending(conn, k); - if(result) - return result; - } - } - - Curl_pgrsSetUploadCounter(data, k->writebytecount); - - } WHILE_FALSE; /* just to break out from! */ - - return CURLE_OK; -} - -/* - * Curl_readwrite() is the low-level function to be called when data is to - * be read and written to/from the connection. - * - * return '*comeback' TRUE if we didn't properly drain the socket so this - * function should get called again without select() or similar in between! - */ -CURLcode Curl_readwrite(struct connectdata *conn, - struct Curl_easy *data, - bool *done, - bool *comeback) -{ - struct SingleRequest *k = &data->req; - CURLcode result; - int didwhat = 0; - - curl_socket_t fd_read; - curl_socket_t fd_write; - int select_res = conn->cselect_bits; - - conn->cselect_bits = 0; - - /* only use the proper socket if the *_HOLD bit is not set simultaneously as - then we are in rate limiting state in that transfer direction */ - - if((k->keepon & KEEP_RECVBITS) == KEEP_RECV) - fd_read = conn->sockfd; - else - fd_read = CURL_SOCKET_BAD; - - if((k->keepon & KEEP_SENDBITS) == KEEP_SEND) - fd_write = conn->writesockfd; - else - fd_write = CURL_SOCKET_BAD; - - if(conn->data->state.drain) { - select_res |= CURL_CSELECT_IN; - DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n")); - } - - if(!select_res) /* Call for select()/poll() only, if read/write/error - status is not known. */ - select_res = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0); - - if(select_res == CURL_CSELECT_ERR) { - failf(data, "select/poll returned error"); - return CURLE_SEND_ERROR; - } - - /* We go ahead and do a read if we have a readable socket or if - the stream was rewound (in which case we have data in a - buffer) */ - if((k->keepon & KEEP_RECV) && - ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { - - result = readwrite_data(data, conn, k, &didwhat, done, comeback); - if(result || *done) - return result; - } - - /* If we still have writing to do, we check if we have a writable socket. */ - if((k->keepon & KEEP_SEND) && (select_res & CURL_CSELECT_OUT)) { - /* write */ - - result = readwrite_upload(data, conn, &didwhat); - if(result) - return result; - } - - k->now = Curl_tvnow(); - if(didwhat) { - /* Update read/write counters */ - if(k->bytecountp) - *k->bytecountp = k->bytecount; /* read count */ - if(k->writebytecountp) - *k->writebytecountp = k->writebytecount; /* write count */ - } - else { - /* no read no write, this is a timeout? */ - if(k->exp100 == EXP100_AWAITING_CONTINUE) { - /* This should allow some time for the header to arrive, but only a - very short time as otherwise it'll be too much wasted time too - often. */ - - /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status": - - Therefore, when a client sends this header field to an origin server - (possibly via a proxy) from which it has never seen a 100 (Continue) - status, the client SHOULD NOT wait for an indefinite period before - sending the request body. - - */ - - time_t ms = Curl_tvdiff(k->now, k->start100); - if(ms >= data->set.expect_100_timeout) { - /* we've waited long enough, continue anyway */ - k->exp100 = EXP100_SEND_DATA; - k->keepon |= KEEP_SEND; - Curl_expire_done(data, EXPIRE_100_TIMEOUT); - infof(data, "Done waiting for 100-continue\n"); - } - } - } - - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else - result = Curl_speedcheck(data, k->now); - if(result) - return result; - - if(k->keepon) { - if(0 > Curl_timeleft(data, &k->now, FALSE)) { - if(k->size != -1) { - failf(data, "Operation timed out after %ld milliseconds with %" - CURL_FORMAT_CURL_OFF_T " out of %" - CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount, - k->size); - } - else { - failf(data, "Operation timed out after %ld milliseconds with %" - CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount); - } - return CURLE_OPERATION_TIMEDOUT; - } - } - else { - /* - * The transfer has been performed. Just make some general checks before - * returning. - */ - - if(!(data->set.opt_no_body) && (k->size != -1) && - (k->bytecount != k->size) && -#ifdef CURL_DO_LINEEND_CONV - /* Most FTP servers don't adjust their file SIZE response for CRLFs, - so we'll check to see if the discrepancy can be explained - by the number of CRLFs we've changed to LFs. - */ - (k->bytecount != (k->size + data->state.crlf_conversions)) && -#endif /* CURL_DO_LINEEND_CONV */ - !k->newurl) { - failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T - " bytes remaining to read", k->size - k->bytecount); - return CURLE_PARTIAL_FILE; - } - if(!(data->set.opt_no_body) && k->chunk && - (conn->chunk.state != CHUNK_STOP)) { - /* - * In chunked mode, return an error if the connection is closed prior to - * the empty (terminating) chunk is read. - * - * The condition above used to check for - * conn->proto.http->chunk.datasize != 0 which is true after reading - * *any* chunk, not just the empty chunk. - * - */ - failf(data, "transfer closed with outstanding read data remaining"); - return CURLE_PARTIAL_FILE; - } - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - } - - /* Now update the "done" boolean we return */ - *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND| - KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE; - - return CURLE_OK; -} - -/* - * Curl_single_getsock() gets called by the multi interface code when the app - * has requested to get the sockets for the current connection. This function - * will then be called once for every connection that the multi interface - * keeps track of. This function will only be called for connections that are - * in the proper state to have this information available. - */ -int Curl_single_getsock(const struct connectdata *conn, - curl_socket_t *sock, /* points to numsocks number - of sockets */ - int numsocks) -{ - const struct Curl_easy *data = conn->data; - int bitmap = GETSOCK_BLANK; - unsigned sockindex = 0; - - if(conn->handler->perform_getsock) - return conn->handler->perform_getsock(conn, sock, numsocks); - - if(numsocks < 2) - /* simple check but we might need two slots */ - return GETSOCK_BLANK; - - /* don't include HOLD and PAUSE connections */ - if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) { - - DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD); - - bitmap |= GETSOCK_READSOCK(sockindex); - sock[sockindex] = conn->sockfd; - } - - /* don't include HOLD and PAUSE connections */ - if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) { - - if((conn->sockfd != conn->writesockfd) || - bitmap == GETSOCK_BLANK) { - /* only if they are not the same socket and we have a readable - one, we increase index */ - if(bitmap != GETSOCK_BLANK) - sockindex++; /* increase index if we need two entries */ - - DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); - - sock[sockindex] = conn->writesockfd; - } - - bitmap |= GETSOCK_WRITESOCK(sockindex); - } - - return bitmap; -} - -/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT - which means this gets called once for each subsequent redirect etc */ -void Curl_init_CONNECT(struct Curl_easy *data) -{ - data->state.fread_func = data->set.fread_func_set; - data->state.in = data->set.in_set; -} - -/* - * Curl_pretransfer() is called immediately before a transfer starts, and only - * once for one transfer no matter if it has redirects or do multi-pass - * authentication etc. - */ -CURLcode Curl_pretransfer(struct Curl_easy *data) -{ - CURLcode result; - if(!data->change.url) { - /* we can't do anything without URL */ - failf(data, "No URL set!"); - return CURLE_URL_MALFORMAT; - } - /* since the URL may have been redirected in a previous use of this handle */ - if(data->change.url_alloc) { - /* the already set URL is allocated, free it first! */ - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - data->change.url = data->set.str[STRING_SET_URL]; - - /* Init the SSL session ID cache here. We do it here since we want to do it - after the *_setopt() calls (that could specify the size of the cache) but - before any transfer takes place. */ - result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions); - if(result) - return result; - - data->set.followlocation = 0; /* reset the location-follow counter */ - data->state.this_is_a_follow = FALSE; /* reset this */ - data->state.errorbuf = FALSE; /* no error has occurred */ - data->state.httpversion = 0; /* don't assume any particular server version */ - - data->state.authproblem = FALSE; - data->state.authhost.want = data->set.httpauth; - data->state.authproxy.want = data->set.proxyauth; - Curl_safefree(data->info.wouldredirect); - data->info.wouldredirect = NULL; - - if(data->set.httpreq == HTTPREQ_PUT) - data->state.infilesize = data->set.filesize; - else { - data->state.infilesize = data->set.postfieldsize; - if(data->set.postfields && (data->state.infilesize == -1)) - data->state.infilesize = (curl_off_t)strlen(data->set.postfields); - } - - /* If there is a list of cookie files to read, do it now! */ - if(data->change.cookielist) - Curl_cookie_loadfiles(data); - - /* If there is a list of host pairs to deal with */ - if(data->change.resolve) - result = Curl_loadhostpairs(data); - - if(!result) { - /* Allow data->set.use_port to set which port to use. This needs to be - * disabled for example when we follow Location: headers to URLs using - * different ports! */ - data->state.allow_port = TRUE; - -#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) - /************************************************************* - * Tell signal handler to ignore SIGPIPE - *************************************************************/ - if(!data->set.no_signal) - data->state.prev_signal = signal(SIGPIPE, SIG_IGN); -#endif - - Curl_initinfo(data); /* reset session-specific information "variables" */ - Curl_pgrsResetTransferSizes(data); - Curl_pgrsStartNow(data); - - if(data->set.timeout) - Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT); - - if(data->set.connecttimeout) - Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT); - - /* In case the handle is re-used and an authentication method was picked - in the session we need to make sure we only use the one(s) we now - consider to be fine */ - data->state.authhost.picked &= data->state.authhost.want; - data->state.authproxy.picked &= data->state.authproxy.want; - - if(data->set.wildcardmatch) { - struct WildcardData *wc = &data->wildcard; - if(wc->state < CURLWC_INIT) { - result = Curl_wildcard_init(wc); /* init wildcard structures */ - if(result) - return CURLE_OUT_OF_MEMORY; - } - } - } - - return result; -} - -/* - * Curl_posttransfer() is called immediately after a transfer ends - */ -CURLcode Curl_posttransfer(struct Curl_easy *data) -{ -#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) - /* restore the signal handler for SIGPIPE before we get back */ - if(!data->set.no_signal) - signal(SIGPIPE, data->state.prev_signal); -#else - (void)data; /* unused parameter */ -#endif - - return CURLE_OK; -} - -#ifndef CURL_DISABLE_HTTP -/* - * Find the separator at the end of the host name, or the '?' in cases like - * http://www.url.com?id=2380 - */ -static const char *find_host_sep(const char *url) -{ - const char *sep; - const char *query; - - /* Find the start of the hostname */ - sep = strstr(url, "//"); - if(!sep) - sep = url; - else - sep += 2; - - query = strchr(sep, '?'); - sep = strchr(sep, '/'); - - if(!sep) - sep = url + strlen(url); - - if(!query) - query = url + strlen(url); - - return sep < query ? sep : query; -} - -/* - * strlen_url() returns the length of the given URL if the spaces within the - * URL were properly URL encoded. - * URL encoding should be skipped for host names, otherwise IDN resolution - * will fail. - */ -static size_t strlen_url(const char *url, bool relative) -{ - const unsigned char *ptr; - size_t newlen = 0; - bool left = TRUE; /* left side of the ? */ - const unsigned char *host_sep = (const unsigned char *) url; - - if(!relative) - host_sep = (const unsigned char *) find_host_sep(url); - - for(ptr = (unsigned char *)url; *ptr; ptr++) { - - if(ptr < host_sep) { - ++newlen; - continue; - } - - switch(*ptr) { - case '?': - left = FALSE; - /* fall through */ - default: - if(*ptr >= 0x80) - newlen += 2; - newlen++; - break; - case ' ': - if(left) - newlen += 3; - else - newlen++; - break; - } - } - return newlen; -} - -/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in - * the source URL accordingly. - * URL encoding should be skipped for host names, otherwise IDN resolution - * will fail. - */ -static void strcpy_url(char *output, const char *url, bool relative) -{ - /* we must add this with whitespace-replacing */ - bool left = TRUE; - const unsigned char *iptr; - char *optr = output; - const unsigned char *host_sep = (const unsigned char *) url; - - if(!relative) - host_sep = (const unsigned char *) find_host_sep(url); - - for(iptr = (unsigned char *)url; /* read from here */ - *iptr; /* until zero byte */ - iptr++) { - - if(iptr < host_sep) { - *optr++ = *iptr; - continue; - } - - switch(*iptr) { - case '?': - left = FALSE; - /* fall through */ - default: - if(*iptr >= 0x80) { - snprintf(optr, 4, "%%%02x", *iptr); - optr += 3; - } - else - *optr++=*iptr; - break; - case ' ': - if(left) { - *optr++='%'; /* add a '%' */ - *optr++='2'; /* add a '2' */ - *optr++='0'; /* add a '0' */ - } - else - *optr++='+'; /* add a '+' here */ - break; - } - } - *optr = 0; /* zero terminate output buffer */ - -} - -/* - * Returns true if the given URL is absolute (as opposed to relative) - */ -static bool is_absolute_url(const char *url) -{ - char prot[16]; /* URL protocol string storage */ - char letter; /* used for a silly sscanf */ - - return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE; -} - -/* - * Concatenate a relative URL to a base URL making it absolute. - * URL-encodes any spaces. - * The returned pointer must be freed by the caller unless NULL - * (returns NULL on out of memory). - */ -static char *concat_url(const char *base, const char *relurl) -{ - /*** - TRY to append this new path to the old URL - to the right of the host part. Oh crap, this is doomed to cause - problems in the future... - */ - char *newest; - char *protsep; - char *pathsep; - size_t newlen; - bool host_changed = FALSE; - - const char *useurl = relurl; - size_t urllen; - - /* we must make our own copy of the URL to play with, as it may - point to read-only data */ - char *url_clone = strdup(base); - - if(!url_clone) - return NULL; /* skip out of this NOW */ - - /* protsep points to the start of the host name */ - protsep = strstr(url_clone, "//"); - if(!protsep) - protsep = url_clone; - else - protsep += 2; /* pass the slashes */ - - if('/' != relurl[0]) { - int level = 0; - - /* First we need to find out if there's a ?-letter in the URL, - and cut it and the right-side of that off */ - pathsep = strchr(protsep, '?'); - if(pathsep) - *pathsep = 0; - - /* we have a relative path to append to the last slash if there's one - available, or if the new URL is just a query string (starts with a - '?') we append the new one at the end of the entire currently worked - out URL */ - if(useurl[0] != '?') { - pathsep = strrchr(protsep, '/'); - if(pathsep) - *pathsep = 0; - } - - /* Check if there's any slash after the host name, and if so, remember - that position instead */ - pathsep = strchr(protsep, '/'); - if(pathsep) - protsep = pathsep + 1; - else - protsep = NULL; - - /* now deal with one "./" or any amount of "../" in the newurl - and act accordingly */ - - if((useurl[0] == '.') && (useurl[1] == '/')) - useurl += 2; /* just skip the "./" */ - - while((useurl[0] == '.') && - (useurl[1] == '.') && - (useurl[2] == '/')) { - level++; - useurl += 3; /* pass the "../" */ - } - - if(protsep) { - while(level--) { - /* cut off one more level from the right of the original URL */ - pathsep = strrchr(protsep, '/'); - if(pathsep) - *pathsep = 0; - else { - *protsep = 0; - break; - } - } - } - } - else { - /* We got a new absolute path for this server */ - - if((relurl[0] == '/') && (relurl[1] == '/')) { - /* the new URL starts with //, just keep the protocol part from the - original one */ - *protsep = 0; - useurl = &relurl[2]; /* we keep the slashes from the original, so we - skip the new ones */ - host_changed = TRUE; - } - else { - /* cut off the original URL from the first slash, or deal with URLs - without slash */ - pathsep = strchr(protsep, '/'); - if(pathsep) { - /* When people use badly formatted URLs, such as - "http://www.url.com?dir=/home/daniel" we must not use the first - slash, if there's a ?-letter before it! */ - char *sep = strchr(protsep, '?'); - if(sep && (sep < pathsep)) - pathsep = sep; - *pathsep = 0; - } - else { - /* There was no slash. Now, since we might be operating on a badly - formatted URL, such as "http://www.url.com?id=2380" which doesn't - use a slash separator as it is supposed to, we need to check for a - ?-letter as well! */ - pathsep = strchr(protsep, '?'); - if(pathsep) - *pathsep = 0; - } - } - } - - /* If the new part contains a space, this is a mighty stupid redirect - but we still make an effort to do "right". To the left of a '?' - letter we replace each space with %20 while it is replaced with '+' - on the right side of the '?' letter. - */ - newlen = strlen_url(useurl, !host_changed); - - urllen = strlen(url_clone); - - newest = malloc(urllen + 1 + /* possible slash */ - newlen + 1 /* zero byte */); - - if(!newest) { - free(url_clone); /* don't leak this */ - return NULL; - } - - /* copy over the root url part */ - memcpy(newest, url_clone, urllen); - - /* check if we need to append a slash */ - if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0])) - ; - else - newest[urllen++]='/'; - - /* then append the new piece on the right side */ - strcpy_url(&newest[urllen], useurl, !host_changed); - - free(url_clone); - - return newest; -} -#endif /* CURL_DISABLE_HTTP */ - -/* - * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string - * as given by the remote server and set up the new URL to request. - */ -CURLcode Curl_follow(struct Curl_easy *data, - char *newurl, /* the Location: string */ - followtype type) /* see transfer.h */ -{ -#ifdef CURL_DISABLE_HTTP - (void)data; - (void)newurl; - (void)type; - /* Location: following will not happen when HTTP is disabled */ - return CURLE_TOO_MANY_REDIRECTS; -#else - - /* Location: redirect */ - bool disallowport = FALSE; - bool reachedmax = FALSE; - - if(type == FOLLOW_REDIR) { - if((data->set.maxredirs != -1) && - (data->set.followlocation >= data->set.maxredirs)) { - reachedmax = TRUE; - type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected - to URL */ - } - else { - /* mark the next request as a followed location: */ - data->state.this_is_a_follow = TRUE; - - data->set.followlocation++; /* count location-followers */ - - if(data->set.http_auto_referer) { - /* We are asked to automatically set the previous URL as the referer - when we get the next URL. We pick the ->url field, which may or may - not be 100% correct */ - - if(data->change.referer_alloc) { - Curl_safefree(data->change.referer); - data->change.referer_alloc = FALSE; - } - - data->change.referer = strdup(data->change.url); - if(!data->change.referer) - return CURLE_OUT_OF_MEMORY; - data->change.referer_alloc = TRUE; /* yes, free this later */ - } - } - } - - if(!is_absolute_url(newurl)) { - /*** - *DANG* this is an RFC 2068 violation. The URL is supposed - to be absolute and this doesn't seem to be that! - */ - char *absolute = concat_url(data->change.url, newurl); - if(!absolute) - return CURLE_OUT_OF_MEMORY; - newurl = absolute; - } - else { - /* The new URL MAY contain space or high byte values, that means a mighty - stupid redirect URL but we still make an effort to do "right". */ - char *newest; - size_t newlen = strlen_url(newurl, FALSE); - - /* This is an absolute URL, don't allow the custom port number */ - disallowport = TRUE; - - newest = malloc(newlen + 1); /* get memory for this */ - if(!newest) - return CURLE_OUT_OF_MEMORY; - - strcpy_url(newest, newurl, FALSE); /* create a space-free URL */ - newurl = newest; /* use this instead now */ - - } - - if(type == FOLLOW_FAKE) { - /* we're only figuring out the new url if we would've followed locations - but now we're done so we can get out! */ - data->info.wouldredirect = newurl; - - if(reachedmax) { - failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); - return CURLE_TOO_MANY_REDIRECTS; - } - return CURLE_OK; - } - - if(disallowport) - data->state.allow_port = FALSE; - - if(data->change.url_alloc) { - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - - data->change.url = newurl; - data->change.url_alloc = TRUE; - - infof(data, "Issue another request to this URL: '%s'\n", data->change.url); - - /* - * We get here when the HTTP code is 300-399 (and 401). We need to perform - * differently based on exactly what return code there was. - * - * News from 7.10.6: we can also get here on a 401 or 407, in case we act on - * a HTTP (proxy-) authentication scheme other than Basic. - */ - switch(data->info.httpcode) { - /* 401 - Act on a WWW-Authenticate, we keep on moving and do the - Authorization: XXXX header in the HTTP request code snippet */ - /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the - Proxy-Authorization: XXXX header in the HTTP request code snippet */ - /* 300 - Multiple Choices */ - /* 306 - Not used */ - /* 307 - Temporary Redirect */ - default: /* for all above (and the unknown ones) */ - /* Some codes are explicitly mentioned since I've checked RFC2616 and they - * seem to be OK to POST to. - */ - break; - case 301: /* Moved Permanently */ - /* (quote from RFC7231, section 6.4.2) - * - * Note: For historical reasons, a user agent MAY change the request - * method from POST to GET for the subsequent request. If this - * behavior is undesired, the 307 (Temporary Redirect) status code - * can be used instead. - * - * ---- - * - * Many webservers expect this, so these servers often answers to a POST - * request with an error page. To be sure that libcurl gets the page that - * most user agents would get, libcurl has to force GET. - * - * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and - * can be overridden with CURLOPT_POSTREDIR. - */ - if((data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM - || data->set.httpreq == HTTPREQ_POST_MIME) - && !(data->set.keep_post & CURL_REDIR_POST_301)) { - infof(data, "Switch from POST to GET\n"); - data->set.httpreq = HTTPREQ_GET; - } - break; - case 302: /* Found */ - /* (quote from RFC7231, section 6.4.3) - * - * Note: For historical reasons, a user agent MAY change the request - * method from POST to GET for the subsequent request. If this - * behavior is undesired, the 307 (Temporary Redirect) status code - * can be used instead. - * - * ---- - * - * Many webservers expect this, so these servers often answers to a POST - * request with an error page. To be sure that libcurl gets the page that - * most user agents would get, libcurl has to force GET. - * - * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and - * can be overridden with CURLOPT_POSTREDIR. - */ - if((data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM - || data->set.httpreq == HTTPREQ_POST_MIME) - && !(data->set.keep_post & CURL_REDIR_POST_302)) { - infof(data, "Switch from POST to GET\n"); - data->set.httpreq = HTTPREQ_GET; - } - break; - - case 303: /* See Other */ - /* Disable both types of POSTs, unless the user explicitly - asks for POST after POST */ - if(data->set.httpreq != HTTPREQ_GET - && !(data->set.keep_post & CURL_REDIR_POST_303)) { - data->set.httpreq = HTTPREQ_GET; /* enforce GET request */ - infof(data, "Disables POST, goes with %s\n", - data->set.opt_no_body?"HEAD":"GET"); - } - break; - case 304: /* Not Modified */ - /* 304 means we did a conditional request and it was "Not modified". - * We shouldn't get any Location: header in this response! - */ - break; - case 305: /* Use Proxy */ - /* (quote from RFC2616, section 10.3.6): - * "The requested resource MUST be accessed through the proxy given - * by the Location field. The Location field gives the URI of the - * proxy. The recipient is expected to repeat this single request - * via the proxy. 305 responses MUST only be generated by origin - * servers." - */ - break; - } - Curl_pgrsTime(data, TIMER_REDIRECT); - Curl_pgrsResetTransferSizes(data); - - return CURLE_OK; -#endif /* CURL_DISABLE_HTTP */ -} - -/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted. - - NOTE: that the *url is malloc()ed. */ -CURLcode Curl_retry_request(struct connectdata *conn, - char **url) -{ - struct Curl_easy *data = conn->data; - - *url = NULL; - - /* if we're talking upload, we can't do the checks below, unless the protocol - is HTTP as when uploading over HTTP we will still get a response */ - if(data->set.upload && - !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) - return CURLE_OK; - - if((data->req.bytecount + data->req.headerbytecount == 0) && - conn->bits.reuse && - (!data->set.opt_no_body - || (conn->handler->protocol & PROTO_FAMILY_HTTP)) && - (data->set.rtspreq != RTSPREQ_RECEIVE)) { - /* We got no data, we attempted to re-use a connection. For HTTP this - can be a retry so we try again regardless if we expected a body. - For other protocols we only try again only if we expected a body. - - This might happen if the connection was left alive when we were - done using it before, but that was closed when we wanted to read from - it again. Bad luck. Retry the same request on a fresh connect! */ - infof(conn->data, "Connection died, retrying a fresh connect\n"); - *url = strdup(conn->data->change.url); - if(!*url) - return CURLE_OUT_OF_MEMORY; - - connclose(conn, "retry"); /* close this connection */ - conn->bits.retry = TRUE; /* mark this as a connection we're about - to retry. Marking it this way should - prevent i.e HTTP transfers to return - error just because nothing has been - transferred! */ - - - if(conn->handler->protocol&PROTO_FAMILY_HTTP) { - struct HTTP *http = data->req.protop; - if(http->writebytecount) - return Curl_readrewind(conn); - } - } - return CURLE_OK; -} - -/* - * Curl_setup_transfer() is called to setup some basic properties for the - * upcoming transfer. - */ -void -Curl_setup_transfer( - struct connectdata *conn, /* connection data */ - int sockindex, /* socket index to read from or -1 */ - curl_off_t size, /* -1 if unknown at this point */ - bool getheader, /* TRUE if header parsing is wanted */ - curl_off_t *bytecountp, /* return number of bytes read or NULL */ - int writesockindex, /* socket index to write to, it may very well be - the same we read from. -1 disables */ - curl_off_t *writecountp /* return number of bytes written or NULL */ - ) -{ - struct Curl_easy *data; - struct SingleRequest *k; - - DEBUGASSERT(conn != NULL); - - data = conn->data; - k = &data->req; - - DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); - - /* now copy all input parameters */ - conn->sockfd = sockindex == -1 ? - CURL_SOCKET_BAD : conn->sock[sockindex]; - conn->writesockfd = writesockindex == -1 ? - CURL_SOCKET_BAD:conn->sock[writesockindex]; - k->getheader = getheader; - - k->size = size; - k->bytecountp = bytecountp; - k->writebytecountp = writecountp; - - /* The code sequence below is placed in this function just because all - necessary input is not always known in do_complete() as this function may - be called after that */ - - if(!k->getheader) { - k->header = FALSE; - if(size > 0) - Curl_pgrsSetDownloadSize(data, size); - } - /* we want header and/or body, if neither then don't do this! */ - if(k->getheader || !data->set.opt_no_body) { - - if(conn->sockfd != CURL_SOCKET_BAD) - k->keepon |= KEEP_RECV; - - if(conn->writesockfd != CURL_SOCKET_BAD) { - struct HTTP *http = data->req.protop; - /* HTTP 1.1 magic: - - Even if we require a 100-return code before uploading data, we might - need to write data before that since the REQUEST may not have been - finished sent off just yet. - - Thus, we must check if the request has been sent before we set the - state info where we wait for the 100-return code - */ - if((data->state.expect100header) && - (conn->handler->protocol&PROTO_FAMILY_HTTP) && - (http->sending == HTTPSEND_BODY)) { - /* wait with write until we either got 100-continue or a timeout */ - k->exp100 = EXP100_AWAITING_CONTINUE; - k->start100 = Curl_tvnow(); - - /* Set a timeout for the multi interface. Add the inaccuracy margin so - that we don't fire slightly too early and get denied to run. */ - Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); - } - else { - if(data->state.expect100header) - /* when we've sent off the rest of the headers, we must await a - 100-continue but first finish sending the request */ - k->exp100 = EXP100_SENDING_REQUEST; - - /* enable the write bit when we're not waiting for continue */ - k->keepon |= KEEP_SEND; - } - } /* if(conn->writesockfd != CURL_SOCKET_BAD) */ - } /* if(k->getheader || !data->set.opt_no_body) */ - -} diff --git a/dep/cpr/opt/curl/lib/transfer.h b/dep/cpr/opt/curl/lib/transfer.h deleted file mode 100644 index 72526a8348a..00000000000 --- a/dep/cpr/opt/curl/lib/transfer.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef HEADER_CURL_TRANSFER_H -#define HEADER_CURL_TRANSFER_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -char *Curl_checkheaders(const struct connectdata *conn, - const char *thisheader); - -void Curl_init_CONNECT(struct Curl_easy *data); - -CURLcode Curl_pretransfer(struct Curl_easy *data); -CURLcode Curl_second_connect(struct connectdata *conn); -CURLcode Curl_posttransfer(struct Curl_easy *data); - -typedef enum { - FOLLOW_NONE, /* not used within the function, just a placeholder to - allow initing to this */ - FOLLOW_FAKE, /* only records stuff, not actually following */ - FOLLOW_RETRY, /* set if this is a request retry as opposed to a real - redirect following */ - FOLLOW_REDIR, /* a full true redirect */ - FOLLOW_LAST /* never used */ -} followtype; - -CURLcode Curl_follow(struct Curl_easy *data, char *newurl, - followtype type); -CURLcode Curl_readwrite(struct connectdata *conn, - struct Curl_easy *data, bool *done, - bool *comeback); -int Curl_single_getsock(const struct connectdata *conn, - curl_socket_t *socks, - int numsocks); -CURLcode Curl_readrewind(struct connectdata *conn); -CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp); -CURLcode Curl_retry_request(struct connectdata *conn, char **url); -bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc); - -/* This sets up a forthcoming transfer */ -void -Curl_setup_transfer (struct connectdata *data, - int sockindex, /* socket index to read from or -1 */ - curl_off_t size, /* -1 if unknown at this point */ - bool getheader, /* TRUE if header parsing is wanted */ - curl_off_t *bytecountp, /* return number of bytes read */ - int writesockindex, /* socket index to write to, it may - very well be the same we read from. - -1 disables */ - curl_off_t *writecountp /* return number of bytes written */ -); - -#endif /* HEADER_CURL_TRANSFER_H */ - diff --git a/dep/cpr/opt/curl/lib/url.c b/dep/cpr/opt/curl/lib/url.c deleted file mode 100644 index 584635bc3fd..00000000000 --- a/dep/cpr/opt/curl/lib/url.c +++ /dev/null @@ -1,7209 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef __VMS -#include -#include -#endif - -#ifdef HAVE_SYS_UN_H -#include -#endif - -#ifndef HAVE_SOCKET -#error "We can't compile without socket() support!" -#endif - -#ifdef HAVE_LIMITS_H -#include -#endif - -#ifdef USE_LIBIDN2 -#include - -#elif defined(USE_WIN32_IDN) -/* prototype for curl_win32_idn_to_ascii() */ -bool curl_win32_idn_to_ascii(const char *in, char **out); -#endif /* USE_LIBIDN2 */ - -#include "urldata.h" -#include "netrc.h" - -#include "formdata.h" -#include "mime.h" -#include "vtls/vtls.h" -#include "hostip.h" -#include "transfer.h" -#include "sendf.h" -#include "progress.h" -#include "cookie.h" -#include "strcase.h" -#include "strerror.h" -#include "escape.h" -#include "strtok.h" -#include "share.h" -#include "content_encoding.h" -#include "http_digest.h" -#include "http_negotiate.h" -#include "select.h" -#include "multiif.h" -#include "easyif.h" -#include "speedcheck.h" -#include "warnless.h" -#include "non-ascii.h" -#include "inet_pton.h" -#include "getinfo.h" - -/* And now for the protocols */ -#include "ftp.h" -#include "dict.h" -#include "telnet.h" -#include "tftp.h" -#include "http.h" -#include "http2.h" -#include "file.h" -#include "curl_ldap.h" -#include "ssh.h" -#include "imap.h" -#include "url.h" -#include "connect.h" -#include "inet_ntop.h" -#include "http_ntlm.h" -#include "curl_ntlm_wb.h" -#include "socks.h" -#include "curl_rtmp.h" -#include "gopher.h" -#include "http_proxy.h" -#include "conncache.h" -#include "multihandle.h" -#include "pipeline.h" -#include "dotdot.h" -#include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* Local static prototypes */ -static struct connectdata * -find_oldest_idle_connection_in_bundle(struct Curl_easy *data, - struct connectbundle *bundle); -static void conn_free(struct connectdata *conn); -static void free_fixed_hostname(struct hostname *host); -static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); -static CURLcode parse_url_login(struct Curl_easy *data, - struct connectdata *conn, - char **userptr, char **passwdptr, - char **optionsptr); -static CURLcode parse_login_details(const char *login, const size_t len, - char **userptr, char **passwdptr, - char **optionsptr); -static unsigned int get_protocol_family(unsigned int protocol); - -#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE -#define READBUFFER_MAX CURL_MAX_READ_SIZE -#define READBUFFER_MIN 1024 - -/* Some parts of the code (e.g. chunked encoding) assume this buffer has at - * more than just a few bytes to play with. Don't let it become too small or - * bad things will happen. - */ -#if READBUFFER_SIZE < READBUFFER_MIN -# error READBUFFER_SIZE is too small -#endif - - -/* - * Protocol table. - */ - -static const struct Curl_handler * const protocols[] = { - -#ifndef CURL_DISABLE_HTTP - &Curl_handler_http, -#endif - -#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) - &Curl_handler_https, -#endif - -#ifndef CURL_DISABLE_FTP - &Curl_handler_ftp, -#endif - -#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) - &Curl_handler_ftps, -#endif - -#ifndef CURL_DISABLE_TELNET - &Curl_handler_telnet, -#endif - -#ifndef CURL_DISABLE_DICT - &Curl_handler_dict, -#endif - -#ifndef CURL_DISABLE_LDAP - &Curl_handler_ldap, -#if !defined(CURL_DISABLE_LDAPS) && \ - ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ - (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) - &Curl_handler_ldaps, -#endif -#endif - -#ifndef CURL_DISABLE_FILE - &Curl_handler_file, -#endif - -#ifndef CURL_DISABLE_TFTP - &Curl_handler_tftp, -#endif - -#ifdef USE_LIBSSH2 - &Curl_handler_scp, - &Curl_handler_sftp, -#endif - -#ifndef CURL_DISABLE_IMAP - &Curl_handler_imap, -#ifdef USE_SSL - &Curl_handler_imaps, -#endif -#endif - -#ifndef CURL_DISABLE_POP3 - &Curl_handler_pop3, -#ifdef USE_SSL - &Curl_handler_pop3s, -#endif -#endif - -#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ - (CURL_SIZEOF_CURL_OFF_T > 4) && \ - (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)) - &Curl_handler_smb, -#ifdef USE_SSL - &Curl_handler_smbs, -#endif -#endif - -#ifndef CURL_DISABLE_SMTP - &Curl_handler_smtp, -#ifdef USE_SSL - &Curl_handler_smtps, -#endif -#endif - -#ifndef CURL_DISABLE_RTSP - &Curl_handler_rtsp, -#endif - -#ifndef CURL_DISABLE_GOPHER - &Curl_handler_gopher, -#endif - -#ifdef USE_LIBRTMP - &Curl_handler_rtmp, - &Curl_handler_rtmpt, - &Curl_handler_rtmpe, - &Curl_handler_rtmpte, - &Curl_handler_rtmps, - &Curl_handler_rtmpts, -#endif - - (struct Curl_handler *) NULL -}; - -/* - * Dummy handler for undefined protocol schemes. - */ - -static const struct Curl_handler Curl_handler_dummy = { - "", /* scheme */ - ZERO_NULL, /* setup_connection */ - ZERO_NULL, /* do_it */ - ZERO_NULL, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - 0, /* defport */ - 0, /* protocol */ - PROTOPT_NONE /* flags */ -}; - -void Curl_freeset(struct Curl_easy *data) -{ - /* Free all dynamic strings stored in the data->set substructure. */ - enum dupstring i; - for(i = (enum dupstring)0; i < STRING_LAST; i++) { - Curl_safefree(data->set.str[i]); - } - - if(data->change.referer_alloc) { - Curl_safefree(data->change.referer); - data->change.referer_alloc = FALSE; - } - data->change.referer = NULL; - if(data->change.url_alloc) { - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - data->change.url = NULL; -} - -static CURLcode setstropt(char **charp, const char *s) -{ - /* Release the previous storage at `charp' and replace by a dynamic storage - copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */ - - Curl_safefree(*charp); - - if(s) { - char *str = strdup(s); - - if(!str) - return CURLE_OUT_OF_MEMORY; - - *charp = str; - } - - return CURLE_OK; -} - -static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) -{ - CURLcode result = CURLE_OK; - char *user = NULL; - char *passwd = NULL; - - /* Parse the login details if specified. It not then we treat NULL as a hint - to clear the existing data */ - if(option) { - result = parse_login_details(option, strlen(option), - (userp ? &user : NULL), - (passwdp ? &passwd : NULL), - NULL); - } - - if(!result) { - /* Store the username part of option if required */ - if(userp) { - if(!user && option && option[0] == ':') { - /* Allocate an empty string instead of returning NULL as user name */ - user = strdup(""); - if(!user) - result = CURLE_OUT_OF_MEMORY; - } - - Curl_safefree(*userp); - *userp = user; - } - - /* Store the password part of option if required */ - if(passwdp) { - Curl_safefree(*passwdp); - *passwdp = passwd; - } - } - - return result; -} - -CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src) -{ - CURLcode result = CURLE_OK; - enum dupstring i; - - /* Copy src->set into dst->set first, then deal with the strings - afterwards */ - dst->set = src->set; - - /* clear all string pointers first */ - memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); - - /* duplicate all strings */ - for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { - result = setstropt(&dst->set.str[i], src->set.str[i]); - if(result) - return result; - } - - /* duplicate memory areas pointed to */ - i = STRING_COPYPOSTFIELDS; - if(src->set.postfieldsize && src->set.str[i]) { - /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */ - dst->set.str[i] = Curl_memdup(src->set.str[i], - curlx_sotouz(src->set.postfieldsize)); - if(!dst->set.str[i]) - return CURLE_OUT_OF_MEMORY; - /* point to the new copy */ - dst->set.postfields = dst->set.str[i]; - } - - return CURLE_OK; -} - -/* - * This is the internal function curl_easy_cleanup() calls. This should - * cleanup and free all resources associated with this sessionhandle. - * - * NOTE: if we ever add something that attempts to write to a socket or - * similar here, we must ignore SIGPIPE first. It is currently only done - * when curl_easy_perform() is invoked. - */ - -CURLcode Curl_close(struct Curl_easy *data) -{ - struct Curl_multi *m; - - if(!data) - return CURLE_OK; - - Curl_expire_clear(data); /* shut off timers */ - - m = data->multi; - - if(m) - /* This handle is still part of a multi handle, take care of this first - and detach this handle from there. */ - curl_multi_remove_handle(data->multi, data); - - if(data->multi_easy) - /* when curl_easy_perform() is used, it creates its own multi handle to - use and this is the one */ - curl_multi_cleanup(data->multi_easy); - - /* Destroy the timeout list that is held in the easy handle. It is - /normally/ done by curl_multi_remove_handle() but this is "just in - case" */ - Curl_llist_destroy(&data->state.timeoutlist, NULL); - - data->magic = 0; /* force a clear AFTER the possibly enforced removal from - the multi handle, since that function uses the magic - field! */ - - if(data->state.rangestringalloc) - free(data->state.range); - - /* Free the pathbuffer */ - Curl_safefree(data->state.pathbuffer); - data->state.path = NULL; - - /* freed here just in case DONE wasn't called */ - Curl_free_request_state(data); - - /* Close down all open SSL info and sessions */ - Curl_ssl_close_all(data); - Curl_safefree(data->state.first_host); - Curl_safefree(data->state.scratch); - Curl_ssl_free_certinfo(data); - - /* Cleanup possible redirect junk */ - free(data->req.newurl); - data->req.newurl = NULL; - - if(data->change.referer_alloc) { - Curl_safefree(data->change.referer); - data->change.referer_alloc = FALSE; - } - data->change.referer = NULL; - - if(data->change.url_alloc) { - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - data->change.url = NULL; - - Curl_safefree(data->state.buffer); - Curl_safefree(data->state.headerbuff); - - Curl_flush_cookies(data, 1); - - Curl_digest_cleanup(data); - - Curl_safefree(data->info.contenttype); - Curl_safefree(data->info.wouldredirect); - - /* this destroys the channel and we cannot use it anymore after this */ - Curl_resolver_cleanup(data->state.resolver); - - Curl_http2_cleanup_dependencies(data); - Curl_convert_close(data); - - Curl_mime_cleanpart(&data->set.mimepost); - - /* No longer a dirty share, if it exists */ - if(data->share) { - Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); - data->share->dirty--; - Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); - } - - if(data->set.wildcardmatch) { - /* destruct wildcard structures if it is needed */ - struct WildcardData *wc = &data->wildcard; - Curl_wildcard_dtor(wc); - } - - Curl_freeset(data); - free(data); - return CURLE_OK; -} - -/* - * Initialize the UserDefined fields within a Curl_easy. - * This may be safely called on a new or existing Curl_easy. - */ -CURLcode Curl_init_userdefined(struct UserDefined *set) -{ - CURLcode result = CURLE_OK; - - set->out = stdout; /* default output to stdout */ - set->in_set = stdin; /* default input from stdin */ - set->err = stderr; /* default stderr to stderr */ - - /* use fwrite as default function to store output */ - set->fwrite_func = (curl_write_callback)fwrite; - - /* use fread as default function to read input */ - set->fread_func_set = (curl_read_callback)fread; - set->is_fread_set = 0; - set->is_fwrite_set = 0; - - set->seek_func = ZERO_NULL; - set->seek_client = ZERO_NULL; - - /* conversion callbacks for non-ASCII hosts */ - set->convfromnetwork = ZERO_NULL; - set->convtonetwork = ZERO_NULL; - set->convfromutf8 = ZERO_NULL; - - set->filesize = -1; /* we don't know the size */ - set->postfieldsize = -1; /* unknown size */ - set->maxredirs = -1; /* allow any amount by default */ - - set->httpreq = HTTPREQ_GET; /* Default HTTP request */ - set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ - set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ - set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ - set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ - set->ftp_filemethod = FTPFILE_MULTICWD; - - set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ - - /* Set the default size of the SSL session ID cache */ - set->general_ssl.max_ssl_sessions = 5; - - set->proxyport = 0; - set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ - set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ - set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ - - /* SOCKS5 proxy auth defaults to username/password + GSS-API */ - set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; - - /* make libcurl quiet by default: */ - set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ - - /* - * libcurl 7.10 introduced SSL verification *by default*! This needs to be - * switched off unless wanted. - */ - set->ssl.primary.verifypeer = TRUE; - set->ssl.primary.verifyhost = TRUE; -#ifdef USE_TLS_SRP - set->ssl.authtype = CURL_TLSAUTH_NONE; -#endif - set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth - type */ - set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by - default */ - set->proxy_ssl = set->ssl; - - set->new_file_perms = 0644; /* Default permissions */ - set->new_directory_perms = 0755; /* Default permissions */ - - /* for the *protocols fields we don't use the CURLPROTO_ALL convenience - define since we internally only use the lower 16 bits for the passed - in bitmask to not conflict with the private bits */ - set->allowed_protocols = CURLPROTO_ALL; - set->redir_protocols = CURLPROTO_ALL & /* All except FILE, SCP and SMB */ - ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB | - CURLPROTO_SMBS); - -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - /* - * disallow unprotected protection negotiation NEC reference implementation - * seem not to follow rfc1961 section 4.3/4.4 - */ - set->socks5_gssapi_nec = FALSE; -#endif - - /* This is our preferred CA cert bundle/path since install time */ -#if defined(CURL_CA_BUNDLE) - result = setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE); - if(result) - return result; - - result = setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE); - if(result) - return result; -#endif -#if defined(CURL_CA_PATH) - result = setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH); - if(result) - return result; - - result = setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); - if(result) - return result; -#endif - - set->wildcardmatch = FALSE; - set->chunk_bgn = ZERO_NULL; - set->chunk_end = ZERO_NULL; - - /* tcp keepalives are disabled by default, but provide reasonable values for - * the interval and idle times. - */ - set->tcp_keepalive = FALSE; - set->tcp_keepintvl = 60; - set->tcp_keepidle = 60; - set->tcp_fastopen = FALSE; - set->tcp_nodelay = TRUE; - - set->ssl_enable_npn = TRUE; - set->ssl_enable_alpn = TRUE; - - set->expect_100_timeout = 1000L; /* Wait for a second by default. */ - set->sep_headers = TRUE; /* separated header lists by default */ - set->buffer_size = READBUFFER_SIZE; - - Curl_http2_init_userset(set); - return result; -} - -/** - * Curl_open() - * - * @param curl is a pointer to a sessionhandle pointer that gets set by this - * function. - * @return CURLcode - */ - -CURLcode Curl_open(struct Curl_easy **curl) -{ - CURLcode result; - struct Curl_easy *data; - - /* Very simple start-up: alloc the struct, init it with zeroes and return */ - data = calloc(1, sizeof(struct Curl_easy)); - if(!data) { - /* this is a very serious error */ - DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n")); - return CURLE_OUT_OF_MEMORY; - } - - data->magic = CURLEASY_MAGIC_NUMBER; - - result = Curl_resolver_init(&data->state.resolver); - if(result) { - DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); - free(data); - return result; - } - - /* We do some initial setup here, all those fields that can't be just 0 */ - - data->state.buffer = malloc(READBUFFER_SIZE + 1); - if(!data->state.buffer) { - DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n")); - result = CURLE_OUT_OF_MEMORY; - } - - Curl_mime_initpart(&data->set.mimepost, data); - - data->state.headerbuff = malloc(HEADERSIZE); - if(!data->state.headerbuff) { - DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); - result = CURLE_OUT_OF_MEMORY; - } - else { - result = Curl_init_userdefined(&data->set); - - data->state.headersize = HEADERSIZE; - - Curl_convert_init(data); - - Curl_initinfo(data); - - /* most recent connection is not yet defined */ - data->state.lastconnect = NULL; - - data->progress.flags |= PGRS_HIDE; - data->state.current_speed = -1; /* init to negative == impossible */ - data->set.fnmatch = ZERO_NULL; - data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ - - Curl_http2_init_state(&data->state); - } - - if(result) { - Curl_resolver_cleanup(data->state.resolver); - free(data->state.buffer); - free(data->state.headerbuff); - Curl_freeset(data); - free(data); - data = NULL; - } - else - *curl = data; - - return result; -} - -#define C_SSLVERSION_VALUE(x) (x & 0xffff) -#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000) - -CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, - va_list param) -{ - char *argptr; - CURLcode result = CURLE_OK; - long arg; -#ifndef CURL_DISABLE_HTTP - curl_off_t bigsize; -#endif - - switch(option) { - case CURLOPT_DNS_CACHE_TIMEOUT: - data->set.dns_cache_timeout = va_arg(param, long); - break; - case CURLOPT_DNS_USE_GLOBAL_CACHE: - /* remember we want this enabled */ - arg = va_arg(param, long); - data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE; - break; - case CURLOPT_SSL_CIPHER_LIST: - /* set a list of cipher we want to use in the SSL connection */ - result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_PROXY_SSL_CIPHER_LIST: - /* set a list of cipher we want to use in the SSL connection for proxy */ - result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY], - va_arg(param, char *)); - break; - - case CURLOPT_RANDOM_FILE: - /* - * This is the path name to a file that contains random data to seed - * the random SSL stuff with. The file is only used for reading. - */ - result = setstropt(&data->set.str[STRING_SSL_RANDOM_FILE], - va_arg(param, char *)); - break; - case CURLOPT_EGDSOCKET: - /* - * The Entropy Gathering Daemon socket pathname - */ - result = setstropt(&data->set.str[STRING_SSL_EGDSOCKET], - va_arg(param, char *)); - break; - case CURLOPT_MAXCONNECTS: - /* - * Set the absolute number of maximum simultaneous alive connection that - * libcurl is allowed to have. - */ - data->set.maxconnects = va_arg(param, long); - break; - case CURLOPT_FORBID_REUSE: - /* - * When this transfer is done, it must not be left to be reused by a - * subsequent transfer but shall be closed immediately. - */ - data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_FRESH_CONNECT: - /* - * This transfer shall not use a previously cached connection but - * should be made with a fresh new connect! - */ - data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_VERBOSE: - /* - * Verbose means infof() calls that give a lot of information about - * the connection and transfer procedures as well as internal choices. - */ - data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_HEADER: - /* - * Set to include the header in the general data output stream. - */ - data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_NOPROGRESS: - /* - * Shut off the internal supported progress meter - */ - data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE; - if(data->set.hide_progress) - data->progress.flags |= PGRS_HIDE; - else - data->progress.flags &= ~PGRS_HIDE; - break; - case CURLOPT_NOBODY: - /* - * Do not include the body part in the output data stream. - */ - data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_FAILONERROR: - /* - * Don't output the >=400 error code HTML-page, but instead only - * return error. - */ - data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_KEEP_SENDING_ON_ERROR: - data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ? - TRUE : FALSE; - break; - case CURLOPT_UPLOAD: - case CURLOPT_PUT: - /* - * We want to sent data to the remote host. If this is HTTP, that equals - * using the PUT request. - */ - data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE; - if(data->set.upload) { - /* If this is HTTP, PUT is what's needed to "upload" */ - data->set.httpreq = HTTPREQ_PUT; - data->set.opt_no_body = FALSE; /* this is implied */ - } - else - /* In HTTP, the opposite of upload is GET (unless NOBODY is true as - then this can be changed to HEAD later on) */ - data->set.httpreq = HTTPREQ_GET; - break; - case CURLOPT_REQUEST_TARGET: - result = setstropt(&data->set.str[STRING_TARGET], - va_arg(param, char *)); - break; - case CURLOPT_FILETIME: - /* - * Try to get the file time of the remote document. The time will - * later (possibly) become available using curl_easy_getinfo(). - */ - data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_FTP_CREATE_MISSING_DIRS: - /* - * An FTP option that modifies an upload to create missing directories on - * the server. - */ - switch(va_arg(param, long)) { - case 0: - data->set.ftp_create_missing_dirs = 0; - break; - case 1: - data->set.ftp_create_missing_dirs = 1; - break; - case 2: - data->set.ftp_create_missing_dirs = 2; - break; - default: - /* reserve other values for future use */ - result = CURLE_UNKNOWN_OPTION; - break; - } - break; - case CURLOPT_SERVER_RESPONSE_TIMEOUT: - /* - * Option that specifies how quickly an server response must be obtained - * before it is considered failure. For pingpong protocols. - */ - data->set.server_response_timeout = va_arg(param, long) * 1000; - break; - case CURLOPT_TFTP_NO_OPTIONS: - /* - * Option that prevents libcurl from sending TFTP option requests to the - * server. - */ - data->set.tftp_no_options = va_arg(param, long) != 0; - break; - case CURLOPT_TFTP_BLKSIZE: - /* - * TFTP option that specifies the block size to use for data transmission. - */ - data->set.tftp_blksize = va_arg(param, long); - break; - case CURLOPT_DIRLISTONLY: - /* - * An option that changes the command to one that asks for a list - * only, no file info details. - */ - data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_APPEND: - /* - * We want to upload and append to an existing file. - */ - data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_FTP_FILEMETHOD: - /* - * How do access files over FTP. - */ - data->set.ftp_filemethod = (curl_ftpfile)va_arg(param, long); - break; - case CURLOPT_NETRC: - /* - * Parse the $HOME/.netrc file - */ - data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long); - break; - case CURLOPT_NETRC_FILE: - /* - * Use this file instead of the $HOME/.netrc file - */ - result = setstropt(&data->set.str[STRING_NETRC_FILE], - va_arg(param, char *)); - break; - case CURLOPT_TRANSFERTEXT: - /* - * This option was previously named 'FTPASCII'. Renamed to work with - * more protocols than merely FTP. - * - * Transfer using ASCII (instead of BINARY). - */ - data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_TIMECONDITION: - /* - * Set HTTP time condition. This must be one of the defines in the - * curl/curl.h header file. - */ - data->set.timecondition = (curl_TimeCond)va_arg(param, long); - break; - case CURLOPT_TIMEVALUE: - /* - * This is the value to compare with the remote document with the - * method set with CURLOPT_TIMECONDITION - */ - data->set.timevalue = (time_t)va_arg(param, long); - break; - case CURLOPT_SSLVERSION: - /* - * Set explicit SSL version to try to connect with, as some SSL - * implementations are lame. - */ -#ifdef USE_SSL - arg = va_arg(param, long); - data->set.ssl.primary.version = C_SSLVERSION_VALUE(arg); - data->set.ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg); -#else - result = CURLE_UNKNOWN_OPTION; -#endif - break; - case CURLOPT_PROXY_SSLVERSION: - /* - * Set explicit SSL version to try to connect with for proxy, as some SSL - * implementations are lame. - */ -#ifdef USE_SSL - arg = va_arg(param, long); - data->set.proxy_ssl.primary.version = C_SSLVERSION_VALUE(arg); - data->set.proxy_ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg); -#else - result = CURLE_UNKNOWN_OPTION; -#endif - break; - -#ifndef CURL_DISABLE_HTTP - case CURLOPT_AUTOREFERER: - /* - * Switch on automatic referer that gets set if curl follows locations. - */ - data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_ACCEPT_ENCODING: - /* - * String to use at the value of Accept-Encoding header. - * - * If the encoding is set to "" we use an Accept-Encoding header that - * encompasses all the encodings we support. - * If the encoding is set to NULL we don't send an Accept-Encoding header - * and ignore an received Content-Encoding header. - * - */ - argptr = va_arg(param, char *); - result = setstropt(&data->set.str[STRING_ENCODING], - (argptr && !*argptr)? - ALL_CONTENT_ENCODINGS: argptr); - break; - - case CURLOPT_TRANSFER_ENCODING: - data->set.http_transfer_encoding = (0 != va_arg(param, long)) ? - TRUE : FALSE; - break; - - case CURLOPT_FOLLOWLOCATION: - /* - * Follow Location: header hints on a HTTP-server. - */ - data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_UNRESTRICTED_AUTH: - /* - * Send authentication (user+password) when following locations, even when - * hostname changed. - */ - data->set.http_disable_hostname_check_before_authentication = - (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_MAXREDIRS: - /* - * The maximum amount of hops you allow curl to follow Location: - * headers. This should mostly be used to detect never-ending loops. - */ - data->set.maxredirs = va_arg(param, long); - break; - - case CURLOPT_POSTREDIR: - { - /* - * Set the behaviour of POST when redirecting - * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302 - * CURL_REDIR_POST_301 - POST is kept as POST after 301 - * CURL_REDIR_POST_302 - POST is kept as POST after 302 - * CURL_REDIR_POST_303 - POST is kept as POST after 303 - * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303 - * other - POST is kept as POST after 301 and 302 - */ - arg = va_arg(param, long); - data->set.keep_post = arg & CURL_REDIR_POST_ALL; - } - break; - - case CURLOPT_POST: - /* Does this option serve a purpose anymore? Yes it does, when - CURLOPT_POSTFIELDS isn't used and the POST data is read off the - callback! */ - if(va_arg(param, long)) { - data->set.httpreq = HTTPREQ_POST; - data->set.opt_no_body = FALSE; /* this is implied */ - } - else - data->set.httpreq = HTTPREQ_GET; - break; - - case CURLOPT_COPYPOSTFIELDS: - /* - * A string with POST data. Makes curl HTTP POST. Even if it is NULL. - * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to - * CURLOPT_COPYPOSTFIELDS and not altered later. - */ - argptr = va_arg(param, char *); - - if(!argptr || data->set.postfieldsize == -1) - result = setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr); - else { - /* - * Check that requested length does not overflow the size_t type. - */ - - if((data->set.postfieldsize < 0) || - ((sizeof(curl_off_t) != sizeof(size_t)) && - (data->set.postfieldsize > (curl_off_t)((size_t)-1)))) - result = CURLE_OUT_OF_MEMORY; - else { - char *p; - - (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); - - /* Allocate even when size == 0. This satisfies the need of possible - later address compare to detect the COPYPOSTFIELDS mode, and - to mark that postfields is used rather than read function or - form data. - */ - p = malloc((size_t)(data->set.postfieldsize? - data->set.postfieldsize:1)); - - if(!p) - result = CURLE_OUT_OF_MEMORY; - else { - if(data->set.postfieldsize) - memcpy(p, argptr, (size_t)data->set.postfieldsize); - - data->set.str[STRING_COPYPOSTFIELDS] = p; - } - } - } - - data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS]; - data->set.httpreq = HTTPREQ_POST; - break; - - case CURLOPT_POSTFIELDS: - /* - * Like above, but use static data instead of copying it. - */ - data->set.postfields = va_arg(param, void *); - /* Release old copied data. */ - (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); - data->set.httpreq = HTTPREQ_POST; - break; - - case CURLOPT_POSTFIELDSIZE: - /* - * The size of the POSTFIELD data to prevent libcurl to do strlen() to - * figure it out. Enables binary posts. - */ - bigsize = va_arg(param, long); - - if(data->set.postfieldsize < bigsize && - data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { - /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ - (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); - data->set.postfields = NULL; - } - - data->set.postfieldsize = bigsize; - break; - - case CURLOPT_POSTFIELDSIZE_LARGE: - /* - * The size of the POSTFIELD data to prevent libcurl to do strlen() to - * figure it out. Enables binary posts. - */ - bigsize = va_arg(param, curl_off_t); - - if(data->set.postfieldsize < bigsize && - data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { - /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ - (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); - data->set.postfields = NULL; - } - - data->set.postfieldsize = bigsize; - break; - - case CURLOPT_HTTPPOST: - /* - * Set to make us do HTTP POST - */ - data->set.httppost = va_arg(param, struct curl_httppost *); - data->set.httpreq = HTTPREQ_POST_FORM; - data->set.opt_no_body = FALSE; /* this is implied */ - break; -#endif /* CURL_DISABLE_HTTP */ - - case CURLOPT_MIMEPOST: - /* - * Set to make us do MIME/form POST - */ - result = curl_mime_subparts(&data->set.mimepost, - va_arg(param, curl_mime *)); - if(!result) { - data->set.mimepost.freefunc = NULL; /* Avoid free upon easy cleanup. */ - data->set.httpreq = HTTPREQ_POST_MIME; - data->set.opt_no_body = FALSE; /* this is implied */ - } - break; - - case CURLOPT_REFERER: - /* - * String to set in the HTTP Referer: field. - */ - if(data->change.referer_alloc) { - Curl_safefree(data->change.referer); - data->change.referer_alloc = FALSE; - } - result = setstropt(&data->set.str[STRING_SET_REFERER], - va_arg(param, char *)); - data->change.referer = data->set.str[STRING_SET_REFERER]; - break; - - case CURLOPT_USERAGENT: - /* - * String to use in the HTTP User-Agent field - */ - result = setstropt(&data->set.str[STRING_USERAGENT], - va_arg(param, char *)); - break; - - case CURLOPT_HTTPHEADER: - /* - * Set a list with HTTP headers to use (or replace internals with) - */ - data->set.headers = va_arg(param, struct curl_slist *); - break; - -#ifndef CURL_DISABLE_HTTP - case CURLOPT_PROXYHEADER: - /* - * Set a list with proxy headers to use (or replace internals with) - * - * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a - * long time we remain doing it this way until CURLOPT_PROXYHEADER is - * used. As soon as this option has been used, if set to anything but - * NULL, custom headers for proxies are only picked from this list. - * - * Set this option to NULL to restore the previous behavior. - */ - data->set.proxyheaders = va_arg(param, struct curl_slist *); - break; - - case CURLOPT_HEADEROPT: - /* - * Set header option. - */ - arg = va_arg(param, long); - data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE; - break; - - case CURLOPT_HTTP200ALIASES: - /* - * Set a list of aliases for HTTP 200 in response header - */ - data->set.http200aliases = va_arg(param, struct curl_slist *); - break; - -#if !defined(CURL_DISABLE_COOKIES) - case CURLOPT_COOKIE: - /* - * Cookie string to send to the remote server in the request. - */ - result = setstropt(&data->set.str[STRING_COOKIE], - va_arg(param, char *)); - break; - - case CURLOPT_COOKIEFILE: - /* - * Set cookie file to read and parse. Can be used multiple times. - */ - argptr = (char *)va_arg(param, void *); - if(argptr) { - struct curl_slist *cl; - /* append the cookie file name to the list of file names, and deal with - them later */ - cl = curl_slist_append(data->change.cookielist, argptr); - if(!cl) { - curl_slist_free_all(data->change.cookielist); - data->change.cookielist = NULL; - return CURLE_OUT_OF_MEMORY; - } - data->change.cookielist = cl; /* store the list for later use */ - } - break; - - case CURLOPT_COOKIEJAR: - /* - * Set cookie file name to dump all cookies to when we're done. - */ - { - struct CookieInfo *newcookies; - result = setstropt(&data->set.str[STRING_COOKIEJAR], - va_arg(param, char *)); - - /* - * Activate the cookie parser. This may or may not already - * have been made. - */ - newcookies = Curl_cookie_init(data, NULL, data->cookies, - data->set.cookiesession); - if(!newcookies) - result = CURLE_OUT_OF_MEMORY; - data->cookies = newcookies; - } - break; - - case CURLOPT_COOKIESESSION: - /* - * Set this option to TRUE to start a new "cookie session". It will - * prevent the forthcoming read-cookies-from-file actions to accept - * cookies that are marked as being session cookies, as they belong to a - * previous session. - * - * In the original Netscape cookie spec, "session cookies" are cookies - * with no expire date set. RFC2109 describes the same action if no - * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds - * a 'Discard' action that can enforce the discard even for cookies that - * have a Max-Age. - * - * We run mostly with the original cookie spec, as hardly anyone implements - * anything else. - */ - data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_COOKIELIST: - argptr = va_arg(param, char *); - - if(argptr == NULL) - break; - - if(strcasecompare(argptr, "ALL")) { - /* clear all cookies */ - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_clearall(data->cookies); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - else if(strcasecompare(argptr, "SESS")) { - /* clear session cookies */ - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_clearsess(data->cookies); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - else if(strcasecompare(argptr, "FLUSH")) { - /* flush cookies to file, takes care of the locking */ - Curl_flush_cookies(data, 0); - } - else if(strcasecompare(argptr, "RELOAD")) { - /* reload cookies from file */ - Curl_cookie_loadfiles(data); - break; - } - else { - if(!data->cookies) - /* if cookie engine was not running, activate it */ - data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); - - argptr = strdup(argptr); - if(!argptr || !data->cookies) { - result = CURLE_OUT_OF_MEMORY; - free(argptr); - } - else { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - - if(checkprefix("Set-Cookie:", argptr)) - /* HTTP Header format line */ - Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL); - - else - /* Netscape format line */ - Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL); - - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - free(argptr); - } - } - - break; -#endif /* !CURL_DISABLE_COOKIES */ - - case CURLOPT_HTTPGET: - /* - * Set to force us do HTTP GET - */ - if(va_arg(param, long)) { - data->set.httpreq = HTTPREQ_GET; - data->set.upload = FALSE; /* switch off upload */ - data->set.opt_no_body = FALSE; /* this is implied */ - } - break; - - case CURLOPT_HTTP_VERSION: - /* - * This sets a requested HTTP version to be used. The value is one of - * the listed enums in curl/curl.h. - */ - arg = va_arg(param, long); -#ifndef USE_NGHTTP2 - if(arg >= CURL_HTTP_VERSION_2) - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - data->set.httpversion = arg; - break; - - case CURLOPT_EXPECT_100_TIMEOUT_MS: - /* - * Time to wait for a response to a HTTP request containing an - * Expect: 100-continue header before sending the data anyway. - */ - data->set.expect_100_timeout = va_arg(param, long); - break; - -#endif /* CURL_DISABLE_HTTP */ - - case CURLOPT_HTTPAUTH: - /* - * Set HTTP Authentication type BITMASK. - */ - { - int bitcheck; - bool authbits; - unsigned long auth = va_arg(param, unsigned long); - - if(auth == CURLAUTH_NONE) { - data->set.httpauth = auth; - break; - } - - /* the DIGEST_IE bit is only used to set a special marker, for all the - rest we need to handle it as normal DIGEST */ - data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE; - - if(auth & CURLAUTH_DIGEST_IE) { - auth |= CURLAUTH_DIGEST; /* set standard digest bit */ - auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */ - } - - /* switch off bits we can't support */ -#ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM support */ - auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ -#elif !defined(NTLM_WB_ENABLED) - auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ -#endif -#ifndef USE_SPNEGO - auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without - GSS-API or SSPI */ -#endif - - /* check if any auth bit lower than CURLAUTH_ONLY is still set */ - bitcheck = 0; - authbits = FALSE; - while(bitcheck < 31) { - if(auth & (1UL << bitcheck++)) { - authbits = TRUE; - break; - } - } - if(!authbits) - return CURLE_NOT_BUILT_IN; /* no supported types left! */ - - data->set.httpauth = auth; - } - break; - - case CURLOPT_CUSTOMREQUEST: - /* - * Set a custom string to use as request - */ - result = setstropt(&data->set.str[STRING_CUSTOMREQUEST], - va_arg(param, char *)); - - /* we don't set - data->set.httpreq = HTTPREQ_CUSTOM; - here, we continue as if we were using the already set type - and this just changes the actual request keyword */ - break; - -#ifndef CURL_DISABLE_PROXY - case CURLOPT_HTTPPROXYTUNNEL: - /* - * Tunnel operations through the proxy instead of normal proxy use - */ - data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ? - TRUE : FALSE; - break; - - case CURLOPT_PROXYPORT: - /* - * Explicitly set HTTP proxy port number. - */ - data->set.proxyport = va_arg(param, long); - break; - - case CURLOPT_PROXYAUTH: - /* - * Set HTTP Authentication type BITMASK. - */ - { - int bitcheck; - bool authbits; - unsigned long auth = va_arg(param, unsigned long); - - if(auth == CURLAUTH_NONE) { - data->set.proxyauth = auth; - break; - } - - /* the DIGEST_IE bit is only used to set a special marker, for all the - rest we need to handle it as normal DIGEST */ - data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE; - - if(auth & CURLAUTH_DIGEST_IE) { - auth |= CURLAUTH_DIGEST; /* set standard digest bit */ - auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */ - } - /* switch off bits we can't support */ -#ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM support */ - auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ -#elif !defined(NTLM_WB_ENABLED) - auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ -#endif -#ifndef USE_SPNEGO - auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without - GSS-API or SSPI */ -#endif - - /* check if any auth bit lower than CURLAUTH_ONLY is still set */ - bitcheck = 0; - authbits = FALSE; - while(bitcheck < 31) { - if(auth & (1UL << bitcheck++)) { - authbits = TRUE; - break; - } - } - if(!authbits) - return CURLE_NOT_BUILT_IN; /* no supported types left! */ - - data->set.proxyauth = auth; - } - break; - - case CURLOPT_PROXY: - /* - * Set proxy server:port to use as proxy. - * - * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL) - * we explicitly say that we don't want to use a proxy - * (even though there might be environment variables saying so). - * - * Setting it to NULL, means no proxy but allows the environment variables - * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL). - */ - result = setstropt(&data->set.str[STRING_PROXY], - va_arg(param, char *)); - break; - - case CURLOPT_PRE_PROXY: - /* - * Set proxy server:port to use as SOCKS proxy. - * - * If the proxy is set to "" or NULL we explicitly say that we don't want - * to use the socks proxy. - */ - result = setstropt(&data->set.str[STRING_PRE_PROXY], - va_arg(param, char *)); - break; - - case CURLOPT_PROXYTYPE: - /* - * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME - */ - data->set.proxytype = (curl_proxytype)va_arg(param, long); - break; - - case CURLOPT_PROXY_TRANSFER_MODE: - /* - * set transfer mode (;type=) when doing FTP via an HTTP proxy - */ - switch(va_arg(param, long)) { - case 0: - data->set.proxy_transfer_mode = FALSE; - break; - case 1: - data->set.proxy_transfer_mode = TRUE; - break; - default: - /* reserve other values for future use */ - result = CURLE_UNKNOWN_OPTION; - break; - } - break; -#endif /* CURL_DISABLE_PROXY */ - - case CURLOPT_SOCKS5_AUTH: - data->set.socks5auth = va_arg(param, unsigned long); - if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) - result = CURLE_NOT_BUILT_IN; - break; -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - case CURLOPT_SOCKS5_GSSAPI_NEC: - /* - * Set flag for NEC SOCK5 support - */ - data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_SOCKS5_GSSAPI_SERVICE: - case CURLOPT_PROXY_SERVICE_NAME: - /* - * Set proxy authentication service name for Kerberos 5 and SPNEGO - */ - result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], - va_arg(param, char *)); - break; -#endif - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ - defined(USE_SPNEGO) - case CURLOPT_SERVICE_NAME: - /* - * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO - */ - result = setstropt(&data->set.str[STRING_SERVICE_NAME], - va_arg(param, char *)); - break; - -#endif - - case CURLOPT_HEADERDATA: - /* - * Custom pointer to pass the header write callback function - */ - data->set.writeheader = (void *)va_arg(param, void *); - break; - case CURLOPT_ERRORBUFFER: - /* - * Error buffer provided by the caller to get the human readable - * error string in. - */ - data->set.errorbuffer = va_arg(param, char *); - break; - case CURLOPT_WRITEDATA: - /* - * FILE pointer to write to. Or possibly - * used as argument to the write callback. - */ - data->set.out = va_arg(param, void *); - break; - case CURLOPT_FTPPORT: - /* - * Use FTP PORT, this also specifies which IP address to use - */ - result = setstropt(&data->set.str[STRING_FTPPORT], - va_arg(param, char *)); - data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE; - break; - - case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_FTP_USE_PRET: - data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_FTP_SSL_CCC: - data->set.ftp_ccc = (curl_ftpccc)va_arg(param, long); - break; - - case CURLOPT_FTP_SKIP_PASV_IP: - /* - * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the - * bypass of the IP address in PASV responses. - */ - data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_READDATA: - /* - * FILE pointer to read the file to be uploaded from. Or possibly - * used as argument to the read callback. - */ - data->set.in_set = va_arg(param, void *); - break; - case CURLOPT_INFILESIZE: - /* - * If known, this should inform curl about the file size of the - * to-be-uploaded file. - */ - data->set.filesize = va_arg(param, long); - break; - case CURLOPT_INFILESIZE_LARGE: - /* - * If known, this should inform curl about the file size of the - * to-be-uploaded file. - */ - data->set.filesize = va_arg(param, curl_off_t); - break; - case CURLOPT_LOW_SPEED_LIMIT: - /* - * The low speed limit that if transfers are below this for - * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. - */ - data->set.low_speed_limit = va_arg(param, long); - break; - case CURLOPT_MAX_SEND_SPEED_LARGE: - /* - * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE - * bytes per second the transfer is throttled.. - */ - data->set.max_send_speed = va_arg(param, curl_off_t); - break; - case CURLOPT_MAX_RECV_SPEED_LARGE: - /* - * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per - * second the transfer is throttled.. - */ - data->set.max_recv_speed = va_arg(param, curl_off_t); - break; - case CURLOPT_LOW_SPEED_TIME: - /* - * The low speed time that if transfers are below the set - * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. - */ - data->set.low_speed_time = va_arg(param, long); - break; - case CURLOPT_URL: - /* - * The URL to fetch. - */ - if(data->change.url_alloc) { - /* the already set URL is allocated, free it first! */ - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - result = setstropt(&data->set.str[STRING_SET_URL], - va_arg(param, char *)); - data->change.url = data->set.str[STRING_SET_URL]; - break; - case CURLOPT_PORT: - /* - * The port number to use when getting the URL - */ - data->set.use_port = va_arg(param, long); - break; - case CURLOPT_TIMEOUT: - /* - * The maximum time you allow curl to use for a single transfer - * operation. - */ - data->set.timeout = va_arg(param, long) * 1000L; - break; - - case CURLOPT_TIMEOUT_MS: - data->set.timeout = va_arg(param, long); - break; - - case CURLOPT_CONNECTTIMEOUT: - /* - * The maximum time you allow curl to use to connect. - */ - data->set.connecttimeout = va_arg(param, long) * 1000L; - break; - - case CURLOPT_CONNECTTIMEOUT_MS: - data->set.connecttimeout = va_arg(param, long); - break; - - case CURLOPT_ACCEPTTIMEOUT_MS: - /* - * The maximum time you allow curl to wait for server connect - */ - data->set.accepttimeout = va_arg(param, long); - break; - - case CURLOPT_USERPWD: - /* - * user:password to use in the operation - */ - result = setstropt_userpwd(va_arg(param, char *), - &data->set.str[STRING_USERNAME], - &data->set.str[STRING_PASSWORD]); - break; - - case CURLOPT_USERNAME: - /* - * authentication user name to use in the operation - */ - result = setstropt(&data->set.str[STRING_USERNAME], - va_arg(param, char *)); - break; - - case CURLOPT_PASSWORD: - /* - * authentication password to use in the operation - */ - result = setstropt(&data->set.str[STRING_PASSWORD], - va_arg(param, char *)); - break; - - case CURLOPT_LOGIN_OPTIONS: - /* - * authentication options to use in the operation - */ - result = setstropt(&data->set.str[STRING_OPTIONS], - va_arg(param, char *)); - break; - - case CURLOPT_XOAUTH2_BEARER: - /* - * OAuth 2.0 bearer token to use in the operation - */ - result = setstropt(&data->set.str[STRING_BEARER], - va_arg(param, char *)); - break; - - case CURLOPT_POSTQUOTE: - /* - * List of RAW FTP commands to use after a transfer - */ - data->set.postquote = va_arg(param, struct curl_slist *); - break; - case CURLOPT_PREQUOTE: - /* - * List of RAW FTP commands to use prior to RETR (Wesley Laxton) - */ - data->set.prequote = va_arg(param, struct curl_slist *); - break; - case CURLOPT_QUOTE: - /* - * List of RAW FTP commands to use before a transfer - */ - data->set.quote = va_arg(param, struct curl_slist *); - break; - case CURLOPT_RESOLVE: - /* - * List of NAME:[address] names to populate the DNS cache with - * Prefix the NAME with dash (-) to _remove_ the name from the cache. - * - * Names added with this API will remain in the cache until explicitly - * removed or the handle is cleaned up. - * - * This API can remove any name from the DNS cache, but only entries - * that aren't actually in use right now will be pruned immediately. - */ - data->set.resolve = va_arg(param, struct curl_slist *); - data->change.resolve = data->set.resolve; - break; - case CURLOPT_PROGRESSFUNCTION: - /* - * Progress callback function - */ - data->set.fprogress = va_arg(param, curl_progress_callback); - if(data->set.fprogress) - data->progress.callback = TRUE; /* no longer internal */ - else - data->progress.callback = FALSE; /* NULL enforces internal */ - break; - - case CURLOPT_XFERINFOFUNCTION: - /* - * Transfer info callback function - */ - data->set.fxferinfo = va_arg(param, curl_xferinfo_callback); - if(data->set.fxferinfo) - data->progress.callback = TRUE; /* no longer internal */ - else - data->progress.callback = FALSE; /* NULL enforces internal */ - - break; - - case CURLOPT_PROGRESSDATA: - /* - * Custom client data to pass to the progress callback - */ - data->set.progress_client = va_arg(param, void *); - break; - -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXYUSERPWD: - /* - * user:password needed to use the proxy - */ - result = setstropt_userpwd(va_arg(param, char *), - &data->set.str[STRING_PROXYUSERNAME], - &data->set.str[STRING_PROXYPASSWORD]); - break; - case CURLOPT_PROXYUSERNAME: - /* - * authentication user name to use in the operation - */ - result = setstropt(&data->set.str[STRING_PROXYUSERNAME], - va_arg(param, char *)); - break; - case CURLOPT_PROXYPASSWORD: - /* - * authentication password to use in the operation - */ - result = setstropt(&data->set.str[STRING_PROXYPASSWORD], - va_arg(param, char *)); - break; - case CURLOPT_NOPROXY: - /* - * proxy exception list - */ - result = setstropt(&data->set.str[STRING_NOPROXY], - va_arg(param, char *)); - break; -#endif - - case CURLOPT_RANGE: - /* - * What range of the file you want to transfer - */ - result = setstropt(&data->set.str[STRING_SET_RANGE], - va_arg(param, char *)); - break; - case CURLOPT_RESUME_FROM: - /* - * Resume transfer at the given file position - */ - data->set.set_resume_from = va_arg(param, long); - break; - case CURLOPT_RESUME_FROM_LARGE: - /* - * Resume transfer at the given file position - */ - data->set.set_resume_from = va_arg(param, curl_off_t); - break; - case CURLOPT_DEBUGFUNCTION: - /* - * stderr write callback. - */ - data->set.fdebug = va_arg(param, curl_debug_callback); - /* - * if the callback provided is NULL, it'll use the default callback - */ - break; - case CURLOPT_DEBUGDATA: - /* - * Set to a void * that should receive all error writes. This - * defaults to CURLOPT_STDERR for normal operations. - */ - data->set.debugdata = va_arg(param, void *); - break; - case CURLOPT_STDERR: - /* - * Set to a FILE * that should receive all error writes. This - * defaults to stderr for normal operations. - */ - data->set.err = va_arg(param, FILE *); - if(!data->set.err) - data->set.err = stderr; - break; - case CURLOPT_HEADERFUNCTION: - /* - * Set header write callback - */ - data->set.fwrite_header = va_arg(param, curl_write_callback); - break; - case CURLOPT_WRITEFUNCTION: - /* - * Set data write callback - */ - data->set.fwrite_func = va_arg(param, curl_write_callback); - if(!data->set.fwrite_func) { - data->set.is_fwrite_set = 0; - /* When set to NULL, reset to our internal default function */ - data->set.fwrite_func = (curl_write_callback)fwrite; - } - else - data->set.is_fwrite_set = 1; - break; - case CURLOPT_READFUNCTION: - /* - * Read data callback - */ - data->set.fread_func_set = va_arg(param, curl_read_callback); - if(!data->set.fread_func_set) { - data->set.is_fread_set = 0; - /* When set to NULL, reset to our internal default function */ - data->set.fread_func_set = (curl_read_callback)fread; - } - else - data->set.is_fread_set = 1; - break; - case CURLOPT_SEEKFUNCTION: - /* - * Seek callback. Might be NULL. - */ - data->set.seek_func = va_arg(param, curl_seek_callback); - break; - case CURLOPT_SEEKDATA: - /* - * Seek control callback. Might be NULL. - */ - data->set.seek_client = va_arg(param, void *); - break; - case CURLOPT_CONV_FROM_NETWORK_FUNCTION: - /* - * "Convert from network encoding" callback - */ - data->set.convfromnetwork = va_arg(param, curl_conv_callback); - break; - case CURLOPT_CONV_TO_NETWORK_FUNCTION: - /* - * "Convert to network encoding" callback - */ - data->set.convtonetwork = va_arg(param, curl_conv_callback); - break; - case CURLOPT_CONV_FROM_UTF8_FUNCTION: - /* - * "Convert from UTF-8 encoding" callback - */ - data->set.convfromutf8 = va_arg(param, curl_conv_callback); - break; - case CURLOPT_IOCTLFUNCTION: - /* - * I/O control callback. Might be NULL. - */ - data->set.ioctl_func = va_arg(param, curl_ioctl_callback); - break; - case CURLOPT_IOCTLDATA: - /* - * I/O control data pointer. Might be NULL. - */ - data->set.ioctl_client = va_arg(param, void *); - break; - case CURLOPT_SSLCERT: - /* - * String that holds file name of the SSL certificate to use - */ - result = setstropt(&data->set.str[STRING_CERT_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_PROXY_SSLCERT: - /* - * String that holds file name of the SSL certificate to use for proxy - */ - result = setstropt(&data->set.str[STRING_CERT_PROXY], - va_arg(param, char *)); - break; - case CURLOPT_SSLCERTTYPE: - /* - * String that holds file type of the SSL certificate to use - */ - result = setstropt(&data->set.str[STRING_CERT_TYPE_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_PROXY_SSLCERTTYPE: - /* - * String that holds file type of the SSL certificate to use for proxy - */ - result = setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], - va_arg(param, char *)); - break; - case CURLOPT_SSLKEY: - /* - * String that holds file name of the SSL key to use - */ - result = setstropt(&data->set.str[STRING_KEY_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_PROXY_SSLKEY: - /* - * String that holds file name of the SSL key to use for proxy - */ - result = setstropt(&data->set.str[STRING_KEY_PROXY], - va_arg(param, char *)); - break; - case CURLOPT_SSLKEYTYPE: - /* - * String that holds file type of the SSL key to use - */ - result = setstropt(&data->set.str[STRING_KEY_TYPE_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_PROXY_SSLKEYTYPE: - /* - * String that holds file type of the SSL key to use for proxy - */ - result = setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], - va_arg(param, char *)); - break; - case CURLOPT_KEYPASSWD: - /* - * String that holds the SSL or SSH private key password. - */ - result = setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_PROXY_KEYPASSWD: - /* - * String that holds the SSL private key password for proxy. - */ - result = setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], - va_arg(param, char *)); - break; - case CURLOPT_SSLENGINE: - /* - * String that holds the SSL crypto engine. - */ - argptr = va_arg(param, char *); - if(argptr && argptr[0]) - result = Curl_ssl_set_engine(data, argptr); - break; - - case CURLOPT_SSLENGINE_DEFAULT: - /* - * flag to set engine as default. - */ - result = Curl_ssl_set_engine_default(data); - break; - case CURLOPT_CRLF: - /* - * Kludgy option to enable CRLF conversions. Subject for removal. - */ - data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_INTERFACE: - /* - * Set what interface or address/hostname to bind the socket to when - * performing an operation and thus what from-IP your connection will use. - */ - result = setstropt(&data->set.str[STRING_DEVICE], - va_arg(param, char *)); - break; - case CURLOPT_LOCALPORT: - /* - * Set what local port to bind the socket to when performing an operation. - */ - arg = va_arg(param, long); - if((arg < 0) || (arg > 65535)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.localport = curlx_sltous(arg); - break; - case CURLOPT_LOCALPORTRANGE: - /* - * Set number of local ports to try, starting with CURLOPT_LOCALPORT. - */ - arg = va_arg(param, long); - if((arg < 0) || (arg > 65535)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.localportrange = curlx_sltosi(arg); - break; - case CURLOPT_KRBLEVEL: - /* - * A string that defines the kerberos security level. - */ - result = setstropt(&data->set.str[STRING_KRB_LEVEL], - va_arg(param, char *)); - data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE; - break; - case CURLOPT_GSSAPI_DELEGATION: - /* - * GSS-API credential delegation - */ - data->set.gssapi_delegation = va_arg(param, long); - break; - case CURLOPT_SSL_VERIFYPEER: - /* - * Enable peer SSL verifying. - */ - data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ? - TRUE : FALSE; - break; - case CURLOPT_PROXY_SSL_VERIFYPEER: - /* - * Enable peer SSL verifying for proxy. - */ - data->set.proxy_ssl.primary.verifypeer = - (0 != va_arg(param, long))?TRUE:FALSE; - break; - case CURLOPT_SSL_VERIFYHOST: - /* - * Enable verification of the host name in the peer certificate - */ - arg = va_arg(param, long); - - /* Obviously people are not reading documentation and too many thought - this argument took a boolean when it wasn't and misused it. We thus ban - 1 as a sensible input and we warn about its use. Then we only have the - 2 action internally stored as TRUE. */ - - if(1 == arg) { - failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!"); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - - data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE; - break; - case CURLOPT_PROXY_SSL_VERIFYHOST: - /* - * Enable verification of the host name in the peer certificate for proxy - */ - arg = va_arg(param, long); - - /* Obviously people are not reading documentation and too many thought - this argument took a boolean when it wasn't and misused it. We thus ban - 1 as a sensible input and we warn about its use. Then we only have the - 2 action internally stored as TRUE. */ - - if(1 == arg) { - failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!"); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - - data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE; - break; - case CURLOPT_SSL_VERIFYSTATUS: - /* - * Enable certificate status verifying. - */ - if(!Curl_ssl_cert_status_request()) { - result = CURLE_NOT_BUILT_IN; - break; - } - - data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)) ? - TRUE : FALSE; - break; - case CURLOPT_SSL_CTX_FUNCTION: - /* - * Set a SSL_CTX callback - */ -#ifdef USE_SSL - if(Curl_ssl->have_ssl_ctx) - data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); - else -#endif - result = CURLE_NOT_BUILT_IN; - break; - case CURLOPT_SSL_CTX_DATA: - /* - * Set a SSL_CTX callback parameter pointer - */ -#ifdef USE_SSL - if(Curl_ssl->have_ssl_ctx) - data->set.ssl.fsslctxp = va_arg(param, void *); - else -#endif - result = CURLE_NOT_BUILT_IN; - break; - case CURLOPT_SSL_FALSESTART: - /* - * Enable TLS false start. - */ - if(!Curl_ssl_false_start()) { - result = CURLE_NOT_BUILT_IN; - break; - } - - data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_CERTINFO: -#ifdef USE_SSL - if(Curl_ssl->have_certinfo) - data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE; - else -#endif - result = CURLE_NOT_BUILT_IN; - break; - case CURLOPT_PINNEDPUBLICKEY: - /* - * Set pinned public key for SSL connection. - * Specify file name of the public key in DER format. - */ -#ifdef USE_SSL - if(Curl_ssl->have_pinnedpubkey) - result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG], - va_arg(param, char *)); - else -#endif - result = CURLE_NOT_BUILT_IN; - break; - case CURLOPT_PROXY_PINNEDPUBLICKEY: - /* - * Set pinned public key for SSL connection. - * Specify file name of the public key in DER format. - */ -#ifdef USE_SSL - if(Curl_ssl->have_pinnedpubkey) - result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], - va_arg(param, char *)); - else -#endif - result = CURLE_NOT_BUILT_IN; - break; - case CURLOPT_CAINFO: - /* - * Set CA info for SSL connection. Specify file name of the CA certificate - */ - result = setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_PROXY_CAINFO: - /* - * Set CA info SSL connection for proxy. Specify file name of the - * CA certificate - */ - result = setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], - va_arg(param, char *)); - break; - case CURLOPT_CAPATH: - /* - * Set CA path info for SSL connection. Specify directory name of the CA - * certificates which have been prepared using openssl c_rehash utility. - */ -#ifdef USE_SSL - if(Curl_ssl->have_ca_path) - /* This does not work on windows. */ - result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG], - va_arg(param, char *)); - else -#endif - result = CURLE_NOT_BUILT_IN; - break; - case CURLOPT_PROXY_CAPATH: - /* - * Set CA path info for SSL connection proxy. Specify directory name of the - * CA certificates which have been prepared using openssl c_rehash utility. - */ -#ifdef USE_SSL - if(Curl_ssl->have_ca_path) - /* This does not work on windows. */ - result = setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], - va_arg(param, char *)); - else -#endif - result = CURLE_NOT_BUILT_IN; - break; - case CURLOPT_CRLFILE: - /* - * Set CRL file info for SSL connection. Specify file name of the CRL - * to check certificates revocation - */ - result = setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_PROXY_CRLFILE: - /* - * Set CRL file info for SSL connection for proxy. Specify file name of the - * CRL to check certificates revocation - */ - result = setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], - va_arg(param, char *)); - break; - case CURLOPT_ISSUERCERT: - /* - * Set Issuer certificate file - * to check certificates issuer - */ - result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG], - va_arg(param, char *)); - break; - case CURLOPT_TELNETOPTIONS: - /* - * Set a linked list of telnet options - */ - data->set.telnet_options = va_arg(param, struct curl_slist *); - break; - - case CURLOPT_BUFFERSIZE: - /* - * The application kindly asks for a differently sized receive buffer. - * If it seems reasonable, we'll use it. - */ - arg = va_arg(param, long); - - if(arg > READBUFFER_MAX) - arg = READBUFFER_MAX; - else if(arg < 1) - arg = READBUFFER_SIZE; - else if(arg < READBUFFER_MIN) - arg = READBUFFER_MIN; - - /* Resize if new size */ - if(arg != data->set.buffer_size) { - char *newbuff = realloc(data->state.buffer, arg + 1); - if(!newbuff) { - DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n")); - result = CURLE_OUT_OF_MEMORY; - } - else - data->state.buffer = newbuff; - } - data->set.buffer_size = arg; - - break; - - case CURLOPT_NOSIGNAL: - /* - * The application asks not to set any signal() or alarm() handlers, - * even when using a timeout. - */ - data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_SHARE: - { - struct Curl_share *set; - set = va_arg(param, struct Curl_share *); - - /* disconnect from old share, if any */ - if(data->share) { - Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); - - if(data->dns.hostcachetype == HCACHE_SHARED) { - data->dns.hostcache = NULL; - data->dns.hostcachetype = HCACHE_NONE; - } - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(data->share->cookies == data->cookies) - data->cookies = NULL; -#endif - - if(data->share->sslsession == data->state.session) - data->state.session = NULL; - - data->share->dirty--; - - Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); - data->share = NULL; - } - - /* use new share if it set */ - data->share = set; - if(data->share) { - - Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); - - data->share->dirty++; - - if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) { - /* use shared host cache */ - data->dns.hostcache = &data->share->hostcache; - data->dns.hostcachetype = HCACHE_SHARED; - } -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(data->share->cookies) { - /* use shared cookie list, first free own one if any */ - Curl_cookie_cleanup(data->cookies); - /* enable cookies since we now use a share that uses cookies! */ - data->cookies = data->share->cookies; - } -#endif /* CURL_DISABLE_HTTP */ - if(data->share->sslsession) { - data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; - data->state.session = data->share->sslsession; - } - Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); - - } - /* check for host cache not needed, - * it will be done by curl_easy_perform */ - } - break; - - case CURLOPT_PRIVATE: - /* - * Set private data pointer. - */ - data->set.private_data = va_arg(param, void *); - break; - - case CURLOPT_MAXFILESIZE: - /* - * Set the maximum size of a file to download. - */ - data->set.max_filesize = va_arg(param, long); - break; - -#ifdef USE_SSL - case CURLOPT_USE_SSL: - /* - * Make transfers attempt to use SSL/TLS. - */ - data->set.use_ssl = (curl_usessl)va_arg(param, long); - break; - - case CURLOPT_SSL_OPTIONS: - arg = va_arg(param, long); - data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; - data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); - break; - - case CURLOPT_PROXY_SSL_OPTIONS: - arg = va_arg(param, long); - data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; - data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); - break; - -#endif - case CURLOPT_FTPSSLAUTH: - /* - * Set a specific auth for FTP-SSL transfers. - */ - data->set.ftpsslauth = (curl_ftpauth)va_arg(param, long); - break; - - case CURLOPT_IPRESOLVE: - data->set.ipver = va_arg(param, long); - break; - - case CURLOPT_MAXFILESIZE_LARGE: - /* - * Set the maximum size of a file to download. - */ - data->set.max_filesize = va_arg(param, curl_off_t); - break; - - case CURLOPT_TCP_NODELAY: - /* - * Enable or disable TCP_NODELAY, which will disable/enable the Nagle - * algorithm - */ - data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_FTP_ACCOUNT: - result = setstropt(&data->set.str[STRING_FTP_ACCOUNT], - va_arg(param, char *)); - break; - - case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_CONNECT_ONLY: - /* - * No data transfer, set up connection and let application use the socket - */ - data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_FTP_ALTERNATIVE_TO_USER: - result = setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER], - va_arg(param, char *)); - break; - - case CURLOPT_SOCKOPTFUNCTION: - /* - * socket callback function: called after socket() but before connect() - */ - data->set.fsockopt = va_arg(param, curl_sockopt_callback); - break; - - case CURLOPT_SOCKOPTDATA: - /* - * socket callback data pointer. Might be NULL. - */ - data->set.sockopt_client = va_arg(param, void *); - break; - - case CURLOPT_OPENSOCKETFUNCTION: - /* - * open/create socket callback function: called instead of socket(), - * before connect() - */ - data->set.fopensocket = va_arg(param, curl_opensocket_callback); - break; - - case CURLOPT_OPENSOCKETDATA: - /* - * socket callback data pointer. Might be NULL. - */ - data->set.opensocket_client = va_arg(param, void *); - break; - - case CURLOPT_CLOSESOCKETFUNCTION: - /* - * close socket callback function: called instead of close() - * when shutting down a connection - */ - data->set.fclosesocket = va_arg(param, curl_closesocket_callback); - break; - - case CURLOPT_CLOSESOCKETDATA: - /* - * socket callback data pointer. Might be NULL. - */ - data->set.closesocket_client = va_arg(param, void *); - break; - - case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ? - TRUE : FALSE; - data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid; - break; - -#ifdef USE_LIBSSH2 - /* we only include SSH options if explicitly built to support SSH */ - case CURLOPT_SSH_AUTH_TYPES: - data->set.ssh_auth_types = va_arg(param, long); - break; - - case CURLOPT_SSH_PUBLIC_KEYFILE: - /* - * Use this file instead of the $HOME/.ssh/id_dsa.pub file - */ - result = setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY], - va_arg(param, char *)); - break; - - case CURLOPT_SSH_PRIVATE_KEYFILE: - /* - * Use this file instead of the $HOME/.ssh/id_dsa file - */ - result = setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], - va_arg(param, char *)); - break; - case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: - /* - * Option to allow for the MD5 of the host public key to be checked - * for validation purposes. - */ - result = setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], - va_arg(param, char *)); - break; -#ifdef HAVE_LIBSSH2_KNOWNHOST_API - case CURLOPT_SSH_KNOWNHOSTS: - /* - * Store the file name to read known hosts from. - */ - result = setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS], - va_arg(param, char *)); - break; - - case CURLOPT_SSH_KEYFUNCTION: - /* setting to NULL is fine since the ssh.c functions themselves will - then rever to use the internal default */ - data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback); - break; - - case CURLOPT_SSH_KEYDATA: - /* - * Custom client data to pass to the SSH keyfunc callback - */ - data->set.ssh_keyfunc_userp = va_arg(param, void *); - break; -#endif /* HAVE_LIBSSH2_KNOWNHOST_API */ - -#endif /* USE_LIBSSH2 */ - - case CURLOPT_HTTP_TRANSFER_DECODING: - /* - * disable libcurl transfer encoding is used - */ - data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_HTTP_CONTENT_DECODING: - /* - * raw data passed to the application when content encoding is used - */ - data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_NEW_FILE_PERMS: - /* - * Uses these permissions instead of 0644 - */ - data->set.new_file_perms = va_arg(param, long); - break; - - case CURLOPT_NEW_DIRECTORY_PERMS: - /* - * Uses these permissions instead of 0755 - */ - data->set.new_directory_perms = va_arg(param, long); - break; - - case CURLOPT_ADDRESS_SCOPE: - /* - * We always get longs when passed plain numericals, but for this value we - * know that an unsigned int will always hold the value so we blindly - * typecast to this type - */ - arg = va_arg(param, long); - if((arg < 0) || (arg > 0xf)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.scope_id = curlx_sltoui(arg); - break; - - case CURLOPT_PROTOCOLS: - /* set the bitmask for the protocols that are allowed to be used for the - transfer, which thus helps the app which takes URLs from users or other - external inputs and want to restrict what protocol(s) to deal - with. Defaults to CURLPROTO_ALL. */ - data->set.allowed_protocols = va_arg(param, long); - break; - - case CURLOPT_REDIR_PROTOCOLS: - /* set the bitmask for the protocols that libcurl is allowed to follow to, - as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs - to be set in both bitmasks to be allowed to get redirected to. Defaults - to all protocols except FILE and SCP. */ - data->set.redir_protocols = va_arg(param, long); - break; - - case CURLOPT_DEFAULT_PROTOCOL: - /* Set the protocol to use when the URL doesn't include any protocol */ - result = setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], - va_arg(param, char *)); - break; - - case CURLOPT_MAIL_FROM: - /* Set the SMTP mail originator */ - result = setstropt(&data->set.str[STRING_MAIL_FROM], - va_arg(param, char *)); - break; - - case CURLOPT_MAIL_AUTH: - /* Set the SMTP auth originator */ - result = setstropt(&data->set.str[STRING_MAIL_AUTH], - va_arg(param, char *)); - break; - - case CURLOPT_MAIL_RCPT: - /* Set the list of mail recipients */ - data->set.mail_rcpt = va_arg(param, struct curl_slist *); - break; - - case CURLOPT_SASL_IR: - /* Enable/disable SASL initial response */ - data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - - case CURLOPT_RTSP_REQUEST: - { - /* - * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...) - * Would this be better if the RTSPREQ_* were just moved into here? - */ - long curl_rtspreq = va_arg(param, long); - Curl_RtspReq rtspreq = RTSPREQ_NONE; - switch(curl_rtspreq) { - case CURL_RTSPREQ_OPTIONS: - rtspreq = RTSPREQ_OPTIONS; - break; - - case CURL_RTSPREQ_DESCRIBE: - rtspreq = RTSPREQ_DESCRIBE; - break; - - case CURL_RTSPREQ_ANNOUNCE: - rtspreq = RTSPREQ_ANNOUNCE; - break; - - case CURL_RTSPREQ_SETUP: - rtspreq = RTSPREQ_SETUP; - break; - - case CURL_RTSPREQ_PLAY: - rtspreq = RTSPREQ_PLAY; - break; - - case CURL_RTSPREQ_PAUSE: - rtspreq = RTSPREQ_PAUSE; - break; - - case CURL_RTSPREQ_TEARDOWN: - rtspreq = RTSPREQ_TEARDOWN; - break; - - case CURL_RTSPREQ_GET_PARAMETER: - rtspreq = RTSPREQ_GET_PARAMETER; - break; - - case CURL_RTSPREQ_SET_PARAMETER: - rtspreq = RTSPREQ_SET_PARAMETER; - break; - - case CURL_RTSPREQ_RECORD: - rtspreq = RTSPREQ_RECORD; - break; - - case CURL_RTSPREQ_RECEIVE: - rtspreq = RTSPREQ_RECEIVE; - break; - default: - rtspreq = RTSPREQ_NONE; - } - - data->set.rtspreq = rtspreq; - break; - } - - - case CURLOPT_RTSP_SESSION_ID: - /* - * Set the RTSP Session ID manually. Useful if the application is - * resuming a previously established RTSP session - */ - result = setstropt(&data->set.str[STRING_RTSP_SESSION_ID], - va_arg(param, char *)); - break; - - case CURLOPT_RTSP_STREAM_URI: - /* - * Set the Stream URI for the RTSP request. Unless the request is - * for generic server options, the application will need to set this. - */ - result = setstropt(&data->set.str[STRING_RTSP_STREAM_URI], - va_arg(param, char *)); - break; - - case CURLOPT_RTSP_TRANSPORT: - /* - * The content of the Transport: header for the RTSP request - */ - result = setstropt(&data->set.str[STRING_RTSP_TRANSPORT], - va_arg(param, char *)); - break; - - case CURLOPT_RTSP_CLIENT_CSEQ: - /* - * Set the CSEQ number to issue for the next RTSP request. Useful if the - * application is resuming a previously broken connection. The CSEQ - * will increment from this new number henceforth. - */ - data->state.rtsp_next_client_CSeq = va_arg(param, long); - break; - - case CURLOPT_RTSP_SERVER_CSEQ: - /* Same as the above, but for server-initiated requests */ - data->state.rtsp_next_client_CSeq = va_arg(param, long); - break; - - case CURLOPT_INTERLEAVEDATA: - data->set.rtp_out = va_arg(param, void *); - break; - case CURLOPT_INTERLEAVEFUNCTION: - /* Set the user defined RTP write function */ - data->set.fwrite_rtp = va_arg(param, curl_write_callback); - break; - - case CURLOPT_WILDCARDMATCH: - data->set.wildcardmatch = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_CHUNK_BGN_FUNCTION: - data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); - break; - case CURLOPT_CHUNK_END_FUNCTION: - data->set.chunk_end = va_arg(param, curl_chunk_end_callback); - break; - case CURLOPT_FNMATCH_FUNCTION: - data->set.fnmatch = va_arg(param, curl_fnmatch_callback); - break; - case CURLOPT_CHUNK_DATA: - data->wildcard.customptr = va_arg(param, void *); - break; - case CURLOPT_FNMATCH_DATA: - data->set.fnmatch_data = va_arg(param, void *); - break; -#ifdef USE_TLS_SRP - case CURLOPT_TLSAUTH_USERNAME: - result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG], - va_arg(param, char *)); - if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) - data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ - break; - case CURLOPT_PROXY_TLSAUTH_USERNAME: - result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], - va_arg(param, char *)); - if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && - !data->set.proxy_ssl.authtype) - data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ - break; - case CURLOPT_TLSAUTH_PASSWORD: - result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG], - va_arg(param, char *)); - if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) - data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ - break; - case CURLOPT_PROXY_TLSAUTH_PASSWORD: - result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], - va_arg(param, char *)); - if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && - !data->set.proxy_ssl.authtype) - data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ - break; - case CURLOPT_TLSAUTH_TYPE: - argptr = va_arg(param, char *); - if(!argptr || - strncasecompare(argptr, "SRP", strlen("SRP"))) - data->set.ssl.authtype = CURL_TLSAUTH_SRP; - else - data->set.ssl.authtype = CURL_TLSAUTH_NONE; - break; - case CURLOPT_PROXY_TLSAUTH_TYPE: - argptr = va_arg(param, char *); - if(!argptr || - strncasecompare(argptr, "SRP", strlen("SRP"))) - data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; - else - data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE; - break; -#endif - case CURLOPT_DNS_SERVERS: - result = Curl_set_dns_servers(data, va_arg(param, char *)); - break; - case CURLOPT_DNS_INTERFACE: - result = Curl_set_dns_interface(data, va_arg(param, char *)); - break; - case CURLOPT_DNS_LOCAL_IP4: - result = Curl_set_dns_local_ip4(data, va_arg(param, char *)); - break; - case CURLOPT_DNS_LOCAL_IP6: - result = Curl_set_dns_local_ip6(data, va_arg(param, char *)); - break; - - case CURLOPT_TCP_KEEPALIVE: - data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_TCP_KEEPIDLE: - data->set.tcp_keepidle = va_arg(param, long); - break; - case CURLOPT_TCP_KEEPINTVL: - data->set.tcp_keepintvl = va_arg(param, long); - break; - case CURLOPT_TCP_FASTOPEN: -#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) - data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE; -#else - result = CURLE_NOT_BUILT_IN; -#endif - break; - case CURLOPT_SSL_ENABLE_NPN: - data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_SSL_ENABLE_ALPN: - data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - -#ifdef USE_UNIX_SOCKETS - case CURLOPT_UNIX_SOCKET_PATH: - data->set.abstract_unix_socket = FALSE; - result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], - va_arg(param, char *)); - break; - case CURLOPT_ABSTRACT_UNIX_SOCKET: - data->set.abstract_unix_socket = TRUE; - result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], - va_arg(param, char *)); - break; -#endif - - case CURLOPT_PATH_AS_IS: - data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_PIPEWAIT: - data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE; - break; - case CURLOPT_STREAM_WEIGHT: -#ifndef USE_NGHTTP2 - return CURLE_NOT_BUILT_IN; -#else - arg = va_arg(param, long); - if((arg >= 1) && (arg <= 256)) - data->set.stream_weight = (int)arg; - break; -#endif - case CURLOPT_STREAM_DEPENDS: - case CURLOPT_STREAM_DEPENDS_E: - { -#ifndef USE_NGHTTP2 - return CURLE_NOT_BUILT_IN; -#else - struct Curl_easy *dep = va_arg(param, struct Curl_easy *); - if(!dep || GOOD_EASY_HANDLE(dep)) { - if(data->set.stream_depends_on) { - Curl_http2_remove_child(data->set.stream_depends_on, data); - } - Curl_http2_add_child(dep, data, (option == CURLOPT_STREAM_DEPENDS_E)); - } - break; -#endif - } - case CURLOPT_CONNECT_TO: - data->set.connect_to = va_arg(param, struct curl_slist *); - break; - case CURLOPT_SUPPRESS_CONNECT_HEADERS: - data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE; - break; - case CURLOPT_SSH_COMPRESSION: - data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE; - break; - default: - /* unknown tag and its companion, just ignore: */ - result = CURLE_UNKNOWN_OPTION; - break; - } - - return result; -} - -#ifdef USE_RECV_BEFORE_SEND_WORKAROUND -static void conn_reset_postponed_data(struct connectdata *conn, int num) -{ - struct postponed_data * const psnd = &(conn->postponed[num]); - if(psnd->buffer) { - DEBUGASSERT(psnd->allocated_size > 0); - DEBUGASSERT(psnd->recv_size <= psnd->allocated_size); - DEBUGASSERT(psnd->recv_size ? - (psnd->recv_processed < psnd->recv_size) : - (psnd->recv_processed == 0)); - DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD); - free(psnd->buffer); - psnd->buffer = NULL; - psnd->allocated_size = 0; - psnd->recv_size = 0; - psnd->recv_processed = 0; -#ifdef DEBUGBUILD - psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */ -#endif /* DEBUGBUILD */ - } - else { - DEBUGASSERT(psnd->allocated_size == 0); - DEBUGASSERT(psnd->recv_size == 0); - DEBUGASSERT(psnd->recv_processed == 0); - DEBUGASSERT(psnd->bindsock == CURL_SOCKET_BAD); - } -} - -static void conn_reset_all_postponed_data(struct connectdata *conn) -{ - conn_reset_postponed_data(conn, 0); - conn_reset_postponed_data(conn, 1); -} -#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ -/* Use "do-nothing" macro instead of function when workaround not used */ -#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE -#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ - -static void conn_free(struct connectdata *conn) -{ - if(!conn) - return; - - /* possible left-overs from the async name resolvers */ - Curl_resolver_cancel(conn); - - /* close the SSL stuff before we close any sockets since they will/may - write to the sockets */ - Curl_ssl_close(conn, FIRSTSOCKET); - Curl_ssl_close(conn, SECONDARYSOCKET); - - /* close possibly still open sockets */ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); - if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET]) - Curl_closesocket(conn, conn->sock[FIRSTSOCKET]); - if(CURL_SOCKET_BAD != conn->tempsock[0]) - Curl_closesocket(conn, conn->tempsock[0]); - if(CURL_SOCKET_BAD != conn->tempsock[1]) - Curl_closesocket(conn, conn->tempsock[1]); - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ - defined(NTLM_WB_ENABLED) - Curl_ntlm_wb_cleanup(conn); -#endif - - Curl_safefree(conn->user); - Curl_safefree(conn->passwd); - Curl_safefree(conn->oauth_bearer); - Curl_safefree(conn->options); - Curl_safefree(conn->http_proxy.user); - Curl_safefree(conn->socks_proxy.user); - Curl_safefree(conn->http_proxy.passwd); - Curl_safefree(conn->socks_proxy.passwd); - Curl_safefree(conn->allocptr.proxyuserpwd); - Curl_safefree(conn->allocptr.uagent); - Curl_safefree(conn->allocptr.userpwd); - Curl_safefree(conn->allocptr.accept_encoding); - Curl_safefree(conn->allocptr.te); - Curl_safefree(conn->allocptr.rangeline); - Curl_safefree(conn->allocptr.ref); - Curl_safefree(conn->allocptr.host); - Curl_safefree(conn->allocptr.cookiehost); - Curl_safefree(conn->allocptr.rtsp_transport); - Curl_safefree(conn->trailer); - Curl_safefree(conn->host.rawalloc); /* host name buffer */ - Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ - Curl_safefree(conn->secondaryhostname); - Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ - Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ - Curl_safefree(conn->master_buffer); - Curl_safefree(conn->connect_state); - - conn_reset_all_postponed_data(conn); - - Curl_llist_destroy(&conn->send_pipe, NULL); - Curl_llist_destroy(&conn->recv_pipe, NULL); - - Curl_safefree(conn->localdev); - Curl_free_primary_ssl_config(&conn->ssl_config); - Curl_free_primary_ssl_config(&conn->proxy_ssl_config); - -#ifdef USE_UNIX_SOCKETS - Curl_safefree(conn->unix_domain_socket); -#endif - - free(conn); /* free all the connection oriented data */ -} - -/* - * Disconnects the given connection. Note the connection may not be the - * primary connection, like when freeing room in the connection cache or - * killing of a dead old connection. - * - * This function MUST NOT reset state in the Curl_easy struct if that - * isn't strictly bound to the life-time of *this* particular connection. - * - */ - -CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) -{ - struct Curl_easy *data; - if(!conn) - return CURLE_OK; /* this is closed and fine already */ - data = conn->data; - - if(!data) { - DEBUGF(fprintf(stderr, "DISCONNECT without easy handle, ignoring\n")); - return CURLE_OK; - } - - /* - * If this connection isn't marked to force-close, leave it open if there - * are other users of it - */ - if(!conn->bits.close && - (conn->send_pipe.size + conn->recv_pipe.size)) { - DEBUGF(infof(data, "Curl_disconnect, usecounter: %d\n", - conn->send_pipe.size + conn->recv_pipe.size)); - return CURLE_OK; - } - - if(conn->dns_entry != NULL) { - Curl_resolv_unlock(data, conn->dns_entry); - conn->dns_entry = NULL; - } - - Curl_hostcache_prune(data); /* kill old DNS cache entries */ - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) - /* Cleanup NTLM connection-related data */ - Curl_http_ntlm_cleanup(conn); -#endif - - if(conn->handler->disconnect) - /* This is set if protocol-specific cleanups should be made */ - conn->handler->disconnect(conn, dead_connection); - - /* unlink ourselves! */ - infof(data, "Closing connection %ld\n", conn->connection_id); - Curl_conncache_remove_conn(data->state.conn_cache, conn); - - free_fixed_hostname(&conn->host); - free_fixed_hostname(&conn->conn_to_host); - free_fixed_hostname(&conn->http_proxy.host); - free_fixed_hostname(&conn->socks_proxy.host); - - Curl_ssl_close(conn, FIRSTSOCKET); - - /* Indicate to all handles on the pipe that we're dead */ - if(Curl_pipeline_wanted(data->multi, CURLPIPE_ANY)) { - signalPipeClose(&conn->send_pipe, TRUE); - signalPipeClose(&conn->recv_pipe, TRUE); - } - - conn_free(conn); - - return CURLE_OK; -} - -/* - * This function should return TRUE if the socket is to be assumed to - * be dead. Most commonly this happens when the server has closed the - * connection due to inactivity. - */ -static bool SocketIsDead(curl_socket_t sock) -{ - int sval; - bool ret_val = TRUE; - - sval = SOCKET_READABLE(sock, 0); - if(sval == 0) - /* timeout */ - ret_val = FALSE; - - return ret_val; -} - -/* - * IsPipeliningPossible() - * - * Return a bitmask with the available pipelining and multiplexing options for - * the given requested connection. - */ -static int IsPipeliningPossible(const struct Curl_easy *handle, - const struct connectdata *conn) -{ - int avail = 0; - - /* If a HTTP protocol and pipelining is enabled */ - if((conn->handler->protocol & PROTO_FAMILY_HTTP) && - (!conn->bits.protoconnstart || !conn->bits.close)) { - - if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && - (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && - (handle->set.httpreq == HTTPREQ_GET || - handle->set.httpreq == HTTPREQ_HEAD)) - /* didn't ask for HTTP/1.0 and a GET or HEAD */ - avail |= CURLPIPE_HTTP1; - - if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) && - (handle->set.httpversion >= CURL_HTTP_VERSION_2)) - /* allows HTTP/2 */ - avail |= CURLPIPE_MULTIPLEX; - } - return avail; -} - -int Curl_removeHandleFromPipeline(struct Curl_easy *handle, - struct curl_llist *pipeline) -{ - if(pipeline) { - struct curl_llist_element *curr; - - curr = pipeline->head; - while(curr) { - if(curr->ptr == handle) { - Curl_llist_remove(pipeline, curr, NULL); - return 1; /* we removed a handle */ - } - curr = curr->next; - } - } - - return 0; -} - -#if 0 /* this code is saved here as it is useful for debugging purposes */ -static void Curl_printPipeline(struct curl_llist *pipeline) -{ - struct curl_llist_element *curr; - - curr = pipeline->head; - while(curr) { - struct Curl_easy *data = (struct Curl_easy *) curr->ptr; - infof(data, "Handle in pipeline: %s\n", data->state.path); - curr = curr->next; - } -} -#endif - -static struct Curl_easy* gethandleathead(struct curl_llist *pipeline) -{ - struct curl_llist_element *curr = pipeline->head; - if(curr) { - return (struct Curl_easy *) curr->ptr; - } - - return NULL; -} - -/* remove the specified connection from all (possible) pipelines and related - queues */ -void Curl_getoff_all_pipelines(struct Curl_easy *data, - struct connectdata *conn) -{ - bool recv_head = (conn->readchannel_inuse && - Curl_recvpipe_head(data, conn)); - bool send_head = (conn->writechannel_inuse && - Curl_sendpipe_head(data, conn)); - - if(Curl_removeHandleFromPipeline(data, &conn->recv_pipe) && recv_head) - Curl_pipeline_leave_read(conn); - if(Curl_removeHandleFromPipeline(data, &conn->send_pipe) && send_head) - Curl_pipeline_leave_write(conn); -} - -static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) -{ - struct curl_llist_element *curr; - - if(!pipeline) - return; - - curr = pipeline->head; - while(curr) { - struct curl_llist_element *next = curr->next; - struct Curl_easy *data = (struct Curl_easy *) curr->ptr; - -#ifdef DEBUGBUILD /* debug-only code */ - if(data->magic != CURLEASY_MAGIC_NUMBER) { - /* MAJOR BADNESS */ - infof(data, "signalPipeClose() found BAAD easy handle\n"); - } -#endif - - if(pipe_broke) - data->state.pipe_broke = TRUE; - Curl_multi_handlePipeBreak(data); - Curl_llist_remove(pipeline, curr, NULL); - curr = next; - } -} - -/* - * This function finds the connection in the connection - * cache that has been unused for the longest time. - * - * Returns the pointer to the oldest idle connection, or NULL if none was - * found. - */ -struct connectdata * -Curl_oldest_idle_connection(struct Curl_easy *data) -{ - struct conncache *bc = data->state.conn_cache; - struct curl_hash_iterator iter; - struct curl_llist_element *curr; - struct curl_hash_element *he; - time_t highscore =- 1; - time_t score; - struct curltime now; - struct connectdata *conn_candidate = NULL; - struct connectbundle *bundle; - - now = Curl_tvnow(); - - Curl_hash_start_iterate(&bc->hash, &iter); - - he = Curl_hash_next_element(&iter); - while(he) { - struct connectdata *conn; - - bundle = he->ptr; - - curr = bundle->conn_list.head; - while(curr) { - conn = curr->ptr; - - if(!conn->inuse) { - /* Set higher score for the age passed since the connection was used */ - score = Curl_tvdiff(now, conn->now); - - if(score > highscore) { - highscore = score; - conn_candidate = conn; - } - } - curr = curr->next; - } - - he = Curl_hash_next_element(&iter); - } - - return conn_candidate; -} - -static bool -proxy_info_matches(const struct proxy_info* data, - const struct proxy_info* needle) -{ - if((data->proxytype == needle->proxytype) && - (data->port == needle->port) && - Curl_safe_strcasecompare(data->host.name, needle->host.name)) - return TRUE; - - return FALSE; -} - - -/* - * This function finds the connection in the connection - * bundle that has been unused for the longest time. - * - * Returns the pointer to the oldest idle connection, or NULL if none was - * found. - */ -static struct connectdata * -find_oldest_idle_connection_in_bundle(struct Curl_easy *data, - struct connectbundle *bundle) -{ - struct curl_llist_element *curr; - time_t highscore = -1; - time_t score; - struct curltime now; - struct connectdata *conn_candidate = NULL; - struct connectdata *conn; - - (void)data; - - now = Curl_tvnow(); - - curr = bundle->conn_list.head; - while(curr) { - conn = curr->ptr; - - if(!conn->inuse) { - /* Set higher score for the age passed since the connection was used */ - score = Curl_tvdiff(now, conn->now); - - if(score > highscore) { - highscore = score; - conn_candidate = conn; - } - } - curr = curr->next; - } - - return conn_candidate; -} - -/* - * This function checks if given connection is dead and disconnects if so. - * (That also removes it from the connection cache.) - * - * Returns TRUE if the connection actually was dead and disconnected. - */ -static bool disconnect_if_dead(struct connectdata *conn, - struct Curl_easy *data) -{ - size_t pipeLen = conn->send_pipe.size + conn->recv_pipe.size; - if(!pipeLen && !conn->inuse) { - /* The check for a dead socket makes sense only if there are no - handles in pipeline and the connection isn't already marked in - use */ - bool dead; - - if(conn->handler->connection_check) { - /* The protocol has a special method for checking the state of the - connection. Use it to check if the connection is dead. */ - unsigned int state; - - state = conn->handler->connection_check(conn, CONNCHECK_ISDEAD); - dead = (state & CONNRESULT_DEAD); - } - else { - /* Use the general method for determining the death of a connection */ - dead = SocketIsDead(conn->sock[FIRSTSOCKET]); - } - - if(dead) { - conn->data = data; - infof(data, "Connection %ld seems to be dead!\n", conn->connection_id); - - /* disconnect resources */ - Curl_disconnect(conn, /* dead_connection */TRUE); - return TRUE; - } - } - return FALSE; -} - -/* - * Wrapper to use disconnect_if_dead() function in Curl_conncache_foreach() - * - * Returns always 0. - */ -static int call_disconnect_if_dead(struct connectdata *conn, - void *param) -{ - struct Curl_easy* data = (struct Curl_easy*)param; - disconnect_if_dead(conn, data); - return 0; /* continue iteration */ -} - -/* - * This function scans the connection cache for half-open/dead connections, - * closes and removes them. - * The cleanup is done at most once per second. - */ -static void prune_dead_connections(struct Curl_easy *data) -{ - struct curltime now = Curl_tvnow(); - time_t elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup); - - if(elapsed >= 1000L) { - Curl_conncache_foreach(data->state.conn_cache, data, - call_disconnect_if_dead); - data->state.conn_cache->last_cleanup = now; - } -} - - -static size_t max_pipeline_length(struct Curl_multi *multi) -{ - return multi ? multi->max_pipeline_length : 0; -} - - -/* - * Given one filled in connection struct (named needle), this function should - * detect if there already is one that has all the significant details - * exactly the same and thus should be used instead. - * - * If there is a match, this function returns TRUE - and has marked the - * connection as 'in-use'. It must later be called with ConnectionDone() to - * return back to 'idle' (unused) state. - * - * The force_reuse flag is set if the connection must be used, even if - * the pipelining strategy wants to open a new connection instead of reusing. - */ -static bool -ConnectionExists(struct Curl_easy *data, - struct connectdata *needle, - struct connectdata **usethis, - bool *force_reuse, - bool *waitpipe) -{ - struct connectdata *check; - struct connectdata *chosen = 0; - bool foundPendingCandidate = FALSE; - int canpipe = IsPipeliningPossible(data, needle); - struct connectbundle *bundle; - -#ifdef USE_NTLM - bool wantNTLMhttp = ((data->state.authhost.want & - (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && - (needle->handler->protocol & PROTO_FAMILY_HTTP)); - bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd && - ((data->state.authproxy.want & - (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && - (needle->handler->protocol & PROTO_FAMILY_HTTP))); -#endif - - *force_reuse = FALSE; - *waitpipe = FALSE; - - /* We can't pipeline if the site is blacklisted */ - if((canpipe & CURLPIPE_HTTP1) && - Curl_pipeline_site_blacklisted(data, needle)) - canpipe &= ~ CURLPIPE_HTTP1; - - /* Look up the bundle with all the connections to this - particular host */ - bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache); - if(bundle) { - /* Max pipe length is zero (unlimited) for multiplexed connections */ - size_t max_pipe_len = (bundle->multiuse != BUNDLE_MULTIPLEX)? - max_pipeline_length(data->multi):0; - size_t best_pipe_len = max_pipe_len; - struct curl_llist_element *curr; - - infof(data, "Found bundle for host %s: %p [%s]\n", - (needle->bits.conn_to_host ? needle->conn_to_host.name : - needle->host.name), (void *)bundle, - (bundle->multiuse == BUNDLE_PIPELINING ? - "can pipeline" : - (bundle->multiuse == BUNDLE_MULTIPLEX ? - "can multiplex" : "serially"))); - - /* We can't pipeline if we don't know anything about the server */ - if(canpipe) { - if(bundle->multiuse <= BUNDLE_UNKNOWN) { - if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) { - infof(data, "Server doesn't support multi-use yet, wait\n"); - *waitpipe = TRUE; - return FALSE; /* no re-use */ - } - - infof(data, "Server doesn't support multi-use (yet)\n"); - canpipe = 0; - } - if((bundle->multiuse == BUNDLE_PIPELINING) && - !Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1)) { - /* not asked for, switch off */ - infof(data, "Could pipeline, but not asked to!\n"); - canpipe = 0; - } - else if((bundle->multiuse == BUNDLE_MULTIPLEX) && - !Curl_pipeline_wanted(data->multi, CURLPIPE_MULTIPLEX)) { - infof(data, "Could multiplex, but not asked to!\n"); - canpipe = 0; - } - } - - curr = bundle->conn_list.head; - while(curr) { - bool match = FALSE; - size_t pipeLen; - - /* - * Note that if we use a HTTP proxy in normal mode (no tunneling), we - * check connections to that proxy and not to the actual remote server. - */ - check = curr->ptr; - curr = curr->next; - - if(disconnect_if_dead(check, data)) - continue; - - pipeLen = check->send_pipe.size + check->recv_pipe.size; - - if(canpipe) { - if(check->bits.protoconnstart && check->bits.close) - continue; - - if(!check->bits.multiplex) { - /* If not multiplexing, make sure the connection is fine for HTTP/1 - pipelining */ - struct Curl_easy* sh = gethandleathead(&check->send_pipe); - struct Curl_easy* rh = gethandleathead(&check->recv_pipe); - if(sh) { - if(!(IsPipeliningPossible(sh, check) & CURLPIPE_HTTP1)) - continue; - } - else if(rh) { - if(!(IsPipeliningPossible(rh, check) & CURLPIPE_HTTP1)) - continue; - } - } - } - else { - if(pipeLen > 0) { - /* can only happen within multi handles, and means that another easy - handle is using this connection */ - continue; - } - - if(Curl_resolver_asynch()) { - /* ip_addr_str[0] is NUL only if the resolving of the name hasn't - completed yet and until then we don't re-use this connection */ - if(!check->ip_addr_str[0]) { - infof(data, - "Connection #%ld is still name resolving, can't reuse\n", - check->connection_id); - continue; - } - } - - if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || - check->bits.close) { - if(!check->bits.close) - foundPendingCandidate = TRUE; - /* Don't pick a connection that hasn't connected yet or that is going - to get closed. */ - infof(data, "Connection #%ld isn't open enough, can't reuse\n", - check->connection_id); -#ifdef DEBUGBUILD - if(check->recv_pipe.size > 0) { - infof(data, - "BAD! Unconnected #%ld has a non-empty recv pipeline!\n", - check->connection_id); - } -#endif - continue; - } - } - -#ifdef USE_UNIX_SOCKETS - if(needle->unix_domain_socket) { - if(!check->unix_domain_socket) - continue; - if(strcmp(needle->unix_domain_socket, check->unix_domain_socket)) - continue; - if(needle->abstract_unix_socket != check->abstract_unix_socket) - continue; - } - else if(check->unix_domain_socket) - continue; -#endif - - if((needle->handler->flags&PROTOPT_SSL) != - (check->handler->flags&PROTOPT_SSL)) - /* don't do mixed SSL and non-SSL connections */ - if(get_protocol_family(check->handler->protocol) != - needle->handler->protocol || !check->tls_upgraded) - /* except protocols that have been upgraded via TLS */ - continue; - - if(needle->bits.httpproxy != check->bits.httpproxy || - needle->bits.socksproxy != check->bits.socksproxy) - continue; - - if(needle->bits.socksproxy && !proxy_info_matches(&needle->socks_proxy, - &check->socks_proxy)) - continue; - - if(needle->bits.conn_to_host != check->bits.conn_to_host) - /* don't mix connections that use the "connect to host" feature and - * connections that don't use this feature */ - continue; - - if(needle->bits.conn_to_port != check->bits.conn_to_port) - /* don't mix connections that use the "connect to port" feature and - * connections that don't use this feature */ - continue; - - if(needle->bits.httpproxy) { - if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy)) - continue; - - if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy) - continue; - - if(needle->http_proxy.proxytype == CURLPROXY_HTTPS) { - /* use https proxy */ - if(needle->handler->flags&PROTOPT_SSL) { - /* use double layer ssl */ - if(!Curl_ssl_config_matches(&needle->proxy_ssl_config, - &check->proxy_ssl_config)) - continue; - if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete) - continue; - } - else { - if(!Curl_ssl_config_matches(&needle->ssl_config, - &check->ssl_config)) - continue; - if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) - continue; - } - } - } - - if(!canpipe && check->inuse) - /* this request can't be pipelined but the checked connection is - already in use so we skip it */ - continue; - - if(needle->localdev || needle->localport) { - /* If we are bound to a specific local end (IP+port), we must not - re-use a random other one, although if we didn't ask for a - particular one we can reuse one that was bound. - - This comparison is a bit rough and too strict. Since the input - parameters can be specified in numerous ways and still end up the - same it would take a lot of processing to make it really accurate. - Instead, this matching will assume that re-uses of bound connections - will most likely also re-use the exact same binding parameters and - missing out a few edge cases shouldn't hurt anyone very much. - */ - if((check->localport != needle->localport) || - (check->localportrange != needle->localportrange) || - (needle->localdev && - (!check->localdev || strcmp(check->localdev, needle->localdev)))) - continue; - } - - if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { - /* This protocol requires credentials per connection, - so verify that we're using the same name and password as well */ - if(strcmp(needle->user, check->user) || - strcmp(needle->passwd, check->passwd)) { - /* one of them was different */ - continue; - } - } - - if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || - needle->bits.tunnel_proxy) { - /* The requested connection does not use a HTTP proxy or it uses SSL or - it is a non-SSL protocol tunneled or it is a non-SSL protocol which - is allowed to be upgraded via TLS */ - - if((strcasecompare(needle->handler->scheme, check->handler->scheme) || - (get_protocol_family(check->handler->protocol) == - needle->handler->protocol && check->tls_upgraded)) && - (!needle->bits.conn_to_host || strcasecompare( - needle->conn_to_host.name, check->conn_to_host.name)) && - (!needle->bits.conn_to_port || - needle->conn_to_port == check->conn_to_port) && - strcasecompare(needle->host.name, check->host.name) && - needle->remote_port == check->remote_port) { - /* The schemes match or the the protocol family is the same and the - previous connection was TLS upgraded, and the hostname and host - port match */ - if(needle->handler->flags & PROTOPT_SSL) { - /* This is a SSL connection so verify that we're using the same - SSL options as well */ - if(!Curl_ssl_config_matches(&needle->ssl_config, - &check->ssl_config)) { - DEBUGF(infof(data, - "Connection #%ld has different SSL parameters, " - "can't reuse\n", - check->connection_id)); - continue; - } - if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { - foundPendingCandidate = TRUE; - DEBUGF(infof(data, - "Connection #%ld has not started SSL connect, " - "can't reuse\n", - check->connection_id)); - continue; - } - } - match = TRUE; - } - } - else { - /* The requested connection is using the same HTTP proxy in normal - mode (no tunneling) */ - match = TRUE; - } - - if(match) { -#if defined(USE_NTLM) - /* If we are looking for an HTTP+NTLM connection, check if this is - already authenticating with the right credentials. If not, keep - looking so that we can reuse NTLM connections if - possible. (Especially we must not reuse the same connection if - partway through a handshake!) */ - if(wantNTLMhttp) { - if(strcmp(needle->user, check->user) || - strcmp(needle->passwd, check->passwd)) - continue; - } - else if(check->ntlm.state != NTLMSTATE_NONE) { - /* Connection is using NTLM auth but we don't want NTLM */ - continue; - } - - /* Same for Proxy NTLM authentication */ - if(wantProxyNTLMhttp) { - /* Both check->http_proxy.user and check->http_proxy.passwd can be - * NULL */ - if(!check->http_proxy.user || !check->http_proxy.passwd) - continue; - - if(strcmp(needle->http_proxy.user, check->http_proxy.user) || - strcmp(needle->http_proxy.passwd, check->http_proxy.passwd)) - continue; - } - else if(check->proxyntlm.state != NTLMSTATE_NONE) { - /* Proxy connection is using NTLM auth but we don't want NTLM */ - continue; - } - - if(wantNTLMhttp || wantProxyNTLMhttp) { - /* Credentials are already checked, we can use this connection */ - chosen = check; - - if((wantNTLMhttp && - (check->ntlm.state != NTLMSTATE_NONE)) || - (wantProxyNTLMhttp && - (check->proxyntlm.state != NTLMSTATE_NONE))) { - /* We must use this connection, no other */ - *force_reuse = TRUE; - break; - } - - /* Continue look up for a better connection */ - continue; - } -#endif - if(canpipe) { - /* We can pipeline if we want to. Let's continue looking for - the optimal connection to use, i.e the shortest pipe that is not - blacklisted. */ - - if(pipeLen == 0) { - /* We have the optimal connection. Let's stop looking. */ - chosen = check; - break; - } - - /* We can't use the connection if the pipe is full */ - if(max_pipe_len && (pipeLen >= max_pipe_len)) { - infof(data, "Pipe is full, skip (%zu)\n", pipeLen); - continue; - } -#ifdef USE_NGHTTP2 - /* If multiplexed, make sure we don't go over concurrency limit */ - if(check->bits.multiplex) { - /* Multiplexed connections can only be HTTP/2 for now */ - struct http_conn *httpc = &check->proto.httpc; - if(pipeLen >= httpc->settings.max_concurrent_streams) { - infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n", - pipeLen); - continue; - } - } -#endif - /* We can't use the connection if the pipe is penalized */ - if(Curl_pipeline_penalized(data, check)) { - infof(data, "Penalized, skip\n"); - continue; - } - - if(max_pipe_len) { - if(pipeLen < best_pipe_len) { - /* This connection has a shorter pipe so far. We'll pick this - and continue searching */ - chosen = check; - best_pipe_len = pipeLen; - continue; - } - } - else { - /* When not pipelining (== multiplexed), we have a match here! */ - chosen = check; - infof(data, "Multiplexed connection found!\n"); - break; - } - } - else { - /* We have found a connection. Let's stop searching. */ - chosen = check; - break; - } - } - } - } - - if(chosen) { - *usethis = chosen; - return TRUE; /* yes, we found one to use! */ - } - - if(foundPendingCandidate && data->set.pipewait) { - infof(data, - "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n"); - *waitpipe = TRUE; - } - - return FALSE; /* no matching connecting exists */ -} - -/* after a TCP connection to the proxy has been verified, this function does - the next magic step. - - Note: this function's sub-functions call failf() - -*/ -CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex) -{ - CURLcode result = CURLE_OK; - - if(conn->bits.socksproxy) { -#ifndef CURL_DISABLE_PROXY - /* for the secondary socket (FTP), use the "connect to host" - * but ignore the "connect to port" (use the secondary port) - */ - const char * const host = conn->bits.httpproxy ? - conn->http_proxy.host.name : - conn->bits.conn_to_host ? - conn->conn_to_host.name : - sockindex == SECONDARYSOCKET ? - conn->secondaryhostname : conn->host.name; - const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port : - sockindex == SECONDARYSOCKET ? conn->secondary_port : - conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port; - conn->bits.socksproxy_connecting = TRUE; - switch(conn->socks_proxy.proxytype) { - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: - result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd, - host, port, sockindex, conn); - break; - - case CURLPROXY_SOCKS4: - case CURLPROXY_SOCKS4A: - result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex, - conn); - break; - - default: - failf(conn->data, "unknown proxytype option given"); - result = CURLE_COULDNT_CONNECT; - } /* switch proxytype */ - conn->bits.socksproxy_connecting = FALSE; -#else - (void)sockindex; -#endif /* CURL_DISABLE_PROXY */ - } - - return result; -} - -/* - * verboseconnect() displays verbose information after a connect - */ -#ifndef CURL_DISABLE_VERBOSE_STRINGS -void Curl_verboseconnect(struct connectdata *conn) -{ - if(conn->data->set.verbose) - infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", - conn->bits.socksproxy ? conn->socks_proxy.host.dispname : - conn->bits.httpproxy ? conn->http_proxy.host.dispname : - conn->bits.conn_to_host ? conn->conn_to_host.dispname : - conn->host.dispname, - conn->ip_addr_str, conn->port, conn->connection_id); -} -#endif - -int Curl_protocol_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - if(conn->handler->proto_getsock) - return conn->handler->proto_getsock(conn, socks, numsocks); - return GETSOCK_BLANK; -} - -int Curl_doing_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - if(conn && conn->handler->doing_getsock) - return conn->handler->doing_getsock(conn, socks, numsocks); - return GETSOCK_BLANK; -} - -/* - * We are doing protocol-specific connecting and this is being called over and - * over from the multi interface until the connection phase is done on - * protocol layer. - */ - -CURLcode Curl_protocol_connecting(struct connectdata *conn, - bool *done) -{ - CURLcode result = CURLE_OK; - - if(conn && conn->handler->connecting) { - *done = FALSE; - result = conn->handler->connecting(conn, done); - } - else - *done = TRUE; - - return result; -} - -/* - * We are DOING this is being called over and over from the multi interface - * until the DOING phase is done on protocol layer. - */ - -CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done) -{ - CURLcode result = CURLE_OK; - - if(conn && conn->handler->doing) { - *done = FALSE; - result = conn->handler->doing(conn, done); - } - else - *done = TRUE; - - return result; -} - -/* - * We have discovered that the TCP connection has been successful, we can now - * proceed with some action. - * - */ -CURLcode Curl_protocol_connect(struct connectdata *conn, - bool *protocol_done) -{ - CURLcode result = CURLE_OK; - - *protocol_done = FALSE; - - if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) { - /* We already are connected, get back. This may happen when the connect - worked fine in the first call, like when we connect to a local server - or proxy. Note that we don't know if the protocol is actually done. - - Unless this protocol doesn't have any protocol-connect callback, as - then we know we're done. */ - if(!conn->handler->connecting) - *protocol_done = TRUE; - - return CURLE_OK; - } - - if(!conn->bits.protoconnstart) { - - result = Curl_proxy_connect(conn, FIRSTSOCKET); - if(result) - return result; - - if(CONNECT_FIRSTSOCKET_PROXY_SSL()) - /* wait for HTTPS proxy SSL initialization to complete */ - return CURLE_OK; - - if(conn->bits.tunnel_proxy && conn->bits.httpproxy && - Curl_connect_ongoing(conn)) - /* when using an HTTP tunnel proxy, await complete tunnel establishment - before proceeding further. Return CURLE_OK so we'll be called again */ - return CURLE_OK; - - if(conn->handler->connect_it) { - /* is there a protocol-specific connect() procedure? */ - - /* Call the protocol-specific connect function */ - result = conn->handler->connect_it(conn, protocol_done); - } - else - *protocol_done = TRUE; - - /* it has started, possibly even completed but that knowledge isn't stored - in this bit! */ - if(!result) - conn->bits.protoconnstart = TRUE; - } - - return result; /* pass back status */ -} - -/* - * Helpers for IDNA conversions. - */ -static bool is_ASCII_name(const char *hostname) -{ - const unsigned char *ch = (const unsigned char *)hostname; - - while(*ch) { - if(*ch++ & 0x80) - return FALSE; - } - return TRUE; -} - -/* - * Perform any necessary IDN conversion of hostname - */ -static void fix_hostname(struct connectdata *conn, struct hostname *host) -{ - size_t len; - struct Curl_easy *data = conn->data; - -#ifndef USE_LIBIDN2 - (void)data; - (void)conn; -#elif defined(CURL_DISABLE_VERBOSE_STRINGS) - (void)conn; -#endif - - /* set the name we use to display the host name */ - host->dispname = host->name; - - len = strlen(host->name); - if(len && (host->name[len-1] == '.')) - /* strip off a single trailing dot if present, primarily for SNI but - there's no use for it */ - host->name[len-1] = 0; - - /* Check name for non-ASCII and convert hostname to ACE form if we can */ - if(!is_ASCII_name(host->name)) { -#ifdef USE_LIBIDN2 - if(idn2_check_version(IDN2_VERSION)) { - char *ace_hostname = NULL; -#if IDN2_VERSION_NUMBER >= 0x00140000 - /* IDN2_NFC_INPUT: Normalize input string using normalization form C. - IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional - processing. */ - int flags = IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL; -#else - int flags = IDN2_NFC_INPUT; -#endif - int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, flags); - if(rc == IDN2_OK) { - host->encalloc = (char *)ace_hostname; - /* change the name pointer to point to the encoded hostname */ - host->name = host->encalloc; - } - else - infof(data, "Failed to convert %s to ACE; %s\n", host->name, - idn2_strerror(rc)); - } -#elif defined(USE_WIN32_IDN) - char *ace_hostname = NULL; - - if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) { - host->encalloc = ace_hostname; - /* change the name pointer to point to the encoded hostname */ - host->name = host->encalloc; - } - else - infof(data, "Failed to convert %s to ACE;\n", host->name); -#else - infof(data, "IDN support not present, can't parse Unicode domains\n"); -#endif - } -} - -/* - * Frees data allocated by fix_hostname() - */ -static void free_fixed_hostname(struct hostname *host) -{ -#if defined(USE_LIBIDN2) - if(host->encalloc) { - idn2_free(host->encalloc); /* must be freed with idn2_free() since this was - allocated by libidn */ - host->encalloc = NULL; - } -#elif defined(USE_WIN32_IDN) - free(host->encalloc); /* must be freed with free() since this was - allocated by curl_win32_idn_to_ascii */ - host->encalloc = NULL; -#else - (void)host; -#endif -} - -static void llist_dtor(void *user, void *element) -{ - (void)user; - (void)element; - /* Do nothing */ -} - -/* - * Allocate and initialize a new connectdata object. - */ -static struct connectdata *allocate_conn(struct Curl_easy *data) -{ -#ifdef USE_SSL -#define SSL_EXTRA + 4 * Curl_ssl->sizeof_ssl_backend_data - sizeof(long long) -#else -#define SSL_EXTRA 0 -#endif - struct connectdata *conn = calloc(1, sizeof(struct connectdata) + SSL_EXTRA); - if(!conn) - return NULL; - - conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined - already from start to avoid NULL - situations and checks */ - - /* and we setup a few fields in case we end up actually using this struct */ - - conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->tempsock[0] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->tempsock[1] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->connection_id = -1; /* no ID */ - conn->port = -1; /* unknown at this point */ - conn->remote_port = -1; /* unknown at this point */ -#if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD) - conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ - conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ -#endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */ - - /* Default protocol-independent behavior doesn't support persistent - connections, so we set this to force-close. Protocols that support - this need to set this to FALSE in their "curl_do" functions. */ - connclose(conn, "Default to force-close"); - - /* Store creation time to help future close decision making */ - conn->created = Curl_tvnow(); - - conn->data = data; /* Setup the association between this connection - and the Curl_easy */ - - conn->http_proxy.proxytype = data->set.proxytype; - conn->socks_proxy.proxytype = CURLPROXY_SOCKS4; - -#ifdef CURL_DISABLE_PROXY - - conn->bits.proxy = FALSE; - conn->bits.httpproxy = FALSE; - conn->bits.socksproxy = FALSE; - conn->bits.proxy_user_passwd = FALSE; - conn->bits.tunnel_proxy = FALSE; - -#else /* CURL_DISABLE_PROXY */ - - /* note that these two proxy bits are now just on what looks to be - requested, they may be altered down the road */ - conn->bits.proxy = (data->set.str[STRING_PROXY] && - *data->set.str[STRING_PROXY]) ? TRUE : FALSE; - conn->bits.httpproxy = (conn->bits.proxy && - (conn->http_proxy.proxytype == CURLPROXY_HTTP || - conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 || - conn->http_proxy.proxytype == CURLPROXY_HTTPS)) ? - TRUE : FALSE; - conn->bits.socksproxy = (conn->bits.proxy && - !conn->bits.httpproxy) ? TRUE : FALSE; - - if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) { - conn->bits.proxy = TRUE; - conn->bits.socksproxy = TRUE; - } - - conn->bits.proxy_user_passwd = - (data->set.str[STRING_PROXYUSERNAME]) ? TRUE : FALSE; - conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; - -#endif /* CURL_DISABLE_PROXY */ - - conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE; - conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; - conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; - - conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; - conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; - conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; - conn->proxy_ssl_config.verifystatus = - data->set.proxy_ssl.primary.verifystatus; - conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; - conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; - - conn->ip_version = data->set.ipver; - -#ifdef USE_SSL - /* - * To save on malloc()s, the SSL backend-specific data has been allocated - * at the end of the connectdata struct. - */ - { - char *p = (char *)&conn->align_data__do_not_use; - conn->ssl[0].backend = (struct ssl_backend_data *)p; - conn->ssl[1].backend = - (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data); - conn->proxy_ssl[0].backend = - (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data * 2); - conn->proxy_ssl[1].backend = - (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data * 3); - } -#endif - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ - defined(NTLM_WB_ENABLED) - conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; - conn->ntlm_auth_hlpr_pid = 0; - conn->challenge_header = NULL; - conn->response_header = NULL; -#endif - - if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) && - !conn->master_buffer) { - /* Allocate master_buffer to be used for HTTP/1 pipelining */ - conn->master_buffer = calloc(MASTERBUF_SIZE, sizeof(char)); - if(!conn->master_buffer) - goto error; - } - - /* Initialize the pipeline lists */ - Curl_llist_init(&conn->send_pipe, (curl_llist_dtor) llist_dtor); - Curl_llist_init(&conn->recv_pipe, (curl_llist_dtor) llist_dtor); - -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CLEAR; -#endif - - /* Store the local bind parameters that will be used for this connection */ - if(data->set.str[STRING_DEVICE]) { - conn->localdev = strdup(data->set.str[STRING_DEVICE]); - if(!conn->localdev) - goto error; - } - conn->localportrange = data->set.localportrange; - conn->localport = data->set.localport; - - /* the close socket stuff needs to be copied to the connection struct as - it may live on without (this specific) Curl_easy */ - conn->fclosesocket = data->set.fclosesocket; - conn->closesocket_client = data->set.closesocket_client; - - return conn; - error: - - Curl_llist_destroy(&conn->send_pipe, NULL); - Curl_llist_destroy(&conn->recv_pipe, NULL); - - free(conn->master_buffer); - free(conn->localdev); - free(conn); - return NULL; -} - -static CURLcode findprotocol(struct Curl_easy *data, - struct connectdata *conn, - const char *protostr) -{ - const struct Curl_handler * const *pp; - const struct Curl_handler *p; - - /* Scan protocol handler table and match against 'protostr' to set a few - variables based on the URL. Now that the handler may be changed later - when the protocol specific setup function is called. */ - for(pp = protocols; (p = *pp) != NULL; pp++) { - if(strcasecompare(p->scheme, protostr)) { - /* Protocol found in table. Check if allowed */ - if(!(data->set.allowed_protocols & p->protocol)) - /* nope, get out */ - break; - - /* it is allowed for "normal" request, now do an extra check if this is - the result of a redirect */ - if(data->state.this_is_a_follow && - !(data->set.redir_protocols & p->protocol)) - /* nope, get out */ - break; - - /* Perform setup complement if some. */ - conn->handler = conn->given = p; - - /* 'port' and 'remote_port' are set in setup_connection_internals() */ - return CURLE_OK; - } - } - - - /* The protocol was not found in the table, but we don't have to assign it - to anything since it is already assigned to a dummy-struct in the - create_conn() function when the connectdata struct is allocated. */ - failf(data, "Protocol \"%s\" not supported or disabled in " LIBCURL_NAME, - protostr); - - return CURLE_UNSUPPORTED_PROTOCOL; -} - -/* - * Parse URL and fill in the relevant members of the connection struct. - */ -static CURLcode parseurlandfillconn(struct Curl_easy *data, - struct connectdata *conn, - bool *prot_missing, - char **userp, char **passwdp, - char **optionsp) -{ - char *at; - char *fragment; - char *path = data->state.path; - char *query; - int i; - int rc; - const char *protop = ""; - CURLcode result; - bool rebuild_url = FALSE; - bool url_has_scheme = FALSE; - char protobuf[16]; - - *prot_missing = FALSE; - - /* We might pass the entire URL into the request so we need to make sure - * there are no bad characters in there.*/ - if(strpbrk(data->change.url, "\r\n")) { - failf(data, "Illegal characters found in URL"); - return CURLE_URL_MALFORMAT; - } - - /************************************************************* - * Parse the URL. - * - * We need to parse the url even when using the proxy, because we will need - * the hostname and port in case we are trying to SSL connect through the - * proxy -- and we don't know if we will need to use SSL until we parse the - * url ... - ************************************************************/ - if(data->change.url[0] == ':') { - failf(data, "Bad URL, colon is first character"); - return CURLE_URL_MALFORMAT; - } - - /* MSDOS/Windows style drive prefix, eg c: in c:foo */ -#define STARTS_WITH_DRIVE_PREFIX(str) \ - ((('a' <= str[0] && str[0] <= 'z') || \ - ('A' <= str[0] && str[0] <= 'Z')) && \ - (str[1] == ':')) - - /* Don't mistake a drive letter for a scheme if the default protocol is file. - curld --proto-default file c:/foo/bar.txt */ - if(STARTS_WITH_DRIVE_PREFIX(data->change.url) && - data->set.str[STRING_DEFAULT_PROTOCOL] && - strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file")) { - ; /* do nothing */ - } - else { /* check for a scheme */ - for(i = 0; i < 16 && data->change.url[i]; ++i) { - if(data->change.url[i] == '/') - break; - if(data->change.url[i] == ':') { - url_has_scheme = TRUE; - break; - } - } - } - - /* handle the file: scheme */ - if((url_has_scheme && strncasecompare(data->change.url, "file:", 5)) || - (!url_has_scheme && data->set.str[STRING_DEFAULT_PROTOCOL] && - strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file"))) { - if(url_has_scheme) - rc = sscanf(data->change.url, "%*15[^\n/:]:%[^\n]", path); - else - rc = sscanf(data->change.url, "%[^\n]", path); - - if(rc != 1) { - failf(data, "Bad URL"); - return CURLE_URL_MALFORMAT; - } - - if(url_has_scheme && path[0] == '/' && path[1] == '/') { - /* Allow omitted hostname (e.g. file:/). This is not strictly - * speaking a valid file: URL by RFC 1738, but treating file:/ as - * file://localhost/ is similar to how other schemes treat missing - * hostnames. See RFC 1808. */ - - /* This cannot be done with strcpy() in a portable manner, since the - memory areas overlap! */ - memmove(path, path + 2, strlen(path + 2) + 1); - } - - /* - * we deal with file:/// differently since it supports no - * hostname other than "localhost" and "127.0.0.1", which is unique among - * the URL protocols specified in RFC 1738 - */ - if(path[0] != '/' && !STARTS_WITH_DRIVE_PREFIX(path)) { - /* the URL includes a host name, it must match "localhost" or - "127.0.0.1" to be valid */ - char *ptr; - if(!checkprefix("localhost/", path) && - !checkprefix("127.0.0.1/", path)) { - failf(data, "Invalid file://hostname/, " - "expected localhost or 127.0.0.1 or none"); - return CURLE_URL_MALFORMAT; - } - ptr = &path[9]; /* now points to the slash after the host */ - - /* there was a host name and slash present - - RFC1738 (section 3.1, page 5) says: - - The rest of the locator consists of data specific to the scheme, - and is known as the "url-path". It supplies the details of how the - specified resource can be accessed. Note that the "/" between the - host (or port) and the url-path is NOT part of the url-path. - - As most agents use file://localhost/foo to get '/foo' although the - slash preceding foo is a separator and not a slash for the path, - a URL as file://localhost//foo must be valid as well, to refer to - the same file with an absolute path. - */ - - if('/' == ptr[1]) - /* if there was two slashes, we skip the first one as that is then - used truly as a separator */ - ptr++; - - /* This cannot be made with strcpy, as the memory chunks overlap! */ - memmove(path, ptr, strlen(ptr) + 1); - } - -#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) - if(STARTS_WITH_DRIVE_PREFIX(path)) { - failf(data, "File drive letters are only accepted in MSDOS/Windows."); - return CURLE_URL_MALFORMAT; - } -#endif - - protop = "file"; /* protocol string */ - *prot_missing = !url_has_scheme; - } - else { - /* clear path */ - char slashbuf[4]; - path[0] = 0; - - rc = sscanf(data->change.url, - "%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]", - protobuf, slashbuf, conn->host.name, path); - if(2 == rc) { - failf(data, "Bad URL"); - return CURLE_URL_MALFORMAT; - } - if(3 > rc) { - - /* - * The URL was badly formatted, let's try the browser-style _without_ - * protocol specified like 'http://'. - */ - rc = sscanf(data->change.url, "%[^\n/?#]%[^\n]", conn->host.name, path); - if(1 > rc) { - /* - * We couldn't even get this format. - * djgpp 2.04 has a sscanf() bug where 'conn->host.name' is - * assigned, but the return value is EOF! - */ -#if defined(__DJGPP__) && (DJGPP_MINOR == 4) - if(!(rc == -1 && *conn->host.name)) -#endif - { - failf(data, " malformed"); - return CURLE_URL_MALFORMAT; - } - } - - /* - * Since there was no protocol part specified in the URL use the - * user-specified default protocol. If we weren't given a default make a - * guess by matching some protocols against the host's outermost - * sub-domain name. Finally if there was no match use HTTP. - */ - - protop = data->set.str[STRING_DEFAULT_PROTOCOL]; - if(!protop) { - /* Note: if you add a new protocol, please update the list in - * lib/version.c too! */ - if(checkprefix("FTP.", conn->host.name)) - protop = "ftp"; - else if(checkprefix("DICT.", conn->host.name)) - protop = "DICT"; - else if(checkprefix("LDAP.", conn->host.name)) - protop = "LDAP"; - else if(checkprefix("IMAP.", conn->host.name)) - protop = "IMAP"; - else if(checkprefix("SMTP.", conn->host.name)) - protop = "smtp"; - else if(checkprefix("POP3.", conn->host.name)) - protop = "pop3"; - else - protop = "http"; - } - - *prot_missing = TRUE; /* not given in URL */ - } - else { - size_t s = strlen(slashbuf); - protop = protobuf; - if(s != 2) { - infof(data, "Unwillingly accepted illegal URL using %d slash%s!\n", - s, s>1?"es":""); - - if(data->change.url_alloc) - free(data->change.url); - /* repair the URL to use two slashes */ - data->change.url = aprintf("%s://%s%s", - protobuf, conn->host.name, path); - if(!data->change.url) - return CURLE_OUT_OF_MEMORY; - data->change.url_alloc = TRUE; - } - } - } - - /* We search for '?' in the host name (but only on the right side of a - * @-letter to allow ?-letters in username and password) to handle things - * like http://example.com?param= (notice the missing '/'). - */ - at = strchr(conn->host.name, '@'); - if(at) - query = strchr(at + 1, '?'); - else - query = strchr(conn->host.name, '?'); - - if(query) { - /* We must insert a slash before the '?'-letter in the URL. If the URL had - a slash after the '?', that is where the path currently begins and the - '?string' is still part of the host name. - - We must move the trailing part from the host name and put it first in - the path. And have it all prefixed with a slash. - */ - - size_t hostlen = strlen(query); - size_t pathlen = strlen(path); - - /* move the existing path plus the zero byte forward, to make room for - the host-name part */ - memmove(path + hostlen + 1, path, pathlen + 1); - - /* now copy the trailing host part in front of the existing path */ - memcpy(path + 1, query, hostlen); - - path[0]='/'; /* prepend the missing slash */ - rebuild_url = TRUE; - - *query = 0; /* now cut off the hostname at the ? */ - } - else if(!path[0]) { - /* if there's no path set, use a single slash */ - strcpy(path, "/"); - rebuild_url = TRUE; - } - - /* If the URL is malformatted (missing a '/' after hostname before path) we - * insert a slash here. The only letters except '/' that can start a path is - * '?' and '#' - as controlled by the two sscanf() patterns above. - */ - if(path[0] != '/') { - /* We need this function to deal with overlapping memory areas. We know - that the memory area 'path' points to is 'urllen' bytes big and that - is bigger than the path. Use +1 to move the zero byte too. */ - memmove(&path[1], path, strlen(path) + 1); - path[0] = '/'; - rebuild_url = TRUE; - } - else if(!data->set.path_as_is) { - /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */ - char *newp = Curl_dedotdotify(path); - if(!newp) - return CURLE_OUT_OF_MEMORY; - - if(strcmp(newp, path)) { - rebuild_url = TRUE; - free(data->state.pathbuffer); - data->state.pathbuffer = newp; - data->state.path = newp; - path = newp; - } - else - free(newp); - } - - /* - * "rebuild_url" means that one or more URL components have been modified so - * we need to generate an updated full version. We need the corrected URL - * when communicating over HTTP proxy and we don't know at this point if - * we're using a proxy or not. - */ - if(rebuild_url) { - char *reurl; - - size_t plen = strlen(path); /* new path, should be 1 byte longer than - the original */ - size_t prefixlen = strlen(conn->host.name); - - if(!*prot_missing) { - size_t protolen = strlen(protop); - - if(curl_strnequal(protop, data->change.url, protolen)) - prefixlen += protolen; - else { - failf(data, " malformed"); - return CURLE_URL_MALFORMAT; - } - - if(curl_strnequal("://", &data->change.url[protolen], 3)) - prefixlen += 3; - /* only file: is allowed to omit one or both slashes */ - else if(curl_strnequal("file:", data->change.url, 5)) - prefixlen += 1 + (data->change.url[5] == '/'); - else { - failf(data, " malformed"); - return CURLE_URL_MALFORMAT; - } - } - - reurl = malloc(prefixlen + plen + 1); - if(!reurl) - return CURLE_OUT_OF_MEMORY; - - /* copy the prefix */ - memcpy(reurl, data->change.url, prefixlen); - - /* append the trailing piece + zerobyte */ - memcpy(&reurl[prefixlen], path, plen + 1); - - /* possible free the old one */ - if(data->change.url_alloc) { - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - - infof(data, "Rebuilt URL to: %s\n", reurl); - - data->change.url = reurl; - data->change.url_alloc = TRUE; /* free this later */ - } - - result = findprotocol(data, conn, protop); - if(result) - return result; - - /* - * Parse the login details from the URL and strip them out of - * the host name - */ - result = parse_url_login(data, conn, userp, passwdp, optionsp); - if(result) - return result; - - if(conn->host.name[0] == '[') { - /* This looks like an IPv6 address literal. See if there is an address - scope if there is no location header */ - char *percent = strchr(conn->host.name, '%'); - if(percent) { - unsigned int identifier_offset = 3; - char *endp; - unsigned long scope; - if(strncmp("%25", percent, 3) != 0) { - infof(data, - "Please URL encode %% as %%25, see RFC 6874.\n"); - identifier_offset = 1; - } - scope = strtoul(percent + identifier_offset, &endp, 10); - if(*endp == ']') { - /* The address scope was well formed. Knock it out of the - hostname. */ - memmove(percent, endp, strlen(endp) + 1); - conn->scope_id = (unsigned int)scope; - } - else { - /* Zone identifier is not numeric */ -#if defined(HAVE_NET_IF_H) && defined(IFNAMSIZ) && defined(HAVE_IF_NAMETOINDEX) - char ifname[IFNAMSIZ + 2]; - char *square_bracket; - unsigned int scopeidx = 0; - strncpy(ifname, percent + identifier_offset, IFNAMSIZ + 2); - /* Ensure nullbyte termination */ - ifname[IFNAMSIZ + 1] = '\0'; - square_bracket = strchr(ifname, ']'); - if(square_bracket) { - /* Remove ']' */ - *square_bracket = '\0'; - scopeidx = if_nametoindex(ifname); - if(scopeidx == 0) { - infof(data, "Invalid network interface: %s; %s\n", ifname, - strerror(errno)); - } - } - if(scopeidx > 0) { - char *p = percent + identifier_offset + strlen(ifname); - - /* Remove zone identifier from hostname */ - memmove(percent, p, strlen(p) + 1); - conn->scope_id = scopeidx; - } - else -#endif /* HAVE_NET_IF_H && IFNAMSIZ */ - infof(data, "Invalid IPv6 address format\n"); - } - } - } - - if(data->set.scope_id) - /* Override any scope that was set above. */ - conn->scope_id = data->set.scope_id; - - /* Remove the fragment part of the path. Per RFC 2396, this is always the - last part of the URI. We are looking for the first '#' so that we deal - gracefully with non conformant URI such as http://example.com#foo#bar. */ - fragment = strchr(path, '#'); - if(fragment) { - *fragment = 0; - - /* we know the path part ended with a fragment, so we know the full URL - string does too and we need to cut it off from there so it isn't used - over proxy */ - fragment = strchr(data->change.url, '#'); - if(fragment) - *fragment = 0; - } - - /* - * So if the URL was A://B/C#D, - * protop is A - * conn->host.name is B - * data->state.path is /C - */ - return CURLE_OK; -} - -/* - * If we're doing a resumed transfer, we need to setup our stuff - * properly. - */ -static CURLcode setup_range(struct Curl_easy *data) -{ - struct UrlState *s = &data->state; - s->resume_from = data->set.set_resume_from; - if(s->resume_from || data->set.str[STRING_SET_RANGE]) { - if(s->rangestringalloc) - free(s->range); - - if(s->resume_from) - s->range = aprintf("%" CURL_FORMAT_CURL_OFF_TU "-", s->resume_from); - else - s->range = strdup(data->set.str[STRING_SET_RANGE]); - - s->rangestringalloc = (s->range) ? TRUE : FALSE; - - if(!s->range) - return CURLE_OUT_OF_MEMORY; - - /* tell ourselves to fetch this range */ - s->use_range = TRUE; /* enable range download */ - } - else - s->use_range = FALSE; /* disable range download */ - - return CURLE_OK; -} - - -/* - * setup_connection_internals() - - * - * Setup connection internals specific to the requested protocol in the - * Curl_easy. This is inited and setup before the connection is made but - * is about the particular protocol that is to be used. - * - * This MUST get called after proxy magic has been figured out. - */ -static CURLcode setup_connection_internals(struct connectdata *conn) -{ - const struct Curl_handler * p; - CURLcode result; - struct Curl_easy *data = conn->data; - - /* in some case in the multi state-machine, we go back to the CONNECT state - and then a second (or third or...) call to this function will be made - without doing a DISCONNECT or DONE in between (since the connection is - yet in place) and therefore this function needs to first make sure - there's no lingering previous data allocated. */ - Curl_free_request_state(data); - - memset(&data->req, 0, sizeof(struct SingleRequest)); - data->req.maxdownload = -1; - - conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ - - /* Perform setup complement if some. */ - p = conn->handler; - - if(p->setup_connection) { - result = (*p->setup_connection)(conn); - - if(result) - return result; - - p = conn->handler; /* May have changed. */ - } - - if(conn->port < 0) - /* we check for -1 here since if proxy was detected already, this - was very likely already set to the proxy port */ - conn->port = p->defport; - - return CURLE_OK; -} - -/* - * Curl_free_request_state() should free temp data that was allocated in the - * Curl_easy for this single request. - */ - -void Curl_free_request_state(struct Curl_easy *data) -{ - Curl_safefree(data->req.protop); - Curl_safefree(data->req.newurl); -} - - -#ifndef CURL_DISABLE_PROXY -/**************************************************************** -* Checks if the host is in the noproxy list. returns true if it matches -* and therefore the proxy should NOT be used. -****************************************************************/ -static bool check_noproxy(const char *name, const char *no_proxy) -{ - /* no_proxy=domain1.dom,host.domain2.dom - * (a comma-separated list of hosts which should - * not be proxied, or an asterisk to override - * all proxy variables) - */ - size_t tok_start; - size_t tok_end; - const char *separator = ", "; - size_t no_proxy_len; - size_t namelen; - char *endptr; - - if(no_proxy && no_proxy[0]) { - if(strcasecompare("*", no_proxy)) { - return TRUE; - } - - /* NO_PROXY was specified and it wasn't just an asterisk */ - - no_proxy_len = strlen(no_proxy); - endptr = strchr(name, ':'); - if(endptr) - namelen = endptr - name; - else - namelen = strlen(name); - - for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) { - while(tok_start < no_proxy_len && - strchr(separator, no_proxy[tok_start]) != NULL) { - /* Look for the beginning of the token. */ - ++tok_start; - } - - if(tok_start == no_proxy_len) - break; /* It was all trailing separator chars, no more tokens. */ - - for(tok_end = tok_start; tok_end < no_proxy_len && - strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) - /* Look for the end of the token. */ - ; - - /* To match previous behaviour, where it was necessary to specify - * ".local.com" to prevent matching "notlocal.com", we will leave - * the '.' off. - */ - if(no_proxy[tok_start] == '.') - ++tok_start; - - if((tok_end - tok_start) <= namelen) { - /* Match the last part of the name to the domain we are checking. */ - const char *checkn = name + namelen - (tok_end - tok_start); - if(strncasecompare(no_proxy + tok_start, checkn, - tok_end - tok_start)) { - if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') { - /* We either have an exact match, or the previous character is a . - * so it is within the same domain, so no proxy for this host. - */ - return TRUE; - } - } - } /* if((tok_end - tok_start) <= namelen) */ - } /* for(tok_start = 0; tok_start < no_proxy_len; - tok_start = tok_end + 1) */ - } /* NO_PROXY was specified and it wasn't just an asterisk */ - - return FALSE; -} - -#ifndef CURL_DISABLE_HTTP -/**************************************************************** -* Detect what (if any) proxy to use. Remember that this selects a host -* name and is not limited to HTTP proxies only. -* The returned pointer must be freed by the caller (unless NULL) -****************************************************************/ -static char *detect_proxy(struct connectdata *conn) -{ - char *proxy = NULL; - - /* If proxy was not specified, we check for default proxy environment - * variables, to enable i.e Lynx compliance: - * - * http_proxy=http://some.server.dom:port/ - * https_proxy=http://some.server.dom:port/ - * ftp_proxy=http://some.server.dom:port/ - * no_proxy=domain1.dom,host.domain2.dom - * (a comma-separated list of hosts which should - * not be proxied, or an asterisk to override - * all proxy variables) - * all_proxy=http://some.server.dom:port/ - * (seems to exist for the CERN www lib. Probably - * the first to check for.) - * - * For compatibility, the all-uppercase versions of these variables are - * checked if the lowercase versions don't exist. - */ - char proxy_env[128]; - const char *protop = conn->handler->scheme; - char *envp = proxy_env; - char *prox; - - /* Now, build _proxy and check for such a one to use */ - while(*protop) - *envp++ = (char)tolower((int)*protop++); - - /* append _proxy */ - strcpy(envp, "_proxy"); - - /* read the protocol proxy: */ - prox = curl_getenv(proxy_env); - - /* - * We don't try the uppercase version of HTTP_PROXY because of - * security reasons: - * - * When curl is used in a webserver application - * environment (cgi or php), this environment variable can - * be controlled by the web server user by setting the - * http header 'Proxy:' to some value. - * - * This can cause 'internal' http/ftp requests to be - * arbitrarily redirected by any external attacker. - */ - if(!prox && !strcasecompare("http_proxy", proxy_env)) { - /* There was no lowercase variable, try the uppercase version: */ - Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); - prox = curl_getenv(proxy_env); - } - - if(prox) - proxy = prox; /* use this */ - else { - proxy = curl_getenv("all_proxy"); /* default proxy to use */ - if(!proxy) - proxy = curl_getenv("ALL_PROXY"); - } - - return proxy; -} -#endif /* CURL_DISABLE_HTTP */ - -/* - * If this is supposed to use a proxy, we need to figure out the proxy - * host name, so that we can re-use an existing connection - * that may exist registered to the same proxy host. - */ -static CURLcode parse_proxy(struct Curl_easy *data, - struct connectdata *conn, char *proxy, - curl_proxytype proxytype) -{ - char *prox_portno; - char *endofprot; - - /* We use 'proxyptr' to point to the proxy name from now on... */ - char *proxyptr; - char *portptr; - char *atsign; - long port = -1; - char *proxyuser = NULL; - char *proxypasswd = NULL; - bool sockstype; - - /* We do the proxy host string parsing here. We want the host name and the - * port name. Accept a protocol:// prefix - */ - - /* Parse the protocol part if present */ - endofprot = strstr(proxy, "://"); - if(endofprot) { - proxyptr = endofprot + 3; - if(checkprefix("https", proxy)) - proxytype = CURLPROXY_HTTPS; - else if(checkprefix("socks5h", proxy)) - proxytype = CURLPROXY_SOCKS5_HOSTNAME; - else if(checkprefix("socks5", proxy)) - proxytype = CURLPROXY_SOCKS5; - else if(checkprefix("socks4a", proxy)) - proxytype = CURLPROXY_SOCKS4A; - else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy)) - proxytype = CURLPROXY_SOCKS4; - else if(checkprefix("http:", proxy)) - ; /* leave it as HTTP or HTTP/1.0 */ - else { - /* Any other xxx:// reject! */ - failf(data, "Unsupported proxy scheme for \'%s\'", proxy); - return CURLE_COULDNT_CONNECT; - } - } - else - proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */ - -#ifdef USE_SSL - if(!Curl_ssl->support_https_proxy) -#endif - if(proxytype == CURLPROXY_HTTPS) { - failf(data, "Unsupported proxy \'%s\', libcurl is built without the " - "HTTPS-proxy support.", proxy); - return CURLE_NOT_BUILT_IN; - } - - sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME || - proxytype == CURLPROXY_SOCKS5 || - proxytype == CURLPROXY_SOCKS4A || - proxytype == CURLPROXY_SOCKS4; - - /* Is there a username and password given in this proxy url? */ - atsign = strchr(proxyptr, '@'); - if(atsign) { - CURLcode result = - parse_login_details(proxyptr, atsign - proxyptr, - &proxyuser, &proxypasswd, NULL); - if(result) - return result; - proxyptr = atsign + 1; - } - - /* start scanning for port number at this point */ - portptr = proxyptr; - - /* detect and extract RFC6874-style IPv6-addresses */ - if(*proxyptr == '[') { - char *ptr = ++proxyptr; /* advance beyond the initial bracket */ - while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) - ptr++; - if(*ptr == '%') { - /* There might be a zone identifier */ - if(strncmp("%25", ptr, 3)) - infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); - ptr++; - /* Allow unreserved characters as defined in RFC 3986 */ - while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || - (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) - ptr++; - } - if(*ptr == ']') - /* yeps, it ended nicely with a bracket as well */ - *ptr++ = 0; - else - infof(data, "Invalid IPv6 address format\n"); - portptr = ptr; - /* Note that if this didn't end with a bracket, we still advanced the - * proxyptr first, but I can't see anything wrong with that as no host - * name nor a numeric can legally start with a bracket. - */ - } - - /* Get port number off proxy.server.com:1080 */ - prox_portno = strchr(portptr, ':'); - if(prox_portno) { - char *endp = NULL; - - *prox_portno = 0x0; /* cut off number from host name */ - prox_portno ++; - /* now set the local port number */ - port = strtol(prox_portno, &endp, 10); - if((endp && *endp && (*endp != '/') && (*endp != ' ')) || - (port < 0) || (port > 65535)) { - /* meant to detect for example invalid IPv6 numerical addresses without - brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only - because we then allow "URL style" with the number followed by a - slash, used in curl test cases already. Space is also an acceptable - terminating symbol. */ - infof(data, "No valid port number in proxy string (%s)\n", - prox_portno); - } - else - conn->port = port; - } - else { - if(proxyptr[0]=='/') { - /* If the first character in the proxy string is a slash, fail - immediately. The following code will otherwise clear the string which - will lead to code running as if no proxy was set! */ - Curl_safefree(proxyuser); - Curl_safefree(proxypasswd); - return CURLE_COULDNT_RESOLVE_PROXY; - } - - /* without a port number after the host name, some people seem to use - a slash so we strip everything from the first slash */ - atsign = strchr(proxyptr, '/'); - if(atsign) - *atsign = '\0'; /* cut off path part from host name */ - - if(data->set.proxyport) - /* None given in the proxy string, then get the default one if it is - given */ - port = data->set.proxyport; - else { - if(proxytype == CURLPROXY_HTTPS) - port = CURL_DEFAULT_HTTPS_PROXY_PORT; - else - port = CURL_DEFAULT_PROXY_PORT; - } - } - - if(*proxyptr) { - struct proxy_info *proxyinfo = - sockstype ? &conn->socks_proxy : &conn->http_proxy; - proxyinfo->proxytype = proxytype; - - if(proxyuser) { - /* found user and password, rip them out. note that we are unescaping - them, as there is otherwise no way to have a username or password - with reserved characters like ':' in them. */ - Curl_safefree(proxyinfo->user); - proxyinfo->user = curl_easy_unescape(data, proxyuser, 0, NULL); - Curl_safefree(proxyuser); - - if(!proxyinfo->user) { - Curl_safefree(proxypasswd); - return CURLE_OUT_OF_MEMORY; - } - - Curl_safefree(proxyinfo->passwd); - if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) - proxyinfo->passwd = curl_easy_unescape(data, proxypasswd, 0, NULL); - else - proxyinfo->passwd = strdup(""); - Curl_safefree(proxypasswd); - - if(!proxyinfo->passwd) - return CURLE_OUT_OF_MEMORY; - - conn->bits.proxy_user_passwd = TRUE; /* enable it */ - } - - if(port >= 0) { - proxyinfo->port = port; - if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc) - conn->port = port; - } - - /* now, clone the cleaned proxy host name */ - Curl_safefree(proxyinfo->host.rawalloc); - proxyinfo->host.rawalloc = strdup(proxyptr); - proxyinfo->host.name = proxyinfo->host.rawalloc; - - if(!proxyinfo->host.rawalloc) - return CURLE_OUT_OF_MEMORY; - } - - Curl_safefree(proxyuser); - Curl_safefree(proxypasswd); - - return CURLE_OK; -} - -/* - * Extract the user and password from the authentication string - */ -static CURLcode parse_proxy_auth(struct Curl_easy *data, - struct connectdata *conn) -{ - char proxyuser[MAX_CURL_USER_LENGTH]=""; - char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; - CURLcode result; - - if(data->set.str[STRING_PROXYUSERNAME] != NULL) { - strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME], - MAX_CURL_USER_LENGTH); - proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/ - } - if(data->set.str[STRING_PROXYPASSWORD] != NULL) { - strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD], - MAX_CURL_PASSWORD_LENGTH); - proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ - } - - result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL, - FALSE); - if(!result) - result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd, - NULL, FALSE); - return result; -} - -/* create_conn helper to parse and init proxy values. to be called after unix - socket init but before any proxy vars are evaluated. */ -static CURLcode create_conn_helper_init_proxy(struct connectdata *conn) -{ - char *proxy = NULL; - char *socksproxy = NULL; - char *no_proxy = NULL; - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - /************************************************************* - * Extract the user and password from the authentication string - *************************************************************/ - if(conn->bits.proxy_user_passwd) { - result = parse_proxy_auth(data, conn); - if(result) - goto out; - } - - /************************************************************* - * Detect what (if any) proxy to use - *************************************************************/ - if(data->set.str[STRING_PROXY]) { - proxy = strdup(data->set.str[STRING_PROXY]); - /* if global proxy is set, this is it */ - if(NULL == proxy) { - failf(data, "memory shortage"); - result = CURLE_OUT_OF_MEMORY; - goto out; - } - } - - if(data->set.str[STRING_PRE_PROXY]) { - socksproxy = strdup(data->set.str[STRING_PRE_PROXY]); - /* if global socks proxy is set, this is it */ - if(NULL == socksproxy) { - failf(data, "memory shortage"); - result = CURLE_OUT_OF_MEMORY; - goto out; - } - } - - if(!data->set.str[STRING_NOPROXY]) { - no_proxy = curl_getenv("no_proxy"); - if(!no_proxy) - no_proxy = curl_getenv("NO_PROXY"); - } - - if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ? - data->set.str[STRING_NOPROXY] : no_proxy)) { - Curl_safefree(proxy); - Curl_safefree(socksproxy); - } -#ifndef CURL_DISABLE_HTTP - else if(!proxy && !socksproxy) - /* if the host is not in the noproxy list, detect proxy. */ - proxy = detect_proxy(conn); -#endif /* CURL_DISABLE_HTTP */ - - Curl_safefree(no_proxy); - -#ifdef USE_UNIX_SOCKETS - /* For the time being do not mix proxy and unix domain sockets. See #1274 */ - if(proxy && conn->unix_domain_socket) { - free(proxy); - proxy = NULL; - } -#endif - - if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { - free(proxy); /* Don't bother with an empty proxy string or if the - protocol doesn't work with network */ - proxy = NULL; - } - if(socksproxy && (!*socksproxy || - (conn->handler->flags & PROTOPT_NONETWORK))) { - free(socksproxy); /* Don't bother with an empty socks proxy string or if - the protocol doesn't work with network */ - socksproxy = NULL; - } - - /*********************************************************************** - * If this is supposed to use a proxy, we need to figure out the proxy host - * name, proxy type and port number, so that we can re-use an existing - * connection that may exist registered to the same proxy host. - ***********************************************************************/ - if(proxy || socksproxy) { - if(proxy) { - result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype); - Curl_safefree(proxy); /* parse_proxy copies the proxy string */ - if(result) - goto out; - } - - if(socksproxy) { - result = parse_proxy(data, conn, socksproxy, - conn->socks_proxy.proxytype); - /* parse_proxy copies the socks proxy string */ - Curl_safefree(socksproxy); - if(result) - goto out; - } - - if(conn->http_proxy.host.rawalloc) { -#ifdef CURL_DISABLE_HTTP - /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */ - result = CURLE_UNSUPPORTED_PROTOCOL; - goto out; -#else - /* force this connection's protocol to become HTTP if compatible */ - if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) { - if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) && - !conn->bits.tunnel_proxy) - conn->handler = &Curl_handler_http; - else - /* if not converting to HTTP over the proxy, enforce tunneling */ - conn->bits.tunnel_proxy = TRUE; - } - conn->bits.httpproxy = TRUE; -#endif - } - else { - conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ - conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ - } - - if(conn->socks_proxy.host.rawalloc) { - if(!conn->http_proxy.host.rawalloc) { - /* once a socks proxy */ - if(!conn->socks_proxy.user) { - conn->socks_proxy.user = conn->http_proxy.user; - conn->http_proxy.user = NULL; - Curl_safefree(conn->socks_proxy.passwd); - conn->socks_proxy.passwd = conn->http_proxy.passwd; - conn->http_proxy.passwd = NULL; - } - } - conn->bits.socksproxy = TRUE; - } - else - conn->bits.socksproxy = FALSE; /* not a socks proxy */ - } - else { - conn->bits.socksproxy = FALSE; - conn->bits.httpproxy = FALSE; - } - conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy; - - if(!conn->bits.proxy) { - /* we aren't using the proxy after all... */ - conn->bits.proxy = FALSE; - conn->bits.httpproxy = FALSE; - conn->bits.socksproxy = FALSE; - conn->bits.proxy_user_passwd = FALSE; - conn->bits.tunnel_proxy = FALSE; - } - -out: - - free(socksproxy); - free(proxy); - return result; -} -#endif /* CURL_DISABLE_PROXY */ - -/* - * parse_url_login() - * - * Parse the login details (user name, password and options) from the URL and - * strip them out of the host name - * - * Inputs: data->set.use_netrc (CURLOPT_NETRC) - * conn->host.name - * - * Outputs: (almost :- all currently undefined) - * conn->bits.user_passwd - non-zero if non-default passwords exist - * user - non-zero length if defined - * passwd - non-zero length if defined - * options - non-zero length if defined - * conn->host.name - remove user name and password - */ -static CURLcode parse_url_login(struct Curl_easy *data, - struct connectdata *conn, - char **user, char **passwd, char **options) -{ - CURLcode result = CURLE_OK; - char *userp = NULL; - char *passwdp = NULL; - char *optionsp = NULL; - - /* At this point, we're hoping all the other special cases have - * been taken care of, so conn->host.name is at most - * [user[:password][;options]]@]hostname - * - * We need somewhere to put the embedded details, so do that first. - */ - - char *ptr = strchr(conn->host.name, '@'); - char *login = conn->host.name; - - DEBUGASSERT(!**user); - DEBUGASSERT(!**passwd); - DEBUGASSERT(!**options); - DEBUGASSERT(conn->handler); - - if(!ptr) - goto out; - - /* We will now try to extract the - * possible login information in a string like: - * ftp://user:password@ftp.my.site:8021/README */ - conn->host.name = ++ptr; - - /* So the hostname is sane. Only bother interpreting the - * results if we could care. It could still be wasted - * work because it might be overtaken by the programmatically - * set user/passwd, but doing that first adds more cases here :-( - */ - - if(data->set.use_netrc == CURL_NETRC_REQUIRED) - goto out; - - /* We could use the login information in the URL so extract it. Only parse - options if the handler says we should. */ - result = parse_login_details(login, ptr - login - 1, - &userp, &passwdp, - (conn->handler->flags & PROTOPT_URLOPTIONS)? - &optionsp:NULL); - if(result) - goto out; - - if(userp) { - char *newname; - - /* We have a user in the URL */ - conn->bits.userpwd_in_url = TRUE; - conn->bits.user_passwd = TRUE; /* enable user+password */ - - /* Decode the user */ - result = Curl_urldecode(data, userp, 0, &newname, NULL, FALSE); - if(result) { - goto out; - } - - free(*user); - *user = newname; - } - - if(passwdp) { - /* We have a password in the URL so decode it */ - char *newpasswd; - result = Curl_urldecode(data, passwdp, 0, &newpasswd, NULL, FALSE); - if(result) { - goto out; - } - - free(*passwd); - *passwd = newpasswd; - } - - if(optionsp) { - /* We have an options list in the URL so decode it */ - char *newoptions; - result = Curl_urldecode(data, optionsp, 0, &newoptions, NULL, FALSE); - if(result) { - goto out; - } - - free(*options); - *options = newoptions; - } - - - out: - - free(userp); - free(passwdp); - free(optionsp); - - return result; -} - -/* - * parse_login_details() - * - * This is used to parse a login string for user name, password and options in - * the following formats: - * - * user - * user:password - * user:password;options - * user;options - * user;options:password - * :password - * :password;options - * ;options - * ;options:password - * - * Parameters: - * - * login [in] - The login string. - * len [in] - The length of the login string. - * userp [in/out] - The address where a pointer to newly allocated memory - * holding the user will be stored upon completion. - * passdwp [in/out] - The address where a pointer to newly allocated memory - * holding the password will be stored upon completion. - * optionsp [in/out] - The address where a pointer to newly allocated memory - * holding the options will be stored upon completion. - * - * Returns CURLE_OK on success. - */ -static CURLcode parse_login_details(const char *login, const size_t len, - char **userp, char **passwdp, - char **optionsp) -{ - CURLcode result = CURLE_OK; - char *ubuf = NULL; - char *pbuf = NULL; - char *obuf = NULL; - const char *psep = NULL; - const char *osep = NULL; - size_t ulen; - size_t plen; - size_t olen; - - /* Attempt to find the password separator */ - if(passwdp) { - psep = strchr(login, ':'); - - /* Within the constraint of the login string */ - if(psep >= login + len) - psep = NULL; - } - - /* Attempt to find the options separator */ - if(optionsp) { - osep = strchr(login, ';'); - - /* Within the constraint of the login string */ - if(osep >= login + len) - osep = NULL; - } - - /* Calculate the portion lengths */ - ulen = (psep ? - (size_t)(osep && psep > osep ? osep - login : psep - login) : - (osep ? (size_t)(osep - login) : len)); - plen = (psep ? - (osep && osep > psep ? (size_t)(osep - psep) : - (size_t)(login + len - psep)) - 1 : 0); - olen = (osep ? - (psep && psep > osep ? (size_t)(psep - osep) : - (size_t)(login + len - osep)) - 1 : 0); - - /* Allocate the user portion buffer */ - if(userp && ulen) { - ubuf = malloc(ulen + 1); - if(!ubuf) - result = CURLE_OUT_OF_MEMORY; - } - - /* Allocate the password portion buffer */ - if(!result && passwdp && plen) { - pbuf = malloc(plen + 1); - if(!pbuf) { - free(ubuf); - result = CURLE_OUT_OF_MEMORY; - } - } - - /* Allocate the options portion buffer */ - if(!result && optionsp && olen) { - obuf = malloc(olen + 1); - if(!obuf) { - free(pbuf); - free(ubuf); - result = CURLE_OUT_OF_MEMORY; - } - } - - if(!result) { - /* Store the user portion if necessary */ - if(ubuf) { - memcpy(ubuf, login, ulen); - ubuf[ulen] = '\0'; - Curl_safefree(*userp); - *userp = ubuf; - } - - /* Store the password portion if necessary */ - if(pbuf) { - memcpy(pbuf, psep + 1, plen); - pbuf[plen] = '\0'; - Curl_safefree(*passwdp); - *passwdp = pbuf; - } - - /* Store the options portion if necessary */ - if(obuf) { - memcpy(obuf, osep + 1, olen); - obuf[olen] = '\0'; - Curl_safefree(*optionsp); - *optionsp = obuf; - } - } - - return result; -} - -/************************************************************* - * Figure out the remote port number and fix it in the URL - * - * No matter if we use a proxy or not, we have to figure out the remote - * port number of various reasons. - * - * To be able to detect port number flawlessly, we must not confuse them - * IPv6-specified addresses in the [0::1] style. (RFC2732) - * - * The conn->host.name is currently [user:passwd@]host[:port] where host - * could be a hostname, IPv4 address or IPv6 address. - * - * The port number embedded in the URL is replaced, if necessary. - *************************************************************/ -static CURLcode parse_remote_port(struct Curl_easy *data, - struct connectdata *conn) -{ - char *portptr; - char endbracket; - - /* Note that at this point, the IPv6 address cannot contain any scope - suffix as that has already been removed in the parseurlandfillconn() - function */ - if((1 == sscanf(conn->host.name, "[%*45[0123456789abcdefABCDEF:.]%c", - &endbracket)) && - (']' == endbracket)) { - /* this is a RFC2732-style specified IP-address */ - conn->bits.ipv6_ip = TRUE; - - conn->host.name++; /* skip over the starting bracket */ - portptr = strchr(conn->host.name, ']'); - if(portptr) { - *portptr++ = '\0'; /* zero terminate, killing the bracket */ - if(':' != *portptr) - portptr = NULL; /* no port number available */ - } - } - else { -#ifdef ENABLE_IPV6 - struct in6_addr in6; - if(Curl_inet_pton(AF_INET6, conn->host.name, &in6) > 0) { - /* This is a numerical IPv6 address, meaning this is a wrongly formatted - URL */ - failf(data, "IPv6 numerical address used in URL without brackets"); - return CURLE_URL_MALFORMAT; - } -#endif - - portptr = strchr(conn->host.name, ':'); - } - - if(data->set.use_port && data->state.allow_port) { - /* if set, we use this and ignore the port possibly given in the URL */ - conn->remote_port = (unsigned short)data->set.use_port; - if(portptr) - *portptr = '\0'; /* cut off the name there anyway - if there was a port - number - since the port number is to be ignored! */ - if(conn->bits.httpproxy) { - /* we need to create new URL with the new port number */ - char *url; - char type[12]=""; - - if(conn->bits.type_set) - snprintf(type, sizeof(type), ";type=%c", - data->set.prefer_ascii?'A': - (data->set.ftp_list_only?'D':'I')); - - /* - * This synthesized URL isn't always right--suffixes like ;type=A are - * stripped off. It would be better to work directly from the original - * URL and simply replace the port part of it. - */ - url = aprintf("%s://%s%s%s:%hu%s%s%s", conn->given->scheme, - conn->bits.ipv6_ip?"[":"", conn->host.name, - conn->bits.ipv6_ip?"]":"", conn->remote_port, - data->state.slash_removed?"/":"", data->state.path, - type); - if(!url) - return CURLE_OUT_OF_MEMORY; - - if(data->change.url_alloc) { - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - - data->change.url = url; - data->change.url_alloc = TRUE; - } - } - else if(portptr) { - /* no CURLOPT_PORT given, extract the one from the URL */ - - char *rest; - long port; - - port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */ - - if((port < 0) || (port > 0xffff)) { - /* Single unix standard says port numbers are 16 bits long */ - failf(data, "Port number out of range"); - return CURLE_URL_MALFORMAT; - } - - if(rest[0]) { - failf(data, "Port number ended with '%c'", rest[0]); - return CURLE_URL_MALFORMAT; - } - - if(rest != &portptr[1]) { - *portptr = '\0'; /* cut off the name there */ - conn->remote_port = curlx_ultous(port); - } - else { - /* Browser behavior adaptation. If there's a colon with no digits after, - just cut off the name there which makes us ignore the colon and just - use the default port. Firefox and Chrome both do that. */ - *portptr = '\0'; - } - } - - /* only if remote_port was not already parsed off the URL we use the - default port number */ - if(conn->remote_port < 0) - conn->remote_port = (unsigned short)conn->given->defport; - - return CURLE_OK; -} - -/* - * Override the login details from the URL with that in the CURLOPT_USERPWD - * option or a .netrc file, if applicable. - */ -static CURLcode override_login(struct Curl_easy *data, - struct connectdata *conn, - char **userp, char **passwdp, char **optionsp) -{ - if(data->set.str[STRING_USERNAME]) { - free(*userp); - *userp = strdup(data->set.str[STRING_USERNAME]); - if(!*userp) - return CURLE_OUT_OF_MEMORY; - } - - if(data->set.str[STRING_PASSWORD]) { - free(*passwdp); - *passwdp = strdup(data->set.str[STRING_PASSWORD]); - if(!*passwdp) - return CURLE_OUT_OF_MEMORY; - } - - if(data->set.str[STRING_OPTIONS]) { - free(*optionsp); - *optionsp = strdup(data->set.str[STRING_OPTIONS]); - if(!*optionsp) - return CURLE_OUT_OF_MEMORY; - } - - conn->bits.netrc = FALSE; - if(data->set.use_netrc != CURL_NETRC_IGNORED) { - int ret = Curl_parsenetrc(conn->host.name, - userp, passwdp, - data->set.str[STRING_NETRC_FILE]); - if(ret > 0) { - infof(data, "Couldn't find host %s in the " - DOT_CHAR "netrc file; using defaults\n", - conn->host.name); - } - else if(ret < 0) { - return CURLE_OUT_OF_MEMORY; - } - else { - /* set bits.netrc TRUE to remember that we got the name from a .netrc - file, so that it is safe to use even if we followed a Location: to a - different host or similar. */ - conn->bits.netrc = TRUE; - - conn->bits.user_passwd = TRUE; /* enable user+password */ - } - } - - return CURLE_OK; -} - -/* - * Set the login details so they're available in the connection - */ -static CURLcode set_login(struct connectdata *conn, - const char *user, const char *passwd, - const char *options) -{ - CURLcode result = CURLE_OK; - - /* If our protocol needs a password and we have none, use the defaults */ - if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) { - /* Store the default user */ - conn->user = strdup(CURL_DEFAULT_USER); - - /* Store the default password */ - if(conn->user) - conn->passwd = strdup(CURL_DEFAULT_PASSWORD); - else - conn->passwd = NULL; - - /* This is the default password, so DON'T set conn->bits.user_passwd */ - } - else { - /* Store the user, zero-length if not set */ - conn->user = strdup(user); - - /* Store the password (only if user is present), zero-length if not set */ - if(conn->user) - conn->passwd = strdup(passwd); - else - conn->passwd = NULL; - } - - if(!conn->user || !conn->passwd) - result = CURLE_OUT_OF_MEMORY; - - /* Store the options, null if not set */ - if(!result && options[0]) { - conn->options = strdup(options); - - if(!conn->options) - result = CURLE_OUT_OF_MEMORY; - } - - return result; -} - -/* - * Parses a "host:port" string to connect to. - * The hostname and the port may be empty; in this case, NULL is returned for - * the hostname and -1 for the port. - */ -static CURLcode parse_connect_to_host_port(struct Curl_easy *data, - const char *host, - char **hostname_result, - int *port_result) -{ - char *host_dup; - char *hostptr; - char *host_portno; - char *portptr; - int port = -1; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - *hostname_result = NULL; - *port_result = -1; - - if(!host || !*host) - return CURLE_OK; - - host_dup = strdup(host); - if(!host_dup) - return CURLE_OUT_OF_MEMORY; - - hostptr = host_dup; - - /* start scanning for port number at this point */ - portptr = hostptr; - - /* detect and extract RFC6874-style IPv6-addresses */ - if(*hostptr == '[') { - char *ptr = ++hostptr; /* advance beyond the initial bracket */ - while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) - ptr++; - if(*ptr == '%') { - /* There might be a zone identifier */ - if(strncmp("%25", ptr, 3)) - infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); - ptr++; - /* Allow unreserved characters as defined in RFC 3986 */ - while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || - (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) - ptr++; - } - if(*ptr == ']') - /* yeps, it ended nicely with a bracket as well */ - *ptr++ = '\0'; - else - infof(data, "Invalid IPv6 address format\n"); - portptr = ptr; - /* Note that if this didn't end with a bracket, we still advanced the - * hostptr first, but I can't see anything wrong with that as no host - * name nor a numeric can legally start with a bracket. - */ - } - - /* Get port number off server.com:1080 */ - host_portno = strchr(portptr, ':'); - if(host_portno) { - char *endp = NULL; - *host_portno = '\0'; /* cut off number from host name */ - host_portno++; - if(*host_portno) { - long portparse = strtol(host_portno, &endp, 10); - if((endp && *endp) || (portparse < 0) || (portparse > 65535)) { - infof(data, "No valid port number in connect to host string (%s)\n", - host_portno); - hostptr = NULL; - port = -1; - } - else - port = (int)portparse; /* we know it will fit */ - } - } - - /* now, clone the cleaned host name */ - if(hostptr) { - *hostname_result = strdup(hostptr); - if(!*hostname_result) { - free(host_dup); - return CURLE_OUT_OF_MEMORY; - } - } - - *port_result = port; - - free(host_dup); - return CURLE_OK; -} - -/* - * Parses one "connect to" string in the form: - * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". - */ -static CURLcode parse_connect_to_string(struct Curl_easy *data, - struct connectdata *conn, - const char *conn_to_host, - char **host_result, - int *port_result) -{ - CURLcode result = CURLE_OK; - const char *ptr = conn_to_host; - int host_match = FALSE; - int port_match = FALSE; - - *host_result = NULL; - *port_result = -1; - - if(*ptr == ':') { - /* an empty hostname always matches */ - host_match = TRUE; - ptr++; - } - else { - /* check whether the URL's hostname matches */ - size_t hostname_to_match_len; - char *hostname_to_match = aprintf("%s%s%s", - conn->bits.ipv6_ip ? "[" : "", - conn->host.name, - conn->bits.ipv6_ip ? "]" : ""); - if(!hostname_to_match) - return CURLE_OUT_OF_MEMORY; - hostname_to_match_len = strlen(hostname_to_match); - host_match = strncasecompare(ptr, hostname_to_match, - hostname_to_match_len); - free(hostname_to_match); - ptr += hostname_to_match_len; - - host_match = host_match && *ptr == ':'; - ptr++; - } - - if(host_match) { - if(*ptr == ':') { - /* an empty port always matches */ - port_match = TRUE; - ptr++; - } - else { - /* check whether the URL's port matches */ - char *ptr_next = strchr(ptr, ':'); - if(ptr_next) { - char *endp = NULL; - long port_to_match = strtol(ptr, &endp, 10); - if((endp == ptr_next) && (port_to_match == conn->remote_port)) { - port_match = TRUE; - ptr = ptr_next + 1; - } - } - } - } - - if(host_match && port_match) { - /* parse the hostname and port to connect to */ - result = parse_connect_to_host_port(data, ptr, host_result, port_result); - } - - return result; -} - -/* - * Processes all strings in the "connect to" slist, and uses the "connect - * to host" and "connect to port" of the first string that matches. - */ -static CURLcode parse_connect_to_slist(struct Curl_easy *data, - struct connectdata *conn, - struct curl_slist *conn_to_host) -{ - CURLcode result = CURLE_OK; - char *host = NULL; - int port = -1; - - while(conn_to_host && !host && port == -1) { - result = parse_connect_to_string(data, conn, conn_to_host->data, - &host, &port); - if(result) - return result; - - if(host && *host) { - conn->conn_to_host.rawalloc = host; - conn->conn_to_host.name = host; - conn->bits.conn_to_host = TRUE; - - infof(data, "Connecting to hostname: %s\n", host); - } - else { - /* no "connect to host" */ - conn->bits.conn_to_host = FALSE; - Curl_safefree(host); - } - - if(port >= 0) { - conn->conn_to_port = port; - conn->bits.conn_to_port = TRUE; - infof(data, "Connecting to port: %d\n", port); - } - else { - /* no "connect to port" */ - conn->bits.conn_to_port = FALSE; - port = -1; - } - - conn_to_host = conn_to_host->next; - } - - return result; -} - -/************************************************************* - * Resolve the address of the server or proxy - *************************************************************/ -static CURLcode resolve_server(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ - CURLcode result = CURLE_OK; - time_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - - /************************************************************* - * Resolve the name of the server or proxy - *************************************************************/ - if(conn->bits.reuse) - /* We're reusing the connection - no need to resolve anything, and - fix_hostname() was called already in create_conn() for the re-use - case. */ - *async = FALSE; - - else { - /* this is a fresh connect */ - int rc; - struct Curl_dns_entry *hostaddr; - -#ifdef USE_UNIX_SOCKETS - if(conn->unix_domain_socket) { - /* Unix domain sockets are local. The host gets ignored, just use the - * specified domain socket address. Do not cache "DNS entries". There is - * no DNS involved and we already have the filesystem path available */ - const char *path = conn->unix_domain_socket; - - hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); - if(!hostaddr) - result = CURLE_OUT_OF_MEMORY; - else { - bool longpath = FALSE; - hostaddr->addr = Curl_unix2addr(path, &longpath, - conn->abstract_unix_socket); - if(hostaddr->addr) - hostaddr->inuse++; - else { - /* Long paths are not supported for now */ - if(longpath) { - failf(data, "Unix socket path too long: '%s'", path); - result = CURLE_COULDNT_RESOLVE_HOST; - } - else - result = CURLE_OUT_OF_MEMORY; - free(hostaddr); - hostaddr = NULL; - } - } - } - else -#endif - if(!conn->bits.proxy) { - struct hostname *connhost; - if(conn->bits.conn_to_host) - connhost = &conn->conn_to_host; - else - connhost = &conn->host; - - /* If not connecting via a proxy, extract the port from the URL, if it is - * there, thus overriding any defaults that might have been set above. */ - if(conn->bits.conn_to_port) - conn->port = conn->conn_to_port; - else - conn->port = conn->remote_port; - - /* Resolve target host right on */ - rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port, - &hostaddr, timeout_ms); - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - - else if(rc == CURLRESOLV_TIMEDOUT) - result = CURLE_OPERATION_TIMEDOUT; - - else if(!hostaddr) { - failf(data, "Couldn't resolve host '%s'", connhost->dispname); - result = CURLE_COULDNT_RESOLVE_HOST; - /* don't return yet, we need to clean up the timeout first */ - } - } - else { - /* This is a proxy that hasn't been resolved yet. */ - - struct hostname * const host = conn->bits.socksproxy ? - &conn->socks_proxy.host : &conn->http_proxy.host; - - /* resolve proxy */ - rc = Curl_resolv_timeout(conn, host->name, (int)conn->port, - &hostaddr, timeout_ms); - - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - - else if(rc == CURLRESOLV_TIMEDOUT) - result = CURLE_OPERATION_TIMEDOUT; - - else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", host->dispname); - result = CURLE_COULDNT_RESOLVE_PROXY; - /* don't return yet, we need to clean up the timeout first */ - } - } - DEBUGASSERT(conn->dns_entry == NULL); - conn->dns_entry = hostaddr; - } - - return result; -} - -/* - * Cleanup the connection just allocated before we can move along and use the - * previously existing one. All relevant data is copied over and old_conn is - * ready for freeing once this function returns. - */ -static void reuse_conn(struct connectdata *old_conn, - struct connectdata *conn) -{ - free_fixed_hostname(&old_conn->http_proxy.host); - free_fixed_hostname(&old_conn->socks_proxy.host); - - free(old_conn->http_proxy.host.rawalloc); - free(old_conn->socks_proxy.host.rawalloc); - - /* free the SSL config struct from this connection struct as this was - allocated in vain and is targeted for destruction */ - Curl_free_primary_ssl_config(&old_conn->ssl_config); - Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config); - - conn->data = old_conn->data; - - /* get the user+password information from the old_conn struct since it may - * be new for this request even when we re-use an existing connection */ - conn->bits.user_passwd = old_conn->bits.user_passwd; - if(conn->bits.user_passwd) { - /* use the new user name and password though */ - Curl_safefree(conn->user); - Curl_safefree(conn->passwd); - conn->user = old_conn->user; - conn->passwd = old_conn->passwd; - old_conn->user = NULL; - old_conn->passwd = NULL; - } - - conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd; - if(conn->bits.proxy_user_passwd) { - /* use the new proxy user name and proxy password though */ - Curl_safefree(conn->http_proxy.user); - Curl_safefree(conn->socks_proxy.user); - Curl_safefree(conn->http_proxy.passwd); - Curl_safefree(conn->socks_proxy.passwd); - conn->http_proxy.user = old_conn->http_proxy.user; - conn->socks_proxy.user = old_conn->socks_proxy.user; - conn->http_proxy.passwd = old_conn->http_proxy.passwd; - conn->socks_proxy.passwd = old_conn->socks_proxy.passwd; - old_conn->http_proxy.user = NULL; - old_conn->socks_proxy.user = NULL; - old_conn->http_proxy.passwd = NULL; - old_conn->socks_proxy.passwd = NULL; - } - - /* host can change, when doing keepalive with a proxy or if the case is - different this time etc */ - free_fixed_hostname(&conn->host); - free_fixed_hostname(&conn->conn_to_host); - Curl_safefree(conn->host.rawalloc); - Curl_safefree(conn->conn_to_host.rawalloc); - conn->host = old_conn->host; - conn->conn_to_host = old_conn->conn_to_host; - conn->conn_to_port = old_conn->conn_to_port; - conn->remote_port = old_conn->remote_port; - - /* persist connection info in session handle */ - Curl_persistconninfo(conn); - - conn_reset_all_postponed_data(old_conn); /* free buffers */ - - /* re-use init */ - conn->bits.reuse = TRUE; /* yes, we're re-using here */ - - Curl_safefree(old_conn->user); - Curl_safefree(old_conn->passwd); - Curl_safefree(old_conn->http_proxy.user); - Curl_safefree(old_conn->socks_proxy.user); - Curl_safefree(old_conn->http_proxy.passwd); - Curl_safefree(old_conn->socks_proxy.passwd); - Curl_safefree(old_conn->localdev); - - Curl_llist_destroy(&old_conn->send_pipe, NULL); - Curl_llist_destroy(&old_conn->recv_pipe, NULL); - - Curl_safefree(old_conn->master_buffer); - -#ifdef USE_UNIX_SOCKETS - Curl_safefree(old_conn->unix_domain_socket); -#endif -} - -/** - * create_conn() sets up a new connectdata struct, or re-uses an already - * existing one, and resolves host name. - * - * if this function returns CURLE_OK and *async is set to TRUE, the resolve - * response will be coming asynchronously. If *async is FALSE, the name is - * already resolved. - * - * @param data The sessionhandle pointer - * @param in_connect is set to the next connection data pointer - * @param async is set TRUE when an async DNS resolution is pending - * @see Curl_setup_conn() - * - * *NOTE* this function assigns the conn->data pointer! - */ - -static CURLcode create_conn(struct Curl_easy *data, - struct connectdata **in_connect, - bool *async) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn; - struct connectdata *conn_temp = NULL; - size_t urllen; - char *user = NULL; - char *passwd = NULL; - char *options = NULL; - bool reuse; - bool prot_missing = FALSE; - bool connections_available = TRUE; - bool force_reuse = FALSE; - bool waitpipe = FALSE; - size_t max_host_connections = Curl_multi_max_host_connections(data->multi); - size_t max_total_connections = Curl_multi_max_total_connections(data->multi); - - *async = FALSE; - - /************************************************************* - * Check input data - *************************************************************/ - - if(!data->change.url) { - result = CURLE_URL_MALFORMAT; - goto out; - } - - /* First, split up the current URL in parts so that we can use the - parts for checking against the already present connections. In order - to not have to modify everything at once, we allocate a temporary - connection data struct and fill in for comparison purposes. */ - conn = allocate_conn(data); - - if(!conn) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - /* We must set the return variable as soon as possible, so that our - parent can cleanup any possible allocs we may have done before - any failure */ - *in_connect = conn; - - /* This initing continues below, see the comment "Continue connectdata - * initialization here" */ - - /*********************************************************** - * We need to allocate memory to store the path in. We get the size of the - * full URL to be sure, and we need to make it at least 256 bytes since - * other parts of the code will rely on this fact - ***********************************************************/ -#define LEAST_PATH_ALLOC 256 - urllen = strlen(data->change.url); - if(urllen < LEAST_PATH_ALLOC) - urllen = LEAST_PATH_ALLOC; - - /* - * We malloc() the buffers below urllen+2 to make room for 2 possibilities: - * 1 - an extra terminating zero - * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used) - */ - - Curl_safefree(data->state.pathbuffer); - data->state.path = NULL; - - data->state.pathbuffer = malloc(urllen + 2); - if(NULL == data->state.pathbuffer) { - result = CURLE_OUT_OF_MEMORY; /* really bad error */ - goto out; - } - data->state.path = data->state.pathbuffer; - - conn->host.rawalloc = malloc(urllen + 2); - if(NULL == conn->host.rawalloc) { - Curl_safefree(data->state.pathbuffer); - data->state.path = NULL; - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - conn->host.name = conn->host.rawalloc; - conn->host.name[0] = 0; - - user = strdup(""); - passwd = strdup(""); - options = strdup(""); - if(!user || !passwd || !options) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd, - &options); - if(result) - goto out; - - /************************************************************* - * No protocol part in URL was used, add it! - *************************************************************/ - if(prot_missing) { - /* We're guessing prefixes here and if we're told to use a proxy or if - we're gonna follow a Location: later or... then we need the protocol - part added so that we have a valid URL. */ - char *reurl; - char *ch_lower; - - reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url); - - if(!reurl) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - /* Change protocol prefix to lower-case */ - for(ch_lower = reurl; *ch_lower != ':'; ch_lower++) - *ch_lower = (char)TOLOWER(*ch_lower); - - if(data->change.url_alloc) { - Curl_safefree(data->change.url); - data->change.url_alloc = FALSE; - } - - data->change.url = reurl; - data->change.url_alloc = TRUE; /* free this later */ - } - - /************************************************************* - * If the protocol can't handle url query strings, then cut - * off the unhandable part - *************************************************************/ - if((conn->given->flags&PROTOPT_NOURLQUERY)) { - char *path_q_sep = strchr(conn->data->state.path, '?'); - if(path_q_sep) { - /* according to rfc3986, allow the query (?foo=bar) - also on protocols that can't handle it. - - cut the string-part after '?' - */ - - /* terminate the string */ - path_q_sep[0] = 0; - } - } - - if(data->set.str[STRING_BEARER]) { - conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); - if(!conn->oauth_bearer) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - } - -#ifdef USE_UNIX_SOCKETS - if(data->set.str[STRING_UNIX_SOCKET_PATH]) { - conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); - if(conn->unix_domain_socket == NULL) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - conn->abstract_unix_socket = data->set.abstract_unix_socket; - } -#endif - - /* After the unix socket init but before the proxy vars are used, parse and - initialize the proxy vars */ -#ifndef CURL_DISABLE_PROXY - result = create_conn_helper_init_proxy(conn); - if(result) - goto out; -#endif - - /************************************************************* - * If the protocol is using SSL and HTTP proxy is used, we set - * the tunnel_proxy bit. - *************************************************************/ - if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) - conn->bits.tunnel_proxy = TRUE; - - /************************************************************* - * Figure out the remote port number and fix it in the URL - *************************************************************/ - result = parse_remote_port(data, conn); - if(result) - goto out; - - /* Check for overridden login details and set them accordingly so they - they are known when protocol->setup_connection is called! */ - result = override_login(data, conn, &user, &passwd, &options); - if(result) - goto out; - result = set_login(conn, user, passwd, options); - if(result) - goto out; - - /************************************************************* - * Process the "connect to" linked list of hostname/port mappings. - * Do this after the remote port number has been fixed in the URL. - *************************************************************/ - result = parse_connect_to_slist(data, conn, data->set.connect_to); - if(result) - goto out; - - /************************************************************* - * IDN-fix the hostnames - *************************************************************/ - fix_hostname(conn, &conn->host); - if(conn->bits.conn_to_host) - fix_hostname(conn, &conn->conn_to_host); - if(conn->bits.httpproxy) - fix_hostname(conn, &conn->http_proxy.host); - if(conn->bits.socksproxy) - fix_hostname(conn, &conn->socks_proxy.host); - - /************************************************************* - * Check whether the host and the "connect to host" are equal. - * Do this after the hostnames have been IDN-fixed. - *************************************************************/ - if(conn->bits.conn_to_host && - strcasecompare(conn->conn_to_host.name, conn->host.name)) { - conn->bits.conn_to_host = FALSE; - } - - /************************************************************* - * Check whether the port and the "connect to port" are equal. - * Do this after the remote port number has been fixed in the URL. - *************************************************************/ - if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { - conn->bits.conn_to_port = FALSE; - } - - /************************************************************* - * If the "connect to" feature is used with an HTTP proxy, - * we set the tunnel_proxy bit. - *************************************************************/ - if((conn->bits.conn_to_host || conn->bits.conn_to_port) && - conn->bits.httpproxy) - conn->bits.tunnel_proxy = TRUE; - - /************************************************************* - * Setup internals depending on protocol. Needs to be done after - * we figured out what/if proxy to use. - *************************************************************/ - result = setup_connection_internals(conn); - if(result) - goto out; - - conn->recv[FIRSTSOCKET] = Curl_recv_plain; - conn->send[FIRSTSOCKET] = Curl_send_plain; - conn->recv[SECONDARYSOCKET] = Curl_recv_plain; - conn->send[SECONDARYSOCKET] = Curl_send_plain; - - conn->bits.tcp_fastopen = data->set.tcp_fastopen; - - /*********************************************************************** - * file: is a special case in that it doesn't need a network connection - ***********************************************************************/ -#ifndef CURL_DISABLE_FILE - if(conn->handler->flags & PROTOPT_NONETWORK) { - bool done; - /* this is supposed to be the connect function so we better at least check - that the file is present here! */ - DEBUGASSERT(conn->handler->connect_it); - result = conn->handler->connect_it(conn, &done); - - /* Setup a "faked" transfer that'll do nothing */ - if(!result) { - conn->data = data; - conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ - - Curl_conncache_add_conn(data->state.conn_cache, conn); - - /* - * Setup whatever necessary for a resumed transfer - */ - result = setup_range(data); - if(result) { - DEBUGASSERT(conn->handler->done); - /* we ignore the return code for the protocol-specific DONE */ - (void)conn->handler->done(conn, result, FALSE); - goto out; - } - - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ - -1, NULL); /* no upload */ - } - - /* since we skip do_init() */ - Curl_init_do(data, conn); - - goto out; - } -#endif - - /* Get a cloned copy of the SSL config situation stored in the - connection struct. But to get this going nicely, we must first make - sure that the strings in the master copy are pointing to the correct - strings in the session handle strings array! - - Keep in mind that the pointers in the master copy are pointing to strings - that will be freed as part of the Curl_easy struct, but all cloned - copies will be separately allocated. - */ - data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG]; - data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; - data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG]; - data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; - data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; - data->set.proxy_ssl.primary.random_file = - data->set.str[STRING_SSL_RANDOM_FILE]; - data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; - data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; - data->set.ssl.primary.cipher_list = - data->set.str[STRING_SSL_CIPHER_LIST_ORIG]; - data->set.proxy_ssl.primary.cipher_list = - data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; - - data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; - data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; - data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; - data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; - data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; - data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; - data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; - data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; - data->set.ssl.key = data->set.str[STRING_KEY_ORIG]; - data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; - data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG]; - data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; - data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG]; - data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; - data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG]; - data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; -#ifdef USE_TLS_SRP - data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; - data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; - data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; - data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; -#endif - - if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, - &conn->ssl_config)) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary, - &conn->proxy_ssl_config)) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - prune_dead_connections(data); - - /************************************************************* - * Check the current list of connections to see if we can - * re-use an already existing one or if we have to create a - * new one. - *************************************************************/ - - /* reuse_fresh is TRUE if we are told to use a new connection by force, but - we only acknowledge this option if this is not a re-used connection - already (which happens due to follow-location or during a HTTP - authentication phase). */ - if(data->set.reuse_fresh && !data->state.this_is_a_follow) - reuse = FALSE; - else - reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe); - - /* If we found a reusable connection, we may still want to - open a new connection if we are pipelining. */ - if(reuse && !force_reuse && IsPipeliningPossible(data, conn_temp)) { - size_t pipelen = conn_temp->send_pipe.size + conn_temp->recv_pipe.size; - if(pipelen > 0) { - infof(data, "Found connection %ld, with requests in the pipe (%zu)\n", - conn_temp->connection_id, pipelen); - - if(conn_temp->bundle->num_connections < max_host_connections && - data->state.conn_cache->num_connections < max_total_connections) { - /* We want a new connection anyway */ - reuse = FALSE; - - infof(data, "We can reuse, but we want a new connection anyway\n"); - } - } - } - - if(reuse) { - /* - * We already have a connection for this, we got the former connection - * in the conn_temp variable and thus we need to cleanup the one we - * just allocated before we can move along and use the previously - * existing one. - */ - conn_temp->inuse = TRUE; /* mark this as being in use so that no other - handle in a multi stack may nick it */ - reuse_conn(conn, conn_temp); - free(conn); /* we don't need this anymore */ - conn = conn_temp; - *in_connect = conn; - - infof(data, "Re-using existing connection! (#%ld) with %s %s\n", - conn->connection_id, - conn->bits.proxy?"proxy":"host", - conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : - conn->http_proxy.host.name ? conn->http_proxy.host.dispname : - conn->host.dispname); - } - else { - /* We have decided that we want a new connection. However, we may not - be able to do that if we have reached the limit of how many - connections we are allowed to open. */ - struct connectbundle *bundle = NULL; - - if(conn->handler->flags & PROTOPT_ALPN_NPN) { - /* The protocol wants it, so set the bits if enabled in the easy handle - (default) */ - if(data->set.ssl_enable_alpn) - conn->bits.tls_enable_alpn = TRUE; - if(data->set.ssl_enable_npn) - conn->bits.tls_enable_npn = TRUE; - } - - if(waitpipe) - /* There is a connection that *might* become usable for pipelining - "soon", and we wait for that */ - connections_available = FALSE; - else - bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); - - if(max_host_connections > 0 && bundle && - (bundle->num_connections >= max_host_connections)) { - struct connectdata *conn_candidate; - - /* The bundle is full. Let's see if we can kill a connection. */ - conn_candidate = find_oldest_idle_connection_in_bundle(data, bundle); - - if(conn_candidate) { - /* Set the connection's owner correctly, then kill it */ - conn_candidate->data = data; - (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); - } - else { - infof(data, "No more connections allowed to host: %d\n", - max_host_connections); - connections_available = FALSE; - } - } - - if(connections_available && - (max_total_connections > 0) && - (data->state.conn_cache->num_connections >= max_total_connections)) { - struct connectdata *conn_candidate; - - /* The cache is full. Let's see if we can kill a connection. */ - conn_candidate = Curl_oldest_idle_connection(data); - - if(conn_candidate) { - /* Set the connection's owner correctly, then kill it */ - conn_candidate->data = data; - (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); - } - else { - infof(data, "No connections available in cache\n"); - connections_available = FALSE; - } - } - - if(!connections_available) { - infof(data, "No connections available.\n"); - - conn_free(conn); - *in_connect = NULL; - - result = CURLE_NO_CONNECTION_AVAILABLE; - goto out; - } - else { - /* - * This is a brand new connection, so let's store it in the connection - * cache of ours! - */ - Curl_conncache_add_conn(data->state.conn_cache, conn); - } - -#if defined(USE_NTLM) - /* If NTLM is requested in a part of this connection, make sure we don't - assume the state is fine as this is a fresh connection and NTLM is - connection based. */ - if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && - data->state.authhost.done) { - infof(data, "NTLM picked AND auth done set, clear picked!\n"); - data->state.authhost.picked = CURLAUTH_NONE; - data->state.authhost.done = FALSE; - } - - if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && - data->state.authproxy.done) { - infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n"); - data->state.authproxy.picked = CURLAUTH_NONE; - data->state.authproxy.done = FALSE; - } -#endif - } - - /* Mark the connection as used */ - conn->inuse = TRUE; - - /* Setup and init stuff before DO starts, in preparing for the transfer. */ - Curl_init_do(data, conn); - - /* - * Setup whatever necessary for a resumed transfer - */ - result = setup_range(data); - if(result) - goto out; - - /* Continue connectdata initialization here. */ - - /* - * Inherit the proper values from the urldata struct AFTER we have arranged - * the persistent connection stuff - */ - conn->seek_func = data->set.seek_func; - conn->seek_client = data->set.seek_client; - - /************************************************************* - * Resolve the address of the server or proxy - *************************************************************/ - result = resolve_server(data, conn, async); - -out: - - free(options); - free(passwd); - free(user); - return result; -} - -/* Curl_setup_conn() is called after the name resolve initiated in - * create_conn() is all done. - * - * Curl_setup_conn() also handles reused connections - * - * conn->data MUST already have been setup fine (in create_conn) - */ - -CURLcode Curl_setup_conn(struct connectdata *conn, - bool *protocol_done) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - Curl_pgrsTime(data, TIMER_NAMELOOKUP); - - if(conn->handler->flags & PROTOPT_NONETWORK) { - /* nothing to setup when not using a network */ - *protocol_done = TRUE; - return result; - } - *protocol_done = FALSE; /* default to not done */ - - /* set proxy_connect_closed to false unconditionally already here since it - is used strictly to provide extra information to a parent function in the - case of proxy CONNECT failures and we must make sure we don't have it - lingering set from a previous invoke */ - conn->bits.proxy_connect_closed = FALSE; - - /* - * Set user-agent. Used for HTTP, but since we can attempt to tunnel - * basically anything through a http proxy we can't limit this based on - * protocol. - */ - if(data->set.str[STRING_USERAGENT]) { - Curl_safefree(conn->allocptr.uagent); - conn->allocptr.uagent = - aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]); - if(!conn->allocptr.uagent) - return CURLE_OUT_OF_MEMORY; - } - - data->req.headerbytecount = 0; - -#ifdef CURL_DO_LINEEND_CONV - data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ -#endif /* CURL_DO_LINEEND_CONV */ - - /* set start time here for timeout purposes in the connect procedure, it - is later set again for the progress meter purpose */ - conn->now = Curl_tvnow(); - - if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) { - conn->bits.tcpconnect[FIRSTSOCKET] = FALSE; - result = Curl_connecthost(conn, conn->dns_entry); - if(result) - return result; - } - else { - Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ - Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */ - conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; - *protocol_done = TRUE; - Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]); - Curl_verboseconnect(conn); - } - - conn->now = Curl_tvnow(); /* time this *after* the connect is done, we - set this here perhaps a second time */ - -#ifdef __EMX__ - /* - * This check is quite a hack. We're calling _fsetmode to fix the problem - * with fwrite converting newline characters (you get mangled text files, - * and corrupted binary files when you download to stdout and redirect it to - * a file). - */ - - if((data->set.out)->_handle == NULL) { - _fsetmode(stdout, "b"); - } -#endif - - return result; -} - -CURLcode Curl_connect(struct Curl_easy *data, - struct connectdata **in_connect, - bool *asyncp, - bool *protocol_done) -{ - CURLcode result; - - *asyncp = FALSE; /* assume synchronous resolves by default */ - - /* call the stuff that needs to be called */ - result = create_conn(data, in_connect, asyncp); - - if(!result) { - /* no error */ - if((*in_connect)->send_pipe.size || (*in_connect)->recv_pipe.size) - /* pipelining */ - *protocol_done = TRUE; - else if(!*asyncp) { - /* DNS resolution is done: that's either because this is a reused - connection, in which case DNS was unnecessary, or because DNS - really did finish already (synch resolver/fast async resolve) */ - result = Curl_setup_conn(*in_connect, protocol_done); - } - } - - if(result == CURLE_NO_CONNECTION_AVAILABLE) { - *in_connect = NULL; - return result; - } - - if(result && *in_connect) { - /* We're not allowed to return failure with memory left allocated - in the connectdata struct, free those here */ - Curl_disconnect(*in_connect, FALSE); /* close the connection */ - *in_connect = NULL; /* return a NULL */ - } - - return result; -} - -/* - * Curl_init_do() inits the readwrite session. This is inited each time (in - * the DO function before the protocol-specific DO functions are invoked) for - * a transfer, sometimes multiple times on the same Curl_easy. Make sure - * nothing in here depends on stuff that are setup dynamically for the - * transfer. - * - * Allow this function to get called with 'conn' set to NULL. - */ - -CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) -{ - struct SingleRequest *k = &data->req; - - if(conn) - conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to - * use */ - - data->state.done = FALSE; /* *_done() is not called yet */ - data->state.expect100header = FALSE; - - if(data->set.opt_no_body) - /* in HTTP lingo, no body means using the HEAD request... */ - data->set.httpreq = HTTPREQ_HEAD; - else if(HTTPREQ_HEAD == data->set.httpreq) - /* ... but if unset there really is no perfect method that is the - "opposite" of HEAD but in reality most people probably think GET - then. The important thing is that we can't let it remain HEAD if the - opt_no_body is set FALSE since then we'll behave wrong when getting - HTTP. */ - data->set.httpreq = HTTPREQ_GET; - - k->start = Curl_tvnow(); /* start time */ - k->now = k->start; /* current time is now */ - k->header = TRUE; /* assume header */ - - k->bytecount = 0; - - k->buf = data->state.buffer; - k->hbufp = data->state.headerbuff; - k->ignorebody = FALSE; - - Curl_speedinit(data); - - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - - return CURLE_OK; -} - -/* -* get_protocol_family() -* -* This is used to return the protocol family for a given protocol. -* -* Parameters: -* -* protocol [in] - A single bit protocol identifier such as HTTP or HTTPS. -* -* Returns the family as a single bit protocol identifier. -*/ - -static unsigned int get_protocol_family(unsigned int protocol) -{ - unsigned int family; - - switch(protocol) { - case CURLPROTO_HTTP: - case CURLPROTO_HTTPS: - family = CURLPROTO_HTTP; - break; - - case CURLPROTO_FTP: - case CURLPROTO_FTPS: - family = CURLPROTO_FTP; - break; - - case CURLPROTO_SCP: - family = CURLPROTO_SCP; - break; - - case CURLPROTO_SFTP: - family = CURLPROTO_SFTP; - break; - - case CURLPROTO_TELNET: - family = CURLPROTO_TELNET; - break; - - case CURLPROTO_LDAP: - case CURLPROTO_LDAPS: - family = CURLPROTO_LDAP; - break; - - case CURLPROTO_DICT: - family = CURLPROTO_DICT; - break; - - case CURLPROTO_FILE: - family = CURLPROTO_FILE; - break; - - case CURLPROTO_TFTP: - family = CURLPROTO_TFTP; - break; - - case CURLPROTO_IMAP: - case CURLPROTO_IMAPS: - family = CURLPROTO_IMAP; - break; - - case CURLPROTO_POP3: - case CURLPROTO_POP3S: - family = CURLPROTO_POP3; - break; - - case CURLPROTO_SMTP: - case CURLPROTO_SMTPS: - family = CURLPROTO_SMTP; - break; - - case CURLPROTO_RTSP: - family = CURLPROTO_RTSP; - break; - - case CURLPROTO_RTMP: - case CURLPROTO_RTMPS: - family = CURLPROTO_RTMP; - break; - - case CURLPROTO_RTMPT: - case CURLPROTO_RTMPTS: - family = CURLPROTO_RTMPT; - break; - - case CURLPROTO_RTMPE: - family = CURLPROTO_RTMPE; - break; - - case CURLPROTO_RTMPTE: - family = CURLPROTO_RTMPTE; - break; - - case CURLPROTO_GOPHER: - family = CURLPROTO_GOPHER; - break; - - case CURLPROTO_SMB: - case CURLPROTO_SMBS: - family = CURLPROTO_SMB; - break; - - default: - family = 0; - break; - } - - return family; -} diff --git a/dep/cpr/opt/curl/lib/url.h b/dep/cpr/opt/curl/lib/url.h deleted file mode 100644 index f13c8e66403..00000000000 --- a/dep/cpr/opt/curl/lib/url.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef HEADER_CURL_URL_H -#define HEADER_CURL_URL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -/* - * Prototypes for library-wide functions provided by url.c - */ - -CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn); -CURLcode Curl_open(struct Curl_easy **curl); -CURLcode Curl_init_userdefined(struct UserDefined *set); -CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, - va_list arg); -CURLcode Curl_dupset(struct Curl_easy * dst, struct Curl_easy * src); -void Curl_freeset(struct Curl_easy * data); -CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */ -CURLcode Curl_connect(struct Curl_easy *, struct connectdata **, - bool *async, bool *protocol_connect); -CURLcode Curl_disconnect(struct connectdata *, bool dead_connection); -CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); -CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); -CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); -CURLcode Curl_setup_conn(struct connectdata *conn, - bool *protocol_done); -void Curl_free_request_state(struct Curl_easy *data); - -int Curl_protocol_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); -int Curl_doing_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - -bool Curl_isPipeliningEnabled(const struct Curl_easy *handle); -CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle, - struct curl_llist *pipeline); -int Curl_removeHandleFromPipeline(struct Curl_easy *handle, - struct curl_llist *pipeline); -struct connectdata * -Curl_oldest_idle_connection(struct Curl_easy *data); -/* remove the specified connection from all (possible) pipelines and related - queues */ -void Curl_getoff_all_pipelines(struct Curl_easy *data, - struct connectdata *conn); - -void Curl_close_connections(struct Curl_easy *data); - -#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ -#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless - specified */ - -CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex); - -#ifdef CURL_DISABLE_VERBOSE_STRINGS -#define Curl_verboseconnect(x) Curl_nop_stmt -#else -void Curl_verboseconnect(struct connectdata *conn); -#endif - -#define CONNECT_PROXY_SSL()\ - (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ - !conn->bits.proxy_ssl_connected[sockindex]) - -#define CONNECT_FIRSTSOCKET_PROXY_SSL()\ - (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ - !conn->bits.proxy_ssl_connected[FIRSTSOCKET]) - -#define CONNECT_SECONDARYSOCKET_PROXY_SSL()\ - (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ - !conn->bits.proxy_ssl_connected[SECONDARYSOCKET]) - -#endif /* HEADER_CURL_URL_H */ diff --git a/dep/cpr/opt/curl/lib/urldata.h b/dep/cpr/opt/curl/lib/urldata.h deleted file mode 100644 index 66e4596fdc7..00000000000 --- a/dep/cpr/opt/curl/lib/urldata.h +++ /dev/null @@ -1,1785 +0,0 @@ -#ifndef HEADER_CURL_URLDATA_H -#define HEADER_CURL_URLDATA_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* This file is for lib internal stuff */ - -#include "curl_setup.h" - -#define PORT_FTP 21 -#define PORT_FTPS 990 -#define PORT_TELNET 23 -#define PORT_HTTP 80 -#define PORT_HTTPS 443 -#define PORT_DICT 2628 -#define PORT_LDAP 389 -#define PORT_LDAPS 636 -#define PORT_TFTP 69 -#define PORT_SSH 22 -#define PORT_IMAP 143 -#define PORT_IMAPS 993 -#define PORT_POP3 110 -#define PORT_POP3S 995 -#define PORT_SMB 445 -#define PORT_SMBS 445 -#define PORT_SMTP 25 -#define PORT_SMTPS 465 /* sometimes called SSMTP */ -#define PORT_RTSP 554 -#define PORT_RTMP 1935 -#define PORT_RTMPT PORT_HTTP -#define PORT_RTMPS PORT_HTTPS -#define PORT_GOPHER 70 - -#define DICT_MATCH "/MATCH:" -#define DICT_MATCH2 "/M:" -#define DICT_MATCH3 "/FIND:" -#define DICT_DEFINE "/DEFINE:" -#define DICT_DEFINE2 "/D:" -#define DICT_DEFINE3 "/LOOKUP:" - -#define CURL_DEFAULT_USER "anonymous" -#define CURL_DEFAULT_PASSWORD "ftp@example.com" - -/* Convenience defines for checking protocols or their SSL based version. Each - protocol handler should only ever have a single CURLPROTO_ in its protocol - field. */ -#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS) -#define PROTO_FAMILY_FTP (CURLPROTO_FTP|CURLPROTO_FTPS) -#define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S) -#define PROTO_FAMILY_SMB (CURLPROTO_SMB|CURLPROTO_SMBS) -#define PROTO_FAMILY_SMTP (CURLPROTO_SMTP|CURLPROTO_SMTPS) - -#define DEFAULT_CONNCACHE_SIZE 5 - -/* length of longest IPv6 address string including the trailing null */ -#define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - -/* Default FTP/IMAP etc response timeout in milliseconds. - Symbian OS panics when given a timeout much greater than 1/2 hour. -*/ -#define RESP_TIMEOUT (1800*1000) - -#include "cookie.h" -#include "formdata.h" - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include "timeval.h" - -#ifdef HAVE_ZLIB_H -#include /* for content-encoding */ -#ifdef __SYMBIAN32__ -/* zlib pollutes the namespace with this definition */ -#undef WIN32 -#endif -#endif - -#include - -#include "http_chunks.h" /* for the structs and enum stuff */ -#include "hostip.h" -#include "hash.h" -#include "splay.h" - -#include "mime.h" -#include "imap.h" -#include "pop3.h" -#include "smtp.h" -#include "ftp.h" -#include "file.h" -#include "ssh.h" -#include "http.h" -#include "rtsp.h" -#include "smb.h" -#include "wildcard.h" -#include "multihandle.h" - -#ifdef HAVE_GSSAPI -# ifdef HAVE_GSSGNU -# include -# elif defined HAVE_GSSMIT -# include -# include -# else -# include -# endif -#endif - -#ifdef HAVE_LIBSSH2_H -#include -#include -#endif /* HAVE_LIBSSH2_H */ - -/* The upload buffer size, should not be smaller than CURL_MAX_WRITE_SIZE, as - it needs to hold a full buffer as could be sent in a write callback */ -#define UPLOAD_BUFSIZE CURL_MAX_WRITE_SIZE - -/* The "master buffer" is for HTTP pipelining */ -#define MASTERBUF_SIZE 16384 - -/* Initial size of the buffer to store headers in, it'll be enlarged in case - of need. */ -#define HEADERSIZE 256 - -#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU -#define GOOD_EASY_HANDLE(x) \ - ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) - -/* Some convenience macros to get the larger/smaller value out of two given. - We prefix with CURL to prevent name collisions. */ -#define CURLMAX(x,y) ((x)>(y)?(x):(y)) -#define CURLMIN(x,y) ((x)<(y)?(x):(y)) - -#ifdef HAVE_GSSAPI -/* Types needed for krb5-ftp connections */ -struct krb5buffer { - void *data; - size_t size; - size_t index; - int eof_flag; -}; - -enum protection_level { - PROT_NONE, /* first in list */ - PROT_CLEAR, - PROT_SAFE, - PROT_CONFIDENTIAL, - PROT_PRIVATE, - PROT_CMD, - PROT_LAST /* last in list */ -}; -#endif - -/* enum for the nonblocking SSL connection state machine */ -typedef enum { - ssl_connect_1, - ssl_connect_2, - ssl_connect_2_reading, - ssl_connect_2_writing, - ssl_connect_3, - ssl_connect_done -} ssl_connect_state; - -typedef enum { - ssl_connection_none, - ssl_connection_negotiating, - ssl_connection_complete -} ssl_connection_state; - -/* SSL backend-specific data; declared differently by each SSL backend */ -struct ssl_backend_data; - -/* struct for data related to each SSL connection */ -struct ssl_connect_data { - /* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm - but at least asked to or meaning to use it. See 'state' for the exact - current state of the connection. */ - bool use; - ssl_connection_state state; - ssl_connect_state connecting_state; -#if defined(USE_SSL) - struct ssl_backend_data *backend; -#endif -}; - -struct ssl_primary_config { - long version; /* what version the client wants to use */ - long version_max; /* max supported version the client wants to use*/ - bool verifypeer; /* set TRUE if this is desired */ - bool verifyhost; /* set TRUE if CN/SAN must match hostname */ - bool verifystatus; /* set TRUE if certificate status must be checked */ - bool sessionid; /* cache session IDs or not */ - char *CApath; /* certificate dir (doesn't work on windows) */ - char *CAfile; /* certificate to verify peer against */ - char *clientcert; - char *random_file; /* path to file containing "random" data */ - char *egdsocket; /* path to file containing the EGD daemon socket */ - char *cipher_list; /* list of ciphers to use */ -}; - -struct ssl_config_data { - struct ssl_primary_config primary; - bool enable_beast; /* especially allow this flaw for interoperability's - sake*/ - bool no_revoke; /* disable SSL certificate revocation checks */ - long certverifyresult; /* result from the certificate verification */ - char *CRLfile; /* CRL to check certificate revocation */ - char *issuercert;/* optional issuer certificate filename */ - curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ - void *fsslctxp; /* parameter for call back */ - bool certinfo; /* gather lots of certificate info */ - bool falsestart; - - char *cert; /* client certificate file name */ - char *cert_type; /* format for certificate (default: PEM)*/ - char *key; /* private key file name */ - char *key_type; /* format for private key (default: PEM) */ - char *key_passwd; /* plain text private key password */ - -#ifdef USE_TLS_SRP - char *username; /* TLS username (for, e.g., SRP) */ - char *password; /* TLS password (for, e.g., SRP) */ - enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ -#endif -}; - -struct ssl_general_config { - size_t max_ssl_sessions; /* SSL session id cache size */ -}; - -/* information stored about one single SSL session */ -struct curl_ssl_session { - char *name; /* host name for which this ID was used */ - char *conn_to_host; /* host name for the connection (may be NULL) */ - const char *scheme; /* protocol scheme used */ - void *sessionid; /* as returned from the SSL layer */ - size_t idsize; /* if known, otherwise 0 */ - long age; /* just a number, the higher the more recent */ - int remote_port; /* remote port */ - int conn_to_port; /* remote port for the connection (may be -1) */ - struct ssl_primary_config ssl_config; /* setup for this session */ -}; - -#ifdef USE_WINDOWS_SSPI -#include "curl_sspi.h" -#endif - -/* Struct used for Digest challenge-response authentication */ -struct digestdata { -#if defined(USE_WINDOWS_SSPI) - BYTE *input_token; - size_t input_token_len; - CtxtHandle *http_context; - /* copy of user/passwd used to make the identity for http_context. - either may be NULL. */ - char *user; - char *passwd; -#else - char *nonce; - char *cnonce; - char *realm; - int algo; - bool stale; /* set true for re-negotiation */ - char *opaque; - char *qop; - char *algorithm; - int nc; /* nounce count */ -#endif -}; - -typedef enum { - NTLMSTATE_NONE, - NTLMSTATE_TYPE1, - NTLMSTATE_TYPE2, - NTLMSTATE_TYPE3, - NTLMSTATE_LAST -} curlntlm; - -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) -#include -#endif - -/* Struct used for GSSAPI (Kerberos V5) authentication */ -#if defined(USE_KERBEROS5) -struct kerberos5data { -#if defined(USE_WINDOWS_SSPI) - CredHandle *credentials; - CtxtHandle *context; - TCHAR *spn; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - size_t token_max; - BYTE *output_token; -#else - gss_ctx_id_t context; - gss_name_t spn; -#endif -}; -#endif - -/* Struct used for NTLM challenge-response authentication */ -#if defined(USE_NTLM) -struct ntlmdata { - curlntlm state; -#ifdef USE_WINDOWS_SSPI - CredHandle *credentials; - CtxtHandle *context; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - size_t token_max; - BYTE *output_token; - BYTE *input_token; - size_t input_token_len; -#else - unsigned int flags; - unsigned char nonce[8]; - void *target_info; /* TargetInfo received in the ntlm type-2 message */ - unsigned int target_info_len; -#endif -}; -#endif - -#ifdef USE_SPNEGO -struct negotiatedata { - /* When doing Negotiate (SPNEGO) auth, we first need to send a token - and then validate the received one. */ - enum { GSS_AUTHNONE, GSS_AUTHRECV, GSS_AUTHSENT } state; -#ifdef HAVE_GSSAPI - OM_uint32 status; - gss_ctx_id_t context; - gss_name_t spn; - gss_buffer_desc output_token; -#else -#ifdef USE_WINDOWS_SSPI - DWORD status; - CredHandle *credentials; - CtxtHandle *context; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - TCHAR *spn; - size_t token_max; - BYTE *output_token; - size_t output_token_length; -#endif -#endif -}; -#endif - - -/* - * Boolean values that concerns this connection. - */ -struct ConnectBits { - /* always modify bits.close with the connclose() and connkeep() macros! */ - bool close; /* if set, we close the connection after this request */ - bool reuse; /* if set, this is a re-used connection */ - bool conn_to_host; /* if set, this connection has a "connect to host" - that overrides the host in the URL */ - bool conn_to_port; /* if set, this connection has a "connect to port" - that overrides the port in the URL (remote port) */ - bool proxy; /* if set, this transfer is done through a proxy - any type */ - bool httpproxy; /* if set, this transfer is done through a http proxy */ - bool socksproxy; /* if set, this transfer is done through a socks proxy */ - bool user_passwd; /* do we use user+password for this connection? */ - bool proxy_user_passwd; /* user+password for the proxy? */ - bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6 - IP address */ - bool ipv6; /* we communicate with a site using an IPv6 address */ - - bool do_more; /* this is set TRUE if the ->curl_do_more() function is - supposed to be called, after ->curl_do() */ - bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set - the first time on the first connect function call */ - bool protoconnstart;/* the protocol layer has STARTED its operation after - the TCP layer connect */ - - bool retry; /* this connection is about to get closed and then - re-attempted at another connection. */ - bool tunnel_proxy; /* if CONNECT is used to "tunnel" through the proxy. - This is implicit when SSL-protocols are used through - proxies, but can also be enabled explicitly by - apps */ - bool authneg; /* TRUE when the auth phase has started, which means - that we are creating a request with an auth header, - but it is not the final request in the auth - negotiation. */ - bool rewindaftersend;/* TRUE when the sending couldn't be stopped even - though it will be discarded. When the whole send - operation is done, we must call the data rewind - callback. */ - bool ftp_use_epsv; /* As set with CURLOPT_FTP_USE_EPSV, but if we find out - EPSV doesn't work we disable it for the forthcoming - requests */ - - bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out - EPRT doesn't work we disable it for the forthcoming - requests */ - bool ftp_use_data_ssl; /* Enabled SSL for the data connection */ - bool netrc; /* name+password provided by netrc */ - bool userpwd_in_url; /* name+password found in url */ - bool stream_was_rewound; /* Indicates that the stream was rewound after a - request read past the end of its response byte - boundary */ - bool proxy_connect_closed; /* set true if a proxy disconnected the - connection in a CONNECT request with auth, so - that libcurl should reconnect and continue. */ - bool bound; /* set true if bind() has already been done on this socket/ - connection */ - bool type_set; /* type= was used in the URL */ - bool multiplex; /* connection is multiplexed */ - - bool tcp_fastopen; /* use TCP Fast Open */ - bool tls_enable_npn; /* TLS NPN extension? */ - bool tls_enable_alpn; /* TLS ALPN extension? */ - bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy - is complete */ - bool socksproxy_connecting; /* connecting through a socks proxy */ -}; - -struct hostname { - char *rawalloc; /* allocated "raw" version of the name */ - char *encalloc; /* allocated IDN-encoded version of the name */ - char *name; /* name to use internally, might be encoded, might be raw */ - const char *dispname; /* name to display, as 'name' might be encoded */ -}; - -/* - * Flags on the keepon member of the Curl_transfer_keeper - */ - -#define KEEP_NONE 0 -#define KEEP_RECV (1<<0) /* there is or may be data to read */ -#define KEEP_SEND (1<<1) /* there is or may be data to write */ -#define KEEP_RECV_HOLD (1<<2) /* when set, no reading should be done but there - might still be data to read */ -#define KEEP_SEND_HOLD (1<<3) /* when set, no writing should be done but there - might still be data to write */ -#define KEEP_RECV_PAUSE (1<<4) /* reading is paused */ -#define KEEP_SEND_PAUSE (1<<5) /* writing is paused */ - -#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE) -#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE) - - -#ifdef HAVE_LIBZ -typedef enum { - ZLIB_UNINIT, /* uninitialized */ - ZLIB_INIT, /* initialized */ - ZLIB_GZIP_HEADER, /* reading gzip header */ - ZLIB_GZIP_INFLATING, /* inflating gzip stream */ - ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ -} zlibInitState; -#endif - -#ifdef CURLRES_ASYNCH -struct Curl_async { - char *hostname; - int port; - struct Curl_dns_entry *dns; - bool done; /* set TRUE when the lookup is complete */ - int status; /* if done is TRUE, this is the status from the callback */ - void *os_specific; /* 'struct thread_data' for Windows */ -}; -#endif - -#define FIRSTSOCKET 0 -#define SECONDARYSOCKET 1 - -/* These function pointer types are here only to allow easier typecasting - within the source when we need to cast between data pointers (such as NULL) - and function pointers. */ -typedef CURLcode (*Curl_do_more_func)(struct connectdata *, int *); -typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool); - -enum expect100 { - EXP100_SEND_DATA, /* enough waiting, just send the body now */ - EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */ - EXP100_SENDING_REQUEST, /* still sending the request but will wait for - the 100 header once done with the request */ - EXP100_FAILED /* used on 417 Expectation Failed */ -}; - -enum upgrade101 { - UPGR101_INIT, /* default state */ - UPGR101_REQUESTED, /* upgrade requested */ - UPGR101_RECEIVED, /* response received */ - UPGR101_WORKING /* talking upgraded protocol */ -}; - -/* - * Request specific data in the easy handle (Curl_easy). Previously, - * these members were on the connectdata struct but since a conn struct may - * now be shared between different Curl_easys, we store connection-specific - * data here. This struct only keeps stuff that's interesting for *this* - * request, as it will be cleared between multiple ones - */ -struct SingleRequest { - curl_off_t size; /* -1 if unknown at this point */ - curl_off_t *bytecountp; /* return number of bytes read or NULL */ - - curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, - -1 means unlimited */ - curl_off_t *writebytecountp; /* return number of bytes written or NULL */ - - curl_off_t bytecount; /* total number of bytes read */ - curl_off_t writebytecount; /* number of bytes written */ - - long headerbytecount; /* only count received headers */ - long deductheadercount; /* this amount of bytes doesn't count when we check - if anything has been transferred at the end of a - connection. We use this counter to make only a - 100 reply (without a following second response - code) result in a CURLE_GOT_NOTHING error code */ - - struct curltime start; /* transfer started at this time */ - struct curltime now; /* current time */ - bool header; /* incoming data has HTTP header */ - enum { - HEADER_NORMAL, /* no bad header at all */ - HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest - is normal data */ - HEADER_ALLBAD /* all was believed to be header */ - } badheader; /* the header was deemed bad and will be - written as body */ - int headerline; /* counts header lines to better track the - first one */ - char *hbufp; /* points at *end* of header line */ - size_t hbuflen; - char *str; /* within buf */ - char *str_start; /* within buf */ - char *end_ptr; /* within buf */ - char *p; /* within headerbuff */ - bool content_range; /* set TRUE if Content-Range: was found */ - curl_off_t offset; /* possible resume offset read from the - Content-Range: header */ - int httpcode; /* error code from the 'HTTP/1.? XXX' or - 'RTSP/1.? XXX' line */ - struct curltime start100; /* time stamp to wait for the 100 code from */ - enum expect100 exp100; /* expect 100 continue state */ - enum upgrade101 upgr101; /* 101 upgrade state */ - - int auto_decoding; /* What content encoding. sec 3.5, RFC2616. */ - -#define IDENTITY 0 /* No encoding */ -#define DEFLATE 1 /* zlib deflate [RFC 1950 & 1951] */ -#define GZIP 2 /* gzip algorithm [RFC 1952] */ - -#ifdef HAVE_LIBZ - zlibInitState zlib_init; /* possible zlib init state; - undefined if Content-Encoding header. */ - z_stream z; /* State structure for zlib. */ -#endif - - time_t timeofdoc; - long bodywrites; - - char *buf; - curl_socket_t maxfd; - - int keepon; - - bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload - and we're uploading the last chunk */ - - bool ignorebody; /* we read a response-body but we ignore it! */ - bool ignorecl; /* This HTTP response has no body so we ignore the Content- - Length: header */ - - char *location; /* This points to an allocated version of the Location: - header data */ - char *newurl; /* Set to the new URL to use when a redirect or a retry is - wanted */ - - /* 'upload_present' is used to keep a byte counter of how much data there is - still left in the buffer, aimed for upload. */ - ssize_t upload_present; - - /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a - buffer, so the next read should read from where this pointer points to, - and the 'upload_present' contains the number of bytes available at this - position */ - char *upload_fromhere; - - bool chunk; /* if set, this is a chunked transfer-encoding */ - bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding - on upload */ - bool getheader; /* TRUE if header parsing is wanted */ - - bool forbidchunk; /* used only to explicitly forbid chunk-upload for - specific upload buffers. See readmoredata() in - http.c for details. */ - - void *protop; /* Allocated protocol-specific data. Each protocol - handler makes sure this points to data it needs. */ -}; - -/* - * Specific protocol handler. - */ - -struct Curl_handler { - const char *scheme; /* URL scheme name. */ - - /* Complement to setup_connection_internals(). */ - CURLcode (*setup_connection)(struct connectdata *); - - /* These two functions MUST be set to be protocol dependent */ - CURLcode (*do_it)(struct connectdata *, bool *done); - Curl_done_func done; - - /* If the curl_do() function is better made in two halves, this - * curl_do_more() function will be called afterwards, if set. For example - * for doing the FTP stuff after the PASV/PORT command. - */ - Curl_do_more_func do_more; - - /* This function *MAY* be set to a protocol-dependent function that is run - * after the connect() and everything is done, as a step in the connection. - * The 'done' pointer points to a bool that should be set to TRUE if the - * function completes before return. If it doesn't complete, the caller - * should call the curl_connecting() function until it is. - */ - CURLcode (*connect_it)(struct connectdata *, bool *done); - - /* See above. Currently only used for FTP. */ - CURLcode (*connecting)(struct connectdata *, bool *done); - CURLcode (*doing)(struct connectdata *, bool *done); - - /* Called from the multi interface during the PROTOCONNECT phase, and it - should then return a proper fd set */ - int (*proto_getsock)(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - - /* Called from the multi interface during the DOING phase, and it should - then return a proper fd set */ - int (*doing_getsock)(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - - /* Called from the multi interface during the DO_MORE phase, and it should - then return a proper fd set */ - int (*domore_getsock)(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - - /* Called from the multi interface during the DO_DONE, PERFORM and - WAITPERFORM phases, and it should then return a proper fd set. Not setting - this will make libcurl use the generic default one. */ - int (*perform_getsock)(const struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - - /* This function *MAY* be set to a protocol-dependent function that is run - * by the curl_disconnect(), as a step in the disconnection. If the handler - * is called because the connection has been considered dead, dead_connection - * is set to TRUE. - */ - CURLcode (*disconnect)(struct connectdata *, bool dead_connection); - - /* If used, this function gets called from transfer.c:readwrite_data() to - allow the protocol to do extra reads/writes */ - CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, - ssize_t *nread, bool *readmore); - - /* This function can perform various checks on the connection. See - CONNCHECK_* for more information about the checks that can be performed, - and CONNRESULT_* for the results that can be returned. */ - unsigned int (*connection_check)(struct connectdata *conn, - unsigned int checks_to_perform); - - long defport; /* Default port. */ - unsigned int protocol; /* See CURLPROTO_* - this needs to be the single - specific protocol bit */ - unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */ -}; - -#define PROTOPT_NONE 0 /* nothing extra */ -#define PROTOPT_SSL (1<<0) /* uses SSL */ -#define PROTOPT_DUAL (1<<1) /* this protocol uses two connections */ -#define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */ -/* some protocols will have to call the underlying functions without regard to - what exact state the socket signals. IE even if the socket says "readable", - the send function might need to be called while uploading, or vice versa. -*/ -#define PROTOPT_DIRLOCK (1<<3) -#define PROTOPT_NONETWORK (1<<4) /* protocol doesn't use the network! */ -#define PROTOPT_NEEDSPWD (1<<5) /* needs a password, and if none is set it - gets a default */ -#define PROTOPT_NOURLQUERY (1<<6) /* protocol can't handle - url query strings (?foo=bar) ! */ -#define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per - request instead of per connection */ -#define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ -#define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ -#define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field - of the URL */ -#define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a - HTTP proxy as HTTP proxies may know - this protocol and act as a gateway */ - -#define CONNCHECK_NONE 0 /* No checks */ -#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */ - -#define CONNRESULT_NONE 0 /* No extra information. */ -#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */ - -/* return the count of bytes sent, or -1 on error */ -typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ - int sockindex, /* socketindex */ - const void *buf, /* data to write */ - size_t len, /* max amount to write */ - CURLcode *err); /* error to return */ - -/* return the count of bytes read, or -1 on error */ -typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */ - int sockindex, /* socketindex */ - char *buf, /* store data here */ - size_t len, /* max amount to read */ - CURLcode *err); /* error to return */ - -#ifdef USE_RECV_BEFORE_SEND_WORKAROUND -struct postponed_data { - char *buffer; /* Temporal store for received data during - sending, must be freed */ - size_t allocated_size; /* Size of temporal store */ - size_t recv_size; /* Size of received data during sending */ - size_t recv_processed; /* Size of processed part of postponed data */ -#ifdef DEBUGBUILD - curl_socket_t bindsock;/* Structure must be bound to specific socket, - used only for DEBUGASSERT */ -#endif /* DEBUGBUILD */ -}; -#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ - -struct proxy_info { - struct hostname host; - long port; - curl_proxytype proxytype; /* what kind of proxy that is in use */ - char *user; /* proxy user name string, allocated */ - char *passwd; /* proxy password string, allocated */ -}; - -#define CONNECT_BUFFER_SIZE 16384 - -/* struct for HTTP CONNECT state data */ -struct http_connect_state { - char connect_buffer[CONNECT_BUFFER_SIZE]; - int perline; /* count bytes per line */ - int keepon; - char *line_start; - char *ptr; /* where to store more data */ - curl_off_t cl; /* size of content to read and ignore */ - bool chunked_encoding; - enum { - TUNNEL_INIT, /* init/default/no tunnel state */ - TUNNEL_CONNECT, /* CONNECT has been sent off */ - TUNNEL_COMPLETE /* CONNECT response received completely */ - } tunnel_state; -}; - -/* - * The connectdata struct contains all fields and variables that should be - * unique for an entire connection. - */ -struct connectdata { - /* 'data' is the CURRENT Curl_easy using this connection -- take great - caution that this might very well vary between different times this - connection is used! */ - struct Curl_easy *data; - - struct curl_llist_element bundle_node; /* conncache */ - - /* chunk is for HTTP chunked encoding, but is in the general connectdata - struct only because we can do just about any protocol through a HTTP proxy - and a HTTP proxy may in fact respond using chunked encoding */ - struct Curl_chunker chunk; - - curl_closesocket_callback fclosesocket; /* function closing the socket(s) */ - void *closesocket_client; - - bool inuse; /* This is a marker for the connection cache logic. If this is - TRUE this handle is being used by an easy handle and cannot - be used by any other easy handle without careful - consideration (== only for pipelining). */ - - /**** Fields set when inited and not modified again */ - long connection_id; /* Contains a unique number to make it easier to - track the connections in the log output */ - - /* 'dns_entry' is the particular host we use. This points to an entry in the - DNS cache and it will not get pruned while locked. It gets unlocked in - Curl_done(). This entry will be NULL if the connection is re-used as then - there is no name resolve done. */ - struct Curl_dns_entry *dns_entry; - - /* 'ip_addr' is the particular IP we connected to. It points to a struct - within the DNS cache, so this pointer is only valid as long as the DNS - cache entry remains locked. It gets unlocked in Curl_done() */ - Curl_addrinfo *ip_addr; - Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */ - - /* 'ip_addr_str' is the ip_addr data as a human readable string. - It remains available as long as the connection does, which is longer than - the ip_addr itself. */ - char ip_addr_str[MAX_IPADR_LEN]; - - unsigned int scope_id; /* Scope id for IPv6 */ - - int socktype; /* SOCK_STREAM or SOCK_DGRAM */ - - struct hostname host; - char *secondaryhostname; /* secondary socket host name (ftp) */ - struct hostname conn_to_host; /* the host to connect to. valid only if - bits.conn_to_host is set */ - - struct proxy_info socks_proxy; - struct proxy_info http_proxy; - - long port; /* which port to use locally */ - int remote_port; /* the remote port, not the proxy port! */ - int conn_to_port; /* the remote port to connect to. valid only if - bits.conn_to_port is set */ - unsigned short secondary_port; /* secondary socket remote port to connect to - (ftp) */ - - /* 'primary_ip' and 'primary_port' get filled with peer's numerical - ip address and port number whenever an outgoing connection is - *attempted* from the primary socket to a remote address. When more - than one address is tried for a connection these will hold data - for the last attempt. When the connection is actually established - these are updated with data which comes directly from the socket. */ - - char primary_ip[MAX_IPADR_LEN]; - long primary_port; - - /* 'local_ip' and 'local_port' get filled with local's numerical - ip address and port number whenever an outgoing connection is - **established** from the primary socket to a remote address. */ - - char local_ip[MAX_IPADR_LEN]; - long local_port; - - char *user; /* user name string, allocated */ - char *passwd; /* password string, allocated */ - char *options; /* options string, allocated */ - - char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */ - - int httpversion; /* the HTTP version*10 reported by the server */ - int rtspversion; /* the RTSP version*10 reported by the server */ - - struct curltime now; /* "current" time */ - struct curltime created; /* creation time */ - curl_socket_t sock[2]; /* two sockets, the second is used for the data - transfer when doing FTP */ - curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */ - bool sock_accepted[2]; /* TRUE if the socket on this index was created with - accept() */ - Curl_recv *recv[2]; - Curl_send *send[2]; - -#ifdef USE_RECV_BEFORE_SEND_WORKAROUND - struct postponed_data postponed[2]; /* two buffers for two sockets */ -#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ - struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ - struct ssl_connect_data proxy_ssl[2]; /* this is for proxy ssl-stuff */ - struct ssl_primary_config ssl_config; - struct ssl_primary_config proxy_ssl_config; - bool tls_upgraded; - - struct ConnectBits bits; /* various state-flags for this connection */ - - /* connecttime: when connect() is called on the current IP address. Used to - be able to track when to move on to try next IP - but only when the multi - interface is used. */ - struct curltime connecttime; - /* The two fields below get set in Curl_connecthost */ - int num_addr; /* number of addresses to try to connect to */ - time_t timeoutms_per_addr; /* how long time in milliseconds to spend on - trying to connect to each IP address */ - - const struct Curl_handler *handler; /* Connection's protocol handler */ - const struct Curl_handler *given; /* The protocol first given */ - - long ip_version; /* copied from the Curl_easy at creation time */ - - /**** curl_get() phase fields */ - - curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */ - curl_socket_t writesockfd; /* socket to write to, it may very - well be the same we read from. - CURL_SOCKET_BAD disables */ - - /** Dynamicly allocated strings, MUST be freed before this **/ - /** struct is killed. **/ - struct dynamically_allocated_data { - char *proxyuserpwd; - char *uagent; - char *accept_encoding; - char *userpwd; - char *rangeline; - char *ref; - char *host; - char *cookiehost; - char *rtsp_transport; - char *te; /* TE: request header */ - } allocptr; - -#ifdef HAVE_GSSAPI - int sec_complete; /* if Kerberos is enabled for this connection */ - enum protection_level command_prot; - enum protection_level data_prot; - enum protection_level request_data_prot; - size_t buffer_size; - struct krb5buffer in_buffer; - void *app_data; - const struct Curl_sec_client_mech *mech; - struct sockaddr_in local_addr; -#endif - -#if defined(USE_KERBEROS5) /* Consider moving some of the above GSS-API */ - struct kerberos5data krb5; /* variables into the structure definition, */ -#endif /* however, some of them are ftp specific. */ - - /* the two following *_inuse fields are only flags, not counters in any way. - If TRUE it means the channel is in use, and if FALSE it means the channel - is up for grabs by one. */ - - bool readchannel_inuse; /* whether the read channel is in use by an easy - handle */ - bool writechannel_inuse; /* whether the write channel is in use by an easy - handle */ - struct curl_llist send_pipe; /* List of handles waiting to send on this - pipeline */ - struct curl_llist recv_pipe; /* List of handles waiting to read their - responses on this pipeline */ - char *master_buffer; /* The master buffer allocated on-demand; - used for pipelining. */ - size_t read_pos; /* Current read position in the master buffer */ - size_t buf_len; /* Length of the buffer?? */ - - - curl_seek_callback seek_func; /* function that seeks the input */ - void *seek_client; /* pointer to pass to the seek() above */ - - /*************** Request - specific items ************/ - -#if defined(USE_NTLM) - struct ntlmdata ntlm; /* NTLM differs from other authentication schemes - because it authenticates connections, not - single requests! */ - struct ntlmdata proxyntlm; /* NTLM data for proxy */ - -#if defined(NTLM_WB_ENABLED) - /* used for communication with Samba's winbind daemon helper ntlm_auth */ - curl_socket_t ntlm_auth_hlpr_socket; - pid_t ntlm_auth_hlpr_pid; - char *challenge_header; - char *response_header; -#endif -#endif - - char syserr_buf [256]; /* buffer for Curl_strerror() */ - -#ifdef CURLRES_ASYNCH - /* data used for the asynch name resolve callback */ - struct Curl_async async; -#endif - - /* These three are used for chunked-encoding trailer support */ - char *trailer; /* allocated buffer to store trailer in */ - int trlMax; /* allocated buffer size */ - int trlPos; /* index of where to store data */ - - union { - struct ftp_conn ftpc; - struct http_conn httpc; - struct ssh_conn sshc; - struct tftp_state_data *tftpc; - struct imap_conn imapc; - struct pop3_conn pop3c; - struct smtp_conn smtpc; - struct rtsp_conn rtspc; - struct smb_conn smbc; - void *generic; /* RTMP and LDAP use this */ - } proto; - - int cselect_bits; /* bitmask of socket events */ - int waitfor; /* current READ/WRITE bits to wait for */ - -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - int socks5_gssapi_enctype; -#endif - - /* When this connection is created, store the conditions for the local end - bind. This is stored before the actual bind and before any connection is - made and will serve the purpose of being used for comparison reasons so - that subsequent bound-requested connections aren't accidentally re-using - wrong connections. */ - char *localdev; - unsigned short localport; - int localportrange; - struct http_connect_state *connect_state; /* for HTTP CONNECT */ - struct connectbundle *bundle; /* The bundle we are member of */ - int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */ - -#ifdef USE_UNIX_SOCKETS - char *unix_domain_socket; - bool abstract_unix_socket; -#endif - -#ifdef USE_SSL - /* - * To avoid multiple malloc() calls, the ssl_connect_data structures - * associated with a connectdata struct are allocated in the same block - * as the latter. This field forces alignment to an 8-byte boundary so - * that this all works. - */ - long long *align_data__do_not_use; -#endif -}; - -/* The end of connectdata. */ - -/* - * Struct to keep statistical and informational data. - * All variables in this struct must be initialized/reset in Curl_initinfo(). - */ -struct PureInfo { - int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */ - int httpproxycode; /* response code from proxy when received separate */ - int httpversion; /* the http version number X.Y = X*10+Y */ - long filetime; /* If requested, this is might get set. Set to -1 if the time - was unretrievable. We cannot have this of type time_t, - since time_t is unsigned on several platforms such as - OpenVMS. */ - bool timecond; /* set to TRUE if the time condition didn't match, which - thus made the document NOT get fetched */ - long header_size; /* size of read header(s) in bytes */ - long request_size; /* the amount of bytes sent in the request(s) */ - unsigned long proxyauthavail; /* what proxy auth types were announced */ - unsigned long httpauthavail; /* what host auth types were announced */ - long numconnects; /* how many new connection did libcurl created */ - char *contenttype; /* the content type of the object */ - char *wouldredirect; /* URL this would've been redirected to if asked to */ - - /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip' - and, 'conn_local_port' are copied over from the connectdata struct in - order to allow curl_easy_getinfo() to return this information even when - the session handle is no longer associated with a connection, and also - allow curl_easy_reset() to clear this information from the session handle - without disturbing information which is still alive, and that might be - reused, in the connection cache. */ - - char conn_primary_ip[MAX_IPADR_LEN]; - long conn_primary_port; - - char conn_local_ip[MAX_IPADR_LEN]; - long conn_local_port; - - const char *conn_scheme; - unsigned int conn_protocol; - - struct curl_certinfo certs; /* info about the certs, only populated in - OpenSSL builds. Asked for with - CURLOPT_CERTINFO / CURLINFO_CERTINFO */ -}; - - -struct Progress { - time_t lastshow; /* time() of the last displayed progress meter or NULL to - force redraw at next call */ - curl_off_t size_dl; /* total expected size */ - curl_off_t size_ul; /* total expected size */ - curl_off_t downloaded; /* transferred so far */ - curl_off_t uploaded; /* transferred so far */ - - curl_off_t current_speed; /* uses the currently fastest transfer */ - - bool callback; /* set when progress callback is used */ - int width; /* screen width at download start */ - int flags; /* see progress.h */ - - time_t timespent; - - curl_off_t dlspeed; - curl_off_t ulspeed; - - time_t t_nslookup; - time_t t_connect; - time_t t_appconnect; - time_t t_pretransfer; - time_t t_starttransfer; - time_t t_redirect; - - struct curltime start; - struct curltime t_startsingle; - struct curltime t_startop; - struct curltime t_acceptdata; - - bool is_t_startransfer_set; - - /* upload speed limit */ - struct curltime ul_limit_start; - curl_off_t ul_limit_size; - /* download speed limit */ - struct curltime dl_limit_start; - curl_off_t dl_limit_size; - -#define CURR_TIME (5 + 1) /* 6 entries for 5 seconds */ - - curl_off_t speeder[ CURR_TIME ]; - struct curltime speeder_time[ CURR_TIME ]; - int speeder_c; -}; - -typedef enum { - HTTPREQ_NONE, /* first in list */ - HTTPREQ_GET, - HTTPREQ_POST, - HTTPREQ_POST_FORM, /* we make a difference internally */ - HTTPREQ_POST_MIME, /* we make a difference internally */ - HTTPREQ_PUT, - HTTPREQ_HEAD, - HTTPREQ_OPTIONS, - HTTPREQ_CUSTOM, - HTTPREQ_LAST /* last in list */ -} Curl_HttpReq; - -typedef enum { - RTSPREQ_NONE, /* first in list */ - RTSPREQ_OPTIONS, - RTSPREQ_DESCRIBE, - RTSPREQ_ANNOUNCE, - RTSPREQ_SETUP, - RTSPREQ_PLAY, - RTSPREQ_PAUSE, - RTSPREQ_TEARDOWN, - RTSPREQ_GET_PARAMETER, - RTSPREQ_SET_PARAMETER, - RTSPREQ_RECORD, - RTSPREQ_RECEIVE, - RTSPREQ_LAST /* last in list */ -} Curl_RtspReq; - -/* - * Values that are generated, temporary or calculated internally for a - * "session handle" must be defined within the 'struct UrlState'. This struct - * will be used within the Curl_easy struct. When the 'Curl_easy' - * struct is cloned, this data MUST NOT be copied. - * - * Remember that any "state" information goes globally for the curl handle. - * Session-data MUST be put in the connectdata struct and here. */ -#define MAX_CURL_USER_LENGTH 256 -#define MAX_CURL_PASSWORD_LENGTH 256 - -struct auth { - unsigned long want; /* Bitmask set to the authentication methods wanted by - app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ - unsigned long picked; - unsigned long avail; /* Bitmask for what the server reports to support for - this resource */ - bool done; /* TRUE when the auth phase is done and ready to do the *actual* - request */ - bool multipass; /* TRUE if this is not yet authenticated but within the - auth multipass negotiation */ - bool iestyle; /* TRUE if digest should be done IE-style or FALSE if it should - be RFC compliant */ -}; - -struct Curl_http2_dep { - struct Curl_http2_dep *next; - struct Curl_easy *data; -}; - -/* - * This struct is for holding data that was attemped to get sent to the user's - * callback but is held due to pausing. One instance per type (BOTH, HEADER, - * BODY). - */ -struct tempbuf { - char *buf; /* allocated buffer to keep data in when a write callback - returns to make the connection paused */ - size_t len; /* size of the 'tempwrite' allocated buffer */ - int type; /* type of the 'tempwrite' buffer as a bitmask that is used with - Curl_client_write() */ -}; - -/* Timers */ -typedef enum { - EXPIRE_100_TIMEOUT, - EXPIRE_ASYNC_NAME, - EXPIRE_CONNECTTIMEOUT, - EXPIRE_DNS_PER_NAME, - EXPIRE_HAPPY_EYEBALLS, - EXPIRE_MULTI_PENDING, - EXPIRE_RUN_NOW, - EXPIRE_SPEEDCHECK, - EXPIRE_TIMEOUT, - EXPIRE_TOOFAST, - EXPIRE_LAST /* not an actual timer, used as a marker only */ -} expire_id; - -/* - * One instance for each timeout an easy handle can set. - */ -struct time_node { - struct curl_llist_element list; - struct curltime time; - expire_id eid; -}; - -struct UrlState { - - /* Points to the connection cache */ - struct conncache *conn_cache; - - /* when curl_easy_perform() is called, the multi handle is "owned" by - the easy handle so curl_easy_cleanup() on such an easy handle will - also close the multi handle! */ - bool multi_owned_by_easy; - - /* buffers to store authentication data in, as parsed from input options */ - struct curltime keeps_speed; /* for the progress meter really */ - - struct connectdata *lastconnect; /* The last connection, NULL if undefined */ - - char *headerbuff; /* allocated buffer to store headers in */ - size_t headersize; /* size of the allocation */ - - char *buffer; /* download buffer */ - char uploadbuffer[UPLOAD_BUFSIZE + 1]; /* upload buffer */ - curl_off_t current_speed; /* the ProgressShow() function sets this, - bytes / second */ - bool this_is_a_follow; /* this is a followed Location: request */ - - char *first_host; /* host name of the first (not followed) request. - if set, this should be the host name that we will - sent authorization to, no else. Used to make Location: - following not keep sending user+password... This is - strdup() data. - */ - int first_remote_port; /* remote port of the first (not followed) request */ - struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ - long sessionage; /* number of the most recent session */ - unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */ - struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */ - char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */ - bool errorbuf; /* Set to TRUE if the error buffer is already filled in. - This must be set to FALSE every time _easy_perform() is - called. */ - int os_errno; /* filled in with errno whenever an error occurs */ -#ifdef HAVE_SIGNAL - /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */ - void (*prev_signal)(int sig); -#endif - bool allow_port; /* Is set.use_port allowed to take effect or not. This - is always set TRUE when curl_easy_perform() is called. */ - struct digestdata digest; /* state data for host Digest auth */ - struct digestdata proxydigest; /* state data for proxy Digest auth */ - -#ifdef USE_SPNEGO - struct negotiatedata negotiate; /* state data for host Negotiate auth */ - struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */ -#endif - - struct auth authhost; /* auth details for host */ - struct auth authproxy; /* auth details for proxy */ - - bool authproblem; /* TRUE if there's some problem authenticating */ - - void *resolver; /* resolver state, if it is used in the URL state - - ares_channel f.e. */ - -#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) - /* void instead of ENGINE to avoid bleeding OpenSSL into this header */ - void *engine; -#endif /* USE_OPENSSL */ - struct curltime expiretime; /* set this with Curl_expire() only */ - struct Curl_tree timenode; /* for the splay stuff */ - struct curl_llist timeoutlist; /* list of pending timeouts */ - struct time_node expires[EXPIRE_LAST]; /* nodes for each expire type */ - - /* a place to store the most recently set FTP entrypath */ - char *most_recent_ftp_entrypath; - - /* set after initial USER failure, to prevent an authentication loop */ - bool ftp_trying_alternative; - - int httpversion; /* the lowest HTTP version*10 reported by any server - involved in this request */ - bool expect100header; /* TRUE if we added Expect: 100-continue */ - - bool pipe_broke; /* TRUE if the connection we were pipelined on broke - and we need to restart from the beginning */ - -#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__) && \ - !defined(__SYMBIAN32__) -/* do FTP line-end conversions on most platforms */ -#define CURL_DO_LINEEND_CONV - /* for FTP downloads: track CRLF sequences that span blocks */ - bool prev_block_had_trailing_cr; - /* for FTP downloads: how many CRLFs did we converted to LFs? */ - curl_off_t crlf_conversions; -#endif - char *pathbuffer;/* allocated buffer to store the URL's path part in */ - char *path; /* path to use, points to somewhere within the pathbuffer - area */ - bool slash_removed; /* set TRUE if the 'path' points to a path where the - initial URL slash separator has been taken off */ - bool use_range; - bool rangestringalloc; /* the range string is malloc()'ed */ - - char *range; /* range, if used. See README for detailed specification on - this syntax. */ - curl_off_t resume_from; /* continue [ftp] transfer from here */ - - /* This RTSP state information survives requests and connections */ - long rtsp_next_client_CSeq; /* the session's next client CSeq */ - long rtsp_next_server_CSeq; /* the session's next server CSeq */ - long rtsp_CSeq_recv; /* most recent CSeq received */ - - curl_off_t infilesize; /* size of file to upload, -1 means unknown. - Copied from set.filesize at start of operation */ - - size_t drain; /* Increased when this stream has data to read, even if its - socket is not necessarily is readable. Decreased when - checked. */ - bool done; /* set to FALSE when Curl_init_do() is called and set to TRUE - when multi_done() is called, to prevent multi_done() to get - invoked twice when the multi interface is used. */ - - curl_read_callback fread_func; /* read callback/function */ - void *in; /* CURLOPT_READDATA */ - - struct Curl_easy *stream_depends_on; - bool stream_depends_e; /* set or don't set the Exclusive bit */ - int stream_weight; -}; - - -/* - * This 'DynamicStatic' struct defines dynamic states that actually change - * values in the 'UserDefined' area, which MUST be taken into consideration - * if the UserDefined struct is cloned or similar. You can probably just - * copy these, but each one indicate a special action on other data. - */ - -struct DynamicStatic { - char *url; /* work URL, copied from UserDefined */ - bool url_alloc; /* URL string is malloc()'ed */ - char *referer; /* referer string */ - bool referer_alloc; /* referer sting is malloc()ed */ - struct curl_slist *cookielist; /* list of cookie files set by - curl_easy_setopt(COOKIEFILE) calls */ - struct curl_slist *resolve; /* set to point to the set.resolve list when - this should be dealt with in pretransfer */ -}; - -/* - * This 'UserDefined' struct must only contain data that is set once to go - * for many (perhaps) independent connections. Values that are generated or - * calculated internally for the "session handle" MUST be defined within the - * 'struct UrlState' instead. The only exceptions MUST note the changes in - * the 'DynamicStatic' struct. - * Character pointer fields point to dynamic storage, unless otherwise stated. - */ - -struct Curl_multi; /* declared and used only in multi.c */ - -enum dupstring { - STRING_CERT_ORIG, /* client certificate file name */ - STRING_CERT_PROXY, /* client certificate file name */ - STRING_CERT_TYPE_ORIG, /* format for certificate (default: PEM)*/ - STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/ - STRING_COOKIE, /* HTTP cookie string to send */ - STRING_COOKIEJAR, /* dump all cookies to this file */ - STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */ - STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */ - STRING_DEVICE, /* local network interface/address to use */ - STRING_ENCODING, /* Accept-Encoding string */ - STRING_FTP_ACCOUNT, /* ftp account data */ - STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ - STRING_FTPPORT, /* port to send with the FTP PORT command */ - STRING_KEY_ORIG, /* private key file name */ - STRING_KEY_PROXY, /* private key file name */ - STRING_KEY_PASSWD_ORIG, /* plain text private key password */ - STRING_KEY_PASSWD_PROXY, /* plain text private key password */ - STRING_KEY_TYPE_ORIG, /* format for private key (default: PEM) */ - STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */ - STRING_KRB_LEVEL, /* krb security level */ - STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find - $HOME/.netrc */ - STRING_PROXY, /* proxy to use */ - STRING_PRE_PROXY, /* pre socks proxy to use */ - STRING_SET_RANGE, /* range, if used */ - STRING_SET_REFERER, /* custom string for the HTTP referer field */ - STRING_SET_URL, /* what original URL to work on */ - STRING_SSL_CAPATH_ORIG, /* CA directory name (doesn't work on windows) */ - STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */ - STRING_SSL_CAFILE_ORIG, /* certificate file to verify peer against */ - STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */ - STRING_SSL_PINNEDPUBLICKEY_ORIG, /* public key file to verify peer against */ - STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */ - STRING_SSL_CIPHER_LIST_ORIG, /* list of ciphers to use */ - STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */ - STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */ - STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ - STRING_USERAGENT, /* User-Agent string */ - STRING_SSL_CRLFILE_ORIG, /* crl file to check certificate */ - STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */ - STRING_SSL_ISSUERCERT_ORIG, /* issuer cert file to check certificate */ - STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */ - STRING_USERNAME, /* , if used */ - STRING_PASSWORD, /* , if used */ - STRING_OPTIONS, /* , if used */ - STRING_PROXYUSERNAME, /* Proxy , if used */ - STRING_PROXYPASSWORD, /* Proxy , if used */ - STRING_NOPROXY, /* List of hosts which should not use the proxy, if - used */ - STRING_RTSP_SESSION_ID, /* Session ID to use */ - STRING_RTSP_STREAM_URI, /* Stream URI for this request */ - STRING_RTSP_TRANSPORT, /* Transport for this session */ -#ifdef USE_LIBSSH2 - STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */ - STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */ - STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */ - STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ -#endif -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - STRING_PROXY_SERVICE_NAME, /* Proxy service name */ -#endif -#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ - defined(USE_SPNEGO) - STRING_SERVICE_NAME, /* Service name */ -#endif - STRING_MAIL_FROM, - STRING_MAIL_AUTH, - -#ifdef USE_TLS_SRP - STRING_TLSAUTH_USERNAME_ORIG, /* TLS auth */ - STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth */ - STRING_TLSAUTH_PASSWORD_ORIG, /* TLS auth */ - STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth */ -#endif - STRING_BEARER, /* , if used */ -#ifdef USE_UNIX_SOCKETS - STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */ -#endif - STRING_TARGET, /* CURLOPT_REQUEST_TARGET */ - /* -- end of zero-terminated strings -- */ - - STRING_LASTZEROTERMINATED, - - /* -- below this are pointers to binary data that cannot be strdup'ed. - Each such pointer must be added manually to Curl_dupset() --- */ - - STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ - - STRING_LAST /* not used, just an end-of-list marker */ -}; - -struct UserDefined { - FILE *err; /* the stderr user data goes here */ - void *debugdata; /* the data that will be passed to fdebug */ - char *errorbuffer; /* (Static) store failure messages in here */ - long proxyport; /* If non-zero, use this port number by default. If the - proxy string features a ":[port]" that one will override - this. */ - void *out; /* CURLOPT_WRITEDATA */ - void *in_set; /* CURLOPT_READDATA */ - void *writeheader; /* write the header to this if non-NULL */ - void *rtp_out; /* write RTP to this if non-NULL */ - long use_port; /* which port to use (when not using default) */ - unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */ - unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */ - unsigned long socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */ - long followlocation; /* as in HTTP Location: */ - long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 - for infinity */ - - int keep_post; /* keep POSTs as POSTs after a 30x request; each - bit represents a request, from 301 to 303 */ - bool free_referer; /* set TRUE if 'referer' points to a string we - allocated */ - void *postfields; /* if POST, set the fields' values here */ - curl_seek_callback seek_func; /* function that seeks the input */ - curl_off_t postfieldsize; /* if POST, this might have a size to use instead - of strlen(), and then the data *may* be binary - (contain zero bytes) */ - unsigned short localport; /* local port number to bind to */ - int localportrange; /* number of additional port numbers to test in case the - 'localport' one can't be bind()ed */ - curl_write_callback fwrite_func; /* function that stores the output */ - curl_write_callback fwrite_header; /* function that stores headers */ - curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */ - curl_read_callback fread_func_set; /* function that reads the input */ - int is_fread_set; /* boolean, has read callback been set to non-NULL? */ - int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */ - curl_progress_callback fprogress; /* OLD and deprecated progress callback */ - curl_xferinfo_callback fxferinfo; /* progress callback */ - curl_debug_callback fdebug; /* function that write informational data */ - curl_ioctl_callback ioctl_func; /* function for I/O control */ - curl_sockopt_callback fsockopt; /* function for setting socket options */ - void *sockopt_client; /* pointer to pass to the socket options callback */ - curl_opensocket_callback fopensocket; /* function for checking/translating - the address and opening the - socket */ - void *opensocket_client; - curl_closesocket_callback fclosesocket; /* function for closing the - socket */ - void *closesocket_client; - - void *seek_client; /* pointer to pass to the seek callback */ - /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */ - /* function to convert from the network encoding: */ - curl_conv_callback convfromnetwork; - /* function to convert to the network encoding: */ - curl_conv_callback convtonetwork; - /* function to convert from UTF-8 encoding: */ - curl_conv_callback convfromutf8; - - void *progress_client; /* pointer to pass to the progress callback */ - void *ioctl_client; /* pointer to pass to the ioctl callback */ - long timeout; /* in milliseconds, 0 means no timeout */ - long connecttimeout; /* in milliseconds, 0 means no timeout */ - long accepttimeout; /* in milliseconds, 0 means no timeout */ - long server_response_timeout; /* in milliseconds, 0 means no timeout */ - long tftp_blksize; /* in bytes, 0 means use default */ - bool tftp_no_options; /* do not send TFTP options requests */ - curl_off_t filesize; /* size of file to upload, -1 means unknown */ - long low_speed_limit; /* bytes/second */ - long low_speed_time; /* number of seconds */ - curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */ - curl_off_t max_recv_speed; /* high speed limit in bytes/second for - download */ - curl_off_t set_resume_from; /* continue [ftp] transfer from here */ - struct curl_slist *headers; /* linked list of extra headers */ - struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */ - struct curl_httppost *httppost; /* linked list of old POST data */ - curl_mimepart mimepost; /* MIME/POST data. */ - bool sep_headers; /* handle host and proxy headers separately */ - bool cookiesession; /* new cookie session? */ - bool crlf; /* convert crlf on ftp upload(?) */ - struct curl_slist *quote; /* after connection is established */ - struct curl_slist *postquote; /* after the transfer */ - struct curl_slist *prequote; /* before the transfer, after type */ - struct curl_slist *source_quote; /* 3rd party quote */ - struct curl_slist *source_prequote; /* in 3rd party transfer mode - before - the transfer on source host */ - struct curl_slist *source_postquote; /* in 3rd party transfer mode - after - the transfer on source host */ - struct curl_slist *telnet_options; /* linked list of telnet options */ - struct curl_slist *resolve; /* list of names to add/remove from - DNS cache */ - struct curl_slist *connect_to; /* list of host:port mappings to override - the hostname and port to connect to */ - curl_TimeCond timecondition; /* kind of time/date comparison */ - time_t timevalue; /* what time to compare with */ - Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ - long httpversion; /* when non-zero, a specific HTTP version requested to - be used in the library's request(s) */ - bool strip_path_slash; /* strip off initial slash from path */ - struct ssl_config_data ssl; /* user defined SSL stuff */ - struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ - struct ssl_general_config general_ssl; /* general user defined SSL stuff */ - curl_proxytype proxytype; /* what kind of proxy that is in use */ - long dns_cache_timeout; /* DNS cache timeout */ - long buffer_size; /* size of receive buffer to use */ - void *private_data; /* application-private data */ - - struct curl_slist *http200aliases; /* linked list of aliases for http200 */ - - long ipver; /* the CURL_IPRESOLVE_* defines in the public header file - 0 - whatever, 1 - v2, 2 - v6 */ - - curl_off_t max_filesize; /* Maximum file size to download */ - - curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */ - - int ftp_create_missing_dirs; /* 1 - create directories that don't exist - 2 - the same but also allow MKD to fail once - */ - - curl_sshkeycallback ssh_keyfunc; /* key matching callback */ - void *ssh_keyfunc_userp; /* custom pointer to callback */ - bool ssh_compression; /* enable SSH compression */ - -/* Here follows boolean settings that define how to behave during - this session. They are STATIC, set by libcurl users or at least initially - and they don't change during operations. */ - - bool printhost; /* printing host name in debug info */ - bool get_filetime; /* get the time and get of the remote file */ - bool tunnel_thru_httpproxy; /* use CONNECT through a HTTP proxy */ - bool prefer_ascii; /* ASCII rather than binary */ - bool ftp_append; /* append, not overwrite, on upload */ - bool ftp_list_only; /* switch FTP command for listing directories */ - bool ftp_use_port; /* use the FTP PORT command */ - bool hide_progress; /* don't use the progress meter */ - bool http_fail_on_error; /* fail on HTTP error codes >= 400 */ - bool http_keep_sending_on_error; /* for HTTP status codes >= 300 */ - bool http_follow_location; /* follow HTTP redirects */ - bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */ - bool http_disable_hostname_check_before_authentication; - bool include_header; /* include received protocol headers in data output */ - bool http_set_referer; /* is a custom referer used */ - bool http_auto_referer; /* set "correct" referer when following location: */ - bool opt_no_body; /* as set with CURLOPT_NOBODY */ - bool upload; /* upload request */ - enum CURL_NETRC_OPTION - use_netrc; /* defined in include/curl.h */ - bool verbose; /* output verbosity */ - bool krb; /* Kerberos connection requested */ - bool reuse_forbid; /* forbidden to be reused, close after use */ - bool reuse_fresh; /* do not re-use an existing connection */ - bool ftp_use_epsv; /* if EPSV is to be attempted or not */ - bool ftp_use_eprt; /* if EPRT is to be attempted or not */ - bool ftp_use_pret; /* if PRET is to be used before PASV or not */ - - curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or - IMAP or POP3 or others! */ - curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */ - curl_ftpccc ftp_ccc; /* FTP CCC options */ - bool no_signal; /* do not use any signal/alarm handler */ - bool global_dns_cache; /* subject for future removal */ - bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */ - bool ignorecl; /* ignore content length */ - bool ftp_skip_ip; /* skip the IP address the FTP server passes on to - us */ - bool connect_only; /* make connection, let application use the socket */ - long ssh_auth_types; /* allowed SSH auth types */ - bool http_te_skip; /* pass the raw body data to the user, even when - transfer-encoded (chunked, compressed) */ - bool http_ce_skip; /* pass the raw body data to the user, even when - content-encoded (chunked, compressed) */ - long new_file_perms; /* Permissions to use when creating remote files */ - long new_directory_perms; /* Permissions to use when creating remote dirs */ - bool proxy_transfer_mode; /* set transfer mode (;type=) when doing FTP - via an HTTP proxy */ - char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ - unsigned int scope_id; /* Scope id for IPv6 */ - long allowed_protocols; - long redir_protocols; -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - bool socks5_gssapi_nec; /* Flag to support NEC SOCKS5 server */ -#endif - struct curl_slist *mail_rcpt; /* linked list of mail recipients */ - bool sasl_ir; /* Enable/disable SASL initial response */ - /* Common RTSP header options */ - Curl_RtspReq rtspreq; /* RTSP request type */ - long rtspversion; /* like httpversion, for RTSP */ - bool wildcardmatch; /* enable wildcard matching */ - curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer - starts */ - curl_chunk_end_callback chunk_end; /* called after part transferring - stopped */ - curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds - to pattern (e.g. if WILDCARDMATCH is on) */ - void *fnmatch_data; - - long gssapi_delegation; /* GSS-API credential delegation, see the - documentation of CURLOPT_GSSAPI_DELEGATION */ - - bool tcp_keepalive; /* use TCP keepalives */ - long tcp_keepidle; /* seconds in idle before sending keepalive probe */ - long tcp_keepintvl; /* seconds between TCP keepalive probes */ - bool tcp_fastopen; /* use TCP Fast Open */ - - size_t maxconnects; /* Max idle connections in the connection cache */ - - bool ssl_enable_npn; /* TLS NPN extension? */ - bool ssl_enable_alpn; /* TLS ALPN extension? */ - bool path_as_is; /* allow dotdots? */ - bool pipewait; /* wait for pipe/multiplex status before starting a - new connection */ - long expect_100_timeout; /* in milliseconds */ - bool suppress_connect_headers; /* suppress proxy CONNECT response headers - from user callbacks */ - - struct Curl_easy *stream_depends_on; - bool stream_depends_e; /* set or don't set the Exclusive bit */ - int stream_weight; - - struct Curl_http2_dep *stream_dependents; - - bool abstract_unix_socket; -}; - -struct Names { - struct curl_hash *hostcache; - enum { - HCACHE_NONE, /* not pointing to anything */ - HCACHE_GLOBAL, /* points to the (shrug) global one */ - HCACHE_MULTI, /* points to a shared one in the multi handle */ - HCACHE_SHARED /* points to a shared one in a shared object */ - } hostcachetype; -}; - -/* - * The 'connectdata' struct MUST have all the connection oriented stuff as we - * may have several simultaneous connections and connection structs in memory. - * - * The 'struct UserDefined' must only contain data that is set once to go for - * many (perhaps) independent connections. Values that are generated or - * calculated internally for the "session handle" must be defined within the - * 'struct UrlState' instead. - */ - -struct Curl_easy { - /* first, two fields for the linked list of these */ - struct Curl_easy *next; - struct Curl_easy *prev; - - struct connectdata *easy_conn; /* the "unit's" connection */ - struct curl_llist_element connect_queue; - struct curl_llist_element pipeline_queue; - - CURLMstate mstate; /* the handle's state */ - CURLcode result; /* previous result */ - - struct Curl_message msg; /* A single posted message. */ - - /* Array with the plain socket numbers this handle takes care of, in no - particular order. Note that all sockets are added to the sockhash, where - the state etc are also kept. This array is mostly used to detect when a - socket is to be removed from the hash. See singlesocket(). */ - curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; - int numsocks; - - struct Names dns; - struct Curl_multi *multi; /* if non-NULL, points to the multi handle - struct to which this "belongs" when used by - the multi interface */ - struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle - struct to which this "belongs" when used - by the easy interface */ - struct Curl_share *share; /* Share, handles global variable mutexing */ - struct SingleRequest req; /* Request-specific data */ - struct UserDefined set; /* values set by the libcurl user */ - struct DynamicStatic change; /* possibly modified userdefined data */ - struct CookieInfo *cookies; /* the cookies, read from files and servers. - NOTE that the 'cookie' field in the - UserDefined struct defines if the "engine" - is to be used or not. */ - struct Progress progress; /* for all the progress meter data */ - struct UrlState state; /* struct for fields used for state info and - other dynamic purposes */ - struct WildcardData wildcard; /* wildcard download state info */ - struct PureInfo info; /* stats, reports and info data */ - struct curl_tlssessioninfo tsi; /* Information about the TLS session, only - valid after a client has asked for it */ -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - iconv_t outbound_cd; /* for translating to the network encoding */ - iconv_t inbound_cd; /* for translating from the network encoding */ - iconv_t utf8_cd; /* for translating to UTF8 */ -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ - unsigned int magic; /* set to a CURLEASY_MAGIC_NUMBER */ -}; - -#define LIBCURL_NAME "libcurl" - -#endif /* HEADER_CURL_URLDATA_H */ diff --git a/dep/cpr/opt/curl/lib/vauth/cleartext.c b/dep/cpr/opt/curl/lib/vauth/cleartext.c deleted file mode 100644 index a761ae78466..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/cleartext.c +++ /dev/null @@ -1,165 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC4616 PLAIN authentication - * Draft LOGIN SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include -#include "urldata.h" - -#include "vauth/vauth.h" -#include "curl_base64.h" -#include "curl_md5.h" -#include "warnless.h" -#include "strtok.h" -#include "sendf.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_create_plain_message() - * - * This is used to generate an already encoded PLAIN message ready - * for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen) -{ - CURLcode result; - char *plainauth; - size_t ulen; - size_t plen; - size_t plainlen; - - *outlen = 0; - *outptr = NULL; - ulen = strlen(userp); - plen = strlen(passwdp); - - /* Compute binary message length, checking for overflows. */ - plainlen = 2 * ulen; - if(plainlen < ulen) - return CURLE_OUT_OF_MEMORY; - plainlen += plen; - if(plainlen < plen) - return CURLE_OUT_OF_MEMORY; - plainlen += 2; - if(plainlen < 2) - return CURLE_OUT_OF_MEMORY; - - plainauth = malloc(plainlen); - if(!plainauth) - return CURLE_OUT_OF_MEMORY; - - /* Calculate the reply */ - memcpy(plainauth, userp, ulen); - plainauth[ulen] = '\0'; - memcpy(plainauth + ulen + 1, userp, ulen); - plainauth[2 * ulen + 1] = '\0'; - memcpy(plainauth + 2 * ulen + 2, passwdp, plen); - - /* Base64 encode the reply */ - result = Curl_base64_encode(data, plainauth, plainlen, outptr, outlen); - free(plainauth); - - return result; -} - -/* - * Curl_auth_create_login_message() - * - * This is used to generate an already encoded LOGIN message containing the - * user name or password ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * valuep [in] - The user name or user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_login_message(struct Curl_easy *data, - const char *valuep, char **outptr, - size_t *outlen) -{ - size_t vlen = strlen(valuep); - - if(!vlen) { - /* Calculate an empty reply */ - *outptr = strdup("="); - if(*outptr) { - *outlen = (size_t) 1; - return CURLE_OK; - } - - *outlen = 0; - return CURLE_OUT_OF_MEMORY; - } - - /* Base64 encode the value */ - return Curl_base64_encode(data, valuep, vlen, outptr, outlen); -} - -/* - * Curl_auth_create_external_message() - * - * This is used to generate an already encoded EXTERNAL message containing - * the user name ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * user [in] - The user name. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_external_message(struct Curl_easy *data, - const char *user, char **outptr, - size_t *outlen) -{ - /* This is the same formatting as the login message */ - return Curl_auth_create_login_message(data, user, outptr, outlen); -} diff --git a/dep/cpr/opt/curl/lib/vauth/cram.c b/dep/cpr/opt/curl/lib/vauth/cram.c deleted file mode 100644 index 3074a163a13..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/cram.c +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC2195 CRAM-MD5 authentication - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) - -#include -#include "urldata.h" - -#include "vauth/vauth.h" -#include "curl_base64.h" -#include "curl_hmac.h" -#include "curl_md5.h" -#include "warnless.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_decode_cram_md5_message() - * - * This is used to decode an already encoded CRAM-MD5 challenge message. - * - * Parameters: - * - * chlg64 [in] - The base64 encoded challenge message. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, - size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlg64len = strlen(chlg64); - - *outptr = NULL; - *outlen = 0; - - /* Decode the challenge if necessary */ - if(chlg64len && *chlg64 != '=') - result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen); - - return result; -} - -/* - * Curl_auth_create_cram_md5_message() - * - * This is used to generate an already encoded CRAM-MD5 response message ready - * for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg [in] - The challenge. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, - const char *chlg, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - HMAC_context *ctxt; - unsigned char digest[MD5_DIGEST_LEN]; - char *response; - - if(chlg) - chlglen = strlen(chlg); - - /* Compute the digest using the password as the key */ - ctxt = Curl_HMAC_init(Curl_HMAC_MD5, - (const unsigned char *) passwdp, - curlx_uztoui(strlen(passwdp))); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - /* Update the digest with the given challenge */ - if(chlglen > 0) - Curl_HMAC_update(ctxt, (const unsigned char *) chlg, - curlx_uztoui(chlglen)); - - /* Finalise the digest */ - Curl_HMAC_final(ctxt, digest); - - /* Generate the response */ - response = aprintf( - "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - userp, digest[0], digest[1], digest[2], digest[3], digest[4], - digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], - digest[11], digest[12], digest[13], digest[14], digest[15]); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the response */ - result = Curl_base64_encode(data, response, 0, outptr, outlen); - - free(response); - - return result; -} - -#endif /* !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/dep/cpr/opt/curl/lib/vauth/digest.c b/dep/cpr/opt/curl/lib/vauth/digest.c deleted file mode 100644 index 185098ed68e..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/digest.c +++ /dev/null @@ -1,893 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC2831 DIGEST-MD5 authentication - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) - -#include - -#include "vauth/vauth.h" -#include "vauth/digest.h" -#include "urldata.h" -#include "curl_base64.h" -#include "curl_hmac.h" -#include "curl_md5.h" -#include "vtls/vtls.h" -#include "warnless.h" -#include "strtok.h" -#include "strcase.h" -#include "non-ascii.h" /* included for Curl_convert_... prototypes */ -#include "curl_printf.h" -#include "rand.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -#if !defined(USE_WINDOWS_SSPI) -#define DIGEST_QOP_VALUE_AUTH (1 << 0) -#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) -#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2) - -#define DIGEST_QOP_VALUE_STRING_AUTH "auth" -#define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" -#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" - -/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. - It converts digest text to ASCII so the MD5 will be correct for - what ultimately goes over the network. -*/ -#define CURL_OUTPUT_DIGEST_CONV(a, b) \ - result = Curl_convert_to_network(a, (char *)b, strlen((const char *)b)); \ - if(result) { \ - free(b); \ - return result; \ - } -#endif /* !USE_WINDOWS_SSPI */ - -bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, - const char **endptr) -{ - int c; - bool starts_with_quote = FALSE; - bool escape = FALSE; - - for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);) - *value++ = *str++; - *value = 0; - - if('=' != *str++) - /* eek, no match */ - return FALSE; - - if('\"' == *str) { - /* This starts with a quote so it must end with one as well! */ - str++; - starts_with_quote = TRUE; - } - - for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) { - switch(*str) { - case '\\': - if(!escape) { - /* possibly the start of an escaped quote */ - escape = TRUE; - *content++ = '\\'; /* Even though this is an escape character, we still - store it as-is in the target buffer */ - continue; - } - break; - - case ',': - if(!starts_with_quote) { - /* This signals the end of the content if we didn't get a starting - quote and then we do "sloppy" parsing */ - c = 0; /* the end */ - continue; - } - break; - - case '\r': - case '\n': - /* end of string */ - c = 0; - continue; - - case '\"': - if(!escape && starts_with_quote) { - /* end of string */ - c = 0; - continue; - } - break; - } - - escape = FALSE; - *content++ = *str; - } - - *content = 0; - *endptr = str; - - return TRUE; -} - -#if !defined(USE_WINDOWS_SSPI) -/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ -static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ - unsigned char *dest) /* 33 bytes */ -{ - int i; - for(i = 0; i < 16; i++) - snprintf((char *) &dest[i * 2], 3, "%02x", source[i]); -} - -/* Perform quoted-string escaping as described in RFC2616 and its errata */ -static char *auth_digest_string_quoted(const char *source) -{ - char *dest, *d; - const char *s = source; - size_t n = 1; /* null terminator */ - - /* Calculate size needed */ - while(*s) { - ++n; - if(*s == '"' || *s == '\\') { - ++n; - } - ++s; - } - - dest = malloc(n); - if(dest) { - s = source; - d = dest; - while(*s) { - if(*s == '"' || *s == '\\') { - *d++ = '\\'; - } - *d++ = *s++; - } - *d = 0; - } - - return dest; -} - -/* Retrieves the value for a corresponding key from the challenge string - * returns TRUE if the key could be found, FALSE if it does not exists - */ -static bool auth_digest_get_key_value(const char *chlg, - const char *key, - char *value, - size_t max_val_len, - char end_char) -{ - char *find_pos; - size_t i; - - find_pos = strstr(chlg, key); - if(!find_pos) - return FALSE; - - find_pos += strlen(key); - - for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) - value[i] = *find_pos++; - value[i] = '\0'; - - return TRUE; -} - -static CURLcode auth_digest_get_qop_values(const char *options, int *value) -{ - char *tmp; - char *token; - char *tok_buf = NULL; - - /* Initialise the output */ - *value = 0; - - /* Tokenise the list of qop values. Use a temporary clone of the buffer since - strtok_r() ruins it. */ - tmp = strdup(options); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { - if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) - *value |= DIGEST_QOP_VALUE_AUTH; - else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) - *value |= DIGEST_QOP_VALUE_AUTH_INT; - else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) - *value |= DIGEST_QOP_VALUE_AUTH_CONF; - - token = strtok_r(NULL, ",", &tok_buf); - } - - free(tmp); - - return CURLE_OK; -} - -/* - * auth_decode_digest_md5_message() - * - * This is used internally to decode an already encoded DIGEST-MD5 challenge - * message into the separate attributes. - * - * Parameters: - * - * chlg64 [in] - The base64 encoded challenge message. - * nonce [in/out] - The buffer where the nonce will be stored. - * nlen [in] - The length of the nonce buffer. - * realm [in/out] - The buffer where the realm will be stored. - * rlen [in] - The length of the realm buffer. - * alg [in/out] - The buffer where the algorithm will be stored. - * alen [in] - The length of the algorithm buffer. - * qop [in/out] - The buffer where the qop-options will be stored. - * qlen [in] - The length of the qop buffer. - * - * Returns CURLE_OK on success. - */ -static CURLcode auth_decode_digest_md5_message(const char *chlg64, - char *nonce, size_t nlen, - char *realm, size_t rlen, - char *alg, size_t alen, - char *qop, size_t qlen) -{ - CURLcode result = CURLE_OK; - unsigned char *chlg = NULL; - size_t chlglen = 0; - size_t chlg64len = strlen(chlg64); - - /* Decode the base-64 encoded challenge message */ - if(chlg64len && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) - return CURLE_BAD_CONTENT_ENCODING; - - /* Retrieve nonce string from the challenge */ - if(!auth_digest_get_key_value((char *) chlg, "nonce=\"", nonce, nlen, - '\"')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Retrieve realm string from the challenge */ - if(!auth_digest_get_key_value((char *) chlg, "realm=\"", realm, rlen, - '\"')) { - /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ - strcpy(realm, ""); - } - - /* Retrieve algorithm string from the challenge */ - if(!auth_digest_get_key_value((char *) chlg, "algorithm=", alg, alen, ',')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Retrieve qop-options string from the challenge */ - if(!auth_digest_get_key_value((char *) chlg, "qop=\"", qop, qlen, '\"')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - free(chlg); - - return CURLE_OK; -} - -/* - * Curl_auth_is_digest_supported() - * - * This is used to evaluate if DIGEST is supported. - * - * Parameters: None - * - * Returns TRUE as DIGEST as handled by libcurl. - */ -bool Curl_auth_is_digest_supported(void) -{ - return TRUE; -} - -/* - * Curl_auth_create_digest_md5_message() - * - * This is used to generate an already encoded DIGEST-MD5 response message - * ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The base64 encoded challenge message. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * service [in] - The service type such as http, smtp, pop or imap. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t i; - MD5_context *ctxt; - char *response = NULL; - unsigned char digest[MD5_DIGEST_LEN]; - char HA1_hex[2 * MD5_DIGEST_LEN + 1]; - char HA2_hex[2 * MD5_DIGEST_LEN + 1]; - char resp_hash_hex[2 * MD5_DIGEST_LEN + 1]; - char nonce[64]; - char realm[128]; - char algorithm[64]; - char qop_options[64]; - int qop_values; - char cnonce[33]; - char nonceCount[] = "00000001"; - char method[] = "AUTHENTICATE"; - char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; - char *spn = NULL; - - /* Decode the challenge message */ - result = auth_decode_digest_md5_message(chlg64, nonce, sizeof(nonce), - realm, sizeof(realm), - algorithm, sizeof(algorithm), - qop_options, sizeof(qop_options)); - if(result) - return result; - - /* We only support md5 sessions */ - if(strcmp(algorithm, "md5-sess") != 0) - return CURLE_BAD_CONTENT_ENCODING; - - /* Get the qop-values from the qop-options */ - result = auth_digest_get_qop_values(qop_options, &qop_values); - if(result) - return result; - - /* We only support auth quality-of-protection */ - if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) - return CURLE_BAD_CONTENT_ENCODING; - - /* Generate 32 random hex chars, 32 bytes + 1 zero termination */ - result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce)); - if(result) - return result; - - /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - Curl_MD5_update(ctxt, (const unsigned char *) userp, - curlx_uztoui(strlen(userp))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) realm, - curlx_uztoui(strlen(realm))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) passwdp, - curlx_uztoui(strlen(passwdp))); - Curl_MD5_final(ctxt, digest); - - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) nonce, - curlx_uztoui(strlen(nonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) cnonce, - curlx_uztoui(strlen(cnonce))); - Curl_MD5_final(ctxt, digest); - - /* Convert calculated 16 octet hex into 32 bytes string */ - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); - - /* Generate our SPN */ - spn = Curl_auth_build_spn(service, realm, NULL); - if(!spn) - return CURLE_OUT_OF_MEMORY; - - /* Calculate H(A2) */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) { - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - Curl_MD5_update(ctxt, (const unsigned char *) method, - curlx_uztoui(strlen(method))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) spn, - curlx_uztoui(strlen(spn))); - Curl_MD5_final(ctxt, digest); - - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); - - /* Now calculate the response hash */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) { - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) nonce, - curlx_uztoui(strlen(nonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - - Curl_MD5_update(ctxt, (const unsigned char *) nonceCount, - curlx_uztoui(strlen(nonceCount))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) cnonce, - curlx_uztoui(strlen(cnonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) qop, - curlx_uztoui(strlen(qop))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - - Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN); - Curl_MD5_final(ctxt, digest); - - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); - - /* Generate the response */ - response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," - "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," - "qop=%s", - userp, realm, nonce, - cnonce, nonceCount, spn, resp_hash_hex, qop); - free(spn); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the response */ - result = Curl_base64_encode(data, response, 0, outptr, outlen); - - free(response); - - return result; -} - -/* - * Curl_auth_decode_digest_http_message() - * - * This is used to decode a HTTP DIGEST challenge message into the separate - * attributes. - * - * Parameters: - * - * chlg [in] - The challenge message. - * digest [in/out] - The digest data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_decode_digest_http_message(const char *chlg, - struct digestdata *digest) -{ - bool before = FALSE; /* got a nonce before */ - bool foundAuth = FALSE; - bool foundAuthInt = FALSE; - char *token = NULL; - char *tmp = NULL; - - /* If we already have received a nonce, keep that in mind */ - if(digest->nonce) - before = TRUE; - - /* Clean up any former leftovers and initialise to defaults */ - Curl_auth_digest_cleanup(digest); - - for(;;) { - char value[DIGEST_MAX_VALUE_LENGTH]; - char content[DIGEST_MAX_CONTENT_LENGTH]; - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Extract a value=content pair */ - if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(strcasecompare(value, "nonce")) { - free(digest->nonce); - digest->nonce = strdup(content); - if(!digest->nonce) - return CURLE_OUT_OF_MEMORY; - } - else if(strcasecompare(value, "stale")) { - if(strcasecompare(content, "true")) { - digest->stale = TRUE; - digest->nc = 1; /* we make a new nonce now */ - } - } - else if(strcasecompare(value, "realm")) { - free(digest->realm); - digest->realm = strdup(content); - if(!digest->realm) - return CURLE_OUT_OF_MEMORY; - } - else if(strcasecompare(value, "opaque")) { - free(digest->opaque); - digest->opaque = strdup(content); - if(!digest->opaque) - return CURLE_OUT_OF_MEMORY; - } - else if(strcasecompare(value, "qop")) { - char *tok_buf = NULL; - /* Tokenize the list and choose auth if possible, use a temporary - clone of the buffer since strtok_r() ruins it */ - tmp = strdup(content); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { - if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { - foundAuth = TRUE; - } - else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { - foundAuthInt = TRUE; - } - token = strtok_r(NULL, ",", &tok_buf); - } - - free(tmp); - - /* Select only auth or auth-int. Otherwise, ignore */ - if(foundAuth) { - free(digest->qop); - digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); - if(!digest->qop) - return CURLE_OUT_OF_MEMORY; - } - else if(foundAuthInt) { - free(digest->qop); - digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); - if(!digest->qop) - return CURLE_OUT_OF_MEMORY; - } - } - else if(strcasecompare(value, "algorithm")) { - free(digest->algorithm); - digest->algorithm = strdup(content); - if(!digest->algorithm) - return CURLE_OUT_OF_MEMORY; - - if(strcasecompare(content, "MD5-sess")) - digest->algo = CURLDIGESTALGO_MD5SESS; - else if(strcasecompare(content, "MD5")) - digest->algo = CURLDIGESTALGO_MD5; - else - return CURLE_BAD_CONTENT_ENCODING; - } - else { - /* Unknown specifier, ignore it! */ - } - } - else - break; /* We're done here */ - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Allow the list to be comma-separated */ - if(',' == *chlg) - chlg++; - } - - /* We had a nonce since before, and we got another one now without - 'stale=true'. This means we provided bad credentials in the previous - request */ - if(before && !digest->stale) - return CURLE_BAD_CONTENT_ENCODING; - - /* We got this header without a nonce, that's a bad Digest line! */ - if(!digest->nonce) - return CURLE_BAD_CONTENT_ENCODING; - - return CURLE_OK; -} - -/* - * Curl_auth_create_digest_http_message() - * - * This is used to generate a HTTP DIGEST response message ready for sending - * to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * request [in] - The HTTP request. - * uripath [in] - The path of the HTTP uri. - * digest [in/out] - The digest data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uripath, - struct digestdata *digest, - char **outptr, size_t *outlen) -{ - CURLcode result; - unsigned char md5buf[16]; /* 16 bytes/128 bits */ - unsigned char request_digest[33]; - unsigned char *md5this; - unsigned char ha1[33]; /* 32 digits and 1 zero byte */ - unsigned char ha2[33]; /* 32 digits and 1 zero byte */ - char cnoncebuf[33]; - char *cnonce = NULL; - size_t cnonce_sz = 0; - char *userp_quoted; - char *response = NULL; - char *tmp = NULL; - - if(!digest->nc) - digest->nc = 1; - - if(!digest->cnonce) { - result = Curl_rand_hex(data, (unsigned char *)cnoncebuf, - sizeof(cnoncebuf)); - if(result) - return result; - - result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), - &cnonce, &cnonce_sz); - if(result) - return result; - - digest->cnonce = cnonce; - } - - /* - If the algorithm is "MD5" or unspecified (which then defaults to MD5): - - A1 = unq(username-value) ":" unq(realm-value) ":" passwd - - If the algorithm is "MD5-sess" then: - - A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":" - unq(nonce-value) ":" unq(cnonce-value) - */ - - md5this = (unsigned char *) - aprintf("%s:%s:%s", userp, digest->realm, passwdp); - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - auth_digest_md5_to_ascii(md5buf, ha1); - - if(digest->algo == CURLDIGESTALGO_MD5SESS) { - /* nonce and cnonce are OUTSIDE the hash */ - tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */ - Curl_md5it(md5buf, (unsigned char *) tmp); - free(tmp); - auth_digest_md5_to_ascii(md5buf, ha1); - } - - /* - If the "qop" directive's value is "auth" or is unspecified, then A2 is: - - A2 = Method ":" digest-uri-value - - If the "qop" value is "auth-int", then A2 is: - - A2 = Method ":" digest-uri-value ":" H(entity-body) - - (The "Method" value is the HTTP request method as specified in section - 5.1.1 of RFC 2616) - */ - - md5this = (unsigned char *) aprintf("%s:%s", request, uripath); - - if(digest->qop && strcasecompare(digest->qop, "auth-int")) { - /* We don't support auth-int for PUT or POST at the moment. - TODO: replace md5 of empty string with entity-body for PUT/POST */ - unsigned char *md5this2 = (unsigned char *) - aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); - free(md5this); - md5this = md5this2; - } - - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - auth_digest_md5_to_ascii(md5buf, ha2); - - if(digest->qop) { - md5this = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s", - ha1, - digest->nonce, - digest->nc, - digest->cnonce, - digest->qop, - ha2); - } - else { - md5this = (unsigned char *) aprintf("%s:%s:%s", - ha1, - digest->nonce, - ha2); - } - - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - auth_digest_md5_to_ascii(md5buf, request_digest); - - /* For test case 64 (snooped from a Mozilla 1.3a request) - - Authorization: Digest username="testuser", realm="testrealm", \ - nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" - - Digest parameters are all quoted strings. Username which is provided by - the user will need double quotes and backslashes within it escaped. For - the other fields, this shouldn't be an issue. realm, nonce, and opaque - are copied as is from the server, escapes and all. cnonce is generated - with web-safe characters. uri is already percent encoded. nc is 8 hex - characters. algorithm and qop with standard values only contain web-safe - characters. - */ - userp_quoted = auth_digest_string_quoted(userp); - if(!userp_quoted) - return CURLE_OUT_OF_MEMORY; - - if(digest->qop) { - response = aprintf("username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "cnonce=\"%s\", " - "nc=%08x, " - "qop=%s, " - "response=\"%s\"", - userp_quoted, - digest->realm, - digest->nonce, - uripath, - digest->cnonce, - digest->nc, - digest->qop, - request_digest); - - if(strcasecompare(digest->qop, "auth")) - digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 - padded which tells to the server how many times you are - using the same nonce in the qop=auth mode */ - } - else { - response = aprintf("username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "response=\"%s\"", - userp_quoted, - digest->realm, - digest->nonce, - uripath, - request_digest); - } - free(userp_quoted); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Add the optional fields */ - if(digest->opaque) { - /* Append the opaque */ - tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); - free(response); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - response = tmp; - } - - if(digest->algorithm) { - /* Append the algorithm */ - tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm); - free(response); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - response = tmp; - } - - /* Return the output */ - *outptr = response; - *outlen = strlen(response); - - return CURLE_OK; -} - -/* - * Curl_auth_digest_cleanup() - * - * This is used to clean up the digest specific data. - * - * Parameters: - * - * digest [in/out] - The digest data struct being cleaned up. - * - */ -void Curl_auth_digest_cleanup(struct digestdata *digest) -{ - Curl_safefree(digest->nonce); - Curl_safefree(digest->cnonce); - Curl_safefree(digest->realm); - Curl_safefree(digest->opaque); - Curl_safefree(digest->qop); - Curl_safefree(digest->algorithm); - - digest->nc = 0; - digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ - digest->stale = FALSE; /* default means normal, not stale */ -} -#endif /* !USE_WINDOWS_SSPI */ - -#endif /* CURL_DISABLE_CRYPTO_AUTH */ diff --git a/dep/cpr/opt/curl/lib/vauth/digest.h b/dep/cpr/opt/curl/lib/vauth/digest.h deleted file mode 100644 index 5722dceced3..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/digest.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef HEADER_CURL_DIGEST_H -#define HEADER_CURL_DIGEST_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) - -#define DIGEST_MAX_VALUE_LENGTH 256 -#define DIGEST_MAX_CONTENT_LENGTH 1024 - -enum { - CURLDIGESTALGO_MD5, - CURLDIGESTALGO_MD5SESS -}; - -/* This is used to extract the realm from a challenge message */ -bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, - const char **endptr); - -#endif - -#endif /* HEADER_CURL_DIGEST_H */ diff --git a/dep/cpr/opt/curl/lib/vauth/digest_sspi.c b/dep/cpr/opt/curl/lib/vauth/digest_sspi.c deleted file mode 100644 index a3f96ed2457..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/digest_sspi.c +++ /dev/null @@ -1,669 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014 - 2016, Steve Holme, . - * Copyright (C) 2015 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC2831 DIGEST-MD5 authentication - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH) - -#include - -#include "vauth/vauth.h" -#include "vauth/digest.h" -#include "urldata.h" -#include "curl_base64.h" -#include "warnless.h" -#include "curl_multibyte.h" -#include "sendf.h" -#include "strdup.h" -#include "strcase.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* -* Curl_auth_is_digest_supported() -* -* This is used to evaluate if DIGEST is supported. -* -* Parameters: None -* -* Returns TRUE if DIGEST is supported by Windows SSPI. -*/ -bool Curl_auth_is_digest_supported(void) -{ - PSecPkgInfo SecurityPackage; - SECURITY_STATUS status; - - /* Query the security package for Digest */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), - &SecurityPackage); - - return (status == SEC_E_OK ? TRUE : FALSE); -} - -/* - * Curl_auth_create_digest_md5_message() - * - * This is used to generate an already encoded DIGEST-MD5 response message - * ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The base64 encoded challenge message. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * service [in] - The service type such as http, smtp, pop or imap. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - TCHAR *spn = NULL; - size_t chlglen = 0; - size_t token_max = 0; - unsigned char *input_token = NULL; - unsigned char *output_token = NULL; - CredHandle credentials; - CtxtHandle context; - PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - SecBuffer chlg_buf; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - /* Decode the base-64 encoded challenge message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &input_token, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!input_token) { - infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Query the security package for DigestSSP */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), - &SecurityPackage); - if(status != SEC_E_OK) { - free(input_token); - - return CURLE_NOT_BUILT_IN; - } - - token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our response buffer */ - output_token = malloc(token_max); - if(!output_token) { - free(input_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Generate our SPN */ - spn = Curl_auth_build_spn(service, data->easy_conn->host.name, NULL); - if(!spn) { - free(output_token); - free(input_token); - - return CURLE_OUT_OF_MEMORY; - } - - if(userp && *userp) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &identity); - if(result) { - free(spn); - free(output_token); - free(input_token); - - return result; - } - - /* Allow proper cleanup of the identity structure */ - p_identity = &identity; - } - else - /* Use the current Windows user */ - p_identity = NULL; - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_DIGEST), - SECPKG_CRED_OUTBOUND, NULL, - p_identity, NULL, NULL, - &credentials, &expiry); - - if(status != SEC_E_OK) { - Curl_sspi_free_identity(p_identity); - free(spn); - free(output_token); - free(input_token); - - return CURLE_LOGIN_DENIED; - } - - /* Setup the challenge "input" security buffer */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 1; - chlg_desc.pBuffers = &chlg_buf; - chlg_buf.BufferType = SECBUFFER_TOKEN; - chlg_buf.pvBuffer = input_token; - chlg_buf.cbBuffer = curlx_uztoul(chlglen); - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = output_token; - resp_buf.cbBuffer = curlx_uztoul(token_max); - - /* Generate our response message */ - status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, - 0, 0, 0, &chlg_desc, 0, - &context, &resp_desc, &attrs, - &expiry); - - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - s_pSecFn->FreeCredentialsHandle(&credentials); - Curl_sspi_free_identity(p_identity); - free(spn); - free(output_token); - free(input_token); - - return CURLE_RECV_ERROR; - } - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, - outptr, outlen); - - /* Free our handles */ - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - /* Free the identity structure */ - Curl_sspi_free_identity(p_identity); - - /* Free the SPN */ - free(spn); - - /* Free the response buffer */ - free(output_token); - - /* Free the decoded challenge message */ - free(input_token); - - return result; -} - -/* - * Curl_override_sspi_http_realm() - * - * This is used to populate the domain in a SSPI identity structure - * The realm is extracted from the challenge message and used as the - * domain if it is not already explicitly set. - * - * Parameters: - * - * chlg [in] - The challenge message. - * identity [in/out] - The identity structure. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_override_sspi_http_realm(const char *chlg, - SEC_WINNT_AUTH_IDENTITY *identity) -{ - xcharp_u domain, dup_domain; - - /* If domain is blank or unset, check challenge message for realm */ - if(!identity->Domain || !identity->DomainLength) { - for(;;) { - char value[DIGEST_MAX_VALUE_LENGTH]; - char content[DIGEST_MAX_CONTENT_LENGTH]; - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Extract a value=content pair */ - if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(strcasecompare(value, "realm")) { - - /* Setup identity's domain and length */ - domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); - if(!domain.tchar_ptr) - return CURLE_OUT_OF_MEMORY; - - dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); - if(!dup_domain.tchar_ptr) { - Curl_unicodefree(domain.tchar_ptr); - return CURLE_OUT_OF_MEMORY; - } - - free(identity->Domain); - identity->Domain = dup_domain.tbyte_ptr; - identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); - dup_domain.tchar_ptr = NULL; - - Curl_unicodefree(domain.tchar_ptr); - } - else { - /* Unknown specifier, ignore it! */ - } - } - else - break; /* We're done here */ - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Allow the list to be comma-separated */ - if(',' == *chlg) - chlg++; - } - } - - return CURLE_OK; -} - -/* - * Curl_auth_decode_digest_http_message() - * - * This is used to decode a HTTP DIGEST challenge message into the separate - * attributes. - * - * Parameters: - * - * chlg [in] - The challenge message. - * digest [in/out] - The digest data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_decode_digest_http_message(const char *chlg, - struct digestdata *digest) -{ - size_t chlglen = strlen(chlg); - - /* We had an input token before so if there's another one now that means we - provided bad credentials in the previous request or it's stale. */ - if(digest->input_token) { - bool stale = false; - const char *p = chlg; - - /* Check for the 'stale' directive */ - for(;;) { - char value[DIGEST_MAX_VALUE_LENGTH]; - char content[DIGEST_MAX_CONTENT_LENGTH]; - - while(*p && ISSPACE(*p)) - p++; - - if(!Curl_auth_digest_get_pair(p, value, content, &p)) - break; - - if(strcasecompare(value, "stale") && - strcasecompare(content, "true")) { - stale = true; - break; - } - - while(*p && ISSPACE(*p)) - p++; - - if(',' == *p) - p++; - } - - if(stale) - Curl_auth_digest_cleanup(digest); - else - return CURLE_LOGIN_DENIED; - } - - /* Store the challenge for use later */ - digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1); - if(!digest->input_token) - return CURLE_OUT_OF_MEMORY; - - digest->input_token_len = chlglen; - - return CURLE_OK; -} - -/* - * Curl_auth_create_digest_http_message() - * - * This is used to generate a HTTP DIGEST response message ready for sending - * to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * request [in] - The HTTP request. - * uripath [in] - The path of the HTTP uri. - * digest [in/out] - The digest data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uripath, - struct digestdata *digest, - char **outptr, size_t *outlen) -{ - size_t token_max; - char *resp; - BYTE *output_token; - size_t output_token_len = 0; - PSecPkgInfo SecurityPackage; - SecBuffer chlg_buf[5]; - SecBufferDesc chlg_desc; - SECURITY_STATUS status; - - (void) data; - - /* Query the security package for DigestSSP */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate the output buffer according to the max token size as indicated - by the security package */ - output_token = malloc(token_max); - if(!output_token) { - return CURLE_OUT_OF_MEMORY; - } - - /* If the user/passwd that was used to make the identity for http_context - has changed then delete that context. */ - if((userp && !digest->user) || (!userp && digest->user) || - (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || - (userp && digest->user && strcmp(userp, digest->user)) || - (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) { - if(digest->http_context) { - s_pSecFn->DeleteSecurityContext(digest->http_context); - Curl_safefree(digest->http_context); - } - Curl_safefree(digest->user); - Curl_safefree(digest->passwd); - } - - if(digest->http_context) { - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 5; - chlg_desc.pBuffers = chlg_buf; - chlg_buf[0].BufferType = SECBUFFER_TOKEN; - chlg_buf[0].pvBuffer = NULL; - chlg_buf[0].cbBuffer = 0; - chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[1].pvBuffer = (void *) request; - chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); - chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[2].pvBuffer = (void *) uripath; - chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath)); - chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[3].pvBuffer = NULL; - chlg_buf[3].cbBuffer = 0; - chlg_buf[4].BufferType = SECBUFFER_PADDING; - chlg_buf[4].pvBuffer = output_token; - chlg_buf[4].cbBuffer = curlx_uztoul(token_max); - - status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0); - if(status == SEC_E_OK) - output_token_len = chlg_buf[4].cbBuffer; - else { /* delete the context so a new one can be made */ - infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n", - (long)status); - s_pSecFn->DeleteSecurityContext(digest->http_context); - Curl_safefree(digest->http_context); - } - } - - if(!digest->http_context) { - CredHandle credentials; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - SecBuffer resp_buf; - SecBufferDesc resp_desc; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - TCHAR *spn; - - /* free the copy of user/passwd used to make the previous identity */ - Curl_safefree(digest->user); - Curl_safefree(digest->passwd); - - if(userp && *userp) { - /* Populate our identity structure */ - if(Curl_create_sspi_identity(userp, passwdp, &identity)) { - free(output_token); - return CURLE_OUT_OF_MEMORY; - } - - /* Populate our identity domain */ - if(Curl_override_sspi_http_realm((const char *) digest->input_token, - &identity)) { - free(output_token); - return CURLE_OUT_OF_MEMORY; - } - - /* Allow proper cleanup of the identity structure */ - p_identity = &identity; - } - else - /* Use the current Windows user */ - p_identity = NULL; - - if(userp) { - digest->user = strdup(userp); - - if(!digest->user) { - free(output_token); - return CURLE_OUT_OF_MEMORY; - } - } - - if(passwdp) { - digest->passwd = strdup(passwdp); - - if(!digest->passwd) { - free(output_token); - Curl_safefree(digest->user); - return CURLE_OUT_OF_MEMORY; - } - } - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_DIGEST), - SECPKG_CRED_OUTBOUND, NULL, - p_identity, NULL, NULL, - &credentials, &expiry); - if(status != SEC_E_OK) { - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_LOGIN_DENIED; - } - - /* Setup the challenge "input" security buffer if present */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 3; - chlg_desc.pBuffers = chlg_buf; - chlg_buf[0].BufferType = SECBUFFER_TOKEN; - chlg_buf[0].pvBuffer = digest->input_token; - chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); - chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[1].pvBuffer = (void *) request; - chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); - chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[2].pvBuffer = NULL; - chlg_buf[2].cbBuffer = 0; - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = output_token; - resp_buf.cbBuffer = curlx_uztoul(token_max); - - spn = Curl_convert_UTF8_to_tchar((char *) uripath); - if(!spn) { - s_pSecFn->FreeCredentialsHandle(&credentials); - - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Allocate our new context handle */ - digest->http_context = calloc(1, sizeof(CtxtHandle)); - if(!digest->http_context) - return CURLE_OUT_OF_MEMORY; - - /* Generate our response message */ - status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, - spn, - ISC_REQ_USE_HTTP_STYLE, 0, 0, - &chlg_desc, 0, - digest->http_context, - &resp_desc, &attrs, &expiry); - Curl_unicodefree(spn); - - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - s_pSecFn->FreeCredentialsHandle(&credentials); - - Curl_sspi_free_identity(p_identity); - free(output_token); - - Curl_safefree(digest->http_context); - - return CURLE_OUT_OF_MEMORY; - } - - output_token_len = resp_buf.cbBuffer; - - s_pSecFn->FreeCredentialsHandle(&credentials); - Curl_sspi_free_identity(p_identity); - } - - resp = malloc(output_token_len + 1); - if(!resp) { - free(output_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Copy the generated response */ - memcpy(resp, output_token, output_token_len); - resp[output_token_len] = 0; - - /* Return the response */ - *outptr = resp; - *outlen = output_token_len; - - /* Free the response buffer */ - free(output_token); - - return CURLE_OK; -} - -/* - * Curl_auth_digest_cleanup() - * - * This is used to clean up the digest specific data. - * - * Parameters: - * - * digest [in/out] - The digest data struct being cleaned up. - * - */ -void Curl_auth_digest_cleanup(struct digestdata *digest) -{ - /* Free the input token */ - Curl_safefree(digest->input_token); - - /* Reset any variables */ - digest->input_token_len = 0; - - /* Delete security context */ - if(digest->http_context) { - s_pSecFn->DeleteSecurityContext(digest->http_context); - Curl_safefree(digest->http_context); - } - - /* Free the copy of user/passwd used to make the identity for http_context */ - Curl_safefree(digest->user); - Curl_safefree(digest->passwd); -} - -#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/dep/cpr/opt/curl/lib/vauth/krb5_gssapi.c b/dep/cpr/opt/curl/lib/vauth/krb5_gssapi.c deleted file mode 100644 index 560ecc5bc06..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/krb5_gssapi.c +++ /dev/null @@ -1,401 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014 - 2017, Steve Holme, . - * Copyright (C) 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5) - -#include - -#include "vauth/vauth.h" -#include "curl_sasl.h" -#include "urldata.h" -#include "curl_base64.h" -#include "curl_gssapi.h" -#include "sendf.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_is_gssapi_supported() - * - * This is used to evaluate if GSSAPI (Kerberos V5) is supported. - * - * Parameters: None - * - * Returns TRUE if Kerberos V5 is supported by the GSS-API library. - */ -bool Curl_auth_is_gssapi_supported(void) -{ - return TRUE; -} - -/* - * Curl_auth_create_gssapi_user_message() - * - * This is used to generate an already encoded GSSAPI (Kerberos V5) user token - * message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * service [in] - The service type such as http, smtp, pop or imap. - * host [in[ - The host name. - * mutual_auth [in] - Flag specifying whether or not mutual authentication - * is enabled. - * chlg64 [in] - Pointer to the optional base64 encoded challenge - * message. - * krb5 [in/out] - The Kerberos 5 data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - const char *service, - const char *host, - const bool mutual_auth, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - unsigned char *chlg = NULL; - OM_uint32 major_status; - OM_uint32 minor_status; - OM_uint32 unused_status; - gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - - (void) userp; - (void) passwdp; - - if(!krb5->spn) { - /* Generate our SPN */ - char *spn = Curl_auth_build_spn(service, NULL, host); - if(!spn) - return CURLE_OUT_OF_MEMORY; - - /* Populate the SPN structure */ - spn_token.value = spn; - spn_token.length = strlen(spn); - - /* Import the SPN */ - major_status = gss_import_name(&minor_status, &spn_token, - GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, "gss_import_name() failed: ", - major_status, minor_status); - - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - free(spn); - } - - if(chlg64 && *chlg64) { - /* Decode the base-64 encoded challenge message */ - if(*chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "GSSAPI handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Setup the challenge "input" security buffer */ - input_token.value = chlg; - input_token.length = chlglen; - } - - major_status = Curl_gss_init_sec_context(data, - &minor_status, - &krb5->context, - krb5->spn, - &Curl_krb5_mech_oid, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - &output_token, - mutual_auth, - NULL); - - /* Free the decoded challenge as it is not required anymore */ - free(input_token.value); - - if(GSS_ERROR(major_status)) { - if(output_token.value) - gss_release_buffer(&unused_status, &output_token); - - Curl_gss_log_error(data, "gss_init_sec_context() failed: ", - major_status, minor_status); - - return CURLE_RECV_ERROR; - } - - if(output_token.value && output_token.length) { - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) output_token.value, - output_token.length, outptr, outlen); - - gss_release_buffer(&unused_status, &output_token); - } - else if(mutual_auth) { - *outptr = strdup(""); - if(!*outptr) - result = CURLE_OUT_OF_MEMORY; - } - - return result; -} - -/* - * Curl_auth_create_gssapi_security_message() - * - * This is used to generate an already encoded GSSAPI (Kerberos V5) security - * token message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - Pointer to the optional base64 encoded challenge message. - * krb5 [in/out] - The Kerberos 5 data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, - size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - size_t messagelen = 0; - unsigned char *chlg = NULL; - unsigned char *message = NULL; - OM_uint32 major_status; - OM_uint32 minor_status; - OM_uint32 unused_status; - gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - unsigned int indata = 0; - unsigned int outdata = 0; - gss_qop_t qop = GSS_C_QOP_DEFAULT; - unsigned int sec_layer = 0; - unsigned int max_size = 0; - gss_name_t username = GSS_C_NO_NAME; - gss_buffer_desc username_token; - - /* Decode the base-64 encoded input message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "GSSAPI handshake failure (empty security message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Get the fully qualified username back from the context */ - major_status = gss_inquire_context(&minor_status, krb5->context, - &username, NULL, NULL, NULL, NULL, - NULL, NULL); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, "gss_inquire_context() failed: ", - major_status, minor_status); - - free(chlg); - - return CURLE_OUT_OF_MEMORY; - } - - /* Convert the username from internal format to a displayable token */ - major_status = gss_display_name(&minor_status, username, - &username_token, NULL); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, "gss_display_name() failed: ", - major_status, minor_status); - - free(chlg); - - return CURLE_OUT_OF_MEMORY; - } - - /* Setup the challenge "input" security buffer */ - input_token.value = chlg; - input_token.length = chlglen; - - /* Decrypt the inbound challenge and obtain the qop */ - major_status = gss_unwrap(&minor_status, krb5->context, &input_token, - &output_token, NULL, &qop); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, "gss_unwrap() failed: ", - major_status, minor_status); - - gss_release_buffer(&unused_status, &username_token); - free(chlg); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ - if(output_token.length != 4) { - infof(data, "GSSAPI handshake failure (invalid security data)\n"); - - gss_release_buffer(&unused_status, &username_token); - free(chlg); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Copy the data out and free the challenge as it is not required anymore */ - memcpy(&indata, output_token.value, 4); - gss_release_buffer(&unused_status, &output_token); - free(chlg); - - /* Extract the security layer */ - sec_layer = indata & 0x000000FF; - if(!(sec_layer & GSSAUTH_P_NONE)) { - infof(data, "GSSAPI handshake failure (invalid security layer)\n"); - - gss_release_buffer(&unused_status, &username_token); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Extract the maximum message size the server can receive */ - max_size = ntohl(indata & 0xFFFFFF00); - if(max_size > 0) { - /* The server has told us it supports a maximum receive buffer, however, as - we don't require one unless we are encrypting data, we tell the server - our receive buffer is zero. */ - max_size = 0; - } - - /* Allocate our message */ - messagelen = sizeof(outdata) + username_token.length + 1; - message = malloc(messagelen); - if(!message) { - gss_release_buffer(&unused_status, &username_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Populate the message with the security layer, client supported receive - message size and authorization identity including the 0x00 based - terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization - identity is not terminated with the zero-valued (%x00) octet." it seems - necessary to include it. */ - outdata = htonl(max_size) | sec_layer; - memcpy(message, &outdata, sizeof(outdata)); - memcpy(message + sizeof(outdata), username_token.value, - username_token.length); - message[messagelen - 1] = '\0'; - - /* Free the username token as it is not required anymore */ - gss_release_buffer(&unused_status, &username_token); - - /* Setup the "authentication data" security buffer */ - input_token.value = message; - input_token.length = messagelen; - - /* Encrypt the data */ - major_status = gss_wrap(&minor_status, krb5->context, 0, - GSS_C_QOP_DEFAULT, &input_token, NULL, - &output_token); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, "gss_wrap() failed: ", - major_status, minor_status); - - free(message); - - return CURLE_OUT_OF_MEMORY; - } - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) output_token.value, - output_token.length, outptr, outlen); - - /* Free the output buffer */ - gss_release_buffer(&unused_status, &output_token); - - /* Free the message buffer */ - free(message); - - return result; -} - -/* - * Curl_auth_gssapi_cleanup() - * - * This is used to clean up the GSSAPI (Kerberos V5) specific data. - * - * Parameters: - * - * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. - * - */ -void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5) -{ - OM_uint32 minor_status; - - /* Free our security context */ - if(krb5->context != GSS_C_NO_CONTEXT) { - gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER); - krb5->context = GSS_C_NO_CONTEXT; - } - - /* Free the SPN */ - if(krb5->spn != GSS_C_NO_NAME) { - gss_release_name(&minor_status, &krb5->spn); - krb5->spn = GSS_C_NO_NAME; - } -} - -#endif /* HAVE_GSSAPI && USE_KERBEROS5 */ diff --git a/dep/cpr/opt/curl/lib/vauth/krb5_sspi.c b/dep/cpr/opt/curl/lib/vauth/krb5_sspi.c deleted file mode 100644 index 1b4cef486db..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/krb5_sspi.c +++ /dev/null @@ -1,518 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014 - 2017, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5) - -#include - -#include "vauth/vauth.h" -#include "urldata.h" -#include "curl_base64.h" -#include "warnless.h" -#include "curl_multibyte.h" -#include "sendf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_is_gssapi_supported() - * - * This is used to evaluate if GSSAPI (Kerberos V5) is supported. - * - * Parameters: None - * - * Returns TRUE if Kerberos V5 is supported by Windows SSPI. - */ -bool Curl_auth_is_gssapi_supported(void) -{ - PSecPkgInfo SecurityPackage; - SECURITY_STATUS status; - - /* Query the security package for Kerberos */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) - TEXT(SP_NAME_KERBEROS), - &SecurityPackage); - - return (status == SEC_E_OK ? TRUE : FALSE); -} - -/* - * Curl_auth_create_gssapi_user_message() - * - * This is used to generate an already encoded GSSAPI (Kerberos V5) user token - * message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * service [in] - The service type such as http, smtp, pop or imap. - * host [in] - The host name. - * mutual_auth [in] - Flag specifying whether or not mutual authentication - * is enabled. - * chlg64 [in] - The optional base64 encoded challenge message. - * krb5 [in/out] - The Kerberos 5 data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - const char *service, - const char *host, - const bool mutual_auth, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - unsigned char *chlg = NULL; - CtxtHandle context; - PSecPkgInfo SecurityPackage; - SecBuffer chlg_buf; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - if(!krb5->spn) { - /* Generate our SPN */ - krb5->spn = Curl_auth_build_spn(service, host, NULL); - if(!krb5->spn) - return CURLE_OUT_OF_MEMORY; - } - - if(!krb5->output_token) { - /* Query the security package for Kerberos */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) - TEXT(SP_NAME_KERBEROS), - &SecurityPackage); - if(status != SEC_E_OK) { - return CURLE_NOT_BUILT_IN; - } - - krb5->token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our response buffer */ - krb5->output_token = malloc(krb5->token_max); - if(!krb5->output_token) - return CURLE_OUT_OF_MEMORY; - } - - if(!krb5->credentials) { - /* Do we have credientials to use or are we using single sign-on? */ - if(userp && *userp) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - krb5->p_identity = &krb5->identity; - } - else - /* Use the current Windows user */ - krb5->p_identity = NULL; - - /* Allocate our credentials handle */ - krb5->credentials = malloc(sizeof(CredHandle)); - if(!krb5->credentials) - return CURLE_OUT_OF_MEMORY; - - memset(krb5->credentials, 0, sizeof(CredHandle)); - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) - TEXT(SP_NAME_KERBEROS), - SECPKG_CRED_OUTBOUND, NULL, - krb5->p_identity, NULL, NULL, - krb5->credentials, &expiry); - if(status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - - /* Allocate our new context handle */ - krb5->context = malloc(sizeof(CtxtHandle)); - if(!krb5->context) - return CURLE_OUT_OF_MEMORY; - - memset(krb5->context, 0, sizeof(CtxtHandle)); - } - - if(chlg64 && *chlg64) { - /* Decode the base-64 encoded challenge message */ - if(*chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "GSSAPI handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Setup the challenge "input" security buffer */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 1; - chlg_desc.pBuffers = &chlg_buf; - chlg_buf.BufferType = SECBUFFER_TOKEN; - chlg_buf.pvBuffer = chlg; - chlg_buf.cbBuffer = curlx_uztoul(chlglen); - } - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = krb5->output_token; - resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); - - /* Generate our challenge-response message */ - status = s_pSecFn->InitializeSecurityContext(krb5->credentials, - chlg ? krb5->context : NULL, - krb5->spn, - (mutual_auth ? - ISC_REQ_MUTUAL_AUTH : 0), - 0, SECURITY_NATIVE_DREP, - chlg ? &chlg_desc : NULL, 0, - &context, - &resp_desc, &attrs, - &expiry); - - /* Free the decoded challenge as it is not required anymore */ - free(chlg); - - if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - return CURLE_RECV_ERROR; - } - - if(memcmp(&context, krb5->context, sizeof(context))) { - s_pSecFn->DeleteSecurityContext(krb5->context); - - memcpy(krb5->context, &context, sizeof(context)); - } - - if(resp_buf.cbBuffer) { - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) resp_buf.pvBuffer, - resp_buf.cbBuffer, outptr, outlen); - } - else if(mutual_auth) { - *outptr = strdup(""); - if(!*outptr) - result = CURLE_OUT_OF_MEMORY; - } - - return result; -} - -/* - * Curl_auth_create_gssapi_security_message() - * - * This is used to generate an already encoded GSSAPI (Kerberos V5) security - * token message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The optional base64 encoded challenge message. - * krb5 [in/out] - The Kerberos 5 data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, - size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t offset = 0; - size_t chlglen = 0; - size_t messagelen = 0; - size_t appdatalen = 0; - unsigned char *chlg = NULL; - unsigned char *trailer = NULL; - unsigned char *message = NULL; - unsigned char *padding = NULL; - unsigned char *appdata = NULL; - SecBuffer input_buf[2]; - SecBuffer wrap_buf[3]; - SecBufferDesc input_desc; - SecBufferDesc wrap_desc; - unsigned long indata = 0; - unsigned long outdata = 0; - unsigned long qop = 0; - unsigned long sec_layer = 0; - unsigned long max_size = 0; - SecPkgContext_Sizes sizes; - SecPkgCredentials_Names names; - SECURITY_STATUS status; - char *user_name; - - /* Decode the base-64 encoded input message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "GSSAPI handshake failure (empty security message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Get our response size information */ - status = s_pSecFn->QueryContextAttributes(krb5->context, - SECPKG_ATTR_SIZES, - &sizes); - if(status != SEC_E_OK) { - free(chlg); - - return CURLE_OUT_OF_MEMORY; - } - - /* Get the fully qualified username back from the context */ - status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, - SECPKG_CRED_ATTR_NAMES, - &names); - if(status != SEC_E_OK) { - free(chlg); - - return CURLE_RECV_ERROR; - } - - /* Setup the "input" security buffer */ - input_desc.ulVersion = SECBUFFER_VERSION; - input_desc.cBuffers = 2; - input_desc.pBuffers = input_buf; - input_buf[0].BufferType = SECBUFFER_STREAM; - input_buf[0].pvBuffer = chlg; - input_buf[0].cbBuffer = curlx_uztoul(chlglen); - input_buf[1].BufferType = SECBUFFER_DATA; - input_buf[1].pvBuffer = NULL; - input_buf[1].cbBuffer = 0; - - /* Decrypt the inbound challenge and obtain the qop */ - status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); - if(status != SEC_E_OK) { - infof(data, "GSSAPI handshake failure (empty security message)\n"); - - free(chlg); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ - if(input_buf[1].cbBuffer != 4) { - infof(data, "GSSAPI handshake failure (invalid security data)\n"); - - free(chlg); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Copy the data out and free the challenge as it is not required anymore */ - memcpy(&indata, input_buf[1].pvBuffer, 4); - s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); - free(chlg); - - /* Extract the security layer */ - sec_layer = indata & 0x000000FF; - if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { - infof(data, "GSSAPI handshake failure (invalid security layer)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Extract the maximum message size the server can receive */ - max_size = ntohl(indata & 0xFFFFFF00); - if(max_size > 0) { - /* The server has told us it supports a maximum receive buffer, however, as - we don't require one unless we are encrypting data, we tell the server - our receive buffer is zero. */ - max_size = 0; - } - - /* Allocate the trailer */ - trailer = malloc(sizes.cbSecurityTrailer); - if(!trailer) - return CURLE_OUT_OF_MEMORY; - - /* Convert the user name to UTF8 when operating with Unicode */ - user_name = Curl_convert_tchar_to_UTF8(names.sUserName); - if(!user_name) { - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Allocate our message */ - messagelen = sizeof(outdata) + strlen(user_name) + 1; - message = malloc(messagelen); - if(!message) { - free(trailer); - Curl_unicodefree(user_name); - - return CURLE_OUT_OF_MEMORY; - } - - /* Populate the message with the security layer, client supported receive - message size and authorization identity including the 0x00 based - terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization - identity is not terminated with the zero-valued (%x00) octet." it seems - necessary to include it. */ - outdata = htonl(max_size) | sec_layer; - memcpy(message, &outdata, sizeof(outdata)); - strcpy((char *) message + sizeof(outdata), user_name); - Curl_unicodefree(user_name); - - /* Allocate the padding */ - padding = malloc(sizes.cbBlockSize); - if(!padding) { - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Setup the "authentication data" security buffer */ - wrap_desc.ulVersion = SECBUFFER_VERSION; - wrap_desc.cBuffers = 3; - wrap_desc.pBuffers = wrap_buf; - wrap_buf[0].BufferType = SECBUFFER_TOKEN; - wrap_buf[0].pvBuffer = trailer; - wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; - wrap_buf[1].BufferType = SECBUFFER_DATA; - wrap_buf[1].pvBuffer = message; - wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); - wrap_buf[2].BufferType = SECBUFFER_PADDING; - wrap_buf[2].pvBuffer = padding; - wrap_buf[2].cbBuffer = sizes.cbBlockSize; - - /* Encrypt the data */ - status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, - &wrap_desc, 0); - if(status != SEC_E_OK) { - free(padding); - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Allocate the encryption (wrap) buffer */ - appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + - wrap_buf[2].cbBuffer; - appdata = malloc(appdatalen); - if(!appdata) { - free(padding); - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Populate the encryption buffer */ - memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); - offset += wrap_buf[0].cbBuffer; - memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); - offset += wrap_buf[1].cbBuffer; - memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) appdata, appdatalen, outptr, - outlen); - - /* Free all of our local buffers */ - free(appdata); - free(padding); - free(message); - free(trailer); - - return result; -} - -/* - * Curl_auth_gssapi_cleanup() - * - * This is used to clean up the GSSAPI (Kerberos V5) specific data. - * - * Parameters: - * - * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. - * - */ -void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5) -{ - /* Free our security context */ - if(krb5->context) { - s_pSecFn->DeleteSecurityContext(krb5->context); - free(krb5->context); - krb5->context = NULL; - } - - /* Free our credentials handle */ - if(krb5->credentials) { - s_pSecFn->FreeCredentialsHandle(krb5->credentials); - free(krb5->credentials); - krb5->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(krb5->p_identity); - krb5->p_identity = NULL; - - /* Free the SPN and output token */ - Curl_safefree(krb5->spn); - Curl_safefree(krb5->output_token); - - /* Reset any variables */ - krb5->token_max = 0; -} - -#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5*/ diff --git a/dep/cpr/opt/curl/lib/vauth/ntlm.c b/dep/cpr/opt/curl/lib/vauth/ntlm.c deleted file mode 100644 index 50d922208b6..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/ntlm.c +++ /dev/null @@ -1,860 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) - -/* - * NTLM details: - * - * https://davenport.sourceforge.io/ntlm.html - * https://www.innovation.ch/java/ntlm.html - */ - -#define DEBUG_ME 0 - -#include "urldata.h" -#include "non-ascii.h" -#include "sendf.h" -#include "curl_base64.h" -#include "curl_ntlm_core.h" -#include "curl_gethostname.h" -#include "curl_multibyte.h" -#include "warnless.h" -#include "rand.h" -#include "vtls/vtls.h" - -/* SSL backend-specific #if branches in this file must be kept in the order - documented in curl_ntlm_core. */ -#if defined(NTLM_NEEDS_NSS_INIT) -#include "vtls/nssg.h" /* for Curl_nss_force_init() */ -#endif - -#define BUILDING_CURL_NTLM_MSGS_C -#include "vauth/vauth.h" -#include "vauth/ntlm.h" -#include "curl_endian.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* "NTLMSSP" signature is always in ASCII regardless of the platform */ -#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" - -#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) -#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \ - (((x) >> 16) & 0xff), (((x) >> 24) & 0xff) - -#if DEBUG_ME -# define DEBUG_OUT(x) x -static void ntlm_print_flags(FILE *handle, unsigned long flags) -{ - if(flags & NTLMFLAG_NEGOTIATE_UNICODE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); - if(flags & NTLMFLAG_NEGOTIATE_OEM) - fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); - if(flags & NTLMFLAG_REQUEST_TARGET) - fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); - if(flags & (1<<3)) - fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); - if(flags & NTLMFLAG_NEGOTIATE_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); - if(flags & NTLMFLAG_NEGOTIATE_SEAL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); - if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); - if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); - if(flags & NTLMFLAG_NEGOTIATE_NETWARE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); - if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); - if(flags & (1<<10)) - fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); - if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); - if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); - if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); - if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); - if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); - if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); - if(flags & NTLMFLAG_TARGET_TYPE_SERVER) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); - if(flags & NTLMFLAG_TARGET_TYPE_SHARE) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); - if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); - if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); - if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); - if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) - fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); - if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) - fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); - if(flags & (1<<24)) - fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); - if(flags & (1<<25)) - fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); - if(flags & (1<<26)) - fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); - if(flags & (1<<27)) - fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); - if(flags & (1<<28)) - fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); - if(flags & NTLMFLAG_NEGOTIATE_128) - fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); - if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); - if(flags & NTLMFLAG_NEGOTIATE_56) - fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); -} - -static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) -{ - const char *p = buf; - - (void) handle; - - fprintf(stderr, "0x"); - while(len-- > 0) - fprintf(stderr, "%02.2x", (unsigned int)*p++); -} -#else -# define DEBUG_OUT(x) Curl_nop_stmt -#endif - -/* - * ntlm_decode_type2_target() - * - * This is used to decode the "target info" in the NTLM type-2 message - * received. - * - * Parameters: - * - * data [in] - The session handle. - * buffer [in] - The decoded type-2 message. - * size [in] - The input buffer size, at least 32 bytes. - * ntlm [in/out] - The NTLM data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, - unsigned char *buffer, - size_t size, - struct ntlmdata *ntlm) -{ - unsigned short target_info_len = 0; - unsigned int target_info_offset = 0; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - if(size >= 48) { - target_info_len = Curl_read16_le(&buffer[40]); - target_info_offset = Curl_read32_le(&buffer[44]); - if(target_info_len > 0) { - if(((target_info_offset + target_info_len) > size) || - (target_info_offset < 48)) { - infof(data, "NTLM handshake failure (bad type-2 message). " - "Target Info Offset Len is set incorrect by the peer\n"); - return CURLE_BAD_CONTENT_ENCODING; - } - - ntlm->target_info = malloc(target_info_len); - if(!ntlm->target_info) - return CURLE_OUT_OF_MEMORY; - - memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len); - } - } - - ntlm->target_info_len = target_info_len; - - return CURLE_OK; -} - -/* - NTLM message structure notes: - - A 'short' is a 'network short', a little-endian 16-bit unsigned value. - - A 'long' is a 'network long', a little-endian, 32-bit unsigned value. - - A 'security buffer' represents a triplet used to point to a buffer, - consisting of two shorts and one long: - - 1. A 'short' containing the length of the buffer content in bytes. - 2. A 'short' containing the allocated space for the buffer in bytes. - 3. A 'long' containing the offset to the start of the buffer in bytes, - from the beginning of the NTLM message. -*/ - -/* - * Curl_auth_is_ntlm_supported() - * - * This is used to evaluate if NTLM is supported. - * - * Parameters: None - * - * Returns TRUE as NTLM as handled by libcurl. - */ -bool Curl_auth_is_ntlm_supported(void) -{ - return TRUE; -} - -/* - * Curl_auth_decode_ntlm_type2_message() - * - * This is used to decode an already encoded NTLM type-2 message. The message - * is first decoded from a base64 string into a raw NTLM message and checked - * for validity before the appropriate data for creating a type-3 message is - * written to the given NTLM data structure. - * - * Parameters: - * - * data [in] - The session handle. - * type2msg [in] - The base64 encoded type-2 message. - * ntlm [in/out] - The NTLM data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, - const char *type2msg, - struct ntlmdata *ntlm) -{ - static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; - - /* NTLM type-2 message structure: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x02000000) - 12 Target Name security buffer - 20 Flags long - 24 Challenge 8 bytes - (32) Context 8 bytes (two consecutive longs) (*) - (40) Target Information security buffer (*) - (48) OS Version Structure 8 bytes (*) - 32 (48) (56) Start of data block (*) - (*) -> Optional - */ - - CURLcode result = CURLE_OK; - unsigned char *type2 = NULL; - size_t type2_len = 0; - -#if defined(NTLM_NEEDS_NSS_INIT) - /* Make sure the crypto backend is initialized */ - result = Curl_nss_force_init(data); - if(result) - return result; -#elif defined(CURL_DISABLE_VERBOSE_STRINGS) - (void)data; -#endif - - /* Decode the base-64 encoded type-2 message */ - if(strlen(type2msg) && *type2msg != '=') { - result = Curl_base64_decode(type2msg, &type2, &type2_len); - if(result) - return result; - } - - /* Ensure we have a valid type-2 message */ - if(!type2) { - infof(data, "NTLM handshake failure (empty type-2 message)\n"); - return CURLE_BAD_CONTENT_ENCODING; - } - - ntlm->flags = 0; - - if((type2_len < 32) || - (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) || - (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) { - /* This was not a good enough type-2 message */ - free(type2); - infof(data, "NTLM handshake failure (bad type-2 message)\n"); - return CURLE_BAD_CONTENT_ENCODING; - } - - ntlm->flags = Curl_read32_le(&type2[20]); - memcpy(ntlm->nonce, &type2[24], 8); - - if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) { - result = ntlm_decode_type2_target(data, type2, type2_len, ntlm); - if(result) { - free(type2); - infof(data, "NTLM handshake failure (bad type-2 message)\n"); - return result; - } - } - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); - ntlm_print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n nonce="); - ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); - fprintf(stderr, "\n****\n"); - fprintf(stderr, "**** Header %s\n ", header); - }); - - free(type2); - - return result; -} - -/* copy the source to the destination and fill in zeroes in every - other destination byte! */ -static void unicodecpy(unsigned char *dest, const char *src, size_t length) -{ - size_t i; - for(i = 0; i < length; i++) { - dest[2 * i] = (unsigned char)src[i]; - dest[2 * i + 1] = '\0'; - } -} - -/* - * Curl_auth_create_ntlm_type1_message() - * - * This is used to generate an already encoded NTLM type-1 message ready for - * sending to the recipient using the appropriate compile time crypto API. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * ntlm [in/out] - The NTLM data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) -{ - /* NTLM type-1 message structure: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x01000000) - 12 Flags long - (16) Supplied Domain security buffer (*) - (24) Supplied Workstation security buffer (*) - (32) OS Version Structure 8 bytes (*) - (32) (40) Start of data block (*) - (*) -> Optional - */ - - size_t size; - - unsigned char ntlmbuf[NTLM_BUFSIZE]; - const char *host = ""; /* empty */ - const char *domain = ""; /* empty */ - size_t hostlen = 0; - size_t domlen = 0; - size_t hostoff = 0; - size_t domoff = hostoff + hostlen; /* This is 0: remember that host and - domain are empty */ - (void)userp; - (void)passwdp; - - /* Clean up any former leftovers and initialise to defaults */ - Curl_auth_ntlm_cleanup(ntlm); - -#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION) -#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY -#else -#define NTLM2FLAG 0 -#endif - snprintf((char *)ntlmbuf, NTLM_BUFSIZE, - NTLMSSP_SIGNATURE "%c" - "\x01%c%c%c" /* 32-bit type = 1 */ - "%c%c%c%c" /* 32-bit NTLM flag field */ - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host name offset */ - "%c%c" /* 2 zeroes */ - "%s" /* host name */ - "%s", /* domain string */ - 0, /* trailing zero */ - 0, 0, 0, /* part of type-1 long */ - - LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | - NTLMFLAG_REQUEST_TARGET | - NTLMFLAG_NEGOTIATE_NTLM_KEY | - NTLM2FLAG | - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0, 0, - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0, 0, - host, /* this is empty */ - domain /* this is empty */); - - /* Initial packet length */ - size = 32 + hostlen + domlen; - - DEBUG_OUT({ - fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " - "0x%08.8x ", - LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | - NTLMFLAG_REQUEST_TARGET | - NTLMFLAG_NEGOTIATE_NTLM_KEY | - NTLM2FLAG | - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - NTLMFLAG_NEGOTIATE_OEM | - NTLMFLAG_REQUEST_TARGET | - NTLMFLAG_NEGOTIATE_NTLM_KEY | - NTLM2FLAG | - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - ntlm_print_flags(stderr, - NTLMFLAG_NEGOTIATE_OEM | - NTLMFLAG_REQUEST_TARGET | - NTLMFLAG_NEGOTIATE_NTLM_KEY | - NTLM2FLAG | - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - fprintf(stderr, "\n****\n"); - }); - - /* Return with binary blob encoded into base64 */ - return Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen); -} - -/* - * Curl_auth_create_ntlm_type3_message() - * - * This is used to generate an already encoded NTLM type-3 message ready for - * sending to the recipient using the appropriate compile time crypto API. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * ntlm [in/out] - The NTLM data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) - -{ - /* NTLM type-3 message structure: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x03000000) - 12 LM/LMv2 Response security buffer - 20 NTLM/NTLMv2 Response security buffer - 28 Target Name security buffer - 36 User Name security buffer - 44 Workstation Name security buffer - (52) Session Key security buffer (*) - (60) Flags long (*) - (64) OS Version Structure 8 bytes (*) - 52 (64) (72) Start of data block - (*) -> Optional - */ - - CURLcode result = CURLE_OK; - size_t size; - unsigned char ntlmbuf[NTLM_BUFSIZE]; - int lmrespoff; - unsigned char lmresp[24]; /* fixed-size */ -#ifdef USE_NTRESPONSES - int ntrespoff; - unsigned int ntresplen = 24; - unsigned char ntresp[24]; /* fixed-size */ - unsigned char *ptr_ntresp = &ntresp[0]; - unsigned char *ntlmv2resp = NULL; -#endif - bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE; - char host[HOSTNAME_MAX + 1] = ""; - const char *user; - const char *domain = ""; - size_t hostoff = 0; - size_t useroff = 0; - size_t domoff = 0; - size_t hostlen = 0; - size_t userlen = 0; - size_t domlen = 0; - - user = strchr(userp, '\\'); - if(!user) - user = strchr(userp, '/'); - - if(user) { - domain = userp; - domlen = (user - domain); - user++; - } - else - user = userp; - - if(user) - userlen = strlen(user); - - /* Get the machine's un-qualified host name as NTLM doesn't like the fully - qualified domain name */ - if(Curl_gethostname(host, sizeof(host))) { - infof(data, "gethostname() failed, continuing without!\n"); - hostlen = 0; - } - else { - hostlen = strlen(host); - } - -#if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2) - if(ntlm->target_info_len) { - unsigned char ntbuffer[0x18]; - unsigned char entropy[8]; - unsigned char ntlmv2hash[0x18]; - - result = Curl_rand(data, entropy, 8); - if(result) - return result; - - result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); - if(result) - return result; - - result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen, - ntbuffer, ntlmv2hash); - if(result) - return result; - - /* LMv2 response */ - result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy, - &ntlm->nonce[0], lmresp); - if(result) - return result; - - /* NTLMv2 response */ - result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy, - ntlm, &ntlmv2resp, &ntresplen); - if(result) - return result; - - ptr_ntresp = ntlmv2resp; - } - else -#endif - -#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION) - /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ - if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { - unsigned char ntbuffer[0x18]; - unsigned char tmp[0x18]; - unsigned char md5sum[MD5_DIGEST_LENGTH]; - unsigned char entropy[8]; - - /* Need to create 8 bytes random data */ - result = Curl_rand(data, entropy, 8); - if(result) - return result; - - /* 8 bytes random data as challenge in lmresp */ - memcpy(lmresp, entropy, 8); - - /* Pad with zeros */ - memset(lmresp + 8, 0, 0x10); - - /* Fill tmp with challenge(nonce?) + entropy */ - memcpy(tmp, &ntlm->nonce[0], 8); - memcpy(tmp + 8, entropy, 8); - - result = Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH); - if(!result) - /* We shall only use the first 8 bytes of md5sum, but the des code in - Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ - result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); - if(result) - return result; - - Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); - - /* End of NTLM2 Session code */ - - } - else -#endif - { - -#ifdef USE_NTRESPONSES - unsigned char ntbuffer[0x18]; -#endif - unsigned char lmbuffer[0x18]; - -#ifdef USE_NTRESPONSES - result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); - if(result) - return result; - - Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); -#endif - - result = Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); - if(result) - return result; - - Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); - - /* A safer but less compatible alternative is: - * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */ - } - - if(unicode) { - domlen = domlen * 2; - userlen = userlen * 2; - hostlen = hostlen * 2; - } - - lmrespoff = 64; /* size of the message header */ -#ifdef USE_NTRESPONSES - ntrespoff = lmrespoff + 0x18; - domoff = ntrespoff + ntresplen; -#else - domoff = lmrespoff + 0x18; -#endif - useroff = domoff + domlen; - hostoff = useroff + userlen; - - /* Create the big type-3 message binary blob */ - size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE, - NTLMSSP_SIGNATURE "%c" - "\x03%c%c%c" /* 32-bit type = 3 */ - - "%c%c" /* LanManager length */ - "%c%c" /* LanManager allocated space */ - "%c%c" /* LanManager offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* NT-response length */ - "%c%c" /* NT-response allocated space */ - "%c%c" /* NT-response offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* user length */ - "%c%c" /* user allocated space */ - "%c%c" /* user offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* session key length (unknown purpose) */ - "%c%c" /* session key allocated space (unknown purpose) */ - "%c%c" /* session key offset (unknown purpose) */ - "%c%c" /* 2 zeroes */ - - "%c%c%c%c", /* flags */ - - /* domain string */ - /* user string */ - /* host string */ - /* LanManager response */ - /* NT response */ - - 0, /* zero termination */ - 0, 0, 0, /* type-3 long, the 24 upper bits */ - - SHORTPAIR(0x18), /* LanManager response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(lmrespoff), - 0x0, 0x0, - -#ifdef USE_NTRESPONSES - SHORTPAIR(ntresplen), /* NT-response length, twice */ - SHORTPAIR(ntresplen), - SHORTPAIR(ntrespoff), - 0x0, 0x0, -#else - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, -#endif - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0x0, 0x0, - - SHORTPAIR(userlen), - SHORTPAIR(userlen), - SHORTPAIR(useroff), - 0x0, 0x0, - - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0x0, 0x0, - - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - - LONGQUARTET(ntlm->flags)); - - DEBUGASSERT(size == 64); - DEBUGASSERT(size == (size_t)lmrespoff); - - /* We append the binary hashes */ - if(size < (NTLM_BUFSIZE - 0x18)) { - memcpy(&ntlmbuf[size], lmresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE3 header lmresp="); - ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); - }); - -#ifdef USE_NTRESPONSES - if(size < (NTLM_BUFSIZE - ntresplen)) { - DEBUGASSERT(size == (size_t)ntrespoff); - memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen); - size += ntresplen; - } - - DEBUG_OUT({ - fprintf(stderr, "\n ntresp="); - ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen); - }); - - free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ - -#endif - - DEBUG_OUT({ - fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", - LONGQUARTET(ntlm->flags), ntlm->flags); - ntlm_print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n****\n"); - }); - - /* Make sure that the domain, user and host strings fit in the - buffer before we copy them there. */ - if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) { - failf(data, "user + domain + host name too big"); - return CURLE_OUT_OF_MEMORY; - } - - DEBUGASSERT(size == domoff); - if(unicode) - unicodecpy(&ntlmbuf[size], domain, domlen / 2); - else - memcpy(&ntlmbuf[size], domain, domlen); - - size += domlen; - - DEBUGASSERT(size == useroff); - if(unicode) - unicodecpy(&ntlmbuf[size], user, userlen / 2); - else - memcpy(&ntlmbuf[size], user, userlen); - - size += userlen; - - DEBUGASSERT(size == hostoff); - if(unicode) - unicodecpy(&ntlmbuf[size], host, hostlen / 2); - else - memcpy(&ntlmbuf[size], host, hostlen); - - size += hostlen; - - /* Convert domain, user, and host to ASCII but leave the rest as-is */ - result = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], - size - domoff); - if(result) - return CURLE_CONV_FAILED; - - /* Return with binary blob encoded into base64 */ - result = Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen); - - Curl_auth_ntlm_cleanup(ntlm); - - return result; -} - -/* -* Curl_auth_ntlm_cleanup() -* -* This is used to clean up the NTLM specific data. -* -* Parameters: -* -* ntlm [in/out] - The NTLM data struct being cleaned up. -* -*/ -void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm) -{ - /* Free the target info */ - Curl_safefree(ntlm->target_info); - - /* Reset any variables */ - ntlm->target_info_len = 0; -} - -#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ diff --git a/dep/cpr/opt/curl/lib/vauth/ntlm.h b/dep/cpr/opt/curl/lib/vauth/ntlm.h deleted file mode 100644 index f906a3c7a7c..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/ntlm.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef HEADER_CURL_NTLM_H -#define HEADER_CURL_NTLM_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_NTLM - -/* NTLM buffer fixed size, large enough for long user + host + domain */ -#define NTLM_BUFSIZE 1024 - -/* Stuff only required for curl_ntlm_msgs.c */ -#ifdef BUILDING_CURL_NTLM_MSGS_C - -/* Flag bits definitions based on https://davenport.sourceforge.io/ntlm.html */ - -#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) -/* Indicates that Unicode strings are supported for use in security buffer - data. */ - -#define NTLMFLAG_NEGOTIATE_OEM (1<<1) -/* Indicates that OEM strings are supported for use in security buffer data. */ - -#define NTLMFLAG_REQUEST_TARGET (1<<2) -/* Requests that the server's authentication realm be included in the Type 2 - message. */ - -/* unknown (1<<3) */ -#define NTLMFLAG_NEGOTIATE_SIGN (1<<4) -/* Specifies that authenticated communication between the client and server - should carry a digital signature (message integrity). */ - -#define NTLMFLAG_NEGOTIATE_SEAL (1<<5) -/* Specifies that authenticated communication between the client and server - should be encrypted (message confidentiality). */ - -#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6) -/* Indicates that datagram authentication is being used. */ - -#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7) -/* Indicates that the LAN Manager session key should be used for signing and - sealing authenticated communications. */ - -#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8) -/* unknown purpose */ - -#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9) -/* Indicates that NTLM authentication is being used. */ - -/* unknown (1<<10) */ - -#define NTLMFLAG_NEGOTIATE_ANONYMOUS (1<<11) -/* Sent by the client in the Type 3 message to indicate that an anonymous - context has been established. This also affects the response fields. */ - -#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12) -/* Sent by the client in the Type 1 message to indicate that a desired - authentication realm is included in the message. */ - -#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13) -/* Sent by the client in the Type 1 message to indicate that the client - workstation's name is included in the message. */ - -#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14) -/* Sent by the server to indicate that the server and client are on the same - machine. Implies that the client may use a pre-established local security - context rather than responding to the challenge. */ - -#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15) -/* Indicates that authenticated communication between the client and server - should be signed with a "dummy" signature. */ - -#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16) -/* Sent by the server in the Type 2 message to indicate that the target - authentication realm is a domain. */ - -#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17) -/* Sent by the server in the Type 2 message to indicate that the target - authentication realm is a server. */ - -#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18) -/* Sent by the server in the Type 2 message to indicate that the target - authentication realm is a share. Presumably, this is for share-level - authentication. Usage is unclear. */ - -#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19) -/* Indicates that the NTLM2 signing and sealing scheme should be used for - protecting authenticated communications. */ - -#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20) -/* unknown purpose */ - -#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21) -/* unknown purpose */ - -#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22) -/* unknown purpose */ - -#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23) -/* Sent by the server in the Type 2 message to indicate that it is including a - Target Information block in the message. */ - -/* unknown (1<24) */ -/* unknown (1<25) */ -/* unknown (1<26) */ -/* unknown (1<27) */ -/* unknown (1<28) */ - -#define NTLMFLAG_NEGOTIATE_128 (1<<29) -/* Indicates that 128-bit encryption is supported. */ - -#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30) -/* Indicates that the client will provide an encrypted master key in - the "Session Key" field of the Type 3 message. */ - -#define NTLMFLAG_NEGOTIATE_56 (1<<31) -/* Indicates that 56-bit encryption is supported. */ - -#endif /* BUILDING_CURL_NTLM_MSGS_C */ - -#endif /* USE_NTLM */ - -#endif /* HEADER_CURL_NTLM_H */ diff --git a/dep/cpr/opt/curl/lib/vauth/ntlm_sspi.c b/dep/cpr/opt/curl/lib/vauth/ntlm_sspi.c deleted file mode 100644 index e748ce3b677..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/ntlm_sspi.c +++ /dev/null @@ -1,338 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM) - -#include - -#include "vauth/vauth.h" -#include "urldata.h" -#include "curl_base64.h" -#include "curl_ntlm_core.h" -#include "warnless.h" -#include "curl_multibyte.h" -#include "sendf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_is_ntlm_supported() - * - * This is used to evaluate if NTLM is supported. - * - * Parameters: None - * - * Returns TRUE if NTLM is supported by Windows SSPI. - */ -bool Curl_auth_is_ntlm_supported(void) -{ - PSecPkgInfo SecurityPackage; - SECURITY_STATUS status; - - /* Query the security package for NTLM */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), - &SecurityPackage); - - return (status == SEC_E_OK ? TRUE : FALSE); -} - -/* - * Curl_auth_create_ntlm_type1_message() - * - * This is used to generate an already encoded NTLM type-1 message ready for - * sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * ntlm [in/out] - The NTLM data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) -{ - PSecPkgInfo SecurityPackage; - SecBuffer type_1_buf; - SecBufferDesc type_1_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - /* Clean up any former leftovers and initialise to defaults */ - Curl_auth_ntlm_cleanup(ntlm); - - /* Query the security package for NTLM */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - ntlm->token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our output buffer */ - ntlm->output_token = malloc(ntlm->token_max); - if(!ntlm->output_token) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - CURLcode result; - - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - ntlm->p_identity = &ntlm->identity; - } - else - /* Use the current Windows user */ - ntlm->p_identity = NULL; - - /* Allocate our credentials handle */ - ntlm->credentials = malloc(sizeof(CredHandle)); - if(!ntlm->credentials) - return CURLE_OUT_OF_MEMORY; - - memset(ntlm->credentials, 0, sizeof(CredHandle)); - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_NTLM), - SECPKG_CRED_OUTBOUND, NULL, - ntlm->p_identity, NULL, NULL, - ntlm->credentials, &expiry); - if(status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - - /* Allocate our new context handle */ - ntlm->context = malloc(sizeof(CtxtHandle)); - if(!ntlm->context) - return CURLE_OUT_OF_MEMORY; - - memset(ntlm->context, 0, sizeof(CtxtHandle)); - - /* Setup the type-1 "output" security buffer */ - type_1_desc.ulVersion = SECBUFFER_VERSION; - type_1_desc.cBuffers = 1; - type_1_desc.pBuffers = &type_1_buf; - type_1_buf.BufferType = SECBUFFER_TOKEN; - type_1_buf.pvBuffer = ntlm->output_token; - type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); - - /* Generate our type-1 message */ - status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, - (TCHAR *) TEXT(""), - 0, 0, SECURITY_NETWORK_DREP, - NULL, 0, - ntlm->context, &type_1_desc, - &attrs, &expiry); - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) - return CURLE_RECV_ERROR; - - /* Base64 encode the response */ - return Curl_base64_encode(data, (char *) ntlm->output_token, - type_1_buf.cbBuffer, outptr, outlen); -} - -/* - * Curl_auth_decode_ntlm_type2_message() - * - * This is used to decode an already encoded NTLM type-2 message. - * - * Parameters: - * - * data [in] - The session handle. - * type2msg [in] - The base64 encoded type-2 message. - * ntlm [in/out] - The NTLM data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, - const char *type2msg, - struct ntlmdata *ntlm) -{ - CURLcode result = CURLE_OK; - unsigned char *type2 = NULL; - size_t type2_len = 0; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - /* Decode the base-64 encoded type-2 message */ - if(strlen(type2msg) && *type2msg != '=') { - result = Curl_base64_decode(type2msg, &type2, &type2_len); - if(result) - return result; - } - - /* Ensure we have a valid type-2 message */ - if(!type2) { - infof(data, "NTLM handshake failure (empty type-2 message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Simply store the challenge for use later */ - ntlm->input_token = type2; - ntlm->input_token_len = type2_len; - - return result; -} - -/* -* Curl_auth_create_ntlm_type3_message() - * Curl_auth_create_ntlm_type3_message() - * - * This is used to generate an already encoded NTLM type-3 message ready for - * sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * ntlm [in/out] - The NTLM data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - SecBuffer type_2_buf; - SecBuffer type_3_buf; - SecBufferDesc type_2_desc; - SecBufferDesc type_3_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - (void) passwdp; - (void) userp; - - /* Setup the type-2 "input" security buffer */ - type_2_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2_buf; - type_2_buf.BufferType = SECBUFFER_TOKEN; - type_2_buf.pvBuffer = ntlm->input_token; - type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len); - - /* Setup the type-3 "output" security buffer */ - type_3_desc.ulVersion = SECBUFFER_VERSION; - type_3_desc.cBuffers = 1; - type_3_desc.pBuffers = &type_3_buf; - type_3_buf.BufferType = SECBUFFER_TOKEN; - type_3_buf.pvBuffer = ntlm->output_token; - type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); - - /* Generate our type-3 message */ - status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, - ntlm->context, - (TCHAR *) TEXT(""), - 0, 0, SECURITY_NETWORK_DREP, - &type_2_desc, - 0, ntlm->context, - &type_3_desc, - &attrs, &expiry); - if(status != SEC_E_OK) { - infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", - status); - - return CURLE_RECV_ERROR; - } - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) ntlm->output_token, - type_3_buf.cbBuffer, outptr, outlen); - - Curl_auth_ntlm_cleanup(ntlm); - - return result; -} - -/* - * Curl_auth_ntlm_cleanup() - * - * This is used to clean up the NTLM specific data. - * - * Parameters: - * - * ntlm [in/out] - The NTLM data struct being cleaned up. - * - */ -void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm) -{ - /* Free our security context */ - if(ntlm->context) { - s_pSecFn->DeleteSecurityContext(ntlm->context); - free(ntlm->context); - ntlm->context = NULL; - } - - /* Free our credentials handle */ - if(ntlm->credentials) { - s_pSecFn->FreeCredentialsHandle(ntlm->credentials); - free(ntlm->credentials); - ntlm->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(ntlm->p_identity); - ntlm->p_identity = NULL; - - /* Free the input and output tokens */ - Curl_safefree(ntlm->input_token); - Curl_safefree(ntlm->output_token); - - /* Reset any variables */ - ntlm->token_max = 0; -} - -#endif /* USE_WINDOWS_SSPI && USE_NTLM */ diff --git a/dep/cpr/opt/curl/lib/vauth/oauth2.c b/dep/cpr/opt/curl/lib/vauth/oauth2.c deleted file mode 100644 index 6288f89a388..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/oauth2.c +++ /dev/null @@ -1,86 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC6749 OAuth 2.0 Authorization Framework - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include -#include "urldata.h" - -#include "vauth/vauth.h" -#include "curl_base64.h" -#include "warnless.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_create_oauth_bearer_message() - * - * This is used to generate an already encoded OAuth 2.0 message ready for - * sending to the recipient. - * - * Parameters: - * - * data[in] - The session handle. - * user[in] - The user name. - * host[in] - The host name(for OAUTHBEARER). - * port[in] - The port(for OAUTHBEARER when not Port 80). - * bearer[in] - The bearer token. - * outptr[in / out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen[out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, - const char *user, - const char *host, - const long port, - const char *bearer, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - char *oauth = NULL; - - /* Generate the message */ - if(host == NULL && (port == 0 || port == 80)) - oauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); - else if(port == 0 || port == 80) - oauth = aprintf("user=%s\1host=%s\1auth=Bearer %s\1\1", user, host, - bearer); - else - oauth = aprintf("user=%s\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user, - host, port, bearer); - if(!oauth) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the reply */ - result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen); - - free(oauth); - - return result; -} diff --git a/dep/cpr/opt/curl/lib/vauth/spnego_gssapi.c b/dep/cpr/opt/curl/lib/vauth/spnego_gssapi.c deleted file mode 100644 index 5196c27049c..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/spnego_gssapi.c +++ /dev/null @@ -1,278 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC4178 Simple and Protected GSS-API Negotiation Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(HAVE_GSSAPI) && defined(USE_SPNEGO) - -#include - -#include "vauth/vauth.h" -#include "urldata.h" -#include "curl_base64.h" -#include "curl_gssapi.h" -#include "warnless.h" -#include "curl_multibyte.h" -#include "sendf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_is_spnego_supported() - * - * This is used to evaluate if SPNEGO (Negotiate) is supported. - * - * Parameters: None - * - * Returns TRUE if Negotiate supported by the GSS-API library. - */ -bool Curl_auth_is_spnego_supported(void) -{ - return TRUE; -} - -/* - * Curl_auth_decode_spnego_message() - * - * This is used to decode an already encoded SPNEGO (Negotiate) challenge - * message. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * service [in] - The service type such as http, smtp, pop or imap. - * host [in] - The host name. - * chlg64 [in] - The optional base64 encoded challenge message. - * nego [in/out] - The Negotiate data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, - const char *user, - const char *password, - const char *service, - const char *host, - const char *chlg64, - struct negotiatedata *nego) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - unsigned char *chlg = NULL; - OM_uint32 major_status; - OM_uint32 minor_status; - OM_uint32 unused_status; - gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - - (void) user; - (void) password; - - if(nego->context && nego->status == GSS_S_COMPLETE) { - /* We finished successfully our part of authentication, but server - * rejected it (since we're again here). Exit with an error since we - * can't invent anything better */ - Curl_auth_spnego_cleanup(nego); - return CURLE_LOGIN_DENIED; - } - - if(!nego->spn) { - /* Generate our SPN */ - char *spn = Curl_auth_build_spn(service, NULL, host); - if(!spn) - return CURLE_OUT_OF_MEMORY; - - /* Populate the SPN structure */ - spn_token.value = spn; - spn_token.length = strlen(spn); - - /* Import the SPN */ - major_status = gss_import_name(&minor_status, &spn_token, - GSS_C_NT_HOSTBASED_SERVICE, - &nego->spn); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, "gss_import_name() failed: ", - major_status, minor_status); - - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - free(spn); - } - - if(chlg64 && *chlg64) { - /* Decode the base-64 encoded challenge message */ - if(*chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "SPNEGO handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Setup the challenge "input" security buffer */ - input_token.value = chlg; - input_token.length = chlglen; - } - - /* Generate our challenge-response message */ - major_status = Curl_gss_init_sec_context(data, - &minor_status, - &nego->context, - nego->spn, - &Curl_spnego_mech_oid, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - &output_token, - TRUE, - NULL); - - /* Free the decoded challenge as it is not required anymore */ - Curl_safefree(input_token.value); - - nego->status = major_status; - if(GSS_ERROR(major_status)) { - if(output_token.value) - gss_release_buffer(&unused_status, &output_token); - - Curl_gss_log_error(data, "gss_init_sec_context() failed: ", - major_status, minor_status); - - return CURLE_OUT_OF_MEMORY; - } - - if(!output_token.value || !output_token.length) { - if(output_token.value) - gss_release_buffer(&unused_status, &output_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Free previous token */ - if(nego->output_token.length && nego->output_token.value) - gss_release_buffer(&unused_status, &nego->output_token); - - nego->output_token = output_token; - - return CURLE_OK; -} - -/* - * Curl_auth_create_spnego_message() - * - * This is used to generate an already encoded SPNEGO (Negotiate) response - * message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * nego [in/out] - The Negotiate data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, - struct negotiatedata *nego, - char **outptr, size_t *outlen) -{ - CURLcode result; - OM_uint32 minor_status; - - /* Base64 encode the already generated response */ - result = Curl_base64_encode(data, - nego->output_token.value, - nego->output_token.length, - outptr, outlen); - - if(result) { - gss_release_buffer(&minor_status, &nego->output_token); - nego->output_token.value = NULL; - nego->output_token.length = 0; - - return result; - } - - if(!*outptr || !*outlen) { - gss_release_buffer(&minor_status, &nego->output_token); - nego->output_token.value = NULL; - nego->output_token.length = 0; - - return CURLE_REMOTE_ACCESS_DENIED; - } - - return CURLE_OK; -} - -/* - * Curl_auth_spnego_cleanup() - * - * This is used to clean up the SPNEGO (Negotiate) specific data. - * - * Parameters: - * - * nego [in/out] - The Negotiate data struct being cleaned up. - * - */ -void Curl_auth_spnego_cleanup(struct negotiatedata *nego) -{ - OM_uint32 minor_status; - - /* Free our security context */ - if(nego->context != GSS_C_NO_CONTEXT) { - gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER); - nego->context = GSS_C_NO_CONTEXT; - } - - /* Free the output token */ - if(nego->output_token.value) { - gss_release_buffer(&minor_status, &nego->output_token); - nego->output_token.value = NULL; - nego->output_token.length = 0; - - } - - /* Free the SPN */ - if(nego->spn != GSS_C_NO_NAME) { - gss_release_name(&minor_status, &nego->spn); - nego->spn = GSS_C_NO_NAME; - } - - /* Reset any variables */ - nego->status = 0; -} - -#endif /* HAVE_GSSAPI && USE_SPNEGO */ diff --git a/dep/cpr/opt/curl/lib/vauth/spnego_sspi.c b/dep/cpr/opt/curl/lib/vauth/spnego_sspi.c deleted file mode 100644 index a6797cdaff7..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/spnego_sspi.c +++ /dev/null @@ -1,324 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC4178 Simple and Protected GSS-API Negotiation Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_WINDOWS_SSPI) && defined(USE_SPNEGO) - -#include - -#include "vauth/vauth.h" -#include "urldata.h" -#include "curl_base64.h" -#include "warnless.h" -#include "curl_multibyte.h" -#include "sendf.h" -#include "strerror.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_is_spnego_supported() - * - * This is used to evaluate if SPNEGO (Negotiate) is supported. - * - * Parameters: None - * - * Returns TRUE if Negotiate is supported by Windows SSPI. - */ -bool Curl_auth_is_spnego_supported(void) -{ - PSecPkgInfo SecurityPackage; - SECURITY_STATUS status; - - /* Query the security package for Negotiate */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) - TEXT(SP_NAME_NEGOTIATE), - &SecurityPackage); - - return (status == SEC_E_OK ? TRUE : FALSE); -} - -/* - * Curl_auth_decode_spnego_message() - * - * This is used to decode an already encoded SPNEGO (Negotiate) challenge - * message. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * service [in] - The service type such as http, smtp, pop or imap. - * host [in] - The host name. - * chlg64 [in] - The optional base64 encoded challenge message. - * nego [in/out] - The Negotiate data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, - const char *user, - const char *password, - const char *service, - const char *host, - const char *chlg64, - struct negotiatedata *nego) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - unsigned char *chlg = NULL; - PSecPkgInfo SecurityPackage; - SecBuffer chlg_buf; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - if(nego->context && nego->status == SEC_E_OK) { - /* We finished successfully our part of authentication, but server - * rejected it (since we're again here). Exit with an error since we - * can't invent anything better */ - Curl_auth_spnego_cleanup(nego); - return CURLE_LOGIN_DENIED; - } - - if(!nego->spn) { - /* Generate our SPN */ - nego->spn = Curl_auth_build_spn(service, host, NULL); - if(!nego->spn) - return CURLE_OUT_OF_MEMORY; - } - - if(!nego->output_token) { - /* Query the security package for Negotiate */ - nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) - TEXT(SP_NAME_NEGOTIATE), - &SecurityPackage); - if(nego->status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - nego->token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our output buffer */ - nego->output_token = malloc(nego->token_max); - if(!nego->output_token) - return CURLE_OUT_OF_MEMORY; - } - - if(!nego->credentials) { - /* Do we have credientials to use or are we using single sign-on? */ - if(user && *user) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(user, password, &nego->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - nego->p_identity = &nego->identity; - } - else - /* Use the current Windows user */ - nego->p_identity = NULL; - - /* Allocate our credentials handle */ - nego->credentials = malloc(sizeof(CredHandle)); - if(!nego->credentials) - return CURLE_OUT_OF_MEMORY; - - memset(nego->credentials, 0, sizeof(CredHandle)); - - /* Acquire our credentials handle */ - nego->status = - s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *)TEXT(SP_NAME_NEGOTIATE), - SECPKG_CRED_OUTBOUND, NULL, - nego->p_identity, NULL, NULL, - nego->credentials, &expiry); - if(nego->status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - - /* Allocate our new context handle */ - nego->context = malloc(sizeof(CtxtHandle)); - if(!nego->context) - return CURLE_OUT_OF_MEMORY; - - memset(nego->context, 0, sizeof(CtxtHandle)); - } - - if(chlg64 && *chlg64) { - /* Decode the base-64 encoded challenge message */ - if(*chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "SPNEGO handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Setup the challenge "input" security buffer */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 1; - chlg_desc.pBuffers = &chlg_buf; - chlg_buf.BufferType = SECBUFFER_TOKEN; - chlg_buf.pvBuffer = chlg; - chlg_buf.cbBuffer = curlx_uztoul(chlglen); - } - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = nego->output_token; - resp_buf.cbBuffer = curlx_uztoul(nego->token_max); - - /* Generate our challenge-response message */ - nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials, - chlg ? nego->context : - NULL, - nego->spn, - ISC_REQ_CONFIDENTIALITY, - 0, SECURITY_NATIVE_DREP, - chlg ? &chlg_desc : NULL, - 0, nego->context, - &resp_desc, &attrs, - &expiry); - - /* Free the decoded challenge as it is not required anymore */ - free(chlg); - - if(GSS_ERROR(nego->status)) { - failf(data, "InitializeSecurityContext failed: %s", - Curl_sspi_strerror(data->easy_conn, nego->status)); - return CURLE_OUT_OF_MEMORY; - } - - if(nego->status == SEC_I_COMPLETE_NEEDED || - nego->status == SEC_I_COMPLETE_AND_CONTINUE) { - nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc); - if(GSS_ERROR(nego->status)) { - return CURLE_RECV_ERROR; - } - } - - nego->output_token_length = resp_buf.cbBuffer; - - return result; -} - -/* - * Curl_auth_create_spnego_message() - * - * This is used to generate an already encoded SPNEGO (Negotiate) response - * message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * nego [in/out] - The Negotiate data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, - struct negotiatedata *nego, - char **outptr, size_t *outlen) -{ - CURLcode result; - - /* Base64 encode the already generated response */ - result = Curl_base64_encode(data, - (const char *) nego->output_token, - nego->output_token_length, - outptr, outlen); - - if(result) - return result; - - if(!*outptr || !*outlen) { - free(*outptr); - return CURLE_REMOTE_ACCESS_DENIED; - } - - return CURLE_OK; -} - -/* - * Curl_auth_spnego_cleanup() - * - * This is used to clean up the SPNEGO (Negotiate) specific data. - * - * Parameters: - * - * nego [in/out] - The Negotiate data struct being cleaned up. - * - */ -void Curl_auth_spnego_cleanup(struct negotiatedata *nego) -{ - /* Free our security context */ - if(nego->context) { - s_pSecFn->DeleteSecurityContext(nego->context); - free(nego->context); - nego->context = NULL; - } - - /* Free our credentials handle */ - if(nego->credentials) { - s_pSecFn->FreeCredentialsHandle(nego->credentials); - free(nego->credentials); - nego->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(nego->p_identity); - nego->p_identity = NULL; - - /* Free the SPN and output token */ - Curl_safefree(nego->spn); - Curl_safefree(nego->output_token); - - /* Reset any variables */ - nego->status = 0; - nego->token_max = 0; -} - -#endif /* USE_WINDOWS_SSPI && USE_SPNEGO */ diff --git a/dep/cpr/opt/curl/lib/vauth/vauth.c b/dep/cpr/opt/curl/lib/vauth/vauth.c deleted file mode 100644 index b995f34e277..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/vauth.c +++ /dev/null @@ -1,147 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014 - 2016, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#include "vauth.h" -#include "curl_multibyte.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_auth_build_spn() - * - * This is used to build a SPN string in the following formats: - * - * service/host@realm (Not currently used) - * service/host (Not used by GSS-API) - * service@realm (Not used by Windows SSPI) - * - * Parameters: - * - * service [in] - The service type such as http, smtp, pop or imap. - * host [in] - The host name. - * realm [in] - The realm. - * - * Returns a pointer to the newly allocated SPN. - */ -#if !defined(USE_WINDOWS_SSPI) -char *Curl_auth_build_spn(const char *service, const char *host, - const char *realm) -{ - char *spn = NULL; - - /* Generate our SPN */ - if(host && realm) - spn = aprintf("%s/%s@%s", service, host, realm); - else if(host) - spn = aprintf("%s/%s", service, host); - else if(realm) - spn = aprintf("%s@%s", service, realm); - - /* Return our newly allocated SPN */ - return spn; -} -#else -TCHAR *Curl_auth_build_spn(const char *service, const char *host, - const char *realm) -{ - char *utf8_spn = NULL; - TCHAR *tchar_spn = NULL; - - (void) realm; - - /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather - than doing this ourselves but the first is only available in Windows XP - and Windows Server 2003 and the latter is only available in Windows 2000 - but not Windows95/98/ME or Windows NT4.0 unless the Active Directory - Client Extensions are installed. As such it is far simpler for us to - formulate the SPN instead. */ - - /* Generate our UTF8 based SPN */ - utf8_spn = aprintf("%s/%s", service, host); - if(!utf8_spn) { - return NULL; - } - - /* Allocate our TCHAR based SPN */ - tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); - if(!tchar_spn) { - free(utf8_spn); - - return NULL; - } - - /* Release the UTF8 variant when operating with Unicode */ - Curl_unicodefree(utf8_spn); - - /* Return our newly allocated SPN */ - return tchar_spn; -} -#endif /* USE_WINDOWS_SSPI */ - -/* -* Curl_auth_user_contains_domain() -* -* This is used to test if the specified user contains a Windows domain name as -* follows: -* -* User\Domain (Down-level Logon Name) -* User/Domain (curl Down-level format - for compatibility with existing code) -* User@Domain (User Principal Name) -* -* Note: The user name may be empty when using a GSS-API library or Windows SSPI -* as the user and domain are either obtained from the credientals cache when -* using GSS-API or via the currently logged in user's credientals when using -* Windows SSPI. -* -* Parameters: -* -* user [in] - The user name. -* -* Returns TRUE on success; otherwise FALSE. -*/ -bool Curl_auth_user_contains_domain(const char *user) -{ - bool valid = FALSE; - - if(user && *user) { - /* Check we have a domain name or UPN present */ - char *p = strpbrk(user, "\\/@"); - - valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE : - FALSE); - } -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - else - /* User and domain are obtained from the GSS-API credientials cache or the - currently logged in user from Windows */ - valid = TRUE; -#endif - - return valid; -} diff --git a/dep/cpr/opt/curl/lib/vauth/vauth.h b/dep/cpr/opt/curl/lib/vauth/vauth.h deleted file mode 100644 index dfaf985c60a..00000000000 --- a/dep/cpr/opt/curl/lib/vauth/vauth.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef HEADER_CURL_VAUTH_H -#define HEADER_CURL_VAUTH_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014 - 2017, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -struct Curl_easy; - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -struct digestdata; -#endif - -#if defined(USE_NTLM) -struct ntlmdata; -#endif - -#if defined(USE_KERBEROS5) -struct kerberos5data; -#endif - -#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO) -struct negotiatedata; -#endif - -#if defined(USE_WINDOWS_SSPI) -#define GSS_ERROR(status) (status & 0x80000000) -#endif - -/* This is used to build a SPN string */ -#if !defined(USE_WINDOWS_SSPI) -char *Curl_auth_build_spn(const char *service, const char *host, - const char *realm); -#else -TCHAR *Curl_auth_build_spn(const char *service, const char *host, - const char *realm); -#endif - -/* This is used to test if the user contains a Windows domain name */ -bool Curl_auth_user_contains_domain(const char *user); - -/* This is used to generate a base64 encoded PLAIN cleartext message */ -CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen); - -/* This is used to generate a base64 encoded LOGIN cleartext message */ -CURLcode Curl_auth_create_login_message(struct Curl_easy *data, - const char *valuep, char **outptr, - size_t *outlen); - -/* This is used to generate a base64 encoded EXTERNAL cleartext message */ -CURLcode Curl_auth_create_external_message(struct Curl_easy *data, - const char *user, char **outptr, - size_t *outlen); - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -/* This is used to decode a CRAM-MD5 challenge message */ -CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, - size_t *outlen); - -/* This is used to generate a CRAM-MD5 response message */ -CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, - const char *chlg, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen); - -/* This is used to evaluate if DIGEST is supported */ -bool Curl_auth_is_digest_supported(void); - -/* This is used to generate a base64 encoded DIGEST-MD5 response message */ -CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen); - -/* This is used to decode a HTTP DIGEST challenge message */ -CURLcode Curl_auth_decode_digest_http_message(const char *chlg, - struct digestdata *digest); - -/* This is used to generate a HTTP DIGEST response message */ -CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uri, - struct digestdata *digest, - char **outptr, size_t *outlen); - -/* This is used to clean up the digest specific data */ -void Curl_auth_digest_cleanup(struct digestdata *digest); -#endif /* !CURL_DISABLE_CRYPTO_AUTH */ - -#if defined(USE_NTLM) -/* This is used to evaluate if NTLM is supported */ -bool Curl_auth_is_ntlm_supported(void); - -/* This is used to generate a base64 encoded NTLM type-1 message */ -CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, - size_t *outlen); - -/* This is used to decode a base64 encoded NTLM type-2 message */ -CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, - const char *type2msg, - struct ntlmdata *ntlm); - -/* This is used to generate a base64 encoded NTLM type-3 message */ -CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen); - -/* This is used to clean up the NTLM specific data */ -void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm); -#endif /* USE_NTLM */ - -/* This is used to generate a base64 encoded OAuth 2.0 message */ -CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, - const char *user, - const char *host, - const long port, - const char *bearer, - char **outptr, size_t *outlen); -#if defined(USE_KERBEROS5) -/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */ -bool Curl_auth_is_gssapi_supported(void); - -/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token - message */ -CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, - const char *userp, - const char *passwdp, - const char *service, - const char *host, - const bool mutual, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, size_t *outlen); - -/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security - token message */ -CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, - const char *input, - struct kerberos5data *krb5, - char **outptr, - size_t *outlen); - -/* This is used to clean up the GSSAPI specific data */ -void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5); -#endif /* USE_KERBEROS5 */ - -#if defined(USE_SPNEGO) -/* This is used to evaluate if SPNEGO (Negotiate) is supported */ -bool Curl_auth_is_spnego_supported(void); - -/* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge - message */ -CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, - const char *user, - const char *passwood, - const char *service, - const char *host, - const char *chlg64, - struct negotiatedata *nego); - -/* This is used to generate a base64 encoded SPNEGO (Negotiate) response - message */ -CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, - struct negotiatedata *nego, - char **outptr, size_t *outlen); - -/* This is used to clean up the SPNEGO specifiec data */ -void Curl_auth_spnego_cleanup(struct negotiatedata *nego); - -#endif /* USE_SPNEGO */ - -#endif /* HEADER_CURL_VAUTH_H */ diff --git a/dep/cpr/opt/curl/lib/version.c b/dep/cpr/opt/curl/lib/version.c deleted file mode 100644 index ebd600635fe..00000000000 --- a/dep/cpr/opt/curl/lib/version.c +++ /dev/null @@ -1,403 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include -#include "urldata.h" -#include "vtls/vtls.h" -#include "http2.h" -#include "curl_printf.h" - -#ifdef USE_ARES -# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ - (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) -# define CARES_STATICLIB -# endif -# include -#endif - -#ifdef USE_LIBIDN2 -#include -#endif - -#ifdef USE_LIBPSL -#include -#endif - -#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) -#include -#endif - -#ifdef USE_LIBRTMP -#include -#endif - -#ifdef USE_LIBSSH2 -#include -#endif - -#ifdef HAVE_LIBSSH2_VERSION -/* get it run-time if possible */ -#define CURL_LIBSSH2_VERSION libssh2_version(0) -#else -/* use build-time if run-time not possible */ -#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION -#endif - -void Curl_version_init(void); - -/* For thread safety purposes this function is called by global_init so that - the static data in both version functions is initialized. */ -void Curl_version_init(void) -{ - curl_version(); - curl_version_info(CURLVERSION_NOW); -} - -char *curl_version(void) -{ - static bool initialized; - static char version[200]; - char *ptr = version; - size_t len; - size_t left = sizeof(version); - - if(initialized) - return version; - - strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION); - len = strlen(ptr); - left -= len; - ptr += len; - - if(left > 1) { - len = Curl_ssl_version(ptr + 1, left - 1); - - if(len > 0) { - *ptr = ' '; - left -= ++len; - ptr += len; - } - } - -#ifdef HAVE_LIBZ - len = snprintf(ptr, left, " zlib/%s", zlibVersion()); - left -= len; - ptr += len; -#endif -#ifdef USE_ARES - /* this function is only present in c-ares, not in the original ares */ - len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL)); - left -= len; - ptr += len; -#endif -#ifdef USE_LIBIDN2 - if(idn2_check_version(IDN2_VERSION)) { - len = snprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); - left -= len; - ptr += len; - } -#endif -#ifdef USE_LIBPSL - len = snprintf(ptr, left, " libpsl/%s", psl_get_version()); - left -= len; - ptr += len; -#endif -#ifdef USE_WIN32_IDN - len = snprintf(ptr, left, " WinIDN"); - left -= len; - ptr += len; -#endif -#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) -#ifdef _LIBICONV_VERSION - len = snprintf(ptr, left, " iconv/%d.%d", - _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); -#else - /* version unknown */ - len = snprintf(ptr, left, " iconv"); -#endif /* _LIBICONV_VERSION */ - left -= len; - ptr += len; -#endif -#ifdef USE_LIBSSH2 - len = snprintf(ptr, left, " libssh2/%s", CURL_LIBSSH2_VERSION); - left -= len; - ptr += len; -#endif -#ifdef USE_NGHTTP2 - len = Curl_http2_ver(ptr, left); - left -= len; - ptr += len; -#endif -#ifdef USE_LIBRTMP - { - char suff[2]; - if(RTMP_LIB_VERSION & 0xff) { - suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1; - suff[1] = '\0'; - } - else - suff[0] = '\0'; - - snprintf(ptr, left, " librtmp/%d.%d%s", - RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, - suff); -/* - If another lib version is added below this one, this code would - also have to do: - - len = what snprintf() returned - - left -= len; - ptr += len; -*/ - } -#endif - - initialized = true; - return version; -} - -/* data for curl_version_info - - Keep the list sorted alphabetically. It is also written so that each - protocol line has its own #if line to make things easier on the eye. - */ - -static const char * const protocols[] = { -#ifndef CURL_DISABLE_DICT - "dict", -#endif -#ifndef CURL_DISABLE_FILE - "file", -#endif -#ifndef CURL_DISABLE_FTP - "ftp", -#endif -#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) - "ftps", -#endif -#ifndef CURL_DISABLE_GOPHER - "gopher", -#endif -#ifndef CURL_DISABLE_HTTP - "http", -#endif -#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) - "https", -#endif -#ifndef CURL_DISABLE_IMAP - "imap", -#endif -#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP) - "imaps", -#endif -#ifndef CURL_DISABLE_LDAP - "ldap", -#if !defined(CURL_DISABLE_LDAPS) && \ - ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ - (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) - "ldaps", -#endif -#endif -#ifndef CURL_DISABLE_POP3 - "pop3", -#endif -#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3) - "pop3s", -#endif -#ifdef USE_LIBRTMP - "rtmp", -#endif -#ifndef CURL_DISABLE_RTSP - "rtsp", -#endif -#ifdef USE_LIBSSH2 - "scp", -#endif -#ifdef USE_LIBSSH2 - "sftp", -#endif -#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ - (CURL_SIZEOF_CURL_OFF_T > 4) && \ - (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)) - "smb", -# ifdef USE_SSL - "smbs", -# endif -#endif -#ifndef CURL_DISABLE_SMTP - "smtp", -#endif -#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP) - "smtps", -#endif -#ifndef CURL_DISABLE_TELNET - "telnet", -#endif -#ifndef CURL_DISABLE_TFTP - "tftp", -#endif - - NULL -}; - -static curl_version_info_data version_info = { - CURLVERSION_NOW, - LIBCURL_VERSION, - LIBCURL_VERSION_NUM, - OS, /* as found by configure or set by hand at build-time */ - 0 /* features is 0 by default */ -#ifdef ENABLE_IPV6 - | CURL_VERSION_IPV6 -#endif -#ifdef USE_SSL - | CURL_VERSION_SSL -#endif -#ifdef USE_NTLM - | CURL_VERSION_NTLM -#endif -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ - defined(NTLM_WB_ENABLED) - | CURL_VERSION_NTLM_WB -#endif -#ifdef USE_SPNEGO - | CURL_VERSION_SPNEGO -#endif -#ifdef USE_KERBEROS5 - | CURL_VERSION_KERBEROS5 -#endif -#ifdef HAVE_GSSAPI - | CURL_VERSION_GSSAPI -#endif -#ifdef USE_WINDOWS_SSPI - | CURL_VERSION_SSPI -#endif -#ifdef HAVE_LIBZ - | CURL_VERSION_LIBZ -#endif -#ifdef DEBUGBUILD - | CURL_VERSION_DEBUG -#endif -#ifdef CURLDEBUG - | CURL_VERSION_CURLDEBUG -#endif -#ifdef CURLRES_ASYNCH - | CURL_VERSION_ASYNCHDNS -#endif -#if (CURL_SIZEOF_CURL_OFF_T > 4) && \ - ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) ) - | CURL_VERSION_LARGEFILE -#endif -#if defined(CURL_DOES_CONVERSIONS) - | CURL_VERSION_CONV -#endif -#if defined(USE_TLS_SRP) - | CURL_VERSION_TLSAUTH_SRP -#endif -#if defined(USE_NGHTTP2) - | CURL_VERSION_HTTP2 -#endif -#if defined(USE_UNIX_SOCKETS) - | CURL_VERSION_UNIX_SOCKETS -#endif -#if defined(USE_LIBPSL) - | CURL_VERSION_PSL -#endif -#if defined(CURL_WITH_MULTI_SSL) - | CURL_VERSION_MULTI_SSL -#endif - , - NULL, /* ssl_version */ - 0, /* ssl_version_num, this is kept at zero */ - NULL, /* zlib_version */ - protocols, - NULL, /* c-ares version */ - 0, /* c-ares version numerical */ - NULL, /* libidn version */ - 0, /* iconv version */ - NULL, /* ssh lib version */ -}; - -curl_version_info_data *curl_version_info(CURLversion stamp) -{ - static bool initialized; -#ifdef USE_LIBSSH2 - static char ssh_buffer[80]; -#endif -#ifdef USE_SSL - static char ssl_buffer[80]; -#endif - - if(initialized) - return &version_info; - -#ifdef USE_SSL - Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); - version_info.ssl_version = ssl_buffer; - if(Curl_ssl->support_https_proxy) - version_info.features |= CURL_VERSION_HTTPS_PROXY; - else - version_info.features &= ~CURL_VERSION_HTTPS_PROXY; -#endif - -#ifdef HAVE_LIBZ - version_info.libz_version = zlibVersion(); - /* libz left NULL if non-existing */ -#endif -#ifdef USE_ARES - { - int aresnum; - version_info.ares = ares_version(&aresnum); - version_info.ares_num = aresnum; - } -#endif -#ifdef USE_LIBIDN2 - /* This returns a version string if we use the given version or later, - otherwise it returns NULL */ - version_info.libidn = idn2_check_version(IDN2_VERSION); - if(version_info.libidn) - version_info.features |= CURL_VERSION_IDN; -#elif defined(USE_WIN32_IDN) - version_info.features |= CURL_VERSION_IDN; -#endif - -#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) -#ifdef _LIBICONV_VERSION - version_info.iconv_ver_num = _LIBICONV_VERSION; -#else - /* version unknown */ - version_info.iconv_ver_num = -1; -#endif /* _LIBICONV_VERSION */ -#endif - -#ifdef USE_LIBSSH2 - snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION); - version_info.libssh_version = ssh_buffer; -#endif - - (void)stamp; /* avoid compiler warnings, we don't use this */ - - initialized = true; - return &version_info; -} diff --git a/dep/cpr/opt/curl/lib/vtls/axtls.c b/dep/cpr/opt/curl/lib/vtls/axtls.c deleted file mode 100644 index 6b42708d831..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/axtls.c +++ /dev/null @@ -1,742 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010, DirecTV, Contact: Eric Hu, . - * Copyright (C) 2010 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all axTLS-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - */ - -#include "curl_setup.h" - -#ifdef USE_AXTLS -#include -#include -#include "axtls.h" - -#include "sendf.h" -#include "inet_pton.h" -#include "vtls.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "curl_printf.h" -#include "hostcheck.h" -#include - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -struct ssl_backend_data { - SSL_CTX* ssl_ctx; - SSL* ssl; -}; - -#define BACKEND connssl->backend - -static CURLcode map_error_to_curl(int axtls_err) -{ - switch(axtls_err) { - case SSL_ERROR_NOT_SUPPORTED: - case SSL_ERROR_INVALID_VERSION: - case -70: /* protocol version alert from server */ - return CURLE_UNSUPPORTED_PROTOCOL; - break; - case SSL_ERROR_NO_CIPHER: - return CURLE_SSL_CIPHER; - break; - case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */ - case SSL_ERROR_NO_CERT_DEFINED: - case -42: /* bad certificate alert from server */ - case -43: /* unsupported cert alert from server */ - case -44: /* cert revoked alert from server */ - case -45: /* cert expired alert from server */ - case -46: /* cert unknown alert from server */ - return CURLE_SSL_CERTPROBLEM; - break; - case SSL_X509_ERROR(X509_NOT_OK): - case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT): - case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE): - case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID): - case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED): - case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED): - case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN): - case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST): - case SSL_X509_ERROR(X509_INVALID_PRIV_KEY): - return CURLE_PEER_FAILED_VERIFICATION; - break; - case -48: /* unknown ca alert from server */ - return CURLE_SSL_CACERT; - break; - case -49: /* access denied alert from server */ - return CURLE_REMOTE_ACCESS_DENIED; - break; - case SSL_ERROR_CONN_LOST: - case SSL_ERROR_SOCK_SETUP_FAILURE: - case SSL_ERROR_INVALID_HANDSHAKE: - case SSL_ERROR_INVALID_PROT_MSG: - case SSL_ERROR_INVALID_HMAC: - case SSL_ERROR_INVALID_SESSION: - case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */ - case SSL_ERROR_FINISHED_INVALID: - case SSL_ERROR_NO_CLIENT_RENOG: - default: - return CURLE_SSL_CONNECT_ERROR; - break; - } -} - -static Curl_recv axtls_recv; -static Curl_send axtls_send; - -static void free_ssl_structs(struct ssl_connect_data *connssl) -{ - if(BACKEND->ssl) { - ssl_free(BACKEND->ssl); - BACKEND->ssl = NULL; - } - if(BACKEND->ssl_ctx) { - ssl_ctx_free(BACKEND->ssl_ctx); - BACKEND->ssl_ctx = NULL; - } -} - -/* - * For both blocking and non-blocking connects, this function sets up the - * ssl context and state. This function is called after the TCP connect - * has completed. - */ -static CURLcode connect_prep(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - SSL_CTX *ssl_ctx; - SSL *ssl = NULL; - int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0}; - int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0}; - int i, ssl_fcn_return; - - /* Assuming users will not compile in custom key/cert to axTLS. - * Also, even for blocking connects, use axTLS non-blocking feature. - */ - uint32_t client_option = SSL_NO_DEFAULT_KEY | - SSL_SERVER_VERIFY_LATER | - SSL_CONNECT_IN_PARTS; - - if(connssl->state == ssl_connection_complete) - /* to make us tolerant against being called more than once for the - same connection */ - return CURLE_OK; - - if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { - failf(data, "axtls does not support CURL_SSLVERSION_MAX"); - return CURLE_SSL_CONNECT_ERROR; - } - - - /* axTLS only supports TLSv1 */ - /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - break; - default: - failf(data, "axTLS only supports TLS 1.0 and 1.1, " - "and it cannot be specified which one to use"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef AXTLSDEBUG - client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS; -#endif /* AXTLSDEBUG */ - - /* Allocate an SSL_CTX struct */ - ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS); - if(ssl_ctx == NULL) { - failf(data, "unable to create client SSL context"); - return CURLE_SSL_CONNECT_ERROR; - } - - BACKEND->ssl_ctx = ssl_ctx; - BACKEND->ssl = NULL; - - /* Load the trusted CA cert bundle file */ - if(SSL_CONN_CONFIG(CAfile)) { - if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, - SSL_CONN_CONFIG(CAfile), NULL) != SSL_OK) { - infof(data, "error reading ca cert file %s \n", - SSL_CONN_CONFIG(CAfile)); - if(SSL_CONN_CONFIG(verifypeer)) { - return CURLE_SSL_CACERT_BADFILE; - } - } - else - infof(data, "found certificates in %s\n", SSL_CONN_CONFIG(CAfile)); - } - - /* gtls.c tasks we're skipping for now: - * 1) certificate revocation list checking - * 2) dns name assignment to host - * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore - * 4) set certificate priority. axTLS ignores type and sends certs in - * order added. can probably ignore this. - */ - - /* Load client certificate */ - if(SSL_SET_OPTION(cert)) { - i = 0; - /* Instead of trying to analyze cert type here, let axTLS try them all. */ - while(cert_types[i] != 0) { - ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], - SSL_SET_OPTION(cert), NULL); - if(ssl_fcn_return == SSL_OK) { - infof(data, "successfully read cert file %s \n", - SSL_SET_OPTION(cert)); - break; - } - i++; - } - /* Tried all cert types, none worked. */ - if(cert_types[i] == 0) { - failf(data, "%s is not x509 or pkcs12 format", - SSL_SET_OPTION(cert)); - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load client key. - If a pkcs12 file successfully loaded a cert, then there's nothing to do - because the key has already been loaded. */ - if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) { - i = 0; - /* Instead of trying to analyze key type here, let axTLS try them all. */ - while(key_types[i] != 0) { - ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], - SSL_SET_OPTION(key), NULL); - if(ssl_fcn_return == SSL_OK) { - infof(data, "successfully read key file %s \n", - SSL_SET_OPTION(key)); - break; - } - i++; - } - /* Tried all key types, none worked. */ - if(key_types[i] == 0) { - failf(data, "Failure: %s is not a supported key file", - SSL_SET_OPTION(key)); - return CURLE_SSL_CONNECT_ERROR; - } - } - - /* gtls.c does more here that is being left out for now - * 1) set session credentials. can probably ignore since axtls puts this - * info in the ssl_ctx struct - * 2) setting up callbacks. these seem gnutls specific - */ - - if(SSL_SET_OPTION(primary.sessionid)) { - const uint8_t *ssl_sessionid; - size_t ssl_idsize; - - /* In axTLS, handshaking happens inside ssl_client_new. */ - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize, - sockindex)) { - /* we got a session id, use it! */ - infof(data, "SSL re-using session ID\n"); - ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], - ssl_sessionid, (uint8_t)ssl_idsize, NULL); - } - Curl_ssl_sessionid_unlock(conn); - } - - if(!ssl) - ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL); - - BACKEND->ssl = ssl; - return CURLE_OK; -} - -static void Curl_axtls_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - infof(conn->data, " Curl_axtls_close\n"); - - /* line from openssl.c: (void)SSL_shutdown(BACKEND->ssl); - axTLS compat layer does nothing for SSL_shutdown */ - - /* The following line is from openssl.c. There seems to be no axTLS - equivalent. ssl_free and ssl_ctx_free close things. - SSL_set_connect_state(connssl->handle); */ - - free_ssl_structs(connssl); -} - -/* - * For both blocking and non-blocking connects, this function finalizes the - * SSL connection. - */ -static CURLcode connect_finish(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL *ssl = BACKEND->ssl; - const char *peer_CN; - uint32_t dns_altname_index; - const char *dns_altname; - int8_t found_subject_alt_names = 0; - int8_t found_subject_alt_name_matching_conn = 0; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const char * const dispname = SSL_IS_PROXY() ? - conn->http_proxy.host.dispname : conn->host.dispname; - - /* Here, gtls.c gets the peer certificates and fails out depending on - * settings in "data." axTLS api doesn't have get cert chain fcn, so omit? - */ - - /* Verify server's certificate */ - if(SSL_CONN_CONFIG(verifypeer)) { - if(ssl_verify_cert(ssl) != SSL_OK) { - Curl_axtls_close(conn, sockindex); - failf(data, "server cert verify failed"); - return CURLE_PEER_FAILED_VERIFICATION; - } - } - else - infof(data, "\t server certificate verification SKIPPED\n"); - - /* Here, gtls.c does issuer verification. axTLS has no straightforward - * equivalent, so omitting for now.*/ - - /* Here, gtls.c does the following - * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but - * it seems useful. This is now implemented, by Oscar Koeroo - * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert - * 3) displays a bunch of cert information. axTLS doesn't support most of - * this, but a couple fields are available. - */ - - /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a - risk of an inifite loop */ - for(dns_altname_index = 0; ; dns_altname_index++) { - dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index); - if(dns_altname == NULL) { - break; - } - found_subject_alt_names = 1; - - infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n", - dns_altname, hostname); - if(Curl_cert_hostcheck(dns_altname, hostname)) { - found_subject_alt_name_matching_conn = 1; - break; - } - } - - /* RFC2818 checks */ - if(found_subject_alt_names && !found_subject_alt_name_matching_conn) { - if(SSL_CONN_CONFIG(verifyhost)) { - /* Break connection ! */ - Curl_axtls_close(conn, sockindex); - failf(data, "\tsubjectAltName(s) do not match %s\n", dispname); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\tsubjectAltName(s) do not match %s\n", dispname); - } - else if(found_subject_alt_names == 0) { - /* Per RFC2818, when no Subject Alt Names were available, examine the peer - CN as a legacy fallback */ - peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); - if(peer_CN == NULL) { - if(SSL_CONN_CONFIG(verifyhost)) { - Curl_axtls_close(conn, sockindex); - failf(data, "unable to obtain common name from peer certificate"); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "unable to obtain common name from peer certificate"); - } - else { - if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { - if(SSL_CONN_CONFIG(verifyhost)) { - /* Break connection ! */ - Curl_axtls_close(conn, sockindex); - failf(data, "\tcommon name \"%s\" does not match \"%s\"\n", - peer_CN, dispname); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\tcommon name \"%s\" does not match \"%s\"\n", - peer_CN, dispname); - } - } - } - - /* General housekeeping */ - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = axtls_recv; - conn->send[sockindex] = axtls_send; - - /* Put our freshly minted SSL session in cache */ - if(SSL_SET_OPTION(primary.sessionid)) { - const uint8_t *ssl_sessionid = ssl_get_session_id(ssl); - size_t ssl_idsize = ssl_get_session_id_size(ssl); - Curl_ssl_sessionid_lock(conn); - if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize, - sockindex) != CURLE_OK) - infof(data, "failed to add session to cache\n"); - Curl_ssl_sessionid_unlock(conn); - } - - return CURLE_OK; -} - -/* - * Use axTLS's non-blocking connection feature to open an SSL connection. - * This is called after a TCP connection is already established. - */ -static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - CURLcode conn_step; - int ssl_fcn_return; - int i; - - *done = FALSE; - /* connectdata is calloc'd and connecting_state is only changed in this - function, so this is safe, as the state is effectively initialized. */ - if(connssl->connecting_state == ssl_connect_1) { - conn_step = connect_prep(conn, sockindex); - if(conn_step != CURLE_OK) { - Curl_axtls_close(conn, sockindex); - return conn_step; - } - connssl->connecting_state = ssl_connect_2; - } - - if(connssl->connecting_state == ssl_connect_2) { - /* Check to make sure handshake was ok. */ - if(ssl_handshake_status(BACKEND->ssl) != SSL_OK) { - /* Loop to perform more work in between sleeps. This is work around the - fact that axtls does not expose any knowledge about when work needs - to be performed. This can save ~25% of time on SSL handshakes. */ - for(i = 0; i<5; i++) { - ssl_fcn_return = ssl_read(BACKEND->ssl, NULL); - if(ssl_fcn_return < 0) { - Curl_axtls_close(conn, sockindex); - ssl_display_error(ssl_fcn_return); /* goes to stdout. */ - return map_error_to_curl(ssl_fcn_return); - } - return CURLE_OK; - } - } - infof(conn->data, "handshake completed successfully\n"); - connssl->connecting_state = ssl_connect_3; - } - - if(connssl->connecting_state == ssl_connect_3) { - conn_step = connect_finish(conn, sockindex); - if(conn_step != CURLE_OK) { - Curl_axtls_close(conn, sockindex); - return conn_step; - } - - /* Reset connect state */ - connssl->connecting_state = ssl_connect_1; - - *done = TRUE; - return CURLE_OK; - } - - /* Unrecognized state. Things are very bad. */ - connssl->state = ssl_connection_none; - connssl->connecting_state = ssl_connect_1; - /* Return value perhaps not strictly correct, but distinguishes the issue.*/ - return CURLE_BAD_FUNCTION_ARGUMENT; -} - - -/* - * This function is called after the TCP connect has completed. Setup the TLS - * layer and do all necessary magic for a blocking connect. - */ -static CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - CURLcode conn_step = connect_prep(conn, sockindex); - int ssl_fcn_return; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL *ssl = BACKEND->ssl; - long timeout_ms; - - if(conn_step != CURLE_OK) { - Curl_axtls_close(conn, sockindex); - return conn_step; - } - - /* Check to make sure handshake was ok. */ - while(ssl_handshake_status(ssl) != SSL_OK) { - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - ssl_fcn_return = ssl_read(ssl, NULL); - if(ssl_fcn_return < 0) { - Curl_axtls_close(conn, sockindex); - ssl_display_error(ssl_fcn_return); /* goes to stdout. */ - return map_error_to_curl(ssl_fcn_return); - } - /* TODO: avoid polling */ - Curl_wait_ms(10); - } - infof(conn->data, "handshake completed successfully\n"); - - conn_step = connect_finish(conn, sockindex); - if(conn_step != CURLE_OK) { - Curl_axtls_close(conn, sockindex); - return conn_step; - } - - return CURLE_OK; -} - -/* return number of sent (non-SSL) bytes */ -static ssize_t axtls_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *err) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - /* ssl_write() returns 'int' while write() and send() returns 'size_t' */ - int rc = ssl_write(BACKEND->ssl, mem, (int)len); - - infof(conn->data, " axtls_send\n"); - - if(rc < 0) { - *err = map_error_to_curl(rc); - rc = -1; /* generic error code for send failure */ - } - - *err = CURLE_OK; - return rc; -} - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -static int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) -{ - /* Outline taken from openssl.c since functions are in axTLS compat layer. - axTLS's error set is much smaller, so a lot of error-handling was removed. - */ - int retval = 0; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - uint8_t *buf; - ssize_t nread; - - infof(conn->data, " Curl_axtls_shutdown\n"); - - /* This has only been tested on the proftpd server, and the mod_tls code - sends a close notify alert without waiting for a close notify alert in - response. Thus we wait for a close notify alert from the server, but - we do not send one. Let's hope other servers do the same... */ - - /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too - if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - (void)SSL_shutdown(BACKEND->ssl); - */ - - if(BACKEND->ssl) { - int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); - if(what > 0) { - /* Something to read, let's do it and hope that it is the close - notify alert from the server. buf is managed internally by - axTLS and will be released upon calling ssl_free via - free_ssl_structs. */ - nread = (ssize_t)ssl_read(BACKEND->ssl, &buf); - - if(nread < SSL_OK) { - failf(data, "close notify alert not received during shutdown"); - retval = -1; - } - } - else if(0 == what) { - /* timeout */ - failf(data, "SSL shutdown timeout"); - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - retval = -1; - } - - free_ssl_structs(connssl); - } - return retval; -} - -static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *err) -{ - struct ssl_connect_data *connssl = &conn->ssl[num]; - ssize_t ret = 0; - uint8_t *read_buf; - - infof(conn->data, " axtls_recv\n"); - - *err = CURLE_OK; - if(connssl) { - ret = ssl_read(BACKEND->ssl, &read_buf); - if(ret > SSL_OK) { - /* ssl_read returns SSL_OK if there is more data to read, so if it is - larger, then all data has been read already. */ - memcpy(buf, read_buf, - (size_t)ret > buffersize ? buffersize : (size_t)ret); - } - else if(ret == SSL_OK) { - /* more data to be read, signal caller to call again */ - *err = CURLE_AGAIN; - ret = -1; - } - else if(ret == -3) { - /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS - team approves proposed fix. */ - Curl_axtls_close(conn, num); - } - else { - failf(conn->data, "axTLS recv error (%d)", ret); - *err = map_error_to_curl((int) ret); - ret = -1; - } - } - - return ret; -} - -/* - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int Curl_axtls_check_cxn(struct connectdata *conn) -{ - /* openssl.c line: - rc = SSL_peek(conn->ssl[FIRSTSOCKET].backend->ssl, (void*)&buf, 1); - axTLS compat layer always returns the last argument, so connection is - always alive? */ - - infof(conn->data, " Curl_axtls_check_cxn\n"); - return 1; /* connection still in place */ -} - -static void Curl_axtls_session_free(void *ptr) -{ - (void)ptr; - /* free the ID */ - /* both openssl.c and gtls.c do something here, but axTLS's OpenSSL - compatibility layer does nothing, so we do nothing too. */ -} - -static size_t Curl_axtls_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, "axTLS/%s", ssl_version()); -} - -static CURLcode Curl_axtls_random(struct Curl_easy *data, - unsigned char *entropy, size_t length) -{ - static bool ssl_seeded = FALSE; - (void)data; - if(!ssl_seeded) { - ssl_seeded = TRUE; - /* Initialize the seed if not already done. This call is not exactly thread - * safe (and neither is the ssl_seeded check), but the worst effect of a - * race condition is that some global resources will leak. */ - RNG_initialize(); - } - get_random((int)length, entropy); - return CURLE_OK; -} - -static void *Curl_axtls_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return BACKEND->ssl; -} - -const struct Curl_ssl Curl_ssl_axtls = { - { CURLSSLBACKEND_AXTLS, "axtls" }, /* info */ - - 0, /* have_ca_path */ - 0, /* have_certinfo */ - 0, /* have_pinnedpubkey */ - 0, /* have_ssl_ctx */ - 0, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - /* - * axTLS has no global init. Everything is done through SSL and SSL_CTX - * structs stored in connectdata structure. - */ - Curl_none_init, /* init */ - /* axTLS has no global cleanup. */ - Curl_none_cleanup, /* cleanup */ - Curl_axtls_version, /* version */ - Curl_axtls_check_cxn, /* check_cxn */ - Curl_axtls_shutdown, /* shutdown */ - Curl_none_data_pending, /* data_pending */ - Curl_axtls_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_axtls_connect, /* connect */ - Curl_axtls_connect_nonblocking, /* connect_nonblocking */ - Curl_axtls_get_internals, /* get_internals */ - Curl_axtls_close, /* close */ - Curl_none_close_all, /* close_all */ - Curl_axtls_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - NULL /* sha256sum */ -}; - -#endif /* USE_AXTLS */ diff --git a/dep/cpr/opt/curl/lib/vtls/axtls.h b/dep/cpr/opt/curl/lib/vtls/axtls.h deleted file mode 100644 index 3f1e129c285..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/axtls.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef HEADER_CURL_AXTLS_H -#define HEADER_CURL_AXTLS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010, DirecTV, Contact: Eric Hu - * Copyright (C) 2010 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#ifdef USE_AXTLS -#include "curl/curl.h" -#include "urldata.h" - -extern const struct Curl_ssl Curl_ssl_axtls; - -#endif /* USE_AXTLS */ -#endif /* HEADER_CURL_AXTLS_H */ - diff --git a/dep/cpr/opt/curl/lib/vtls/cyassl.c b/dep/cpr/opt/curl/lib/vtls/cyassl.c deleted file mode 100644 index ba5ee154867..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/cyassl.c +++ /dev/null @@ -1,1017 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - * - */ - -#include "curl_setup.h" - -#ifdef USE_CYASSL - -#define WOLFSSL_OPTIONS_IGNORE_SYS -/* CyaSSL's version.h, which should contain only the version, should come -before all other CyaSSL includes and be immediately followed by build config -aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */ -#include -#if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008) -#if defined(CYASSL_API) || defined(WOLFSSL_API) -/* Safety measure. If either is defined some API include was already included -and that's a problem since options.h hasn't been included yet. */ -#error "CyaSSL API was included before the CyaSSL build options." -#endif -#include -#endif - -/* To determine what functions are available we rely on one or both of: - - the user's options.h generated by CyaSSL/wolfSSL - - the symbols detected by curl's configure - Since they are markedly different from one another, and one or the other may - not be available, we do some checking below to bring things in sync. */ - -/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */ -#ifndef HAVE_ALPN -#ifdef HAVE_WOLFSSL_USEALPN -#define HAVE_ALPN -#endif -#endif - -/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in - options.h, but is only seen in >= 3.6.6 since that's when they started - disabling SSLv3 by default. */ -#ifndef WOLFSSL_ALLOW_SSLV3 -#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \ - defined(HAVE_WOLFSSLV3_CLIENT_METHOD) -#define WOLFSSL_ALLOW_SSLV3 -#endif -#endif - -/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC - supported curve extension in options.h. Note ECC is enabled separately. */ -#ifndef HAVE_SUPPORTED_CURVES -#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \ - defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE) -#define HAVE_SUPPORTED_CURVES -#endif -#endif - -#ifdef HAVE_LIMITS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "inet_pton.h" -#include "vtls.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "strcase.h" -#include "x509asn1.h" -#include "curl_printf.h" - -#include -#include -#ifdef HAVE_CYASSL_ERROR_SSL_H -#include -#else -#include -#endif -#include -#include - -#include "cyassl.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -#if LIBCYASSL_VERSION_HEX < 0x02007002 /* < 2.7.2 */ -#define CYASSL_MAX_ERROR_SZ 80 -#endif - -/* KEEP_PEER_CERT is a product of the presence of build time symbol - OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is - in wolfSSL's settings.h, and the latter two are build time symbols in - options.h. */ -#ifndef KEEP_PEER_CERT -#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \ - defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ - (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) -#define KEEP_PEER_CERT -#endif -#endif - -struct ssl_backend_data { - SSL_CTX* ctx; - SSL* handle; -}; - -#define BACKEND connssl->backend - -static Curl_recv cyassl_recv; -static Curl_send cyassl_send; - - -static int do_file_type(const char *type) -{ - if(!type || !type[0]) - return SSL_FILETYPE_PEM; - if(strcasecompare(type, "PEM")) - return SSL_FILETYPE_PEM; - if(strcasecompare(type, "DER")) - return SSL_FILETYPE_ASN1; - return -1; -} - -/* - * This function loads all the client/CA certificates and CRLs. Setup the TLS - * layer and do all necessary magic. - */ -static CURLcode -cyassl_connect_step1(struct connectdata *conn, - int sockindex) -{ - char error_buffer[CYASSL_MAX_ERROR_SZ]; - char *ciphers; - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - SSL_METHOD* req_method = NULL; - curl_socket_t sockfd = conn->sock[sockindex]; -#ifdef HAVE_SNI - bool sni = FALSE; -#define use_sni(x) sni = (x) -#else -#define use_sni(x) Curl_nop_stmt -#endif - - if(connssl->state == ssl_connection_complete) - return CURLE_OK; - - if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { - failf(data, "CyaSSL does not support to set maximum SSL/TLS version"); - return CURLE_SSL_CONNECT_ERROR; - } - - /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: -#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ - /* minimum protocol version is set later after the CTX object is created */ - req_method = SSLv23_client_method(); -#else - infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " - "TLS 1.0 is used exclusively\n"); - req_method = TLSv1_client_method(); -#endif - use_sni(TRUE); - break; - case CURL_SSLVERSION_TLSv1_0: - req_method = TLSv1_client_method(); - use_sni(TRUE); - break; - case CURL_SSLVERSION_TLSv1_1: - req_method = TLSv1_1_client_method(); - use_sni(TRUE); - break; - case CURL_SSLVERSION_TLSv1_2: - req_method = TLSv1_2_client_method(); - use_sni(TRUE); - break; - case CURL_SSLVERSION_TLSv1_3: - failf(data, "CyaSSL: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; - case CURL_SSLVERSION_SSLv3: -#ifdef WOLFSSL_ALLOW_SSLV3 - req_method = SSLv3_client_method(); - use_sni(FALSE); -#else - failf(data, "CyaSSL does not support SSLv3"); - return CURLE_NOT_BUILT_IN; -#endif - break; - case CURL_SSLVERSION_SSLv2: - failf(data, "CyaSSL does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - if(!req_method) { - failf(data, "SSL: couldn't create a method!"); - return CURLE_OUT_OF_MEMORY; - } - - if(BACKEND->ctx) - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = SSL_CTX_new(req_method); - - if(!BACKEND->ctx) { - failf(data, "SSL: couldn't create a context!"); - return CURLE_OUT_OF_MEMORY; - } - - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: -#if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ - /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever - minimum version of TLS was built in and at least TLS 1.0. For later library - versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so - we have this short circuit evaluation to find the minimum supported TLS - version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion - because only the former will work before the user's CTX callback is called. - */ - if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) && - (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) && - (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)) { - failf(data, "SSL: couldn't set the minimum protocol version"); - return CURLE_SSL_CONNECT_ERROR; - } -#endif - break; - } - - ciphers = SSL_CONN_CONFIG(cipher_list); - if(ciphers) { - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { - failf(data, "failed setting cipher list: %s", ciphers); - return CURLE_SSL_CIPHER; - } - infof(data, "Cipher selection: %s\n", ciphers); - } - -#ifndef NO_FILESYSTEM - /* load trusted cacert */ - if(SSL_CONN_CONFIG(CAfile)) { - if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx, - SSL_CONN_CONFIG(CAfile), - SSL_CONN_CONFIG(CApath))) { - if(SSL_CONN_CONFIG(verifypeer)) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:\n" - " CAfile: %s\n CApath: %s", - SSL_CONN_CONFIG(CAfile)? - SSL_CONN_CONFIG(CAfile): "none", - SSL_CONN_CONFIG(CApath)? - SSL_CONN_CONFIG(CApath) : "none"); - return CURLE_SSL_CACERT_BADFILE; - } - else { - /* Just continue with a warning if no strict certificate - verification is required. */ - infof(data, "error setting certificate verify locations," - " continuing anyway:\n"); - } - } - else { - /* Everything is fine. */ - infof(data, "successfully set certificate verify locations:\n"); - } - infof(data, - " CAfile: %s\n" - " CApath: %s\n", - SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): - "none", - SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): - "none"); - } - - /* Load the client certificate, and private key */ - if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) { - int file_type = do_file_type(SSL_SET_OPTION(cert_type)); - - if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert), - file_type) != 1) { - failf(data, "unable to use client certificate (no key or wrong pass" - " phrase?)"); - return CURLE_SSL_CONNECT_ERROR; - } - - file_type = do_file_type(SSL_SET_OPTION(key_type)); - if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key), - file_type) != 1) { - failf(data, "unable to set private key"); - return CURLE_SSL_CONNECT_ERROR; - } - } -#endif /* !NO_FILESYSTEM */ - - /* SSL always tries to verify the peer, this only says whether it should - * fail to connect if the verification fails, or if it should continue - * anyway. In the latter case the result of the verification is checked with - * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(BACKEND->ctx, - SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: - SSL_VERIFY_NONE, - NULL); - -#ifdef HAVE_SNI - if(sni) { - struct in_addr addr4; -#ifdef ENABLE_IPV6 - struct in6_addr addr6; -#endif - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - size_t hostname_len = strlen(hostname); - if((hostname_len < USHRT_MAX) && - (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) && -#ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) && -#endif - (CyaSSL_CTX_UseSNI(BACKEND->ctx, CYASSL_SNI_HOST_NAME, hostname, - (unsigned short)hostname_len) != 1)) { - infof(data, "WARNING: failed to configure server name indication (SNI) " - "TLS extension\n"); - } - } -#endif - -#ifdef HAVE_SUPPORTED_CURVES - /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically: - https://github.com/wolfSSL/wolfssl/issues/366 - The supported curves below are those also supported by OpenSSL 1.0.2 and - in the same order. */ - CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x17); /* secp256r1 */ - CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x19); /* secp521r1 */ - CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x18); /* secp384r1 */ -#endif - - /* give application a chance to interfere with SSL set up. */ - if(data->set.ssl.fsslctx) { - CURLcode result = CURLE_OK; - result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, - data->set.ssl.fsslctxp); - if(result) { - failf(data, "error signaled by ssl ctx callback"); - return result; - } - } -#ifdef NO_FILESYSTEM - else if(SSL_CONN_CONFIG(verifypeer)) { - failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built" - " with \"no filesystem\". Either disable peer verification" - " (insecure) or if you are building an application with libcurl you" - " can load certificates via CURLOPT_SSL_CTX_FUNCTION."); - return CURLE_SSL_CONNECT_ERROR; - } -#endif - - /* Let's make an SSL structure */ - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { - failf(data, "SSL: couldn't create a context (handle)!"); - return CURLE_OUT_OF_MEMORY; - } - -#ifdef HAVE_ALPN - if(conn->bits.tls_enable_alpn) { - char protocols[128]; - *protocols = '\0'; - - /* wolfSSL's ALPN protocol name list format is a comma separated string of - protocols in descending order of preference, eg: "h2,http/1.1" */ - -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2) { - strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ","); - infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); - } -#endif - - strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - - if(wolfSSL_UseALPN(BACKEND->handle, protocols, - (unsigned)strlen(protocols), - WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { - failf(data, "SSL: failed setting ALPN protocols"); - return CURLE_SSL_CONNECT_ERROR; - } - } -#endif /* HAVE_ALPN */ - - /* Check if there's a cached ID we can/should use here! */ - if(SSL_SET_OPTION(primary.sessionid)) { - void *ssl_sessionid = NULL; - - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { - /* we got a session id, use it! */ - if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(BACKEND->handle, 0), - error_buffer)); - return CURLE_SSL_CONNECT_ERROR; - } - /* Informational message */ - infof(data, "SSL re-using session ID\n"); - } - Curl_ssl_sessionid_unlock(conn); - } - - /* pass the raw socket into the SSL layer */ - if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { - failf(data, "SSL: SSL_set_fd failed"); - return CURLE_SSL_CONNECT_ERROR; - } - - connssl->connecting_state = ssl_connect_2; - return CURLE_OK; -} - - -static CURLcode -cyassl_connect_step2(struct connectdata *conn, - int sockindex) -{ - int ret = -1; - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const char * const dispname = SSL_IS_PROXY() ? - conn->http_proxy.host.dispname : conn->host.dispname; - const char * const pinnedpubkey = SSL_IS_PROXY() ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - - conn->recv[sockindex] = cyassl_recv; - conn->send[sockindex] = cyassl_send; - - /* Enable RFC2818 checks */ - if(SSL_CONN_CONFIG(verifyhost)) { - ret = CyaSSL_check_domain_name(BACKEND->handle, hostname); - if(ret == SSL_FAILURE) - return CURLE_OUT_OF_MEMORY; - } - - ret = SSL_connect(BACKEND->handle); - if(ret != 1) { - char error_buffer[CYASSL_MAX_ERROR_SZ]; - int detail = SSL_get_error(BACKEND->handle, ret); - - if(SSL_ERROR_WANT_READ == detail) { - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - } - else if(SSL_ERROR_WANT_WRITE == detail) { - connssl->connecting_state = ssl_connect_2_writing; - return CURLE_OK; - } - /* There is no easy way to override only the CN matching. - * This will enable the override of both mismatching SubjectAltNames - * as also mismatching CN fields */ - else if(DOMAIN_NAME_MISMATCH == detail) { -#if 1 - failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", - dispname); - return CURLE_PEER_FAILED_VERIFICATION; -#else - /* When the CyaSSL_check_domain_name() is used and you desire to continue - * on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost == 0', - * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only - * way to do this is currently to switch the CyaSSL_check_domain_name() - * in and out based on the 'conn->ssl_config.verifyhost' value. */ - if(SSL_CONN_CONFIG(verifyhost)) { - failf(data, - "\tsubject alt name(s) or common name do not match \"%s\"\n", - dispname); - return CURLE_PEER_FAILED_VERIFICATION; - } - else { - infof(data, - "\tsubject alt name(s) and/or common name do not match \"%s\"\n", - dispname); - return CURLE_OK; - } -#endif - } -#if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ - else if(ASN_NO_SIGNER_E == detail) { - if(SSL_CONN_CONFIG(verifypeer)) { - failf(data, "\tCA signer not available for verification\n"); - return CURLE_SSL_CACERT_BADFILE; - } - else { - /* Just continue with a warning if no strict certificate - verification is required. */ - infof(data, "CA signer not available for verification, " - "continuing anyway\n"); - } - } -#endif - else { - failf(data, "SSL_connect failed with error %d: %s", detail, - ERR_error_string(detail, error_buffer)); - return CURLE_SSL_CONNECT_ERROR; - } - } - - if(pinnedpubkey) { -#ifdef KEEP_PEER_CERT - X509 *x509; - const char *x509_der; - int x509_der_len; - curl_X509certificate x509_parsed; - curl_asn1Element *pubkey; - CURLcode result; - - x509 = SSL_get_peer_certificate(BACKEND->handle); - if(!x509) { - failf(data, "SSL: failed retrieving server certificate"); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len); - if(!x509_der) { - failf(data, "SSL: failed retrieving ASN.1 server certificate"); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - memset(&x509_parsed, 0, sizeof x509_parsed); - if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len)) - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - - pubkey = &x509_parsed.subjectPublicKeyInfo; - if(!pubkey->header || pubkey->end <= pubkey->header) { - failf(data, "SSL: failed retrieving public key from server certificate"); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - result = Curl_pin_peer_pubkey(data, - pinnedpubkey, - (const unsigned char *)pubkey->header, - (size_t)(pubkey->end - pubkey->header)); - if(result) { - failf(data, "SSL: public key does not match pinned public key!"); - return result; - } -#else - failf(data, "Library lacks pinning support built-in"); - return CURLE_NOT_BUILT_IN; -#endif - } - -#ifdef HAVE_ALPN - if(conn->bits.tls_enable_alpn) { - int rc; - char *protocol = NULL; - unsigned short protocol_len = 0; - - rc = wolfSSL_ALPN_GetProtocol(BACKEND->handle, &protocol, &protocol_len); - - if(rc == SSL_SUCCESS) { - infof(data, "ALPN, server accepted to use %.*s\n", protocol_len, - protocol); - - if(protocol_len == ALPN_HTTP_1_1_LENGTH && - !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) - conn->negnpn = CURL_HTTP_VERSION_1_1; -#ifdef USE_NGHTTP2 - else if(data->set.httpversion >= CURL_HTTP_VERSION_2 && - protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN && - !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN)) - conn->negnpn = CURL_HTTP_VERSION_2; -#endif - else - infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len, - protocol); - } - else if(rc == SSL_ALPN_NOT_FOUND) - infof(data, "ALPN, server did not agree to a protocol\n"); - else { - failf(data, "ALPN, failure getting protocol, error %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } - } -#endif /* HAVE_ALPN */ - - connssl->connecting_state = ssl_connect_3; -#if (LIBCYASSL_VERSION_HEX >= 0x03009010) - infof(data, "SSL connection using %s / %s\n", - wolfSSL_get_version(BACKEND->handle), - wolfSSL_get_cipher_name(BACKEND->handle)); -#else - infof(data, "SSL connected\n"); -#endif - - return CURLE_OK; -} - - -static CURLcode -cyassl_connect_step3(struct connectdata *conn, - int sockindex) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - - if(SSL_SET_OPTION(primary.sessionid)) { - bool incache; - SSL_SESSION *our_ssl_sessionid; - void *old_ssl_sessionid = NULL; - - our_ssl_sessionid = SSL_get_session(BACKEND->handle); - - Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, - sockindex)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; - } - } - - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */, sockindex); - if(result) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "failed to store ssl session"); - return result; - } - } - Curl_ssl_sessionid_unlock(conn); - } - - connssl->connecting_state = ssl_connect_done; - - return result; -} - - -static ssize_t cyassl_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - char error_buffer[CYASSL_MAX_ERROR_SZ]; - int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - int rc = SSL_write(BACKEND->handle, mem, memlen); - - if(rc < 0) { - int err = SSL_get_error(BACKEND->handle, rc); - - switch(err) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - /* there's data pending, re-invoke SSL_write() */ - *curlcode = CURLE_AGAIN; - return -1; - default: - failf(conn->data, "SSL write: %s, errno %d", - ERR_error_string(err, error_buffer), - SOCKERRNO); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - } - return rc; -} - -static void Curl_cyassl_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(BACKEND->handle) { - (void)SSL_shutdown(BACKEND->handle); - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; - } - if(BACKEND->ctx) { - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = NULL; - } -} - -static ssize_t cyassl_recv(struct connectdata *conn, - int num, - char *buf, - size_t buffersize, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[num]; - char error_buffer[CYASSL_MAX_ERROR_SZ]; - int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - int nread = SSL_read(BACKEND->handle, buf, buffsize); - - if(nread < 0) { - int err = SSL_get_error(BACKEND->handle, nread); - - switch(err) { - case SSL_ERROR_ZERO_RETURN: /* no more data */ - break; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - /* there's data pending, re-invoke SSL_read() */ - *curlcode = CURLE_AGAIN; - return -1; - default: - failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(err, error_buffer), - SOCKERRNO); - *curlcode = CURLE_RECV_ERROR; - return -1; - } - } - return nread; -} - - -static void Curl_cyassl_session_free(void *ptr) -{ - (void)ptr; - /* CyaSSL reuses sessions on own, no free */ -} - - -static size_t Curl_cyassl_version(char *buffer, size_t size) -{ -#if LIBCYASSL_VERSION_HEX >= 0x03006000 - return snprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); -#elif defined(WOLFSSL_VERSION) - return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); -#elif defined(CYASSL_VERSION) - return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION); -#else - return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8"); -#endif -} - - -static int Curl_cyassl_init(void) -{ - return (CyaSSL_Init() == SSL_SUCCESS); -} - - -static bool Curl_cyassl_data_pending(const struct connectdata* conn, - int connindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - if(BACKEND->handle) /* SSL is in use */ - return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE; - else - return FALSE; -} - - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -static int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex) -{ - int retval = 0; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(BACKEND->handle) { - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; - } - return retval; -} - - -static CURLcode -cyassl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - time_t timeout_ms; - int what; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - result = cyassl_connect_step1(conn, sockindex); - if(result) - return result; - } - - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if - * this connection is part of a multi handle and this loop would - * execute again. This permits the owner of a multi handle to - * abort a connection attempt before step2 has completed while - * ensuring that a client using select() or epoll() will always - * have a valid fdset to wait on. - */ - result = cyassl_connect_step2(conn, sockindex); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return result; - } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3 == connssl->connecting_state) { - result = cyassl_connect_step3(conn, sockindex); - if(result) - return result; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = cyassl_recv; - conn->send[sockindex] = cyassl_send; - *done = TRUE; - } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - - -static CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - return cyassl_connect_common(conn, sockindex, TRUE, done); -} - - -static CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done = FALSE; - - result = cyassl_connect_common(conn, sockindex, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -static CURLcode Curl_cyassl_random(struct Curl_easy *data, - unsigned char *entropy, size_t length) -{ - RNG rng; - (void)data; - if(InitRng(&rng)) - return CURLE_FAILED_INIT; - if(length > UINT_MAX) - return CURLE_FAILED_INIT; - if(RNG_GenerateBlock(&rng, entropy, (unsigned)length)) - return CURLE_FAILED_INIT; - return CURLE_OK; -} - -static void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum /* output */, - size_t unused) -{ - Sha256 SHA256pw; - (void)unused; - InitSha256(&SHA256pw); - Sha256Update(&SHA256pw, tmp, (word32)tmplen); - Sha256Final(&SHA256pw, sha256sum); -} - -static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return BACKEND->handle; -} - -const struct Curl_ssl Curl_ssl_cyassl = { - { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */ - - 0, /* have_ca_path */ - 0, /* have_certinfo */ -#ifdef KEEP_PEER_CERT - 1, /* have_pinnedpubkey */ -#else - 0, /* have_pinnedpubkey */ -#endif - 1, /* have_ssl_ctx */ - 0, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_cyassl_init, /* init */ - Curl_none_cleanup, /* cleanup */ - Curl_cyassl_version, /* version */ - Curl_none_check_cxn, /* check_cxn */ - Curl_cyassl_shutdown, /* shutdown */ - Curl_cyassl_data_pending, /* data_pending */ - Curl_cyassl_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_cyassl_connect, /* connect */ - Curl_cyassl_connect_nonblocking, /* connect_nonblocking */ - Curl_cyassl_get_internals, /* get_internals */ - Curl_cyassl_close, /* close */ - Curl_none_close_all, /* close_all */ - Curl_cyassl_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - Curl_cyassl_sha256sum /* sha256sum */ -}; - -#endif diff --git a/dep/cpr/opt/curl/lib/vtls/cyassl.h b/dep/cpr/opt/curl/lib/vtls/cyassl.h deleted file mode 100644 index 01e11cc23a7..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/cyassl.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef HEADER_CURL_CYASSL_H -#define HEADER_CURL_CYASSL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifdef USE_CYASSL - -extern const struct Curl_ssl Curl_ssl_cyassl; - -#endif /* USE_CYASSL */ -#endif /* HEADER_CURL_CYASSL_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/darwinssl.c b/dep/cpr/opt/curl/lib/vtls/darwinssl.c deleted file mode 100644 index a98f43307af..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/darwinssl.c +++ /dev/null @@ -1,2950 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2014, Nick Zitzmann, . - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all iOS and Mac OS X SecureTransport-specific code for the - * TLS/SSL layer. No code but vtls.c should ever call or use these functions. - */ - -#include "curl_setup.h" - -#include "urldata.h" /* for the Curl_easy definition */ -#include "curl_base64.h" -#include "strtok.h" - -#ifdef USE_DARWINSSL - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-pointer-compare" -#endif /* __clang__ */ - -#ifdef HAVE_LIMITS_H -#include -#endif - -#include -/* For some reason, when building for iOS, the omnibus header above does - * not include SecureTransport.h as of iOS SDK 5.1. */ -#include -#include -#include - -/* The Security framework has changed greatly between iOS and different OS X - versions, and we will try to support as many of them as we can (back to - Leopard and iOS 5) by using macros and weak-linking. - - IMPORTANT: If TLS 1.1 and 1.2 support are important for you on OS X, then - you must build this project against the 10.8 SDK or later. */ -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) - -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 -#error "The darwinssl back-end requires Leopard or later." -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */ - -#define CURL_BUILD_IOS 0 -#define CURL_BUILD_IOS_7 0 -#define CURL_BUILD_MAC 1 -/* This is the maximum API level we are allowed to use when building: */ -#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 -#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 -#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 -#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 -#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 -/* These macros mean "the following code is present to allow runtime backward - compatibility with at least this cat or earlier": - (You set this at build-time by setting the MACOSX_DEPLOYMENT_TARGET - environmental variable.) */ -#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 -#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060 -#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 -#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080 -#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 - -#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE -#define CURL_BUILD_IOS 1 -#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 -#define CURL_BUILD_MAC 0 -#define CURL_BUILD_MAC_10_5 0 -#define CURL_BUILD_MAC_10_6 0 -#define CURL_BUILD_MAC_10_7 0 -#define CURL_BUILD_MAC_10_8 0 -#define CURL_SUPPORT_MAC_10_5 0 -#define CURL_SUPPORT_MAC_10_6 0 -#define CURL_SUPPORT_MAC_10_7 0 -#define CURL_SUPPORT_MAC_10_8 0 -#define CURL_SUPPORT_MAC_10_9 0 - -#else -#error "The darwinssl back-end requires iOS or OS X." -#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ - -#if CURL_BUILD_MAC -#include -#endif /* CURL_BUILD_MAC */ - -#include "urldata.h" -#include "sendf.h" -#include "inet_pton.h" -#include "connect.h" -#include "select.h" -#include "vtls.h" -#include "darwinssl.h" -#include "curl_printf.h" - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* From MacTypes.h (which we can't include because it isn't present in iOS: */ -#define ioErr -36 -#define paramErr -50 - -struct ssl_backend_data { - SSLContextRef ssl_ctx; - curl_socket_t ssl_sockfd; - bool ssl_direction; /* true if writing, false if reading */ - size_t ssl_write_buffered_length; -}; - -#define BACKEND connssl->backend - -/* pinned public key support tests */ - -/* version 1 supports macOS 10.12+ and iOS 10+ */ -#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \ - (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)) -#define DARWIN_SSL_PINNEDPUBKEY_V1 1 -#endif - -/* version 2 supports MacOSX 10.7+ */ -#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) -#define DARWIN_SSL_PINNEDPUBKEY_V2 1 -#endif - -#if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2) -/* this backend supports CURLOPT_PINNEDPUBLICKEY */ -#define DARWIN_SSL_PINNEDPUBKEY 1 -#endif /* DARWIN_SSL_PINNEDPUBKEY */ - -#ifdef DARWIN_SSL_PINNEDPUBKEY -/* both new and old APIs return rsa keys missing the spki header (not DER) */ -static const unsigned char rsa4096SpkiHeader[] = { - 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, - 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00}; - -static const unsigned char rsa2048SpkiHeader[] = { - 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, - 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00}; -#ifdef DARWIN_SSL_PINNEDPUBKEY_V1 -/* the *new* version doesn't return DER encoded ecdsa certs like the old... */ -static const unsigned char ecDsaSecp256r1SpkiHeader[] = { - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, - 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, - 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, - 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, - 0x42, 0x00}; - -static const unsigned char ecDsaSecp384r1SpkiHeader[] = { - 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, - 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, - 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, - 0x00, 0x22, 0x03, 0x62, 0x00}; -#endif /* DARWIN_SSL_PINNEDPUBKEY_V1 */ -#endif /* DARWIN_SSL_PINNEDPUBKEY */ - -/* The following two functions were ripped from Apple sample code, - * with some modifications: */ -static OSStatus SocketRead(SSLConnectionRef connection, - void *data, /* owned by - * caller, data - * RETURNED */ - size_t *dataLength) /* IN/OUT */ -{ - size_t bytesToGo = *dataLength; - size_t initLen = bytesToGo; - UInt8 *currData = (UInt8 *)data; - /*int sock = *(int *)connection;*/ - struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; - int sock = BACKEND->ssl_sockfd; - OSStatus rtn = noErr; - size_t bytesRead; - ssize_t rrtn; - int theErr; - - *dataLength = 0; - - for(;;) { - bytesRead = 0; - rrtn = read(sock, currData, bytesToGo); - if(rrtn <= 0) { - /* this is guesswork... */ - theErr = errno; - if(rrtn == 0) { /* EOF = server hung up */ - /* the framework will turn this into errSSLClosedNoNotify */ - rtn = errSSLClosedGraceful; - } - else /* do the switch */ - switch(theErr) { - case ENOENT: - /* connection closed */ - rtn = errSSLClosedGraceful; - break; - case ECONNRESET: - rtn = errSSLClosedAbort; - break; - case EAGAIN: - rtn = errSSLWouldBlock; - BACKEND->ssl_direction = false; - break; - default: - rtn = ioErr; - break; - } - break; - } - else { - bytesRead = rrtn; - } - bytesToGo -= bytesRead; - currData += bytesRead; - - if(bytesToGo == 0) { - /* filled buffer with incoming data, done */ - break; - } - } - *dataLength = initLen - bytesToGo; - - return rtn; -} - -static OSStatus SocketWrite(SSLConnectionRef connection, - const void *data, - size_t *dataLength) /* IN/OUT */ -{ - size_t bytesSent = 0; - /*int sock = *(int *)connection;*/ - struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; - int sock = BACKEND->ssl_sockfd; - ssize_t length; - size_t dataLen = *dataLength; - const UInt8 *dataPtr = (UInt8 *)data; - OSStatus ortn; - int theErr; - - *dataLength = 0; - - do { - length = write(sock, - (char *)dataPtr + bytesSent, - dataLen - bytesSent); - } while((length > 0) && - ( (bytesSent += length) < dataLen) ); - - if(length <= 0) { - theErr = errno; - if(theErr == EAGAIN) { - ortn = errSSLWouldBlock; - BACKEND->ssl_direction = true; - } - else { - ortn = ioErr; - } - } - else { - ortn = noErr; - } - *dataLength = bytesSent; - return ortn; -} - -#ifndef CURL_DISABLE_VERBOSE_STRINGS -CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) -{ - switch(cipher) { - /* SSL version 3.0 */ - case SSL_RSA_WITH_NULL_MD5: - return "SSL_RSA_WITH_NULL_MD5"; - break; - case SSL_RSA_WITH_NULL_SHA: - return "SSL_RSA_WITH_NULL_SHA"; - break; - case SSL_RSA_EXPORT_WITH_RC4_40_MD5: - return "SSL_RSA_EXPORT_WITH_RC4_40_MD5"; - break; - case SSL_RSA_WITH_RC4_128_MD5: - return "SSL_RSA_WITH_RC4_128_MD5"; - break; - case SSL_RSA_WITH_RC4_128_SHA: - return "SSL_RSA_WITH_RC4_128_SHA"; - break; - case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: - return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"; - break; - case SSL_RSA_WITH_IDEA_CBC_SHA: - return "SSL_RSA_WITH_IDEA_CBC_SHA"; - break; - case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"; - break; - case SSL_RSA_WITH_DES_CBC_SHA: - return "SSL_RSA_WITH_DES_CBC_SHA"; - break; - case SSL_RSA_WITH_3DES_EDE_CBC_SHA: - return "SSL_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"; - break; - case SSL_DH_DSS_WITH_DES_CBC_SHA: - return "SSL_DH_DSS_WITH_DES_CBC_SHA"; - break; - case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: - return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"; - break; - case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"; - break; - case SSL_DH_RSA_WITH_DES_CBC_SHA: - return "SSL_DH_RSA_WITH_DES_CBC_SHA"; - break; - case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: - return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"; - break; - case SSL_DHE_DSS_WITH_DES_CBC_SHA: - return "SSL_DHE_DSS_WITH_DES_CBC_SHA"; - break; - case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; - break; - case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"; - break; - case SSL_DHE_RSA_WITH_DES_CBC_SHA: - return "SSL_DHE_RSA_WITH_DES_CBC_SHA"; - break; - case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: - return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: - return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"; - break; - case SSL_DH_anon_WITH_RC4_128_MD5: - return "SSL_DH_anon_WITH_RC4_128_MD5"; - break; - case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"; - break; - case SSL_DH_anon_WITH_DES_CBC_SHA: - return "SSL_DH_anon_WITH_DES_CBC_SHA"; - break; - case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: - return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"; - break; - case SSL_FORTEZZA_DMS_WITH_NULL_SHA: - return "SSL_FORTEZZA_DMS_WITH_NULL_SHA"; - break; - case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: - return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"; - break; - /* TLS 1.0 with AES (RFC 3268) - (Apparently these are used in SSLv3 implementations as well.) */ - case TLS_RSA_WITH_AES_128_CBC_SHA: - return "TLS_RSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_DH_DSS_WITH_AES_128_CBC_SHA: - return "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; - break; - case TLS_DH_RSA_WITH_AES_128_CBC_SHA: - return "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; - break; - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: - return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_DH_anon_WITH_AES_128_CBC_SHA: - return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; - break; - case TLS_RSA_WITH_AES_256_CBC_SHA: - return "TLS_RSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_DH_DSS_WITH_AES_256_CBC_SHA: - return "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; - break; - case TLS_DH_RSA_WITH_AES_256_CBC_SHA: - return "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; - break; - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: - return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_DH_anon_WITH_AES_256_CBC_SHA: - return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; - break; - /* SSL version 2.0 */ - case SSL_RSA_WITH_RC2_CBC_MD5: - return "SSL_RSA_WITH_RC2_CBC_MD5"; - break; - case SSL_RSA_WITH_IDEA_CBC_MD5: - return "SSL_RSA_WITH_IDEA_CBC_MD5"; - break; - case SSL_RSA_WITH_DES_CBC_MD5: - return "SSL_RSA_WITH_DES_CBC_MD5"; - break; - case SSL_RSA_WITH_3DES_EDE_CBC_MD5: - return "SSL_RSA_WITH_3DES_EDE_CBC_MD5"; - break; - } - return "SSL_NULL_WITH_NULL_NULL"; -} - -CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) -{ - switch(cipher) { - /* TLS 1.0 with AES (RFC 3268) */ - case TLS_RSA_WITH_AES_128_CBC_SHA: - return "TLS_RSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_DH_DSS_WITH_AES_128_CBC_SHA: - return "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; - break; - case TLS_DH_RSA_WITH_AES_128_CBC_SHA: - return "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; - break; - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: - return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_DH_anon_WITH_AES_128_CBC_SHA: - return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; - break; - case TLS_RSA_WITH_AES_256_CBC_SHA: - return "TLS_RSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_DH_DSS_WITH_AES_256_CBC_SHA: - return "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; - break; - case TLS_DH_RSA_WITH_AES_256_CBC_SHA: - return "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; - break; - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: - return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_DH_anon_WITH_AES_256_CBC_SHA: - return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; - break; -#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS - /* TLS 1.0 with ECDSA (RFC 4492) */ - case TLS_ECDH_ECDSA_WITH_NULL_SHA: - return "TLS_ECDH_ECDSA_WITH_NULL_SHA"; - break; - case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: - return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"; - break; - case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: - return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: - return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: - return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_ECDHE_ECDSA_WITH_NULL_SHA: - return "TLS_ECDHE_ECDSA_WITH_NULL_SHA"; - break; - case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: - return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"; - break; - case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: - return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: - return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: - return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_ECDH_RSA_WITH_NULL_SHA: - return "TLS_ECDH_RSA_WITH_NULL_SHA"; - break; - case TLS_ECDH_RSA_WITH_RC4_128_SHA: - return "TLS_ECDH_RSA_WITH_RC4_128_SHA"; - break; - case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: - return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: - return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: - return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_ECDHE_RSA_WITH_NULL_SHA: - return "TLS_ECDHE_RSA_WITH_NULL_SHA"; - break; - case TLS_ECDHE_RSA_WITH_RC4_128_SHA: - return "TLS_ECDHE_RSA_WITH_RC4_128_SHA"; - break; - case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: - return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: - return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; - break; - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: - return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; - break; - case TLS_ECDH_anon_WITH_NULL_SHA: - return "TLS_ECDH_anon_WITH_NULL_SHA"; - break; - case TLS_ECDH_anon_WITH_RC4_128_SHA: - return "TLS_ECDH_anon_WITH_RC4_128_SHA"; - break; - case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: - return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: - return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"; - break; - case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: - return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; - break; -#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - /* TLS 1.2 (RFC 5246) */ - case TLS_RSA_WITH_NULL_MD5: - return "TLS_RSA_WITH_NULL_MD5"; - break; - case TLS_RSA_WITH_NULL_SHA: - return "TLS_RSA_WITH_NULL_SHA"; - break; - case TLS_RSA_WITH_RC4_128_MD5: - return "TLS_RSA_WITH_RC4_128_MD5"; - break; - case TLS_RSA_WITH_RC4_128_SHA: - return "TLS_RSA_WITH_RC4_128_SHA"; - break; - case TLS_RSA_WITH_3DES_EDE_CBC_SHA: - return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_RSA_WITH_NULL_SHA256: - return "TLS_RSA_WITH_NULL_SHA256"; - break; - case TLS_RSA_WITH_AES_128_CBC_SHA256: - return "TLS_RSA_WITH_AES_128_CBC_SHA256"; - break; - case TLS_RSA_WITH_AES_256_CBC_SHA256: - return "TLS_RSA_WITH_AES_256_CBC_SHA256"; - break; - case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: - return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: - return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: - return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_DH_DSS_WITH_AES_128_CBC_SHA256: - return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"; - break; - case TLS_DH_RSA_WITH_AES_128_CBC_SHA256: - return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"; - break; - case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: - return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"; - break; - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: - return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"; - break; - case TLS_DH_DSS_WITH_AES_256_CBC_SHA256: - return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"; - break; - case TLS_DH_RSA_WITH_AES_256_CBC_SHA256: - return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"; - break; - case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: - return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"; - break; - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: - return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"; - break; - case TLS_DH_anon_WITH_RC4_128_MD5: - return "TLS_DH_anon_WITH_RC4_128_MD5"; - break; - case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: - return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_DH_anon_WITH_AES_128_CBC_SHA256: - return "TLS_DH_anon_WITH_AES_128_CBC_SHA256"; - break; - case TLS_DH_anon_WITH_AES_256_CBC_SHA256: - return "TLS_DH_anon_WITH_AES_256_CBC_SHA256"; - break; - /* TLS 1.2 with AES GCM (RFC 5288) */ - case TLS_RSA_WITH_AES_128_GCM_SHA256: - return "TLS_RSA_WITH_AES_128_GCM_SHA256"; - break; - case TLS_RSA_WITH_AES_256_GCM_SHA384: - return "TLS_RSA_WITH_AES_256_GCM_SHA384"; - break; - case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: - return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"; - break; - case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: - return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"; - break; - case TLS_DH_RSA_WITH_AES_128_GCM_SHA256: - return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"; - break; - case TLS_DH_RSA_WITH_AES_256_GCM_SHA384: - return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"; - break; - case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: - return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"; - break; - case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: - return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"; - break; - case TLS_DH_DSS_WITH_AES_128_GCM_SHA256: - return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"; - break; - case TLS_DH_DSS_WITH_AES_256_GCM_SHA384: - return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"; - break; - case TLS_DH_anon_WITH_AES_128_GCM_SHA256: - return "TLS_DH_anon_WITH_AES_128_GCM_SHA256"; - break; - case TLS_DH_anon_WITH_AES_256_GCM_SHA384: - return "TLS_DH_anon_WITH_AES_256_GCM_SHA384"; - break; - /* TLS 1.2 with elliptic curve ciphers (RFC 5289) */ - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: - return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"; - break; - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: - return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"; - break; - case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: - return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"; - break; - case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: - return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"; - break; - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: - return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"; - break; - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: - return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"; - break; - case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: - return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"; - break; - case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: - return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"; - break; - case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: - return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; - break; - case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: - return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; - break; - case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: - return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"; - break; - case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: - return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"; - break; - case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: - return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; - break; - case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: - return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"; - break; - case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: - return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"; - break; - case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: - return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"; - break; - case TLS_EMPTY_RENEGOTIATION_INFO_SCSV: - return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; - break; -#else - case SSL_RSA_WITH_NULL_MD5: - return "TLS_RSA_WITH_NULL_MD5"; - break; - case SSL_RSA_WITH_NULL_SHA: - return "TLS_RSA_WITH_NULL_SHA"; - break; - case SSL_RSA_WITH_RC4_128_MD5: - return "TLS_RSA_WITH_RC4_128_MD5"; - break; - case SSL_RSA_WITH_RC4_128_SHA: - return "TLS_RSA_WITH_RC4_128_SHA"; - break; - case SSL_RSA_WITH_3DES_EDE_CBC_SHA: - return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; - break; - case SSL_DH_anon_WITH_RC4_128_MD5: - return "TLS_DH_anon_WITH_RC4_128_MD5"; - break; - case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: - return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; - break; -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ -#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 - /* TLS PSK (RFC 4279): */ - case TLS_PSK_WITH_RC4_128_SHA: - return "TLS_PSK_WITH_RC4_128_SHA"; - break; - case TLS_PSK_WITH_3DES_EDE_CBC_SHA: - return "TLS_PSK_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_PSK_WITH_AES_128_CBC_SHA: - return "TLS_PSK_WITH_AES_128_CBC_SHA"; - break; - case TLS_PSK_WITH_AES_256_CBC_SHA: - return "TLS_PSK_WITH_AES_256_CBC_SHA"; - break; - case TLS_DHE_PSK_WITH_RC4_128_SHA: - return "TLS_DHE_PSK_WITH_RC4_128_SHA"; - break; - case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: - return "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_DHE_PSK_WITH_AES_128_CBC_SHA: - return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"; - break; - case TLS_DHE_PSK_WITH_AES_256_CBC_SHA: - return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"; - break; - case TLS_RSA_PSK_WITH_RC4_128_SHA: - return "TLS_RSA_PSK_WITH_RC4_128_SHA"; - break; - case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: - return "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"; - break; - case TLS_RSA_PSK_WITH_AES_128_CBC_SHA: - return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"; - break; - case TLS_RSA_PSK_WITH_AES_256_CBC_SHA: - return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"; - break; - /* More TLS PSK (RFC 4785): */ - case TLS_PSK_WITH_NULL_SHA: - return "TLS_PSK_WITH_NULL_SHA"; - break; - case TLS_DHE_PSK_WITH_NULL_SHA: - return "TLS_DHE_PSK_WITH_NULL_SHA"; - break; - case TLS_RSA_PSK_WITH_NULL_SHA: - return "TLS_RSA_PSK_WITH_NULL_SHA"; - break; - /* Even more TLS PSK (RFC 5487): */ - case TLS_PSK_WITH_AES_128_GCM_SHA256: - return "TLS_PSK_WITH_AES_128_GCM_SHA256"; - break; - case TLS_PSK_WITH_AES_256_GCM_SHA384: - return "TLS_PSK_WITH_AES_256_GCM_SHA384"; - break; - case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: - return "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"; - break; - case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: - return "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"; - break; - case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: - return "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"; - break; - case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: - return "TLS_PSK_WITH_AES_256_GCM_SHA384"; - break; - case TLS_PSK_WITH_AES_128_CBC_SHA256: - return "TLS_PSK_WITH_AES_128_CBC_SHA256"; - break; - case TLS_PSK_WITH_AES_256_CBC_SHA384: - return "TLS_PSK_WITH_AES_256_CBC_SHA384"; - break; - case TLS_PSK_WITH_NULL_SHA256: - return "TLS_PSK_WITH_NULL_SHA256"; - break; - case TLS_PSK_WITH_NULL_SHA384: - return "TLS_PSK_WITH_NULL_SHA384"; - break; - case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: - return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"; - break; - case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: - return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"; - break; - case TLS_DHE_PSK_WITH_NULL_SHA256: - return "TLS_DHE_PSK_WITH_NULL_SHA256"; - break; - case TLS_DHE_PSK_WITH_NULL_SHA384: - return "TLS_RSA_PSK_WITH_NULL_SHA384"; - break; - case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: - return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"; - break; - case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: - return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"; - break; - case TLS_RSA_PSK_WITH_NULL_SHA256: - return "TLS_RSA_PSK_WITH_NULL_SHA256"; - break; - case TLS_RSA_PSK_WITH_NULL_SHA384: - return "TLS_RSA_PSK_WITH_NULL_SHA384"; - break; -#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ - } - return "TLS_NULL_WITH_NULL_NULL"; -} -#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ - -#if CURL_BUILD_MAC -CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) -{ - int mib[2]; - char *os_version; - size_t os_version_len; - char *os_version_major, *os_version_minor; - char *tok_buf; - - /* Get the Darwin kernel version from the kernel using sysctl(): */ - mib[0] = CTL_KERN; - mib[1] = KERN_OSRELEASE; - if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1) - return; - os_version = malloc(os_version_len*sizeof(char)); - if(!os_version) - return; - if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) { - free(os_version); - return; - } - - /* Parse the version: */ - os_version_major = strtok_r(os_version, ".", &tok_buf); - os_version_minor = strtok_r(NULL, ".", &tok_buf); - *major = atoi(os_version_major); - *minor = atoi(os_version_minor); - free(os_version); -} -#endif /* CURL_BUILD_MAC */ - -/* Apple provides a myriad of ways of getting information about a certificate - into a string. Some aren't available under iOS or newer cats. So here's - a unified function for getting a string describing the certificate that - ought to work in all cats starting with Leopard. */ -CF_INLINE CFStringRef getsubject(SecCertificateRef cert) -{ - CFStringRef server_cert_summary = CFSTR("(null)"); - -#if CURL_BUILD_IOS - /* iOS: There's only one way to do this. */ - server_cert_summary = SecCertificateCopySubjectSummary(cert); -#else -#if CURL_BUILD_MAC_10_7 - /* Lion & later: Get the long description if we can. */ - if(SecCertificateCopyLongDescription != NULL) - server_cert_summary = - SecCertificateCopyLongDescription(NULL, cert, NULL); - else -#endif /* CURL_BUILD_MAC_10_7 */ -#if CURL_BUILD_MAC_10_6 - /* Snow Leopard: Get the certificate summary. */ - if(SecCertificateCopySubjectSummary != NULL) - server_cert_summary = SecCertificateCopySubjectSummary(cert); - else -#endif /* CURL_BUILD_MAC_10_6 */ - /* Leopard is as far back as we go... */ - (void)SecCertificateCopyCommonName(cert, &server_cert_summary); -#endif /* CURL_BUILD_IOS */ - return server_cert_summary; -} - -static CURLcode CopyCertSubject(struct Curl_easy *data, - SecCertificateRef cert, char **certp) -{ - CFStringRef c = getsubject(cert); - CURLcode result = CURLE_OK; - const char *direct; - char *cbuf = NULL; - *certp = NULL; - - if(!c) { - failf(data, "SSL: invalid CA certificate subject"); - return CURLE_OUT_OF_MEMORY; - } - - /* If the subject is already available as UTF-8 encoded (ie 'direct') then - use that, else convert it. */ - direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8); - if(direct) { - *certp = strdup(direct); - if(!*certp) { - failf(data, "SSL: out of memory"); - result = CURLE_OUT_OF_MEMORY; - } - } - else { - size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1; - cbuf = calloc(cbuf_size, 1); - if(cbuf) { - if(!CFStringGetCString(c, cbuf, cbuf_size, - kCFStringEncodingUTF8)) { - failf(data, "SSL: invalid CA certificate subject"); - result = CURLE_SSL_CACERT; - } - else - /* pass back the buffer */ - *certp = cbuf; - } - else { - failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size); - result = CURLE_OUT_OF_MEMORY; - } - } - if(result) - free(cbuf); - CFRelease(c); - return result; -} - -#if CURL_SUPPORT_MAC_10_6 -/* The SecKeychainSearch API was deprecated in Lion, and using it will raise - deprecation warnings, so let's not compile this unless it's necessary: */ -static OSStatus CopyIdentityWithLabelOldSchool(char *label, - SecIdentityRef *out_c_a_k) -{ - OSStatus status = errSecItemNotFound; - SecKeychainAttributeList attr_list; - SecKeychainAttribute attr; - SecKeychainSearchRef search = NULL; - SecCertificateRef cert = NULL; - - /* Set up the attribute list: */ - attr_list.count = 1L; - attr_list.attr = &attr; - - /* Set up our lone search criterion: */ - attr.tag = kSecLabelItemAttr; - attr.data = label; - attr.length = (UInt32)strlen(label); - - /* Start searching: */ - status = SecKeychainSearchCreateFromAttributes(NULL, - kSecCertificateItemClass, - &attr_list, - &search); - if(status == noErr) { - status = SecKeychainSearchCopyNext(search, - (SecKeychainItemRef *)&cert); - if(status == noErr && cert) { - /* If we found a certificate, does it have a private key? */ - status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k); - CFRelease(cert); - } - } - - if(search) - CFRelease(search); - return status; -} -#endif /* CURL_SUPPORT_MAC_10_6 */ - -static OSStatus CopyIdentityWithLabel(char *label, - SecIdentityRef *out_cert_and_key) -{ - OSStatus status = errSecItemNotFound; - -#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS - CFArrayRef keys_list; - CFIndex keys_list_count; - CFIndex i; - CFStringRef common_name; - - /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. - kSecClassIdentity was introduced in Lion. If both exist, let's use them - to find the certificate. */ - if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) { - CFTypeRef keys[5]; - CFTypeRef values[5]; - CFDictionaryRef query_dict; - CFStringRef label_cf = CFStringCreateWithCString(NULL, label, - kCFStringEncodingUTF8); - - /* Set up our search criteria and expected results: */ - values[0] = kSecClassIdentity; /* we want a certificate and a key */ - keys[0] = kSecClass; - values[1] = kCFBooleanTrue; /* we want a reference */ - keys[1] = kSecReturnRef; - values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the - * label matching below worked correctly */ - keys[2] = kSecMatchLimit; - /* identity searches need a SecPolicyRef in order to work */ - values[3] = SecPolicyCreateSSL(false, NULL); - keys[3] = kSecMatchPolicy; - /* match the name of the certificate (doesn't work in macOS 10.12.1) */ - values[4] = label_cf; - keys[4] = kSecAttrLabel; - query_dict = CFDictionaryCreate(NULL, (const void **)keys, - (const void **)values, 5L, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFRelease(values[3]); - - /* Do we have a match? */ - status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list); - - /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity, - * we need to find the correct identity ourselves */ - if(status == noErr) { - keys_list_count = CFArrayGetCount(keys_list); - *out_cert_and_key = NULL; - status = 1; - for(i = 0; idata; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - - switch(ssl_version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - ssl_version = CURL_SSLVERSION_TLSv1_0; - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - ssl_version_max = ssl_version << 16; - break; - case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLSetProtocolVersionMax != NULL) { - SSLProtocol darwin_ver_min = kTLSProtocol1; - SSLProtocol darwin_ver_max = kTLSProtocol1; - CURLcode result = darwinssl_version_from_curl(&darwin_ver_min, - ssl_version); - if(result) { - failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); - return result; - } - result = darwinssl_version_from_curl(&darwin_ver_max, - ssl_version_max >> 16); - if(result) { - failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); - return result; - } - - (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, darwin_ver_min); - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, darwin_ver_max); - return result; - } - else { -#if CURL_SUPPORT_MAC_10_8 - long i = ssl_version; - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kSSLProtocolAll, - false); - for(; i <= (ssl_version_max >> 16); i++) { - switch(i) { - case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kTLSProtocol1, - true); - break; - case CURL_SSLVERSION_TLSv1_1: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kTLSProtocol11, - true); - break; - case CURL_SSLVERSION_TLSv1_2: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kTLSProtocol12, - true); - break; - case CURL_SSLVERSION_TLSv1_3: - failf(data, "DarwinSSL: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; - } - } - return CURLE_OK; -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - failf(data, "DarwinSSL: cannot set SSL protocol"); - return CURLE_SSL_CONNECT_ERROR; -} - - -static CURLcode darwinssl_connect_step1(struct connectdata *conn, - int sockindex) -{ - struct Curl_easy *data = conn->data; - curl_socket_t sockfd = conn->sock[sockindex]; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); - const bool verifypeer = SSL_CONN_CONFIG(verifypeer); - char * const ssl_cert = SSL_SET_OPTION(cert); - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif /* ENABLE_IPV6 */ - size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i; - SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL; - OSStatus err = noErr; -#if CURL_BUILD_MAC - int darwinver_maj = 0, darwinver_min = 0; - - GetDarwinVersionNumber(&darwinver_maj, &darwinver_min); -#endif /* CURL_BUILD_MAC */ - -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLCreateContext != NULL) { /* use the newer API if avaialble */ - if(BACKEND->ssl_ctx) - CFRelease(BACKEND->ssl_ctx); - BACKEND->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); - if(!BACKEND->ssl_ctx) { - failf(data, "SSL: couldn't create a context!"); - return CURLE_OUT_OF_MEMORY; - } - } - else { - /* The old ST API does not exist under iOS, so don't compile it: */ -#if CURL_SUPPORT_MAC_10_8 - if(BACKEND->ssl_ctx) - (void)SSLDisposeContext(BACKEND->ssl_ctx); - err = SSLNewContext(false, &(BACKEND->ssl_ctx)); - if(err != noErr) { - failf(data, "SSL: couldn't create a context: OSStatus %d", err); - return CURLE_OUT_OF_MEMORY; - } -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#else - if(BACKEND->ssl_ctx) - (void)SSLDisposeContext(BACKEND->ssl_ctx); - err = SSLNewContext(false, &(BACKEND->ssl_ctx)); - if(err != noErr) { - failf(data, "SSL: couldn't create a context: OSStatus %d", err); - return CURLE_OUT_OF_MEMORY; - } -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - BACKEND->ssl_write_buffered_length = 0UL; /* reset buffered write length */ - - /* check to see if we've been told to use an explicit SSL/TLS version */ -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLSetProtocolVersionMax != NULL) { - switch(conn->ssl_config.version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kTLSProtocol1); - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12); - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(conn, sockindex); - if(result != CURLE_OK) - return result; - break; - } - case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol3); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv3"); - return CURLE_SSL_CONNECT_ERROR; - } - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol3); - break; - case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol2); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol2); - break; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - } - else { -#if CURL_SUPPORT_MAC_10_8 - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kSSLProtocolAll, - false); - switch(conn->ssl_config.version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kTLSProtocol1, - true); - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kTLSProtocol11, - true); - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kTLSProtocol12, - true); - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(conn, sockindex); - if(result != CURLE_OK) - return result; - break; - } - case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kSSLProtocol3, - true); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv3"); - return CURLE_SSL_CONNECT_ERROR; - } - break; - case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kSSLProtocol2, - true); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - break; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#else - if(conn->ssl_config.version_max != CURL_SSLVERSION_MAX_NONE) { - failf(data, "Your version of the OS does not support to set maximum" - " SSL/TLS version"); - return CURLE_SSL_CONNECT_ERROR; - } - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocolAll, false); - switch(conn->ssl_config.version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kTLSProtocol1, - true); - break; - case CURL_SSLVERSION_TLSv1_1: - failf(data, "Your version of the OS does not support TLSv1.1"); - return CURLE_SSL_CONNECT_ERROR; - case CURL_SSLVERSION_TLSv1_2: - failf(data, "Your version of the OS does not support TLSv1.2"); - return CURLE_SSL_CONNECT_ERROR; - case CURL_SSLVERSION_TLSv1_3: - failf(data, "Your version of the OS does not support TLSv1.3"); - return CURLE_SSL_CONNECT_ERROR; - case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kSSLProtocol2, - true); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - break; - case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, - kSSLProtocol3, - true); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv3"); - return CURLE_SSL_CONNECT_ERROR; - } - break; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - - if(SSL_SET_OPTION(key)) { - infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " - "Transport. The private key must be in the Keychain.\n"); - } - - if(ssl_cert) { - SecIdentityRef cert_and_key = NULL; - bool is_cert_file = is_file(ssl_cert); - - /* User wants to authenticate with a client cert. Look for it: - If we detect that this is a file on disk, then let's load it. - Otherwise, assume that the user wants to use an identity loaded - from the Keychain. */ - if(is_cert_file) { - if(!SSL_SET_OPTION(cert_type)) - infof(data, "WARNING: SSL: Certificate type not set, assuming " - "PKCS#12 format.\n"); - else if(strncmp(SSL_SET_OPTION(cert_type), "P12", - strlen(SSL_SET_OPTION(cert_type))) != 0) - infof(data, "WARNING: SSL: The Security framework only supports " - "loading identities that are in PKCS#12 format.\n"); - - err = CopyIdentityFromPKCS12File(ssl_cert, - SSL_SET_OPTION(key_passwd), &cert_and_key); - } - else - err = CopyIdentityWithLabel(ssl_cert, &cert_and_key); - - if(err == noErr && cert_and_key) { - SecCertificateRef cert = NULL; - CFTypeRef certs_c[1]; - CFArrayRef certs; - - /* If we found one, print it out: */ - err = SecIdentityCopyCertificate(cert_and_key, &cert); - if(err == noErr) { - char *certp; - CURLcode result = CopyCertSubject(data, cert, &certp); - if(!result) { - infof(data, "Client certificate: %s\n", certp); - free(certp); - } - - CFRelease(cert); - if(result) - return result; - } - certs_c[0] = cert_and_key; - certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, - &kCFTypeArrayCallBacks); - err = SSLSetCertificate(BACKEND->ssl_ctx, certs); - if(certs) - CFRelease(certs); - if(err != noErr) { - failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err); - return CURLE_SSL_CERTPROBLEM; - } - CFRelease(cert_and_key); - } - else { - switch(err) { - case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ - failf(data, "SSL: Incorrect password for the certificate \"%s\" " - "and its private key.", ssl_cert); - break; - case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ - failf(data, "SSL: Couldn't make sense of the data in the " - "certificate \"%s\" and its private key.", - ssl_cert); - break; - case -25260: /* errSecPassphraseRequired */ - failf(data, "SSL The certificate \"%s\" requires a password.", - ssl_cert); - break; - case errSecItemNotFound: - failf(data, "SSL: Can't find the certificate \"%s\" and its private " - "key in the Keychain.", ssl_cert); - break; - default: - failf(data, "SSL: Can't load the certificate \"%s\" and its private " - "key: OSStatus %d", ssl_cert, err); - break; - } - return CURLE_SSL_CERTPROBLEM; - } - } - - /* SSL always tries to verify the peer, this only says whether it should - * fail to connect if the verification fails, or if it should continue - * anyway. In the latter case the result of the verification is checked with - * SSL_get_verify_result() below. */ -#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS - /* Snow Leopard introduced the SSLSetSessionOption() function, but due to - a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag - works, it doesn't work as expected under Snow Leopard, Lion or - Mountain Lion. - So we need to call SSLSetEnableCertVerify() on those older cats in order - to disable certificate validation if the user turned that off. - (SecureTransport will always validate the certificate chain by - default.) - Note: - Darwin 11.x.x is Lion (10.7) - Darwin 12.x.x is Mountain Lion (10.8) - Darwin 13.x.x is Mavericks (10.9) - Darwin 14.x.x is Yosemite (10.10) - Darwin 15.x.x is El Capitan (10.11) - */ -#if CURL_BUILD_MAC - if(SSLSetSessionOption != NULL && darwinver_maj >= 13) { -#else - if(SSLSetSessionOption != NULL) { -#endif /* CURL_BUILD_MAC */ - bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile; - err = SSLSetSessionOption(BACKEND->ssl_ctx, - kSSLSessionOptionBreakOnServerAuth, - break_on_auth); - if(err != noErr) { - failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - } - else { -#if CURL_SUPPORT_MAC_10_8 - err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, - conn->ssl_config.verifypeer?true:false); - if(err != noErr) { - failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#else - err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, - conn->ssl_config.verifypeer?true:false); - if(err != noErr) { - failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } -#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ - - if(ssl_cafile && verifypeer) { - bool is_cert_file = is_file(ssl_cafile); - - if(!is_cert_file) { - failf(data, "SSL: can't load CA certificate file %s", ssl_cafile); - return CURLE_SSL_CACERT_BADFILE; - } - } - - /* Configure hostname check. SNI is used if available. - * Both hostname check and SNI require SSLSetPeerDomainName(). - * Also: the verifyhost setting influences SNI usage */ - if(conn->ssl_config.verifyhost) { - err = SSLSetPeerDomainName(BACKEND->ssl_ctx, hostname, - strlen(hostname)); - - if(err != noErr) { - infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n", - err); - } - - if((Curl_inet_pton(AF_INET, hostname, &addr)) - #ifdef ENABLE_IPV6 - || (Curl_inet_pton(AF_INET6, hostname, &addr)) - #endif - ) { - infof(data, "WARNING: using IP address, SNI is being disabled by " - "the OS.\n"); - } - } - else { - infof(data, "WARNING: disabling hostname validation also disables SNI.\n"); - } - - /* Disable cipher suites that ST supports but are not safe. These ciphers - are unlikely to be used in any case since ST gives other ciphers a much - higher priority, but it's probably better that we not connect at all than - to give the user a false sense of security if the server only supports - insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */ - (void)SSLGetNumberSupportedCiphers(BACKEND->ssl_ctx, &all_ciphers_count); - all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); - allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); - if(all_ciphers && allowed_ciphers && - SSLGetSupportedCiphers(BACKEND->ssl_ctx, all_ciphers, - &all_ciphers_count) == noErr) { - for(i = 0UL ; i < all_ciphers_count ; i++) { -#if CURL_BUILD_MAC - /* There's a known bug in early versions of Mountain Lion where ST's ECC - ciphers (cipher suite 0xC001 through 0xC032) simply do not work. - Work around the problem here by disabling those ciphers if we are - running in an affected version of OS X. */ - if(darwinver_maj == 12 && darwinver_min <= 3 && - all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) { - continue; - } -#endif /* CURL_BUILD_MAC */ - switch(all_ciphers[i]) { - /* Disable NULL ciphersuites: */ - case SSL_NULL_WITH_NULL_NULL: - case SSL_RSA_WITH_NULL_MD5: - case SSL_RSA_WITH_NULL_SHA: - case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */ - case SSL_FORTEZZA_DMS_WITH_NULL_SHA: - case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */ - case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */ - case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */ - case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */ - case 0x002C: /* TLS_PSK_WITH_NULL_SHA */ - case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */ - case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */ - case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */ - case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */ - case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */ - case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */ - case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */ - case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */ - /* Disable anonymous ciphersuites: */ - case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: - case SSL_DH_anon_WITH_RC4_128_MD5: - case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: - case SSL_DH_anon_WITH_DES_CBC_SHA: - case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: - case TLS_DH_anon_WITH_AES_128_CBC_SHA: - case TLS_DH_anon_WITH_AES_256_CBC_SHA: - case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */ - case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */ - case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */ - case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */ - case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */ - case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */ - case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */ - case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */ - case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */ - /* Disable weak key ciphersuites: */ - case SSL_RSA_EXPORT_WITH_RC4_40_MD5: - case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: - case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: - case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: - case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: - case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: - case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: - case SSL_RSA_WITH_DES_CBC_SHA: - case SSL_DH_DSS_WITH_DES_CBC_SHA: - case SSL_DH_RSA_WITH_DES_CBC_SHA: - case SSL_DHE_DSS_WITH_DES_CBC_SHA: - case SSL_DHE_RSA_WITH_DES_CBC_SHA: - /* Disable IDEA: */ - case SSL_RSA_WITH_IDEA_CBC_SHA: - case SSL_RSA_WITH_IDEA_CBC_MD5: - /* Disable RC4: */ - case SSL_RSA_WITH_RC4_128_MD5: - case SSL_RSA_WITH_RC4_128_SHA: - case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */ - case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/ - case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */ - case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */ - case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */ - case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */ - case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */ - break; - default: /* enable everything else */ - allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i]; - break; - } - } - err = SSLSetEnabledCiphers(BACKEND->ssl_ctx, allowed_ciphers, - allowed_ciphers_count); - if(err != noErr) { - failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - } - else { - Curl_safefree(all_ciphers); - Curl_safefree(allowed_ciphers); - failf(data, "SSL: Failed to allocate memory for allowed ciphers"); - return CURLE_OUT_OF_MEMORY; - } - Curl_safefree(all_ciphers); - Curl_safefree(allowed_ciphers); - -#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 - /* We want to enable 1/n-1 when using a CBC cipher unless the user - specifically doesn't want us doing that: */ - if(SSLSetSessionOption != NULL) { - /* TODO s/data->set.ssl.enable_beast/SSL_SET_OPTION(enable_beast)/g */ - SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionSendOneByteRecord, - !data->set.ssl.enable_beast); - SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionFalseStart, - data->set.ssl.falsestart); /* false start support */ - } -#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ - - /* Check if there's a cached ID we can/should use here! */ - if(SSL_SET_OPTION(primary.sessionid)) { - char *ssl_sessionid; - size_t ssl_sessionid_len; - - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, - &ssl_sessionid_len, sockindex)) { - /* we got a session id, use it! */ - err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); - Curl_ssl_sessionid_unlock(conn); - if(err != noErr) { - failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - /* Informational message */ - infof(data, "SSL re-using session ID\n"); - } - /* If there isn't one, then let's make one up! This has to be done prior - to starting the handshake. */ - else { - CURLcode result; - ssl_sessionid = - aprintf("%s:%d:%d:%s:%hu", ssl_cafile, - verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port); - ssl_sessionid_len = strlen(ssl_sessionid); - - err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); - if(err != noErr) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - - result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len, - sockindex); - Curl_ssl_sessionid_unlock(conn); - if(result) { - failf(data, "failed to store ssl session"); - return result; - } - } - } - - err = SSLSetIOFuncs(BACKEND->ssl_ctx, SocketRead, SocketWrite); - if(err != noErr) { - failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - - /* pass the raw socket into the SSL layers */ - /* We need to store the FD in a constant memory address, because - * SSLSetConnection() will not copy that address. I've found that - * conn->sock[sockindex] may change on its own. */ - BACKEND->ssl_sockfd = sockfd; - err = SSLSetConnection(BACKEND->ssl_ctx, connssl); - if(err != noErr) { - failf(data, "SSL: SSLSetConnection() failed: %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - - connssl->connecting_state = ssl_connect_2; - return CURLE_OK; -} - -static long pem_to_der(const char *in, unsigned char **out, size_t *outlen) -{ - char *sep_start, *sep_end, *cert_start, *cert_end; - size_t i, j, err; - size_t len; - unsigned char *b64; - - /* Jump through the separators at the beginning of the certificate. */ - sep_start = strstr(in, "-----"); - if(sep_start == NULL) - return 0; - cert_start = strstr(sep_start + 1, "-----"); - if(cert_start == NULL) - return -1; - - cert_start += 5; - - /* Find separator after the end of the certificate. */ - cert_end = strstr(cert_start, "-----"); - if(cert_end == NULL) - return -1; - - sep_end = strstr(cert_end + 1, "-----"); - if(sep_end == NULL) - return -1; - sep_end += 5; - - len = cert_end - cert_start; - b64 = malloc(len + 1); - if(!b64) - return -1; - - /* Create base64 string without linefeeds. */ - for(i = 0, j = 0; i < len; i++) { - if(cert_start[i] != '\r' && cert_start[i] != '\n') - b64[j++] = cert_start[i]; - } - b64[j] = '\0'; - - err = Curl_base64_decode((const char *)b64, out, outlen); - free(b64); - if(err) { - free(*out); - return -1; - } - - return sep_end - in; -} - -static int read_cert(const char *file, unsigned char **out, size_t *outlen) -{ - int fd; - ssize_t n, len = 0, cap = 512; - unsigned char buf[512], *data; - - fd = open(file, 0); - if(fd < 0) - return -1; - - data = malloc(cap); - if(!data) { - close(fd); - return -1; - } - - for(;;) { - n = read(fd, buf, sizeof(buf)); - if(n < 0) { - close(fd); - free(data); - return -1; - } - else if(n == 0) { - close(fd); - break; - } - - if(len + n >= cap) { - cap *= 2; - data = realloc(data, cap); - if(!data) { - close(fd); - return -1; - } - } - - memcpy(data + len, buf, n); - len += n; - } - data[len] = '\0'; - - *out = data; - *outlen = len; - - return 0; -} - -static int sslerr_to_curlerr(struct Curl_easy *data, int err) -{ - switch(err) { - case errSSLXCertChainInvalid: - failf(data, "SSL certificate problem: Invalid certificate chain"); - return CURLE_SSL_CACERT; - case errSSLUnknownRootCert: - failf(data, "SSL certificate problem: Untrusted root certificate"); - return CURLE_SSL_CACERT; - case errSSLNoRootCert: - failf(data, "SSL certificate problem: No root certificate"); - return CURLE_SSL_CACERT; - case errSSLCertExpired: - failf(data, "SSL certificate problem: Certificate chain had an " - "expired certificate"); - return CURLE_SSL_CACERT; - case errSSLBadCert: - failf(data, "SSL certificate problem: Couldn't understand the server " - "certificate format"); - return CURLE_SSL_CONNECT_ERROR; - case errSSLHostNameMismatch: - failf(data, "SSL certificate peer hostname mismatch"); - return CURLE_PEER_FAILED_VERIFICATION; - default: - failf(data, "SSL unexpected certificate error %d", err); - return CURLE_SSL_CACERT; - } -} - -static int append_cert_to_array(struct Curl_easy *data, - unsigned char *buf, size_t buflen, - CFMutableArrayRef array) -{ - CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen); - char *certp; - CURLcode result; - if(!certdata) { - failf(data, "SSL: failed to allocate array for CA certificate"); - return CURLE_OUT_OF_MEMORY; - } - - SecCertificateRef cacert = - SecCertificateCreateWithData(kCFAllocatorDefault, certdata); - CFRelease(certdata); - if(!cacert) { - failf(data, "SSL: failed to create SecCertificate from CA certificate"); - return CURLE_SSL_CACERT; - } - - /* Check if cacert is valid. */ - result = CopyCertSubject(data, cacert, &certp); - if(result) - return result; - free(certp); - - CFArrayAppendValue(array, cacert); - CFRelease(cacert); - - return CURLE_OK; -} - -static int verify_cert(const char *cafile, struct Curl_easy *data, - SSLContextRef ctx) -{ - int n = 0, rc; - long res; - unsigned char *certbuf, *der; - size_t buflen, derlen, offset = 0; - - if(read_cert(cafile, &certbuf, &buflen) < 0) { - failf(data, "SSL: failed to read or invalid CA certificate"); - return CURLE_SSL_CACERT; - } - - /* - * Certbuf now contains the contents of the certificate file, which can be - * - a single DER certificate, - * - a single PEM certificate or - * - a bunch of PEM certificates (certificate bundle). - * - * Go through certbuf, and convert any PEM certificate in it into DER - * format. - */ - CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks); - if(array == NULL) { - free(certbuf); - failf(data, "SSL: out of memory creating CA certificate array"); - return CURLE_OUT_OF_MEMORY; - } - - while(offset < buflen) { - n++; - - /* - * Check if the certificate is in PEM format, and convert it to DER. If - * this fails, we assume the certificate is in DER format. - */ - res = pem_to_der((const char *)certbuf + offset, &der, &derlen); - if(res < 0) { - free(certbuf); - CFRelease(array); - failf(data, "SSL: invalid CA certificate #%d (offset %d) in bundle", - n, offset); - return CURLE_SSL_CACERT; - } - offset += res; - - if(res == 0 && offset == 0) { - /* This is not a PEM file, probably a certificate in DER format. */ - rc = append_cert_to_array(data, certbuf, buflen, array); - free(certbuf); - if(rc != CURLE_OK) { - CFRelease(array); - return rc; - } - break; - } - else if(res == 0) { - /* No more certificates in the bundle. */ - free(certbuf); - break; - } - - rc = append_cert_to_array(data, der, derlen, array); - free(der); - if(rc != CURLE_OK) { - free(certbuf); - CFRelease(array); - return rc; - } - } - - SecTrustRef trust; - OSStatus ret = SSLCopyPeerTrust(ctx, &trust); - if(trust == NULL) { - failf(data, "SSL: error getting certificate chain"); - CFRelease(array); - return CURLE_OUT_OF_MEMORY; - } - else if(ret != noErr) { - CFRelease(array); - return sslerr_to_curlerr(data, ret); - } - - ret = SecTrustSetAnchorCertificates(trust, array); - if(ret != noErr) { - CFRelease(trust); - return sslerr_to_curlerr(data, ret); - } - ret = SecTrustSetAnchorCertificatesOnly(trust, true); - if(ret != noErr) { - CFRelease(trust); - return sslerr_to_curlerr(data, ret); - } - - SecTrustResultType trust_eval = 0; - ret = SecTrustEvaluate(trust, &trust_eval); - CFRelease(array); - CFRelease(trust); - if(ret != noErr) { - return sslerr_to_curlerr(data, ret); - } - - switch(trust_eval) { - case kSecTrustResultUnspecified: - case kSecTrustResultProceed: - return CURLE_OK; - - case kSecTrustResultRecoverableTrustFailure: - case kSecTrustResultDeny: - default: - failf(data, "SSL: certificate verification failed (result: %d)", - trust_eval); - return CURLE_PEER_FAILED_VERIFICATION; - } -} - -#ifdef DARWIN_SSL_PINNEDPUBKEY -static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, - SSLContextRef ctx, - const char *pinnedpubkey) -{ /* Scratch */ - size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24; - unsigned char *pubkey = NULL, *realpubkey = NULL; - const unsigned char *spkiHeader = NULL; - CFDataRef publicKeyBits = NULL; - - /* Result is returned to caller */ - CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - - /* if a path wasn't specified, don't pin */ - if(!pinnedpubkey) - return CURLE_OK; - - - if(!ctx) - return result; - - do { - SecTrustRef trust; - OSStatus ret = SSLCopyPeerTrust(ctx, &trust); - if(ret != noErr || trust == NULL) - break; - - SecKeyRef keyRef = SecTrustCopyPublicKey(trust); - CFRelease(trust); - if(keyRef == NULL) - break; - -#ifdef DARWIN_SSL_PINNEDPUBKEY_V1 - - publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL); - CFRelease(keyRef); - if(publicKeyBits == NULL) - break; - -#elif DARWIN_SSL_PINNEDPUBKEY_V2 - - OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL, - &publicKeyBits); - CFRelease(keyRef); - if(success != errSecSuccess || publicKeyBits == NULL) - break; - -#endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */ - - pubkeylen = CFDataGetLength(publicKeyBits); - pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits); - - switch(pubkeylen) { - case 526: - /* 4096 bit RSA pubkeylen == 526 */ - spkiHeader = rsa4096SpkiHeader; - break; - case 270: - /* 2048 bit RSA pubkeylen == 270 */ - spkiHeader = rsa2048SpkiHeader; - break; -#ifdef DARWIN_SSL_PINNEDPUBKEY_V1 - case 65: - /* ecDSA secp256r1 pubkeylen == 65 */ - spkiHeader = ecDsaSecp256r1SpkiHeader; - spkiHeaderLength = 26; - break; - case 97: - /* ecDSA secp384r1 pubkeylen == 97 */ - spkiHeader = ecDsaSecp384r1SpkiHeader; - spkiHeaderLength = 23; - break; - default: - infof(data, "SSL: unhandled public key length: %d\n", pubkeylen); -#elif DARWIN_SSL_PINNEDPUBKEY_V2 - default: - /* ecDSA secp256r1 pubkeylen == 91 header already included? - * ecDSA secp384r1 header already included too - * we assume rest of algorithms do same, so do nothing - */ - result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey, - pubkeylen); -#endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */ - continue; /* break from loop */ - } - - realpubkeylen = pubkeylen + spkiHeaderLength; - realpubkey = malloc(realpubkeylen); - if(!realpubkey) - break; - - memcpy(realpubkey, spkiHeader, spkiHeaderLength); - memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen); - - result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey, - realpubkeylen); - - } while(0); - - Curl_safefree(realpubkey); - if(publicKeyBits != NULL) - CFRelease(publicKeyBits); - - return result; -} -#endif /* DARWIN_SSL_PINNEDPUBKEY */ - -static CURLcode -darwinssl_connect_step2(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - OSStatus err; - SSLCipherSuite cipher; - SSLProtocol protocol = 0; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - - DEBUGASSERT(ssl_connect_2 == connssl->connecting_state - || ssl_connect_2_reading == connssl->connecting_state - || ssl_connect_2_writing == connssl->connecting_state); - - /* Here goes nothing: */ - err = SSLHandshake(BACKEND->ssl_ctx); - - if(err != noErr) { - switch(err) { - case errSSLWouldBlock: /* they're not done with us yet */ - connssl->connecting_state = BACKEND->ssl_direction ? - ssl_connect_2_writing : ssl_connect_2_reading; - return CURLE_OK; - - /* The below is errSSLServerAuthCompleted; it's not defined in - Leopard's headers */ - case -9841: - if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { - int res = verify_cert(SSL_CONN_CONFIG(CAfile), data, - BACKEND->ssl_ctx); - if(res != CURLE_OK) - return res; - } - /* the documentation says we need to call SSLHandshake() again */ - return darwinssl_connect_step2(conn, sockindex); - - /* These are all certificate problems with the server: */ - case errSSLXCertChainInvalid: - failf(data, "SSL certificate problem: Invalid certificate chain"); - return CURLE_SSL_CACERT; - case errSSLUnknownRootCert: - failf(data, "SSL certificate problem: Untrusted root certificate"); - return CURLE_SSL_CACERT; - case errSSLNoRootCert: - failf(data, "SSL certificate problem: No root certificate"); - return CURLE_SSL_CACERT; - case errSSLCertExpired: - failf(data, "SSL certificate problem: Certificate chain had an " - "expired certificate"); - return CURLE_SSL_CACERT; - case errSSLBadCert: - failf(data, "SSL certificate problem: Couldn't understand the server " - "certificate format"); - return CURLE_SSL_CONNECT_ERROR; - - /* These are all certificate problems with the client: */ - case errSecAuthFailed: - failf(data, "SSL authentication failed"); - return CURLE_SSL_CONNECT_ERROR; - case errSSLPeerHandshakeFail: - failf(data, "SSL peer handshake failed, the server most likely " - "requires a client certificate to connect"); - return CURLE_SSL_CONNECT_ERROR; - case errSSLPeerUnknownCA: - failf(data, "SSL server rejected the client certificate due to " - "the certificate being signed by an unknown certificate " - "authority"); - return CURLE_SSL_CONNECT_ERROR; - - /* This error is raised if the server's cert didn't match the server's - host name: */ - case errSSLHostNameMismatch: - failf(data, "SSL certificate peer verification failed, the " - "certificate did not match \"%s\"\n", conn->host.dispname); - return CURLE_PEER_FAILED_VERIFICATION; - - /* Generic handshake errors: */ - case errSSLConnectionRefused: - failf(data, "Server dropped the connection during the SSL handshake"); - return CURLE_SSL_CONNECT_ERROR; - case errSSLClosedAbort: - failf(data, "Server aborted the SSL handshake"); - return CURLE_SSL_CONNECT_ERROR; - case errSSLNegotiation: - failf(data, "Could not negotiate an SSL cipher suite with the server"); - return CURLE_SSL_CONNECT_ERROR; - /* Sometimes paramErr happens with buggy ciphers: */ - case paramErr: case errSSLInternal: - failf(data, "Internal SSL engine error encountered during the " - "SSL handshake"); - return CURLE_SSL_CONNECT_ERROR; - case errSSLFatalAlert: - failf(data, "Fatal SSL engine error encountered during the SSL " - "handshake"); - return CURLE_SSL_CONNECT_ERROR; - default: - failf(data, "Unknown SSL protocol error in connection to %s:%d", - hostname, err); - return CURLE_SSL_CONNECT_ERROR; - } - } - else { - /* we have been connected fine, we're not waiting for anything else. */ - connssl->connecting_state = ssl_connect_3; - -#ifdef DARWIN_SSL_PINNEDPUBKEY - if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) { - CURLcode result = pkp_pin_peer_pubkey(data, BACKEND->ssl_ctx, - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]); - if(result) { - failf(data, "SSL: public key does not match pinned public key!"); - return result; - } - } -#endif /* DARWIN_SSL_PINNEDPUBKEY */ - - /* Informational message */ - (void)SSLGetNegotiatedCipher(BACKEND->ssl_ctx, &cipher); - (void)SSLGetNegotiatedProtocolVersion(BACKEND->ssl_ctx, &protocol); - switch(protocol) { - case kSSLProtocol2: - infof(data, "SSL 2.0 connection using %s\n", - SSLCipherNameForNumber(cipher)); - break; - case kSSLProtocol3: - infof(data, "SSL 3.0 connection using %s\n", - SSLCipherNameForNumber(cipher)); - break; - case kTLSProtocol1: - infof(data, "TLS 1.0 connection using %s\n", - TLSCipherNameForNumber(cipher)); - break; -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - case kTLSProtocol11: - infof(data, "TLS 1.1 connection using %s\n", - TLSCipherNameForNumber(cipher)); - break; - case kTLSProtocol12: - infof(data, "TLS 1.2 connection using %s\n", - TLSCipherNameForNumber(cipher)); - break; -#endif - default: - infof(data, "Unknown protocol connection\n"); - break; - } - - return CURLE_OK; - } -} - -#ifndef CURL_DISABLE_VERBOSE_STRINGS -/* This should be called during step3 of the connection at the earliest */ -static void -show_verbose_server_cert(struct connectdata *conn, - int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - CFArrayRef server_certs = NULL; - SecCertificateRef server_cert; - OSStatus err; - CFIndex i, count; - SecTrustRef trust = NULL; - - if(!BACKEND->ssl_ctx) - return; - -#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS -#if CURL_BUILD_IOS -#pragma unused(server_certs) - err = SSLCopyPeerTrust(BACKEND->ssl_ctx, &trust); - /* For some reason, SSLCopyPeerTrust() can return noErr and yet return - a null trust, so be on guard for that: */ - if(err == noErr && trust) { - count = SecTrustGetCertificateCount(trust); - for(i = 0L ; i < count ; i++) { - CURLcode result; - char *certp; - server_cert = SecTrustGetCertificateAtIndex(trust, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s\n", certp); - free(certp); - } - } - CFRelease(trust); - } -#else - /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion. - The function SecTrustGetCertificateAtIndex() is officially present - in Lion, but it is unfortunately also present in Snow Leopard as - private API and doesn't work as expected. So we have to look for - a different symbol to make sure this code is only executed under - Lion or later. */ - if(SecTrustEvaluateAsync != NULL) { -#pragma unused(server_certs) - err = SSLCopyPeerTrust(BACKEND->ssl_ctx, &trust); - /* For some reason, SSLCopyPeerTrust() can return noErr and yet return - a null trust, so be on guard for that: */ - if(err == noErr && trust) { - count = SecTrustGetCertificateCount(trust); - for(i = 0L ; i < count ; i++) { - char *certp; - CURLcode result; - server_cert = SecTrustGetCertificateAtIndex(trust, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s\n", certp); - free(certp); - } - } - CFRelease(trust); - } - } - else { -#if CURL_SUPPORT_MAC_10_8 - err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); - /* Just in case SSLCopyPeerCertificates() returns null too... */ - if(err == noErr && server_certs) { - count = CFArrayGetCount(server_certs); - for(i = 0L ; i < count ; i++) { - char *certp; - CURLcode result; - server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, - i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s\n", certp); - free(certp); - } - } - CFRelease(server_certs); - } -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#endif /* CURL_BUILD_IOS */ -#else -#pragma unused(trust) - err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); - if(err == noErr) { - count = CFArrayGetCount(server_certs); - for(i = 0L ; i < count ; i++) { - CURLcode result; - char *certp; - server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s\n", certp); - free(certp); - } - } - CFRelease(server_certs); - } -#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ -} -#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ - -static CURLcode -darwinssl_connect_step3(struct connectdata *conn, - int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - /* There is no step 3! - * Well, okay, if verbose mode is on, let's print the details of the - * server certificates. */ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - if(data->set.verbose) - show_verbose_server_cert(conn, sockindex); -#endif - - connssl->connecting_state = ssl_connect_done; - return CURLE_OK; -} - -static Curl_recv darwinssl_recv; -static Curl_send darwinssl_send; - -static CURLcode -darwinssl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; - int what; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - result = darwinssl_connect_step1(conn, sockindex); - if(result) - return result; - } - - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading || - connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if this - * connection is done nonblocking and this loop would execute again. This - * permits the owner of a multi handle to abort a connection attempt - * before step2 has completed while ensuring that a client using select() - * or epoll() will always have a valid fdset to wait on. - */ - result = darwinssl_connect_step2(conn, sockindex); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return result; - - } /* repeat step2 until all transactions are done. */ - - - if(ssl_connect_3 == connssl->connecting_state) { - result = darwinssl_connect_step3(conn, sockindex); - if(result) - return result; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = darwinssl_recv; - conn->send[sockindex] = darwinssl_send; - *done = TRUE; - } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - return darwinssl_connect_common(conn, sockindex, TRUE, done); -} - -static CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done = FALSE; - - result = darwinssl_connect_common(conn, sockindex, FALSE, &done); - - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -static void Curl_darwinssl_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(BACKEND->ssl_ctx) { - (void)SSLClose(BACKEND->ssl_ctx); -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLCreateContext != NULL) - CFRelease(BACKEND->ssl_ctx); -#if CURL_SUPPORT_MAC_10_8 - else - (void)SSLDisposeContext(BACKEND->ssl_ctx); -#endif /* CURL_SUPPORT_MAC_10_8 */ -#else - (void)SSLDisposeContext(BACKEND->ssl_ctx); -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - BACKEND->ssl_ctx = NULL; - } - BACKEND->ssl_sockfd = 0; -} - -static int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - ssize_t nread; - int what; - int rc; - char buf[120]; - - if(!BACKEND->ssl_ctx) - return 0; - - if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) - return 0; - - Curl_darwinssl_close(conn, sockindex); - - rc = 0; - - what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); - - for(;;) { - if(what < 0) { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - rc = -1; - break; - } - - if(!what) { /* timeout */ - failf(data, "SSL shutdown timeout"); - break; - } - - /* Something to read, let's do it and hope that it is the close - notify alert from the server. No way to SSL_Read now, so use read(). */ - - nread = read(conn->sock[sockindex], buf, sizeof(buf)); - - if(nread < 0) { - failf(data, "read: %s", strerror(errno)); - rc = -1; - } - - if(nread <= 0) - break; - - what = SOCKET_READABLE(conn->sock[sockindex], 0); - } - - return rc; -} - -static void Curl_darwinssl_session_free(void *ptr) -{ - /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a - cached session ID inside the Security framework. There is a private - function that does this, but I don't want to have to explain to you why I - got your application rejected from the App Store due to the use of a - private API, so the best we can do is free up our own char array that we - created way back in darwinssl_connect_step1... */ - Curl_safefree(ptr); -} - -static size_t Curl_darwinssl_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, "SecureTransport"); -} - -/* - * This function uses SSLGetSessionState to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int Curl_darwinssl_check_cxn(struct connectdata *conn) -{ - struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; - OSStatus err; - SSLSessionState state; - - if(BACKEND->ssl_ctx) { - err = SSLGetSessionState(BACKEND->ssl_ctx, &state); - if(err == noErr) - return state == kSSLConnected || state == kSSLHandshake; - return -1; - } - return 0; -} - -static bool Curl_darwinssl_data_pending(const struct connectdata *conn, - int connindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - OSStatus err; - size_t buffer; - - if(BACKEND->ssl_ctx) { /* SSL is in use */ - err = SSLGetBufferedReadSize(BACKEND->ssl_ctx, &buffer); - if(err == noErr) - return buffer > 0UL; - return false; - } - else - return false; -} - -static CURLcode Curl_darwinssl_random(struct Curl_easy *data UNUSED_PARAM, - unsigned char *entropy, size_t length) -{ - /* arc4random_buf() isn't available on cats older than Lion, so let's - do this manually for the benefit of the older cats. */ - size_t i; - u_int32_t random_number = 0; - - (void)data; - - for(i = 0 ; i < length ; i++) { - if(i % sizeof(u_int32_t) == 0) - random_number = arc4random(); - entropy[i] = random_number & 0xFF; - random_number >>= 8; - } - i = random_number = 0; - return CURLE_OK; -} - -static CURLcode Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len) -{ - (void)md5len; - (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum); - return CURLE_OK; -} - -static void Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len) -{ - assert(sha256len >= CURL_SHA256_DIGEST_LENGTH); - (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum); -} - -static bool Curl_darwinssl_false_start(void) -{ -#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 - if(SSLSetSessionOption != NULL) - return TRUE; -#endif - return FALSE; -} - -static ssize_t darwinssl_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - /*struct Curl_easy *data = conn->data;*/ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - size_t processed = 0UL; - OSStatus err; - - /* The SSLWrite() function works a little differently than expected. The - fourth argument (processed) is currently documented in Apple's - documentation as: "On return, the length, in bytes, of the data actually - written." - - Now, one could interpret that as "written to the socket," but actually, - it returns the amount of data that was written to a buffer internal to - the SSLContextRef instead. So it's possible for SSLWrite() to return - errSSLWouldBlock and a number of bytes "written" because those bytes were - encrypted and written to a buffer, not to the socket. - - So if this happens, then we need to keep calling SSLWrite() over and - over again with no new data until it quits returning errSSLWouldBlock. */ - - /* Do we have buffered data to write from the last time we were called? */ - if(BACKEND->ssl_write_buffered_length) { - /* Write the buffered data: */ - err = SSLWrite(BACKEND->ssl_ctx, NULL, 0UL, &processed); - switch(err) { - case noErr: - /* processed is always going to be 0 because we didn't write to - the buffer, so return how much was written to the socket */ - processed = BACKEND->ssl_write_buffered_length; - BACKEND->ssl_write_buffered_length = 0UL; - break; - case errSSLWouldBlock: /* argh, try again */ - *curlcode = CURLE_AGAIN; - return -1L; - default: - failf(conn->data, "SSLWrite() returned error %d", err); - *curlcode = CURLE_SEND_ERROR; - return -1L; - } - } - else { - /* We've got new data to write: */ - err = SSLWrite(BACKEND->ssl_ctx, mem, len, &processed); - if(err != noErr) { - switch(err) { - case errSSLWouldBlock: - /* Data was buffered but not sent, we have to tell the caller - to try sending again, and remember how much was buffered */ - BACKEND->ssl_write_buffered_length = len; - *curlcode = CURLE_AGAIN; - return -1L; - default: - failf(conn->data, "SSLWrite() returned error %d", err); - *curlcode = CURLE_SEND_ERROR; - return -1L; - } - } - } - return (ssize_t)processed; -} - -static ssize_t darwinssl_recv(struct connectdata *conn, - int num, - char *buf, - size_t buffersize, - CURLcode *curlcode) -{ - /*struct Curl_easy *data = conn->data;*/ - struct ssl_connect_data *connssl = &conn->ssl[num]; - size_t processed = 0UL; - OSStatus err = SSLRead(BACKEND->ssl_ctx, buf, buffersize, &processed); - - if(err != noErr) { - switch(err) { - case errSSLWouldBlock: /* return how much we read (if anything) */ - if(processed) - return (ssize_t)processed; - *curlcode = CURLE_AGAIN; - return -1L; - break; - - /* errSSLClosedGraceful - server gracefully shut down the SSL session - errSSLClosedNoNotify - server hung up on us instead of sending a - closure alert notice, read() is returning 0 - Either way, inform the caller that the server disconnected. */ - case errSSLClosedGraceful: - case errSSLClosedNoNotify: - *curlcode = CURLE_OK; - return -1L; - break; - - default: - failf(conn->data, "SSLRead() return error %d", err); - *curlcode = CURLE_RECV_ERROR; - return -1L; - break; - } - } - return (ssize_t)processed; -} - -static void *Curl_darwinssl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return BACKEND->ssl_ctx; -} - -const struct Curl_ssl Curl_ssl_darwinssl = { - { CURLSSLBACKEND_DARWINSSL, "darwinssl" }, /* info */ - - 0, /* have_ca_path */ - 0, /* have_certinfo */ -#ifdef DARWIN_SSL_PINNEDPUBKEY - 1, /* have_pinnedpubkey */ -#else - 0, /* have_pinnedpubkey */ -#endif /* DARWIN_SSL_PINNEDPUBKEY */ - 0, /* have_ssl_ctx */ - 0, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_none_init, /* init */ - Curl_none_cleanup, /* cleanup */ - Curl_darwinssl_version, /* version */ - Curl_darwinssl_check_cxn, /* check_cxn */ - Curl_darwinssl_shutdown, /* shutdown */ - Curl_darwinssl_data_pending, /* data_pending */ - Curl_darwinssl_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_darwinssl_connect, /* connect */ - Curl_darwinssl_connect_nonblocking, /* connect_nonblocking */ - Curl_darwinssl_get_internals, /* get_internals */ - Curl_darwinssl_close, /* close */ - Curl_none_close_all, /* close_all */ - Curl_darwinssl_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_darwinssl_false_start, /* false_start */ - Curl_darwinssl_md5sum, /* md5sum */ - Curl_darwinssl_sha256sum /* sha256sum */ -}; - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif /* USE_DARWINSSL */ diff --git a/dep/cpr/opt/curl/lib/vtls/darwinssl.h b/dep/cpr/opt/curl/lib/vtls/darwinssl.h deleted file mode 100644 index 23c7f705cbd..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/darwinssl.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef HEADER_CURL_DARWINSSL_H -#define HEADER_CURL_DARWINSSL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2014, Nick Zitzmann, . - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifdef USE_DARWINSSL - -extern const struct Curl_ssl Curl_ssl_darwinssl; - -#endif /* USE_DARWINSSL */ -#endif /* HEADER_CURL_DARWINSSL_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/gskit.c b/dep/cpr/opt/curl/lib/vtls/gskit.c deleted file mode 100644 index ba5faeff8e4..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/gskit.c +++ /dev/null @@ -1,1390 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_GSKIT - -#include -#include - -/* Some symbols are undefined/unsupported on OS400 versions < V7R1. */ -#ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST -#define GSK_SSL_EXTN_SERVERNAME_REQUEST 230 -#endif - -#ifndef GSK_TLSV10_CIPHER_SPECS -#define GSK_TLSV10_CIPHER_SPECS 236 -#endif - -#ifndef GSK_TLSV11_CIPHER_SPECS -#define GSK_TLSV11_CIPHER_SPECS 237 -#endif - -#ifndef GSK_TLSV12_CIPHER_SPECS -#define GSK_TLSV12_CIPHER_SPECS 238 -#endif - -#ifndef GSK_PROTOCOL_TLSV11 -#define GSK_PROTOCOL_TLSV11 437 -#endif - -#ifndef GSK_PROTOCOL_TLSV12 -#define GSK_PROTOCOL_TLSV12 438 -#endif - -#ifndef GSK_FALSE -#define GSK_FALSE 0 -#endif - -#ifndef GSK_TRUE -#define GSK_TRUE 1 -#endif - - -#ifdef HAVE_LIMITS_H -# include -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "gskit.h" -#include "vtls.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "strcase.h" -#include "x509asn1.h" -#include "curl_printf.h" - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - - -/* Directions. */ -#define SOS_READ 0x01 -#define SOS_WRITE 0x02 - -/* SSL version flags. */ -#define CURL_GSKPROTO_SSLV2 0 -#define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2) -#define CURL_GSKPROTO_SSLV3 1 -#define CURL_GSKPROTO_SSLV3_MASK (1 << CURL_GSKPROTO_SSLV3) -#define CURL_GSKPROTO_TLSV10 2 -#define CURL_GSKPROTO_TLSV10_MASK (1 << CURL_GSKPROTO_TLSV10) -#define CURL_GSKPROTO_TLSV11 3 -#define CURL_GSKPROTO_TLSV11_MASK (1 << CURL_GSKPROTO_TLSV11) -#define CURL_GSKPROTO_TLSV12 4 -#define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12) -#define CURL_GSKPROTO_LAST 5 - -struct ssl_backend_data { - gsk_handle handle; - int iocport; - int localfd; - int remotefd; -}; - -#define BACKEND connssl->backend - -/* Supported ciphers. */ -typedef struct { - const char *name; /* Cipher name. */ - const char *gsktoken; /* Corresponding token for GSKit String. */ - unsigned int versions; /* SSL version flags. */ -} gskit_cipher; - -static const gskit_cipher ciphertable[] = { - { "null-md5", "01", - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | - CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, - { "null-sha", "02", - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | - CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, - { "exp-rc4-md5", "03", - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK }, - { "rc4-md5", "04", - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | - CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, - { "rc4-sha", "05", - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | - CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, - { "exp-rc2-cbc-md5", "06", - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK }, - { "exp-des-cbc-sha", "09", - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | - CURL_GSKPROTO_TLSV11_MASK }, - { "des-cbc3-sha", "0A", - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | - CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, - { "aes128-sha", "2F", - CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | - CURL_GSKPROTO_TLSV12_MASK }, - { "aes256-sha", "35", - CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | - CURL_GSKPROTO_TLSV12_MASK }, - { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK }, - { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK }, - { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK }, - { "aes128-gcm-sha256", - "9C", CURL_GSKPROTO_TLSV12_MASK }, - { "aes256-gcm-sha384", - "9D", CURL_GSKPROTO_TLSV12_MASK }, - { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK }, - { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK }, - { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK }, - { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK }, - { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK }, - { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK }, - { (const char *) NULL, (const char *) NULL, 0 } -}; - - -static bool is_separator(char c) -{ - /* Return whether character is a cipher list separator. */ - switch(c) { - case ' ': - case '\t': - case ':': - case ',': - case ';': - return true; - } - return false; -} - - -static CURLcode gskit_status(struct Curl_easy *data, int rc, - const char *procname, CURLcode defcode) -{ - /* Process GSKit status and map it to a CURLcode. */ - switch(rc) { - case GSK_OK: - case GSK_OS400_ASYNCHRONOUS_SOC_INIT: - return CURLE_OK; - case GSK_KEYRING_OPEN_ERROR: - case GSK_OS400_ERROR_NO_ACCESS: - return CURLE_SSL_CACERT_BADFILE; - case GSK_INSUFFICIENT_STORAGE: - return CURLE_OUT_OF_MEMORY; - case GSK_ERROR_BAD_V2_CIPHER: - case GSK_ERROR_BAD_V3_CIPHER: - case GSK_ERROR_NO_CIPHERS: - return CURLE_SSL_CIPHER; - case GSK_OS400_ERROR_NOT_TRUSTED_ROOT: - case GSK_ERROR_CERT_VALIDATION: - return CURLE_PEER_FAILED_VERIFICATION; - case GSK_OS400_ERROR_TIMED_OUT: - return CURLE_OPERATION_TIMEDOUT; - case GSK_WOULD_BLOCK: - return CURLE_AGAIN; - case GSK_OS400_ERROR_NOT_REGISTERED: - break; - case GSK_ERROR_IO: - switch(errno) { - case ENOMEM: - return CURLE_OUT_OF_MEMORY; - default: - failf(data, "%s I/O error: %s", procname, strerror(errno)); - break; - } - break; - default: - failf(data, "%s: %s", procname, gsk_strerror(rc)); - break; - } - return defcode; -} - - -static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, - GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok) -{ - int rc = gsk_attribute_set_enum(h, id, value); - - switch(rc) { - case GSK_OK: - return CURLE_OK; - case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno)); - break; - case GSK_ATTRIBUTE_INVALID_ID: - if(unsupported_ok) - return CURLE_UNSUPPORTED_PROTOCOL; - default: - failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc)); - break; - } - return CURLE_SSL_CONNECT_ERROR; -} - - -static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, - GSK_BUF_ID id, const char *buffer, bool unsupported_ok) -{ - int rc = gsk_attribute_set_buffer(h, id, buffer, 0); - - switch(rc) { - case GSK_OK: - return CURLE_OK; - case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno)); - break; - case GSK_ATTRIBUTE_INVALID_ID: - if(unsupported_ok) - return CURLE_UNSUPPORTED_PROTOCOL; - default: - failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc)); - break; - } - return CURLE_SSL_CONNECT_ERROR; -} - - -static CURLcode set_numeric(struct Curl_easy *data, - gsk_handle h, GSK_NUM_ID id, int value) -{ - int rc = gsk_attribute_set_numeric_value(h, id, value); - - switch(rc) { - case GSK_OK: - return CURLE_OK; - case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_numeric_value() I/O error: %s", - strerror(errno)); - break; - default: - failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc)); - break; - } - return CURLE_SSL_CONNECT_ERROR; -} - - -static CURLcode set_callback(struct Curl_easy *data, - gsk_handle h, GSK_CALLBACK_ID id, void *info) -{ - int rc = gsk_attribute_set_callback(h, id, info); - - switch(rc) { - case GSK_OK: - return CURLE_OK; - case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno)); - break; - default: - failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc)); - break; - } - return CURLE_SSL_CONNECT_ERROR; -} - - -static CURLcode set_ciphers(struct connectdata *conn, - gsk_handle h, unsigned int *protoflags) -{ - struct Curl_easy *data = conn->data; - const char *cipherlist = SSL_CONN_CONFIG(cipher_list); - const char *clp; - const gskit_cipher *ctp; - int i; - int l; - bool unsupported; - CURLcode result; - struct { - char *buf; - char *ptr; - } ciphers[CURL_GSKPROTO_LAST]; - - /* Compile cipher list into GSKit-compatible cipher lists. */ - - if(!cipherlist) - return CURLE_OK; - while(is_separator(*cipherlist)) /* Skip initial separators. */ - cipherlist++; - if(!*cipherlist) - return CURLE_OK; - - /* We allocate GSKit buffers of the same size as the input string: since - GSKit tokens are always shorter than their cipher names, allocated buffers - will always be large enough to accommodate the result. */ - l = strlen(cipherlist) + 1; - memset((char *) ciphers, 0, sizeof ciphers); - for(i = 0; i < CURL_GSKPROTO_LAST; i++) { - ciphers[i].buf = malloc(l); - if(!ciphers[i].buf) { - while(i--) - free(ciphers[i].buf); - return CURLE_OUT_OF_MEMORY; - } - ciphers[i].ptr = ciphers[i].buf; - *ciphers[i].ptr = '\0'; - } - - /* Process each cipher in input string. */ - unsupported = FALSE; - result = CURLE_OK; - for(;;) { - for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);) - cipherlist++; - l = cipherlist - clp; - if(!l) - break; - /* Search the cipher in our table. */ - for(ctp = ciphertable; ctp->name; ctp++) - if(strncasecompare(ctp->name, clp, l) && !ctp->name[l]) - break; - if(!ctp->name) { - failf(data, "Unknown cipher %.*s", l, clp); - result = CURLE_SSL_CIPHER; - } - else { - unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK | - CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK)); - for(i = 0; i < CURL_GSKPROTO_LAST; i++) { - if(ctp->versions & (1 << i)) { - strcpy(ciphers[i].ptr, ctp->gsktoken); - ciphers[i].ptr += strlen(ctp->gsktoken); - } - } - } - - /* Advance to next cipher name or end of string. */ - while(is_separator(*cipherlist)) - cipherlist++; - } - - /* Disable protocols with empty cipher lists. */ - for(i = 0; i < CURL_GSKPROTO_LAST; i++) { - if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) { - *protoflags &= ~(1 << i); - ciphers[i].buf[0] = '\0'; - } - } - - /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */ - if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) { - result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE); - if(result == CURLE_UNSUPPORTED_PROTOCOL) { - result = CURLE_OK; - if(unsupported) { - failf(data, "TLSv1.1-only ciphers are not yet supported"); - result = CURLE_SSL_CIPHER; - } - } - } - if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) { - result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE); - if(result == CURLE_UNSUPPORTED_PROTOCOL) { - result = CURLE_OK; - if(unsupported) { - failf(data, "TLSv1.2-only ciphers are not yet supported"); - result = CURLE_SSL_CIPHER; - } - } - } - - /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to - the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */ - if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) { - result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE); - if(result == CURLE_UNSUPPORTED_PROTOCOL) { - result = CURLE_OK; - strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr, - ciphers[CURL_GSKPROTO_TLSV10].ptr); - } - } - - /* Set-up other ciphers. */ - if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK)) - result = set_buffer(data, h, GSK_V3_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE); - if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK)) - result = set_buffer(data, h, GSK_V2_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE); - - /* Clean-up. */ - for(i = 0; i < CURL_GSKPROTO_LAST; i++) - free(ciphers[i].buf); - - return result; -} - - -static int Curl_gskit_init(void) -{ - /* No initialisation needed. */ - - return 1; -} - - -static void Curl_gskit_cleanup(void) -{ - /* Nothing to do. */ -} - - -static CURLcode init_environment(struct Curl_easy *data, - gsk_handle *envir, const char *appid, - const char *file, const char *label, - const char *password) -{ - int rc; - CURLcode result; - gsk_handle h; - - /* Creates the GSKit environment. */ - - rc = gsk_environment_open(&h); - switch(rc) { - case GSK_OK: - break; - case GSK_INSUFFICIENT_STORAGE: - return CURLE_OUT_OF_MEMORY; - default: - failf(data, "gsk_environment_open(): %s", gsk_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } - - result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE); - if(!result && appid) - result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE); - if(!result && file) - result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE); - if(!result && label) - result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE); - if(!result && password) - result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE); - - if(!result) { - /* Locate CAs, Client certificate and key according to our settings. - Note: this call may be blocking for some tenths of seconds. */ - result = gskit_status(data, gsk_environment_init(h), - "gsk_environment_init()", CURLE_SSL_CERTPROBLEM); - if(!result) { - *envir = h; - return result; - } - } - /* Error: rollback. */ - gsk_environment_close(&h); - return result; -} - - -static void cancel_async_handshake(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - Qso_OverlappedIO_t cstat; - - if(QsoCancelOperation(conn->sock[sockindex], 0) > 0) - QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL); -} - - -static void close_async_handshake(struct ssl_connect_data *connssl) -{ - QsoDestroyIOCompletionPort(BACKEND->iocport); - BACKEND->iocport = -1; -} - -/* SSL over SSL - * Problems: - * 1) GSKit can only perform SSL on an AF_INET or AF_INET6 stream socket. To - * pipe an SSL stream into another, it is therefore needed to have a pair - * of such communicating sockets and handle the pipelining explicitly. - * 2) OS/400 socketpair() is only implemented for domain AF_UNIX, thus cannot - * be used to produce the pipeline. - * The solution is to simulate socketpair() for AF_INET with low-level API - * listen(), bind() and connect(). - */ - -static int -inetsocketpair(int sv[2]) -{ - int lfd; /* Listening socket. */ - int sfd; /* Server socket. */ - int cfd; /* Client socket. */ - int len; - struct sockaddr_in addr1; - struct sockaddr_in addr2; - - /* Create listening socket on a local dynamic port. */ - lfd = socket(AF_INET, SOCK_STREAM, 0); - if(lfd < 0) - return -1; - memset((char *) &addr1, 0, sizeof addr1); - addr1.sin_family = AF_INET; - addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr1.sin_port = 0; - if(bind(lfd, (struct sockaddr *) &addr1, sizeof addr1) || - listen(lfd, 2) < 0) { - close(lfd); - return -1; - } - - /* Get the allocated port. */ - len = sizeof addr1; - if(getsockname(lfd, (struct sockaddr *) &addr1, &len) < 0) { - close(lfd); - return -1; - } - - /* Create the client socket. */ - cfd = socket(AF_INET, SOCK_STREAM, 0); - if(cfd < 0) { - close(lfd); - return -1; - } - - /* Request unblocking connection to the listening socket. */ - curlx_nonblock(cfd, TRUE); - if(connect(cfd, (struct sockaddr *) &addr1, sizeof addr1) < 0 && - errno != EINPROGRESS) { - close(lfd); - close(cfd); - return -1; - } - - /* Get the client dynamic port for intrusion check below. */ - len = sizeof addr2; - if(getsockname(cfd, (struct sockaddr *) &addr2, &len) < 0) { - close(lfd); - close(cfd); - return -1; - } - - /* Accept the incoming connection and get the server socket. */ - curlx_nonblock(lfd, TRUE); - for(;;) { - len = sizeof addr1; - sfd = accept(lfd, (struct sockaddr *) &addr1, &len); - if(sfd < 0) { - close(lfd); - close(cfd); - return -1; - } - - /* Check for possible intrusion from an external process. */ - if(addr1.sin_addr.s_addr == addr2.sin_addr.s_addr && - addr1.sin_port == addr2.sin_port) - break; - - /* Intrusion: reject incoming connection. */ - close(sfd); - } - - /* Done, return sockets and succeed. */ - close(lfd); - curlx_nonblock(cfd, FALSE); - sv[0] = cfd; - sv[1] = sfd; - return 0; -} - -static int pipe_ssloverssl(struct connectdata *conn, int sockindex, - int directions) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex]; - fd_set fds_read; - fd_set fds_write; - int n; - int m; - int i; - int ret = 0; - struct timeval tv = {0, 0}; - char buf[CURL_MAX_WRITE_SIZE]; - - if(!connssl->use || !connproxyssl->use) - return 0; /* No SSL over SSL: OK. */ - - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - n = -1; - if(directions & SOS_READ) { - FD_SET(BACKEND->remotefd, &fds_write); - n = BACKEND->remotefd; - } - if(directions & SOS_WRITE) { - FD_SET(BACKEND->remotefd, &fds_read); - n = BACKEND->remotefd; - FD_SET(conn->sock[sockindex], &fds_write); - if(n < conn->sock[sockindex]) - n = conn->sock[sockindex]; - } - i = select(n + 1, &fds_read, &fds_write, NULL, &tv); - if(i < 0) - return -1; /* Select error. */ - - if(FD_ISSET(BACKEND->remotefd, &fds_write)) { - /* Try getting data from HTTPS proxy and pipe it upstream. */ - n = 0; - i = gsk_secure_soc_read(connproxyssl->backend->handle, - buf, sizeof buf, &n); - switch(i) { - case GSK_OK: - if(n) { - i = write(BACKEND->remotefd, buf, n); - if(i < 0) - return -1; - ret = 1; - } - break; - case GSK_OS400_ERROR_TIMED_OUT: - case GSK_WOULD_BLOCK: - break; - default: - return -1; - } - } - - if(FD_ISSET(BACKEND->remotefd, &fds_read) && - FD_ISSET(conn->sock[sockindex], &fds_write)) { - /* Pipe data to HTTPS proxy. */ - n = read(BACKEND->remotefd, buf, sizeof buf); - if(n < 0) - return -1; - if(n) { - i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m); - if(i != GSK_OK || n != m) - return -1; - ret = 1; - } - } - - return ret; /* OK */ -} - - -static void close_one(struct ssl_connect_data *connssl, - struct connectdata *conn, int sockindex) -{ - if(BACKEND->handle) { - gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle), - "gsk_secure_soc_close()", 0); - /* Last chance to drain output. */ - while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0) - ; - BACKEND->handle = (gsk_handle) NULL; - if(BACKEND->localfd >= 0) { - close(BACKEND->localfd); - BACKEND->localfd = -1; - } - if(BACKEND->remotefd >= 0) { - close(BACKEND->remotefd); - BACKEND->remotefd = -1; - } - } - if(BACKEND->iocport >= 0) - close_async_handshake(connssl); -} - - -static ssize_t gskit_send(struct connectdata *conn, int sockindex, - const void *mem, size_t len, CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - CURLcode cc = CURLE_SEND_ERROR; - int written; - - if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) { - cc = gskit_status(data, - gsk_secure_soc_write(BACKEND->handle, - (char *) mem, (int) len, &written), - "gsk_secure_soc_write()", CURLE_SEND_ERROR); - if(cc == CURLE_OK) - if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0) - cc = CURLE_SEND_ERROR; - } - if(cc != CURLE_OK) { - *curlcode = cc; - written = -1; - } - return (ssize_t) written; /* number of bytes */ -} - - -static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, - size_t buffersize, CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[num]; - struct Curl_easy *data = conn->data; - int buffsize; - int nread; - CURLcode cc = CURLE_RECV_ERROR; - - if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) { - buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; - cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle, - buf, buffsize, &nread), - "gsk_secure_soc_read()", CURLE_RECV_ERROR); - } - switch(cc) { - case CURLE_OK: - break; - case CURLE_OPERATION_TIMEDOUT: - cc = CURLE_AGAIN; - default: - *curlcode = cc; - nread = -1; - break; - } - return (ssize_t) nread; -} - -static CURLcode -set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - long i = ssl_version; - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - ssl_version_max = ssl_version; - break; - case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_TLSv1_2; - break; - } - for(; i <= (ssl_version_max >> 16); ++i) { - switch(i) { - case CURL_SSLVERSION_TLSv1_0: - *protoflags |= CURL_GSKPROTO_TLSV10_MASK; - break; - case CURL_SSLVERSION_TLSv1_1: - *protoflags |= CURL_GSKPROTO_TLSV11_MASK; - break; - case CURL_SSLVERSION_TLSv1_2: - *protoflags |= CURL_GSKPROTO_TLSV11_MASK; - break; - case CURL_SSLVERSION_TLSv1_3: - failf(data, "GSKit: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; - } - } - - return CURLE_OK; -} - -static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gsk_handle envir; - CURLcode result; - int rc; - const char * const keyringfile = SSL_CONN_CONFIG(CAfile); - const char * const keyringpwd = SSL_SET_OPTION(key_passwd); - const char * const keyringlabel = SSL_SET_OPTION(cert); - const long int ssl_version = SSL_CONN_CONFIG(version); - const bool verifypeer = SSL_CONN_CONFIG(verifypeer); - const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: - conn->host.name; - const char *sni; - unsigned int protoflags = 0; - long timeout; - Qso_OverlappedIO_t commarea; - int sockpair[2]; - static const int sobufsize = CURL_MAX_WRITE_SIZE; - - /* Create SSL environment, start (preferably asynchronous) handshake. */ - - BACKEND->handle = (gsk_handle) NULL; - BACKEND->iocport = -1; - BACKEND->localfd = -1; - BACKEND->remotefd = -1; - - /* GSKit supports two ways of specifying an SSL context: either by - * application identifier (that should have been defined at the system - * level) or by keyring file, password and certificate label. - * Local certificate name (CURLOPT_SSLCERT) is used to hold either the - * application identifier of the certificate label. - * Key password (CURLOPT_KEYPASSWD) holds the keyring password. - * It is not possible to have different keyrings for the CAs and the - * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify - * the keyring file. - * If no key password is given and the keyring is the system keyring, - * application identifier mode is tried first, as recommended in IBM doc. - */ - - envir = (gsk_handle) NULL; - - if(keyringlabel && *keyringlabel && !keyringpwd && - !strcmp(keyringfile, CURL_CA_BUNDLE)) { - /* Try application identifier mode. */ - init_environment(data, &envir, keyringlabel, (const char *) NULL, - (const char *) NULL, (const char *) NULL); - } - - if(!envir) { - /* Use keyring mode. */ - result = init_environment(data, &envir, (const char *) NULL, - keyringfile, keyringlabel, keyringpwd); - if(result) - return result; - } - - /* Create secure session. */ - result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle), - "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR); - gsk_environment_close(&envir); - if(result) - return result; - - /* Establish a pipelining socket pair for SSL over SSL. */ - if(conn->proxy_ssl[sockindex].use) { - if(inetsocketpair(sockpair)) - return CURLE_SSL_CONNECT_ERROR; - BACKEND->localfd = sockpair[0]; - BACKEND->remotefd = sockpair[1]; - setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF, - (void *) sobufsize, sizeof sobufsize); - setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF, - (void *) sobufsize, sizeof sobufsize); - setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF, - (void *) sobufsize, sizeof sobufsize); - setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF, - (void *) sobufsize, sizeof sobufsize); - curlx_nonblock(BACKEND->localfd, TRUE); - curlx_nonblock(BACKEND->remotefd, TRUE); - } - - /* Determine which SSL/TLS version should be enabled. */ - sni = hostname; - switch(ssl_version) { - case CURL_SSLVERSION_SSLv2: - protoflags = CURL_GSKPROTO_SSLV2_MASK; - sni = NULL; - break; - case CURL_SSLVERSION_SSLv3: - protoflags = CURL_GSKPROTO_SSLV3_MASK; - sni = NULL; - break; - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - protoflags = CURL_GSKPROTO_TLSV10_MASK | - CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK; - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - result = set_ssl_version_min_max(&protoflags, conn); - if(result != CURLE_OK) - return result; - break; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - /* Process SNI. Ignore if not supported (on OS400 < V7R1). */ - if(sni) { - result = set_buffer(data, BACKEND->handle, - GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE); - if(result == CURLE_UNSUPPORTED_PROTOCOL) - result = CURLE_OK; - } - - /* Set session parameters. */ - if(!result) { - /* Compute the handshake timeout. Since GSKit granularity is 1 second, - we round up the required value. */ - timeout = Curl_timeleft(data, NULL, TRUE); - if(timeout < 0) - result = CURLE_OPERATION_TIMEDOUT; - else - result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT, - (timeout + 999) / 1000); - } - if(!result) - result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1); - if(!result) - result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0? - BACKEND->localfd: conn->sock[sockindex]); - if(!result) - result = set_ciphers(conn, BACKEND->handle, &protoflags); - if(!protoflags) { - failf(data, "No SSL protocol/cipher combination enabled"); - result = CURLE_SSL_CIPHER; - } - if(!result) - result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2, - (protoflags & CURL_GSKPROTO_SSLV2_MASK)? - GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE); - if(!result) - result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3, - (protoflags & CURL_GSKPROTO_SSLV3_MASK)? - GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE); - if(!result) - result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1, - (protoflags & CURL_GSKPROTO_TLSV10_MASK)? - GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE); - if(!result) { - result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11, - (protoflags & CURL_GSKPROTO_TLSV11_MASK)? - GSK_TRUE: GSK_FALSE, TRUE); - if(result == CURLE_UNSUPPORTED_PROTOCOL) { - result = CURLE_OK; - if(protoflags == CURL_GSKPROTO_TLSV11_MASK) { - failf(data, "TLS 1.1 not yet supported"); - result = CURLE_SSL_CIPHER; - } - } - } - if(!result) { - result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12, - (protoflags & CURL_GSKPROTO_TLSV12_MASK)? - GSK_TRUE: GSK_FALSE, TRUE); - if(result == CURLE_UNSUPPORTED_PROTOCOL) { - result = CURLE_OK; - if(protoflags == CURL_GSKPROTO_TLSV12_MASK) { - failf(data, "TLS 1.2 not yet supported"); - result = CURLE_SSL_CIPHER; - } - } - } - if(!result) - result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE, - verifypeer? GSK_SERVER_AUTH_FULL: - GSK_SERVER_AUTH_PASSTHRU, FALSE); - - if(!result) { - /* Start handshake. Try asynchronous first. */ - memset(&commarea, 0, sizeof commarea); - BACKEND->iocport = QsoCreateIOCompletionPort(); - if(BACKEND->iocport != -1) { - result = gskit_status(data, - gsk_secure_soc_startInit(BACKEND->handle, - BACKEND->iocport, - &commarea), - "gsk_secure_soc_startInit()", - CURLE_SSL_CONNECT_ERROR); - if(!result) { - connssl->connecting_state = ssl_connect_2; - return CURLE_OK; - } - else - close_async_handshake(connssl); - } - else if(errno != ENOBUFS) - result = gskit_status(data, GSK_ERROR_IO, - "QsoCreateIOCompletionPort()", 0); - else if(conn->proxy_ssl[sockindex].use) { - /* Cannot pipeline while handshaking synchronously. */ - result = CURLE_SSL_CONNECT_ERROR; - } - else { - /* No more completion port available. Use synchronous IO. */ - result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle), - "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR); - if(!result) { - connssl->connecting_state = ssl_connect_3; - return CURLE_OK; - } - } - } - - /* Error: rollback. */ - close_one(connssl, conn, sockindex); - return result; -} - - -static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, - bool nonblocking) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - Qso_OverlappedIO_t cstat; - long timeout_ms; - struct timeval stmv; - CURLcode result; - - /* Poll or wait for end of SSL asynchronous handshake. */ - - for(;;) { - timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE); - if(timeout_ms < 0) - timeout_ms = 0; - stmv.tv_sec = timeout_ms / 1000; - stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000; - switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) { - case 1: /* Operation complete. */ - break; - case -1: /* An error occurred: handshake still in progress. */ - if(errno == EINTR) { - if(nonblocking) - return CURLE_OK; - continue; /* Retry. */ - } - if(errno != ETIME) { - failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno)); - cancel_async_handshake(conn, sockindex); - close_async_handshake(connssl); - return CURLE_SSL_CONNECT_ERROR; - } - /* FALL INTO... */ - case 0: /* Handshake in progress, timeout occurred. */ - if(nonblocking) - return CURLE_OK; - cancel_async_handshake(conn, sockindex); - close_async_handshake(connssl); - return CURLE_OPERATION_TIMEDOUT; - } - break; - } - result = gskit_status(data, cstat.returnValue, "SSL handshake", - CURLE_SSL_CONNECT_ERROR); - if(!result) - connssl->connecting_state = ssl_connect_3; - close_async_handshake(connssl); - return result; -} - - -static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - const gsk_cert_data_elem *cdev; - int cdec; - const gsk_cert_data_elem *p; - const char *cert = (const char *) NULL; - const char *certend; - const char *ptr; - int i; - CURLcode result; - - /* SSL handshake done: gather certificate info and verify host. */ - - if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle, - GSK_PARTNER_CERT_INFO, - &cdev, &cdec), - "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) == - CURLE_OK) { - infof(data, "Server certificate:\n"); - p = cdev; - for(i = 0; i++ < cdec; p++) - switch(p->cert_data_id) { - case CERT_BODY_DER: - cert = p->cert_data_p; - certend = cert + cdev->cert_data_l; - break; - case CERT_DN_PRINTABLE: - infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p); - break; - case CERT_ISSUER_DN_PRINTABLE: - infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p); - break; - case CERT_VALID_FROM: - infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p); - break; - case CERT_VALID_TO: - infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p); - break; - } - } - - /* Verify host. */ - result = Curl_verifyhost(conn, cert, certend); - if(result) - return result; - - /* The only place GSKit can get the whole CA chain is a validation - callback where no user data pointer is available. Therefore it's not - possible to copy this chain into our structures for CAINFO. - However the server certificate may be available, thus we can return - info about it. */ - if(data->set.ssl.certinfo) { - result = Curl_ssl_init_certinfo(data, 1); - if(result) - return result; - - if(cert) { - result = Curl_extract_certinfo(conn, 0, cert, certend); - if(result) - return result; - } - } - - /* Check pinned public key. */ - ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - if(!result && ptr) { - curl_X509certificate x509; - curl_asn1Element *p; - - if(Curl_parseX509(&x509, cert, certend)) - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - p = &x509.subjectPublicKeyInfo; - result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header); - if(result) { - failf(data, "SSL: public key does not match pinned public key!"); - return result; - } - } - - connssl->connecting_state = ssl_connect_done; - return CURLE_OK; -} - - -static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, - bool nonblocking, bool *done) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - long timeout_ms; - Qso_OverlappedIO_t cstat; - CURLcode result = CURLE_OK; - - *done = connssl->state == ssl_connection_complete; - if(*done) - return CURLE_OK; - - /* Step 1: create session, start handshake. */ - if(connssl->connecting_state == ssl_connect_1) { - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - result = CURLE_OPERATION_TIMEDOUT; - } - else - result = gskit_connect_step1(conn, sockindex); - } - - /* Handle handshake pipelining. */ - if(!result) - if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) - result = CURLE_SSL_CONNECT_ERROR; - - /* Step 2: check if handshake is over. */ - if(!result && connssl->connecting_state == ssl_connect_2) { - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - result = CURLE_OPERATION_TIMEDOUT; - } - else - result = gskit_connect_step2(conn, sockindex, nonblocking); - } - - /* Handle handshake pipelining. */ - if(!result) - if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) - result = CURLE_SSL_CONNECT_ERROR; - - /* Step 3: gather certificate info, verify host. */ - if(!result && connssl->connecting_state == ssl_connect_3) - result = gskit_connect_step3(conn, sockindex); - - if(result) - close_one(connssl, conn, sockindex); - else if(connssl->connecting_state == ssl_connect_done) { - connssl->state = ssl_connection_complete; - connssl->connecting_state = ssl_connect_1; - conn->recv[sockindex] = gskit_recv; - conn->send[sockindex] = gskit_send; - *done = TRUE; - } - - return result; -} - - -static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - CURLcode result; - - result = gskit_connect_common(conn, sockindex, TRUE, done); - if(*done || result) - conn->ssl[sockindex].connecting_state = ssl_connect_1; - return result; -} - - -static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done; - - conn->ssl[sockindex].connecting_state = ssl_connect_1; - result = gskit_connect_common(conn, sockindex, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - - -static void Curl_gskit_close(struct connectdata *conn, int sockindex) -{ - close_one(&conn->ssl[sockindex], conn, sockindex); - close_one(&conn->proxy_ssl[sockindex], conn, sockindex); -} - - -static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - ssize_t nread; - int what; - int rc; - char buf[120]; - - if(!BACKEND->handle) - return 0; - - if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) - return 0; - - close_one(connssl, conn, sockindex); - rc = 0; - what = SOCKET_READABLE(conn->sock[sockindex], - SSL_SHUTDOWN_TIMEOUT); - - for(;;) { - if(what < 0) { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - rc = -1; - break; - } - - if(!what) { /* timeout */ - failf(data, "SSL shutdown timeout"); - break; - } - - /* Something to read, let's do it and hope that it is the close - notify alert from the server. No way to gsk_secure_soc_read() now, so - use read(). */ - - nread = read(conn->sock[sockindex], buf, sizeof(buf)); - - if(nread < 0) { - failf(data, "read: %s", strerror(errno)); - rc = -1; - } - - if(nread <= 0) - break; - - what = SOCKET_READABLE(conn->sock[sockindex], 0); - } - - return rc; -} - - -static size_t Curl_gskit_version(char *buffer, size_t size) -{ - strncpy(buffer, "GSKit", size); - return strlen(buffer); -} - - -static int Curl_gskit_check_cxn(struct connectdata *cxn) -{ - struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET]; - int err; - int errlen; - - /* The only thing that can be tested here is at the socket level. */ - - if(!BACKEND->handle) - return 0; /* connection has been closed */ - - err = 0; - errlen = sizeof err; - - if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, - (unsigned char *) &err, &errlen) || - errlen != sizeof err || err) - return 0; /* connection has been closed */ - - return -1; /* connection status unknown */ -} - -static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return BACKEND->handle; -} - -const struct Curl_ssl Curl_ssl_gskit = { - { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */ - - 0, /* have_ca_path */ - 1, /* have_certinfo */ - 0, /* have_pinnedpubkey */ - 0, /* have_ssl_ctx */ - /* TODO: convert to 1 and fix test #1014 (if need) */ - 0, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_gskit_init, /* init */ - Curl_gskit_cleanup, /* cleanup */ - Curl_gskit_version, /* version */ - Curl_gskit_check_cxn, /* check_cxn */ - Curl_gskit_shutdown, /* shutdown */ - Curl_none_data_pending, /* data_pending */ - Curl_none_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_gskit_connect, /* connect */ - Curl_gskit_connect_nonblocking, /* connect_nonblocking */ - Curl_gskit_get_internals, /* get_internals */ - Curl_gskit_close, /* close */ - Curl_none_close_all, /* close_all */ - /* No session handling for GSKit */ - Curl_none_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - NULL /* sha256sum */ -}; - -#endif /* USE_GSKIT */ diff --git a/dep/cpr/opt/curl/lib/vtls/gskit.h b/dep/cpr/opt/curl/lib/vtls/gskit.h deleted file mode 100644 index 466ee4d9de4..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/gskit.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef HEADER_CURL_GSKIT_H -#define HEADER_CURL_GSKIT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -/* - * This header should only be needed to get included by vtls.c and gskit.c - */ - -#include "urldata.h" - -#ifdef USE_GSKIT - -extern const struct Curl_ssl Curl_ssl_gskit; - -#endif /* USE_GSKIT */ - -#endif /* HEADER_CURL_GSKIT_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/gtls.c b/dep/cpr/opt/curl/lib/vtls/gtls.c deleted file mode 100644 index a844915ef08..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/gtls.c +++ /dev/null @@ -1,1841 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - * - * Note: don't use the GnuTLS' *_t variable type names in this source code, - * since they were not present in 1.0.X. - */ - -#include "curl_setup.h" - -#ifdef USE_GNUTLS - -#include -#include -#include - -#ifdef USE_GNUTLS_NETTLE -#include -#include -#include -#else -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "inet_pton.h" -#include "gtls.h" -#include "vtls.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "strcase.h" -#include "warnless.h" -#include "x509asn1.h" -#include "curl_printf.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -#ifndef GNUTLS_POINTER_TO_SOCKET_CAST -#define GNUTLS_POINTER_TO_SOCKET_CAST(p) \ - ((curl_socket_t) ((char *)(p) - (char *)NULL)) -#endif -#ifndef GNUTLS_SOCKET_TO_POINTER_CAST -#define GNUTLS_SOCKET_TO_POINTER_CAST(s) \ - ((void *) ((char *)NULL + (s))) -#endif - -/* Enable GnuTLS debugging by defining GTLSDEBUG */ -/*#define GTLSDEBUG */ - -#ifdef GTLSDEBUG -static void tls_log_func(int level, const char *str) -{ - fprintf(stderr, "|<%d>| %s", level, str); -} -#endif -static bool gtls_inited = FALSE; - -#if defined(GNUTLS_VERSION_NUMBER) -# if (GNUTLS_VERSION_NUMBER >= 0x020c00) -# undef gnutls_transport_set_lowat -# define gnutls_transport_set_lowat(A,B) Curl_nop_stmt -# define USE_GNUTLS_PRIORITY_SET_DIRECT 1 -# endif -# if (GNUTLS_VERSION_NUMBER >= 0x020c03) -# define GNUTLS_MAPS_WINSOCK_ERRORS 1 -# endif - -# if HAVE_GNUTLS_ALPN_SET_PROTOCOLS -# define HAS_ALPN -# endif - -# if HAVE_GNUTLS_OCSP_REQ_INIT -# define HAS_OCSP -# endif - -# if (GNUTLS_VERSION_NUMBER >= 0x030306) -# define HAS_CAPATH -# endif -#endif - -#ifdef HAS_OCSP -# include -#endif - -struct ssl_backend_data { - gnutls_session_t session; - gnutls_certificate_credentials_t cred; -#ifdef USE_TLS_SRP - gnutls_srp_client_credentials_t srp_client_cred; -#endif -}; - -#define BACKEND connssl->backend - -/* - * Custom push and pull callback functions used by GNU TLS to read and write - * to the socket. These functions are simple wrappers to send() and recv() - * (although here using the sread/swrite macros as defined by - * curl_setup_once.h). - * We use custom functions rather than the GNU TLS defaults because it allows - * us to get specific about the fourth "flags" argument, and to use arbitrary - * private data with gnutls_transport_set_ptr if we wish. - * - * When these custom push and pull callbacks fail, GNU TLS checks its own - * session-specific error variable, and when not set also its own global - * errno variable, in order to take appropriate action. GNU TLS does not - * require that the transport is actually a socket. This implies that for - * Windows builds these callbacks should ideally set the session-specific - * error variable using function gnutls_transport_set_errno or as a last - * resort global errno variable using gnutls_transport_set_global_errno, - * with a transport agnostic error value. This implies that some winsock - * error translation must take place in these callbacks. - * - * Paragraph above applies to GNU TLS versions older than 2.12.3, since - * this version GNU TLS does its own internal winsock error translation - * using system_errno() function. - */ - -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) -# define gtls_EINTR 4 -# define gtls_EIO 5 -# define gtls_EAGAIN 11 -static int gtls_mapped_sockerrno(void) -{ - switch(SOCKERRNO) { - case WSAEWOULDBLOCK: - return gtls_EAGAIN; - case WSAEINTR: - return gtls_EINTR; - default: - break; - } - return gtls_EIO; -} -#endif - -static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) -{ - ssize_t ret = swrite(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len); -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) - if(ret < 0) - gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); -#endif - return ret; -} - -static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) -{ - ssize_t ret = sread(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len); -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) - if(ret < 0) - gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); -#endif - return ret; -} - -static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len) -{ - return gnutls_record_send((gnutls_session_t) s, buf, len); -} - -static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len) -{ - return gnutls_record_recv((gnutls_session_t) s, buf, len); -} - -/* Curl_gtls_init() - * - * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that - * are not thread-safe and thus this function itself is not thread-safe and - * must only be called from within curl_global_init() to keep the thread - * situation under control! - */ -static int Curl_gtls_init(void) -{ - int ret = 1; - if(!gtls_inited) { - ret = gnutls_global_init()?0:1; -#ifdef GTLSDEBUG - gnutls_global_set_log_function(tls_log_func); - gnutls_global_set_log_level(2); -#endif - gtls_inited = TRUE; - } - return ret; -} - -static void Curl_gtls_cleanup(void) -{ - if(gtls_inited) { - gnutls_global_deinit(); - gtls_inited = FALSE; - } -} - -#ifndef CURL_DISABLE_VERBOSE_STRINGS -static void showtime(struct Curl_easy *data, - const char *text, - time_t stamp) -{ - struct tm buffer; - const struct tm *tm = &buffer; - char str[96]; - CURLcode result = Curl_gmtime(stamp, &buffer); - if(result) - return; - - snprintf(str, - sizeof(str), - "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT", - text, - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - infof(data, "%s\n", str); -} -#endif - -static gnutls_datum_t load_file(const char *file) -{ - FILE *f; - gnutls_datum_t loaded_file = { NULL, 0 }; - long filelen; - void *ptr; - - f = fopen(file, "rb"); - if(!f) - return loaded_file; - if(fseek(f, 0, SEEK_END) != 0 - || (filelen = ftell(f)) < 0 - || fseek(f, 0, SEEK_SET) != 0 - || !(ptr = malloc((size_t)filelen))) - goto out; - if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { - free(ptr); - goto out; - } - - loaded_file.data = ptr; - loaded_file.size = (unsigned int)filelen; -out: - fclose(f); - return loaded_file; -} - -static void unload_file(gnutls_datum_t data) -{ - free(data.data); -} - - -/* this function does a SSL/TLS (re-)handshake */ -static CURLcode handshake(struct connectdata *conn, - int sockindex, - bool duringconnect, - bool nonblocking) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gnutls_session_t session = BACKEND->session; - curl_socket_t sockfd = conn->sock[sockindex]; - time_t timeout_ms; - int rc; - int what; - - for(;;) { - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, duringconnect); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0: - timeout_ms?timeout_ms:1000); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) - return CURLE_OK; - else if(timeout_ms) { - /* timeout */ - failf(data, "SSL connection timeout at %ld", (long)timeout_ms); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - rc = gnutls_handshake(session); - - if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - connssl->connecting_state = - gnutls_record_get_direction(session)? - ssl_connect_2_writing:ssl_connect_2_reading; - continue; - } - else if((rc < 0) && !gnutls_error_is_fatal(rc)) { - const char *strerr = NULL; - - if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { - int alert = gnutls_alert_get(session); - strerr = gnutls_alert_get_name(alert); - } - - if(strerr == NULL) - strerr = gnutls_strerror(rc); - - infof(data, "gnutls_handshake() warning: %s\n", strerr); - continue; - } - else if(rc < 0) { - const char *strerr = NULL; - - if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { - int alert = gnutls_alert_get(session); - strerr = gnutls_alert_get_name(alert); - } - - if(strerr == NULL) - strerr = gnutls_strerror(rc); - - failf(data, "gnutls_handshake() failed: %s", strerr); - return CURLE_SSL_CONNECT_ERROR; - } - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - return CURLE_OK; - } -} - -static gnutls_x509_crt_fmt_t do_file_type(const char *type) -{ - if(!type || !type[0]) - return GNUTLS_X509_FMT_PEM; - if(strcasecompare(type, "PEM")) - return GNUTLS_X509_FMT_PEM; - if(strcasecompare(type, "DER")) - return GNUTLS_X509_FMT_DER; - return -1; -} - -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT -static CURLcode -set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - long i = ssl_version; - long protocol_priority_idx = 0; - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - ssl_version_max = ssl_version << 16; - break; - case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - for(; i <= (ssl_version_max >> 16) && - protocol_priority_idx < list_size; ++i) { - switch(i) { - case CURL_SSLVERSION_TLSv1_0: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0; - break; - case CURL_SSLVERSION_TLSv1_1: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1; - break; - case CURL_SSLVERSION_TLSv1_2: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2; - break; - case CURL_SSLVERSION_TLSv1_3: - failf(data, "GnuTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; - } - } - return CURLE_OK; -} -#else -#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" -/* If GnuTLS was compiled without support for SRP it will error out if SRP is - requested in the priority string, so treat it specially - */ -#define GNUTLS_SRP "+SRP" - -static CURLcode -set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - if(ssl_version == CURL_SSLVERSION_TLSv1_3 || - ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) { - failf(data, "GnuTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; - } - if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) { - ssl_version_max = ssl_version << 16; - } - switch(ssl_version | ssl_version_max) { - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: - case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - } - - failf(data, "GnuTLS: cannot set ssl protocol"); - return CURLE_SSL_CONNECT_ERROR; -} -#endif - -static CURLcode -gtls_connect_step1(struct connectdata *conn, - int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - unsigned int init_flags; - gnutls_session_t session; - int rc; - bool sni = TRUE; /* default is SNI enabled */ - void *transport_ptr = NULL; - gnutls_push_func gnutls_transport_push = NULL; - gnutls_pull_func gnutls_transport_pull = NULL; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT - static const int cipher_priority[] = { - /* These two ciphers were added to GnuTLS as late as ver. 3.0.1, - but this code path is only ever used for ver. < 2.12.0. - GNUTLS_CIPHER_AES_128_GCM, - GNUTLS_CIPHER_AES_256_GCM, - */ - GNUTLS_CIPHER_AES_128_CBC, - GNUTLS_CIPHER_AES_256_CBC, - GNUTLS_CIPHER_CAMELLIA_128_CBC, - GNUTLS_CIPHER_CAMELLIA_256_CBC, - GNUTLS_CIPHER_3DES_CBC, - }; - static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; - int protocol_priority[] = { 0, 0, 0, 0 }; -#else - const char *prioritylist; - const char *err = NULL; -#endif - - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - - if(connssl->state == ssl_connection_complete) - /* to make us tolerant against being called more than once for the - same connection */ - return CURLE_OK; - - if(!gtls_inited) - Curl_gtls_init(); - - if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { - failf(data, "GnuTLS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) - sni = FALSE; /* SSLv3 has no SNI */ - - /* allocate a cred struct */ - rc = gnutls_certificate_allocate_credentials(&BACKEND->cred); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef USE_TLS_SRP - if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { - infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); - - rc = gnutls_srp_allocate_client_credentials( - &BACKEND->srp_client_cred); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_srp_allocate_client_cred() failed: %s", - gnutls_strerror(rc)); - return CURLE_OUT_OF_MEMORY; - } - - rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred, - SSL_SET_OPTION(username), - SSL_SET_OPTION(password)); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_srp_set_client_cred() failed: %s", - gnutls_strerror(rc)); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - } -#endif - - if(SSL_CONN_CONFIG(CAfile)) { - /* set the trusted CA cert bundle file */ - gnutls_certificate_set_verify_flags(BACKEND->cred, - GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); - - rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred, - SSL_CONN_CONFIG(CAfile), - GNUTLS_X509_FMT_PEM); - if(rc < 0) { - infof(data, "error reading ca cert file %s (%s)\n", - SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc)); - if(SSL_CONN_CONFIG(verifypeer)) - return CURLE_SSL_CACERT_BADFILE; - } - else - infof(data, "found %d certificates in %s\n", rc, - SSL_CONN_CONFIG(CAfile)); - } - -#ifdef HAS_CAPATH - if(SSL_CONN_CONFIG(CApath)) { - /* set the trusted CA cert directory */ - rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred, - SSL_CONN_CONFIG(CApath), - GNUTLS_X509_FMT_PEM); - if(rc < 0) { - infof(data, "error reading ca cert file %s (%s)\n", - SSL_CONN_CONFIG(CApath), gnutls_strerror(rc)); - if(SSL_CONN_CONFIG(verifypeer)) - return CURLE_SSL_CACERT_BADFILE; - } - else - infof(data, "found %d certificates in %s\n", - rc, SSL_CONN_CONFIG(CApath)); - } -#endif - -#ifdef CURL_CA_FALLBACK - /* use system ca certificate store as fallback */ - if(SSL_CONN_CONFIG(verifypeer) && - !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) { - gnutls_certificate_set_x509_system_trust(BACKEND->cred); - } -#endif - - if(SSL_SET_OPTION(CRLfile)) { - /* set the CRL list file */ - rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred, - SSL_SET_OPTION(CRLfile), - GNUTLS_X509_FMT_PEM); - if(rc < 0) { - failf(data, "error reading crl file %s (%s)", - SSL_SET_OPTION(CRLfile), gnutls_strerror(rc)); - return CURLE_SSL_CRL_BADFILE; - } - else - infof(data, "found %d CRL in %s\n", - rc, SSL_SET_OPTION(CRLfile)); - } - - /* Initialize TLS session as a client */ - init_flags = GNUTLS_CLIENT; - -#if defined(GNUTLS_NO_TICKETS) - /* Disable TLS session tickets */ - init_flags |= GNUTLS_NO_TICKETS; -#endif - - rc = gnutls_init(&BACKEND->session, init_flags); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_init() failed: %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } - - /* convenient assign */ - session = BACKEND->session; - - if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && -#ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && -#endif - sni && - (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, - strlen(hostname)) < 0)) - infof(data, "WARNING: failed to configure server name indication (SNI) " - "TLS extension\n"); - - /* Use default priorities */ - rc = gnutls_set_default_priority(session); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT - rc = gnutls_cipher_set_priority(session, cipher_priority); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - - /* Sets the priority on the certificate types supported by gnutls. Priority - is higher for types specified before others. After specifying the types - you want, you must append a 0. */ - rc = gnutls_certificate_type_set_priority(session, cert_type_priority); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - - if(SSL_CONN_CONFIG(cipher_list) != NULL) { - failf(data, "can't pass a custom cipher list to older GnuTLS" - " versions"); - return CURLE_SSL_CONNECT_ERROR; - } - - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_SSLv3: - protocol_priority[0] = GNUTLS_SSL3; - break; - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - protocol_priority[0] = GNUTLS_TLS1_0; - protocol_priority[1] = GNUTLS_TLS1_1; - protocol_priority[2] = GNUTLS_TLS1_2; - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(protocol_priority, - sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn); - if(result != CURLE_OK) - return result; - break; - } - case CURL_SSLVERSION_SSLv2: - failf(data, "GnuTLS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - rc = gnutls_protocol_set_priority(session, protocol_priority); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "Did you pass a valid GnuTLS cipher list?"); - return CURLE_SSL_CONNECT_ERROR; - } - -#else - /* Ensure +SRP comes at the *end* of all relevant strings so that it can be - * removed if a run-time error indicates that SRP is not supported by this - * GnuTLS version */ - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_SSLv3: - prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0"; - sni = false; - break; - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP; - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(&prioritylist, conn); - if(result != CURLE_OK) - return result; - break; - } - case CURL_SSLVERSION_SSLv2: - failf(data, "GnuTLS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - rc = gnutls_priority_set_direct(session, prioritylist, &err); - if((rc == GNUTLS_E_INVALID_REQUEST) && err) { - if(!strcmp(err, GNUTLS_SRP)) { - /* This GnuTLS was probably compiled without support for SRP. - * Note that fact and try again without it. */ - int validprioritylen = curlx_uztosi(err - prioritylist); - char *prioritycopy = strdup(prioritylist); - if(!prioritycopy) - return CURLE_OUT_OF_MEMORY; - - infof(data, "This GnuTLS does not support SRP\n"); - if(validprioritylen) - /* Remove the :+SRP */ - prioritycopy[validprioritylen - 1] = 0; - rc = gnutls_priority_set_direct(session, prioritycopy, &err); - free(prioritycopy); - } - } - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "Error %d setting GnuTLS cipher list starting with %s", - rc, err); - return CURLE_SSL_CONNECT_ERROR; - } -#endif - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - int cur = 0; - gnutls_datum_t protocols[2]; - -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2 && - (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { - protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; - protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; - cur++; - infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); - } -#endif - - protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; - protocols[cur].size = ALPN_HTTP_1_1_LENGTH; - cur++; - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - - gnutls_alpn_set_protocols(session, protocols, cur, 0); - } -#endif - - if(SSL_SET_OPTION(cert)) { - if(SSL_SET_OPTION(key_passwd)) { -#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 - const unsigned int supported_key_encryption_algorithms = - GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | - GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | - GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | - GNUTLS_PKCS_USE_PBES2_AES_256; - rc = gnutls_certificate_set_x509_key_file2( - BACKEND->cred, - SSL_SET_OPTION(cert), - SSL_SET_OPTION(key) ? - SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), - do_file_type(SSL_SET_OPTION(cert_type)), - SSL_SET_OPTION(key_passwd), - supported_key_encryption_algorithms); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, - "error reading X.509 potentially-encrypted key file: %s", - gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } -#else - failf(data, "gnutls lacks support for encrypted key files"); - return CURLE_SSL_CONNECT_ERROR; -#endif - } - else { - if(gnutls_certificate_set_x509_key_file( - BACKEND->cred, - SSL_SET_OPTION(cert), - SSL_SET_OPTION(key) ? - SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), - do_file_type(SSL_SET_OPTION(cert_type)) ) != - GNUTLS_E_SUCCESS) { - failf(data, "error reading X.509 key or certificate file"); - return CURLE_SSL_CONNECT_ERROR; - } - } - } - -#ifdef USE_TLS_SRP - /* put the credentials to the current session */ - if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { - rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, - BACKEND->srp_client_cred); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } - } - else -#endif - { - rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, - BACKEND->cred); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } - } - - if(conn->proxy_ssl[sockindex].use) { - transport_ptr = conn->proxy_ssl[sockindex].backend->session; - gnutls_transport_push = Curl_gtls_push_ssl; - gnutls_transport_pull = Curl_gtls_pull_ssl; - } - else { - /* file descriptor for the socket */ - transport_ptr = GNUTLS_SOCKET_TO_POINTER_CAST(conn->sock[sockindex]); - gnutls_transport_push = Curl_gtls_push; - gnutls_transport_pull = Curl_gtls_pull; - } - - /* set the connection handle */ - gnutls_transport_set_ptr(session, transport_ptr); - - /* register callback functions to send and receive data. */ - gnutls_transport_set_push_function(session, gnutls_transport_push); - gnutls_transport_set_pull_function(session, gnutls_transport_pull); - - /* lowat must be set to zero when using custom push and pull functions. */ - gnutls_transport_set_lowat(session, 0); - -#ifdef HAS_OCSP - if(SSL_CONN_CONFIG(verifystatus)) { - rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } - } -#endif - - /* This might be a reconnect, so we check for a session ID in the cache - to speed up things */ - if(SSL_SET_OPTION(primary.sessionid)) { - void *ssl_sessionid; - size_t ssl_idsize; - - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) { - /* we got a session id, use it! */ - gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); - - /* Informational message */ - infof(data, "SSL re-using session ID\n"); - } - Curl_ssl_sessionid_unlock(conn); - } - - return CURLE_OK; -} - -static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, - gnutls_x509_crt_t cert, - const char *pinnedpubkey) -{ - /* Scratch */ - size_t len1 = 0, len2 = 0; - unsigned char *buff1 = NULL; - - gnutls_pubkey_t key = NULL; - - /* Result is returned to caller */ - int ret = 0; - CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - - /* if a path wasn't specified, don't pin */ - if(NULL == pinnedpubkey) - return CURLE_OK; - - if(NULL == cert) - return result; - - do { - /* Begin Gyrations to get the public key */ - gnutls_pubkey_init(&key); - - ret = gnutls_pubkey_import_x509(key, cert, 0); - if(ret < 0) - break; /* failed */ - - ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1); - if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0) - break; /* failed */ - - buff1 = malloc(len1); - if(NULL == buff1) - break; /* failed */ - - len2 = len1; - - ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2); - if(ret < 0 || len1 != len2) - break; /* failed */ - - /* End Gyrations */ - - /* The one good exit point */ - result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); - } while(0); - - if(NULL != key) - gnutls_pubkey_deinit(key); - - Curl_safefree(buff1); - - return result; -} - -static Curl_recv gtls_recv; -static Curl_send gtls_send; - -static CURLcode -gtls_connect_step3(struct connectdata *conn, - int sockindex) -{ - unsigned int cert_list_size; - const gnutls_datum_t *chainp; - unsigned int verify_status = 0; - gnutls_x509_crt_t x509_cert, x509_issuer; - gnutls_datum_t issuerp; - char certbuf[256] = ""; /* big enough? */ - size_t size; - time_t certclock; - const char *ptr; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gnutls_session_t session = BACKEND->session; - int rc; -#ifdef HAS_ALPN - gnutls_datum_t proto; -#endif - CURLcode result = CURLE_OK; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - unsigned int algo; - unsigned int bits; - gnutls_protocol_t version = gnutls_protocol_get_version(session); -#endif - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - - /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ - ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), - gnutls_cipher_get(session), - gnutls_mac_get(session)); - - infof(data, "SSL connection using %s / %s\n", - gnutls_protocol_get_name(version), ptr); - - /* This function will return the peer's raw certificate (chain) as sent by - the peer. These certificates are in raw format (DER encoded for - X.509). In case of a X.509 then a certificate list may be present. The - first certificate in the list is the peer's certificate, following the - issuer's certificate, then the issuer's issuer etc. */ - - chainp = gnutls_certificate_get_peers(session, &cert_list_size); - if(!chainp) { - if(SSL_CONN_CONFIG(verifypeer) || - SSL_CONN_CONFIG(verifyhost) || - SSL_SET_OPTION(issuercert)) { -#ifdef USE_TLS_SRP - if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP - && SSL_SET_OPTION(username) != NULL - && !SSL_CONN_CONFIG(verifypeer) - && gnutls_cipher_get(session)) { - /* no peer cert, but auth is ok if we have SRP user and cipher and no - peer verify */ - } - else { -#endif - failf(data, "failed to get server cert"); - return CURLE_PEER_FAILED_VERIFICATION; -#ifdef USE_TLS_SRP - } -#endif - } - infof(data, "\t common name: WARNING couldn't obtain\n"); - } - - if(data->set.ssl.certinfo && chainp) { - unsigned int i; - - result = Curl_ssl_init_certinfo(data, cert_list_size); - if(result) - return result; - - for(i = 0; i < cert_list_size; i++) { - const char *beg = (const char *) chainp[i].data; - const char *end = beg + chainp[i].size; - - result = Curl_extract_certinfo(conn, i, beg, end); - if(result) - return result; - } - } - - if(SSL_CONN_CONFIG(verifypeer)) { - /* This function will try to verify the peer's certificate and return its - status (trusted, invalid etc.). The value of status should be one or - more of the gnutls_certificate_status_t enumerated elements bitwise - or'd. To avoid denial of service attacks some default upper limits - regarding the certificate key size and chain size are set. To override - them use gnutls_certificate_set_verify_limits(). */ - - rc = gnutls_certificate_verify_peers2(session, &verify_status); - if(rc < 0) { - failf(data, "server cert verify failed: %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } - - /* verify_status is a bitmask of gnutls_certificate_status bits */ - if(verify_status & GNUTLS_CERT_INVALID) { - if(SSL_CONN_CONFIG(verifypeer)) { - failf(data, "server certificate verification failed. CAfile: %s " - "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): - "none", - SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none"); - return CURLE_SSL_CACERT; - } - else - infof(data, "\t server certificate verification FAILED\n"); - } - else - infof(data, "\t server certificate verification OK\n"); - } - else - infof(data, "\t server certificate verification SKIPPED\n"); - -#ifdef HAS_OCSP - if(SSL_CONN_CONFIG(verifystatus)) { - if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { - gnutls_datum_t status_request; - gnutls_ocsp_resp_t ocsp_resp; - - gnutls_ocsp_cert_status_t status; - gnutls_x509_crl_reason_t reason; - - rc = gnutls_ocsp_status_request_get(session, &status_request); - - infof(data, "\t server certificate status verification FAILED\n"); - - if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - failf(data, "No OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - if(rc < 0) { - failf(data, "Invalid OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - gnutls_ocsp_resp_init(&ocsp_resp); - - rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); - if(rc < 0) { - failf(data, "Invalid OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, - &status, NULL, NULL, NULL, &reason); - - switch(status) { - case GNUTLS_OCSP_CERT_GOOD: - break; - - case GNUTLS_OCSP_CERT_REVOKED: { - const char *crl_reason; - - switch(reason) { - default: - case GNUTLS_X509_CRLREASON_UNSPECIFIED: - crl_reason = "unspecified reason"; - break; - - case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: - crl_reason = "private key compromised"; - break; - - case GNUTLS_X509_CRLREASON_CACOMPROMISE: - crl_reason = "CA compromised"; - break; - - case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: - crl_reason = "affiliation has changed"; - break; - - case GNUTLS_X509_CRLREASON_SUPERSEDED: - crl_reason = "certificate superseded"; - break; - - case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: - crl_reason = "operation has ceased"; - break; - - case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: - crl_reason = "certificate is on hold"; - break; - - case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: - crl_reason = "will be removed from delta CRL"; - break; - - case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: - crl_reason = "privilege withdrawn"; - break; - - case GNUTLS_X509_CRLREASON_AACOMPROMISE: - crl_reason = "AA compromised"; - break; - } - - failf(data, "Server certificate was revoked: %s", crl_reason); - break; - } - - default: - case GNUTLS_OCSP_CERT_UNKNOWN: - failf(data, "Server certificate status is unknown"); - break; - } - - gnutls_ocsp_resp_deinit(ocsp_resp); - - return CURLE_SSL_INVALIDCERTSTATUS; - } - else - infof(data, "\t server certificate status verification OK\n"); - } - else - infof(data, "\t server certificate status verification SKIPPED\n"); -#endif - - /* initialize an X.509 certificate structure. */ - gnutls_x509_crt_init(&x509_cert); - - if(chainp) - /* convert the given DER or PEM encoded Certificate to the native - gnutls_x509_crt_t format */ - gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); - - if(SSL_SET_OPTION(issuercert)) { - gnutls_x509_crt_init(&x509_issuer); - issuerp = load_file(SSL_SET_OPTION(issuercert)); - gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); - rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); - gnutls_x509_crt_deinit(x509_issuer); - unload_file(issuerp); - if(rc <= 0) { - failf(data, "server certificate issuer check failed (IssuerCert: %s)", - SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_ISSUER_ERROR; - } - infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", - SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); - } - - size = sizeof(certbuf); - rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, - 0, /* the first and only one */ - FALSE, - certbuf, - &size); - if(rc) { - infof(data, "error fetching CN from cert:%s\n", - gnutls_strerror(rc)); - } - - /* This function will check if the given certificate's subject matches the - given hostname. This is a basic implementation of the matching described - in RFC2818 (HTTPS), which takes into account wildcards, and the subject - alternative name PKIX extension. Returns non zero on success, and zero on - failure. */ - rc = gnutls_x509_crt_check_hostname(x509_cert, hostname); -#if GNUTLS_VERSION_NUMBER < 0x030306 - /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP - addresses. */ - if(!rc) { -#ifdef ENABLE_IPV6 - #define use_addr in6_addr -#else - #define use_addr in_addr -#endif - unsigned char addrbuf[sizeof(struct use_addr)]; - unsigned char certaddr[sizeof(struct use_addr)]; - size_t addrlen = 0, certaddrlen; - int i; - int ret = 0; - - if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0) - addrlen = 4; -#ifdef ENABLE_IPV6 - else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0) - addrlen = 16; -#endif - - if(addrlen) { - for(i = 0; ; i++) { - certaddrlen = sizeof(certaddr); - ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr, - &certaddrlen, NULL); - /* If this happens, it wasn't an IP address. */ - if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) - continue; - if(ret < 0) - break; - if(ret != GNUTLS_SAN_IPADDRESS) - continue; - if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) { - rc = 1; - break; - } - } - } - } -#endif - if(!rc) { - const char * const dispname = SSL_IS_PROXY() ? - conn->http_proxy.host.dispname : conn->host.dispname; - - if(SSL_CONN_CONFIG(verifyhost)) { - failf(data, "SSL: certificate subject name (%s) does not match " - "target host name '%s'", certbuf, dispname); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\t common name: %s (does not match '%s')\n", - certbuf, dispname); - } - else - infof(data, "\t common name: %s (matched)\n", certbuf); - - /* Check for time-based validity */ - certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - - if(certclock == (time_t)-1) { - if(SSL_CONN_CONFIG(verifypeer)) { - failf(data, "server cert expiration date verify failed"); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_CONNECT_ERROR; - } - else - infof(data, "\t server certificate expiration date verify FAILED\n"); - } - else { - if(certclock < time(NULL)) { - if(SSL_CONN_CONFIG(verifypeer)) { - failf(data, "server certificate expiration date has passed."); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\t server certificate expiration date FAILED\n"); - } - else - infof(data, "\t server certificate expiration date OK\n"); - } - - certclock = gnutls_x509_crt_get_activation_time(x509_cert); - - if(certclock == (time_t)-1) { - if(SSL_CONN_CONFIG(verifypeer)) { - failf(data, "server cert activation date verify failed"); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_CONNECT_ERROR; - } - else - infof(data, "\t server certificate activation date verify FAILED\n"); - } - else { - if(certclock > time(NULL)) { - if(SSL_CONN_CONFIG(verifypeer)) { - failf(data, "server certificate not activated yet."); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\t server certificate activation date FAILED\n"); - } - else - infof(data, "\t server certificate activation date OK\n"); - } - - ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - if(ptr) { - result = pkp_pin_peer_pubkey(data, x509_cert, ptr); - if(result != CURLE_OK) { - failf(data, "SSL: public key does not match pinned public key!"); - gnutls_x509_crt_deinit(x509_cert); - return result; - } - } - - /* Show: - - - subject - - start date - - expire date - - common name - - issuer - - */ - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - /* public key algorithm's parameters */ - algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); - infof(data, "\t certificate public key: %s\n", - gnutls_pk_algorithm_get_name(algo)); - - /* version of the X.509 certificate. */ - infof(data, "\t certificate version: #%d\n", - gnutls_x509_crt_get_version(x509_cert)); - - - size = sizeof(certbuf); - gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); - infof(data, "\t subject: %s\n", certbuf); - - certclock = gnutls_x509_crt_get_activation_time(x509_cert); - showtime(data, "start date", certclock); - - certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - showtime(data, "expire date", certclock); - - size = sizeof(certbuf); - gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); - infof(data, "\t issuer: %s\n", certbuf); - - /* compression algorithm (if any) */ - ptr = gnutls_compression_get_name(gnutls_compression_get(session)); - /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ - infof(data, "\t compression: %s\n", ptr); -#endif - - gnutls_x509_crt_deinit(x509_cert); - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - rc = gnutls_alpn_get_selected_protocol(session, &proto); - if(rc == 0) { - infof(data, "ALPN, server accepted to use %.*s\n", proto.size, - proto.data); - -#ifdef USE_NGHTTP2 - if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN && - !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, - NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(proto.size == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } - } - else - infof(data, "ALPN, server did not agree to a protocol\n"); - } -#endif - - conn->ssl[sockindex].state = ssl_connection_complete; - conn->recv[sockindex] = gtls_recv; - conn->send[sockindex] = gtls_send; - - if(SSL_SET_OPTION(primary.sessionid)) { - /* we always unconditionally get the session id here, as even if we - already got it from the cache and asked to use it in the connection, it - might've been rejected and then a new one is in use now and we need to - detect that. */ - bool incache; - void *ssl_sessionid; - void *connect_sessionid; - size_t connect_idsize = 0; - - /* get the session ID data size */ - gnutls_session_get_data(session, NULL, &connect_idsize); - connect_sessionid = malloc(connect_idsize); /* get a buffer for it */ - - if(connect_sessionid) { - /* extract session ID to the allocated buffer */ - gnutls_session_get_data(session, connect_sessionid, &connect_idsize); - - Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, - sockindex)); - if(incache) { - /* there was one before in the cache, so instead of risking that the - previous one was rejected, we just kill that and store the new */ - Curl_ssl_delsessionid(conn, ssl_sessionid); - } - - /* store this session id */ - result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize, - sockindex); - Curl_ssl_sessionid_unlock(conn); - if(result) { - free(connect_sessionid); - result = CURLE_OUT_OF_MEMORY; - } - } - else - result = CURLE_OUT_OF_MEMORY; - } - - return result; -} - - -/* - * This function is called after the TCP connect has completed. Setup the TLS - * layer and do all necessary magic. - */ -/* We use connssl->connecting_state to keep track of the connection status; - there are three states: 'ssl_connect_1' (not started yet or complete), - 'ssl_connect_2_reading' (waiting for data from server), and - 'ssl_connect_2_writing' (waiting to be able to write). - */ -static CURLcode -gtls_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - int rc; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - /* Initiate the connection, if not already done */ - if(ssl_connect_1 == connssl->connecting_state) { - rc = gtls_connect_step1(conn, sockindex); - if(rc) - return rc; - } - - rc = handshake(conn, sockindex, TRUE, nonblocking); - if(rc) - /* handshake() sets its own error message with failf() */ - return rc; - - /* Finish connecting once the handshake is done */ - if(ssl_connect_1 == connssl->connecting_state) { - rc = gtls_connect_step3(conn, sockindex); - if(rc) - return rc; - } - - *done = ssl_connect_1 == connssl->connecting_state; - - return CURLE_OK; -} - -static CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - return gtls_connect_common(conn, sockindex, TRUE, done); -} - -static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done = FALSE; - - result = gtls_connect_common(conn, sockindex, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -static bool Curl_gtls_data_pending(const struct connectdata *conn, - int connindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - bool res = FALSE; - if(BACKEND->session && - 0 != gnutls_record_check_pending(BACKEND->session)) - res = TRUE; - - connssl = &conn->proxy_ssl[connindex]; - if(BACKEND->session && - 0 != gnutls_record_check_pending(BACKEND->session)) - res = TRUE; - - return res; -} - -static ssize_t gtls_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - ssize_t rc = gnutls_record_send(BACKEND->session, mem, len); - - if(rc < 0) { - *curlcode = (rc == GNUTLS_E_AGAIN) - ? CURLE_AGAIN - : CURLE_SEND_ERROR; - - rc = -1; - } - - return rc; -} - -static void close_one(struct ssl_connect_data *connssl) -{ - if(BACKEND->session) { - gnutls_bye(BACKEND->session, GNUTLS_SHUT_RDWR); - gnutls_deinit(BACKEND->session); - BACKEND->session = NULL; - } - if(BACKEND->cred) { - gnutls_certificate_free_credentials(BACKEND->cred); - BACKEND->cred = NULL; - } -#ifdef USE_TLS_SRP - if(BACKEND->srp_client_cred) { - gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); - BACKEND->srp_client_cred = NULL; - } -#endif -} - -static void Curl_gtls_close(struct connectdata *conn, int sockindex) -{ - close_one(&conn->ssl[sockindex]); - close_one(&conn->proxy_ssl[sockindex]); -} - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - ssize_t result; - int retval = 0; - struct Curl_easy *data = conn->data; - int done = 0; - char buf[120]; - - /* This has only been tested on the proftpd server, and the mod_tls code - sends a close notify alert without waiting for a close notify alert in - response. Thus we wait for a close notify alert from the server, but - we do not send one. Let's hope other servers do the same... */ - - if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); - - if(BACKEND->session) { - while(!done) { - int what = SOCKET_READABLE(conn->sock[sockindex], - SSL_SHUTDOWN_TIMEOUT); - if(what > 0) { - /* Something to read, let's do it and hope that it is the close - notify alert from the server */ - result = gnutls_record_recv(BACKEND->session, - buf, sizeof(buf)); - switch(result) { - case 0: - /* This is the expected response. There was no data but only - the close notify alert */ - done = 1; - break; - case GNUTLS_E_AGAIN: - case GNUTLS_E_INTERRUPTED: - infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); - break; - default: - retval = -1; - done = 1; - break; - } - } - else if(0 == what) { - /* timeout */ - failf(data, "SSL shutdown timeout"); - done = 1; - break; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - retval = -1; - done = 1; - } - } - gnutls_deinit(BACKEND->session); - } - gnutls_certificate_free_credentials(BACKEND->cred); - -#ifdef USE_TLS_SRP - if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP - && SSL_SET_OPTION(username) != NULL) - gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); -#endif - - BACKEND->cred = NULL; - BACKEND->session = NULL; - - return retval; -} - -static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[num]; - ssize_t ret; - - ret = gnutls_record_recv(BACKEND->session, buf, buffersize); - if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { - *curlcode = CURLE_AGAIN; - return -1; - } - - if(ret == GNUTLS_E_REHANDSHAKE) { - /* BLOCKING call, this is bad but a work-around for now. Fixing this "the - proper way" takes a whole lot of work. */ - CURLcode result = handshake(conn, num, FALSE, FALSE); - if(result) - /* handshake() writes error message on its own */ - *curlcode = result; - else - *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ - return -1; - } - - if(ret < 0) { - failf(conn->data, "GnuTLS recv error (%d): %s", - - (int)ret, gnutls_strerror((int)ret)); - *curlcode = CURLE_RECV_ERROR; - return -1; - } - - return ret; -} - -static void Curl_gtls_session_free(void *ptr) -{ - free(ptr); -} - -static size_t Curl_gtls_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); -} - -#ifndef USE_GNUTLS_NETTLE -static int Curl_gtls_seed(struct Curl_easy *data) -{ - /* we have the "SSL is seeded" boolean static to prevent multiple - time-consuming seedings in vain */ - static bool ssl_seeded = FALSE; - - /* Quickly add a bit of entropy */ - gcry_fast_random_poll(); - - if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || - data->set.str[STRING_SSL_EGDSOCKET]) { - - /* TODO: to a good job seeding the RNG - This may involve the gcry_control function and these options: - GCRYCTL_SET_RANDOM_SEED_FILE - GCRYCTL_SET_RNDEGD_SOCKET - */ - ssl_seeded = TRUE; - } - return 0; -} -#endif - -/* data might be NULL! */ -static CURLcode Curl_gtls_random(struct Curl_easy *data, - unsigned char *entropy, size_t length) -{ -#if defined(USE_GNUTLS_NETTLE) - int rc; - (void)data; - rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); - return rc?CURLE_FAILED_INIT:CURLE_OK; -#elif defined(USE_GNUTLS) - if(data) - Curl_gtls_seed(data); /* Initiate the seed if not already done */ - gcry_randomize(entropy, length, GCRY_STRONG_RANDOM); -#endif - return CURLE_OK; -} - -static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len) -{ -#if defined(USE_GNUTLS_NETTLE) - struct md5_ctx MD5pw; - md5_init(&MD5pw); - md5_update(&MD5pw, (unsigned int)tmplen, tmp); - md5_digest(&MD5pw, (unsigned int)md5len, md5sum); -#elif defined(USE_GNUTLS) - gcry_md_hd_t MD5pw; - gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); - gcry_md_write(MD5pw, tmp, tmplen); - memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len); - gcry_md_close(MD5pw); -#endif - return CURLE_OK; -} - -static void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len) -{ -#if defined(USE_GNUTLS_NETTLE) - struct sha256_ctx SHA256pw; - sha256_init(&SHA256pw); - sha256_update(&SHA256pw, (unsigned int)tmplen, tmp); - sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum); -#elif defined(USE_GNUTLS) - gcry_md_hd_t SHA256pw; - gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0); - gcry_md_write(SHA256pw, tmp, tmplen); - memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len); - gcry_md_close(SHA256pw); -#endif -} - -static bool Curl_gtls_cert_status_request(void) -{ -#ifdef HAS_OCSP - return TRUE; -#else - return FALSE; -#endif -} - -static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return BACKEND->session; -} - -const struct Curl_ssl Curl_ssl_gnutls = { - { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */ - - 1, /* have_ca_path */ - 1, /* have_certinfo */ - 1, /* have_pinnedpubkey */ - 0, /* have_ssl_ctx */ - 1, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_gtls_init, /* init */ - Curl_gtls_cleanup, /* cleanup */ - Curl_gtls_version, /* version */ - Curl_none_check_cxn, /* check_cxn */ - Curl_gtls_shutdown, /* shutdown */ - Curl_gtls_data_pending, /* data_pending */ - Curl_gtls_random, /* random */ - Curl_gtls_cert_status_request, /* cert_status_request */ - Curl_gtls_connect, /* connect */ - Curl_gtls_connect_nonblocking, /* connect_nonblocking */ - Curl_gtls_get_internals, /* get_internals */ - Curl_gtls_close, /* close */ - Curl_none_close_all, /* close_all */ - Curl_gtls_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_gtls_md5sum, /* md5sum */ - Curl_gtls_sha256sum /* sha256sum */ -}; - -#endif /* USE_GNUTLS */ diff --git a/dep/cpr/opt/curl/lib/vtls/gtls.h b/dep/cpr/opt/curl/lib/vtls/gtls.h deleted file mode 100644 index 780fc109d7d..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/gtls.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef HEADER_CURL_GTLS_H -#define HEADER_CURL_GTLS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_GNUTLS - -#include "urldata.h" - -extern const struct Curl_ssl Curl_ssl_gnutls; - -#endif /* USE_GNUTLS */ -#endif /* HEADER_CURL_GTLS_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/mbedtls.c b/dep/cpr/opt/curl/lib/vtls/mbedtls.c deleted file mode 100644 index ce1f8eba80c..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/mbedtls.c +++ /dev/null @@ -1,1075 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010 - 2011, Hoi-Ho Chan, - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - * - */ - -#include "curl_setup.h" - -#ifdef USE_MBEDTLS - -#include -#if MBEDTLS_VERSION_NUMBER >= 0x02040000 -#include -#else -#include -#endif -#include -#include -#include - -#include -#include -#include -#include - -#include "urldata.h" -#include "sendf.h" -#include "inet_pton.h" -#include "mbedtls.h" -#include "vtls.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "polarssl_threadlock.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -struct ssl_backend_data { - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_entropy_context entropy; - mbedtls_ssl_context ssl; - int server_fd; - mbedtls_x509_crt cacert; - mbedtls_x509_crt clicert; - mbedtls_x509_crl crl; - mbedtls_pk_context pk; - mbedtls_ssl_config config; - const char *protocols[3]; -}; - -#define BACKEND connssl->backend - -/* apply threading? */ -#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -#define THREADING_SUPPORT -#endif - -#if defined(THREADING_SUPPORT) -static mbedtls_entropy_context ts_entropy; - -static int entropy_init_initialized = 0; - -/* start of entropy_init_mutex() */ -static void entropy_init_mutex(mbedtls_entropy_context *ctx) -{ - /* lock 0 = entropy_init_mutex() */ - Curl_polarsslthreadlock_lock_function(0); - if(entropy_init_initialized == 0) { - mbedtls_entropy_init(ctx); - entropy_init_initialized = 1; - } - Curl_polarsslthreadlock_unlock_function(0); -} -/* end of entropy_init_mutex() */ - -/* start of entropy_func_mutex() */ -static int entropy_func_mutex(void *data, unsigned char *output, size_t len) -{ - int ret; - /* lock 1 = entropy_func_mutex() */ - Curl_polarsslthreadlock_lock_function(1); - ret = mbedtls_entropy_func(data, output, len); - Curl_polarsslthreadlock_unlock_function(1); - - return ret; -} -/* end of entropy_func_mutex() */ - -#endif /* THREADING_SUPPORT */ - -/* Define this to enable lots of debugging for mbedTLS */ -#undef MBEDTLS_DEBUG - -#ifdef MBEDTLS_DEBUG -static void mbed_debug(void *context, int level, const char *f_name, - int line_nb, const char *line) -{ - struct Curl_easy *data = NULL; - - if(!context) - return; - - data = (struct Curl_easy *)context; - - infof(data, "%s", line); - (void) level; -} -#else -#endif - -/* ALPN for http2? */ -#ifdef USE_NGHTTP2 -# undef HAS_ALPN -# ifdef MBEDTLS_SSL_ALPN -# define HAS_ALPN -# endif -#endif - - -/* - * profile - */ -static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = -{ - /* Hashes from SHA-1 and above */ - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), - 0xFFFFFFF, /* Any PK alg */ - 0xFFFFFFF, /* Any curve */ - 1024, /* RSA min key len */ -}; - -/* See https://tls.mbed.org/discussions/generic/ - howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der -*/ -#define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE) -#define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES) - -#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ - RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) - -static Curl_recv mbed_recv; -static Curl_send mbed_send; - -static CURLcode mbedtls_version_from_curl(int *mbedver, long version) -{ - switch(version) { - case CURL_SSLVERSION_TLSv1_0: - *mbedver = MBEDTLS_SSL_MINOR_VERSION_1; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1: - *mbedver = MBEDTLS_SSL_MINOR_VERSION_2; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2: - *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_3: - break; - } - return CURLE_SSL_CONNECT_ERROR; -} - -static CURLcode -set_ssl_version_min_max(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; - int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - CURLcode result = CURLE_OK; - - switch(ssl_version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - ssl_version = CURL_SSLVERSION_TLSv1_0; - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - ssl_version_max = ssl_version << 16; - break; - case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version); - if(result) { - failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); - return result; - } - result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16); - if(result) { - failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); - return result; - } - - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, - mbedtls_ver_min); - mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, - mbedtls_ver_max); - - return result; -} - -static CURLcode -mbed_connect_step1(struct connectdata *conn, - int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); - const bool verifypeer = SSL_CONN_CONFIG(verifypeer); - const char * const ssl_capath = SSL_CONN_CONFIG(CApath); - char * const ssl_cert = SSL_SET_OPTION(cert); - const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; - int ret = -1; - char errorbuf[128]; - errorbuf[0] = 0; - - /* mbedTLS only supports SSLv3 and TLSv1 */ - if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { - failf(data, "mbedTLS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef THREADING_SUPPORT - entropy_init_mutex(&ts_entropy); - mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); - - ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, entropy_func_mutex, - &ts_entropy, NULL, 0); - if(ret) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); - } -#else - mbedtls_entropy_init(&BACKEND->entropy); - mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); - - ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, mbedtls_entropy_func, - &BACKEND->entropy, NULL, 0); - if(ret) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); - } -#endif /* THREADING_SUPPORT */ - - /* Load the trusted CA */ - mbedtls_x509_crt_init(&BACKEND->cacert); - - if(ssl_cafile) { - ret = mbedtls_x509_crt_parse_file(&BACKEND->cacert, ssl_cafile); - - if(ret<0) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", - ssl_cafile, -ret, errorbuf); - - if(verifypeer) - return CURLE_SSL_CACERT_BADFILE; - } - } - - if(ssl_capath) { - ret = mbedtls_x509_crt_parse_path(&BACKEND->cacert, ssl_capath); - - if(ret<0) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s", - ssl_capath, -ret, errorbuf); - - if(verifypeer) - return CURLE_SSL_CACERT_BADFILE; - } - } - - /* Load the client certificate */ - mbedtls_x509_crt_init(&BACKEND->clicert); - - if(ssl_cert) { - ret = mbedtls_x509_crt_parse_file(&BACKEND->clicert, ssl_cert); - - if(ret) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s", - ssl_cert, -ret, errorbuf); - - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load the client private key */ - mbedtls_pk_init(&BACKEND->pk); - - if(SSL_SET_OPTION(key)) { - ret = mbedtls_pk_parse_keyfile(&BACKEND->pk, SSL_SET_OPTION(key), - SSL_SET_OPTION(key_passwd)); - if(ret == 0 && !mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA)) - ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; - - if(ret) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", - SSL_SET_OPTION(key), -ret, errorbuf); - - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load the CRL */ - mbedtls_x509_crl_init(&BACKEND->crl); - - if(ssl_crlfile) { - ret = mbedtls_x509_crl_parse_file(&BACKEND->crl, ssl_crlfile); - - if(ret) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s", - ssl_crlfile, -ret, errorbuf); - - return CURLE_SSL_CRL_BADFILE; - } - } - - infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port); - - mbedtls_ssl_config_init(&BACKEND->config); - - mbedtls_ssl_init(&BACKEND->ssl); - if(mbedtls_ssl_setup(&BACKEND->ssl, &BACKEND->config)) { - failf(data, "mbedTLS: ssl_init failed"); - return CURLE_SSL_CONNECT_ERROR; - } - ret = mbedtls_ssl_config_defaults(&BACKEND->config, - MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT); - if(ret) { - failf(data, "mbedTLS: ssl_config failed"); - return CURLE_SSL_CONNECT_ERROR; - } - - /* new profile with RSA min key len = 1024 ... */ - mbedtls_ssl_conf_cert_profile(&BACKEND->config, - &mbedtls_x509_crt_profile_fr); - - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_1); - infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n"); - break; - case CURL_SSLVERSION_SSLv3: - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_0); - mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_0); - infof(data, "mbedTLS: Set SSL version to SSLv3\n"); - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(conn, sockindex); - if(result != CURLE_OK) - return result; - break; - } - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - mbedtls_ssl_conf_authmode(&BACKEND->config, MBEDTLS_SSL_VERIFY_OPTIONAL); - - mbedtls_ssl_conf_rng(&BACKEND->config, mbedtls_ctr_drbg_random, - &BACKEND->ctr_drbg); - mbedtls_ssl_set_bio(&BACKEND->ssl, &conn->sock[sockindex], - mbedtls_net_send, - mbedtls_net_recv, - NULL /* rev_timeout() */); - - mbedtls_ssl_conf_ciphersuites(&BACKEND->config, - mbedtls_ssl_list_ciphersuites()); - -#if defined(MBEDTLS_SSL_RENEGOTIATION) - mbedtls_ssl_conf_renegotiation(&BACKEND->config, - MBEDTLS_SSL_RENEGOTIATION_ENABLED); -#endif - -#if defined(MBEDTLS_SSL_SESSION_TICKETS) - mbedtls_ssl_conf_session_tickets(&BACKEND->config, - MBEDTLS_SSL_SESSION_TICKETS_DISABLED); -#endif - - /* Check if there's a cached ID we can/should use here! */ - if(SSL_SET_OPTION(primary.sessionid)) { - void *old_session = NULL; - - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { - ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session); - if(ret) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; - } - infof(data, "mbedTLS re-using session\n"); - } - Curl_ssl_sessionid_unlock(conn); - } - - mbedtls_ssl_conf_ca_chain(&BACKEND->config, - &BACKEND->cacert, - &BACKEND->crl); - - if(SSL_SET_OPTION(key)) { - mbedtls_ssl_conf_own_cert(&BACKEND->config, - &BACKEND->clicert, &BACKEND->pk); - } - if(mbedtls_ssl_set_hostname(&BACKEND->ssl, hostname)) { - /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and* - the name to set in the SNI extension. So even if curl connects to a - host specified as an IP address, this function must be used. */ - failf(data, "couldn't set hostname in mbedTLS"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - const char **p = &BACKEND->protocols[0]; -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2) - *p++ = NGHTTP2_PROTO_VERSION_ID; -#endif - *p++ = ALPN_HTTP_1_1; - *p = NULL; - /* this function doesn't clone the protocols array, which is why we need - to keep it around */ - if(mbedtls_ssl_conf_alpn_protocols(&BACKEND->config, - &BACKEND->protocols[0])) { - failf(data, "Failed setting ALPN protocols"); - return CURLE_SSL_CONNECT_ERROR; - } - for(p = &BACKEND->protocols[0]; *p; ++p) - infof(data, "ALPN, offering %s\n", *p); - } -#endif - -#ifdef MBEDTLS_DEBUG - /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ - mbedtls_ssl_conf_dbg(&BACKEND->config, mbed_debug, data); - /* - 0 No debug - * - 1 Error - * - 2 State change - * - 3 Informational - * - 4 Verbose - */ - mbedtls_debug_set_threshold(4); -#endif - - /* give application a chance to interfere with mbedTLS set up. */ - if(data->set.ssl.fsslctx) { - ret = (*data->set.ssl.fsslctx)(data, &BACKEND->config, - data->set.ssl.fsslctxp); - if(ret) { - failf(data, "error signaled by ssl ctx callback"); - return ret; - } - } - - connssl->connecting_state = ssl_connect_2; - - return CURLE_OK; -} - -static CURLcode -mbed_connect_step2(struct connectdata *conn, - int sockindex) -{ - int ret; - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - const mbedtls_x509_crt *peercert; - const char * const pinnedpubkey = SSL_IS_PROXY() ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - -#ifdef HAS_ALPN - const char *next_protocol; -#endif - - char errorbuf[128]; - errorbuf[0] = 0; - - conn->recv[sockindex] = mbed_recv; - conn->send[sockindex] = mbed_send; - - ret = mbedtls_ssl_handshake(&BACKEND->ssl); - - if(ret == MBEDTLS_ERR_SSL_WANT_READ) { - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - } - else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { - connssl->connecting_state = ssl_connect_2_writing; - return CURLE_OK; - } - else if(ret) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", - -ret, errorbuf); - return CURLE_SSL_CONNECT_ERROR; - } - - infof(data, "mbedTLS: Handshake complete, cipher is %s\n", - mbedtls_ssl_get_ciphersuite(&BACKEND->ssl) - ); - - ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl); - - if(ret && SSL_CONN_CONFIG(verifypeer)) { - if(ret & MBEDTLS_X509_BADCERT_EXPIRED) - failf(data, "Cert verify failed: BADCERT_EXPIRED"); - - if(ret & MBEDTLS_X509_BADCERT_REVOKED) { - failf(data, "Cert verify failed: BADCERT_REVOKED"); - return CURLE_SSL_CACERT; - } - - if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) - failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); - - if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) - failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); - - return CURLE_PEER_FAILED_VERIFICATION; - } - - peercert = mbedtls_ssl_get_peer_cert(&BACKEND->ssl); - - if(peercert && data->set.verbose) { - const size_t bufsize = 16384; - char *buffer = malloc(bufsize); - - if(!buffer) - return CURLE_OUT_OF_MEMORY; - - if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) - infof(data, "Dumping cert info:\n%s\n", buffer); - else - infof(data, "Unable to dump certificate information.\n"); - - free(buffer); - } - - if(pinnedpubkey) { - int size; - CURLcode result; - mbedtls_x509_crt *p; - unsigned char pubkey[PUB_DER_MAX_BYTES]; - - if(!peercert || !peercert->raw.p || !peercert->raw.len) { - failf(data, "Failed due to missing peer certificate"); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - p = calloc(1, sizeof(*p)); - - if(!p) - return CURLE_OUT_OF_MEMORY; - - mbedtls_x509_crt_init(p); - - /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der - needs a non-const key, for now. - https://github.com/ARMmbed/mbedtls/issues/396 */ - if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { - failf(data, "Failed copying peer certificate"); - mbedtls_x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); - - if(size <= 0) { - failf(data, "Failed copying public key from peer certificate"); - mbedtls_x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ - result = Curl_pin_peer_pubkey(data, - pinnedpubkey, - &pubkey[PUB_DER_MAX_BYTES - size], size); - if(result) { - mbedtls_x509_crt_free(p); - free(p); - return result; - } - - mbedtls_x509_crt_free(p); - free(p); - } - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl); - - if(next_protocol) { - infof(data, "ALPN, server accepted to use %s\n", next_protocol); -#ifdef USE_NGHTTP2 - if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN) && - !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) { - conn->negnpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && - !next_protocol[ALPN_HTTP_1_1_LENGTH]) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } - } - else { - infof(data, "ALPN, server did not agree to a protocol\n"); - } - } -#endif - - connssl->connecting_state = ssl_connect_3; - infof(data, "SSL connected\n"); - - return CURLE_OK; -} - -static CURLcode -mbed_connect_step3(struct connectdata *conn, - int sockindex) -{ - CURLcode retcode = CURLE_OK; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - - if(SSL_SET_OPTION(primary.sessionid)) { - int ret; - mbedtls_ssl_session *our_ssl_sessionid; - void *old_ssl_sessionid = NULL; - - our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); - if(!our_ssl_sessionid) - return CURLE_OUT_OF_MEMORY; - - mbedtls_ssl_session_init(our_ssl_sessionid); - - ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid); - if(ret) { - free(our_ssl_sessionid); - failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; - } - - /* If there's already a matching session in the cache, delete it */ - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); - Curl_ssl_sessionid_unlock(conn); - if(retcode) { - free(our_ssl_sessionid); - failf(data, "failed to store ssl session"); - return retcode; - } - } - - connssl->connecting_state = ssl_connect_done; - - return CURLE_OK; -} - -static ssize_t mbed_send(struct connectdata *conn, int sockindex, - const void *mem, size_t len, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - int ret = -1; - - ret = mbedtls_ssl_write(&BACKEND->ssl, - (unsigned char *)mem, len); - - if(ret < 0) { - *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ? - CURLE_AGAIN : CURLE_SEND_ERROR; - ret = -1; - } - - return ret; -} - -static void Curl_mbedtls_close_all(struct Curl_easy *data) -{ - (void)data; -} - -static void Curl_mbedtls_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - mbedtls_pk_free(&BACKEND->pk); - mbedtls_x509_crt_free(&BACKEND->clicert); - mbedtls_x509_crt_free(&BACKEND->cacert); - mbedtls_x509_crl_free(&BACKEND->crl); - mbedtls_ssl_config_free(&BACKEND->config); - mbedtls_ssl_free(&BACKEND->ssl); - mbedtls_ctr_drbg_free(&BACKEND->ctr_drbg); -#ifndef THREADING_SUPPORT - mbedtls_entropy_free(&BACKEND->entropy); -#endif /* THREADING_SUPPORT */ -} - -static ssize_t mbed_recv(struct connectdata *conn, int num, - char *buf, size_t buffersize, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[num]; - int ret = -1; - ssize_t len = -1; - - memset(buf, 0, buffersize); - ret = mbedtls_ssl_read(&BACKEND->ssl, (unsigned char *)buf, - buffersize); - - if(ret <= 0) { - if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) - return 0; - - *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ? - CURLE_AGAIN : CURLE_RECV_ERROR; - return -1; - } - - len = ret; - - return len; -} - -static void Curl_mbedtls_session_free(void *ptr) -{ - mbedtls_ssl_session_free(ptr); - free(ptr); -} - -static size_t Curl_mbedtls_version(char *buffer, size_t size) -{ - unsigned int version = mbedtls_version_get_number(); - return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24, - (version>>16)&0xff, (version>>8)&0xff); -} - -static CURLcode Curl_mbedtls_random(struct Curl_easy *data, - unsigned char *entropy, size_t length) -{ -#if defined(MBEDTLS_CTR_DRBG_C) - int ret = -1; - char errorbuf[128]; - mbedtls_entropy_context ctr_entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_entropy_init(&ctr_entropy); - mbedtls_ctr_drbg_init(&ctr_drbg); - errorbuf[0] = 0; - - ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, - &ctr_entropy, NULL, 0); - - if(ret) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s\n", - -ret, errorbuf); - } - else { - ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length); - - if(ret) { -#ifdef MBEDTLS_ERROR_C - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ - failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); - } - } - - mbedtls_ctr_drbg_free(&ctr_drbg); - mbedtls_entropy_free(&ctr_entropy); - - return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT; -#elif defined(MBEDTLS_HAVEGE_C) - mbedtls_havege_state hs; - mbedtls_havege_init(&hs); - mbedtls_havege_random(&hs, entropy, length); - mbedtls_havege_free(&hs); - return CURLE_OK; -#else - return CURLE_NOT_BUILT_IN; -#endif -} - -static CURLcode -mbed_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - CURLcode retcode; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; - int what; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - retcode = mbed_connect_step1(conn, sockindex); - if(retcode) - return retcode; - } - - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if - * this connection is part of a multi handle and this loop would - * execute again. This permits the owner of a multi handle to - * abort a connection attempt before step2 has completed while - * ensuring that a client using select() or epoll() will always - * have a valid fdset to wait on. - */ - retcode = mbed_connect_step2(conn, sockindex); - if(retcode || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return retcode; - - } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3 == connssl->connecting_state) { - retcode = mbed_connect_step3(conn, sockindex); - if(retcode) - return retcode; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = mbed_recv; - conn->send[sockindex] = mbed_send; - *done = TRUE; - } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - return mbed_connect_common(conn, sockindex, TRUE, done); -} - - -static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex) -{ - CURLcode retcode; - bool done = FALSE; - - retcode = mbed_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -/* - * return 0 error initializing SSL - * return 1 SSL initialized successfully - */ -static int Curl_mbedtls_init(void) -{ - return Curl_polarsslthreadlock_thread_setup(); -} - -static void Curl_mbedtls_cleanup(void) -{ - (void)Curl_polarsslthreadlock_thread_cleanup(); -} - -static bool Curl_mbedtls_data_pending(const struct connectdata *conn, - int sockindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0; -} - -static void Curl_mbedtls_sha256sum(const unsigned char *input, - size_t inputlen, - unsigned char *sha256sum, - size_t sha256len UNUSED_PARAM) -{ - (void)sha256len; - mbedtls_sha256(input, inputlen, sha256sum, 0); -} - -static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return &BACKEND->ssl; -} - -const struct Curl_ssl Curl_ssl_mbedtls = { - { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */ - - 1, /* have_ca_path */ - 0, /* have_certinfo */ - 1, /* have_pinnedpubkey */ - 1, /* have_ssl_ctx */ - 0, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_mbedtls_init, /* init */ - Curl_mbedtls_cleanup, /* cleanup */ - Curl_mbedtls_version, /* version */ - Curl_none_check_cxn, /* check_cxn */ - Curl_none_shutdown, /* shutdown */ - Curl_mbedtls_data_pending, /* data_pending */ - Curl_mbedtls_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_mbedtls_connect, /* connect */ - Curl_mbedtls_connect_nonblocking, /* connect_nonblocking */ - Curl_mbedtls_get_internals, /* get_internals */ - Curl_mbedtls_close, /* close */ - Curl_mbedtls_close_all, /* close_all */ - Curl_mbedtls_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - Curl_mbedtls_sha256sum /* sha256sum */ -}; - -#endif /* USE_MBEDTLS */ diff --git a/dep/cpr/opt/curl/lib/vtls/mbedtls.h b/dep/cpr/opt/curl/lib/vtls/mbedtls.h deleted file mode 100644 index 4a938605bdb..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/mbedtls.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef HEADER_CURL_MBEDTLS_H -#define HEADER_CURL_MBEDTLS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. - * Copyright (C) 2010, Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifdef USE_MBEDTLS - -extern const struct Curl_ssl Curl_ssl_mbedtls; - -#endif /* USE_MBEDTLS */ -#endif /* HEADER_CURL_MBEDTLS_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/nss.c b/dep/cpr/opt/curl/lib/vtls/nss.c deleted file mode 100644 index c0b7e63abc9..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/nss.c +++ /dev/null @@ -1,2380 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all NSS-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - */ - -#include "curl_setup.h" - -#ifdef USE_NSS - -#include "urldata.h" -#include "sendf.h" -#include "formdata.h" /* for the boundary function */ -#include "url.h" /* for the ssl config check function */ -#include "connect.h" -#include "strcase.h" -#include "select.h" -#include "vtls.h" -#include "llist.h" -#include "curl_printf.h" -#include "nssg.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for SECKEY_DestroyPublicKey() */ -#include /* for PR_ImportTCPSocket */ - -#define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH) - -#if NSSVERNUM >= 0x030f00 /* 3.15.0 */ -#include -#endif - -#include "strcase.h" -#include "warnless.h" -#include "x509asn1.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -#define SSL_DIR "/etc/pki/nssdb" - -/* enough to fit the string "PEM Token #[0|1]" */ -#define SLOTSIZE 13 - -struct ssl_backend_data { - PRFileDesc *handle; - char *client_nickname; - struct Curl_easy *data; - struct curl_llist obj_list; - PK11GenericObject *obj_clicert; -}; - -#define BACKEND connssl->backend - -static PRLock *nss_initlock = NULL; -static PRLock *nss_crllock = NULL; -static PRLock *nss_findslot_lock = NULL; -static PRLock *nss_trustload_lock = NULL; -static struct curl_llist nss_crl_list; -static NSSInitContext *nss_context = NULL; -static volatile int initialized = 0; - -/* type used to wrap pointers as list nodes */ -struct ptr_list_wrap { - void *ptr; - struct curl_llist_element node; -}; - -typedef struct { - const char *name; - int num; -} cipher_s; - -#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \ - CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \ - ptr->type = (_type); \ - ptr->pValue = (_val); \ - ptr->ulValueLen = (_len); \ -} WHILE_FALSE - -#define CERT_NewTempCertificate __CERT_NewTempCertificate - -#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0]) -static const cipher_s cipherlist[] = { - /* SSL2 cipher suites */ - {"rc4", SSL_EN_RC4_128_WITH_MD5}, - {"rc4-md5", SSL_EN_RC4_128_WITH_MD5}, - {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5}, - {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5}, - {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5}, - {"des", SSL_EN_DES_64_CBC_WITH_MD5}, - {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5}, - /* SSL3/TLS cipher suites */ - {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5}, - {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA}, - {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA}, - {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA}, - {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5}, - {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5}, - {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5}, - {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA}, - {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA}, - {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA}, - {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA}, - {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA}, - {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA}, - /* TLS 1.0: Exportable 56-bit Cipher Suites. */ - {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA}, - {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA}, - /* AES ciphers. */ - {"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA}, - {"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA}, - {"dhe_rsa_aes_128_cbc_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA}, - {"dhe_rsa_aes_256_cbc_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA}, - {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA}, - {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA}, - /* ECC ciphers. */ - {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA}, - {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA}, - {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA}, - {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA}, - {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA}, - {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA}, - {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA}, - {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA}, - {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}, - {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, - {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA}, - {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA}, - {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}, - {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA}, - {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA}, - {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, - {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, - {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, - {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, - {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, - {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA}, - {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA}, - {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA}, - {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA}, - {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA}, -#ifdef TLS_RSA_WITH_NULL_SHA256 - /* new HMAC-SHA256 cipher suites specified in RFC */ - {"rsa_null_sha_256", TLS_RSA_WITH_NULL_SHA256}, - {"rsa_aes_128_cbc_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256}, - {"rsa_aes_256_cbc_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256}, - {"dhe_rsa_aes_128_cbc_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256}, - {"dhe_rsa_aes_256_cbc_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256}, - {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}, - {"ecdhe_rsa_aes_128_cbc_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}, -#endif -#ifdef TLS_RSA_WITH_AES_128_GCM_SHA256 - /* AES GCM cipher suites in RFC 5288 and RFC 5289 */ - {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256}, - {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256}, - {"dhe_dss_aes_128_gcm_sha_256", TLS_DHE_DSS_WITH_AES_128_GCM_SHA256}, - {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - {"ecdh_ecdsa_aes_128_gcm_sha_256", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256}, - {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256}, -#endif -#ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - /* cipher suites using SHA384 */ - {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384}, - {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384}, - {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384}, - {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384}, - {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, - {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384}, - {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, -#endif -#ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - /* chacha20-poly1305 cipher suites */ - {"ecdhe_rsa_chacha20_poly1305_sha_256", - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, - {"ecdhe_ecdsa_chacha20_poly1305_sha_256", - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256}, - {"dhe_rsa_chacha20_poly1305_sha_256", - TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, -#endif -}; - -static const char *pem_library = "libnsspem.so"; -static SECMODModule *pem_module = NULL; - -static const char *trust_library = "libnssckbi.so"; -static SECMODModule *trust_module = NULL; - -/* NSPR I/O layer we use to detect blocking direction during SSL handshake */ -static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER; -static PRIOMethods nspr_io_methods; - -static const char *nss_error_to_name(PRErrorCode code) -{ - const char *name = PR_ErrorToName(code); - if(name) - return name; - - return "unknown error"; -} - -static void nss_print_error_message(struct Curl_easy *data, PRUint32 err) -{ - failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); -} - -static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, - char *cipher_list) -{ - unsigned int i; - PRBool cipher_state[NUM_OF_CIPHERS]; - PRBool found; - char *cipher; - - /* use accessors to avoid dynamic linking issues after an update of NSS */ - const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers(); - const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers(); - if(!implemented_ciphers) - return SECFailure; - - /* First disable all ciphers. This uses a different max value in case - * NSS adds more ciphers later we don't want them available by - * accident - */ - for(i = 0; i < num_implemented_ciphers; i++) { - SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE); - } - - /* Set every entry in our list to false */ - for(i = 0; i < NUM_OF_CIPHERS; i++) { - cipher_state[i] = PR_FALSE; - } - - cipher = cipher_list; - - while(cipher_list && (cipher_list[0])) { - while((*cipher) && (ISSPACE(*cipher))) - ++cipher; - - cipher_list = strchr(cipher, ','); - if(cipher_list) { - *cipher_list++ = '\0'; - } - - found = PR_FALSE; - - for(i = 0; i. - */ -static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name) -{ - PK11SlotInfo *slot; - PR_Lock(nss_findslot_lock); - slot = PK11_FindSlotByName(slot_name); - PR_Unlock(nss_findslot_lock); - return slot; -} - -/* wrap 'ptr' as list node and tail-insert into 'list' */ -static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr) -{ - struct ptr_list_wrap *wrap = malloc(sizeof *wrap); - if(!wrap) - return CURLE_OUT_OF_MEMORY; - - wrap->ptr = ptr; - Curl_llist_insert_next(list, list->tail, wrap, &wrap->node); - return CURLE_OK; -} - -/* Call PK11_CreateGenericObject() with the given obj_class and filename. If - * the call succeeds, append the object handle to the list of objects so that - * the object can be destroyed in Curl_nss_close(). */ -static CURLcode nss_create_object(struct ssl_connect_data *connssl, - CK_OBJECT_CLASS obj_class, - const char *filename, bool cacert) -{ - PK11SlotInfo *slot; - PK11GenericObject *obj; - CK_BBOOL cktrue = CK_TRUE; - CK_BBOOL ckfalse = CK_FALSE; - CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; - int attr_cnt = 0; - CURLcode result = (cacert) - ? CURLE_SSL_CACERT_BADFILE - : CURLE_SSL_CERTPROBLEM; - - const int slot_id = (cacert) ? 0 : 1; - char *slot_name = aprintf("PEM Token #%d", slot_id); - if(!slot_name) - return CURLE_OUT_OF_MEMORY; - - slot = nss_find_slot_by_name(slot_name); - free(slot_name); - if(!slot) - return result; - - PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); - PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); - PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename, - (CK_ULONG)strlen(filename) + 1); - - if(CKO_CERTIFICATE == obj_class) { - CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse); - PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval)); - } - - obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE); - PK11_FreeSlot(slot); - if(!obj) - return result; - - if(insert_wrapped_ptr(&BACKEND->obj_list, obj) != CURLE_OK) { - PK11_DestroyGenericObject(obj); - return CURLE_OUT_OF_MEMORY; - } - - if(!cacert && CKO_CERTIFICATE == obj_class) - /* store reference to a client certificate */ - BACKEND->obj_clicert = obj; - - return CURLE_OK; -} - -/* Destroy the NSS object whose handle is given by ptr. This function is - * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy - * NSS objects in Curl_nss_close() */ -static void nss_destroy_object(void *user, void *ptr) -{ - struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr; - PK11GenericObject *obj = (PK11GenericObject *) wrap->ptr; - (void) user; - PK11_DestroyGenericObject(obj); - free(wrap); -} - -/* same as nss_destroy_object() but for CRL items */ -static void nss_destroy_crl_item(void *user, void *ptr) -{ - struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr; - SECItem *crl_der = (SECItem *) wrap->ptr; - (void) user; - SECITEM_FreeItem(crl_der, PR_TRUE); - free(wrap); -} - -static CURLcode nss_load_cert(struct ssl_connect_data *ssl, - const char *filename, PRBool cacert) -{ - CURLcode result = (cacert) - ? CURLE_SSL_CACERT_BADFILE - : CURLE_SSL_CERTPROBLEM; - - /* libnsspem.so leaks memory if the requested file does not exist. For more - * details, go to . */ - if(is_file(filename)) - result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert); - - if(!result && !cacert) { - /* we have successfully loaded a client certificate */ - CERTCertificate *cert; - char *nickname = NULL; - char *n = strrchr(filename, '/'); - if(n) - n++; - - /* The following undocumented magic helps to avoid a SIGSEGV on call - * of PK11_ReadRawAttribute() from SelectClientCert() when using an - * immature version of libnsspem.so. For more details, go to - * . */ - nickname = aprintf("PEM Token #1:%s", n); - if(nickname) { - cert = PK11_FindCertFromNickname(nickname, NULL); - if(cert) - CERT_DestroyCertificate(cert); - - free(nickname); - } - } - - return result; -} - -/* add given CRL to cache if it is not already there */ -static CURLcode nss_cache_crl(SECItem *crl_der) -{ - CERTCertDBHandle *db = CERT_GetDefaultCertDB(); - CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0); - if(crl) { - /* CRL already cached */ - SEC_DestroyCrl(crl); - SECITEM_FreeItem(crl_der, PR_TRUE); - return CURLE_OK; - } - - /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */ - PR_Lock(nss_crllock); - - /* store the CRL item so that we can free it in Curl_nss_cleanup() */ - if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) { - SECITEM_FreeItem(crl_der, PR_TRUE); - PR_Unlock(nss_crllock); - return CURLE_OUT_OF_MEMORY; - } - - if(SECSuccess != CERT_CacheCRL(db, crl_der)) { - /* unable to cache CRL */ - PR_Unlock(nss_crllock); - return CURLE_SSL_CRL_BADFILE; - } - - /* we need to clear session cache, so that the CRL could take effect */ - SSL_ClearSessionCache(); - PR_Unlock(nss_crllock); - return CURLE_OK; -} - -static CURLcode nss_load_crl(const char *crlfilename) -{ - PRFileDesc *infile; - PRFileInfo info; - SECItem filedata = { 0, NULL, 0 }; - SECItem *crl_der = NULL; - char *body; - - infile = PR_Open(crlfilename, PR_RDONLY, 0); - if(!infile) - return CURLE_SSL_CRL_BADFILE; - - if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info)) - goto fail; - - if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1)) - goto fail; - - if(info.size != PR_Read(infile, filedata.data, info.size)) - goto fail; - - crl_der = SECITEM_AllocItem(NULL, NULL, 0U); - if(!crl_der) - goto fail; - - /* place a trailing zero right after the visible data */ - body = (char *)filedata.data; - body[--filedata.len] = '\0'; - - body = strstr(body, "-----BEGIN"); - if(body) { - /* assume ASCII */ - char *trailer; - char *begin = PORT_Strchr(body, '\n'); - if(!begin) - begin = PORT_Strchr(body, '\r'); - if(!begin) - goto fail; - - trailer = strstr(++begin, "-----END"); - if(!trailer) - goto fail; - - /* retrieve DER from ASCII */ - *trailer = '\0'; - if(ATOB_ConvertAsciiToItem(crl_der, begin)) - goto fail; - - SECITEM_FreeItem(&filedata, PR_FALSE); - } - else - /* assume DER */ - *crl_der = filedata; - - PR_Close(infile); - return nss_cache_crl(crl_der); - -fail: - PR_Close(infile); - SECITEM_FreeItem(crl_der, PR_TRUE); - SECITEM_FreeItem(&filedata, PR_FALSE); - return CURLE_SSL_CRL_BADFILE; -} - -static CURLcode nss_load_key(struct connectdata *conn, int sockindex, - char *key_file) -{ - PK11SlotInfo *slot, *tmp; - SECStatus status; - CURLcode result; - struct ssl_connect_data *ssl = conn->ssl; - struct Curl_easy *data = conn->data; - - (void)sockindex; /* unused */ - - result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE); - if(result) { - PR_SetError(SEC_ERROR_BAD_KEY, 0); - return result; - } - - slot = nss_find_slot_by_name("PEM Token #1"); - if(!slot) - return CURLE_SSL_CERTPROBLEM; - - /* This will force the token to be seen as re-inserted */ - tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0); - if(tmp) - PK11_FreeSlot(tmp); - PK11_IsPresent(slot); - - status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd)); - PK11_FreeSlot(slot); - - return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM; -} - -static int display_error(struct connectdata *conn, PRInt32 err, - const char *filename) -{ - switch(err) { - case SEC_ERROR_BAD_PASSWORD: - failf(conn->data, "Unable to load client key: Incorrect password"); - return 1; - case SEC_ERROR_UNKNOWN_CERT: - failf(conn->data, "Unable to load certificate %s", filename); - return 1; - default: - break; - } - return 0; /* The caller will print a generic error */ -} - -static CURLcode cert_stuff(struct connectdata *conn, int sockindex, - char *cert_file, char *key_file) -{ - struct Curl_easy *data = conn->data; - CURLcode result; - - if(cert_file) { - result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE); - if(result) { - const PRErrorCode err = PR_GetError(); - if(!display_error(conn, err, cert_file)) { - const char *err_name = nss_error_to_name(err); - failf(data, "unable to load client cert: %d (%s)", err, err_name); - } - - return result; - } - } - - if(key_file || (is_file(cert_file))) { - if(key_file) - result = nss_load_key(conn, sockindex, key_file); - else - /* In case the cert file also has the key */ - result = nss_load_key(conn, sockindex, cert_file); - if(result) { - const PRErrorCode err = PR_GetError(); - if(!display_error(conn, err, key_file)) { - const char *err_name = nss_error_to_name(err); - failf(data, "unable to load client key: %d (%s)", err, err_name); - } - - return result; - } - } - - return CURLE_OK; -} - -static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg) -{ - (void)slot; /* unused */ - - if(retry || NULL == arg) - return NULL; - else - return (char *)PORT_Strdup((char *)arg); -} - -/* bypass the default SSL_AuthCertificate() hook in case we do not want to - * verify peer */ -static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, - PRBool isServer) -{ - struct connectdata *conn = (struct connectdata *)arg; - -#ifdef SSL_ENABLE_OCSP_STAPLING - if(SSL_CONN_CONFIG(verifystatus)) { - SECStatus cacheResult; - - const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd); - if(!csa) { - failf(conn->data, "Invalid OCSP response"); - return SECFailure; - } - - if(csa->len == 0) { - failf(conn->data, "No OCSP response received"); - return SECFailure; - } - - cacheResult = CERT_CacheOCSPResponseFromSideChannel( - CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd), - PR_Now(), &csa->items[0], arg - ); - - if(cacheResult != SECSuccess) { - failf(conn->data, "Invalid OCSP response"); - return cacheResult; - } - } -#endif - - if(!SSL_CONN_CONFIG(verifypeer)) { - infof(conn->data, "skipping SSL peer certificate verification\n"); - return SECSuccess; - } - - return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer); -} - -/** - * Inform the application that the handshake is complete. - */ -static void HandshakeCallback(PRFileDesc *sock, void *arg) -{ - struct connectdata *conn = (struct connectdata*) arg; - unsigned int buflenmax = 50; - unsigned char buf[50]; - unsigned int buflen; - SSLNextProtoState state; - - if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) { - return; - } - - if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) { - - switch(state) { -#if NSSVERNUM >= 0x031a00 /* 3.26.0 */ - /* used by NSS internally to implement 0-RTT */ - case SSL_NEXT_PROTO_EARLY_VALUE: - /* fall through! */ -#endif - case SSL_NEXT_PROTO_NO_SUPPORT: - case SSL_NEXT_PROTO_NO_OVERLAP: - infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n"); - return; -#ifdef SSL_ENABLE_ALPN - case SSL_NEXT_PROTO_SELECTED: - infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf); - break; -#endif - case SSL_NEXT_PROTO_NEGOTIATED: - infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf); - break; - } - -#ifdef USE_NGHTTP2 - if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN && - !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(buflen == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } - } -} - -#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ -static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data, - PRBool *canFalseStart) -{ - struct connectdata *conn = client_data; - struct Curl_easy *data = conn->data; - - SSLChannelInfo channelInfo; - SSLCipherSuiteInfo cipherInfo; - - SECStatus rv; - PRBool negotiatedExtension; - - *canFalseStart = PR_FALSE; - - if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess) - return SECFailure; - - if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo, - sizeof(cipherInfo)) != SECSuccess) - return SECFailure; - - /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for - * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310 - */ - if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) - goto end; - - /* Only allow ECDHE key exchange algorithm. - * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */ - if(cipherInfo.keaType != ssl_kea_ecdh) - goto end; - - /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC - * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt - * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */ - if(cipherInfo.symCipher != ssl_calg_aes_gcm) - goto end; - - /* Enforce ALPN or NPN to do False Start, as an indicator of server - * compatibility. */ - rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn, - &negotiatedExtension); - if(rv != SECSuccess || !negotiatedExtension) { - rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn, - &negotiatedExtension); - } - - if(rv != SECSuccess || !negotiatedExtension) - goto end; - - *canFalseStart = PR_TRUE; - - infof(data, "Trying TLS False Start\n"); - -end: - return SECSuccess; -} -#endif - -static void display_cert_info(struct Curl_easy *data, - CERTCertificate *cert) -{ - char *subject, *issuer, *common_name; - PRExplodedTime printableTime; - char timeString[256]; - PRTime notBefore, notAfter; - - subject = CERT_NameToAscii(&cert->subject); - issuer = CERT_NameToAscii(&cert->issuer); - common_name = CERT_GetCommonName(&cert->subject); - infof(data, "\tsubject: %s\n", subject); - - CERT_GetCertTimes(cert, ¬Before, ¬After); - PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime); - PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); - infof(data, "\tstart date: %s\n", timeString); - PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime); - PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); - infof(data, "\texpire date: %s\n", timeString); - infof(data, "\tcommon name: %s\n", common_name); - infof(data, "\tissuer: %s\n", issuer); - - PR_Free(subject); - PR_Free(issuer); - PR_Free(common_name); -} - -static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock) -{ - CURLcode result = CURLE_OK; - SSLChannelInfo channel; - SSLCipherSuiteInfo suite; - CERTCertificate *cert; - CERTCertificate *cert2; - CERTCertificate *cert3; - PRTime now; - int i; - - if(SSL_GetChannelInfo(sock, &channel, sizeof channel) == - SECSuccess && channel.length == sizeof channel && - channel.cipherSuite) { - if(SSL_GetCipherSuiteInfo(channel.cipherSuite, - &suite, sizeof suite) == SECSuccess) { - infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName); - } - } - - cert = SSL_PeerCertificate(sock); - if(cert) { - infof(conn->data, "Server certificate:\n"); - - if(!conn->data->set.ssl.certinfo) { - display_cert_info(conn->data, cert); - CERT_DestroyCertificate(cert); - } - else { - /* Count certificates in chain. */ - now = PR_Now(); - i = 1; - if(!cert->isRoot) { - cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); - while(cert2) { - i++; - if(cert2->isRoot) { - CERT_DestroyCertificate(cert2); - break; - } - cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA); - CERT_DestroyCertificate(cert2); - cert2 = cert3; - } - } - - result = Curl_ssl_init_certinfo(conn->data, i); - if(!result) { - for(i = 0; cert; cert = cert2) { - result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data, - (char *)cert->derCert.data + - cert->derCert.len); - if(result) - break; - - if(cert->isRoot) { - CERT_DestroyCertificate(cert); - break; - } - - cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); - CERT_DestroyCertificate(cert); - } - } - } - } - - return result; -} - -static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) -{ - struct connectdata *conn = (struct connectdata *)arg; - struct Curl_easy *data = conn->data; - PRErrorCode err = PR_GetError(); - CERTCertificate *cert; - - /* remember the cert verification result */ - if(SSL_IS_PROXY()) - data->set.proxy_ssl.certverifyresult = err; - else - data->set.ssl.certverifyresult = err; - - if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost)) - /* we are asked not to verify the host name */ - return SECSuccess; - - /* print only info about the cert, the error is printed off the callback */ - cert = SSL_PeerCertificate(sock); - if(cert) { - infof(data, "Server certificate:\n"); - display_cert_info(data, cert); - CERT_DestroyCertificate(cert); - } - - return SECFailure; -} - -/** - * - * Check that the Peer certificate's issuer certificate matches the one found - * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the - * issuer check, so we provide comments that mimic the OpenSSL - * X509_check_issued function (in x509v3/v3_purp.c) - */ -static SECStatus check_issuer_cert(PRFileDesc *sock, - char *issuer_nickname) -{ - CERTCertificate *cert, *cert_issuer, *issuer; - SECStatus res = SECSuccess; - void *proto_win = NULL; - - cert = SSL_PeerCertificate(sock); - cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner); - - proto_win = SSL_RevealPinArg(sock); - issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); - - if((!cert_issuer) || (!issuer)) - res = SECFailure; - else if(SECITEM_CompareItem(&cert_issuer->derCert, - &issuer->derCert) != SECEqual) - res = SECFailure; - - CERT_DestroyCertificate(cert); - CERT_DestroyCertificate(issuer); - CERT_DestroyCertificate(cert_issuer); - return res; -} - -static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, - const char *pinnedpubkey) -{ - CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - struct Curl_easy *data = BACKEND->data; - CERTCertificate *cert; - - if(!pinnedpubkey) - /* no pinned public key specified */ - return CURLE_OK; - - /* get peer certificate */ - cert = SSL_PeerCertificate(BACKEND->handle); - if(cert) { - /* extract public key from peer certificate */ - SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert); - if(pubkey) { - /* encode the public key as DER */ - SECItem *cert_der = PK11_DEREncodePublicKey(pubkey); - if(cert_der) { - /* compare the public key with the pinned public key */ - result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data, - cert_der->len); - SECITEM_FreeItem(cert_der, PR_TRUE); - } - SECKEY_DestroyPublicKey(pubkey); - } - CERT_DestroyCertificate(cert); - } - - /* report the resulting status */ - switch(result) { - case CURLE_OK: - infof(data, "pinned public key verified successfully!\n"); - break; - case CURLE_SSL_PINNEDPUBKEYNOTMATCH: - failf(data, "failed to verify pinned public key"); - break; - default: - /* OOM, etc. */ - break; - } - - return result; -} - -/** - * - * Callback to pick the SSL client certificate. - */ -static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, - struct CERTDistNamesStr *caNames, - struct CERTCertificateStr **pRetCert, - struct SECKEYPrivateKeyStr **pRetKey) -{ - struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; - struct Curl_easy *data = BACKEND->data; - const char *nickname = BACKEND->client_nickname; - static const char pem_slotname[] = "PEM Token #1"; - - if(BACKEND->obj_clicert) { - /* use the cert/key provided by PEM reader */ - SECItem cert_der = { 0, NULL, 0 }; - void *proto_win = SSL_RevealPinArg(sock); - struct CERTCertificateStr *cert; - struct SECKEYPrivateKeyStr *key; - - PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname); - if(NULL == slot) { - failf(data, "NSS: PK11 slot not found: %s", pem_slotname); - return SECFailure; - } - - if(PK11_ReadRawAttribute(PK11_TypeGeneric, BACKEND->obj_clicert, CKA_VALUE, - &cert_der) != SECSuccess) { - failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); - PK11_FreeSlot(slot); - return SECFailure; - } - - cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win); - SECITEM_FreeItem(&cert_der, PR_FALSE); - if(NULL == cert) { - failf(data, "NSS: client certificate from file not found"); - PK11_FreeSlot(slot); - return SECFailure; - } - - key = PK11_FindPrivateKeyFromCert(slot, cert, NULL); - PK11_FreeSlot(slot); - if(NULL == key) { - failf(data, "NSS: private key from file not found"); - CERT_DestroyCertificate(cert); - return SECFailure; - } - - infof(data, "NSS: client certificate from file\n"); - display_cert_info(data, cert); - - *pRetCert = cert; - *pRetKey = key; - return SECSuccess; - } - - /* use the default NSS hook */ - if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, - pRetCert, pRetKey) - || NULL == *pRetCert) { - - if(NULL == nickname) - failf(data, "NSS: client certificate not found (nickname not " - "specified)"); - else - failf(data, "NSS: client certificate not found: %s", nickname); - - return SECFailure; - } - - /* get certificate nickname if any */ - nickname = (*pRetCert)->nickname; - if(NULL == nickname) - nickname = "[unknown]"; - - if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) { - failf(data, "NSS: refusing previously loaded certificate from file: %s", - nickname); - return SECFailure; - } - - if(NULL == *pRetKey) { - failf(data, "NSS: private key not found for certificate: %s", nickname); - return SECFailure; - } - - infof(data, "NSS: using client certificate: %s\n", nickname); - display_cert_info(data, *pRetCert); - return SECSuccess; -} - -/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */ -static void nss_update_connecting_state(ssl_connect_state state, void *secret) -{ - struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret; - if(PR_GetError() != PR_WOULD_BLOCK_ERROR) - /* an unrelated error is passing by */ - return; - - switch(connssl->connecting_state) { - case ssl_connect_2: - case ssl_connect_2_reading: - case ssl_connect_2_writing: - break; - default: - /* we are not called from an SSL handshake */ - return; - } - - /* update the state accordingly */ - connssl->connecting_state = state; -} - -/* recv() wrapper we use to detect blocking direction during SSL handshake */ -static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, - PRIntn flags, PRIntervalTime timeout) -{ - const PRRecvFN recv_fn = fd->lower->methods->recv; - const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout); - if(rv < 0) - /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */ - nss_update_connecting_state(ssl_connect_2_reading, fd->secret); - return rv; -} - -/* send() wrapper we use to detect blocking direction during SSL handshake */ -static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, - PRIntn flags, PRIntervalTime timeout) -{ - const PRSendFN send_fn = fd->lower->methods->send; - const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout); - if(rv < 0) - /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */ - nss_update_connecting_state(ssl_connect_2_writing, fd->secret); - return rv; -} - -/* close() wrapper to avoid assertion failure due to fd->secret != NULL */ -static PRStatus nspr_io_close(PRFileDesc *fd) -{ - const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close; - fd->secret = NULL; - return close_fn(fd); -} - -/* load a PKCS #11 module */ -static CURLcode nss_load_module(SECMODModule **pmod, const char *library, - const char *name) -{ - char *config_string; - SECMODModule *module = *pmod; - if(module) - /* already loaded */ - return CURLE_OK; - - config_string = aprintf("library=%s name=%s", library, name); - if(!config_string) - return CURLE_OUT_OF_MEMORY; - - module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE); - free(config_string); - - if(module && module->loaded) { - /* loaded successfully */ - *pmod = module; - return CURLE_OK; - } - - if(module) - SECMOD_DestroyModule(module); - return CURLE_FAILED_INIT; -} - -/* unload a PKCS #11 module */ -static void nss_unload_module(SECMODModule **pmod) -{ - SECMODModule *module = *pmod; - if(!module) - /* not loaded */ - return; - - if(SECMOD_UnloadUserModule(module) != SECSuccess) - /* unload failed */ - return; - - SECMOD_DestroyModule(module); - *pmod = NULL; -} - -/* data might be NULL */ -static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) -{ - NSSInitParameters initparams; - - if(nss_context != NULL) - return CURLE_OK; - - memset((void *) &initparams, '\0', sizeof(initparams)); - initparams.length = sizeof(initparams); - - if(cert_dir) { - char *certpath = aprintf("sql:%s", cert_dir); - if(!certpath) - return CURLE_OUT_OF_MEMORY; - - infof(data, "Initializing NSS with certpath: %s\n", certpath); - nss_context = NSS_InitContext(certpath, "", "", "", &initparams, - NSS_INIT_READONLY | NSS_INIT_PK11RELOAD); - free(certpath); - - if(nss_context != NULL) - return CURLE_OK; - - infof(data, "Unable to initialize NSS database\n"); - } - - infof(data, "Initializing NSS with certpath: none\n"); - nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY - | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN - | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); - if(nss_context != NULL) - return CURLE_OK; - - infof(data, "Unable to initialize NSS\n"); - return CURLE_SSL_CACERT_BADFILE; -} - -/* data might be NULL */ -static CURLcode nss_init(struct Curl_easy *data) -{ - char *cert_dir; - struct_stat st; - CURLcode result; - - if(initialized) - return CURLE_OK; - - /* list of all CRL items we need to destroy in Curl_nss_cleanup() */ - Curl_llist_init(&nss_crl_list, nss_destroy_crl_item); - - /* First we check if $SSL_DIR points to a valid dir */ - cert_dir = getenv("SSL_DIR"); - if(cert_dir) { - if((stat(cert_dir, &st) != 0) || - (!S_ISDIR(st.st_mode))) { - cert_dir = NULL; - } - } - - /* Now we check if the default location is a valid dir */ - if(!cert_dir) { - if((stat(SSL_DIR, &st) == 0) && - (S_ISDIR(st.st_mode))) { - cert_dir = (char *)SSL_DIR; - } - } - - if(nspr_io_identity == PR_INVALID_IO_LAYER) { - /* allocate an identity for our own NSPR I/O layer */ - nspr_io_identity = PR_GetUniqueIdentity("libcurl"); - if(nspr_io_identity == PR_INVALID_IO_LAYER) - return CURLE_OUT_OF_MEMORY; - - /* the default methods just call down to the lower I/O layer */ - memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(), sizeof nspr_io_methods); - - /* override certain methods in the table by our wrappers */ - nspr_io_methods.recv = nspr_io_recv; - nspr_io_methods.send = nspr_io_send; - nspr_io_methods.close = nspr_io_close; - } - - result = nss_init_core(data, cert_dir); - if(result) - return result; - - if(!any_cipher_enabled()) - NSS_SetDomesticPolicy(); - - initialized = 1; - - return CURLE_OK; -} - -/** - * Global SSL init - * - * @retval 0 error initializing SSL - * @retval 1 SSL initialized successfully - */ -static int Curl_nss_init(void) -{ - /* curl_global_init() is not thread-safe so this test is ok */ - if(nss_initlock == NULL) { - PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); - nss_initlock = PR_NewLock(); - nss_crllock = PR_NewLock(); - nss_findslot_lock = PR_NewLock(); - nss_trustload_lock = PR_NewLock(); - } - - /* We will actually initialize NSS later */ - - return 1; -} - -/* data might be NULL */ -CURLcode Curl_nss_force_init(struct Curl_easy *data) -{ - CURLcode result; - if(!nss_initlock) { - if(data) - failf(data, "unable to initialize NSS, curl_global_init() should have " - "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL"); - return CURLE_FAILED_INIT; - } - - PR_Lock(nss_initlock); - result = nss_init(data); - PR_Unlock(nss_initlock); - - return result; -} - -/* Global cleanup */ -static void Curl_nss_cleanup(void) -{ - /* This function isn't required to be threadsafe and this is only done - * as a safety feature. - */ - PR_Lock(nss_initlock); - if(initialized) { - /* Free references to client certificates held in the SSL session cache. - * Omitting this hampers destruction of the security module owning - * the certificates. */ - SSL_ClearSessionCache(); - - nss_unload_module(&pem_module); - nss_unload_module(&trust_module); - NSS_ShutdownContext(nss_context); - nss_context = NULL; - } - - /* destroy all CRL items */ - Curl_llist_destroy(&nss_crl_list, NULL); - - PR_Unlock(nss_initlock); - - PR_DestroyLock(nss_initlock); - PR_DestroyLock(nss_crllock); - PR_DestroyLock(nss_findslot_lock); - PR_DestroyLock(nss_trustload_lock); - nss_initlock = NULL; - - initialized = 0; -} - -/* - * This function uses SSL_peek to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int Curl_nss_check_cxn(struct connectdata *conn) -{ - struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; - int rc; - char buf; - - rc = - PR_Recv(BACKEND->handle, (void *)&buf, 1, PR_MSG_PEEK, - PR_SecondsToInterval(1)); - if(rc > 0) - return 1; /* connection still in place */ - - if(rc == 0) - return 0; /* connection has been closed */ - - return -1; /* connection status unknown */ -} - -static void nss_close(struct ssl_connect_data *connssl) -{ - /* before the cleanup, check whether we are using a client certificate */ - const bool client_cert = (BACKEND->client_nickname != NULL) - || (BACKEND->obj_clicert != NULL); - - free(BACKEND->client_nickname); - BACKEND->client_nickname = NULL; - - /* destroy all NSS objects in order to avoid failure of NSS shutdown */ - Curl_llist_destroy(&BACKEND->obj_list, NULL); - BACKEND->obj_clicert = NULL; - - if(BACKEND->handle) { - if(client_cert) - /* A server might require different authentication based on the - * particular path being requested by the client. To support this - * scenario, we must ensure that a connection will never reuse the - * authentication data from a previous connection. */ - SSL_InvalidateSession(BACKEND->handle); - - PR_Close(BACKEND->handle); - BACKEND->handle = NULL; - } -} - -/* - * This function is called when an SSL connection is closed. - */ -static void Curl_nss_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex]; - - if(BACKEND->handle || connssl_proxy->backend->handle) { - /* NSS closes the socket we previously handed to it, so we must mark it - as closed to avoid double close */ - fake_sclose(conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - } - - if(BACKEND->handle) - /* nss_close(connssl) will transitively close also - connssl_proxy->backend->handle if both are used. Clear it to avoid - a double close leading to crash. */ - connssl_proxy->backend->handle = NULL; - - nss_close(connssl); - nss_close(connssl_proxy); -} - -/* return true if NSS can provide error code (and possibly msg) for the - error */ -static bool is_nss_error(CURLcode err) -{ - switch(err) { - case CURLE_PEER_FAILED_VERIFICATION: - case CURLE_SSL_CACERT: - case CURLE_SSL_CERTPROBLEM: - case CURLE_SSL_CONNECT_ERROR: - case CURLE_SSL_ISSUER_ERROR: - return true; - - default: - return false; - } -} - -/* return true if the given error code is related to a client certificate */ -static bool is_cc_error(PRInt32 err) -{ - switch(err) { - case SSL_ERROR_BAD_CERT_ALERT: - case SSL_ERROR_EXPIRED_CERT_ALERT: - case SSL_ERROR_REVOKED_CERT_ALERT: - return true; - - default: - return false; - } -} - -static Curl_recv nss_recv; -static Curl_send nss_send; - -static CURLcode nss_load_ca_certificates(struct connectdata *conn, - int sockindex) -{ - struct Curl_easy *data = conn->data; - const char *cafile = SSL_CONN_CONFIG(CAfile); - const char *capath = SSL_CONN_CONFIG(CApath); - bool use_trust_module; - CURLcode result = CURLE_OK; - - /* treat empty string as unset */ - if(cafile && !cafile[0]) - cafile = NULL; - if(capath && !capath[0]) - capath = NULL; - - infof(data, " CAfile: %s\n CApath: %s\n", - cafile ? cafile : "none", - capath ? capath : "none"); - - /* load libnssckbi.so if no other trust roots were specified */ - use_trust_module = !cafile && !capath; - - PR_Lock(nss_trustload_lock); - if(use_trust_module && !trust_module) { - /* libnssckbi.so needed but not yet loaded --> load it! */ - result = nss_load_module(&trust_module, trust_library, "trust"); - infof(data, "%s %s\n", (result) ? "failed to load" : "loaded", - trust_library); - if(result == CURLE_FAILED_INIT) - /* make the error non-fatal if we are not going to verify peer */ - result = CURLE_SSL_CACERT_BADFILE; - } - else if(!use_trust_module && trust_module) { - /* libnssckbi.so not needed but already loaded --> unload it! */ - infof(data, "unloading %s\n", trust_library); - nss_unload_module(&trust_module); - } - PR_Unlock(nss_trustload_lock); - - if(cafile) - result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); - - if(result) - return result; - - if(capath) { - struct_stat st; - if(stat(capath, &st) == -1) - return CURLE_SSL_CACERT_BADFILE; - - if(S_ISDIR(st.st_mode)) { - PRDirEntry *entry; - PRDir *dir = PR_OpenDir(capath); - if(!dir) - return CURLE_SSL_CACERT_BADFILE; - - while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) { - char *fullpath = aprintf("%s/%s", capath, entry->name); - if(!fullpath) { - PR_CloseDir(dir); - return CURLE_OUT_OF_MEMORY; - } - - if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE)) - /* This is purposefully tolerant of errors so non-PEM files can - * be in the same directory */ - infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath); - - free(fullpath); - } - - PR_CloseDir(dir); - } - else - infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath); - } - - return CURLE_OK; -} - -static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version) -{ - switch(version) { - case CURL_SSLVERSION_TLSv1: - /* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */ -#ifdef SSL_LIBRARY_VERSION_TLS_1_2 - *nssver = SSL_LIBRARY_VERSION_TLS_1_2; -#elif defined SSL_LIBRARY_VERSION_TLS_1_1 - *nssver = SSL_LIBRARY_VERSION_TLS_1_1; -#else - *nssver = SSL_LIBRARY_VERSION_TLS_1_0; -#endif - return CURLE_OK; - - case CURL_SSLVERSION_SSLv2: - *nssver = SSL_LIBRARY_VERSION_2; - return CURLE_OK; - - case CURL_SSLVERSION_SSLv3: - *nssver = SSL_LIBRARY_VERSION_3_0; - return CURLE_OK; - - case CURL_SSLVERSION_TLSv1_0: - *nssver = SSL_LIBRARY_VERSION_TLS_1_0; - return CURLE_OK; - - case CURL_SSLVERSION_TLSv1_1: -#ifdef SSL_LIBRARY_VERSION_TLS_1_1 - *nssver = SSL_LIBRARY_VERSION_TLS_1_1; - return CURLE_OK; -#else - return CURLE_SSL_CONNECT_ERROR; -#endif - - case CURL_SSLVERSION_TLSv1_2: -#ifdef SSL_LIBRARY_VERSION_TLS_1_2 - *nssver = SSL_LIBRARY_VERSION_TLS_1_2; - return CURLE_OK; -#else - return CURLE_SSL_CONNECT_ERROR; -#endif - - case CURL_SSLVERSION_TLSv1_3: -#ifdef SSL_LIBRARY_VERSION_TLS_1_3 - *nssver = SSL_LIBRARY_VERSION_TLS_1_3; - return CURLE_OK; -#else - return CURLE_SSL_CONNECT_ERROR; -#endif - - default: - return CURLE_SSL_CONNECT_ERROR; - } -} - -static CURLcode nss_init_sslver(SSLVersionRange *sslver, - struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result; - const long min = SSL_CONN_CONFIG(version); - const long max = SSL_CONN_CONFIG(version_max); - - /* map CURL_SSLVERSION_DEFAULT to NSS default */ - if(min == CURL_SSLVERSION_DEFAULT || max == CURL_SSLVERSION_MAX_DEFAULT) { - /* map CURL_SSLVERSION_DEFAULT to NSS default */ - if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess) - return CURLE_SSL_CONNECT_ERROR; - /* ... but make sure we use at least TLSv1.0 according to libcurl API */ - if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0) - sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; - } - - switch(min) { - case CURL_SSLVERSION_DEFAULT: - break; - case CURL_SSLVERSION_TLSv1: - sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; - break; - default: - result = nss_sslver_from_curl(&sslver->min, min); - if(result) { - failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); - return result; - } - if(max == CURL_SSLVERSION_MAX_NONE) - sslver->max = sslver->min; - } - - switch(max) { - case CURL_SSLVERSION_MAX_NONE: - case CURL_SSLVERSION_MAX_DEFAULT: - break; - default: - result = nss_sslver_from_curl(&sslver->max, max >> 16); - if(result) { - failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); - return result; - } - } - - return CURLE_OK; -} - -static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, - struct Curl_easy *data, - CURLcode curlerr) -{ - PRErrorCode err = 0; - - if(is_nss_error(curlerr)) { - /* read NSPR error code */ - err = PR_GetError(); - if(is_cc_error(err)) - curlerr = CURLE_SSL_CERTPROBLEM; - - /* print the error number and error string */ - infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err)); - - /* print a human-readable message describing the error if available */ - nss_print_error_message(data, err); - } - - /* cleanup on connection failure */ - Curl_llist_destroy(&BACKEND->obj_list, NULL); - - return curlerr; -} - -/* Switch the SSL socket into blocking or non-blocking mode. */ -static CURLcode nss_set_blocking(struct ssl_connect_data *connssl, - struct Curl_easy *data, - bool blocking) -{ - static PRSocketOptionData sock_opt; - sock_opt.option = PR_SockOpt_Nonblocking; - sock_opt.value.non_blocking = !blocking; - - if(PR_SetSocketOption(BACKEND->handle, &sock_opt) != PR_SUCCESS) - return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); - - return CURLE_OK; -} - -static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) -{ - PRFileDesc *model = NULL; - PRFileDesc *nspr_io = NULL; - PRFileDesc *nspr_io_stub = NULL; - PRBool ssl_no_cache; - PRBool ssl_cbc_random_iv; - struct Curl_easy *data = conn->data; - curl_socket_t sockfd = conn->sock[sockindex]; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - CURLcode result; - bool second_layer = FALSE; - - SSLVersionRange sslver = { - SSL_LIBRARY_VERSION_TLS_1_0, /* min */ - SSL_LIBRARY_VERSION_TLS_1_0 /* max */ - }; - - BACKEND->data = data; - - /* list of all NSS objects we need to destroy in Curl_nss_close() */ - Curl_llist_init(&BACKEND->obj_list, nss_destroy_object); - - /* FIXME. NSS doesn't support multiple databases open at the same time. */ - PR_Lock(nss_initlock); - result = nss_init(conn->data); - if(result) { - PR_Unlock(nss_initlock); - goto error; - } - - PK11_SetPasswordFunc(nss_get_password); - - result = nss_load_module(&pem_module, pem_library, "PEM"); - PR_Unlock(nss_initlock); - if(result == CURLE_FAILED_INIT) - infof(data, "WARNING: failed to load NSS PEM library %s. Using " - "OpenSSL PEM certificates will not work.\n", pem_library); - else if(result) - goto error; - - result = CURLE_SSL_CONNECT_ERROR; - - model = PR_NewTCPSocket(); - if(!model) - goto error; - model = SSL_ImportFD(NULL, model); - - if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess) - goto error; - if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) - goto error; - if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) - goto error; - - /* do not use SSL cache if disabled or we are not going to verify peer */ - ssl_no_cache = (SSL_SET_OPTION(primary.sessionid) - && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE; - if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) - goto error; - - /* enable/disable the requested SSL version(s) */ - if(nss_init_sslver(&sslver, data, conn) != CURLE_OK) - goto error; - if(SSL_VersionRangeSet(model, &sslver) != SECSuccess) - goto error; - - ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast); -#ifdef SSL_CBC_RANDOM_IV - /* unless the user explicitly asks to allow the protocol vulnerability, we - use the work-around */ - if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess) - infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n", - ssl_cbc_random_iv); -#else - if(ssl_cbc_random_iv) - infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); -#endif - - if(SSL_CONN_CONFIG(cipher_list)) { - if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) { - result = CURLE_SSL_CIPHER; - goto error; - } - } - - if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost)) - infof(data, "warning: ignoring value of ssl.verifyhost\n"); - - /* bypass the default SSL_AuthCertificate() hook in case we do not want to - * verify peer */ - if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess) - goto error; - - /* not checked yet */ - if(SSL_IS_PROXY()) - data->set.proxy_ssl.certverifyresult = 0; - else - data->set.ssl.certverifyresult = 0; - - if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess) - goto error; - - if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess) - goto error; - - { - const CURLcode rv = nss_load_ca_certificates(conn, sockindex); - if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer)) - /* not a fatal error because we are not going to verify the peer */ - infof(data, "warning: CA certificates failed to load\n"); - else if(rv) { - result = rv; - goto error; - } - } - - if(SSL_SET_OPTION(CRLfile)) { - const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile)); - if(rv) { - result = rv; - goto error; - } - infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile)); - } - - if(SSL_SET_OPTION(cert)) { - char *nickname = dup_nickname(data, SSL_SET_OPTION(cert)); - if(nickname) { - /* we are not going to use libnsspem.so to read the client cert */ - BACKEND->obj_clicert = NULL; - } - else { - CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert), - SSL_SET_OPTION(key)); - if(rv) { - /* failf() is already done in cert_stuff() */ - result = rv; - goto error; - } - } - - /* store the nickname for SelectClientCert() called during handshake */ - BACKEND->client_nickname = nickname; - } - else - BACKEND->client_nickname = NULL; - - if(SSL_GetClientAuthDataHook(model, SelectClientCert, - (void *)connssl) != SECSuccess) { - result = CURLE_SSL_CERTPROBLEM; - goto error; - } - - if(conn->proxy_ssl[sockindex].use) { - DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); - DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL); - nspr_io = conn->proxy_ssl[sockindex].backend->handle; - second_layer = TRUE; - } - else { - /* wrap OS file descriptor by NSPR's file descriptor abstraction */ - nspr_io = PR_ImportTCPSocket(sockfd); - if(!nspr_io) - goto error; - } - - /* create our own NSPR I/O layer */ - nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods); - if(!nspr_io_stub) { - if(!second_layer) - PR_Close(nspr_io); - goto error; - } - - /* make the per-connection data accessible from NSPR I/O callbacks */ - nspr_io_stub->secret = (void *)connssl; - - /* push our new layer to the NSPR I/O stack */ - if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) { - if(!second_layer) - PR_Close(nspr_io); - PR_Close(nspr_io_stub); - goto error; - } - - /* import our model socket onto the current I/O stack */ - BACKEND->handle = SSL_ImportFD(model, nspr_io); - if(!BACKEND->handle) { - if(!second_layer) - PR_Close(nspr_io); - goto error; - } - - PR_Close(model); /* We don't need this any more */ - model = NULL; - - /* This is the password associated with the cert that we're using */ - if(SSL_SET_OPTION(key_passwd)) { - SSL_SetPKCS11PinArg(BACKEND->handle, SSL_SET_OPTION(key_passwd)); - } - -#ifdef SSL_ENABLE_OCSP_STAPLING - if(SSL_CONN_CONFIG(verifystatus)) { - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) - != SECSuccess) - goto error; - } -#endif - -#ifdef SSL_ENABLE_NPN - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn - ? PR_TRUE : PR_FALSE) != SECSuccess) - goto error; -#endif - -#ifdef SSL_ENABLE_ALPN - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn - ? PR_TRUE : PR_FALSE) != SECSuccess) - goto error; -#endif - -#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ - if(data->set.ssl.falsestart) { - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_FALSE_START, PR_TRUE) - != SECSuccess) - goto error; - - if(SSL_SetCanFalseStartCallback(BACKEND->handle, CanFalseStartCallback, - conn) != SECSuccess) - goto error; - } -#endif - -#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) - if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) { - int cur = 0; - unsigned char protocols[128]; - -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2 && - (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { - protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; - memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN); - cur += NGHTTP2_PROTO_VERSION_ID_LEN; - } -#endif - protocols[cur++] = ALPN_HTTP_1_1_LENGTH; - memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - cur += ALPN_HTTP_1_1_LENGTH; - - if(SSL_SetNextProtoNego(BACKEND->handle, protocols, cur) != SECSuccess) - goto error; - } -#endif - - - /* Force handshake on next I/O */ - if(SSL_ResetHandshake(BACKEND->handle, /* asServer */ PR_FALSE) - != SECSuccess) - goto error; - - /* propagate hostname to the TLS layer */ - if(SSL_SetURL(BACKEND->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name) != SECSuccess) - goto error; - - /* prevent NSS from re-using the session for a different hostname */ - if(SSL_SetSockPeerID(BACKEND->handle, SSL_IS_PROXY() ? - conn->http_proxy.host.name : conn->host.name) - != SECSuccess) - goto error; - - return CURLE_OK; - -error: - if(model) - PR_Close(model); - - return nss_fail_connect(connssl, data, result); -} - -static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - CURLcode result = CURLE_SSL_CONNECT_ERROR; - PRUint32 timeout; - long * const certverifyresult = SSL_IS_PROXY() ? - &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; - const char * const pinnedpubkey = SSL_IS_PROXY() ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - - - /* check timeout situation */ - const time_t time_left = Curl_timeleft(data, NULL, TRUE); - if(time_left < 0) { - failf(data, "timed out before SSL handshake"); - result = CURLE_OPERATION_TIMEDOUT; - goto error; - } - - /* Force the handshake now */ - timeout = PR_MillisecondsToInterval((PRUint32) time_left); - if(SSL_ForceHandshakeWithTimeout(BACKEND->handle, timeout) != SECSuccess) { - if(PR_GetError() == PR_WOULD_BLOCK_ERROR) - /* blocking direction is updated by nss_update_connecting_state() */ - return CURLE_AGAIN; - else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) - result = CURLE_PEER_FAILED_VERIFICATION; - else if(*certverifyresult != 0) - result = CURLE_SSL_CACERT; - goto error; - } - - result = display_conn_info(conn, BACKEND->handle); - if(result) - goto error; - - if(SSL_SET_OPTION(issuercert)) { - SECStatus ret = SECFailure; - char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); - if(nickname) { - /* we support only nicknames in case of issuercert for now */ - ret = check_issuer_cert(BACKEND->handle, nickname); - free(nickname); - } - - if(SECFailure == ret) { - infof(data, "SSL certificate issuer check failed\n"); - result = CURLE_SSL_ISSUER_ERROR; - goto error; - } - else { - infof(data, "SSL certificate issuer check ok\n"); - } - } - - result = cmp_peer_pubkey(connssl, pinnedpubkey); - if(result) - /* status already printed */ - goto error; - - return CURLE_OK; - -error: - return nss_fail_connect(connssl, data, result); -} - -static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, - bool *done) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - const bool blocking = (done == NULL); - CURLcode result; - - if(connssl->state == ssl_connection_complete) { - if(!blocking) - *done = TRUE; - return CURLE_OK; - } - - if(connssl->connecting_state == ssl_connect_1) { - result = nss_setup_connect(conn, sockindex); - if(result) - /* we do not expect CURLE_AGAIN from nss_setup_connect() */ - return result; - - connssl->connecting_state = ssl_connect_2; - } - - /* enable/disable blocking mode before handshake */ - result = nss_set_blocking(connssl, data, blocking); - if(result) - return result; - - result = nss_do_connect(conn, sockindex); - switch(result) { - case CURLE_OK: - break; - case CURLE_AGAIN: - if(!blocking) - /* CURLE_AGAIN in non-blocking mode is not an error */ - return CURLE_OK; - /* fall through */ - default: - return result; - } - - if(blocking) { - /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */ - result = nss_set_blocking(connssl, data, /* blocking */ FALSE); - if(result) - return result; - } - else - /* signal completed SSL handshake */ - *done = TRUE; - - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = nss_recv; - conn->send[sockindex] = nss_send; - - /* ssl_connect_done is never used outside, go back to the initial state */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) -{ - return nss_connect_common(conn, sockindex, /* blocking */ NULL); -} - -static CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - return nss_connect_common(conn, sockindex, done); -} - -static ssize_t nss_send(struct connectdata *conn, /* connection data */ - int sockindex, /* socketindex */ - const void *mem, /* send this data */ - size_t len, /* amount to write */ - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - ssize_t rc; - - /* The SelectClientCert() hook uses this for infof() and failf() but the - handle stored in nss_setup_connect() could have already been freed. */ - BACKEND->data = conn->data; - - rc = PR_Send(BACKEND->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT); - if(rc < 0) { - PRInt32 err = PR_GetError(); - if(err == PR_WOULD_BLOCK_ERROR) - *curlcode = CURLE_AGAIN; - else { - /* print the error number and error string */ - const char *err_name = nss_error_to_name(err); - infof(conn->data, "SSL write: error %d (%s)\n", err, err_name); - - /* print a human-readable message describing the error if available */ - nss_print_error_message(conn->data, err); - - *curlcode = (is_cc_error(err)) - ? CURLE_SSL_CERTPROBLEM - : CURLE_SEND_ERROR; - } - - return -1; - } - - return rc; /* number of bytes */ -} - -static ssize_t nss_recv(struct connectdata *conn, /* connection data */ - int sockindex, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - ssize_t nread; - - /* The SelectClientCert() hook uses this for infof() and failf() but the - handle stored in nss_setup_connect() could have already been freed. */ - BACKEND->data = conn->data; - - nread = PR_Recv(BACKEND->handle, buf, (int)buffersize, 0, - PR_INTERVAL_NO_WAIT); - if(nread < 0) { - /* failed SSL read */ - PRInt32 err = PR_GetError(); - - if(err == PR_WOULD_BLOCK_ERROR) - *curlcode = CURLE_AGAIN; - else { - /* print the error number and error string */ - const char *err_name = nss_error_to_name(err); - infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name); - - /* print a human-readable message describing the error if available */ - nss_print_error_message(conn->data, err); - - *curlcode = (is_cc_error(err)) - ? CURLE_SSL_CERTPROBLEM - : CURLE_RECV_ERROR; - } - - return -1; - } - - return nread; -} - -static size_t Curl_nss_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, "NSS/%s", NSS_VERSION); -} - -/* data might be NULL */ -static int Curl_nss_seed(struct Curl_easy *data) -{ - /* make sure that NSS is initialized */ - return !!Curl_nss_force_init(data); -} - -/* data might be NULL */ -static CURLcode Curl_nss_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) -{ - Curl_nss_seed(data); /* Initiate the seed if not already done */ - - if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) - /* signal a failure */ - return CURLE_FAILED_INIT; - - return CURLE_OK; -} - -static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len) -{ - PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); - unsigned int MD5out; - - PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen)); - PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len)); - PK11_DestroyContext(MD5pw, PR_TRUE); - - return CURLE_OK; -} - -static void Curl_nss_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len) -{ - PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256); - unsigned int SHA256out; - - PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen)); - PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len)); - PK11_DestroyContext(SHA256pw, PR_TRUE); -} - -static bool Curl_nss_cert_status_request(void) -{ -#ifdef SSL_ENABLE_OCSP_STAPLING - return TRUE; -#else - return FALSE; -#endif -} - -static bool Curl_nss_false_start(void) -{ -#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ - return TRUE; -#else - return FALSE; -#endif -} - -static void *Curl_nss_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return BACKEND->handle; -} - -const struct Curl_ssl Curl_ssl_nss = { - { CURLSSLBACKEND_NSS, "nss" }, /* info */ - - 1, /* have_ca_path */ - 1, /* have_certinfo */ - 1, /* have_pinnedpubkey */ - 0, /* have_ssl_ctx */ - 1, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_nss_init, /* init */ - Curl_nss_cleanup, /* cleanup */ - Curl_nss_version, /* version */ - Curl_nss_check_cxn, /* check_cxn */ - /* NSS has no shutdown function provided and thus always fail */ - Curl_none_shutdown, /* shutdown */ - Curl_none_data_pending, /* data_pending */ - Curl_nss_random, /* random */ - Curl_nss_cert_status_request, /* cert_status_request */ - Curl_nss_connect, /* connect */ - Curl_nss_connect_nonblocking, /* connect_nonblocking */ - Curl_nss_get_internals, /* get_internals */ - Curl_nss_close, /* close */ - Curl_none_close_all, /* close_all */ - /* NSS has its own session ID cache */ - Curl_none_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_nss_false_start, /* false_start */ - Curl_nss_md5sum, /* md5sum */ - Curl_nss_sha256sum /* sha256sum */ -}; - -#endif /* USE_NSS */ diff --git a/dep/cpr/opt/curl/lib/vtls/nssg.h b/dep/cpr/opt/curl/lib/vtls/nssg.h deleted file mode 100644 index 41e51b021da..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/nssg.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef HEADER_CURL_NSSG_H -#define HEADER_CURL_NSSG_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifdef USE_NSS -/* - * This header should only be needed to get included by vtls.c and nss.c - */ - -#include "urldata.h" - -/* initialize NSS library if not already */ -CURLcode Curl_nss_force_init(struct Curl_easy *data); - -extern const struct Curl_ssl Curl_ssl_nss; - -#endif /* USE_NSS */ -#endif /* HEADER_CURL_NSSG_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/openssl.c b/dep/cpr/opt/curl/lib/vtls/openssl.c deleted file mode 100644 index 4253160aa72..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/openssl.c +++ /dev/null @@ -1,3654 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - */ - -/* - * The original SSLeay-using code for curl was written by Linas Vepstas and - * Sampo Kellomaki 1998. - */ - -#include "curl_setup.h" - -#ifdef USE_OPENSSL - -#ifdef HAVE_LIMITS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "formdata.h" /* for the boundary function */ -#include "url.h" /* for the ssl config check function */ -#include "inet_pton.h" -#include "openssl.h" -#include "connect.h" -#include "slist.h" -#include "select.h" -#include "vtls.h" -#include "strcase.h" -#include "hostcheck.h" -#include "curl_printf.h" -#include -#ifdef HAVE_OPENSSL_ENGINE_H -#include -#endif -#include -#include -#ifndef OPENSSL_NO_DSA -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_OPENSSL_PKCS12_H -#include -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) -#include -#endif - -#include "warnless.h" -#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */ - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -#ifndef OPENSSL_VERSION_NUMBER -#error "OPENSSL_VERSION_NUMBER not defined" -#endif - -#if defined(HAVE_OPENSSL_ENGINE_H) -#include -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00909000L -#define SSL_METHOD_QUAL const -#else -#define SSL_METHOD_QUAL -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) -#define HAVE_ERR_REMOVE_THREAD_STATE 1 -#endif - -#if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ - OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */ -#undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */ -#define OPENSSL_NO_SSL2 -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ - !defined(LIBRESSL_VERSION_NUMBER) -#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER -#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ -#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ -#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ -#define CONST_EXTS const -#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 -#else -/* For OpenSSL before 1.1.0 */ -#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) -#define X509_get0_notBefore(x) X509_get_notBefore(x) -#define X509_get0_notAfter(x) X509_get_notAfter(x) -#define CONST_EXTS /* nope */ -#ifdef LIBRESSL_VERSION_NUMBER -static unsigned long OpenSSL_version_num(void) -{ - return LIBRESSL_VERSION_NUMBER; -} -#else -#define OpenSSL_version_num() SSLeay() -#endif -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ - !defined(LIBRESSL_VERSION_NUMBER) -#define HAVE_X509_GET0_SIGNATURE 1 -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \ - OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \ - !defined(OPENSSL_NO_COMP) -#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1 -#endif - -#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) -/* not present in older OpenSSL */ -#define OPENSSL_load_builtin_modules(x) -#endif - -/* - * Whether SSL_CTX_set_keylog_callback is available. - * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 - * BoringSSL: supported since d28f59c27bac (committed 2015-11-19), the - * BORINGSSL_201512 macro from 2016-01-21 should be close enough. - * LibreSSL: unsupported in at least 2.5.1 (explicitly check for it since it - * lies and pretends to be OpenSSL 2.0.0). - */ -#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ - !defined(LIBRESSL_VERSION_NUMBER)) || \ - defined(BORINGSSL_201512) -#define HAVE_KEYLOG_CALLBACK -#endif - -#if defined(LIBRESSL_VERSION_NUMBER) -#define OSSL_PACKAGE "LibreSSL" -#elif defined(OPENSSL_IS_BORINGSSL) -#define OSSL_PACKAGE "BoringSSL" -#else -#define OSSL_PACKAGE "OpenSSL" -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) -/* up2date versions of OpenSSL maintain the default reasonably secure without - * breaking compatibility, so it is better not to override the default by curl - */ -#define DEFAULT_CIPHER_SELECTION NULL -#else -/* ... but it is not the case with old versions of OpenSSL */ -#define DEFAULT_CIPHER_SELECTION \ - "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" -#endif - -#ifdef ENABLE_SSLKEYLOGFILE -typedef struct ssl_tap_state { - int master_key_length; - unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; - unsigned char client_random[SSL3_RANDOM_SIZE]; -} ssl_tap_state_t; -#endif /* ENABLE_SSLKEYLOGFILE */ - -struct ssl_backend_data { - /* these ones requires specific SSL-types */ - SSL_CTX* ctx; - SSL* handle; - X509* server_cert; -#ifdef ENABLE_SSLKEYLOGFILE - /* tap_state holds the last seen master key if we're logging them */ - ssl_tap_state_t tap_state; -#endif -}; - -#define BACKEND connssl->backend - -/* - * Number of bytes to read from the random number seed file. This must be - * a finite value (because some entropy "files" like /dev/urandom have - * an infinite length), but must be large enough to provide enough - * entropy to properly seed OpenSSL's PRNG. - */ -#define RAND_LOAD_LENGTH 1024 - -#ifdef ENABLE_SSLKEYLOGFILE -/* The fp for the open SSLKEYLOGFILE, or NULL if not open */ -static FILE *keylog_file_fp; - -#ifdef HAVE_KEYLOG_CALLBACK -static void ossl_keylog_callback(const SSL *ssl, const char *line) -{ - (void)ssl; - - /* Using fputs here instead of fprintf since libcurl's fprintf replacement - may not be thread-safe. */ - if(keylog_file_fp && line && *line) { - char stackbuf[256]; - char *buf; - size_t linelen = strlen(line); - - if(linelen <= sizeof(stackbuf) - 2) - buf = stackbuf; - else { - buf = malloc(linelen + 2); - if(!buf) - return; - } - strncpy(buf, line, linelen); - buf[linelen] = '\n'; - buf[linelen + 1] = '\0'; - - fputs(buf, keylog_file_fp); - if(buf != stackbuf) - free(buf); - } -} -#else -#define KEYLOG_PREFIX "CLIENT_RANDOM " -#define KEYLOG_PREFIX_LEN (sizeof(KEYLOG_PREFIX) - 1) -/* - * tap_ssl_key is called by libcurl to make the CLIENT_RANDOMs if the OpenSSL - * being used doesn't have native support for doing that. - */ -static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state) -{ - const char *hex = "0123456789ABCDEF"; - int pos, i; - char line[KEYLOG_PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 + - 2 * SSL_MAX_MASTER_KEY_LENGTH + 1 + 1]; - const SSL_SESSION *session = SSL_get_session(ssl); - unsigned char client_random[SSL3_RANDOM_SIZE]; - unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; - int master_key_length = 0; - - if(!session || !keylog_file_fp) - return; - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that - * we have a valid SSL context if we have a non-NULL session. */ - SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE); - master_key_length = - SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH); -#else - if(ssl->s3 && session->master_key_length > 0) { - master_key_length = session->master_key_length; - memcpy(master_key, session->master_key, session->master_key_length); - memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE); - } -#endif - - if(master_key_length <= 0) - return; - - /* Skip writing keys if there is no key or it did not change. */ - if(state->master_key_length == master_key_length && - !memcmp(state->master_key, master_key, master_key_length) && - !memcmp(state->client_random, client_random, SSL3_RANDOM_SIZE)) { - return; - } - - state->master_key_length = master_key_length; - memcpy(state->master_key, master_key, master_key_length); - memcpy(state->client_random, client_random, SSL3_RANDOM_SIZE); - - memcpy(line, KEYLOG_PREFIX, KEYLOG_PREFIX_LEN); - pos = KEYLOG_PREFIX_LEN; - - /* Client Random for SSLv3/TLS */ - for(i = 0; i < SSL3_RANDOM_SIZE; i++) { - line[pos++] = hex[client_random[i] >> 4]; - line[pos++] = hex[client_random[i] & 0xF]; - } - line[pos++] = ' '; - - /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */ - for(i = 0; i < master_key_length; i++) { - line[pos++] = hex[master_key[i] >> 4]; - line[pos++] = hex[master_key[i] & 0xF]; - } - line[pos++] = '\n'; - line[pos] = '\0'; - - /* Using fputs here instead of fprintf since libcurl's fprintf replacement - may not be thread-safe. */ - fputs(line, keylog_file_fp); -} -#endif /* !HAVE_KEYLOG_CALLBACK */ -#endif /* ENABLE_SSLKEYLOGFILE */ - -static const char *SSL_ERROR_to_str(int err) -{ - switch(err) { - case SSL_ERROR_NONE: - return "SSL_ERROR_NONE"; - case SSL_ERROR_SSL: - return "SSL_ERROR_SSL"; - case SSL_ERROR_WANT_READ: - return "SSL_ERROR_WANT_READ"; - case SSL_ERROR_WANT_WRITE: - return "SSL_ERROR_WANT_WRITE"; - case SSL_ERROR_WANT_X509_LOOKUP: - return "SSL_ERROR_WANT_X509_LOOKUP"; - case SSL_ERROR_SYSCALL: - return "SSL_ERROR_SYSCALL"; - case SSL_ERROR_ZERO_RETURN: - return "SSL_ERROR_ZERO_RETURN"; - case SSL_ERROR_WANT_CONNECT: - return "SSL_ERROR_WANT_CONNECT"; - case SSL_ERROR_WANT_ACCEPT: - return "SSL_ERROR_WANT_ACCEPT"; -#if defined(SSL_ERROR_WANT_ASYNC) - case SSL_ERROR_WANT_ASYNC: - return "SSL_ERROR_WANT_ASYNC"; -#endif -#if defined(SSL_ERROR_WANT_ASYNC_JOB) - case SSL_ERROR_WANT_ASYNC_JOB: - return "SSL_ERROR_WANT_ASYNC_JOB"; -#endif -#if defined(SSL_ERROR_WANT_EARLY) - case SSL_ERROR_WANT_EARLY: - return "SSL_ERROR_WANT_EARLY"; -#endif - default: - return "SSL_ERROR unknown"; - } -} - -/* Return error string for last OpenSSL error - */ -static char *ossl_strerror(unsigned long error, char *buf, size_t size) -{ - ERR_error_string_n(error, buf, size); - return buf; -} - -static int passwd_callback(char *buf, int num, int encrypting, - void *global_passwd) -{ - DEBUGASSERT(0 == encrypting); - - if(!encrypting) { - int klen = curlx_uztosi(strlen((char *)global_passwd)); - if(num > klen) { - memcpy(buf, global_passwd, klen + 1); - return klen; - } - } - return 0; -} - -/* - * rand_enough() returns TRUE if we have seeded the random engine properly. - */ -static bool rand_enough(void) -{ - return (0 != RAND_status()) ? TRUE : FALSE; -} - -static CURLcode Curl_ossl_seed(struct Curl_easy *data) -{ - /* we have the "SSL is seeded" boolean static to prevent multiple - time-consuming seedings in vain */ - static bool ssl_seeded = FALSE; - char fname[256]; - - if(ssl_seeded) - return CURLE_OK; - - if(rand_enough()) { - /* OpenSSL 1.1.0+ will return here */ - ssl_seeded = TRUE; - return CURLE_OK; - } - -#ifndef RANDOM_FILE - /* if RANDOM_FILE isn't defined, we only perform this if an option tells - us to! */ - if(data->set.str[STRING_SSL_RANDOM_FILE]) -#define RANDOM_FILE "" /* doesn't matter won't be used */ -#endif - { - /* let the option override the define */ - RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]? - data->set.str[STRING_SSL_RANDOM_FILE]: - RANDOM_FILE), - RAND_LOAD_LENGTH); - if(rand_enough()) - return CURLE_OK; - } - -#if defined(HAVE_RAND_EGD) - /* only available in OpenSSL 0.9.5 and later */ - /* EGD_SOCKET is set at configure time or not at all */ -#ifndef EGD_SOCKET - /* If we don't have the define set, we only do this if the egd-option - is set */ - if(data->set.str[STRING_SSL_EGDSOCKET]) -#define EGD_SOCKET "" /* doesn't matter won't be used */ -#endif - { - /* If there's an option and a define, the option overrides the - define */ - int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]? - data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET); - if(-1 != ret) { - if(rand_enough()) - return CURLE_OK; - } - } -#endif - - /* fallback to a custom seeding of the PRNG using a hash based on a current - time */ - do { - unsigned char randb[64]; - size_t len = sizeof(randb); - size_t i, i_max; - for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) { - struct curltime tv = curlx_tvnow(); - Curl_wait_ms(1); - tv.tv_sec *= i + 1; - tv.tv_usec *= (unsigned int)i + 2; - tv.tv_sec ^= ((curlx_tvnow().tv_sec + curlx_tvnow().tv_usec) * - (i + 3)) << 8; - tv.tv_usec ^= (unsigned int) ((curlx_tvnow().tv_sec + - curlx_tvnow().tv_usec) * - (i + 4)) << 16; - memcpy(&randb[i * sizeof(struct curltime)], &tv, - sizeof(struct curltime)); - } - RAND_add(randb, (int)len, (double)len/2); - } while(!rand_enough()); - - /* generates a default path for the random seed file */ - fname[0] = 0; /* blank it first */ - RAND_file_name(fname, sizeof(fname)); - if(fname[0]) { - /* we got a file name to try */ - RAND_load_file(fname, RAND_LOAD_LENGTH); - if(rand_enough()) - return CURLE_OK; - } - - infof(data, "libcurl is now using a weak random seed!\n"); - return (rand_enough() ? CURLE_OK : - CURLE_SSL_CONNECT_ERROR /* confusing error code */); -} - -#ifndef SSL_FILETYPE_ENGINE -#define SSL_FILETYPE_ENGINE 42 -#endif -#ifndef SSL_FILETYPE_PKCS12 -#define SSL_FILETYPE_PKCS12 43 -#endif -static int do_file_type(const char *type) -{ - if(!type || !type[0]) - return SSL_FILETYPE_PEM; - if(strcasecompare(type, "PEM")) - return SSL_FILETYPE_PEM; - if(strcasecompare(type, "DER")) - return SSL_FILETYPE_ASN1; - if(strcasecompare(type, "ENG")) - return SSL_FILETYPE_ENGINE; - if(strcasecompare(type, "P12")) - return SSL_FILETYPE_PKCS12; - return -1; -} - -#if defined(HAVE_OPENSSL_ENGINE_H) -/* - * Supply default password to the engine user interface conversation. - * The password is passed by OpenSSL engine from ENGINE_load_private_key() - * last argument to the ui and can be obtained by UI_get0_user_data(ui) here. - */ -static int ssl_ui_reader(UI *ui, UI_STRING *uis) -{ - const char *password; - switch(UI_get_string_type(uis)) { - case UIT_PROMPT: - case UIT_VERIFY: - password = (const char *)UI_get0_user_data(ui); - if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { - UI_set_result(ui, uis, password); - return 1; - } - default: - break; - } - return (UI_method_get_reader(UI_OpenSSL()))(ui, uis); -} - -/* - * Suppress interactive request for a default password if available. - */ -static int ssl_ui_writer(UI *ui, UI_STRING *uis) -{ - switch(UI_get_string_type(uis)) { - case UIT_PROMPT: - case UIT_VERIFY: - if(UI_get0_user_data(ui) && - (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { - return 1; - } - default: - break; - } - return (UI_method_get_writer(UI_OpenSSL()))(ui, uis); -} -#endif - -static -int cert_stuff(struct connectdata *conn, - SSL_CTX* ctx, - char *cert_file, - const char *cert_type, - char *key_file, - const char *key_type, - char *key_passwd) -{ - struct Curl_easy *data = conn->data; - char error_buffer[256]; - bool check_privkey = TRUE; - - int file_type = do_file_type(cert_type); - - if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) { - SSL *ssl; - X509 *x509; - int cert_done = 0; - - if(key_passwd) { - /* set the password in the callback userdata */ - SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd); - /* Set passwd callback: */ - SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); - } - - - switch(file_type) { - case SSL_FILETYPE_PEM: - /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ - if(SSL_CTX_use_certificate_chain_file(ctx, - cert_file) != 1) { - failf(data, - "could not load PEM client certificate, " OSSL_PACKAGE - " error %s, " - "(no key found, wrong pass phrase, or wrong file format?)", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - return 0; - } - break; - - case SSL_FILETYPE_ASN1: - /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but - we use the case above for PEM so this can only be performed with - ASN1 files. */ - if(SSL_CTX_use_certificate_file(ctx, - cert_file, - file_type) != 1) { - failf(data, - "could not load ASN1 client certificate, " OSSL_PACKAGE - " error %s, " - "(no key found, wrong pass phrase, or wrong file format?)", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - return 0; - } - break; - case SSL_FILETYPE_ENGINE: -#if defined(HAVE_OPENSSL_ENGINE_H) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME) - { - if(data->state.engine) { - const char *cmd_name = "LOAD_CERT_CTRL"; - struct { - const char *cert_id; - X509 *cert; - } params; - - params.cert_id = cert_file; - params.cert = NULL; - - /* Does the engine supports LOAD_CERT_CTRL ? */ - if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME, - 0, (void *)cmd_name, NULL)) { - failf(data, "ssl engine does not support loading certificates"); - return 0; - } - - /* Load the certificate from the engine */ - if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name, - 0, ¶ms, NULL, 1)) { - failf(data, "ssl engine cannot load client cert with id" - " '%s' [%s]", cert_file, - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - - if(!params.cert) { - failf(data, "ssl engine didn't initialized the certificate " - "properly."); - return 0; - } - - if(SSL_CTX_use_certificate(ctx, params.cert) != 1) { - failf(data, "unable to set client certificate"); - X509_free(params.cert); - return 0; - } - X509_free(params.cert); /* we don't need the handle any more... */ - } - else { - failf(data, "crypto engine not set, can't load certificate"); - return 0; - } - } - break; -#else - failf(data, "file type ENG for certificate not implemented"); - return 0; -#endif - - case SSL_FILETYPE_PKCS12: - { -#ifdef HAVE_OPENSSL_PKCS12_H - FILE *f; - PKCS12 *p12; - EVP_PKEY *pri; - STACK_OF(X509) *ca = NULL; - - f = fopen(cert_file, "rb"); - if(!f) { - failf(data, "could not open PKCS12 file '%s'", cert_file); - return 0; - } - p12 = d2i_PKCS12_fp(f, NULL); - fclose(f); - - if(!p12) { - failf(data, "error reading PKCS12 file '%s'", cert_file); - return 0; - } - - PKCS12_PBE_add(); - - if(!PKCS12_parse(p12, key_passwd, &pri, &x509, - &ca)) { - failf(data, - "could not parse PKCS12 file, check password, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - PKCS12_free(p12); - return 0; - } - - PKCS12_free(p12); - - if(SSL_CTX_use_certificate(ctx, x509) != 1) { - failf(data, - "could not load PKCS12 client certificate, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - goto fail; - } - - if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { - failf(data, "unable to use private key from PKCS12 file '%s'", - cert_file); - goto fail; - } - - if(!SSL_CTX_check_private_key (ctx)) { - failf(data, "private key from PKCS12 file '%s' " - "does not match certificate in same file", cert_file); - goto fail; - } - /* Set Certificate Verification chain */ - if(ca) { - while(sk_X509_num(ca)) { - /* - * Note that sk_X509_pop() is used below to make sure the cert is - * removed from the stack properly before getting passed to - * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously - * we used sk_X509_value() instead, but then we'd clean it in the - * subsequent sk_X509_pop_free() call. - */ - X509 *x = sk_X509_pop(ca); - if(!SSL_CTX_add_client_CA(ctx, x)) { - X509_free(x); - failf(data, "cannot add certificate to client CA list"); - goto fail; - } - if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { - X509_free(x); - failf(data, "cannot add certificate to certificate chain"); - goto fail; - } - } - } - - cert_done = 1; - fail: - EVP_PKEY_free(pri); - X509_free(x509); - sk_X509_pop_free(ca, X509_free); - - if(!cert_done) - return 0; /* failure! */ - break; -#else - failf(data, "file type P12 for certificate not supported"); - return 0; -#endif - } - default: - failf(data, "not supported file type '%s' for certificate", cert_type); - return 0; - } - - file_type = do_file_type(key_type); - - switch(file_type) { - case SSL_FILETYPE_PEM: - if(cert_done) - break; - if(!key_file) - /* cert & key can only be in PEM case in the same file */ - key_file = cert_file; - /* FALLTHROUGH */ - case SSL_FILETYPE_ASN1: - if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { - failf(data, "unable to set private key file: '%s' type %s", - key_file, key_type?key_type:"PEM"); - return 0; - } - break; - case SSL_FILETYPE_ENGINE: -#ifdef HAVE_OPENSSL_ENGINE_H - { /* XXXX still needs some work */ - EVP_PKEY *priv_key = NULL; - if(data->state.engine) { - UI_METHOD *ui_method = - UI_create_method((char *)"curl user interface"); - if(!ui_method) { - failf(data, "unable do create " OSSL_PACKAGE - " user-interface method"); - return 0; - } - UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); - UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); - UI_method_set_reader(ui_method, ssl_ui_reader); - UI_method_set_writer(ui_method, ssl_ui_writer); - /* the typecast below was added to please mingw32 */ - priv_key = (EVP_PKEY *) - ENGINE_load_private_key(data->state.engine, key_file, - ui_method, - key_passwd); - UI_destroy_method(ui_method); - if(!priv_key) { - failf(data, "failed to load private key from crypto engine"); - return 0; - } - if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { - failf(data, "unable to set private key"); - EVP_PKEY_free(priv_key); - return 0; - } - EVP_PKEY_free(priv_key); /* we don't need the handle any more... */ - } - else { - failf(data, "crypto engine not set, can't load private key"); - return 0; - } - } - break; -#else - failf(data, "file type ENG for private key not supported"); - return 0; -#endif - case SSL_FILETYPE_PKCS12: - if(!cert_done) { - failf(data, "file type P12 for private key not supported"); - return 0; - } - break; - default: - failf(data, "not supported file type for private key"); - return 0; - } - - ssl = SSL_new(ctx); - if(!ssl) { - failf(data, "unable to create an SSL structure"); - return 0; - } - - x509 = SSL_get_certificate(ssl); - - /* This version was provided by Evan Jordan and is supposed to not - leak memory as the previous version: */ - if(x509) { - EVP_PKEY *pktmp = X509_get_pubkey(x509); - EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl)); - EVP_PKEY_free(pktmp); - } - -#ifndef OPENSSL_NO_RSA - { - /* If RSA is used, don't check the private key if its flags indicate - * it doesn't support it. */ - EVP_PKEY *priv_key = SSL_get_privatekey(ssl); - if(EVP_PKEY_id(priv_key) == EVP_PKEY_RSA) { - RSA *rsa = EVP_PKEY_get1_RSA(priv_key); - if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK) - check_privkey = FALSE; - RSA_free(rsa); /* Decrement reference count */ - } - } -#endif - - SSL_free(ssl); - - /* If we are using DSA, we can copy the parameters from - * the private key */ - - if(check_privkey == TRUE) { - /* Now we know that a key and cert have been set against - * the SSL context */ - if(!SSL_CTX_check_private_key(ctx)) { - failf(data, "Private key does not match the certificate public key"); - return 0; - } - } - } - return 1; -} - -/* returns non-zero on failure */ -static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) -{ -#if 0 - return X509_NAME_oneline(a, buf, size); -#else - BIO *bio_out = BIO_new(BIO_s_mem()); - BUF_MEM *biomem; - int rc; - - if(!bio_out) - return 1; /* alloc failed! */ - - rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC); - BIO_get_mem_ptr(bio_out, &biomem); - - if((size_t)biomem->length < size) - size = biomem->length; - else - size--; /* don't overwrite the buffer end */ - - memcpy(buf, biomem->data, size); - buf[size] = 0; - - BIO_free(bio_out); - - return !rc; -#endif -} - -/** - * Global SSL init - * - * @retval 0 error initializing SSL - * @retval 1 SSL initialized successfully - */ -static int Curl_ossl_init(void) -{ -#ifdef ENABLE_SSLKEYLOGFILE - const char *keylog_file_name; -#endif - - OPENSSL_load_builtin_modules(); - -#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES - ENGINE_load_builtin_engines(); -#endif - - /* OPENSSL_config(NULL); is "strongly recommended" to use but unfortunately - that function makes an exit() call on wrongly formatted config files - which makes it hard to use in some situations. OPENSSL_config() itself - calls CONF_modules_load_file() and we use that instead and we ignore - its return code! */ - - /* CONF_MFLAGS_DEFAULT_SECTION introduced some time between 0.9.8b and - 0.9.8e */ -#ifndef CONF_MFLAGS_DEFAULT_SECTION -#define CONF_MFLAGS_DEFAULT_SECTION 0x0 -#endif - - CONF_modules_load_file(NULL, NULL, - CONF_MFLAGS_DEFAULT_SECTION| - CONF_MFLAGS_IGNORE_MISSING_FILE); - -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(LIBRESSL_VERSION_NUMBER) - /* OpenSSL 1.1.0+ takes care of initialization itself */ -#else - /* Lets get nice error messages */ - SSL_load_error_strings(); - - /* Init the global ciphers and digests */ - if(!SSLeay_add_ssl_algorithms()) - return 0; - - OpenSSL_add_all_algorithms(); -#endif - -#ifdef ENABLE_SSLKEYLOGFILE - keylog_file_name = curl_getenv("SSLKEYLOGFILE"); - if(keylog_file_name && !keylog_file_fp) { - keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); - if(keylog_file_fp) { - if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) { - fclose(keylog_file_fp); - keylog_file_fp = NULL; - } - } - } -#endif - - return 1; -} - -/* Global cleanup */ -static void Curl_ossl_cleanup(void) -{ -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(LIBRESSL_VERSION_NUMBER) - /* OpenSSL 1.1 deprecates all these cleanup functions and - turns them into no-ops in OpenSSL 1.0 compatibility mode */ -#else - /* Free ciphers and digests lists */ - EVP_cleanup(); - -#ifdef HAVE_ENGINE_CLEANUP - /* Free engine list */ - ENGINE_cleanup(); -#endif - - /* Free OpenSSL error strings */ - ERR_free_strings(); - - /* Free thread local error state, destroying hash upon zero refcount */ -#ifdef HAVE_ERR_REMOVE_THREAD_STATE - ERR_remove_thread_state(NULL); -#else - ERR_remove_state(0); -#endif - - /* Free all memory allocated by all configuration modules */ - CONF_modules_free(); - -#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS - SSL_COMP_free_compression_methods(); -#endif -#endif - -#ifdef ENABLE_SSLKEYLOGFILE - if(keylog_file_fp) { - fclose(keylog_file_fp); - keylog_file_fp = NULL; - } -#endif -} - -/* - * This function is used to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int Curl_ossl_check_cxn(struct connectdata *conn) -{ - /* SSL_peek takes data out of the raw recv buffer without peeking so we use - recv MSG_PEEK instead. Bug #795 */ -#ifdef MSG_PEEK - char buf; - ssize_t nread; - nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, - (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK); - if(nread == 0) - return 0; /* connection has been closed */ - if(nread == 1) - return 1; /* connection still in place */ - else if(nread == -1) { - int err = SOCKERRNO; - if(err == EINPROGRESS || -#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK) - err == EAGAIN || -#endif - err == EWOULDBLOCK) - return 1; /* connection still in place */ - if(err == ECONNRESET || -#ifdef ECONNABORTED - err == ECONNABORTED || -#endif -#ifdef ENETDOWN - err == ENETDOWN || -#endif -#ifdef ENETRESET - err == ENETRESET || -#endif -#ifdef ESHUTDOWN - err == ESHUTDOWN || -#endif -#ifdef ETIMEDOUT - err == ETIMEDOUT || -#endif - err == ENOTCONN) - return 0; /* connection has been closed */ - } -#endif - return -1; /* connection status unknown */ -} - -/* Selects an OpenSSL crypto engine - */ -static CURLcode Curl_ossl_set_engine(struct Curl_easy *data, - const char *engine) -{ -#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) - ENGINE *e; - -#if OPENSSL_VERSION_NUMBER >= 0x00909000L - e = ENGINE_by_id(engine); -#else - /* avoid memory leak */ - for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { - const char *e_id = ENGINE_get_id(e); - if(!strcmp(engine, e_id)) - break; - } -#endif - - if(!e) { - failf(data, "SSL Engine '%s' not found", engine); - return CURLE_SSL_ENGINE_NOTFOUND; - } - - if(data->state.engine) { - ENGINE_finish(data->state.engine); - ENGINE_free(data->state.engine); - data->state.engine = NULL; - } - if(!ENGINE_init(e)) { - char buf[256]; - - ENGINE_free(e); - failf(data, "Failed to initialise SSL Engine '%s':\n%s", - engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf))); - return CURLE_SSL_ENGINE_INITFAILED; - } - data->state.engine = e; - return CURLE_OK; -#else - (void)engine; - failf(data, "SSL Engine not supported"); - return CURLE_SSL_ENGINE_NOTFOUND; -#endif -} - -/* Sets engine as default for all SSL operations - */ -static CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) -{ -#ifdef HAVE_OPENSSL_ENGINE_H - if(data->state.engine) { - if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) { - infof(data, "set default crypto engine '%s'\n", - ENGINE_get_id(data->state.engine)); - } - else { - failf(data, "set default crypto engine '%s' failed", - ENGINE_get_id(data->state.engine)); - return CURLE_SSL_ENGINE_SETFAILED; - } - } -#else - (void) data; -#endif - return CURLE_OK; -} - -/* Return list of OpenSSL crypto engine names. - */ -static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) -{ - struct curl_slist *list = NULL; -#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) - struct curl_slist *beg; - ENGINE *e; - - for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { - beg = curl_slist_append(list, ENGINE_get_id(e)); - if(!beg) { - curl_slist_free_all(list); - return NULL; - } - list = beg; - } -#endif - (void) data; - return list; -} - - -static void ossl_close(struct ssl_connect_data *connssl) -{ - if(BACKEND->handle) { - (void)SSL_shutdown(BACKEND->handle); - SSL_set_connect_state(BACKEND->handle); - - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; - } - if(BACKEND->ctx) { - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = NULL; - } -} - -/* - * This function is called when an SSL connection is closed. - */ -static void Curl_ossl_close(struct connectdata *conn, int sockindex) -{ - ossl_close(&conn->ssl[sockindex]); - ossl_close(&conn->proxy_ssl[sockindex]); -} - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) -{ - int retval = 0; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - char buf[256]; /* We will use this for the OpenSSL error buffer, so it has - to be at least 256 bytes long. */ - unsigned long sslerror; - ssize_t nread; - int buffsize; - int err; - int done = 0; - - /* This has only been tested on the proftpd server, and the mod_tls code - sends a close notify alert without waiting for a close notify alert in - response. Thus we wait for a close notify alert from the server, but - we do not send one. Let's hope other servers do the same... */ - - if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - (void)SSL_shutdown(BACKEND->handle); - - if(BACKEND->handle) { - buffsize = (int)sizeof(buf); - while(!done) { - int what = SOCKET_READABLE(conn->sock[sockindex], - SSL_SHUTDOWN_TIMEOUT); - if(what > 0) { - ERR_clear_error(); - - /* Something to read, let's do it and hope that it is the close - notify alert from the server */ - nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); - err = SSL_get_error(BACKEND->handle, (int)nread); - - switch(err) { - case SSL_ERROR_NONE: /* this is not an error */ - case SSL_ERROR_ZERO_RETURN: /* no more data */ - /* This is the expected response. There was no data but only - the close notify alert */ - done = 1; - break; - case SSL_ERROR_WANT_READ: - /* there's data pending, re-invoke SSL_read() */ - infof(data, "SSL_ERROR_WANT_READ\n"); - break; - case SSL_ERROR_WANT_WRITE: - /* SSL wants a write. Really odd. Let's bail out. */ - infof(data, "SSL_ERROR_WANT_WRITE\n"); - done = 1; - break; - default: - /* openssl/ssl.h says "look at error stack/return value/errno" */ - sslerror = ERR_get_error(); - failf(conn->data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d", - (sslerror ? - ossl_strerror(sslerror, buf, sizeof(buf)) : - SSL_ERROR_to_str(err)), - SOCKERRNO); - done = 1; - break; - } - } - else if(0 == what) { - /* timeout */ - failf(data, "SSL shutdown timeout"); - done = 1; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - retval = -1; - done = 1; - } - } /* while()-loop for the select() */ - - if(data->set.verbose) { -#ifdef HAVE_SSL_GET_SHUTDOWN - switch(SSL_get_shutdown(BACKEND->handle)) { - case SSL_SENT_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); - break; - case SSL_RECEIVED_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n"); - break; - case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|" - "SSL_RECEIVED__SHUTDOWN\n"); - break; - } -#endif - } - - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; - } - return retval; -} - -static void Curl_ossl_session_free(void *ptr) -{ - /* free the ID */ - SSL_SESSION_free(ptr); -} - -/* - * This function is called when the 'data' struct is going away. Close - * down everything and free all resources! - */ -static void Curl_ossl_close_all(struct Curl_easy *data) -{ -#ifdef HAVE_OPENSSL_ENGINE_H - if(data->state.engine) { - ENGINE_finish(data->state.engine); - ENGINE_free(data->state.engine); - data->state.engine = NULL; - } -#else - (void)data; -#endif -#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \ - defined(HAVE_ERR_REMOVE_THREAD_STATE) - /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread - so we need to clean it here in case the thread will be killed. All OpenSSL - code should extract the error in association with the error so clearing - this queue here should be harmless at worst. */ - ERR_remove_thread_state(NULL); -#endif -} - -/* ====================================================== */ - - -/* Quote from RFC2818 section 3.1 "Server Identity" - - If a subjectAltName extension of type dNSName is present, that MUST - be used as the identity. Otherwise, the (most specific) Common Name - field in the Subject field of the certificate MUST be used. Although - the use of the Common Name is existing practice, it is deprecated and - Certification Authorities are encouraged to use the dNSName instead. - - Matching is performed using the matching rules specified by - [RFC2459]. If more than one identity of a given type is present in - the certificate (e.g., more than one dNSName name, a match in any one - of the set is considered acceptable.) Names may contain the wildcard - character * which is considered to match any single domain name - component or component fragment. E.g., *.a.com matches foo.a.com but - not bar.foo.a.com. f*.com matches foo.com but not bar.com. - - In some cases, the URI is specified as an IP address rather than a - hostname. In this case, the iPAddress subjectAltName must be present - in the certificate and must exactly match the IP in the URI. - -*/ -static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) -{ - bool matched = FALSE; - int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ - size_t addrlen = 0; - struct Curl_easy *data = conn->data; - STACK_OF(GENERAL_NAME) *altnames; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - CURLcode result = CURLE_OK; - bool dNSName = FALSE; /* if a dNSName field exists in the cert */ - bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const char * const dispname = SSL_IS_PROXY() ? - conn->http_proxy.host.dispname : conn->host.dispname; - -#ifdef ENABLE_IPV6 - if(conn->bits.ipv6_ip && - Curl_inet_pton(AF_INET6, hostname, &addr)) { - target = GEN_IPADD; - addrlen = sizeof(struct in6_addr); - } - else -#endif - if(Curl_inet_pton(AF_INET, hostname, &addr)) { - target = GEN_IPADD; - addrlen = sizeof(struct in_addr); - } - - /* get a "list" of alternative names */ - altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); - - if(altnames) { - int numalts; - int i; - bool dnsmatched = FALSE; - bool ipmatched = FALSE; - - /* get amount of alternatives, RFC2459 claims there MUST be at least - one, but we don't depend on it... */ - numalts = sk_GENERAL_NAME_num(altnames); - - /* loop through all alternatives - until a dnsmatch */ - for(i = 0; (i < numalts) && !dnsmatched; i++) { - /* get a handle to alternative name number i */ - const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); - - if(check->type == GEN_DNS) - dNSName = TRUE; - else if(check->type == GEN_IPADD) - iPAddress = TRUE; - - /* only check alternatives of the same type the target is */ - if(check->type == target) { - /* get data and length */ - const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5); - size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5); - - switch(target) { - case GEN_DNS: /* name/pattern comparison */ - /* The OpenSSL man page explicitly says: "In general it cannot be - assumed that the data returned by ASN1_STRING_data() is null - terminated or does not contain embedded nulls." But also that - "The actual format of the data will depend on the actual string - type itself: for example for and IA5String the data will be ASCII" - - Gisle researched the OpenSSL sources: - "I checked the 0.9.6 and 0.9.8 sources before my patch and - it always 0-terminates an IA5String." - */ - if((altlen == strlen(altptr)) && - /* if this isn't true, there was an embedded zero in the name - string and we cannot match it. */ - Curl_cert_hostcheck(altptr, hostname)) { - dnsmatched = TRUE; - infof(data, - " subjectAltName: host \"%s\" matched cert's \"%s\"\n", - dispname, altptr); - } - break; - - case GEN_IPADD: /* IP address comparison */ - /* compare alternative IP address if the data chunk is the same size - our server IP address is */ - if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { - ipmatched = TRUE; - infof(data, - " subjectAltName: host \"%s\" matched cert's IP address!\n", - dispname); - } - break; - } - } - } - GENERAL_NAMES_free(altnames); - - if(dnsmatched || ipmatched) - matched = TRUE; - } - - if(matched) - /* an alternative name matched */ - ; - else if(dNSName || iPAddress) { - infof(data, " subjectAltName does not match %s\n", dispname); - failf(data, "SSL: no alternative certificate subject name matches " - "target host name '%s'", dispname); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else { - /* we have to look to the last occurrence of a commonName in the - distinguished one to get the most significant one. */ - int j, i = -1; - - /* The following is done because of a bug in 0.9.6b */ - - unsigned char *nulstr = (unsigned char *)""; - unsigned char *peer_CN = nulstr; - - X509_NAME *name = X509_get_subject_name(server_cert); - if(name) - while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) - i = j; - - /* we have the name entry and we will now convert this to a string - that we can use for comparison. Doing this we support BMPstring, - UTF8 etc. */ - - if(i >= 0) { - ASN1_STRING *tmp = - X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); - - /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input - is already UTF-8 encoded. We check for this case and copy the raw - string manually to avoid the problem. This code can be made - conditional in the future when OpenSSL has been fixed. Work-around - brought by Alexis S. L. Carvalho. */ - if(tmp) { - if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { - j = ASN1_STRING_length(tmp); - if(j >= 0) { - peer_CN = OPENSSL_malloc(j + 1); - if(peer_CN) { - memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j); - peer_CN[j] = '\0'; - } - } - } - else /* not a UTF8 name */ - j = ASN1_STRING_to_UTF8(&peer_CN, tmp); - - if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != j)) { - /* there was a terminating zero before the end of string, this - cannot match and we return failure! */ - failf(data, "SSL: illegal cert name field"); - result = CURLE_PEER_FAILED_VERIFICATION; - } - } - } - - if(peer_CN == nulstr) - peer_CN = NULL; - else { - /* convert peer_CN from UTF8 */ - CURLcode rc = Curl_convert_from_utf8(data, (char *)peer_CN, - strlen((char *)peer_CN)); - /* Curl_convert_from_utf8 calls failf if unsuccessful */ - if(rc) { - OPENSSL_free(peer_CN); - return rc; - } - } - - if(result) - /* error already detected, pass through */ - ; - else if(!peer_CN) { - failf(data, - "SSL: unable to obtain common name from peer certificate"); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { - failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", peer_CN, dispname); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else { - infof(data, " common name: %s (matched)\n", peer_CN); - } - if(peer_CN) - OPENSSL_free(peer_CN); - } - - return result; -} - -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) -static CURLcode verifystatus(struct connectdata *conn, - struct ssl_connect_data *connssl) -{ - int i, ocsp_status; - const unsigned char *p; - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - OCSP_RESPONSE *rsp = NULL; - OCSP_BASICRESP *br = NULL; - X509_STORE *st = NULL; - STACK_OF(X509) *ch = NULL; - - long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &p); - - if(!p) { - failf(data, "No OCSP response received"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - rsp = d2i_OCSP_RESPONSE(NULL, &p, len); - if(!rsp) { - failf(data, "Invalid OCSP response"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - ocsp_status = OCSP_response_status(rsp); - if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - failf(data, "Invalid OCSP response status: %s (%d)", - OCSP_response_status_str(ocsp_status), ocsp_status); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - br = OCSP_response_get1_basic(rsp); - if(!br) { - failf(data, "Invalid OCSP response"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - ch = SSL_get_peer_cert_chain(BACKEND->handle); - st = SSL_CTX_get_cert_store(BACKEND->ctx); - -#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER <= 0x2040200fL)) - /* The authorized responder cert in the OCSP response MUST be signed by the - peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert, - no problem, but if it's an intermediate cert OpenSSL has a bug where it - expects this issuer to be present in the chain embedded in the OCSP - response. So we add it if necessary. */ - - /* First make sure the peer cert chain includes both a peer and an issuer, - and the OCSP response contains a responder cert. */ - if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) { - X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1); - - /* Find issuer of responder cert and add it to the OCSP response chain */ - for(i = 0; i < sk_X509_num(ch); i++) { - X509 *issuer = sk_X509_value(ch, i); - if(X509_check_issued(issuer, responder) == X509_V_OK) { - if(!OCSP_basic_add1_cert(br, issuer)) { - failf(data, "Could not add issuer cert to OCSP response"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - } - } - } -#endif - - if(OCSP_basic_verify(br, ch, st, 0) <= 0) { - failf(data, "OCSP response verification failed"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - for(i = 0; i < OCSP_resp_count(br); i++) { - int cert_status, crl_reason; - OCSP_SINGLERESP *single = NULL; - - ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; - - single = OCSP_resp_get0(br, i); - if(!single) - continue; - - cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, - &thisupd, &nextupd); - - if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { - failf(data, "OCSP response has expired"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - infof(data, "SSL certificate status: %s (%d)\n", - OCSP_cert_status_str(cert_status), cert_status); - - switch(cert_status) { - case V_OCSP_CERTSTATUS_GOOD: - break; - - case V_OCSP_CERTSTATUS_REVOKED: - result = CURLE_SSL_INVALIDCERTSTATUS; - - failf(data, "SSL certificate revocation reason: %s (%d)", - OCSP_crl_reason_str(crl_reason), crl_reason); - goto end; - - case V_OCSP_CERTSTATUS_UNKNOWN: - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - } - -end: - if(br) OCSP_BASICRESP_free(br); - OCSP_RESPONSE_free(rsp); - - return result; -} -#endif - -#endif /* USE_OPENSSL */ - -/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions - and thus this cannot be done there. */ -#ifdef SSL_CTRL_SET_MSG_CALLBACK - -static const char *ssl_msg_type(int ssl_ver, int msg) -{ -#ifdef SSL2_VERSION_MAJOR - if(ssl_ver == SSL2_VERSION_MAJOR) { - switch(msg) { - case SSL2_MT_ERROR: - return "Error"; - case SSL2_MT_CLIENT_HELLO: - return "Client hello"; - case SSL2_MT_CLIENT_MASTER_KEY: - return "Client key"; - case SSL2_MT_CLIENT_FINISHED: - return "Client finished"; - case SSL2_MT_SERVER_HELLO: - return "Server hello"; - case SSL2_MT_SERVER_VERIFY: - return "Server verify"; - case SSL2_MT_SERVER_FINISHED: - return "Server finished"; - case SSL2_MT_REQUEST_CERTIFICATE: - return "Request CERT"; - case SSL2_MT_CLIENT_CERTIFICATE: - return "Client CERT"; - } - } - else -#endif - if(ssl_ver == SSL3_VERSION_MAJOR) { - switch(msg) { - case SSL3_MT_HELLO_REQUEST: - return "Hello request"; - case SSL3_MT_CLIENT_HELLO: - return "Client hello"; - case SSL3_MT_SERVER_HELLO: - return "Server hello"; -#ifdef SSL3_MT_NEWSESSION_TICKET - case SSL3_MT_NEWSESSION_TICKET: - return "Newsession Ticket"; -#endif - case SSL3_MT_CERTIFICATE: - return "Certificate"; - case SSL3_MT_SERVER_KEY_EXCHANGE: - return "Server key exchange"; - case SSL3_MT_CLIENT_KEY_EXCHANGE: - return "Client key exchange"; - case SSL3_MT_CERTIFICATE_REQUEST: - return "Request CERT"; - case SSL3_MT_SERVER_DONE: - return "Server finished"; - case SSL3_MT_CERTIFICATE_VERIFY: - return "CERT verify"; - case SSL3_MT_FINISHED: - return "Finished"; -#ifdef SSL3_MT_CERTIFICATE_STATUS - case SSL3_MT_CERTIFICATE_STATUS: - return "Certificate Status"; -#endif - } - } - return "Unknown"; -} - -static const char *tls_rt_type(int type) -{ - switch(type) { -#ifdef SSL3_RT_HEADER - case SSL3_RT_HEADER: - return "TLS header"; -#endif - case SSL3_RT_CHANGE_CIPHER_SPEC: - return "TLS change cipher"; - case SSL3_RT_ALERT: - return "TLS alert"; - case SSL3_RT_HANDSHAKE: - return "TLS handshake"; - case SSL3_RT_APPLICATION_DATA: - return "TLS app data"; - default: - return "TLS Unknown"; - } -} - - -/* - * Our callback from the SSL/TLS layers. - */ -static void ssl_tls_trace(int direction, int ssl_ver, int content_type, - const void *buf, size_t len, SSL *ssl, - void *userp) -{ - struct Curl_easy *data; - const char *msg_name, *tls_rt_name; - char ssl_buf[1024]; - char unknown[32]; - int msg_type, txt_len; - const char *verstr = NULL; - struct connectdata *conn = userp; - - if(!conn || !conn->data || !conn->data->set.fdebug || - (direction != 0 && direction != 1)) - return; - - data = conn->data; - - switch(ssl_ver) { -#ifdef SSL2_VERSION /* removed in recent versions */ - case SSL2_VERSION: - verstr = "SSLv2"; - break; -#endif -#ifdef SSL3_VERSION - case SSL3_VERSION: - verstr = "SSLv3"; - break; -#endif - case TLS1_VERSION: - verstr = "TLSv1.0"; - break; -#ifdef TLS1_1_VERSION - case TLS1_1_VERSION: - verstr = "TLSv1.1"; - break; -#endif -#ifdef TLS1_2_VERSION - case TLS1_2_VERSION: - verstr = "TLSv1.2"; - break; -#endif -#ifdef TLS1_3_VERSION - case TLS1_3_VERSION: - verstr = "TLSv1.3"; - break; -#endif - case 0: - break; - default: - snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); - verstr = unknown; - break; - } - - if(ssl_ver) { - /* the info given when the version is zero is not that useful for us */ - - ssl_ver >>= 8; /* check the upper 8 bits only below */ - - /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL - * always pass-up content-type as 0. But the interesting message-type - * is at 'buf[0]'. - */ - if(ssl_ver == SSL3_VERSION_MAJOR && content_type) - tls_rt_name = tls_rt_type(content_type); - else - tls_rt_name = ""; - - msg_type = *(char *)buf; - msg_name = ssl_msg_type(ssl_ver, msg_type); - - txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n", - verstr, direction?"OUT":"IN", - tls_rt_name, msg_name, msg_type); - Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); - } - - Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : - CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL); - (void) ssl; -} -#endif - -#ifdef USE_OPENSSL -/* ====================================================== */ - -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -# define use_sni(x) sni = (x) -#else -# define use_sni(x) Curl_nop_stmt -#endif - -/* Check for OpenSSL 1.0.2 which has ALPN support. */ -#undef HAS_ALPN -#if OPENSSL_VERSION_NUMBER >= 0x10002000L \ - && !defined(OPENSSL_NO_TLSEXT) -# define HAS_ALPN 1 -#endif - -/* Check for OpenSSL 1.0.1 which has NPN support. */ -#undef HAS_NPN -#if OPENSSL_VERSION_NUMBER >= 0x10001000L \ - && !defined(OPENSSL_NO_TLSEXT) \ - && !defined(OPENSSL_NO_NEXTPROTONEG) -# define HAS_NPN 1 -#endif - -#ifdef HAS_NPN - -/* - * in is a list of length prefixed strings. this function has to select - * the protocol we want to use from the list and write its string into out. - */ - -static int -select_next_protocol(unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - const char *key, unsigned int keylen) -{ - unsigned int i; - for(i = 0; i + keylen <= inlen; i += in[i] + 1) { - if(memcmp(&in[i + 1], key, keylen) == 0) { - *out = (unsigned char *) &in[i + 1]; - *outlen = in[i]; - return 0; - } - } - return -1; -} - -static int -select_next_proto_cb(SSL *ssl, - unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - void *arg) -{ - struct connectdata *conn = (struct connectdata*) arg; - - (void)ssl; - -#ifdef USE_NGHTTP2 - if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 && - !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN)) { - infof(conn->data, "NPN, negotiated HTTP2 (%s)\n", - NGHTTP2_PROTO_VERSION_ID); - conn->negnpn = CURL_HTTP_VERSION_2; - return SSL_TLSEXT_ERR_OK; - } -#endif - - if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, - ALPN_HTTP_1_1_LENGTH)) { - infof(conn->data, "NPN, negotiated HTTP1.1\n"); - conn->negnpn = CURL_HTTP_VERSION_1_1; - return SSL_TLSEXT_ERR_OK; - } - - infof(conn->data, "NPN, no overlap, use HTTP1.1\n"); - *out = (unsigned char *)ALPN_HTTP_1_1; - *outlen = ALPN_HTTP_1_1_LENGTH; - conn->negnpn = CURL_HTTP_VERSION_1_1; - - return SSL_TLSEXT_ERR_OK; -} -#endif /* HAS_NPN */ - -static const char * -get_ssl_version_txt(SSL *ssl) -{ - if(!ssl) - return ""; - - switch(SSL_version(ssl)) { -#ifdef TLS1_3_VERSION - case TLS1_3_VERSION: - return "TLSv1.3"; -#endif -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - case TLS1_2_VERSION: - return "TLSv1.2"; - case TLS1_1_VERSION: - return "TLSv1.1"; -#endif - case TLS1_VERSION: - return "TLSv1.0"; - case SSL3_VERSION: - return "SSLv3"; - case SSL2_VERSION: - return "SSLv2"; - } - return "unknown"; -} - -static CURLcode -set_ssl_version_min_max(long *ctx_options, struct connectdata *conn, - int sockindex) -{ -#if (OPENSSL_VERSION_NUMBER < 0x1000100FL) || !defined(TLS1_3_VERSION) - /* convoluted #if condition just to avoid compiler warnings on unused - variable */ - struct Curl_easy *data = conn->data; -#endif - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - - if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) { - ssl_version_max = ssl_version << 16; - } - - switch(ssl_version) { - case CURL_SSLVERSION_TLSv1_3: -#ifdef TLS1_3_VERSION - { - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION); - *ctx_options |= SSL_OP_NO_TLSv1_2; - } -#else - (void)sockindex; - failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); - return CURLE_NOT_BUILT_IN; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_TLSv1_2: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - *ctx_options |= SSL_OP_NO_TLSv1_1; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.2 support"); - return CURLE_NOT_BUILT_IN; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_TLSv1_1: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - *ctx_options |= SSL_OP_NO_TLSv1; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.1 support"); - return CURLE_NOT_BUILT_IN; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_TLSv1_0: - *ctx_options |= SSL_OP_NO_SSLv2; - *ctx_options |= SSL_OP_NO_SSLv3; - break; - } - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_TLSv1_0: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - *ctx_options |= SSL_OP_NO_TLSv1_1; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_MAX_TLSv1_1: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - *ctx_options |= SSL_OP_NO_TLSv1_2; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_MAX_TLSv1_2: - case CURL_SSLVERSION_MAX_DEFAULT: -#ifdef TLS1_3_VERSION - *ctx_options |= SSL_OP_NO_TLSv1_3; -#endif - break; - case CURL_SSLVERSION_MAX_TLSv1_3: -#ifdef TLS1_3_VERSION - break; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); - return CURLE_NOT_BUILT_IN; -#endif - } - return CURLE_OK; -} - -static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) -{ - CURLcode result = CURLE_OK; - char *ciphers; - struct Curl_easy *data = conn->data; - SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; - X509_LOOKUP *lookup = NULL; - curl_socket_t sockfd = conn->sock[sockindex]; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - long ctx_options = 0; -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - bool sni; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif -#endif - long * const certverifyresult = SSL_IS_PROXY() ? - &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; - const long int ssl_version = SSL_CONN_CONFIG(version); -#ifdef USE_TLS_SRP - const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); -#endif - char * const ssl_cert = SSL_SET_OPTION(cert); - const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); - const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); - const char * const ssl_capath = SSL_CONN_CONFIG(CApath); - const bool verifypeer = SSL_CONN_CONFIG(verifypeer); - const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); - char error_buffer[256]; - - DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); - - /* Make funny stuff to get random input */ - result = Curl_ossl_seed(data); - if(result) - return result; - - *certverifyresult = !X509_V_OK; - - /* check to see if we've been told to use an explicit SSL/TLS version */ - - switch(ssl_version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - /* it will be handled later with the context options */ -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(LIBRESSL_VERSION_NUMBER) - req_method = TLS_client_method(); -#else - req_method = SSLv23_client_method(); -#endif - use_sni(TRUE); - break; - case CURL_SSLVERSION_SSLv2: -#ifdef OPENSSL_NO_SSL2 - failf(data, OSSL_PACKAGE " was built without SSLv2 support"); - return CURLE_NOT_BUILT_IN; -#else -#ifdef USE_TLS_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) - return CURLE_SSL_CONNECT_ERROR; -#endif - req_method = SSLv2_client_method(); - use_sni(FALSE); - break; -#endif - case CURL_SSLVERSION_SSLv3: -#ifdef OPENSSL_NO_SSL3_METHOD - failf(data, OSSL_PACKAGE " was built without SSLv3 support"); - return CURLE_NOT_BUILT_IN; -#else -#ifdef USE_TLS_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) - return CURLE_SSL_CONNECT_ERROR; -#endif - req_method = SSLv3_client_method(); - use_sni(FALSE); - break; -#endif - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - if(BACKEND->ctx) - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = SSL_CTX_new(req_method); - - if(!BACKEND->ctx) { - failf(data, "SSL: couldn't create a context: %s", - ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); - return CURLE_OUT_OF_MEMORY; - } - -#ifdef SSL_MODE_RELEASE_BUFFERS - SSL_CTX_set_mode(BACKEND->ctx, SSL_MODE_RELEASE_BUFFERS); -#endif - -#ifdef SSL_CTRL_SET_MSG_CALLBACK - if(data->set.fdebug && data->set.verbose) { - /* the SSL trace callback is only used for verbose logging */ - SSL_CTX_set_msg_callback(BACKEND->ctx, ssl_tls_trace); - SSL_CTX_set_msg_callback_arg(BACKEND->ctx, conn); - } -#endif - - /* OpenSSL contains code to work-around lots of bugs and flaws in various - SSL-implementations. SSL_CTX_set_options() is used to enabled those - work-arounds. The man page for this option states that SSL_OP_ALL enables - all the work-arounds and that "It is usually safe to use SSL_OP_ALL to - enable the bug workaround options if compatibility with somewhat broken - implementations is desired." - - The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to - disable "rfc4507bis session ticket support". rfc4507bis was later turned - into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077 - - The enabled extension concerns the session management. I wonder how often - libcurl stops a connection and then resumes a TLS session. also, sending - the session data is some overhead. .I suggest that you just use your - proposed patch (which explicitly disables TICKET). - - If someone writes an application with libcurl and openssl who wants to - enable the feature, one can do this in the SSL callback. - - SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper - interoperability with web server Netscape Enterprise Server 2.0.1 which - was released back in 1996. - - Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has - become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate - CVE-2010-4180 when using previous OpenSSL versions we no longer enable - this option regardless of OpenSSL version and SSL_OP_ALL definition. - - OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability - (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to - SSL_OP_ALL that _disables_ that work-around despite the fact that - SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to - keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit - must not be set. - */ - - ctx_options = SSL_OP_ALL; - -#ifdef SSL_OP_NO_TICKET - ctx_options |= SSL_OP_NO_TICKET; -#endif - -#ifdef SSL_OP_NO_COMPRESSION - ctx_options |= SSL_OP_NO_COMPRESSION; -#endif - -#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG - /* mitigate CVE-2010-4180 */ - ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; -#endif - -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - /* unless the user explicitly ask to allow the protocol vulnerability we - use the work-around */ - if(!SSL_SET_OPTION(enable_beast)) - ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; -#endif - - switch(ssl_version) { - case CURL_SSLVERSION_SSLv3: -#ifdef USE_TLS_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) { - infof(data, "Set version TLSv1.x for SRP authorisation\n"); - } -#endif - ctx_options |= SSL_OP_NO_SSLv2; - ctx_options |= SSL_OP_NO_TLSv1; -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - ctx_options |= SSL_OP_NO_TLSv1_1; - ctx_options |= SSL_OP_NO_TLSv1_2; -#ifdef TLS1_3_VERSION - ctx_options |= SSL_OP_NO_TLSv1_3; -#endif -#endif - break; - - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - ctx_options |= SSL_OP_NO_SSLv2; - ctx_options |= SSL_OP_NO_SSLv3; - break; - - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - result = set_ssl_version_min_max(&ctx_options, conn, sockindex); - if(result != CURLE_OK) - return result; - break; - - case CURL_SSLVERSION_SSLv2: -#ifndef OPENSSL_NO_SSL2 - ctx_options |= SSL_OP_NO_SSLv3; - ctx_options |= SSL_OP_NO_TLSv1; -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - ctx_options |= SSL_OP_NO_TLSv1_1; - ctx_options |= SSL_OP_NO_TLSv1_2; -#ifdef TLS1_3_VERSION - ctx_options |= SSL_OP_NO_TLSv1_3; -#endif -#endif - break; -#else - failf(data, OSSL_PACKAGE " was built without SSLv2 support"); - return CURLE_NOT_BUILT_IN; -#endif - - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - SSL_CTX_set_options(BACKEND->ctx, ctx_options); - -#ifdef HAS_NPN - if(conn->bits.tls_enable_npn) - SSL_CTX_set_next_proto_select_cb(BACKEND->ctx, select_next_proto_cb, conn); -#endif - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - int cur = 0; - unsigned char protocols[128]; - -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2 && - (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { - protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; - - memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN); - cur += NGHTTP2_PROTO_VERSION_ID_LEN; - infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); - } -#endif - - protocols[cur++] = ALPN_HTTP_1_1_LENGTH; - memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - cur += ALPN_HTTP_1_1_LENGTH; - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - - /* expects length prefixed preference ordered list of protocols in wire - * format - */ - SSL_CTX_set_alpn_protos(BACKEND->ctx, protocols, cur); - } -#endif - - if(ssl_cert || ssl_cert_type) { - if(!cert_stuff(conn, BACKEND->ctx, ssl_cert, ssl_cert_type, - SSL_SET_OPTION(key), SSL_SET_OPTION(key_type), - SSL_SET_OPTION(key_passwd))) { - /* failf() is already done in cert_stuff() */ - return CURLE_SSL_CERTPROBLEM; - } - } - - ciphers = SSL_CONN_CONFIG(cipher_list); - if(!ciphers) - ciphers = (char *)DEFAULT_CIPHER_SELECTION; - if(ciphers) { - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { - failf(data, "failed setting cipher list: %s", ciphers); - return CURLE_SSL_CIPHER; - } - infof(data, "Cipher selection: %s\n", ciphers); - } - -#ifdef USE_TLS_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) { - char * const ssl_username = SSL_SET_OPTION(username); - - infof(data, "Using TLS-SRP username: %s\n", ssl_username); - - if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) { - failf(data, "Unable to set SRP user name"); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) { - failf(data, "failed setting SRP password"); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - if(!SSL_CONN_CONFIG(cipher_list)) { - infof(data, "Setting cipher list SRP\n"); - - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, "SRP")) { - failf(data, "failed setting SRP cipher list"); - return CURLE_SSL_CIPHER; - } - } - } -#endif - - if(ssl_cafile || ssl_capath) { - /* tell SSL where to find CA certificates that are used to verify - the servers certificate. */ - if(!SSL_CTX_load_verify_locations(BACKEND->ctx, ssl_cafile, ssl_capath)) { - if(verifypeer) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:\n" - " CAfile: %s\n CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - return CURLE_SSL_CACERT_BADFILE; - } - /* Just continue with a warning if no strict certificate verification - is required. */ - infof(data, "error setting certificate verify locations," - " continuing anyway:\n"); - } - else { - /* Everything is fine. */ - infof(data, "successfully set certificate verify locations:\n"); - } - infof(data, - " CAfile: %s\n" - " CApath: %s\n", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - } -#ifdef CURL_CA_FALLBACK - else if(verifypeer) { - /* verfying the peer without any CA certificates won't - work so use openssl's built in default as fallback */ - SSL_CTX_set_default_verify_paths(BACKEND->ctx); - } -#endif - - if(ssl_crlfile) { - /* tell SSL where to find CRL file that is used to check certificate - * revocation */ - lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(BACKEND->ctx), - X509_LOOKUP_file()); - if(!lookup || - (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { - failf(data, "error loading CRL file: %s", ssl_crlfile); - return CURLE_SSL_CRL_BADFILE; - } - /* Everything is fine. */ - infof(data, "successfully load CRL file:\n"); - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), - X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); - - infof(data, " CRLfile: %s\n", ssl_crlfile); - } - - /* Try building a chain using issuers in the trusted store first to avoid - problems with server-sent legacy intermediates. - Newer versions of OpenSSL do alternate chain checking by default which - gives us the same fix without as much of a performance hit (slight), so we - prefer that if available. - https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest - */ -#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) - if(verifypeer) { - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), - X509_V_FLAG_TRUSTED_FIRST); - } -#endif - - /* SSL always tries to verify the peer, this only says whether it should - * fail to connect if the verification fails, or if it should continue - * anyway. In the latter case the result of the verification is checked with - * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(BACKEND->ctx, - verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); - - /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ -#if defined(ENABLE_SSLKEYLOGFILE) && defined(HAVE_KEYLOG_CALLBACK) - if(keylog_file) { - SSL_CTX_set_keylog_callback(connssl->ctx, ossl_keylog_callback); - } -#endif - - /* give application a chance to interfere with SSL set up. */ - if(data->set.ssl.fsslctx) { - result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, - data->set.ssl.fsslctxp); - if(result) { - failf(data, "error signaled by ssl ctx callback"); - return result; - } - } - - /* Lets make an SSL structure */ - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { - failf(data, "SSL: couldn't create a context (handle)!"); - return CURLE_OUT_OF_MEMORY; - } - -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) - if(SSL_CONN_CONFIG(verifystatus)) - SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp); -#endif - - SSL_set_connect_state(BACKEND->handle); - - BACKEND->server_cert = 0x0; -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && -#ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && -#endif - sni && - !SSL_set_tlsext_host_name(BACKEND->handle, hostname)) - infof(data, "WARNING: failed to configure server name indication (SNI) " - "TLS extension\n"); -#endif - - /* Check if there's a cached ID we can/should use here! */ - if(SSL_SET_OPTION(primary.sessionid)) { - void *ssl_sessionid = NULL; - - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { - /* we got a session id, use it! */ - if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "SSL: SSL_set_session failed: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return CURLE_SSL_CONNECT_ERROR; - } - /* Informational message */ - infof(data, "SSL re-using session ID\n"); - } - Curl_ssl_sessionid_unlock(conn); - } - - if(conn->proxy_ssl[sockindex].use) { - BIO *const bio = BIO_new(BIO_f_ssl()); - SSL *handle = conn->proxy_ssl[sockindex].backend->handle; - DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); - DEBUGASSERT(handle != NULL); - DEBUGASSERT(bio != NULL); - BIO_set_ssl(bio, handle, FALSE); - SSL_set_bio(BACKEND->handle, bio, bio); - } - else if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { - /* pass the raw socket into the SSL layers */ - failf(data, "SSL: SSL_set_fd failed: %s", - ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); - return CURLE_SSL_CONNECT_ERROR; - } - - connssl->connecting_state = ssl_connect_2; - - return CURLE_OK; -} - -static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - int err; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - long * const certverifyresult = SSL_IS_PROXY() ? - &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; - DEBUGASSERT(ssl_connect_2 == connssl->connecting_state - || ssl_connect_2_reading == connssl->connecting_state - || ssl_connect_2_writing == connssl->connecting_state); - - ERR_clear_error(); - - err = SSL_connect(BACKEND->handle); - /* If keylogging is enabled but the keylog callback is not supported then log - secrets here, immediately after SSL_connect by using tap_ssl_key. */ -#if defined(ENABLE_SSLKEYLOGFILE) && !defined(HAVE_KEYLOG_CALLBACK) - tap_ssl_key(BACKEND->handle, &BACKEND->tap_state); -#endif - - /* 1 is fine - 0 is "not successful but was shut down controlled" - <0 is "handshake was not successful, because a fatal error occurred" */ - if(1 != err) { - int detail = SSL_get_error(BACKEND->handle, err); - - if(SSL_ERROR_WANT_READ == detail) { - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - } - if(SSL_ERROR_WANT_WRITE == detail) { - connssl->connecting_state = ssl_connect_2_writing; - return CURLE_OK; - } - else { - /* untreated error */ - unsigned long errdetail; - char error_buffer[256]=""; - CURLcode result; - long lerr; - int lib; - int reason; - - /* the connection failed, we're not waiting for anything else. */ - connssl->connecting_state = ssl_connect_2; - - /* Get the earliest error code from the thread's error queue and removes - the entry. */ - errdetail = ERR_get_error(); - - /* Extract which lib and reason */ - lib = ERR_GET_LIB(errdetail); - reason = ERR_GET_REASON(errdetail); - - if((lib == ERR_LIB_SSL) && - (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { - result = CURLE_SSL_CACERT; - - lerr = SSL_get_verify_result(BACKEND->handle); - if(lerr != X509_V_OK) { - *certverifyresult = lerr; - snprintf(error_buffer, sizeof(error_buffer), - "SSL certificate problem: %s", - X509_verify_cert_error_string(lerr)); - } - else - /* strcpy() is fine here as long as the string fits within - error_buffer */ - strcpy(error_buffer, "SSL certificate verification failed"); - } - else { - result = CURLE_SSL_CONNECT_ERROR; - ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)); - } - - /* detail is already set to the SSL error above */ - - /* If we e.g. use SSLv2 request-method and the server doesn't like us - * (RST connection etc.), OpenSSL gives no explanation whatsoever and - * the SO_ERROR is also lost. - */ - if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { - const char * const hostname = SSL_IS_PROXY() ? - conn->http_proxy.host.name : conn->host.name; - const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; - failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ", - SSL_ERROR_to_str(detail), hostname, port); - return result; - } - - /* Could be a CERT problem */ - failf(data, "%s", error_buffer); - - return result; - } - } - else { - /* we have been connected fine, we're not waiting for anything else. */ - connssl->connecting_state = ssl_connect_3; - - /* Informational message */ - infof(data, "SSL connection using %s / %s\n", - get_ssl_version_txt(BACKEND->handle), - SSL_get_cipher(BACKEND->handle)); - -#ifdef HAS_ALPN - /* Sets data and len to negotiated protocol, len is 0 if no protocol was - * negotiated - */ - if(conn->bits.tls_enable_alpn) { - const unsigned char *neg_protocol; - unsigned int len; - SSL_get0_alpn_selected(BACKEND->handle, &neg_protocol, &len); - if(len != 0) { - infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); - -#ifdef USE_NGHTTP2 - if(len == NGHTTP2_PROTO_VERSION_ID_LEN && - !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) { - conn->negnpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(len == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } - } - else - infof(data, "ALPN, server did not agree to a protocol\n"); - } -#endif - - return CURLE_OK; - } -} - -static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) -{ - int i, ilen; - - ilen = (int)len; - if(ilen < 0) - return 1; /* buffer too big */ - - i = i2t_ASN1_OBJECT(buf, ilen, a); - - if(i >= ilen) - return 1; /* buffer too small */ - - return 0; -} - -#define push_certinfo(_label, _num) \ -do { \ - long info_len = BIO_get_mem_data(mem, &ptr); \ - Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ - if(1 != BIO_reset(mem)) \ - break; \ -} WHILE_FALSE - -static void pubkey_show(struct Curl_easy *data, - BIO *mem, - int num, - const char *type, - const char *name, -#ifdef HAVE_OPAQUE_RSA_DSA_DH - const -#endif - BIGNUM *bn) -{ - char *ptr; - char namebuf[32]; - - snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); - - if(bn) - BN_print(mem, bn); - push_certinfo(namebuf, num); -} - -#ifdef HAVE_OPAQUE_RSA_DSA_DH -#define print_pubkey_BN(_type, _name, _num) \ - pubkey_show(data, mem, _num, #_type, #_name, _name) - -#else -#define print_pubkey_BN(_type, _name, _num) \ -do { \ - if(_type->_name) { \ - pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ - } \ -} WHILE_FALSE -#endif - -static int X509V3_ext(struct Curl_easy *data, - int certnum, - CONST_EXTS STACK_OF(X509_EXTENSION) *exts) -{ - int i; - size_t j; - - if((int)sk_X509_EXTENSION_num(exts) <= 0) - /* no extensions, bail out */ - return 1; - - for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { - ASN1_OBJECT *obj; - X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); - BUF_MEM *biomem; - char buf[512]; - char *ptr = buf; - char namebuf[128]; - BIO *bio_out = BIO_new(BIO_s_mem()); - - if(!bio_out) - return 1; - - obj = X509_EXTENSION_get_object(ext); - - asn1_object_dump(obj, namebuf, sizeof(namebuf)); - - if(!X509V3_EXT_print(bio_out, ext, 0, 0)) - ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); - - BIO_get_mem_ptr(bio_out, &biomem); - - for(j = 0; j < (size_t)biomem->length; j++) { - const char *sep = ""; - if(biomem->data[j] == '\n') { - sep = ", "; - j++; /* skip the newline */ - }; - while((j<(size_t)biomem->length) && (biomem->data[j] == ' ')) - j++; - if(j<(size_t)biomem->length) - ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, - biomem->data[j]); - } - - Curl_ssl_push_certinfo(data, certnum, namebuf, buf); - - BIO_free(bio_out); - - } - return 0; /* all is fine */ -} - -static CURLcode get_cert_chain(struct connectdata *conn, - struct ssl_connect_data *connssl) - -{ - CURLcode result; - STACK_OF(X509) *sk; - int i; - struct Curl_easy *data = conn->data; - int numcerts; - BIO *mem; - - sk = SSL_get_peer_cert_chain(BACKEND->handle); - if(!sk) { - return CURLE_OUT_OF_MEMORY; - } - - numcerts = sk_X509_num(sk); - - result = Curl_ssl_init_certinfo(data, numcerts); - if(result) { - return result; - } - - mem = BIO_new(BIO_s_mem()); - - for(i = 0; i < numcerts; i++) { - ASN1_INTEGER *num; - X509 *x = sk_X509_value(sk, i); - EVP_PKEY *pubkey = NULL; - int j; - char *ptr; - const ASN1_BIT_STRING *psig = NULL; - - X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); - push_certinfo("Subject", i); - - X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); - push_certinfo("Issuer", i); - - BIO_printf(mem, "%lx", X509_get_version(x)); - push_certinfo("Version", i); - - num = X509_get_serialNumber(x); - if(num->type == V_ASN1_NEG_INTEGER) - BIO_puts(mem, "-"); - for(j = 0; j < num->length; j++) - BIO_printf(mem, "%02x", num->data[j]); - push_certinfo("Serial Number", i); - -#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) - { - const X509_ALGOR *palg = NULL; - ASN1_STRING *a = ASN1_STRING_new(); - if(a) { - X509_get0_signature(&psig, &palg, x); - X509_signature_print(mem, palg, a); - ASN1_STRING_free(a); - - if(palg) { - i2a_ASN1_OBJECT(mem, palg->algorithm); - push_certinfo("Public Key Algorithm", i); - } - } - X509V3_ext(data, i, X509_get0_extensions(x)); - } -#else - { - /* before OpenSSL 1.0.2 */ - X509_CINF *cinf = x->cert_info; - - i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); - push_certinfo("Signature Algorithm", i); - - i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); - push_certinfo("Public Key Algorithm", i); - - X509V3_ext(data, i, cinf->extensions); - - psig = x->signature; - } -#endif - - ASN1_TIME_print(mem, X509_get0_notBefore(x)); - push_certinfo("Start date", i); - - ASN1_TIME_print(mem, X509_get0_notAfter(x)); - push_certinfo("Expire date", i); - - pubkey = X509_get_pubkey(x); - if(!pubkey) - infof(data, " Unable to load public key\n"); - else { - int pktype; -#ifdef HAVE_OPAQUE_EVP_PKEY - pktype = EVP_PKEY_id(pubkey); -#else - pktype = pubkey->type; -#endif - switch(pktype) { - case EVP_PKEY_RSA: - { - RSA *rsa; -#ifdef HAVE_OPAQUE_EVP_PKEY - rsa = EVP_PKEY_get0_RSA(pubkey); -#else - rsa = pubkey->pkey.rsa; -#endif - -#ifdef HAVE_OPAQUE_RSA_DSA_DH - { - const BIGNUM *n; - const BIGNUM *e; - - RSA_get0_key(rsa, &n, &e, NULL); - BN_print(mem, n); - push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); - print_pubkey_BN(rsa, e, i); - } -#else - BIO_printf(mem, "%d", BN_num_bits(rsa->n)); - push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); - print_pubkey_BN(rsa, e, i); -#endif - - break; - } - case EVP_PKEY_DSA: - { -#ifndef OPENSSL_NO_DSA - DSA *dsa; -#ifdef HAVE_OPAQUE_EVP_PKEY - dsa = EVP_PKEY_get0_DSA(pubkey); -#else - dsa = pubkey->pkey.dsa; -#endif -#ifdef HAVE_OPAQUE_RSA_DSA_DH - { - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *g; - const BIGNUM *pub_key; - - DSA_get0_pqg(dsa, &p, &q, &g); - DSA_get0_key(dsa, &pub_key, NULL); - - print_pubkey_BN(dsa, p, i); - print_pubkey_BN(dsa, q, i); - print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, pub_key, i); - } -#else - print_pubkey_BN(dsa, p, i); - print_pubkey_BN(dsa, q, i); - print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, pub_key, i); -#endif -#endif /* !OPENSSL_NO_DSA */ - break; - } - case EVP_PKEY_DH: - { - DH *dh; -#ifdef HAVE_OPAQUE_EVP_PKEY - dh = EVP_PKEY_get0_DH(pubkey); -#else - dh = pubkey->pkey.dh; -#endif -#ifdef HAVE_OPAQUE_RSA_DSA_DH - { - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *g; - const BIGNUM *pub_key; - DH_get0_pqg(dh, &p, &q, &g); - DH_get0_key(dh, &pub_key, NULL); - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, q, i); - print_pubkey_BN(dh, g, i); - print_pubkey_BN(dh, pub_key, i); - } -#else - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, g, i); - print_pubkey_BN(dh, pub_key, i); -#endif - break; - } -#if 0 - case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */ - /* left TODO */ - break; -#endif - } - EVP_PKEY_free(pubkey); - } - - if(psig) { - for(j = 0; j < psig->length; j++) - BIO_printf(mem, "%02x:", psig->data[j]); - push_certinfo("Signature", i); - } - - PEM_write_bio_X509(mem, x); - push_certinfo("Cert", i); - } - - BIO_free(mem); - - return CURLE_OK; -} - -/* - * Heavily modified from: - * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL - */ -static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, - const char *pinnedpubkey) -{ - /* Scratch */ - int len1 = 0, len2 = 0; - unsigned char *buff1 = NULL, *temp = NULL; - - /* Result is returned to caller */ - CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - - /* if a path wasn't specified, don't pin */ - if(!pinnedpubkey) - return CURLE_OK; - - if(!cert) - return result; - - do { - /* Begin Gyrations to get the subjectPublicKeyInfo */ - /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ - - /* https://groups.google.com/group/mailing.openssl.users/browse_thread - /thread/d61858dae102c6c7 */ - len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); - if(len1 < 1) - break; /* failed */ - - /* https://www.openssl.org/docs/crypto/buffer.html */ - buff1 = temp = malloc(len1); - if(!buff1) - break; /* failed */ - - /* https://www.openssl.org/docs/crypto/d2i_X509.html */ - len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp); - - /* - * These checks are verifying we got back the same values as when we - * sized the buffer. It's pretty weak since they should always be the - * same. But it gives us something to test. - */ - if((len1 != len2) || !temp || ((temp - buff1) != len1)) - break; /* failed */ - - /* End Gyrations */ - - /* The one good exit point */ - result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); - } while(0); - - /* https://www.openssl.org/docs/crypto/buffer.html */ - if(buff1) - free(buff1); - - return result; -} - -/* - * Get the server cert, verify it and show it etc, only call failf() if the - * 'strict' argument is TRUE as otherwise all this is for informational - * purposes only! - * - * We check certificates to authenticate the server; otherwise we risk - * man-in-the-middle attack. - */ -static CURLcode servercert(struct connectdata *conn, - struct ssl_connect_data *connssl, - bool strict) -{ - CURLcode result = CURLE_OK; - int rc; - long lerr, len; - struct Curl_easy *data = conn->data; - X509 *issuer; - FILE *fp; - char buffer[2048]; - const char *ptr; - long * const certverifyresult = SSL_IS_PROXY() ? - &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; - BIO *mem = BIO_new(BIO_s_mem()); - - if(data->set.ssl.certinfo) - /* we've been asked to gather certificate info! */ - (void)get_cert_chain(conn, connssl); - - BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle); - if(!BACKEND->server_cert) { - BIO_free(mem); - if(!strict) - return CURLE_OK; - - failf(data, "SSL: couldn't get peer certificate!"); - return CURLE_PEER_FAILED_VERIFICATION; - } - - infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); - - rc = x509_name_oneline(X509_get_subject_name(BACKEND->server_cert), - buffer, sizeof(buffer)); - infof(data, " subject: %s\n", rc?"[NONE]":buffer); - - ASN1_TIME_print(mem, X509_get0_notBefore(BACKEND->server_cert)); - len = BIO_get_mem_data(mem, (char **) &ptr); - infof(data, " start date: %.*s\n", len, ptr); - rc = BIO_reset(mem); - - ASN1_TIME_print(mem, X509_get0_notAfter(BACKEND->server_cert)); - len = BIO_get_mem_data(mem, (char **) &ptr); - infof(data, " expire date: %.*s\n", len, ptr); - rc = BIO_reset(mem); - - BIO_free(mem); - - if(SSL_CONN_CONFIG(verifyhost)) { - result = verifyhost(conn, BACKEND->server_cert); - if(result) { - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - return result; - } - } - - rc = x509_name_oneline(X509_get_issuer_name(BACKEND->server_cert), - buffer, sizeof(buffer)); - if(rc) { - if(strict) - failf(data, "SSL: couldn't get X509-issuer name!"); - result = CURLE_SSL_CONNECT_ERROR; - } - else { - infof(data, " issuer: %s\n", buffer); - - /* We could do all sorts of certificate verification stuff here before - deallocating the certificate. */ - - /* e.g. match issuer name with provided issuer certificate */ - if(SSL_SET_OPTION(issuercert)) { - fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT); - if(!fp) { - if(strict) - failf(data, "SSL: Unable to open issuer cert (%s)", - SSL_SET_OPTION(issuercert)); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - return CURLE_SSL_ISSUER_ERROR; - } - - issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL); - if(!issuer) { - if(strict) - failf(data, "SSL: Unable to read issuer cert (%s)", - SSL_SET_OPTION(issuercert)); - X509_free(BACKEND->server_cert); - X509_free(issuer); - fclose(fp); - return CURLE_SSL_ISSUER_ERROR; - } - - fclose(fp); - - if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) { - if(strict) - failf(data, "SSL: Certificate issuer check failed (%s)", - SSL_SET_OPTION(issuercert)); - X509_free(BACKEND->server_cert); - X509_free(issuer); - BACKEND->server_cert = NULL; - return CURLE_SSL_ISSUER_ERROR; - } - - infof(data, " SSL certificate issuer check ok (%s)\n", - SSL_SET_OPTION(issuercert)); - X509_free(issuer); - } - - lerr = *certverifyresult = SSL_get_verify_result(BACKEND->handle); - - if(*certverifyresult != X509_V_OK) { - if(SSL_CONN_CONFIG(verifypeer)) { - /* We probably never reach this, because SSL_connect() will fail - and we return earlier if verifypeer is set? */ - if(strict) - failf(data, "SSL certificate verify result: %s (%ld)", - X509_verify_cert_error_string(lerr), lerr); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, " SSL certificate verify result: %s (%ld)," - " continuing anyway.\n", - X509_verify_cert_error_string(lerr), lerr); - } - else - infof(data, " SSL certificate verify ok.\n"); - } - -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) - if(SSL_CONN_CONFIG(verifystatus)) { - result = verifystatus(conn, connssl); - if(result) { - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - return result; - } - } -#endif - - if(!strict) - /* when not strict, we don't bother about the verify cert problems */ - result = CURLE_OK; - - ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - if(!result && ptr) { - result = pkp_pin_peer_pubkey(data, BACKEND->server_cert, ptr); - if(result) - failf(data, "SSL: public key does not match pinned public key!"); - } - - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - connssl->connecting_state = ssl_connect_done; - - return result; -} - -static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - - if(SSL_SET_OPTION(primary.sessionid)) { - bool incache; - SSL_SESSION *our_ssl_sessionid; - void *old_ssl_sessionid = NULL; - - our_ssl_sessionid = SSL_get1_session(BACKEND->handle); - - /* SSL_get1_session() will increment the reference count and the session - will stay in memory until explicitly freed with SSL_SESSION_free(3), - regardless of its state. */ - - Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, - sockindex)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; - } - } - - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */, sockindex); - if(result) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "failed to store ssl session"); - return result; - } - } - else { - /* Session was incache, so refcount already incremented earlier. - * Avoid further increments with each SSL_get1_session() call. - * This does not free the session as refcount remains > 0 - */ - SSL_SESSION_free(our_ssl_sessionid); - } - Curl_ssl_sessionid_unlock(conn); - } - - /* - * We check certificates to authenticate the server; otherwise we risk - * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to - * verify the peer ignore faults and failures from the server cert - * operations. - */ - - result = servercert(conn, connssl, (SSL_CONN_CONFIG(verifypeer) || - SSL_CONN_CONFIG(verifyhost))); - - if(!result) - connssl->connecting_state = ssl_connect_done; - - return result; -} - -static Curl_recv ossl_recv; -static Curl_send ossl_send; - -static CURLcode ossl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - time_t timeout_ms; - int what; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - result = ossl_connect_step1(conn, sockindex); - if(result) - return result; - } - - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading || - connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if this - * connection is done nonblocking and this loop would execute again. This - * permits the owner of a multi handle to abort a connection attempt - * before step2 has completed while ensuring that a client using select() - * or epoll() will always have a valid fdset to wait on. - */ - result = ossl_connect_step2(conn, sockindex); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return result; - - } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3 == connssl->connecting_state) { - result = ossl_connect_step3(conn, sockindex); - if(result) - return result; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = ossl_recv; - conn->send[sockindex] = ossl_send; - *done = TRUE; - } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) -{ - return ossl_connect_common(conn, sockindex, TRUE, done); -} - -static CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done = FALSE; - - result = ossl_connect_common(conn, sockindex, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -static bool Curl_ossl_data_pending(const struct connectdata *conn, - int connindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex]; - if(BACKEND->handle) - /* SSL is in use */ - return (0 != SSL_pending(BACKEND->handle) || - (proxyssl->backend->handle && - 0 != SSL_pending(proxyssl->backend->handle))) ? - TRUE : FALSE; - return FALSE; -} - -static size_t Curl_ossl_version(char *buffer, size_t size); - -static ssize_t ossl_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - /* SSL_write() is said to return 'int' while write() and send() returns - 'size_t' */ - int err; - char error_buffer[256]; - unsigned long sslerror; - int memlen; - int rc; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - ERR_clear_error(); - - memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - rc = SSL_write(BACKEND->handle, mem, memlen); - - if(rc <= 0) { - err = SSL_get_error(BACKEND->handle, rc); - - switch(err) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - /* The operation did not complete; the same TLS/SSL I/O function - should be called again later. This is basically an EWOULDBLOCK - equivalent. */ - *curlcode = CURLE_AGAIN; - return -1; - case SSL_ERROR_SYSCALL: - failf(conn->data, "SSL_write() returned SYSCALL, errno = %d", - SOCKERRNO); - *curlcode = CURLE_SEND_ERROR; - return -1; - case SSL_ERROR_SSL: - /* A failure in the SSL library occurred, usually a protocol error. - The OpenSSL error queue contains more information on the error. */ - sslerror = ERR_get_error(); - if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL && - ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET && - conn->ssl[sockindex].state == ssl_connection_complete && - conn->proxy_ssl[sockindex].state == ssl_connection_complete) { - char ver[120]; - Curl_ossl_version(ver, 120); - failf(conn->data, "Error: %s does not support double SSL tunneling.", - ver); - } - else - failf(conn->data, "SSL_write() error: %s", - ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - /* a true error */ - failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d", - SSL_ERROR_to_str(err), SOCKERRNO); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - *curlcode = CURLE_OK; - return (ssize_t)rc; /* number of bytes */ -} - -static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *curlcode) -{ - char error_buffer[256]; - unsigned long sslerror; - ssize_t nread; - int buffsize; - struct ssl_connect_data *connssl = &conn->ssl[num]; - - ERR_clear_error(); - - buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); - if(nread <= 0) { - /* failed SSL_read */ - int err = SSL_get_error(BACKEND->handle, (int)nread); - - switch(err) { - case SSL_ERROR_NONE: /* this is not an error */ - case SSL_ERROR_ZERO_RETURN: /* no more data */ - break; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - /* there's data pending, re-invoke SSL_read() */ - *curlcode = CURLE_AGAIN; - return -1; - default: - /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return - value/errno" */ - /* https://www.openssl.org/docs/crypto/ERR_get_error.html */ - sslerror = ERR_get_error(); - if((nread < 0) || sslerror) { - /* If the return code was negative or there actually is an error in the - queue */ - failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d", - (sslerror ? - ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)) : - SSL_ERROR_to_str(err)), - SOCKERRNO); - *curlcode = CURLE_RECV_ERROR; - return -1; - } - } - } - return nread; -} - -static size_t Curl_ossl_version(char *buffer, size_t size) -{ -#ifdef OPENSSL_IS_BORINGSSL - return snprintf(buffer, size, OSSL_PACKAGE); -#else /* OPENSSL_IS_BORINGSSL */ - char sub[3]; - unsigned long ssleay_value; - sub[2]='\0'; - sub[1]='\0'; - ssleay_value = OpenSSL_version_num(); - if(ssleay_value < 0x906000) { - ssleay_value = SSLEAY_VERSION_NUMBER; - sub[0]='\0'; - } - else { - if(ssleay_value&0xff0) { - int minor_ver = (ssleay_value >> 4) & 0xff; - if(minor_ver > 26) { - /* handle extended version introduced for 0.9.8za */ - sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); - sub[0] = 'z'; - } - else { - sub[0] = (char) (minor_ver + 'a' - 1); - } - } - else - sub[0]='\0'; - } - - return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", - OSSL_PACKAGE, - (ssleay_value>>28)&0xf, - (ssleay_value>>20)&0xff, - (ssleay_value>>12)&0xff, - sub); -#endif /* OPENSSL_IS_BORINGSSL */ -} - -/* can be called with data == NULL */ -static CURLcode Curl_ossl_random(struct Curl_easy *data, - unsigned char *entropy, size_t length) -{ - int rc; - if(data) { - if(Curl_ossl_seed(data)) /* Initiate the seed if not already done */ - return CURLE_FAILED_INIT; /* couldn't seed for some reason */ - } - else { - if(!rand_enough()) - return CURLE_FAILED_INIT; - } - /* RAND_bytes() returns 1 on success, 0 otherwise. */ - rc = RAND_bytes(entropy, curlx_uztosi(length)); - return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT); -} - -static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum /* output */, - size_t unused) -{ - MD5_CTX MD5pw; - (void)unused; - MD5_Init(&MD5pw); - MD5_Update(&MD5pw, tmp, tmplen); - MD5_Final(md5sum, &MD5pw); - return CURLE_OK; -} - -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) -static void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum /* output */, - size_t unused) -{ - SHA256_CTX SHA256pw; - (void)unused; - SHA256_Init(&SHA256pw); - SHA256_Update(&SHA256pw, tmp, tmplen); - SHA256_Final(sha256sum, &SHA256pw); -} -#endif - -static bool Curl_ossl_cert_status_request(void) -{ -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) - return TRUE; -#else - return FALSE; -#endif -} - -static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info) -{ - /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ - return info == CURLINFO_TLS_SESSION ? - (void *)BACKEND->ctx : (void *)BACKEND->handle; -} - -const struct Curl_ssl Curl_ssl_openssl = { - { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */ - - 1, /* have_ca_path */ - 1, /* have_certinfo */ - 1, /* have_pinnedpubkey */ - 1, /* have_ssl_ctx */ - 1, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_ossl_init, /* init */ - Curl_ossl_cleanup, /* cleanup */ - Curl_ossl_version, /* version */ - Curl_ossl_check_cxn, /* check_cxn */ - Curl_ossl_shutdown, /* shutdown */ - Curl_ossl_data_pending, /* data_pending */ - Curl_ossl_random, /* random */ - Curl_ossl_cert_status_request, /* cert_status_request */ - Curl_ossl_connect, /* connect */ - Curl_ossl_connect_nonblocking, /* connect_nonblocking */ - Curl_ossl_get_internals, /* get_internals */ - Curl_ossl_close, /* close */ - Curl_ossl_close_all, /* close_all */ - Curl_ossl_session_free, /* session_free */ - Curl_ossl_set_engine, /* set_engine */ - Curl_ossl_set_engine_default, /* set_engine_default */ - Curl_ossl_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_ossl_md5sum, /* md5sum */ -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) - Curl_ossl_sha256sum /* sha256sum */ -#else - NULL /* sha256sum */ -#endif -}; - -#endif /* USE_OPENSSL */ diff --git a/dep/cpr/opt/curl/lib/vtls/openssl.h b/dep/cpr/opt/curl/lib/vtls/openssl.h deleted file mode 100644 index 114dc4baeb3..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/openssl.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HEADER_CURL_SSLUSE_H -#define HEADER_CURL_SSLUSE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_OPENSSL -/* - * This header should only be needed to get included by vtls.c and openssl.c - */ - -#include "urldata.h" - -extern const struct Curl_ssl Curl_ssl_openssl; - -#endif /* USE_OPENSSL */ -#endif /* HEADER_CURL_SSLUSE_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/polarssl.c b/dep/cpr/opt/curl/lib/vtls/polarssl.c deleted file mode 100644 index fc0644f8969..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/polarssl.c +++ /dev/null @@ -1,937 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * Copyright (C) 2010 - 2011, Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - * - */ - -#include "curl_setup.h" - -#ifdef USE_POLARSSL -#include -#include -#include -#include -#include -#include - -#if POLARSSL_VERSION_NUMBER < 0x01030000 -#error too old PolarSSL -#endif - -#include -#include -#include - -#include "urldata.h" -#include "sendf.h" -#include "inet_pton.h" -#include "polarssl.h" -#include "vtls.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "strcase.h" -#include "polarssl_threadlock.h" -#include "curl_printf.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* See https://tls.mbed.org/discussions/generic/ - howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der -*/ -#define RSA_PUB_DER_MAX_BYTES (38 + 2 * POLARSSL_MPI_MAX_SIZE) -#define ECP_PUB_DER_MAX_BYTES (30 + 2 * POLARSSL_ECP_MAX_BYTES) - -#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ - RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) - -struct ssl_backend_data { - ctr_drbg_context ctr_drbg; - entropy_context entropy; - ssl_context ssl; - int server_fd; - x509_crt cacert; - x509_crt clicert; - x509_crl crl; - rsa_context rsa; -}; - -#define BACKEND connssl->backend - -/* apply threading? */ -#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -#define THREADING_SUPPORT -#endif - -#ifndef POLARSSL_ERROR_C -#define error_strerror(x,y,z) -#endif /* POLARSSL_ERROR_C */ - - -#if defined(THREADING_SUPPORT) -static entropy_context entropy; - -static int entropy_init_initialized = 0; - -/* start of entropy_init_mutex() */ -static void entropy_init_mutex(entropy_context *ctx) -{ - /* lock 0 = entropy_init_mutex() */ - Curl_polarsslthreadlock_lock_function(0); - if(entropy_init_initialized == 0) { - entropy_init(ctx); - entropy_init_initialized = 1; - } - Curl_polarsslthreadlock_unlock_function(0); -} -/* end of entropy_init_mutex() */ - -/* start of entropy_func_mutex() */ -static int entropy_func_mutex(void *data, unsigned char *output, size_t len) -{ - int ret; - /* lock 1 = entropy_func_mutex() */ - Curl_polarsslthreadlock_lock_function(1); - ret = entropy_func(data, output, len); - Curl_polarsslthreadlock_unlock_function(1); - - return ret; -} -/* end of entropy_func_mutex() */ - -#endif /* THREADING_SUPPORT */ - -/* Define this to enable lots of debugging for PolarSSL */ -#undef POLARSSL_DEBUG - -#ifdef POLARSSL_DEBUG -static void polarssl_debug(void *context, int level, const char *line) -{ - struct Curl_easy *data = NULL; - - if(!context) - return; - - data = (struct Curl_easy *)context; - - infof(data, "%s", line); - (void) level; -} -#else -#endif - -/* ALPN for http2? */ -#ifdef POLARSSL_SSL_ALPN -# define HAS_ALPN -#endif - -static Curl_recv polarssl_recv; -static Curl_send polarssl_send; - -static CURLcode polarssl_version_from_curl(int *polarver, long ssl_version) -{ - switch(ssl_version) { - case CURL_SSLVERSION_TLSv1_0: - *polarver = SSL_MINOR_VERSION_1; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1: - *polarver = SSL_MINOR_VERSION_2; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2: - *polarver = SSL_MINOR_VERSION_3; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_3: - break; - } - return CURLE_SSL_CONNECT_ERROR; -} - -static CURLcode -set_ssl_version_min_max(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - int ssl_min_ver = SSL_MINOR_VERSION_1; - int ssl_max_ver = SSL_MINOR_VERSION_1; - CURLcode result = CURLE_OK; - - switch(ssl_version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - ssl_version = CURL_SSLVERSION_TLSv1_0; - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - ssl_version_max = ssl_version << 16; - break; - case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - result = polarssl_version_from_curl(&ssl_min_ver, ssl_version); - if(result) { - failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); - return result; - } - result = polarssl_version_from_curl(&ssl_max_ver, ssl_version_max >> 16); - if(result) { - failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); - return result; - } - - ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver); - ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver); - - return result; -} - -static CURLcode -polarssl_connect_step1(struct connectdata *conn, - int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - const char *capath = SSL_CONN_CONFIG(CApath); - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; - int ret = -1; - char errorbuf[128]; - errorbuf[0] = 0; - - /* PolarSSL only supports SSLv3 and TLSv1 */ - if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { - failf(data, "PolarSSL does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef THREADING_SUPPORT - entropy_init_mutex(&entropy); - - if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func_mutex, &entropy, - NULL, 0)) != 0) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); - } -#else - entropy_init(&BACKEND->entropy); - - if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func, &BACKEND->entropy, - NULL, 0)) != 0) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); - } -#endif /* THREADING_SUPPORT */ - - /* Load the trusted CA */ - memset(&BACKEND->cacert, 0, sizeof(x509_crt)); - - if(SSL_CONN_CONFIG(CAfile)) { - ret = x509_crt_parse_file(&BACKEND->cacert, - SSL_CONN_CONFIG(CAfile)); - - if(ret<0) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s", - SSL_CONN_CONFIG(CAfile), -ret, errorbuf); - - if(SSL_CONN_CONFIG(verifypeer)) - return CURLE_SSL_CACERT_BADFILE; - } - } - - if(capath) { - ret = x509_crt_parse_path(&BACKEND->cacert, capath); - - if(ret<0) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s", - capath, -ret, errorbuf); - - if(SSL_CONN_CONFIG(verifypeer)) - return CURLE_SSL_CACERT_BADFILE; - } - } - - /* Load the client certificate */ - memset(&BACKEND->clicert, 0, sizeof(x509_crt)); - - if(SSL_SET_OPTION(cert)) { - ret = x509_crt_parse_file(&BACKEND->clicert, - SSL_SET_OPTION(cert)); - - if(ret) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s", - SSL_SET_OPTION(cert), -ret, errorbuf); - - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load the client private key */ - if(SSL_SET_OPTION(key)) { - pk_context pk; - pk_init(&pk); - ret = pk_parse_keyfile(&pk, SSL_SET_OPTION(key), - SSL_SET_OPTION(key_passwd)); - if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA)) - ret = POLARSSL_ERR_PK_TYPE_MISMATCH; - if(ret == 0) - rsa_copy(&BACKEND->rsa, pk_rsa(pk)); - else - rsa_free(&BACKEND->rsa); - pk_free(&pk); - - if(ret) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s", - SSL_SET_OPTION(key), -ret, errorbuf); - - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load the CRL */ - memset(&BACKEND->crl, 0, sizeof(x509_crl)); - - if(SSL_SET_OPTION(CRLfile)) { - ret = x509_crl_parse_file(&BACKEND->crl, - SSL_SET_OPTION(CRLfile)); - - if(ret) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s", - SSL_SET_OPTION(CRLfile), -ret, errorbuf); - - return CURLE_SSL_CRL_BADFILE; - } - } - - infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port); - - if(ssl_init(&BACKEND->ssl)) { - failf(data, "PolarSSL: ssl_init failed"); - return CURLE_SSL_CONNECT_ERROR; - } - - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_1); - break; - case CURL_SSLVERSION_SSLv3: - ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_0); - ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_0); - infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n"); - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(conn, sockindex); - if(result != CURLE_OK) - return result; - break; - } - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - ssl_set_endpoint(&BACKEND->ssl, SSL_IS_CLIENT); - ssl_set_authmode(&BACKEND->ssl, SSL_VERIFY_OPTIONAL); - - ssl_set_rng(&BACKEND->ssl, ctr_drbg_random, - &BACKEND->ctr_drbg); - ssl_set_bio(&BACKEND->ssl, - net_recv, &conn->sock[sockindex], - net_send, &conn->sock[sockindex]); - - ssl_set_ciphersuites(&BACKEND->ssl, ssl_list_ciphersuites()); - - /* Check if there's a cached ID we can/should use here! */ - if(SSL_SET_OPTION(primary.sessionid)) { - void *old_session = NULL; - - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { - ret = ssl_set_session(&BACKEND->ssl, old_session); - if(ret) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "ssl_set_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; - } - infof(data, "PolarSSL re-using session\n"); - } - Curl_ssl_sessionid_unlock(conn); - } - - ssl_set_ca_chain(&BACKEND->ssl, - &BACKEND->cacert, - &BACKEND->crl, - hostname); - - ssl_set_own_cert_rsa(&BACKEND->ssl, - &BACKEND->clicert, &BACKEND->rsa); - - if(ssl_set_hostname(&BACKEND->ssl, hostname)) { - /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name - to set in the SNI extension. So even if curl connects to a host - specified as an IP address, this function must be used. */ - failf(data, "couldn't set hostname in PolarSSL"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - static const char *protocols[3]; - int cur = 0; - -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2) { - protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; - infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); - } -#endif - - protocols[cur++] = ALPN_HTTP_1_1; - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - - protocols[cur] = NULL; - - ssl_set_alpn_protocols(&BACKEND->ssl, protocols); - } -#endif - -#ifdef POLARSSL_DEBUG - ssl_set_dbg(&BACKEND->ssl, polarssl_debug, data); -#endif - - connssl->connecting_state = ssl_connect_2; - - return CURLE_OK; -} - -static CURLcode -polarssl_connect_step2(struct connectdata *conn, - int sockindex) -{ - int ret; - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - char buffer[1024]; - const char * const pinnedpubkey = SSL_IS_PROXY() ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - - - char errorbuf[128]; - errorbuf[0] = 0; - - conn->recv[sockindex] = polarssl_recv; - conn->send[sockindex] = polarssl_send; - - ret = ssl_handshake(&BACKEND->ssl); - - switch(ret) { - case 0: - break; - - case POLARSSL_ERR_NET_WANT_READ: - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - - case POLARSSL_ERR_NET_WANT_WRITE: - connssl->connecting_state = ssl_connect_2_writing; - return CURLE_OK; - - default: - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", - -ret, errorbuf); - return CURLE_SSL_CONNECT_ERROR; - } - - infof(data, "PolarSSL: Handshake complete, cipher is %s\n", - ssl_get_ciphersuite(&BACKEND->ssl) ); - - ret = ssl_get_verify_result(&BACKEND->ssl); - - if(ret && SSL_CONN_CONFIG(verifypeer)) { - if(ret & BADCERT_EXPIRED) - failf(data, "Cert verify failed: BADCERT_EXPIRED"); - - if(ret & BADCERT_REVOKED) { - failf(data, "Cert verify failed: BADCERT_REVOKED"); - return CURLE_SSL_CACERT; - } - - if(ret & BADCERT_CN_MISMATCH) - failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); - - if(ret & BADCERT_NOT_TRUSTED) - failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); - - return CURLE_PEER_FAILED_VERIFICATION; - } - - if(ssl_get_peer_cert(&(BACKEND->ssl))) { - /* If the session was resumed, there will be no peer certs */ - memset(buffer, 0, sizeof(buffer)); - - if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ", - ssl_get_peer_cert(&(BACKEND->ssl))) != -1) - infof(data, "Dumping cert info:\n%s\n", buffer); - } - - /* adapted from mbedtls.c */ - if(pinnedpubkey) { - int size; - CURLcode result; - x509_crt *p; - unsigned char pubkey[PUB_DER_MAX_BYTES]; - const x509_crt *peercert; - - peercert = ssl_get_peer_cert(&BACKEND->ssl); - - if(!peercert || !peercert->raw.p || !peercert->raw.len) { - failf(data, "Failed due to missing peer certificate"); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - p = calloc(1, sizeof(*p)); - - if(!p) - return CURLE_OUT_OF_MEMORY; - - x509_crt_init(p); - - /* Make a copy of our const peercert because pk_write_pubkey_der - needs a non-const key, for now. - https://github.com/ARMmbed/mbedtls/issues/396 */ - if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { - failf(data, "Failed copying peer certificate"); - x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); - - if(size <= 0) { - failf(data, "Failed copying public key from peer certificate"); - x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - /* pk_write_pubkey_der writes data at the end of the buffer. */ - result = Curl_pin_peer_pubkey(data, - pinnedpubkey, - &pubkey[PUB_DER_MAX_BYTES - size], size); - if(result) { - x509_crt_free(p); - free(p); - return result; - } - - x509_crt_free(p); - free(p); - } - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - const char *next_protocol = ssl_get_alpn_protocol(&BACKEND->ssl); - - if(next_protocol != NULL) { - infof(data, "ALPN, server accepted to use %s\n", next_protocol); - -#ifdef USE_NGHTTP2 - if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } - } - else - infof(data, "ALPN, server did not agree to a protocol\n"); - } -#endif - - connssl->connecting_state = ssl_connect_3; - infof(data, "SSL connected\n"); - - return CURLE_OK; -} - -static CURLcode -polarssl_connect_step3(struct connectdata *conn, - int sockindex) -{ - CURLcode retcode = CURLE_OK; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - - if(SSL_SET_OPTION(primary.sessionid)) { - int ret; - ssl_session *our_ssl_sessionid; - void *old_ssl_sessionid = NULL; - - our_ssl_sessionid = malloc(sizeof(ssl_session)); - if(!our_ssl_sessionid) - return CURLE_OUT_OF_MEMORY; - - memset(our_ssl_sessionid, 0, sizeof(ssl_session)); - - ret = ssl_get_session(&BACKEND->ssl, our_ssl_sessionid); - if(ret) { - failf(data, "ssl_get_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; - } - - /* If there's already a matching session in the cache, delete it */ - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); - Curl_ssl_sessionid_unlock(conn); - if(retcode) { - free(our_ssl_sessionid); - failf(data, "failed to store ssl session"); - return retcode; - } - } - - connssl->connecting_state = ssl_connect_done; - - return CURLE_OK; -} - -static ssize_t polarssl_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - int ret = -1; - - ret = ssl_write(&BACKEND->ssl, - (unsigned char *)mem, len); - - if(ret < 0) { - *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ? - CURLE_AGAIN : CURLE_SEND_ERROR; - ret = -1; - } - - return ret; -} - -static void Curl_polarssl_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - rsa_free(&BACKEND->rsa); - x509_crt_free(&BACKEND->clicert); - x509_crt_free(&BACKEND->cacert); - x509_crl_free(&BACKEND->crl); - ssl_free(&BACKEND->ssl); -} - -static ssize_t polarssl_recv(struct connectdata *conn, - int num, - char *buf, - size_t buffersize, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[num]; - int ret = -1; - ssize_t len = -1; - - memset(buf, 0, buffersize); - ret = ssl_read(&BACKEND->ssl, (unsigned char *)buf, buffersize); - - if(ret <= 0) { - if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) - return 0; - - *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ? - CURLE_AGAIN : CURLE_RECV_ERROR; - return -1; - } - - len = ret; - - return len; -} - -static void Curl_polarssl_session_free(void *ptr) -{ - ssl_session_free(ptr); - free(ptr); -} - -/* 1.3.10 was the first rebranded version. All new releases (in 1.3 branch and - higher) will be mbed TLS branded.. */ - -static size_t Curl_polarssl_version(char *buffer, size_t size) -{ - unsigned int version = version_get_number(); - return snprintf(buffer, size, "%s/%d.%d.%d", - version >= 0x01030A00?"mbedTLS":"PolarSSL", - version>>24, (version>>16)&0xff, (version>>8)&0xff); -} - -static CURLcode -polarssl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; - int what; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - result = polarssl_connect_step1(conn, sockindex); - if(result) - return result; - } - - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading || - connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if - * this connection is part of a multi handle and this loop would - * execute again. This permits the owner of a multi handle to - * abort a connection attempt before step2 has completed while - * ensuring that a client using select() or epoll() will always - * have a valid fdset to wait on. - */ - result = polarssl_connect_step2(conn, sockindex); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return result; - - } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3 == connssl->connecting_state) { - result = polarssl_connect_step3(conn, sockindex); - if(result) - return result; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = polarssl_recv; - conn->send[sockindex] = polarssl_send; - *done = TRUE; - } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - return polarssl_connect_common(conn, sockindex, TRUE, done); -} - - -static CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done = FALSE; - - result = polarssl_connect_common(conn, sockindex, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -/* - * return 0 error initializing SSL - * return 1 SSL initialized successfully - */ -static int Curl_polarssl_init(void) -{ - return Curl_polarsslthreadlock_thread_setup(); -} - -static void Curl_polarssl_cleanup(void) -{ - (void)Curl_polarsslthreadlock_thread_cleanup(); -} - -static bool Curl_polarssl_data_pending(const struct connectdata *conn, - int sockindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - return ssl_get_bytes_avail(&BACKEND->ssl) != 0; -} - -static void Curl_polarssl_sha256sum(const unsigned char *input, - size_t inputlen, - unsigned char *sha256sum, - size_t sha256len UNUSED_PARAM) -{ - (void)sha256len; - sha256(input, inputlen, sha256sum, 0); -} - -static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return &BACKEND->ssl; -} - -const struct Curl_ssl Curl_ssl_polarssl = { - { CURLSSLBACKEND_POLARSSL, "polarssl" }, /* info */ - - 1, /* have_ca_path */ - 0, /* have_certinfo */ - 1, /* have_pinnedpubkey */ - 0, /* have_ssl_ctx */ - 0, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_polarssl_init, /* init */ - Curl_polarssl_cleanup, /* cleanup */ - Curl_polarssl_version, /* version */ - Curl_none_check_cxn, /* check_cxn */ - Curl_none_shutdown, /* shutdown */ - Curl_polarssl_data_pending, /* data_pending */ - /* This might cause libcurl to use a weeker random! - * TODO: use Polarssl's CTR-DRBG or HMAC-DRBG - */ - Curl_none_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_polarssl_connect, /* connect */ - Curl_polarssl_connect_nonblocking, /* connect_nonblocking */ - Curl_polarssl_get_internals, /* get_internals */ - Curl_polarssl_close, /* close */ - Curl_none_close_all, /* close_all */ - Curl_polarssl_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - Curl_polarssl_sha256sum /* sha256sum */ -}; - -#endif /* USE_POLARSSL */ diff --git a/dep/cpr/opt/curl/lib/vtls/polarssl.h b/dep/cpr/opt/curl/lib/vtls/polarssl.h deleted file mode 100644 index 23c3636ee6a..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/polarssl.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef HEADER_CURL_POLARSSL_H -#define HEADER_CURL_POLARSSL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. - * Copyright (C) 2010, Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifdef USE_POLARSSL - -extern const struct Curl_ssl Curl_ssl_polarssl; - -#endif /* USE_POLARSSL */ -#endif /* HEADER_CURL_POLARSSL_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/polarssl_threadlock.c b/dep/cpr/opt/curl/lib/vtls/polarssl_threadlock.c deleted file mode 100644 index dd5fbd7ec24..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/polarssl_threadlock.c +++ /dev/null @@ -1,153 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2013-2017, Daniel Stenberg, , et al. - * Copyright (C) 2010, 2011, Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#if (defined(USE_POLARSSL) || defined(USE_MBEDTLS)) && \ - (defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)) - -#if defined(USE_THREADS_POSIX) -# ifdef HAVE_PTHREAD_H -# include -# endif -#elif defined(USE_THREADS_WIN32) -# ifdef HAVE_PROCESS_H -# include -# endif -#endif - -#include "polarssl_threadlock.h" -#include "curl_printf.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* number of thread locks */ -#define NUMT 2 - -/* This array will store all of the mutexes available to PolarSSL. */ -static POLARSSL_MUTEX_T *mutex_buf = NULL; - -int Curl_polarsslthreadlock_thread_setup(void) -{ - int i; - int ret; - - mutex_buf = calloc(NUMT * sizeof(POLARSSL_MUTEX_T), 1); - if(!mutex_buf) - return 0; /* error, no number of threads defined */ - -#ifdef HAVE_PTHREAD_H - for(i = 0; i < NUMT; i++) { - ret = pthread_mutex_init(&mutex_buf[i], NULL); - if(ret) - return 0; /* pthread_mutex_init failed */ - } -#elif defined(HAVE_PROCESS_H) - for(i = 0; i < NUMT; i++) { - mutex_buf[i] = CreateMutex(0, FALSE, 0); - if(mutex_buf[i] == 0) - return 0; /* CreateMutex failed */ - } -#endif /* HAVE_PTHREAD_H */ - - return 1; /* OK */ -} - -int Curl_polarsslthreadlock_thread_cleanup(void) -{ - int i; - int ret; - - if(!mutex_buf) - return 0; /* error, no threads locks defined */ - -#ifdef HAVE_PTHREAD_H - for(i = 0; i < NUMT; i++) { - ret = pthread_mutex_destroy(&mutex_buf[i]); - if(ret) - return 0; /* pthread_mutex_destroy failed */ - } -#elif defined(HAVE_PROCESS_H) - for(i = 0; i < NUMT; i++) { - ret = CloseHandle(mutex_buf[i]); - if(!ret) - return 0; /* CloseHandle failed */ - } -#endif /* HAVE_PTHREAD_H */ - free(mutex_buf); - mutex_buf = NULL; - - return 1; /* OK */ -} - -int Curl_polarsslthreadlock_lock_function(int n) -{ - int ret; -#ifdef HAVE_PTHREAD_H - if(n < NUMT) { - ret = pthread_mutex_lock(&mutex_buf[n]); - if(ret) { - DEBUGF(fprintf(stderr, - "Error: polarsslthreadlock_lock_function failed\n")); - return 0; /* pthread_mutex_lock failed */ - } - } -#elif defined(HAVE_PROCESS_H) - if(n < NUMT) { - ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0); - if(ret) { - DEBUGF(fprintf(stderr, - "Error: polarsslthreadlock_lock_function failed\n")); - return 0; /* pthread_mutex_lock failed */ - } - } -#endif /* HAVE_PTHREAD_H */ - return 1; /* OK */ -} - -int Curl_polarsslthreadlock_unlock_function(int n) -{ - int ret; -#ifdef HAVE_PTHREAD_H - if(n < NUMT) { - ret = pthread_mutex_unlock(&mutex_buf[n]); - if(ret) { - DEBUGF(fprintf(stderr, - "Error: polarsslthreadlock_unlock_function failed\n")); - return 0; /* pthread_mutex_unlock failed */ - } - } -#elif defined(HAVE_PROCESS_H) - if(n < NUMT) { - ret = ReleaseMutex(mutex_buf[n]); - if(!ret) { - DEBUGF(fprintf(stderr, - "Error: polarsslthreadlock_unlock_function failed\n")); - return 0; /* pthread_mutex_lock failed */ - } - } -#endif /* HAVE_PTHREAD_H */ - return 1; /* OK */ -} - -#endif /* USE_POLARSSL || USE_MBEDTLS */ diff --git a/dep/cpr/opt/curl/lib/vtls/polarssl_threadlock.h b/dep/cpr/opt/curl/lib/vtls/polarssl_threadlock.h deleted file mode 100644 index dda5359b819..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/polarssl_threadlock.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef HEADER_CURL_POLARSSL_THREADLOCK_H -#define HEADER_CURL_POLARSSL_THREADLOCK_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2013-2015, Daniel Stenberg, , et al. - * Copyright (C) 2010, Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#if (defined USE_POLARSSL) || (defined USE_MBEDTLS) - -#if defined(USE_THREADS_POSIX) -# define POLARSSL_MUTEX_T pthread_mutex_t -#elif defined(USE_THREADS_WIN32) -# define POLARSSL_MUTEX_T HANDLE -#endif - -#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) - -int Curl_polarsslthreadlock_thread_setup(void); -int Curl_polarsslthreadlock_thread_cleanup(void); -int Curl_polarsslthreadlock_lock_function(int n); -int Curl_polarsslthreadlock_unlock_function(int n); - -#else - -#define Curl_polarsslthreadlock_thread_setup() 1 -#define Curl_polarsslthreadlock_thread_cleanup() 1 -#define Curl_polarsslthreadlock_lock_function(x) 1 -#define Curl_polarsslthreadlock_unlock_function(x) 1 - -#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ - -#endif /* USE_POLARSSL */ - -#endif /* HEADER_CURL_POLARSSL_THREADLOCK_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/schannel.c b/dep/cpr/opt/curl/lib/vtls/schannel.c deleted file mode 100644 index 9ca1431bdb2..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/schannel.c +++ /dev/null @@ -1,1852 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2016, Marc Hoersken, - * Copyright (C) 2012, Mark Salisbury, - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all SChannel-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - * - */ - -/* - * Based upon the PolarSSL implementation in polarssl.c and polarssl.h: - * Copyright (C) 2010, 2011, Hoi-Ho Chan, - * - * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * Thanks for code and inspiration! - */ - -#include "curl_setup.h" - -#ifdef USE_SCHANNEL - -#ifndef USE_WINDOWS_SSPI -# error "Can't compile SCHANNEL support without SSPI." -#endif - -#include -#include -#include "curl_sspi.h" -#include "schannel.h" -#include "vtls.h" -#include "sendf.h" -#include "connect.h" /* for the connect timeout */ -#include "strerror.h" -#include "select.h" /* for the socket readyness */ -#include "inet_pton.h" /* for IP addr SNI check */ -#include "curl_multibyte.h" -#include "warnless.h" -#include "x509asn1.h" -#include "curl_printf.h" -#include "system_win32.h" -#include "hostcheck.h" - - /* The last #include file should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* ALPN requires version 8.1 of the Windows SDK, which was - shipped with Visual Studio 2013, aka _MSC_VER 1800: - - https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx -*/ -#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_) -# define HAS_ALPN 1 -#endif - -#ifndef UNISP_NAME_A -#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider" -#endif - -#ifndef UNISP_NAME_W -#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider" -#endif - -#ifndef UNISP_NAME -#ifdef UNICODE -#define UNISP_NAME UNISP_NAME_W -#else -#define UNISP_NAME UNISP_NAME_A -#endif -#endif - -#ifndef SP_PROT_SSL2_CLIENT -#define SP_PROT_SSL2_CLIENT 0x00000008 -#endif - -#ifndef SP_PROT_SSL3_CLIENT -#define SP_PROT_SSL3_CLIENT 0x00000008 -#endif - -#ifndef SP_PROT_TLS1_CLIENT -#define SP_PROT_TLS1_CLIENT 0x00000080 -#endif - -#ifndef SP_PROT_TLS1_0_CLIENT -#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT -#endif - -#ifndef SP_PROT_TLS1_1_CLIENT -#define SP_PROT_TLS1_1_CLIENT 0x00000200 -#endif - -#ifndef SP_PROT_TLS1_2_CLIENT -#define SP_PROT_TLS1_2_CLIENT 0x00000800 -#endif - -#ifndef SECBUFFER_ALERT -#define SECBUFFER_ALERT 17 -#endif - -/* Both schannel buffer sizes must be > 0 */ -#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 -#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 - -/* Uncomment to force verbose output - * #define infof(x, y, ...) printf(y, __VA_ARGS__) - * #define failf(x, y, ...) printf(y, __VA_ARGS__) - */ - -/* Structs to store Schannel handles */ -struct curl_schannel_cred { - CredHandle cred_handle; - TimeStamp time_stamp; - int refcount; -}; - -struct curl_schannel_ctxt { - CtxtHandle ctxt_handle; - TimeStamp time_stamp; -}; - -struct ssl_backend_data { - struct curl_schannel_cred *cred; - struct curl_schannel_ctxt *ctxt; - SecPkgContext_StreamSizes stream_sizes; - size_t encdata_length, decdata_length; - size_t encdata_offset, decdata_offset; - unsigned char *encdata_buffer, *decdata_buffer; - /* encdata_is_incomplete: if encdata contains only a partial record that - can't be decrypted without another Curl_read_plain (that is, status is - SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes - more bytes into encdata then set this back to false. */ - bool encdata_is_incomplete; - unsigned long req_flags, ret_flags; - CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ - bool recv_sspi_close_notify; /* true if connection closed by close_notify */ - bool recv_connection_closed; /* true if connection closed, regardless how */ - bool use_alpn; /* true if ALPN is used for this connection */ -}; - -#define BACKEND connssl->backend - -static Curl_recv schannel_recv; -static Curl_send schannel_send; - -#ifdef _WIN32_WCE -static CURLcode verify_certificate(struct connectdata *conn, int sockindex); -#endif - -static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType, - void *BufDataPtr, unsigned long BufByteSize) -{ - buffer->cbBuffer = BufByteSize; - buffer->BufferType = BufType; - buffer->pvBuffer = BufDataPtr; -} - -static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, - unsigned long NumArrElem) -{ - desc->ulVersion = SECBUFFER_VERSION; - desc->pBuffers = BufArr; - desc->cBuffers = NumArrElem; -} - -static CURLcode -set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - long i = ssl_version; - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - ssl_version_max = ssl_version << 16; - break; - case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - for(; i <= (ssl_version_max >> 16); ++i) { - switch(i) { - case CURL_SSLVERSION_TLSv1_0: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_1: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_2: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_3: - failf(data, "Schannel: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; - } - } - return CURLE_OK; -} - -static CURLcode -schannel_connect_step1(struct connectdata *conn, int sockindex) -{ - ssize_t written = -1; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SecBuffer outbuf; - SecBufferDesc outbuf_desc; - SecBuffer inbuf; - SecBufferDesc inbuf_desc; -#ifdef HAS_ALPN - unsigned char alpn_buffer[128]; -#endif - SCHANNEL_CRED schannel_cred; - SECURITY_STATUS sspi_status = SEC_E_OK; - struct curl_schannel_cred *old_cred = NULL; - struct in_addr addr; -#ifdef ENABLE_IPV6 - struct in6_addr addr6; -#endif - TCHAR *host_name; - CURLcode result; - char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - - infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", - hostname, conn->remote_port); - - if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT, - VERSION_LESS_THAN_EQUAL)) { - /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and - algorithms that may not be supported by all servers. */ - infof(data, "schannel: WinSSL version is old and may not be able to " - "connect to some servers due to lack of SNI, algorithms, etc.\n"); - } - -#ifdef HAS_ALPN - /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. - Also it doesn't seem to be supported for Wine, see curl bug #983. */ - BACKEND->use_alpn = conn->bits.tls_enable_alpn && - !GetProcAddress(GetModuleHandleA("ntdll"), - "wine_get_version") && - Curl_verify_windows_version(6, 3, PLATFORM_WINNT, - VERSION_GREATER_THAN_EQUAL); -#else - BACKEND->use_alpn = false; -#endif - - BACKEND->cred = NULL; - - /* check for an existing re-usable credential handle */ - if(SSL_SET_OPTION(primary.sessionid)) { - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) { - BACKEND->cred = old_cred; - infof(data, "schannel: re-using existing credential handle\n"); - - /* increment the reference counter of the credential/session handle */ - BACKEND->cred->refcount++; - infof(data, "schannel: incremented credential handle refcount = %d\n", - BACKEND->cred->refcount); - } - Curl_ssl_sessionid_unlock(conn); - } - - if(!BACKEND->cred) { - /* setup Schannel API options */ - memset(&schannel_cred, 0, sizeof(schannel_cred)); - schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; - - if(conn->ssl_config.verifypeer) { -#ifdef _WIN32_WCE - /* certificate validation on CE doesn't seem to work right; we'll - do it following a more manual process. */ - schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | - SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE; -#else - schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; - /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */ - if(data->set.ssl.no_revoke) - schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE; - else - schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; -#endif - if(data->set.ssl.no_revoke) - infof(data, "schannel: disabled server certificate revocation " - "checks\n"); - else - infof(data, "schannel: checking server certificate revocation\n"); - } - else { - schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | - SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE; - infof(data, "schannel: disabled server certificate revocation checks\n"); - } - - if(!conn->ssl_config.verifyhost) { - schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; - infof(data, "schannel: verifyhost setting prevents Schannel from " - "comparing the supplied target name with the subject " - "names in server certificates.\n"); - } - - switch(conn->ssl_config.version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | - SP_PROT_TLS1_1_CLIENT | - SP_PROT_TLS1_2_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - result = set_ssl_version_min_max(&schannel_cred, conn); - if(result != CURLE_OK) - return result; - break; - } - case CURL_SSLVERSION_SSLv3: - schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; - break; - case CURL_SSLVERSION_SSLv2: - schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT; - break; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - /* allocate memory for the re-usable credential handle */ - BACKEND->cred = (struct curl_schannel_cred *) - malloc(sizeof(struct curl_schannel_cred)); - if(!BACKEND->cred) { - failf(data, "schannel: unable to allocate memory"); - return CURLE_OUT_OF_MEMORY; - } - memset(BACKEND->cred, 0, sizeof(struct curl_schannel_cred)); - BACKEND->cred->refcount = 1; - - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx - */ - sspi_status = - s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, - SECPKG_CRED_OUTBOUND, NULL, - &schannel_cred, NULL, NULL, - &BACKEND->cred->cred_handle, - &BACKEND->cred->time_stamp); - - if(sspi_status != SEC_E_OK) { - if(sspi_status == SEC_E_WRONG_PRINCIPAL) - failf(data, "schannel: SNI or certificate check failed: %s", - Curl_sspi_strerror(conn, sspi_status)); - else - failf(data, "schannel: AcquireCredentialsHandle failed: %s", - Curl_sspi_strerror(conn, sspi_status)); - Curl_safefree(BACKEND->cred); - return CURLE_SSL_CONNECT_ERROR; - } - } - - /* Warn if SNI is disabled due to use of an IP address */ - if(Curl_inet_pton(AF_INET, hostname, &addr) -#ifdef ENABLE_IPV6 - || Curl_inet_pton(AF_INET6, hostname, &addr6) -#endif - ) { - infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); - } - -#ifdef HAS_ALPN - if(BACKEND->use_alpn) { - int cur = 0; - int list_start_index = 0; - unsigned int *extension_len = NULL; - unsigned short* list_len = NULL; - - /* The first four bytes will be an unsigned int indicating number - of bytes of data in the rest of the the buffer. */ - extension_len = (unsigned int *)(&alpn_buffer[cur]); - cur += sizeof(unsigned int); - - /* The next four bytes are an indicator that this buffer will contain - ALPN data, as opposed to NPN, for example. */ - *(unsigned int *)&alpn_buffer[cur] = - SecApplicationProtocolNegotiationExt_ALPN; - cur += sizeof(unsigned int); - - /* The next two bytes will be an unsigned short indicating the number - of bytes used to list the preferred protocols. */ - list_len = (unsigned short*)(&alpn_buffer[cur]); - cur += sizeof(unsigned short); - - list_start_index = cur; - -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2) { - memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN); - cur += NGHTTP2_PROTO_ALPN_LEN; - infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); - } -#endif - - alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH; - memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - cur += ALPN_HTTP_1_1_LENGTH; - infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1); - - *list_len = curlx_uitous(cur - list_start_index); - *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); - - InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); - InitSecBufferDesc(&inbuf_desc, &inbuf, 1); - } - else - { - InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&inbuf_desc, &inbuf, 1); - } -#else /* HAS_ALPN */ - InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&inbuf_desc, &inbuf, 1); -#endif - - /* setup output buffer */ - InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&outbuf_desc, &outbuf, 1); - - /* setup request flags */ - BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | - ISC_REQ_STREAM; - - /* allocate memory for the security context handle */ - BACKEND->ctxt = (struct curl_schannel_ctxt *) - malloc(sizeof(struct curl_schannel_ctxt)); - if(!BACKEND->ctxt) { - failf(data, "schannel: unable to allocate memory"); - return CURLE_OUT_OF_MEMORY; - } - memset(BACKEND->ctxt, 0, sizeof(struct curl_schannel_ctxt)); - - host_name = Curl_convert_UTF8_to_tchar(hostname); - if(!host_name) - return CURLE_OUT_OF_MEMORY; - - /* Schannel InitializeSecurityContext: - https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx - - At the moment we don't pass inbuf unless we're using ALPN since we only - use it for that, and Wine (for which we currently disable ALPN) is giving - us problems with inbuf regardless. https://github.com/curl/curl/issues/983 - */ - sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0, - (BACKEND->use_alpn ? &inbuf_desc : NULL), - 0, &BACKEND->ctxt->ctxt_handle, - &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); - - Curl_unicodefree(host_name); - - if(sspi_status != SEC_I_CONTINUE_NEEDED) { - if(sspi_status == SEC_E_WRONG_PRINCIPAL) - failf(data, "schannel: SNI or certificate check failed: %s", - Curl_sspi_strerror(conn, sspi_status)); - else - failf(data, "schannel: initial InitializeSecurityContext failed: %s", - Curl_sspi_strerror(conn, sspi_status)); - Curl_safefree(BACKEND->ctxt); - return CURLE_SSL_CONNECT_ERROR; - } - - infof(data, "schannel: sending initial handshake data: " - "sending %lu bytes...\n", outbuf.cbBuffer); - - /* send initial handshake data which is now stored in output buffer */ - result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, - outbuf.cbBuffer, &written); - s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); - if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { - failf(data, "schannel: failed to send initial handshake data: " - "sent %zd of %lu bytes", written, outbuf.cbBuffer); - return CURLE_SSL_CONNECT_ERROR; - } - - infof(data, "schannel: sent initial handshake data: " - "sent %zd bytes\n", written); - - BACKEND->recv_unrecoverable_err = CURLE_OK; - BACKEND->recv_sspi_close_notify = false; - BACKEND->recv_connection_closed = false; - BACKEND->encdata_is_incomplete = false; - - /* continue to second handshake step */ - connssl->connecting_state = ssl_connect_2; - - return CURLE_OK; -} - -static CURLcode -schannel_connect_step2(struct connectdata *conn, int sockindex) -{ - int i; - ssize_t nread = -1, written = -1; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - unsigned char *reallocated_buffer; - size_t reallocated_length; - SecBuffer outbuf[3]; - SecBufferDesc outbuf_desc; - SecBuffer inbuf[2]; - SecBufferDesc inbuf_desc; - SECURITY_STATUS sspi_status = SEC_E_OK; - TCHAR *host_name; - CURLcode result; - bool doread; - char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - - doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; - - infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n", - hostname, conn->remote_port); - - if(!BACKEND->cred || !BACKEND->ctxt) - return CURLE_SSL_CONNECT_ERROR; - - /* buffer to store previously received and decrypted data */ - if(BACKEND->decdata_buffer == NULL) { - BACKEND->decdata_offset = 0; - BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - BACKEND->decdata_buffer = malloc(BACKEND->decdata_length); - if(BACKEND->decdata_buffer == NULL) { - failf(data, "schannel: unable to allocate memory"); - return CURLE_OUT_OF_MEMORY; - } - } - - /* buffer to store previously received and encrypted data */ - if(BACKEND->encdata_buffer == NULL) { - BACKEND->encdata_is_incomplete = false; - BACKEND->encdata_offset = 0; - BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - BACKEND->encdata_buffer = malloc(BACKEND->encdata_length); - if(BACKEND->encdata_buffer == NULL) { - failf(data, "schannel: unable to allocate memory"); - return CURLE_OUT_OF_MEMORY; - } - } - - /* if we need a bigger buffer to read a full message, increase buffer now */ - if(BACKEND->encdata_length - BACKEND->encdata_offset < - CURL_SCHANNEL_BUFFER_FREE_SIZE) { - /* increase internal encrypted data buffer */ - reallocated_length = BACKEND->encdata_offset + - CURL_SCHANNEL_BUFFER_FREE_SIZE; - reallocated_buffer = realloc(BACKEND->encdata_buffer, - reallocated_length); - - if(reallocated_buffer == NULL) { - failf(data, "schannel: unable to re-allocate memory"); - return CURLE_OUT_OF_MEMORY; - } - else { - BACKEND->encdata_buffer = reallocated_buffer; - BACKEND->encdata_length = reallocated_length; - } - } - - for(;;) { - if(doread) { - /* read encrypted handshake data from socket */ - result = Curl_read_plain(conn->sock[sockindex], - (char *) (BACKEND->encdata_buffer + - BACKEND->encdata_offset), - BACKEND->encdata_length - - BACKEND->encdata_offset, - &nread); - if(result == CURLE_AGAIN) { - if(connssl->connecting_state != ssl_connect_2_writing) - connssl->connecting_state = ssl_connect_2_reading; - infof(data, "schannel: failed to receive handshake, " - "need more data\n"); - return CURLE_OK; - } - else if((result != CURLE_OK) || (nread == 0)) { - failf(data, "schannel: failed to receive handshake, " - "SSL/TLS connection failed"); - return CURLE_SSL_CONNECT_ERROR; - } - - /* increase encrypted data buffer offset */ - BACKEND->encdata_offset += nread; - BACKEND->encdata_is_incomplete = false; - infof(data, "schannel: encrypted data got %zd\n", nread); - } - - infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - BACKEND->encdata_offset, BACKEND->encdata_length); - - /* setup input buffers */ - InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset), - curlx_uztoul(BACKEND->encdata_offset)); - InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&inbuf_desc, inbuf, 2); - - /* setup output buffers */ - InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); - InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); - InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&outbuf_desc, outbuf, 3); - - if(inbuf[0].pvBuffer == NULL) { - failf(data, "schannel: unable to allocate memory"); - return CURLE_OUT_OF_MEMORY; - } - - /* copy received handshake data into input buffer */ - memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer, - BACKEND->encdata_offset); - - host_name = Curl_convert_UTF8_to_tchar(hostname); - if(!host_name) - return CURLE_OUT_OF_MEMORY; - - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx - */ - sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, - host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL, - &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); - - Curl_unicodefree(host_name); - - /* free buffer for received handshake data */ - Curl_safefree(inbuf[0].pvBuffer); - - /* check if the handshake was incomplete */ - if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - BACKEND->encdata_is_incomplete = true; - connssl->connecting_state = ssl_connect_2_reading; - infof(data, "schannel: received incomplete message, need more data\n"); - return CURLE_OK; - } - - /* If the server has requested a client certificate, attempt to continue - the handshake without one. This will allow connections to servers which - request a client certificate but do not require it. */ - if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && - !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { - BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; - connssl->connecting_state = ssl_connect_2_writing; - infof(data, "schannel: a client certificate has been requested\n"); - return CURLE_OK; - } - - /* check if the handshake needs to be continued */ - if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) { - for(i = 0; i < 3; i++) { - /* search for handshake tokens that need to be send */ - if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { - infof(data, "schannel: sending next handshake data: " - "sending %lu bytes...\n", outbuf[i].cbBuffer); - - /* send handshake token to server */ - result = Curl_write_plain(conn, conn->sock[sockindex], - outbuf[i].pvBuffer, outbuf[i].cbBuffer, - &written); - if((result != CURLE_OK) || - (outbuf[i].cbBuffer != (size_t) written)) { - failf(data, "schannel: failed to send next handshake data: " - "sent %zd of %lu bytes", written, outbuf[i].cbBuffer); - return CURLE_SSL_CONNECT_ERROR; - } - } - - /* free obsolete buffer */ - if(outbuf[i].pvBuffer != NULL) { - s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer); - } - } - } - else { - if(sspi_status == SEC_E_WRONG_PRINCIPAL) - failf(data, "schannel: SNI or certificate check failed: %s", - Curl_sspi_strerror(conn, sspi_status)); - else - failf(data, "schannel: next InitializeSecurityContext failed: %s", - Curl_sspi_strerror(conn, sspi_status)); - return sspi_status == SEC_E_UNTRUSTED_ROOT ? - CURLE_SSL_CACERT : CURLE_SSL_CONNECT_ERROR; - } - - /* check if there was additional remaining encrypted data */ - if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { - infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer); - /* - There are two cases where we could be getting extra data here: - 1) If we're renegotiating a connection and the handshake is already - complete (from the server perspective), it can encrypted app data - (not handshake data) in an extra buffer at this point. - 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a - connection and this extra data is part of the handshake. - We should process the data immediately; waiting for the socket to - be ready may fail since the server is done sending handshake data. - */ - /* check if the remaining data is less than the total amount - and therefore begins after the already processed data */ - if(BACKEND->encdata_offset > inbuf[1].cbBuffer) { - memmove(BACKEND->encdata_buffer, - (BACKEND->encdata_buffer + BACKEND->encdata_offset) - - inbuf[1].cbBuffer, inbuf[1].cbBuffer); - BACKEND->encdata_offset = inbuf[1].cbBuffer; - if(sspi_status == SEC_I_CONTINUE_NEEDED) { - doread = FALSE; - continue; - } - } - } - else { - BACKEND->encdata_offset = 0; - } - break; - } - - /* check if the handshake needs to be continued */ - if(sspi_status == SEC_I_CONTINUE_NEEDED) { - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - } - - /* check if the handshake is complete */ - if(sspi_status == SEC_E_OK) { - connssl->connecting_state = ssl_connect_3; - infof(data, "schannel: SSL/TLS handshake complete\n"); - } - -#ifdef _WIN32_WCE - /* Windows CE doesn't do any server certificate validation. - We have to do it manually. */ - if(conn->ssl_config.verifypeer) - return verify_certificate(conn, sockindex); -#endif - - return CURLE_OK; -} - -static CURLcode -schannel_connect_step3(struct connectdata *conn, int sockindex) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SECURITY_STATUS sspi_status = SEC_E_OK; - CERT_CONTEXT *ccert_context = NULL; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; -#endif -#ifdef HAS_ALPN - SecPkgContext_ApplicationProtocol alpn_result; -#endif - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - - infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n", - hostname, conn->remote_port); - - if(!BACKEND->cred) - return CURLE_SSL_CONNECT_ERROR; - - /* check if the required context attributes are met */ - if(BACKEND->ret_flags != BACKEND->req_flags) { - if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT)) - failf(data, "schannel: failed to setup sequence detection"); - if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT)) - failf(data, "schannel: failed to setup replay detection"); - if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY)) - failf(data, "schannel: failed to setup confidentiality"); - if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY)) - failf(data, "schannel: failed to setup memory allocation"); - if(!(BACKEND->ret_flags & ISC_RET_STREAM)) - failf(data, "schannel: failed to setup stream orientation"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef HAS_ALPN - if(BACKEND->use_alpn) { - sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, - SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); - - if(sspi_status != SEC_E_OK) { - failf(data, "schannel: failed to retrieve ALPN result"); - return CURLE_SSL_CONNECT_ERROR; - } - - if(alpn_result.ProtoNegoStatus == - SecApplicationProtocolNegotiationStatus_Success) { - - infof(data, "schannel: ALPN, server accepted to use %.*s\n", - alpn_result.ProtocolIdSize, alpn_result.ProtocolId); - -#ifdef USE_NGHTTP2 - if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN && - !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId, - NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, - ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } - } - else - infof(data, "ALPN, server did not agree to a protocol\n"); - } -#endif - - /* save the current session data for possible re-use */ - if(SSL_SET_OPTION(primary.sessionid)) { - bool incache; - struct curl_schannel_cred *old_cred = NULL; - - Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, - sockindex)); - if(incache) { - if(old_cred != BACKEND->cred) { - infof(data, "schannel: old credential handle is stale, removing\n"); - /* we're not taking old_cred ownership here, no refcount++ is needed */ - Curl_ssl_delsessionid(conn, (void *)old_cred); - incache = FALSE; - } - } - if(!incache) { - result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred, - sizeof(struct curl_schannel_cred), - sockindex); - if(result) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "schannel: failed to store credential handle"); - return result; - } - else { - /* this cred session is now also referenced by sessionid cache */ - BACKEND->cred->refcount++; - infof(data, "schannel: stored credential handle in session cache\n"); - } - } - Curl_ssl_sessionid_unlock(conn); - } - - if(data->set.ssl.certinfo) { - sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, - SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); - - if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) { - failf(data, "schannel: failed to retrieve remote cert context"); - return CURLE_SSL_CONNECT_ERROR; - } - - result = Curl_ssl_init_certinfo(data, 1); - if(!result) { - if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) && - (ccert_context->cbCertEncoded > 0)) { - - const char *beg = (const char *) ccert_context->pbCertEncoded; - const char *end = beg + ccert_context->cbCertEncoded; - result = Curl_extract_certinfo(conn, 0, beg, end); - } - } - CertFreeCertificateContext(ccert_context); - if(result) - return result; - } - - connssl->connecting_state = ssl_connect_done; - - return CURLE_OK; -} - -static CURLcode -schannel_connect_common(struct connectdata *conn, int sockindex, - bool nonblocking, bool *done) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - time_t timeout_ms; - int what; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - if(ssl_connect_1 == connssl->connecting_state) { - /* check out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL/TLS connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - result = schannel_connect_step1(conn, sockindex); - if(result) - return result; - } - - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* check out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL/TLS connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL/TLS connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if - * this connection is part of a multi handle and this loop would - * execute again. This permits the owner of a multi handle to - * abort a connection attempt before step2 has completed while - * ensuring that a client using select() or epoll() will always - * have a valid fdset to wait on. - */ - result = schannel_connect_step2(conn, sockindex); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return result; - - } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3 == connssl->connecting_state) { - result = schannel_connect_step3(conn, sockindex); - if(result) - return result; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = schannel_recv; - conn->send[sockindex] = schannel_send; - *done = TRUE; - } - else - *done = FALSE; - - /* reset our connection state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static ssize_t -schannel_send(struct connectdata *conn, int sockindex, - const void *buf, size_t len, CURLcode *err) -{ - ssize_t written = -1; - size_t data_len = 0; - unsigned char *data = NULL; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SecBuffer outbuf[4]; - SecBufferDesc outbuf_desc; - SECURITY_STATUS sspi_status = SEC_E_OK; - CURLcode result; - - /* check if the maximum stream sizes were queried */ - if(BACKEND->stream_sizes.cbMaximumMessage == 0) { - sspi_status = s_pSecFn->QueryContextAttributes( - &BACKEND->ctxt->ctxt_handle, - SECPKG_ATTR_STREAM_SIZES, - &BACKEND->stream_sizes); - if(sspi_status != SEC_E_OK) { - *err = CURLE_SEND_ERROR; - return -1; - } - } - - /* check if the buffer is longer than the maximum message length */ - if(len > BACKEND->stream_sizes.cbMaximumMessage) { - len = BACKEND->stream_sizes.cbMaximumMessage; - } - - /* calculate the complete message length and allocate a buffer for it */ - data_len = BACKEND->stream_sizes.cbHeader + len + - BACKEND->stream_sizes.cbTrailer; - data = (unsigned char *) malloc(data_len); - if(data == NULL) { - *err = CURLE_OUT_OF_MEMORY; - return -1; - } - - /* setup output buffers (header, data, trailer, empty) */ - InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, - data, BACKEND->stream_sizes.cbHeader); - InitSecBuffer(&outbuf[1], SECBUFFER_DATA, - data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len)); - InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, - data + BACKEND->stream_sizes.cbHeader + len, - BACKEND->stream_sizes.cbTrailer); - InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&outbuf_desc, outbuf, 4); - - /* copy data into output buffer */ - memcpy(outbuf[1].pvBuffer, buf, len); - - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ - sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0, - &outbuf_desc, 0); - - /* check if the message was encrypted */ - if(sspi_status == SEC_E_OK) { - written = 0; - - /* send the encrypted message including header, data and trailer */ - len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; - - /* - It's important to send the full message which includes the header, - encrypted payload, and trailer. Until the client receives all the - data a coherent message has not been delivered and the client - can't read any of it. - - If we wanted to buffer the unwritten encrypted bytes, we would - tell the client that all data it has requested to be sent has been - sent. The unwritten encrypted bytes would be the first bytes to - send on the next invocation. - Here's the catch with this - if we tell the client that all the - bytes have been sent, will the client call this method again to - send the buffered data? Looking at who calls this function, it - seems the answer is NO. - */ - - /* send entire message or fail */ - while(len > (size_t)written) { - ssize_t this_write; - time_t timeleft; - int what; - - this_write = 0; - - timeleft = Curl_timeleft(conn->data, NULL, FALSE); - if(timeleft < 0) { - /* we already got the timeout */ - failf(conn->data, "schannel: timed out sending data " - "(bytes sent: %zd)", written); - *err = CURLE_OPERATION_TIMEDOUT; - written = -1; - break; - } - - what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft); - if(what < 0) { - /* fatal error */ - failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - *err = CURLE_SEND_ERROR; - written = -1; - break; - } - else if(0 == what) { - failf(conn->data, "schannel: timed out sending data " - "(bytes sent: %zd)", written); - *err = CURLE_OPERATION_TIMEDOUT; - written = -1; - break; - } - /* socket is writable */ - - result = Curl_write_plain(conn, conn->sock[sockindex], data + written, - len - written, &this_write); - if(result == CURLE_AGAIN) - continue; - else if(result != CURLE_OK) { - *err = result; - written = -1; - break; - } - - written += this_write; - } - } - else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) { - *err = CURLE_OUT_OF_MEMORY; - } - else{ - *err = CURLE_SEND_ERROR; - } - - Curl_safefree(data); - - if(len == (size_t)written) - /* Encrypted message including header, data and trailer entirely sent. - The return value is the number of unencrypted bytes that were sent. */ - written = outbuf[1].cbBuffer; - - return written; -} - -static ssize_t -schannel_recv(struct connectdata *conn, int sockindex, - char *buf, size_t len, CURLcode *err) -{ - size_t size = 0; - ssize_t nread = -1; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - unsigned char *reallocated_buffer; - size_t reallocated_length; - bool done = FALSE; - SecBuffer inbuf[4]; - SecBufferDesc inbuf_desc; - SECURITY_STATUS sspi_status = SEC_E_OK; - /* we want the length of the encrypted buffer to be at least large enough - that it can hold all the bytes requested and some TLS record overhead. */ - size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; - - /**************************************************************************** - * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup. - * The pattern for return error is set *err, optional infof, goto cleanup. - * - * Our priority is to always return as much decrypted data to the caller as - * possible, even if an error occurs. The state of the decrypted buffer must - * always be valid. Transfer of decrypted data to the caller's buffer is - * handled in the cleanup. - */ - - infof(data, "schannel: client wants to read %zu bytes\n", len); - *err = CURLE_OK; - - if(len && len <= BACKEND->decdata_offset) { - infof(data, "schannel: enough decrypted data is already available\n"); - goto cleanup; - } - else if(BACKEND->recv_unrecoverable_err) { - *err = BACKEND->recv_unrecoverable_err; - infof(data, "schannel: an unrecoverable error occurred in a prior call\n"); - goto cleanup; - } - else if(BACKEND->recv_sspi_close_notify) { - /* once a server has indicated shutdown there is no more encrypted data */ - infof(data, "schannel: server indicated shutdown in a prior call\n"); - goto cleanup; - } - else if(!len) { - /* It's debatable what to return when !len. Regardless we can't return - immediately because there may be data to decrypt (in the case we want to - decrypt all encrypted cached data) so handle !len later in cleanup. - */ - ; /* do nothing */ - } - else if(!BACKEND->recv_connection_closed) { - /* increase enc buffer in order to fit the requested amount of data */ - size = BACKEND->encdata_length - BACKEND->encdata_offset; - if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || - BACKEND->encdata_length < min_encdata_length) { - reallocated_length = BACKEND->encdata_offset + - CURL_SCHANNEL_BUFFER_FREE_SIZE; - if(reallocated_length < min_encdata_length) { - reallocated_length = min_encdata_length; - } - reallocated_buffer = realloc(BACKEND->encdata_buffer, - reallocated_length); - if(reallocated_buffer == NULL) { - *err = CURLE_OUT_OF_MEMORY; - failf(data, "schannel: unable to re-allocate memory"); - goto cleanup; - } - - BACKEND->encdata_buffer = reallocated_buffer; - BACKEND->encdata_length = reallocated_length; - size = BACKEND->encdata_length - BACKEND->encdata_offset; - infof(data, "schannel: encdata_buffer resized %zu\n", - BACKEND->encdata_length); - } - - infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - BACKEND->encdata_offset, BACKEND->encdata_length); - - /* read encrypted data from socket */ - *err = Curl_read_plain(conn->sock[sockindex], - (char *)(BACKEND->encdata_buffer + - BACKEND->encdata_offset), - size, &nread); - if(*err) { - nread = -1; - if(*err == CURLE_AGAIN) - infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n"); - else if(*err == CURLE_RECV_ERROR) - infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n"); - else - infof(data, "schannel: Curl_read_plain returned error %d\n", *err); - } - else if(nread == 0) { - BACKEND->recv_connection_closed = true; - infof(data, "schannel: server closed the connection\n"); - } - else if(nread > 0) { - BACKEND->encdata_offset += (size_t)nread; - BACKEND->encdata_is_incomplete = false; - infof(data, "schannel: encrypted data got %zd\n", nread); - } - } - - infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - BACKEND->encdata_offset, BACKEND->encdata_length); - - /* decrypt loop */ - while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK && - (!len || BACKEND->decdata_offset < len || - BACKEND->recv_connection_closed)) { - /* prepare data buffer for DecryptMessage call */ - InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer, - curlx_uztoul(BACKEND->encdata_offset)); - - /* we need 3 more empty input buffers for possible output */ - InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); - InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0); - InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&inbuf_desc, inbuf, 4); - - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx - */ - sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle, - &inbuf_desc, 0, NULL); - - /* check if everything went fine (server may want to renegotiate - or shutdown the connection context) */ - if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE || - sspi_status == SEC_I_CONTEXT_EXPIRED) { - /* check for successfully decrypted data, even before actual - renegotiation or shutdown of the connection context */ - if(inbuf[1].BufferType == SECBUFFER_DATA) { - infof(data, "schannel: decrypted data length: %lu\n", - inbuf[1].cbBuffer); - - /* increase buffer in order to fit the received amount of data */ - size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? - inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; - if(BACKEND->decdata_length - BACKEND->decdata_offset < size || - BACKEND->decdata_length < len) { - /* increase internal decrypted data buffer */ - reallocated_length = BACKEND->decdata_offset + size; - /* make sure that the requested amount of data fits */ - if(reallocated_length < len) { - reallocated_length = len; - } - reallocated_buffer = realloc(BACKEND->decdata_buffer, - reallocated_length); - if(reallocated_buffer == NULL) { - *err = CURLE_OUT_OF_MEMORY; - failf(data, "schannel: unable to re-allocate memory"); - goto cleanup; - } - BACKEND->decdata_buffer = reallocated_buffer; - BACKEND->decdata_length = reallocated_length; - } - - /* copy decrypted data to internal buffer */ - size = inbuf[1].cbBuffer; - if(size) { - memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset, - inbuf[1].pvBuffer, size); - BACKEND->decdata_offset += size; - } - - infof(data, "schannel: decrypted data added: %zu\n", size); - infof(data, "schannel: decrypted data cached: offset %zu length %zu\n", - BACKEND->decdata_offset, BACKEND->decdata_length); - } - - /* check for remaining encrypted data */ - if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) { - infof(data, "schannel: encrypted data length: %lu\n", - inbuf[3].cbBuffer); - - /* check if the remaining data is less than the total amount - * and therefore begins after the already processed data - */ - if(BACKEND->encdata_offset > inbuf[3].cbBuffer) { - /* move remaining encrypted data forward to the beginning of - buffer */ - memmove(BACKEND->encdata_buffer, - (BACKEND->encdata_buffer + BACKEND->encdata_offset) - - inbuf[3].cbBuffer, inbuf[3].cbBuffer); - BACKEND->encdata_offset = inbuf[3].cbBuffer; - } - - infof(data, "schannel: encrypted data cached: offset %zu length %zu\n", - BACKEND->encdata_offset, BACKEND->encdata_length); - } - else { - /* reset encrypted buffer offset, because there is no data remaining */ - BACKEND->encdata_offset = 0; - } - - /* check if server wants to renegotiate the connection context */ - if(sspi_status == SEC_I_RENEGOTIATE) { - infof(data, "schannel: remote party requests renegotiation\n"); - if(*err && *err != CURLE_AGAIN) { - infof(data, "schannel: can't renogotiate, an error is pending\n"); - goto cleanup; - } - if(BACKEND->encdata_offset) { - *err = CURLE_RECV_ERROR; - infof(data, "schannel: can't renogotiate, " - "encrypted data available\n"); - goto cleanup; - } - /* begin renegotiation */ - infof(data, "schannel: renegotiating SSL/TLS connection\n"); - connssl->state = ssl_connection_negotiating; - connssl->connecting_state = ssl_connect_2_writing; - *err = schannel_connect_common(conn, sockindex, FALSE, &done); - if(*err) { - infof(data, "schannel: renegotiation failed\n"); - goto cleanup; - } - /* now retry receiving data */ - sspi_status = SEC_E_OK; - infof(data, "schannel: SSL/TLS connection renegotiated\n"); - continue; - } - /* check if the server closed the connection */ - else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { - /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not - returned so we have to work around that in cleanup. */ - BACKEND->recv_sspi_close_notify = true; - if(!BACKEND->recv_connection_closed) { - BACKEND->recv_connection_closed = true; - infof(data, "schannel: server closed the connection\n"); - } - goto cleanup; - } - } - else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - BACKEND->encdata_is_incomplete = true; - if(!*err) - *err = CURLE_AGAIN; - infof(data, "schannel: failed to decrypt data, need more data\n"); - goto cleanup; - } - else { - *err = CURLE_RECV_ERROR; - infof(data, "schannel: failed to read data from server: %s\n", - Curl_sspi_strerror(conn, sspi_status)); - goto cleanup; - } - } - - infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - BACKEND->encdata_offset, BACKEND->encdata_length); - - infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", - BACKEND->decdata_offset, BACKEND->decdata_length); - -cleanup: - /* Warning- there is no guarantee the encdata state is valid at this point */ - infof(data, "schannel: schannel_recv cleanup\n"); - - /* Error if the connection has closed without a close_notify. - Behavior here is a matter of debate. We don't want to be vulnerable to a - truncation attack however there's some browser precedent for ignoring the - close_notify for compatibility reasons. - Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't - return close_notify. In that case if the connection was closed we assume it - was graceful (close_notify) since there doesn't seem to be a way to tell. - */ - if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed && - !BACKEND->recv_sspi_close_notify) { - bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT, - VERSION_EQUAL); - - if(isWin2k && sspi_status == SEC_E_OK) - BACKEND->recv_sspi_close_notify = true; - else { - *err = CURLE_RECV_ERROR; - infof(data, "schannel: server closed abruptly (missing close_notify)\n"); - } - } - - /* Any error other than CURLE_AGAIN is an unrecoverable error. */ - if(*err && *err != CURLE_AGAIN) - BACKEND->recv_unrecoverable_err = *err; - - size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset; - if(size) { - memcpy(buf, BACKEND->decdata_buffer, size); - memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size, - BACKEND->decdata_offset - size); - BACKEND->decdata_offset -= size; - - infof(data, "schannel: decrypted data returned %zu\n", size); - infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", - BACKEND->decdata_offset, BACKEND->decdata_length); - *err = CURLE_OK; - return (ssize_t)size; - } - - if(!*err && !BACKEND->recv_connection_closed) - *err = CURLE_AGAIN; - - /* It's debatable what to return when !len. We could return whatever error we - got from decryption but instead we override here so the return is consistent. - */ - if(!len) - *err = CURLE_OK; - - return *err ? -1 : 0; -} - -static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - return schannel_connect_common(conn, sockindex, TRUE, done); -} - -static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done = FALSE; - - result = schannel_connect_common(conn, sockindex, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -static bool Curl_schannel_data_pending(const struct connectdata *conn, - int sockindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(connssl->use) /* SSL/TLS is in use */ - return (BACKEND->decdata_offset > 0 || - (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete)); - else - return FALSE; -} - -static void Curl_schannel_close(struct connectdata *conn, int sockindex) -{ - if(conn->ssl[sockindex].use) - /* if the SSL/TLS channel hasn't been shut down yet, do that now. */ - Curl_ssl_shutdown(conn, sockindex); -} - -static void Curl_schannel_session_free(void *ptr) -{ - /* this is expected to be called under sessionid lock */ - struct curl_schannel_cred *cred = ptr; - - cred->refcount--; - if(cred->refcount == 0) { - s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); - Curl_safefree(cred); - } -} - -static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) -{ - /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx - * Shutting Down an Schannel Connection - */ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - - infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", - hostname, conn->remote_port); - - if(BACKEND->cred && BACKEND->ctxt) { - SecBufferDesc BuffDesc; - SecBuffer Buffer; - SECURITY_STATUS sspi_status; - SecBuffer outbuf; - SecBufferDesc outbuf_desc; - CURLcode result; - TCHAR *host_name; - DWORD dwshut = SCHANNEL_SHUTDOWN; - - InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); - InitSecBufferDesc(&BuffDesc, &Buffer, 1); - - sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle, - &BuffDesc); - - if(sspi_status != SEC_E_OK) - failf(data, "schannel: ApplyControlToken failure: %s", - Curl_sspi_strerror(conn, sspi_status)); - - host_name = Curl_convert_UTF8_to_tchar(hostname); - if(!host_name) - return CURLE_OUT_OF_MEMORY; - - /* setup output buffer */ - InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&outbuf_desc, &outbuf, 1); - - sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, - &BACKEND->ctxt->ctxt_handle, - host_name, - BACKEND->req_flags, - 0, - 0, - NULL, - 0, - &BACKEND->ctxt->ctxt_handle, - &outbuf_desc, - &BACKEND->ret_flags, - &BACKEND->ctxt->time_stamp); - - Curl_unicodefree(host_name); - - if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { - /* send close message which is in output buffer */ - ssize_t written; - result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, - outbuf.cbBuffer, &written); - - s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); - if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { - infof(data, "schannel: failed to send close msg: %s" - " (bytes written: %zd)\n", curl_easy_strerror(result), written); - } - } - } - - /* free SSPI Schannel API security context handle */ - if(BACKEND->ctxt) { - infof(data, "schannel: clear security context handle\n"); - s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle); - Curl_safefree(BACKEND->ctxt); - } - - /* free SSPI Schannel API credential handle */ - if(BACKEND->cred) { - Curl_ssl_sessionid_lock(conn); - Curl_schannel_session_free(BACKEND->cred); - Curl_ssl_sessionid_unlock(conn); - BACKEND->cred = NULL; - } - - /* free internal buffer for received encrypted data */ - if(BACKEND->encdata_buffer != NULL) { - Curl_safefree(BACKEND->encdata_buffer); - BACKEND->encdata_length = 0; - BACKEND->encdata_offset = 0; - BACKEND->encdata_is_incomplete = false; - } - - /* free internal buffer for received decrypted data */ - if(BACKEND->decdata_buffer != NULL) { - Curl_safefree(BACKEND->decdata_buffer); - BACKEND->decdata_length = 0; - BACKEND->decdata_offset = 0; - } - - return CURLE_OK; -} - -static int Curl_schannel_init(void) -{ - return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0); -} - -static void Curl_schannel_cleanup(void) -{ - Curl_sspi_global_cleanup(); -} - -static size_t Curl_schannel_version(char *buffer, size_t size) -{ - size = snprintf(buffer, size, "WinSSL"); - - return size; -} - -static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM, - unsigned char *entropy, size_t length) -{ - HCRYPTPROV hCryptProv = 0; - - (void)data; - - if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - return CURLE_FAILED_INIT; - - if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { - CryptReleaseContext(hCryptProv, 0UL); - return CURLE_FAILED_INIT; - } - - CryptReleaseContext(hCryptProv, 0UL); - return CURLE_OK; -} - -#ifdef _WIN32_WCE -static CURLcode verify_certificate(struct connectdata *conn, int sockindex) -{ - SECURITY_STATUS status; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - CURLcode result = CURLE_OK; - CERT_CONTEXT *pCertContextServer = NULL; - const CERT_CHAIN_CONTEXT *pChainContext = NULL; - const char * const conn_hostname = SSL_IS_PROXY() ? - conn->http_proxy.host.name : - conn->host.name; - - status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, - SECPKG_ATTR_REMOTE_CERT_CONTEXT, - &pCertContextServer); - - if((status != SEC_E_OK) || (pCertContextServer == NULL)) { - failf(data, "schannel: Failed to read remote certificate context: %s", - Curl_sspi_strerror(conn, status)); - result = CURLE_PEER_FAILED_VERIFICATION; - } - - if(result == CURLE_OK) { - CERT_CHAIN_PARA ChainPara; - memset(&ChainPara, 0, sizeof(ChainPara)); - ChainPara.cbSize = sizeof(ChainPara); - - if(!CertGetCertificateChain(NULL, - pCertContextServer, - NULL, - pCertContextServer->hCertStore, - &ChainPara, - (data->set.ssl.no_revoke ? 0 : - CERT_CHAIN_REVOCATION_CHECK_CHAIN), - NULL, - &pChainContext)) { - failf(data, "schannel: CertGetCertificateChain failed: %s", - Curl_sspi_strerror(conn, GetLastError())); - pChainContext = NULL; - result = CURLE_PEER_FAILED_VERIFICATION; - } - - if(result == CURLE_OK) { - CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; - DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED); - dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; - if(dwTrustErrorMask) { - if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_REVOKED"); - else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_PARTIAL_CHAIN"); - else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_UNTRUSTED_ROOT"); - else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_NOT_TIME_VALID"); - else - failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", - dwTrustErrorMask); - result = CURLE_PEER_FAILED_VERIFICATION; - } - } - } - - if(result == CURLE_OK) { - if(conn->ssl_config.verifyhost) { - TCHAR cert_hostname_buff[256]; - DWORD len; - - /* TODO: Fix this for certificates with multiple alternative names. - Right now we're only asking for the first preferred alternative name. - Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG - (if WinCE supports that?) and run this section in a loop for each. - https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx - curl: (51) schannel: CertGetNameString() certificate hostname - (.google.com) did not match connection (google.com) - */ - len = CertGetNameString(pCertContextServer, - CERT_NAME_DNS_TYPE, - CERT_NAME_DISABLE_IE4_UTF8_FLAG, - NULL, - cert_hostname_buff, - 256); - if(len > 0) { - const char *cert_hostname; - - /* Comparing the cert name and the connection hostname encoded as UTF-8 - * is acceptable since both values are assumed to use ASCII - * (or some equivalent) encoding - */ - cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff); - if(!cert_hostname) { - result = CURLE_OUT_OF_MEMORY; - } - else{ - int match_result; - - match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name); - if(match_result == CURL_HOST_MATCH) { - infof(data, - "schannel: connection hostname (%s) validated " - "against certificate name (%s)\n", - conn->host.name, - cert_hostname); - result = CURLE_OK; - } - else{ - failf(data, - "schannel: connection hostname (%s) " - "does not match certificate name (%s)", - conn->host.name, - cert_hostname); - result = CURLE_PEER_FAILED_VERIFICATION; - } - Curl_unicodefree(cert_hostname); - } - } - else { - failf(data, - "schannel: CertGetNameString did not provide any " - "certificate name information"); - result = CURLE_PEER_FAILED_VERIFICATION; - } - } - } - - if(pChainContext) - CertFreeCertificateChain(pChainContext); - - if(pCertContextServer) - CertFreeCertificateContext(pCertContextServer); - - return result; -} -#endif /* _WIN32_WCE */ - -static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return &BACKEND->ctxt->ctxt_handle; -} - -const struct Curl_ssl Curl_ssl_schannel = { - { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */ - - 0, /* have_ca_path */ - 1, /* have_certinfo */ - 0, /* have_pinnedpubkey */ - 0, /* have_ssl_ctx */ - 0, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_schannel_init, /* init */ - Curl_schannel_cleanup, /* cleanup */ - Curl_schannel_version, /* version */ - Curl_none_check_cxn, /* check_cxn */ - Curl_schannel_shutdown, /* shutdown */ - Curl_schannel_data_pending, /* data_pending */ - Curl_schannel_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_schannel_connect, /* connect */ - Curl_schannel_connect_nonblocking, /* connect_nonblocking */ - Curl_schannel_get_internals, /* get_internals */ - Curl_schannel_close, /* close */ - Curl_none_close_all, /* close_all */ - Curl_schannel_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - NULL /* sha256sum */ -}; - -#endif /* USE_SCHANNEL */ diff --git a/dep/cpr/opt/curl/lib/vtls/schannel.h b/dep/cpr/opt/curl/lib/vtls/schannel.h deleted file mode 100644 index 932103da473..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/schannel.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef HEADER_CURL_SCHANNEL_H -#define HEADER_CURL_SCHANNEL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012, Marc Hoersken, , et al. - * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -#ifdef USE_SCHANNEL - -#include "urldata.h" - -extern const struct Curl_ssl Curl_ssl_schannel; - -#endif /* USE_SCHANNEL */ -#endif /* HEADER_CURL_SCHANNEL_H */ diff --git a/dep/cpr/opt/curl/lib/vtls/vtls.c b/dep/cpr/opt/curl/lib/vtls/vtls.c deleted file mode 100644 index bb8fda41963..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/vtls.c +++ /dev/null @@ -1,1312 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* This file is for implementing all "generic" SSL functions that all libcurl - internals should use. It is then responsible for calling the proper - "backend" function. - - SSL-functions in libcurl should call functions in this source file, and not - to any specific SSL-layer. - - Curl_ssl_ - prefix for generic ones - - Note that this source code uses the functions of the configured SSL - backend via the global Curl_ssl instance. - - "SSL/TLS Strong Encryption: An Introduction" - https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html -*/ - -#include "curl_setup.h" - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif - -#include "urldata.h" - -#include "vtls.h" /* generic SSL protos etc */ -#include "slist.h" -#include "sendf.h" -#include "strcase.h" -#include "url.h" -#include "progress.h" -#include "share.h" -#include "multiif.h" -#include "timeval.h" -#include "curl_md5.h" -#include "warnless.h" -#include "curl_base64.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* convenience macro to check if this handle is using a shared SSL session */ -#define SSLSESSION_SHARED(data) (data->share && \ - (data->share->specifier & \ - (1<var) { \ - dest->var = strdup(source->var); \ - if(!dest->var) \ - return FALSE; \ - } \ - else \ - dest->var = NULL; - -bool -Curl_ssl_config_matches(struct ssl_primary_config* data, - struct ssl_primary_config* needle) -{ - if((data->version == needle->version) && - (data->version_max == needle->version_max) && - (data->verifypeer == needle->verifypeer) && - (data->verifyhost == needle->verifyhost) && - (data->verifystatus == needle->verifystatus) && - Curl_safe_strcasecompare(data->CApath, needle->CApath) && - Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && - Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && - Curl_safe_strcasecompare(data->random_file, needle->random_file) && - Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) && - Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list)) - return TRUE; - - return FALSE; -} - -bool -Curl_clone_primary_ssl_config(struct ssl_primary_config *source, - struct ssl_primary_config *dest) -{ - dest->version = source->version; - dest->version_max = source->version_max; - dest->verifypeer = source->verifypeer; - dest->verifyhost = source->verifyhost; - dest->verifystatus = source->verifystatus; - dest->sessionid = source->sessionid; - - CLONE_STRING(CApath); - CLONE_STRING(CAfile); - CLONE_STRING(clientcert); - CLONE_STRING(random_file); - CLONE_STRING(egdsocket); - CLONE_STRING(cipher_list); - - return TRUE; -} - -void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc) -{ - Curl_safefree(sslc->CApath); - Curl_safefree(sslc->CAfile); - Curl_safefree(sslc->clientcert); - Curl_safefree(sslc->random_file); - Curl_safefree(sslc->egdsocket); - Curl_safefree(sslc->cipher_list); -} - -#ifdef USE_SSL -static int multissl_init(const struct Curl_ssl *backend); -#endif - -int Curl_ssl_backend(void) -{ -#ifdef USE_SSL - multissl_init(NULL); - return Curl_ssl->info.id; -#else - return (int)CURLSSLBACKEND_NONE; -#endif -} - -#ifdef USE_SSL - -/* "global" init done? */ -static bool init_ssl = FALSE; - -/** - * Global SSL init - * - * @retval 0 error initializing SSL - * @retval 1 SSL initialized successfully - */ -int Curl_ssl_init(void) -{ - /* make sure this is only done once */ - if(init_ssl) - return 1; - init_ssl = TRUE; /* never again */ - - return Curl_ssl->init(); -} - - -/* Global cleanup */ -void Curl_ssl_cleanup(void) -{ - if(init_ssl) { - /* only cleanup if we did a previous init */ - Curl_ssl->cleanup(); - init_ssl = FALSE; - } -} - -static bool ssl_prefs_check(struct Curl_easy *data) -{ - /* check for CURLOPT_SSLVERSION invalid parameter value */ - const long sslver = data->set.ssl.primary.version; - if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) { - failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); - return FALSE; - } - - switch(data->set.ssl.primary.version_max) { - case CURL_SSLVERSION_MAX_NONE: - case CURL_SSLVERSION_MAX_DEFAULT: - break; - - default: - if((data->set.ssl.primary.version_max >> 16) < sslver) { - failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION"); - return FALSE; - } - } - - return TRUE; -} - -static CURLcode -ssl_connect_init_proxy(struct connectdata *conn, int sockindex) -{ - DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]); - if(ssl_connection_complete == conn->ssl[sockindex].state && - !conn->proxy_ssl[sockindex].use) { - struct ssl_backend_data *pbdata; - - if(!Curl_ssl->support_https_proxy) - return CURLE_NOT_BUILT_IN; - - /* The pointers to the ssl backend data, which is opaque here, are swapped - rather than move the contents. */ - pbdata = conn->proxy_ssl[sockindex].backend; - conn->proxy_ssl[sockindex] = conn->ssl[sockindex]; - - memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex])); - memset(pbdata, 0, Curl_ssl->sizeof_ssl_backend_data); - - conn->ssl[sockindex].backend = pbdata; - } - return CURLE_OK; -} - -CURLcode -Curl_ssl_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - - if(conn->bits.proxy_ssl_connected[sockindex]) { - result = ssl_connect_init_proxy(conn, sockindex); - if(result) - return result; - } - - if(!ssl_prefs_check(conn->data)) - return CURLE_SSL_CONNECT_ERROR; - - /* mark this is being ssl-enabled from here on. */ - conn->ssl[sockindex].use = TRUE; - conn->ssl[sockindex].state = ssl_connection_negotiating; - - result = Curl_ssl->connect(conn, sockindex); - - if(!result) - Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ - - return result; -} - -CURLcode -Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, - bool *done) -{ - CURLcode result; - if(conn->bits.proxy_ssl_connected[sockindex]) { - result = ssl_connect_init_proxy(conn, sockindex); - if(result) - return result; - } - - if(!ssl_prefs_check(conn->data)) - return CURLE_SSL_CONNECT_ERROR; - - /* mark this is being ssl requested from here on. */ - conn->ssl[sockindex].use = TRUE; - result = Curl_ssl->connect_nonblocking(conn, sockindex, done); - if(!result && *done) - Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ - return result; -} - -/* - * Lock shared SSL session data - */ -void Curl_ssl_sessionid_lock(struct connectdata *conn) -{ - if(SSLSESSION_SHARED(conn->data)) - Curl_share_lock(conn->data, - CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); -} - -/* - * Unlock shared SSL session data - */ -void Curl_ssl_sessionid_unlock(struct connectdata *conn) -{ - if(SSLSESSION_SHARED(conn->data)) - Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION); -} - -/* - * Check if there's a session ID for the given connection in the cache, and if - * there's one suitable, it is provided. Returns TRUE when no entry matched. - */ -bool Curl_ssl_getsessionid(struct connectdata *conn, - void **ssl_sessionid, - size_t *idsize, /* set 0 if unknown */ - int sockindex) -{ - struct curl_ssl_session *check; - struct Curl_easy *data = conn->data; - size_t i; - long *general_age; - bool no_match = TRUE; - - const bool isProxy = CONNECT_PROXY_SSL(); - struct ssl_primary_config * const ssl_config = isProxy ? - &conn->proxy_ssl_config : - &conn->ssl_config; - const char * const name = isProxy ? conn->http_proxy.host.name : - conn->host.name; - int port = isProxy ? (int)conn->port : conn->remote_port; - *ssl_sessionid = NULL; - - DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); - - if(!SSL_SET_OPTION(primary.sessionid)) - /* session ID re-use is disabled */ - return TRUE; - - /* Lock if shared */ - if(SSLSESSION_SHARED(data)) - general_age = &data->share->sessionage; - else - general_age = &data->state.sessionage; - - for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { - check = &data->state.session[i]; - if(!check->sessionid) - /* not session ID means blank entry */ - continue; - if(strcasecompare(name, check->name) && - ((!conn->bits.conn_to_host && !check->conn_to_host) || - (conn->bits.conn_to_host && check->conn_to_host && - strcasecompare(conn->conn_to_host.name, check->conn_to_host))) && - ((!conn->bits.conn_to_port && check->conn_to_port == -1) || - (conn->bits.conn_to_port && check->conn_to_port != -1 && - conn->conn_to_port == check->conn_to_port)) && - (port == check->remote_port) && - strcasecompare(conn->handler->scheme, check->scheme) && - Curl_ssl_config_matches(ssl_config, &check->ssl_config)) { - /* yes, we have a session ID! */ - (*general_age)++; /* increase general age */ - check->age = *general_age; /* set this as used in this age */ - *ssl_sessionid = check->sessionid; - if(idsize) - *idsize = check->idsize; - no_match = FALSE; - break; - } - } - - return no_match; -} - -/* - * Kill a single session ID entry in the cache. - */ -void Curl_ssl_kill_session(struct curl_ssl_session *session) -{ - if(session->sessionid) { - /* defensive check */ - - /* free the ID the SSL-layer specific way */ - Curl_ssl->session_free(session->sessionid); - - session->sessionid = NULL; - session->age = 0; /* fresh */ - - Curl_free_primary_ssl_config(&session->ssl_config); - - Curl_safefree(session->name); - Curl_safefree(session->conn_to_host); - } -} - -/* - * Delete the given session ID from the cache. - */ -void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) -{ - size_t i; - struct Curl_easy *data = conn->data; - - for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { - struct curl_ssl_session *check = &data->state.session[i]; - - if(check->sessionid == ssl_sessionid) { - Curl_ssl_kill_session(check); - break; - } - } -} - -/* - * Store session id in the session cache. The ID passed on to this function - * must already have been extracted and allocated the proper way for the SSL - * layer. Curl_XXXX_session_free() will be called to free/kill the session ID - * later on. - */ -CURLcode Curl_ssl_addsessionid(struct connectdata *conn, - void *ssl_sessionid, - size_t idsize, - int sockindex) -{ - size_t i; - struct Curl_easy *data = conn->data; /* the mother of all structs */ - struct curl_ssl_session *store = &data->state.session[0]; - long oldest_age = data->state.session[0].age; /* zero if unused */ - char *clone_host; - char *clone_conn_to_host; - int conn_to_port; - long *general_age; - const bool isProxy = CONNECT_PROXY_SSL(); - struct ssl_primary_config * const ssl_config = isProxy ? - &conn->proxy_ssl_config : - &conn->ssl_config; - - DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); - - clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name); - if(!clone_host) - return CURLE_OUT_OF_MEMORY; /* bail out */ - - if(conn->bits.conn_to_host) { - clone_conn_to_host = strdup(conn->conn_to_host.name); - if(!clone_conn_to_host) { - free(clone_host); - return CURLE_OUT_OF_MEMORY; /* bail out */ - } - } - else - clone_conn_to_host = NULL; - - if(conn->bits.conn_to_port) - conn_to_port = conn->conn_to_port; - else - conn_to_port = -1; - - /* Now we should add the session ID and the host name to the cache, (remove - the oldest if necessary) */ - - /* If using shared SSL session, lock! */ - if(SSLSESSION_SHARED(data)) { - general_age = &data->share->sessionage; - } - else { - general_age = &data->state.sessionage; - } - - /* find an empty slot for us, or find the oldest */ - for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) && - data->state.session[i].sessionid; i++) { - if(data->state.session[i].age < oldest_age) { - oldest_age = data->state.session[i].age; - store = &data->state.session[i]; - } - } - if(i == data->set.general_ssl.max_ssl_sessions) - /* cache is full, we must "kill" the oldest entry! */ - Curl_ssl_kill_session(store); - else - store = &data->state.session[i]; /* use this slot */ - - /* now init the session struct wisely */ - store->sessionid = ssl_sessionid; - store->idsize = idsize; - store->age = *general_age; /* set current age */ - /* free it if there's one already present */ - free(store->name); - free(store->conn_to_host); - store->name = clone_host; /* clone host name */ - store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ - store->conn_to_port = conn_to_port; /* connect to port number */ - /* port number */ - store->remote_port = isProxy ? (int)conn->port : conn->remote_port; - store->scheme = conn->handler->scheme; - - if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) { - store->sessionid = NULL; /* let caller free sessionid */ - free(clone_host); - free(clone_conn_to_host); - return CURLE_OUT_OF_MEMORY; - } - - return CURLE_OK; -} - - -void Curl_ssl_close_all(struct Curl_easy *data) -{ - size_t i; - /* kill the session ID cache if not shared */ - if(data->state.session && !SSLSESSION_SHARED(data)) { - for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) - /* the single-killer function handles empty table slots */ - Curl_ssl_kill_session(&data->state.session[i]); - - /* free the cache data */ - Curl_safefree(data->state.session); - } - - Curl_ssl->close_all(data); -} - -#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ - defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \ - defined(USE_MBEDTLS) -int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks) -{ - struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; - - if(!numsocks) - return GETSOCK_BLANK; - - if(connssl->connecting_state == ssl_connect_2_writing) { - /* write mode */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); - } - if(connssl->connecting_state == ssl_connect_2_reading) { - /* read mode */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_READSOCK(0); - } - - return GETSOCK_BLANK; -} -#else -int Curl_ssl_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - (void)conn; - (void)socks; - (void)numsocks; - return GETSOCK_BLANK; -} -/* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */ -#endif - -void Curl_ssl_close(struct connectdata *conn, int sockindex) -{ - DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); - Curl_ssl->close(conn, sockindex); -} - -CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) -{ - if(Curl_ssl->shutdown(conn, sockindex)) - return CURLE_SSL_SHUTDOWN_FAILED; - - conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */ - conn->ssl[sockindex].state = ssl_connection_none; - - conn->recv[sockindex] = Curl_recv_plain; - conn->send[sockindex] = Curl_send_plain; - - return CURLE_OK; -} - -/* Selects an SSL crypto engine - */ -CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine) -{ - return Curl_ssl->set_engine(data, engine); -} - -/* Selects the default SSL crypto engine - */ -CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data) -{ - return Curl_ssl->set_engine_default(data); -} - -/* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data) -{ - return Curl_ssl->engines_list(data); -} - -/* - * This sets up a session ID cache to the specified size. Make sure this code - * is agnostic to what underlying SSL technology we use. - */ -CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) -{ - struct curl_ssl_session *session; - - if(data->state.session) - /* this is just a precaution to prevent multiple inits */ - return CURLE_OK; - - session = calloc(amount, sizeof(struct curl_ssl_session)); - if(!session) - return CURLE_OUT_OF_MEMORY; - - /* store the info in the SSL section */ - data->set.general_ssl.max_ssl_sessions = amount; - data->state.session = session; - data->state.sessionage = 1; /* this is brand new */ - return CURLE_OK; -} - -static size_t Curl_multissl_version(char *buffer, size_t size); - -size_t Curl_ssl_version(char *buffer, size_t size) -{ -#ifdef CURL_WITH_MULTI_SSL - return Curl_multissl_version(buffer, size); -#else - return Curl_ssl->version(buffer, size); -#endif -} - -/* - * This function tries to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -int Curl_ssl_check_cxn(struct connectdata *conn) -{ - return Curl_ssl->check_cxn(conn); -} - -bool Curl_ssl_data_pending(const struct connectdata *conn, - int connindex) -{ - return Curl_ssl->data_pending(conn, connindex); -} - -void Curl_ssl_free_certinfo(struct Curl_easy *data) -{ - int i; - struct curl_certinfo *ci = &data->info.certs; - - if(ci->num_of_certs) { - /* free all individual lists used */ - for(i = 0; inum_of_certs; i++) { - curl_slist_free_all(ci->certinfo[i]); - ci->certinfo[i] = NULL; - } - - free(ci->certinfo); /* free the actual array too */ - ci->certinfo = NULL; - ci->num_of_certs = 0; - } -} - -CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num) -{ - struct curl_certinfo *ci = &data->info.certs; - struct curl_slist **table; - - /* Free any previous certificate information structures */ - Curl_ssl_free_certinfo(data); - - /* Allocate the required certificate information structures */ - table = calloc((size_t) num, sizeof(struct curl_slist *)); - if(!table) - return CURLE_OUT_OF_MEMORY; - - ci->num_of_certs = num; - ci->certinfo = table; - - return CURLE_OK; -} - -/* - * 'value' is NOT a zero terminated string - */ -CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, - int certnum, - const char *label, - const char *value, - size_t valuelen) -{ - struct curl_certinfo *ci = &data->info.certs; - char *output; - struct curl_slist *nl; - CURLcode result = CURLE_OK; - size_t labellen = strlen(label); - size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ - - output = malloc(outlen); - if(!output) - return CURLE_OUT_OF_MEMORY; - - /* sprintf the label and colon */ - snprintf(output, outlen, "%s:", label); - - /* memcpy the value (it might not be zero terminated) */ - memcpy(&output[labellen + 1], value, valuelen); - - /* zero terminate the output */ - output[labellen + 1 + valuelen] = 0; - - nl = Curl_slist_append_nodup(ci->certinfo[certnum], output); - if(!nl) { - free(output); - curl_slist_free_all(ci->certinfo[certnum]); - result = CURLE_OUT_OF_MEMORY; - } - - ci->certinfo[certnum] = nl; - return result; -} - -/* - * This is a convenience function for push_certinfo_len that takes a zero - * terminated value. - */ -CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, - int certnum, - const char *label, - const char *value) -{ - size_t valuelen = strlen(value); - - return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); -} - -CURLcode Curl_ssl_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) -{ - return Curl_ssl->random(data, entropy, length); -} - -/* - * Public key pem to der conversion - */ - -static CURLcode pubkey_pem_to_der(const char *pem, - unsigned char **der, size_t *der_len) -{ - char *stripped_pem, *begin_pos, *end_pos; - size_t pem_count, stripped_pem_count = 0, pem_len; - CURLcode result; - - /* if no pem, exit. */ - if(!pem) - return CURLE_BAD_CONTENT_ENCODING; - - begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----"); - if(!begin_pos) - return CURLE_BAD_CONTENT_ENCODING; - - pem_count = begin_pos - pem; - /* Invalid if not at beginning AND not directly following \n */ - if(0 != pem_count && '\n' != pem[pem_count - 1]) - return CURLE_BAD_CONTENT_ENCODING; - - /* 26 is length of "-----BEGIN PUBLIC KEY-----" */ - pem_count += 26; - - /* Invalid if not directly following \n */ - end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----"); - if(!end_pos) - return CURLE_BAD_CONTENT_ENCODING; - - pem_len = end_pos - pem; - - stripped_pem = malloc(pem_len - pem_count + 1); - if(!stripped_pem) - return CURLE_OUT_OF_MEMORY; - - /* - * Here we loop through the pem array one character at a time between the - * correct indices, and place each character that is not '\n' or '\r' - * into the stripped_pem array, which should represent the raw base64 string - */ - while(pem_count < pem_len) { - if('\n' != pem[pem_count] && '\r' != pem[pem_count]) - stripped_pem[stripped_pem_count++] = pem[pem_count]; - ++pem_count; - } - /* Place the null terminator in the correct place */ - stripped_pem[stripped_pem_count] = '\0'; - - result = Curl_base64_decode(stripped_pem, der, der_len); - - Curl_safefree(stripped_pem); - - return result; -} - -/* - * Generic pinned public key check. - */ - -CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, - const char *pinnedpubkey, - const unsigned char *pubkey, size_t pubkeylen) -{ - FILE *fp; - unsigned char *buf = NULL, *pem_ptr = NULL; - long filesize; - size_t size, pem_len; - CURLcode pem_read; - CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - CURLcode encode; - size_t encodedlen, pinkeylen; - char *encoded, *pinkeycopy, *begin_pos, *end_pos; - unsigned char *sha256sumdigest = NULL; - - /* if a path wasn't specified, don't pin */ - if(!pinnedpubkey) - return CURLE_OK; - if(!pubkey || !pubkeylen) - return result; - - /* only do this if pinnedpubkey starts with "sha256//", length 8 */ - if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { - if(!Curl_ssl->sha256sum) { - /* without sha256 support, this cannot match */ - return result; - } - - /* compute sha256sum of public key */ - sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH); - if(!sha256sumdigest) - return CURLE_OUT_OF_MEMORY; - Curl_ssl->sha256sum(pubkey, pubkeylen, - sha256sumdigest, CURL_SHA256_DIGEST_LENGTH); - encode = Curl_base64_encode(data, (char *)sha256sumdigest, - CURL_SHA256_DIGEST_LENGTH, &encoded, - &encodedlen); - Curl_safefree(sha256sumdigest); - - if(encode) - return encode; - - infof(data, "\t public key hash: sha256//%s\n", encoded); - - /* it starts with sha256//, copy so we can modify it */ - pinkeylen = strlen(pinnedpubkey) + 1; - pinkeycopy = malloc(pinkeylen); - if(!pinkeycopy) { - Curl_safefree(encoded); - return CURLE_OUT_OF_MEMORY; - } - memcpy(pinkeycopy, pinnedpubkey, pinkeylen); - /* point begin_pos to the copy, and start extracting keys */ - begin_pos = pinkeycopy; - do { - end_pos = strstr(begin_pos, ";sha256//"); - /* - * if there is an end_pos, null terminate, - * otherwise it'll go to the end of the original string - */ - if(end_pos) - end_pos[0] = '\0'; - - /* compare base64 sha256 digests, 8 is the length of "sha256//" */ - if(encodedlen == strlen(begin_pos + 8) && - !memcmp(encoded, begin_pos + 8, encodedlen)) { - result = CURLE_OK; - break; - } - - /* - * change back the null-terminator we changed earlier, - * and look for next begin - */ - if(end_pos) { - end_pos[0] = ';'; - begin_pos = strstr(end_pos, "sha256//"); - } - } while(end_pos && begin_pos); - Curl_safefree(encoded); - Curl_safefree(pinkeycopy); - return result; - } - - fp = fopen(pinnedpubkey, "rb"); - if(!fp) - return result; - - do { - /* Determine the file's size */ - if(fseek(fp, 0, SEEK_END)) - break; - filesize = ftell(fp); - if(fseek(fp, 0, SEEK_SET)) - break; - if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE) - break; - - /* - * if the size of our certificate is bigger than the file - * size then it can't match - */ - size = curlx_sotouz((curl_off_t) filesize); - if(pubkeylen > size) - break; - - /* - * Allocate buffer for the pinned key - * With 1 additional byte for null terminator in case of PEM key - */ - buf = malloc(size + 1); - if(!buf) - break; - - /* Returns number of elements read, which should be 1 */ - if((int) fread(buf, size, 1, fp) != 1) - break; - - /* If the sizes are the same, it can't be base64 encoded, must be der */ - if(pubkeylen == size) { - if(!memcmp(pubkey, buf, pubkeylen)) - result = CURLE_OK; - break; - } - - /* - * Otherwise we will assume it's PEM and try to decode it - * after placing null terminator - */ - buf[size] = '\0'; - pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len); - /* if it wasn't read successfully, exit */ - if(pem_read) - break; - - /* - * if the size of our certificate doesn't match the size of - * the decoded file, they can't be the same, otherwise compare - */ - if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen)) - result = CURLE_OK; - } while(0); - - Curl_safefree(buf); - Curl_safefree(pem_ptr); - fclose(fp); - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len) -{ - return Curl_ssl->md5sum(tmp, tmplen, md5sum, md5len); -} -#endif - -/* - * Check whether the SSL backend supports the status_request extension. - */ -bool Curl_ssl_cert_status_request(void) -{ - return Curl_ssl->cert_status_request(); -} - -/* - * Check whether the SSL backend supports false start. - */ -bool Curl_ssl_false_start(void) -{ - return Curl_ssl->false_start(); -} - -/* - * Default implementations for unsupported functions. - */ - -int Curl_none_init(void) -{ - return 1; -} - -void Curl_none_cleanup(void) -{ } - -int Curl_none_shutdown(struct connectdata *conn UNUSED_PARAM, - int sockindex UNUSED_PARAM) -{ - (void)conn; - (void)sockindex; - return 0; -} - -int Curl_none_check_cxn(struct connectdata *conn UNUSED_PARAM) -{ - (void)conn; - return -1; -} - -CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM, - unsigned char *entropy UNUSED_PARAM, - size_t length UNUSED_PARAM) -{ - (void)data; - (void)entropy; - (void)length; - return CURLE_NOT_BUILT_IN; -} - -void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM) -{ - (void)data; -} - -void Curl_none_session_free(void *ptr UNUSED_PARAM) -{ - (void)ptr; -} - -bool Curl_none_data_pending(const struct connectdata *conn UNUSED_PARAM, - int connindex UNUSED_PARAM) -{ - (void)conn; - (void)connindex; - return 0; -} - -bool Curl_none_cert_status_request(void) -{ - return FALSE; -} - -CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM, - const char *engine UNUSED_PARAM) -{ - (void)data; - (void)engine; - return CURLE_NOT_BUILT_IN; -} - -CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM) -{ - (void)data; - return CURLE_NOT_BUILT_IN; -} - -struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM) -{ - (void)data; - return (struct curl_slist *)NULL; -} - -bool Curl_none_false_start(void) -{ - return FALSE; -} - -CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, - unsigned char *md5sum, size_t md5len UNUSED_PARAM) -{ - MD5_context *MD5pw; - - (void)md5len; - - MD5pw = Curl_MD5_init(Curl_DIGEST_MD5); - if(!MD5pw) - return CURLE_OUT_OF_MEMORY; - Curl_MD5_update(MD5pw, input, curlx_uztoui(inputlen)); - Curl_MD5_final(MD5pw, md5sum); - return CURLE_OK; -} - -static int Curl_multissl_init(void) -{ - if(multissl_init(NULL)) - return 1; - return Curl_ssl->init(); -} - -static CURLcode Curl_multissl_connect(struct connectdata *conn, int sockindex) -{ - if(multissl_init(NULL)) - return CURLE_FAILED_INIT; - return Curl_ssl->connect(conn, sockindex); -} - -static CURLcode Curl_multissl_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - if(multissl_init(NULL)) - return CURLE_FAILED_INIT; - return Curl_ssl->connect_nonblocking(conn, sockindex, done); -} - -static void *Curl_multissl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info) -{ - if(multissl_init(NULL)) - return NULL; - return Curl_ssl->get_internals(connssl, info); -} - -static void Curl_multissl_close(struct connectdata *conn, int sockindex) -{ - if(multissl_init(NULL)) - return; - Curl_ssl->close(conn, sockindex); -} - -static const struct Curl_ssl Curl_ssl_multi = { - { CURLSSLBACKEND_NONE, "multi" }, /* info */ - - 0, /* have_ca_path */ - 0, /* have_certinfo */ - 0, /* have_pinnedpubkey */ - 0, /* have_ssl_ctx */ - 0, /* support_https_proxy */ - - (size_t)-1, /* something insanely large to be on the safe side */ - - Curl_multissl_init, /* init */ - Curl_none_cleanup, /* cleanup */ - Curl_multissl_version, /* version */ - Curl_none_check_cxn, /* check_cxn */ - Curl_none_shutdown, /* shutdown */ - Curl_none_data_pending, /* data_pending */ - Curl_none_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_multissl_connect, /* connect */ - Curl_multissl_connect_nonblocking, /* connect_nonblocking */ - Curl_multissl_get_internals, /* get_internals */ - Curl_multissl_close, /* close */ - Curl_none_close_all, /* close_all */ - Curl_none_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - NULL /* sha256sum */ -}; - -const struct Curl_ssl *Curl_ssl = -#if defined(CURL_WITH_MULTI_SSL) - &Curl_ssl_multi; -#elif defined(USE_AXTLS) - &Curl_ssl_axtls; -#elif defined(USE_CYASSL) - &Curl_ssl_cyassl; -#elif defined(USE_DARWINSSL) - &Curl_ssl_darwinssl; -#elif defined(USE_GNUTLS) - &Curl_ssl_gnutls; -#elif defined(USE_GSKIT) - &Curl_ssl_gskit; -#elif defined(USE_MBEDTLS) - &Curl_ssl_mbedtls; -#elif defined(USE_NSS) - &Curl_ssl_nss; -#elif defined(USE_OPENSSL) - &Curl_ssl_openssl; -#elif defined(USE_POLARSSL) - &Curl_ssl_polarssl; -#elif defined(USE_SCHANNEL) - &Curl_ssl_schannel; -#else -#error "Missing struct Curl_ssl for selected SSL backend" -#endif - -static const struct Curl_ssl *available_backends[] = { -#if defined(USE_AXTLS) - &Curl_ssl_axtls, -#endif -#if defined(USE_CYASSL) - &Curl_ssl_cyassl, -#endif -#if defined(USE_DARWINSSL) - &Curl_ssl_darwinssl, -#endif -#if defined(USE_GNUTLS) - &Curl_ssl_gnutls, -#endif -#if defined(USE_GSKIT) - &Curl_ssl_gskit, -#endif -#if defined(USE_MBEDTLS) - &Curl_ssl_mbedtls, -#endif -#if defined(USE_NSS) - &Curl_ssl_nss, -#endif -#if defined(USE_OPENSSL) - &Curl_ssl_openssl, -#endif -#if defined(USE_POLARSSL) - &Curl_ssl_polarssl, -#endif -#if defined(USE_SCHANNEL) - &Curl_ssl_schannel, -#endif - NULL -}; - -static size_t Curl_multissl_version(char *buffer, size_t size) -{ - static const struct Curl_ssl *selected; - static char backends[200]; - static size_t total; - const struct Curl_ssl *current; - - current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl; - - if(current != selected) { - char *p = backends; - int i; - - selected = current; - - for(i = 0; available_backends[i]; i++) { - if(i) - *(p++) = ' '; - if(selected != available_backends[i]) - *(p++) = '('; - p += available_backends[i]->version(p, backends + sizeof(backends) - p); - if(selected != available_backends[i]) - *(p++) = ')'; - } - *p = '\0'; - total = p - backends; - } - - if(size < total) - memcpy(buffer, backends, total + 1); - else { - memcpy(buffer, backends, size - 1); - buffer[size - 1] = '\0'; - } - - return total; -} - -static int multissl_init(const struct Curl_ssl *backend) -{ - const char *env; - int i; - - if(Curl_ssl != &Curl_ssl_multi) - return 1; - - if(backend) { - Curl_ssl = backend; - return 0; - } - - if(!available_backends[0]) - return 1; - - env = getenv("CURL_SSL_BACKEND"); -#ifdef CURL_DEFAULT_SSL_BACKEND - if(!env) - env = CURL_DEFAULT_SSL_BACKEND; -#endif - if(env) { - for(i = 0; available_backends[i]; i++) { - if(strcasecompare(env, available_backends[i]->info.name)) { - Curl_ssl = available_backends[i]; - return 0; - } - } - } - - /* Fall back to first available backend */ - Curl_ssl = available_backends[0]; - return 0; -} - -CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, - const curl_ssl_backend ***avail) -{ - int i; - - if(Curl_ssl != &Curl_ssl_multi) - return id == Curl_ssl->info.id ? CURLSSLSET_OK : CURLSSLSET_TOO_LATE; - - for(i = 0; available_backends[i]; i++) { - if(available_backends[i]->info.id == id || - (name && strcasecompare(available_backends[i]->info.name, name))) { - multissl_init(available_backends[i]); - return CURLSSLSET_OK; - } - } - - if(avail) - *avail = (const curl_ssl_backend **)&available_backends; - return CURLSSLSET_UNKNOWN_BACKEND; -} - -#else /* USE_SSL */ -CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, - const curl_ssl_backend ***avail) -{ - (void)id; - (void)name; - (void)avail; - return CURLSSLSET_NO_BACKENDS; -} - -#endif /* !USE_SSL */ diff --git a/dep/cpr/opt/curl/lib/vtls/vtls.h b/dep/cpr/opt/curl/lib/vtls/vtls.h deleted file mode 100644 index f1a11ea58d7..00000000000 --- a/dep/cpr/opt/curl/lib/vtls/vtls.h +++ /dev/null @@ -1,274 +0,0 @@ -#ifndef HEADER_CURL_VTLS_H -#define HEADER_CURL_VTLS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "curl_setup.h" - -struct connectdata; -struct ssl_connect_data; - -struct Curl_ssl { - /* - * This *must* be the first entry to allow returning the list of available - * backends in curl_global_sslset(). - */ - curl_ssl_backend info; - - unsigned have_ca_path:1; /* supports CAPATH */ - unsigned have_certinfo:1; /* supports CURLOPT_CERTINFO */ - unsigned have_pinnedpubkey:1; /* supports CURLOPT_PINNEDPUBLICKEY */ - unsigned have_ssl_ctx:1; /* supports CURLOPT_SSL_CTX_* */ - - unsigned support_https_proxy:1; /* supports access via HTTPS proxies */ - - size_t sizeof_ssl_backend_data; - - int (*init)(void); - void (*cleanup)(void); - - size_t (*version)(char *buffer, size_t size); - int (*check_cxn)(struct connectdata *cxn); - int (*shutdown)(struct connectdata *conn, int sockindex); - bool (*data_pending)(const struct connectdata *conn, - int connindex); - - /* return 0 if a find random is filled in */ - CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy, - size_t length); - bool (*cert_status_request)(void); - - CURLcode (*connect)(struct connectdata *conn, int sockindex); - CURLcode (*connect_nonblocking)(struct connectdata *conn, int sockindex, - bool *done); - void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info); - void (*close)(struct connectdata *conn, int sockindex); - void (*close_all)(struct Curl_easy *data); - void (*session_free)(void *ptr); - - CURLcode (*set_engine)(struct Curl_easy *data, const char *engine); - CURLcode (*set_engine_default)(struct Curl_easy *data); - struct curl_slist *(*engines_list)(struct Curl_easy *data); - - bool (*false_start)(void); - - CURLcode (*md5sum)(unsigned char *input, size_t inputlen, - unsigned char *md5sum, size_t md5sumlen); - void (*sha256sum)(const unsigned char *input, size_t inputlen, - unsigned char *sha256sum, size_t sha256sumlen); -}; - -#ifdef USE_SSL -extern const struct Curl_ssl *Curl_ssl; -#endif - -int Curl_none_init(void); -void Curl_none_cleanup(void); -int Curl_none_shutdown(struct connectdata *conn, int sockindex); -int Curl_none_check_cxn(struct connectdata *conn); -CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy, - size_t length); -void Curl_none_close_all(struct Curl_easy *data); -void Curl_none_session_free(void *ptr); -bool Curl_none_data_pending(const struct connectdata *conn, int connindex); -bool Curl_none_cert_status_request(void); -CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine); -CURLcode Curl_none_set_engine_default(struct Curl_easy *data); -struct curl_slist *Curl_none_engines_list(struct Curl_easy *data); -bool Curl_none_false_start(void); -CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, - unsigned char *md5sum, size_t md5len); - -#include "openssl.h" /* OpenSSL versions */ -#include "gtls.h" /* GnuTLS versions */ -#include "nssg.h" /* NSS versions */ -#include "gskit.h" /* Global Secure ToolKit versions */ -#include "polarssl.h" /* PolarSSL versions */ -#include "axtls.h" /* axTLS versions */ -#include "cyassl.h" /* CyaSSL versions */ -#include "schannel.h" /* Schannel SSPI version */ -#include "darwinssl.h" /* SecureTransport (Darwin) version */ -#include "mbedtls.h" /* mbedTLS versions */ - -#ifndef MAX_PINNED_PUBKEY_SIZE -#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ -#endif - -#ifndef MD5_DIGEST_LENGTH -#define MD5_DIGEST_LENGTH 16 /* fixed size */ -#endif - -#ifndef CURL_SHA256_DIGEST_LENGTH -#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */ -#endif - -/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */ -#define ALPN_HTTP_1_1_LENGTH 8 -#define ALPN_HTTP_1_1 "http/1.1" - -/* set of helper macros for the backends to access the correct fields. For the - proxy or for the remote host - to properly support HTTPS proxy */ - -#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \ - ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \ - CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state) -#define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \ - data->set.ssl.var) -#define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \ - conn->proxy_ssl_config.var : conn->ssl_config.var) - -bool Curl_ssl_config_matches(struct ssl_primary_config* data, - struct ssl_primary_config* needle); -bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source, - struct ssl_primary_config *dest); -void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc); -int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, - int numsocks); - -int Curl_ssl_backend(void); - -#ifdef USE_SSL -int Curl_ssl_init(void); -void Curl_ssl_cleanup(void); -CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); -/* tell the SSL stuff to close down all open information regarding - connections (and thus session ID caching etc) */ -void Curl_ssl_close_all(struct Curl_easy *data); -void Curl_ssl_close(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine); -/* Sets engine as default for all SSL operations */ -CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data); -struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data); - -/* init the SSL session ID cache */ -CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t); -size_t Curl_ssl_version(char *buffer, size_t size); -bool Curl_ssl_data_pending(const struct connectdata *conn, - int connindex); -int Curl_ssl_check_cxn(struct connectdata *conn); - -/* Certificate information list handling. */ - -void Curl_ssl_free_certinfo(struct Curl_easy *data); -CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num); -CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum, - const char *label, const char *value, - size_t valuelen); -CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum, - const char *label, const char *value); - -/* Functions to be used by SSL library adaptation functions */ - -/* Lock session cache mutex. - * Call this before calling other Curl_ssl_*session* functions - * Caller should unlock this mutex as soon as possible, as it may block - * other SSL connection from making progress. - * The purpose of explicitly locking SSL session cache data is to allow - * individual SSL engines to manage session lifetime in their specific way. - */ -void Curl_ssl_sessionid_lock(struct connectdata *conn); - -/* Unlock session cache mutex */ -void Curl_ssl_sessionid_unlock(struct connectdata *conn); - -/* extract a session ID - * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). - * Caller must make sure that the ownership of returned sessionid object - * is properly taken (e.g. its refcount is incremented - * under sessionid mutex). - */ -bool Curl_ssl_getsessionid(struct connectdata *conn, - void **ssl_sessionid, - size_t *idsize, /* set 0 if unknown */ - int sockindex); -/* add a new session ID - * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). - * Caller must ensure that it has properly shared ownership of this sessionid - * object with cache (e.g. incrementing refcount on success) - */ -CURLcode Curl_ssl_addsessionid(struct connectdata *conn, - void *ssl_sessionid, - size_t idsize, - int sockindex); -/* Kill a single session ID entry in the cache - * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). - * This will call engine-specific curlssl_session_free function, which must - * take sessionid object ownership from sessionid cache - * (e.g. decrement refcount). - */ -void Curl_ssl_kill_session(struct curl_ssl_session *session); -/* delete a session from the cache - * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). - * This will call engine-specific curlssl_session_free function, which must - * take sessionid object ownership from sessionid cache - * (e.g. decrement refcount). - */ -void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); - -/* get N random bytes into the buffer */ -CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer, - size_t length); -CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len); -/* Check pinned public key. */ -CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, - const char *pinnedpubkey, - const unsigned char *pubkey, size_t pubkeylen); - -bool Curl_ssl_cert_status_request(void); - -bool Curl_ssl_false_start(void); - -#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ - -#else - -/* When SSL support is not present, just define away these function calls */ -#define Curl_ssl_init() 1 -#define Curl_ssl_cleanup() Curl_nop_stmt -#define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN -#define Curl_ssl_close_all(x) Curl_nop_stmt -#define Curl_ssl_close(x,y) Curl_nop_stmt -#define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN -#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN -#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN -#define Curl_ssl_engines_list(x) NULL -#define Curl_ssl_send(a,b,c,d,e) -1 -#define Curl_ssl_recv(a,b,c,d,e) -1 -#define Curl_ssl_initsessions(x,y) CURLE_OK -#define Curl_ssl_version(x,y) 0 -#define Curl_ssl_data_pending(x,y) 0 -#define Curl_ssl_check_cxn(x) 0 -#define Curl_ssl_free_certinfo(x) Curl_nop_stmt -#define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN -#define Curl_ssl_kill_session(x) Curl_nop_stmt -#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) -#define Curl_ssl_cert_status_request() FALSE -#define Curl_ssl_false_start() FALSE -#endif - -#endif /* HEADER_CURL_VTLS_H */ diff --git a/dep/cpr/opt/curl/lib/warnless.c b/dep/cpr/opt/curl/lib/warnless.c deleted file mode 100644 index 05d9038dc3c..00000000000 --- a/dep/cpr/opt/curl/lib/warnless.c +++ /dev/null @@ -1,546 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(__INTEL_COMPILER) && defined(__unix__) - -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif - -#endif /* __INTEL_COMPILER && __unix__ */ - -#define BUILDING_WARNLESS_C 1 - -#include "warnless.h" - -#define CURL_MASK_SCHAR 0x7F -#define CURL_MASK_UCHAR 0xFF - -#if (SIZEOF_SHORT == 2) -# define CURL_MASK_SSHORT 0x7FFF -# define CURL_MASK_USHORT 0xFFFF -#elif (SIZEOF_SHORT == 4) -# define CURL_MASK_SSHORT 0x7FFFFFFF -# define CURL_MASK_USHORT 0xFFFFFFFF -#elif (SIZEOF_SHORT == 8) -# define CURL_MASK_SSHORT 0x7FFFFFFFFFFFFFFF -# define CURL_MASK_USHORT 0xFFFFFFFFFFFFFFFF -#else -# error "SIZEOF_SHORT not defined" -#endif - -#if (SIZEOF_INT == 2) -# define CURL_MASK_SINT 0x7FFF -# define CURL_MASK_UINT 0xFFFF -#elif (SIZEOF_INT == 4) -# define CURL_MASK_SINT 0x7FFFFFFF -# define CURL_MASK_UINT 0xFFFFFFFF -#elif (SIZEOF_INT == 8) -# define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFF -# define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFF -#elif (SIZEOF_INT == 16) -# define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -# define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -#else -# error "SIZEOF_INT not defined" -#endif - -#if (SIZEOF_LONG == 2) -# define CURL_MASK_SLONG 0x7FFFL -# define CURL_MASK_ULONG 0xFFFFUL -#elif (SIZEOF_LONG == 4) -# define CURL_MASK_SLONG 0x7FFFFFFFL -# define CURL_MASK_ULONG 0xFFFFFFFFUL -#elif (SIZEOF_LONG == 8) -# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFL -# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFUL -#elif (SIZEOF_LONG == 16) -# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL -# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL -#else -# error "SIZEOF_LONG not defined" -#endif - -#if (SIZEOF_CURL_OFF_T == 2) -# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFF) -# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFF) -#elif (SIZEOF_CURL_OFF_T == 4) -# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFF) -# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFF) -#elif (SIZEOF_CURL_OFF_T == 8) -# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) -# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFF) -#elif (SIZEOF_CURL_OFF_T == 16) -# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) -# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) -#else -# error "SIZEOF_CURL_OFF_T not defined" -#endif - -#if (SIZEOF_SIZE_T == SIZEOF_SHORT) -# define CURL_MASK_SSIZE_T CURL_MASK_SSHORT -# define CURL_MASK_USIZE_T CURL_MASK_USHORT -#elif (SIZEOF_SIZE_T == SIZEOF_INT) -# define CURL_MASK_SSIZE_T CURL_MASK_SINT -# define CURL_MASK_USIZE_T CURL_MASK_UINT -#elif (SIZEOF_SIZE_T == SIZEOF_LONG) -# define CURL_MASK_SSIZE_T CURL_MASK_SLONG -# define CURL_MASK_USIZE_T CURL_MASK_ULONG -#elif (SIZEOF_SIZE_T == SIZEOF_CURL_OFF_T) -# define CURL_MASK_SSIZE_T CURL_MASK_SCOFFT -# define CURL_MASK_USIZE_T CURL_MASK_UCOFFT -#else -# error "SIZEOF_SIZE_T not defined" -#endif - -/* -** unsigned long to unsigned short -*/ - -unsigned short curlx_ultous(unsigned long ulnum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT); - return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned long to unsigned char -*/ - -unsigned char curlx_ultouc(unsigned long ulnum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_UCHAR); - return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned long to signed int -*/ - -int curlx_ultosi(unsigned long ulnum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_SINT); - return (int)(ulnum & (unsigned long) CURL_MASK_SINT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned size_t to signed curl_off_t -*/ - -curl_off_t curlx_uztoso(size_t uznum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#elif defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable:4310) /* cast truncates constant value */ -#endif - - DEBUGASSERT(uznum <= (size_t) CURL_MASK_SCOFFT); - return (curl_off_t)(uznum & (size_t) CURL_MASK_SCOFFT); - -#if defined(__INTEL_COMPILER) || defined(_MSC_VER) -# pragma warning(pop) -#endif -} - -/* -** unsigned size_t to signed int -*/ - -int curlx_uztosi(size_t uznum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(uznum <= (size_t) CURL_MASK_SINT); - return (int)(uznum & (size_t) CURL_MASK_SINT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned size_t to unsigned long -*/ - -unsigned long curlx_uztoul(size_t uznum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - -#if (SIZEOF_LONG < SIZEOF_SIZE_T) - DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG); -#endif - return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned size_t to unsigned int -*/ - -unsigned int curlx_uztoui(size_t uznum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - -#if (SIZEOF_INT < SIZEOF_SIZE_T) - DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT); -#endif - return (unsigned int)(uznum & (size_t) CURL_MASK_UINT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** signed long to signed int -*/ - -int curlx_sltosi(long slnum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(slnum >= 0); -#if (SIZEOF_INT < SIZEOF_LONG) - DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT); -#endif - return (int)(slnum & (long) CURL_MASK_SINT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** signed long to unsigned int -*/ - -unsigned int curlx_sltoui(long slnum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(slnum >= 0); -#if (SIZEOF_INT < SIZEOF_LONG) - DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT); -#endif - return (unsigned int)(slnum & (long) CURL_MASK_UINT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** signed long to unsigned short -*/ - -unsigned short curlx_sltous(long slnum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(slnum >= 0); - DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_USHORT); - return (unsigned short)(slnum & (long) CURL_MASK_USHORT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned size_t to signed ssize_t -*/ - -ssize_t curlx_uztosz(size_t uznum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(uznum <= (size_t) CURL_MASK_SSIZE_T); - return (ssize_t)(uznum & (size_t) CURL_MASK_SSIZE_T); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** signed curl_off_t to unsigned size_t -*/ - -size_t curlx_sotouz(curl_off_t sonum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(sonum >= 0); - return (size_t)(sonum & (curl_off_t) CURL_MASK_USIZE_T); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** signed ssize_t to signed int -*/ - -int curlx_sztosi(ssize_t sznum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(sznum >= 0); -#if (SIZEOF_INT < SIZEOF_SIZE_T) - DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT); -#endif - return (int)(sznum & (ssize_t) CURL_MASK_SINT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned int to unsigned short -*/ - -unsigned short curlx_uitous(unsigned int uinum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT); - return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned int to unsigned char -*/ - -unsigned char curlx_uitouc(unsigned int uinum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_UCHAR); - return (unsigned char) (uinum & (unsigned int) CURL_MASK_UCHAR); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** unsigned int to signed int -*/ - -int curlx_uitosi(unsigned int uinum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_SINT); - return (int) (uinum & (unsigned int) CURL_MASK_SINT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -/* -** signed int to unsigned size_t -*/ - -size_t curlx_sitouz(int sinum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(sinum >= 0); - return (size_t) sinum; - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - -#ifdef USE_WINSOCK - -/* -** curl_socket_t to signed int -*/ - -int curlx_sktosi(curl_socket_t s) -{ - return (int)((ssize_t) s); -} - -/* -** signed int to curl_socket_t -*/ - -curl_socket_t curlx_sitosk(int i) -{ - return (curl_socket_t)((ssize_t) i); -} - -#endif /* USE_WINSOCK */ - -#if defined(WIN32) || defined(_WIN32) - -ssize_t curlx_read(int fd, void *buf, size_t count) -{ - return (ssize_t)read(fd, buf, curlx_uztoui(count)); -} - -ssize_t curlx_write(int fd, const void *buf, size_t count) -{ - return (ssize_t)write(fd, buf, curlx_uztoui(count)); -} - -#endif /* WIN32 || _WIN32 */ - -#if defined(__INTEL_COMPILER) && defined(__unix__) - -int curlx_FD_ISSET(int fd, fd_set *fdset) -{ - #pragma warning(push) - #pragma warning(disable:1469) /* clobber ignored */ - return FD_ISSET(fd, fdset); - #pragma warning(pop) -} - -void curlx_FD_SET(int fd, fd_set *fdset) -{ - #pragma warning(push) - #pragma warning(disable:1469) /* clobber ignored */ - FD_SET(fd, fdset); - #pragma warning(pop) -} - -void curlx_FD_ZERO(fd_set *fdset) -{ - #pragma warning(push) - #pragma warning(disable:593) /* variable was set but never used */ - FD_ZERO(fdset); - #pragma warning(pop) -} - -unsigned short curlx_htons(unsigned short usnum) -{ -#if (__INTEL_COMPILER == 910) && defined(__i386__) - return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF)); -#else - #pragma warning(push) - #pragma warning(disable:810) /* conversion may lose significant bits */ - return htons(usnum); - #pragma warning(pop) -#endif -} - -unsigned short curlx_ntohs(unsigned short usnum) -{ -#if (__INTEL_COMPILER == 910) && defined(__i386__) - return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF)); -#else - #pragma warning(push) - #pragma warning(disable:810) /* conversion may lose significant bits */ - return ntohs(usnum); - #pragma warning(pop) -#endif -} - -#endif /* __INTEL_COMPILER && __unix__ */ diff --git a/dep/cpr/opt/curl/lib/warnless.h b/dep/cpr/opt/curl/lib/warnless.h deleted file mode 100644 index ab6d29998da..00000000000 --- a/dep/cpr/opt/curl/lib/warnless.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef HEADER_CURL_WARNLESS_H -#define HEADER_CURL_WARNLESS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#ifdef USE_WINSOCK -#include /* for curl_socket_t */ -#endif - -unsigned short curlx_ultous(unsigned long ulnum); - -unsigned char curlx_ultouc(unsigned long ulnum); - -int curlx_ultosi(unsigned long ulnum); - -int curlx_uztosi(size_t uznum); - -curl_off_t curlx_uztoso(size_t uznum); - -unsigned long curlx_uztoul(size_t uznum); - -unsigned int curlx_uztoui(size_t uznum); - -int curlx_sltosi(long slnum); - -unsigned int curlx_sltoui(long slnum); - -unsigned short curlx_sltous(long slnum); - -ssize_t curlx_uztosz(size_t uznum); - -size_t curlx_sotouz(curl_off_t sonum); - -int curlx_sztosi(ssize_t sznum); - -unsigned short curlx_uitous(unsigned int uinum); - -unsigned char curlx_uitouc(unsigned int uinum); - -int curlx_uitosi(unsigned int uinum); - -size_t curlx_sitouz(int sinum); - -#ifdef USE_WINSOCK - -int curlx_sktosi(curl_socket_t s); - -curl_socket_t curlx_sitosk(int i); - -#endif /* USE_WINSOCK */ - -#if defined(WIN32) || defined(_WIN32) - -ssize_t curlx_read(int fd, void *buf, size_t count); - -ssize_t curlx_write(int fd, const void *buf, size_t count); - -#ifndef BUILDING_WARNLESS_C -# undef read -# define read(fd, buf, count) curlx_read(fd, buf, count) -# undef write -# define write(fd, buf, count) curlx_write(fd, buf, count) -#endif - -#endif /* WIN32 || _WIN32 */ - -#if defined(__INTEL_COMPILER) && defined(__unix__) - -int curlx_FD_ISSET(int fd, fd_set *fdset); - -void curlx_FD_SET(int fd, fd_set *fdset); - -void curlx_FD_ZERO(fd_set *fdset); - -unsigned short curlx_htons(unsigned short usnum); - -unsigned short curlx_ntohs(unsigned short usnum); - -#ifndef BUILDING_WARNLESS_C -# undef FD_ISSET -# define FD_ISSET(a,b) curlx_FD_ISSET((a),(b)) -# undef FD_SET -# define FD_SET(a,b) curlx_FD_SET((a),(b)) -# undef FD_ZERO -# define FD_ZERO(a) curlx_FD_ZERO((a)) -# undef htons -# define htons(a) curlx_htons((a)) -# undef ntohs -# define ntohs(a) curlx_ntohs((a)) -#endif - -#endif /* __INTEL_COMPILER && __unix__ */ - -#endif /* HEADER_CURL_WARNLESS_H */ diff --git a/dep/cpr/opt/curl/lib/wildcard.c b/dep/cpr/opt/curl/lib/wildcard.c deleted file mode 100644 index af45c79bd3c..00000000000 --- a/dep/cpr/opt/curl/lib/wildcard.c +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "wildcard.h" -#include "llist.h" -#include "fileinfo.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -CURLcode Curl_wildcard_init(struct WildcardData *wc) -{ - Curl_llist_init(&wc->filelist, Curl_fileinfo_dtor); - wc->state = CURLWC_INIT; - - return CURLE_OK; -} - -void Curl_wildcard_dtor(struct WildcardData *wc) -{ - if(!wc) - return; - - if(wc->tmp_dtor) { - wc->tmp_dtor(wc->tmp); - wc->tmp_dtor = ZERO_NULL; - wc->tmp = NULL; - } - DEBUGASSERT(wc->tmp == NULL); - - Curl_llist_destroy(&wc->filelist, NULL); - - - free(wc->path); - wc->path = NULL; - free(wc->pattern); - wc->pattern = NULL; - - wc->customptr = NULL; - wc->state = CURLWC_INIT; -} diff --git a/dep/cpr/opt/curl/lib/wildcard.h b/dep/cpr/opt/curl/lib/wildcard.h deleted file mode 100644 index 8a5e4b769b2..00000000000 --- a/dep/cpr/opt/curl/lib/wildcard.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef HEADER_CURL_WILDCARD_H -#define HEADER_CURL_WILDCARD_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -#include "llist.h" - -/* list of wildcard process states */ -typedef enum { - CURLWC_CLEAR = 0, - CURLWC_INIT = 1, - CURLWC_MATCHING, /* library is trying to get list of addresses for - downloading */ - CURLWC_DOWNLOADING, - CURLWC_CLEAN, /* deallocate resources and reset settings */ - CURLWC_SKIP, /* skip over concrete file */ - CURLWC_ERROR, /* error cases */ - CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop - will end */ -} curl_wildcard_states; - -typedef void (*curl_wildcard_tmp_dtor)(void *ptr); - -/* struct keeping information about wildcard download process */ -struct WildcardData { - curl_wildcard_states state; - char *path; /* path to the directory, where we trying wildcard-match */ - char *pattern; /* wildcard pattern */ - struct curl_llist filelist; /* llist with struct Curl_fileinfo */ - void *tmp; /* pointer to protocol specific temporary data */ - curl_wildcard_tmp_dtor tmp_dtor; - void *customptr; /* for CURLOPT_CHUNK_DATA pointer */ -}; - -CURLcode Curl_wildcard_init(struct WildcardData *wc); -void Curl_wildcard_dtor(struct WildcardData *wc); - -struct Curl_easy; - -#endif /* HEADER_CURL_WILDCARD_H */ diff --git a/dep/cpr/opt/curl/lib/x509asn1.c b/dep/cpr/opt/curl/lib/x509asn1.c deleted file mode 100644 index bba20233f27..00000000000 --- a/dep/cpr/opt/curl/lib/x509asn1.c +++ /dev/null @@ -1,1200 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_CYASSL) || defined(USE_SCHANNEL) - -#include -#include "urldata.h" -#include "strcase.h" -#include "hostcheck.h" -#include "vtls/vtls.h" -#include "sendf.h" -#include "inet_pton.h" -#include "curl_base64.h" -#include "x509asn1.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* For overflow checks. */ -#define CURL_SIZE_T_MAX ((size_t)-1) - - -/* ASN.1 OIDs. */ -static const char cnOID[] = "2.5.4.3"; /* Common name. */ -static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */ - -static const curl_OID OIDtable[] = { - { "1.2.840.10040.4.1", "dsa" }, - { "1.2.840.10040.4.3", "dsa-with-sha1" }, - { "1.2.840.10045.2.1", "ecPublicKey" }, - { "1.2.840.10045.3.0.1", "c2pnb163v1" }, - { "1.2.840.10045.4.1", "ecdsa-with-SHA1" }, - { "1.2.840.10046.2.1", "dhpublicnumber" }, - { "1.2.840.113549.1.1.1", "rsaEncryption" }, - { "1.2.840.113549.1.1.2", "md2WithRSAEncryption" }, - { "1.2.840.113549.1.1.4", "md5WithRSAEncryption" }, - { "1.2.840.113549.1.1.5", "sha1WithRSAEncryption" }, - { "1.2.840.113549.1.1.10", "RSASSA-PSS" }, - { "1.2.840.113549.1.1.14", "sha224WithRSAEncryption" }, - { "1.2.840.113549.1.1.11", "sha256WithRSAEncryption" }, - { "1.2.840.113549.1.1.12", "sha384WithRSAEncryption" }, - { "1.2.840.113549.1.1.13", "sha512WithRSAEncryption" }, - { "1.2.840.113549.2.2", "md2" }, - { "1.2.840.113549.2.5", "md5" }, - { "1.3.14.3.2.26", "sha1" }, - { cnOID, "CN" }, - { "2.5.4.4", "SN" }, - { "2.5.4.5", "serialNumber" }, - { "2.5.4.6", "C" }, - { "2.5.4.7", "L" }, - { "2.5.4.8", "ST" }, - { "2.5.4.9", "streetAddress" }, - { "2.5.4.10", "O" }, - { "2.5.4.11", "OU" }, - { "2.5.4.12", "title" }, - { "2.5.4.13", "description" }, - { "2.5.4.17", "postalCode" }, - { "2.5.4.41", "name" }, - { "2.5.4.42", "givenName" }, - { "2.5.4.43", "initials" }, - { "2.5.4.44", "generationQualifier" }, - { "2.5.4.45", "X500UniqueIdentifier" }, - { "2.5.4.46", "dnQualifier" }, - { "2.5.4.65", "pseudonym" }, - { "1.2.840.113549.1.9.1", "emailAddress" }, - { "2.5.4.72", "role" }, - { sanOID, "subjectAltName" }, - { "2.5.29.18", "issuerAltName" }, - { "2.5.29.19", "basicConstraints" }, - { "2.16.840.1.101.3.4.2.4", "sha224" }, - { "2.16.840.1.101.3.4.2.1", "sha256" }, - { "2.16.840.1.101.3.4.2.2", "sha384" }, - { "2.16.840.1.101.3.4.2.3", "sha512" }, - { (const char *) NULL, (const char *) NULL } -}; - -/* - * Lightweight ASN.1 parser. - * In particular, it does not check for syntactic/lexical errors. - * It is intended to support certificate information gathering for SSL backends - * that offer a mean to get certificates as a whole, but do not supply - * entry points to get particular certificate sub-fields. - * Please note there is no pretention here to rewrite a full SSL library. - */ - - -const char *Curl_getASN1Element(curl_asn1Element *elem, - const char *beg, const char *end) -{ - unsigned char b; - unsigned long len; - curl_asn1Element lelem; - - /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg' - ending at `end'. - Returns a pointer in source string after the parsed element, or NULL - if an error occurs. */ - if(!beg || !end || beg >= end || !*beg || - (size_t)(end - beg) > CURL_ASN1_MAX) - return (const char *) NULL; - - /* Process header byte. */ - elem->header = beg; - b = (unsigned char) *beg++; - elem->constructed = (b & 0x20) != 0; - elem->class = (b >> 6) & 3; - b &= 0x1F; - if(b == 0x1F) - return (const char *) NULL; /* Long tag values not supported here. */ - elem->tag = b; - - /* Process length. */ - if(beg >= end) - return (const char *) NULL; - b = (unsigned char) *beg++; - if(!(b & 0x80)) - len = b; - else if(!(b &= 0x7F)) { - /* Unspecified length. Since we have all the data, we can determine the - effective length by skipping element until an end element is found. */ - if(!elem->constructed) - return (const char *) NULL; - elem->beg = beg; - while(beg < end && *beg) { - beg = Curl_getASN1Element(&lelem, beg, end); - if(!beg) - return (const char *) NULL; - } - if(beg >= end) - return (const char *) NULL; - elem->end = beg; - return beg + 1; - } - else if((unsigned)b > (size_t)(end - beg)) - return (const char *) NULL; /* Does not fit in source. */ - else { - /* Get long length. */ - len = 0; - do { - if(len & 0xFF000000L) - return (const char *) NULL; /* Lengths > 32 bits are not supported. */ - len = (len << 8) | (unsigned char) *beg++; - } while(--b); - } - if(len > (size_t)(end - beg)) - return (const char *) NULL; /* Element data does not fit in source. */ - elem->beg = beg; - elem->end = beg + len; - return elem->end; -} - -static const curl_OID * searchOID(const char *oid) -{ - const curl_OID *op; - - /* Search the null terminated OID or OID identifier in local table. - Return the table entry pointer or NULL if not found. */ - - for(op = OIDtable; op->numoid; op++) - if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid)) - return op; - - return (const curl_OID *) NULL; -} - -static const char *bool2str(const char *beg, const char *end) -{ - /* Convert an ASN.1 Boolean value into its string representation. - Return the dynamically allocated string, or NULL if source is not an - ASN.1 Boolean value. */ - - if(end - beg != 1) - return (const char *) NULL; - return strdup(*beg? "TRUE": "FALSE"); -} - -static const char *octet2str(const char *beg, const char *end) -{ - size_t n = end - beg; - char *buf = NULL; - - /* Convert an ASN.1 octet string to a printable string. - Return the dynamically allocated string, or NULL if an error occurs. */ - - if(n <= (CURL_SIZE_T_MAX - 1) / 3) { - buf = malloc(3 * n + 1); - if(buf) - for(n = 0; beg < end; n += 3) - snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); - } - return buf; -} - -static const char *bit2str(const char *beg, const char *end) -{ - /* Convert an ASN.1 bit string to a printable string. - Return the dynamically allocated string, or NULL if an error occurs. */ - - if(++beg > end) - return (const char *) NULL; - return octet2str(beg, end); -} - -static const char *int2str(const char *beg, const char *end) -{ - long val = 0; - size_t n = end - beg; - - /* Convert an ASN.1 integer value into its string representation. - Return the dynamically allocated string, or NULL if source is not an - ASN.1 integer value. */ - - if(!n) - return (const char *) NULL; - - if(n > 4) - return octet2str(beg, end); - - /* Represent integers <= 32-bit as a single value. */ - if(*beg & 0x80) - val = ~val; - - do - val = (val << 8) | *(const unsigned char *) beg++; - while(beg < end); - return curl_maprintf("%s%lx", (val < 0 || val >= 10)? "0x": "", val); -} - -static ssize_t -utf8asn1str(char **to, int type, const char *from, const char *end) -{ - size_t inlength = end - from; - int size = 1; - size_t outlength; - int charsize; - unsigned int wc; - char *buf; - - /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the - destination buffer dynamically. The allocation size will normally be too - large: this is to avoid buffer overflows. - Terminate the string with a nul byte and return the converted - string length. */ - - *to = (char *) NULL; - switch(type) { - case CURL_ASN1_BMP_STRING: - size = 2; - break; - case CURL_ASN1_UNIVERSAL_STRING: - size = 4; - break; - case CURL_ASN1_NUMERIC_STRING: - case CURL_ASN1_PRINTABLE_STRING: - case CURL_ASN1_TELETEX_STRING: - case CURL_ASN1_IA5_STRING: - case CURL_ASN1_VISIBLE_STRING: - case CURL_ASN1_UTF8_STRING: - break; - default: - return -1; /* Conversion not supported. */ - } - - if(inlength % size) - return -1; /* Length inconsistent with character size. */ - if(inlength / size > (CURL_SIZE_T_MAX - 1) / 4) - return -1; /* Too big. */ - buf = malloc(4 * (inlength / size) + 1); - if(!buf) - return -1; /* Not enough memory. */ - - if(type == CURL_ASN1_UTF8_STRING) { - /* Just copy. */ - outlength = inlength; - if(outlength) - memcpy(buf, from, outlength); - } - else { - for(outlength = 0; from < end;) { - wc = 0; - switch(size) { - case 4: - wc = (wc << 8) | *(const unsigned char *) from++; - wc = (wc << 8) | *(const unsigned char *) from++; - /* fallthrough */ - case 2: - wc = (wc << 8) | *(const unsigned char *) from++; - /* fallthrough */ - default: /* case 1: */ - wc = (wc << 8) | *(const unsigned char *) from++; - } - charsize = 1; - if(wc >= 0x00000080) { - if(wc >= 0x00000800) { - if(wc >= 0x00010000) { - if(wc >= 0x00200000) { - free(buf); - return -1; /* Invalid char. size for target encoding. */ - } - buf[outlength + 3] = (char) (0x80 | (wc & 0x3F)); - wc = (wc >> 6) | 0x00010000; - charsize++; - } - buf[outlength + 2] = (char) (0x80 | (wc & 0x3F)); - wc = (wc >> 6) | 0x00000800; - charsize++; - } - buf[outlength + 1] = (char) (0x80 | (wc & 0x3F)); - wc = (wc >> 6) | 0x000000C0; - charsize++; - } - buf[outlength] = (char) wc; - outlength += charsize; - } - } - buf[outlength] = '\0'; - *to = buf; - return outlength; -} - -static const char *string2str(int type, const char *beg, const char *end) -{ - char *buf; - - /* Convert an ASN.1 String into its UTF-8 string representation. - Return the dynamically allocated string, or NULL if an error occurs. */ - - if(utf8asn1str(&buf, type, beg, end) < 0) - return (const char *) NULL; - return buf; -} - -static int encodeUint(char *buf, int n, unsigned int x) -{ - int i = 0; - unsigned int y = x / 10; - - /* Decimal ASCII encode unsigned integer `x' in the `n'-byte buffer at `buf'. - Return the total number of encoded digits, even if larger than `n'. */ - - if(y) { - i += encodeUint(buf, n, y); - x -= y * 10; - } - if(i < n) - buf[i] = (char) ('0' + x); - i++; - if(i < n) - buf[i] = '\0'; /* Store a terminator if possible. */ - return i; -} - -static int encodeOID(char *buf, int n, const char *beg, const char *end) -{ - int i = 0; - unsigned int x; - unsigned int y; - - /* Convert an ASN.1 OID into its dotted string representation. - Store the result in th `n'-byte buffer at `buf'. - Return the converted string length, or -1 if an error occurs. */ - - /* Process the first two numbers. */ - y = *(const unsigned char *) beg++; - x = y / 40; - y -= x * 40; - i += encodeUint(buf + i, n - i, x); - if(i < n) - buf[i] = '.'; - i++; - i += encodeUint(buf + i, n - i, y); - - /* Process the trailing numbers. */ - while(beg < end) { - if(i < n) - buf[i] = '.'; - i++; - x = 0; - do { - if(x & 0xFF000000) - return -1; - y = *(const unsigned char *) beg++; - x = (x << 7) | (y & 0x7F); - } while(y & 0x80); - i += encodeUint(buf + i, n - i, x); - } - if(i < n) - buf[i] = '\0'; - return i; -} - -static const char *OID2str(const char *beg, const char *end, bool symbolic) -{ - char *buf = (char *) NULL; - const curl_OID * op; - int n; - - /* Convert an ASN.1 OID into its dotted or symbolic string representation. - Return the dynamically allocated string, or NULL if an error occurs. */ - - if(beg < end) { - n = encodeOID((char *) NULL, -1, beg, end); - if(n >= 0) { - buf = malloc(n + 1); - if(buf) { - encodeOID(buf, n, beg, end); - buf[n] = '\0'; - - if(symbolic) { - op = searchOID(buf); - if(op) { - free(buf); - buf = strdup(op->textoid); - } - } - } - } - } - return buf; -} - -static const char *GTime2str(const char *beg, const char *end) -{ - const char *tzp; - const char *fracp; - char sec1, sec2; - size_t fracl; - size_t tzl; - const char *sep = ""; - - /* Convert an ASN.1 Generalized time to a printable string. - Return the dynamically allocated string, or NULL if an error occurs. */ - - for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++) - ; - - /* Get seconds digits. */ - sec1 = '0'; - switch(fracp - beg - 12) { - case 0: - sec2 = '0'; - break; - case 2: - sec1 = fracp[-2]; - /* FALLTHROUGH */ - case 1: - sec2 = fracp[-1]; - break; - default: - return (const char *) NULL; - } - - /* Scan for timezone, measure fractional seconds. */ - tzp = fracp; - fracl = 0; - if(fracp < end && (*fracp == '.' || *fracp == ',')) { - fracp++; - do - tzp++; - while(tzp < end && *tzp >= '0' && *tzp <= '9'); - /* Strip leading zeroes in fractional seconds. */ - for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--) - ; - } - - /* Process timezone. */ - if(tzp >= end) - ; /* Nothing to do. */ - else if(*tzp == 'Z') { - tzp = " GMT"; - end = tzp + 4; - } - else { - sep = " "; - tzp++; - } - - tzl = end - tzp; - return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s", - beg, beg + 4, beg + 6, - beg + 8, beg + 10, sec1, sec2, - fracl? ".": "", fracl, fracp, - sep, tzl, tzp); -} - -static const char *UTime2str(const char *beg, const char *end) -{ - const char *tzp; - size_t tzl; - const char *sec; - - /* Convert an ASN.1 UTC time to a printable string. - Return the dynamically allocated string, or NULL if an error occurs. */ - - for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++) - ; - /* Get the seconds. */ - sec = beg + 10; - switch(tzp - sec) { - case 0: - sec = "00"; - case 2: - break; - default: - return (const char *) NULL; - } - - /* Process timezone. */ - if(tzp >= end) - return (const char *) NULL; - if(*tzp == 'Z') { - tzp = "GMT"; - end = tzp + 3; - } - else - tzp++; - - tzl = end - tzp; - return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s", - 20 - (*beg >= '5'), beg, beg + 2, beg + 4, - beg + 6, beg + 8, sec, - tzl, tzp); -} - -const char *Curl_ASN1tostr(curl_asn1Element *elem, int type) -{ - /* Convert an ASN.1 element to a printable string. - Return the dynamically allocated string, or NULL if an error occurs. */ - - if(elem->constructed) - return (const char *) NULL; /* No conversion of structured elements. */ - - if(!type) - type = elem->tag; /* Type not forced: use element tag as type. */ - - switch(type) { - case CURL_ASN1_BOOLEAN: - return bool2str(elem->beg, elem->end); - case CURL_ASN1_INTEGER: - case CURL_ASN1_ENUMERATED: - return int2str(elem->beg, elem->end); - case CURL_ASN1_BIT_STRING: - return bit2str(elem->beg, elem->end); - case CURL_ASN1_OCTET_STRING: - return octet2str(elem->beg, elem->end); - case CURL_ASN1_NULL: - return strdup(""); - case CURL_ASN1_OBJECT_IDENTIFIER: - return OID2str(elem->beg, elem->end, TRUE); - case CURL_ASN1_UTC_TIME: - return UTime2str(elem->beg, elem->end); - case CURL_ASN1_GENERALIZED_TIME: - return GTime2str(elem->beg, elem->end); - case CURL_ASN1_UTF8_STRING: - case CURL_ASN1_NUMERIC_STRING: - case CURL_ASN1_PRINTABLE_STRING: - case CURL_ASN1_TELETEX_STRING: - case CURL_ASN1_IA5_STRING: - case CURL_ASN1_VISIBLE_STRING: - case CURL_ASN1_UNIVERSAL_STRING: - case CURL_ASN1_BMP_STRING: - return string2str(type, elem->beg, elem->end); - } - - return (const char *) NULL; /* Unsupported. */ -} - -static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn) -{ - curl_asn1Element rdn; - curl_asn1Element atv; - curl_asn1Element oid; - curl_asn1Element value; - size_t l = 0; - const char *p1; - const char *p2; - const char *p3; - const char *str; - - /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'. - Return the total string length, even if larger than `n'. */ - - for(p1 = dn->beg; p1 < dn->end;) { - p1 = Curl_getASN1Element(&rdn, p1, dn->end); - for(p2 = rdn.beg; p2 < rdn.end;) { - p2 = Curl_getASN1Element(&atv, p2, rdn.end); - p3 = Curl_getASN1Element(&oid, atv.beg, atv.end); - Curl_getASN1Element(&value, p3, atv.end); - str = Curl_ASN1tostr(&oid, 0); - if(!str) - return -1; - - /* Encode delimiter. - If attribute has a short uppercase name, delimiter is ", ". */ - if(l) { - for(p3 = str; isupper(*p3); p3++) - ; - for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) { - if(l < n) - buf[l] = *p3; - l++; - } - } - - /* Encode attribute name. */ - for(p3 = str; *p3; p3++) { - if(l < n) - buf[l] = *p3; - l++; - } - free((char *) str); - - /* Generate equal sign. */ - if(l < n) - buf[l] = '='; - l++; - - /* Generate value. */ - str = Curl_ASN1tostr(&value, 0); - if(!str) - return -1; - for(p3 = str; *p3; p3++) { - if(l < n) - buf[l] = *p3; - l++; - } - free((char *) str); - } - } - - return l; -} - -const char *Curl_DNtostr(curl_asn1Element *dn) -{ - char *buf = (char *) NULL; - ssize_t n = encodeDN(buf, 0, dn); - - /* Convert an ASN.1 distinguished name into a printable string. - Return the dynamically allocated string, or NULL if an error occurs. */ - - if(n >= 0) { - buf = malloc(n + 1); - if(buf) { - encodeDN(buf, n + 1, dn); - buf[n] = '\0'; - } - } - return (const char *) buf; -} - -/* - * X509 parser. - */ - -int Curl_parseX509(curl_X509certificate *cert, - const char *beg, const char *end) -{ - curl_asn1Element elem; - curl_asn1Element tbsCertificate; - const char *ccp; - static const char defaultVersion = 0; /* v1. */ - - /* ASN.1 parse an X509 certificate into structure subfields. - Syntax is assumed to have already been checked by the SSL backend. - See RFC 5280. */ - - cert->certificate.header = NULL; - cert->certificate.beg = beg; - cert->certificate.end = end; - - /* Get the sequence content. */ - if(!Curl_getASN1Element(&elem, beg, end)) - return -1; /* Invalid bounds/size. */ - beg = elem.beg; - end = elem.end; - - /* Get tbsCertificate. */ - beg = Curl_getASN1Element(&tbsCertificate, beg, end); - /* Skip the signatureAlgorithm. */ - beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end); - /* Get the signatureValue. */ - Curl_getASN1Element(&cert->signature, beg, end); - - /* Parse TBSCertificate. */ - beg = tbsCertificate.beg; - end = tbsCertificate.end; - /* Get optional version, get serialNumber. */ - cert->version.header = NULL; - cert->version.beg = &defaultVersion; - cert->version.end = &defaultVersion + sizeof defaultVersion;; - beg = Curl_getASN1Element(&elem, beg, end); - if(elem.tag == 0) { - Curl_getASN1Element(&cert->version, elem.beg, elem.end); - beg = Curl_getASN1Element(&elem, beg, end); - } - cert->serialNumber = elem; - /* Get signature algorithm. */ - beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end); - /* Get issuer. */ - beg = Curl_getASN1Element(&cert->issuer, beg, end); - /* Get notBefore and notAfter. */ - beg = Curl_getASN1Element(&elem, beg, end); - ccp = Curl_getASN1Element(&cert->notBefore, elem.beg, elem.end); - Curl_getASN1Element(&cert->notAfter, ccp, elem.end); - /* Get subject. */ - beg = Curl_getASN1Element(&cert->subject, beg, end); - /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */ - beg = Curl_getASN1Element(&cert->subjectPublicKeyInfo, beg, end); - ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm, - cert->subjectPublicKeyInfo.beg, - cert->subjectPublicKeyInfo.end); - Curl_getASN1Element(&cert->subjectPublicKey, ccp, - cert->subjectPublicKeyInfo.end); - /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ - cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; - cert->extensions.tag = elem.tag = 0; - cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; - cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; - cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; - cert->extensions.header = NULL; - cert->extensions.beg = cert->extensions.end = ""; - if(beg < end) - beg = Curl_getASN1Element(&elem, beg, end); - if(elem.tag == 1) { - cert->issuerUniqueID = elem; - if(beg < end) - beg = Curl_getASN1Element(&elem, beg, end); - } - if(elem.tag == 2) { - cert->subjectUniqueID = elem; - if(beg < end) - beg = Curl_getASN1Element(&elem, beg, end); - } - if(elem.tag == 3) - Curl_getASN1Element(&cert->extensions, elem.beg, elem.end); - return 0; -} - -static size_t copySubstring(char *to, const char *from) -{ - size_t i; - - /* Copy at most 64-characters, terminate with a newline and returns the - effective number of stored characters. */ - - for(i = 0; i < 64; i++) { - to[i] = *from; - if(!*from++) - break; - } - - to[i++] = '\n'; - return i; -} - -static const char *dumpAlgo(curl_asn1Element *param, - const char *beg, const char *end) -{ - curl_asn1Element oid; - - /* Get algorithm parameters and return algorithm name. */ - - beg = Curl_getASN1Element(&oid, beg, end); - param->header = NULL; - param->tag = 0; - param->beg = param->end = end; - if(beg < end) - Curl_getASN1Element(param, beg, end); - return OID2str(oid.beg, oid.end, TRUE); -} - -static void do_pubkey_field(struct Curl_easy *data, int certnum, - const char *label, curl_asn1Element *elem) -{ - const char *output; - - /* Generate a certificate information record for the public key. */ - - output = Curl_ASN1tostr(elem, 0); - if(output) { - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, label, output); - if(!certnum) - infof(data, " %s: %s\n", label, output); - free((char *) output); - } -} - -static void do_pubkey(struct Curl_easy *data, int certnum, - const char *algo, curl_asn1Element *param, - curl_asn1Element *pubkey) -{ - curl_asn1Element elem; - curl_asn1Element pk; - const char *p; - const char *q; - unsigned long len; - unsigned int i; - - /* Generate all information records for the public key. */ - - /* Get the public key (single element). */ - Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end); - - if(strcasecompare(algo, "rsaEncryption")) { - p = Curl_getASN1Element(&elem, pk.beg, pk.end); - /* Compute key length. */ - for(q = elem.beg; !*q && q < elem.end; q++) - ; - len = (unsigned long)((elem.end - q) * 8); - if(len) - for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1) - len--; - if(len > 32) - elem.beg = q; /* Strip leading zero bytes. */ - if(!certnum) - infof(data, " RSA Public Key (%lu bits)\n", len); - if(data->set.ssl.certinfo) { - q = curl_maprintf("%lu", len); - if(q) { - Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q); - free((char *) q); - } - } - /* Generate coefficients. */ - do_pubkey_field(data, certnum, "rsa(n)", &elem); - Curl_getASN1Element(&elem, p, pk.end); - do_pubkey_field(data, certnum, "rsa(e)", &elem); - } - else if(strcasecompare(algo, "dsa")) { - p = Curl_getASN1Element(&elem, param->beg, param->end); - do_pubkey_field(data, certnum, "dsa(p)", &elem); - p = Curl_getASN1Element(&elem, p, param->end); - do_pubkey_field(data, certnum, "dsa(q)", &elem); - Curl_getASN1Element(&elem, p, param->end); - do_pubkey_field(data, certnum, "dsa(g)", &elem); - do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); - } - else if(strcasecompare(algo, "dhpublicnumber")) { - p = Curl_getASN1Element(&elem, param->beg, param->end); - do_pubkey_field(data, certnum, "dh(p)", &elem); - Curl_getASN1Element(&elem, param->beg, param->end); - do_pubkey_field(data, certnum, "dh(g)", &elem); - do_pubkey_field(data, certnum, "dh(pub_key)", &pk); - } -#if 0 /* Patent-encumbered. */ - else if(strcasecompare(algo, "ecPublicKey")) { - /* Left TODO. */ - } -#endif -} - -CURLcode Curl_extract_certinfo(struct connectdata *conn, - int certnum, - const char *beg, - const char *end) -{ - curl_X509certificate cert; - struct Curl_easy *data = conn->data; - curl_asn1Element param; - const char *ccp; - char *cp1; - size_t cl1; - char *cp2; - CURLcode result; - unsigned long version; - size_t i; - size_t j; - - if(!data->set.ssl.certinfo) - if(certnum) - return CURLE_OK; - - /* Prepare the certificate information for curl_easy_getinfo(). */ - - /* Extract the certificate ASN.1 elements. */ - if(Curl_parseX509(&cert, beg, end)) - return CURLE_OUT_OF_MEMORY; - - /* Subject. */ - ccp = Curl_DNtostr(&cert.subject); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Subject", ccp); - if(!certnum) - infof(data, "%2d Subject: %s\n", certnum, ccp); - free((char *) ccp); - - /* Issuer. */ - ccp = Curl_DNtostr(&cert.issuer); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp); - if(!certnum) - infof(data, " Issuer: %s\n", ccp); - free((char *) ccp); - - /* Version (always fits in less than 32 bits). */ - version = 0; - for(ccp = cert.version.beg; ccp < cert.version.end; ccp++) - version = (version << 8) | *(const unsigned char *) ccp; - if(data->set.ssl.certinfo) { - ccp = curl_maprintf("%lx", version); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - Curl_ssl_push_certinfo(data, certnum, "Version", ccp); - free((char *) ccp); - } - if(!certnum) - infof(data, " Version: %lu (0x%lx)\n", version + 1, version); - - /* Serial number. */ - ccp = Curl_ASN1tostr(&cert.serialNumber, 0); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp); - if(!certnum) - infof(data, " Serial Number: %s\n", ccp); - free((char *) ccp); - - /* Signature algorithm .*/ - ccp = dumpAlgo(¶m, cert.signatureAlgorithm.beg, - cert.signatureAlgorithm.end); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp); - if(!certnum) - infof(data, " Signature Algorithm: %s\n", ccp); - free((char *) ccp); - - /* Start Date. */ - ccp = Curl_ASN1tostr(&cert.notBefore, 0); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp); - if(!certnum) - infof(data, " Start Date: %s\n", ccp); - free((char *) ccp); - - /* Expire Date. */ - ccp = Curl_ASN1tostr(&cert.notAfter, 0); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp); - if(!certnum) - infof(data, " Expire Date: %s\n", ccp); - free((char *) ccp); - - /* Public Key Algorithm. */ - ccp = dumpAlgo(¶m, cert.subjectPublicKeyAlgorithm.beg, - cert.subjectPublicKeyAlgorithm.end); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp); - if(!certnum) - infof(data, " Public Key Algorithm: %s\n", ccp); - do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey); - free((char *) ccp); - -/* TODO: extensions. */ - - /* Signature. */ - ccp = Curl_ASN1tostr(&cert.signature, 0); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Signature", ccp); - if(!certnum) - infof(data, " Signature: %s\n", ccp); - free((char *) ccp); - - /* Generate PEM certificate. */ - result = Curl_base64_encode(data, cert.certificate.beg, - cert.certificate.end - cert.certificate.beg, - &cp1, &cl1); - if(result) - return result; - /* Compute the number of characters in final certificate string. Format is: - -----BEGIN CERTIFICATE-----\n - \n - . - . - . - -----END CERTIFICATE-----\n - */ - i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26; - cp2 = malloc(i + 1); - if(!cp2) { - free(cp1); - return CURLE_OUT_OF_MEMORY; - } - /* Build the certificate string. */ - i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----"); - for(j = 0; j < cl1; j += 64) - i += copySubstring(cp2 + i, cp1 + j); - i += copySubstring(cp2 + i, "-----END CERTIFICATE-----"); - cp2[i] = '\0'; - free(cp1); - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Cert", cp2); - if(!certnum) - infof(data, "%s\n", cp2); - free(cp2); - return CURLE_OK; -} - -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ - -#if defined(USE_GSKIT) - -static const char *checkOID(const char *beg, const char *end, - const char *oid) -{ - curl_asn1Element e; - const char *ccp; - const char *p; - bool matched; - - /* Check if first ASN.1 element at `beg' is the given OID. - Return a pointer in the source after the OID if found, else NULL. */ - - ccp = Curl_getASN1Element(&e, beg, end); - if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER) - return (const char *) NULL; - - p = OID2str(e.beg, e.end, FALSE); - if(!p) - return (const char *) NULL; - - matched = !strcmp(p, oid); - free((char *) p); - return matched? ccp: (const char *) NULL; -} - -CURLcode Curl_verifyhost(struct connectdata *conn, - const char *beg, const char *end) -{ - struct Curl_easy *data = conn->data; - curl_X509certificate cert; - curl_asn1Element dn; - curl_asn1Element elem; - curl_asn1Element ext; - curl_asn1Element name; - const char *p; - const char *q; - char *dnsname; - int matched = -1; - size_t addrlen = (size_t) -1; - ssize_t len; - const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: - conn->host.name; - const char * const dispname = SSL_IS_PROXY()? - conn->http_proxy.host.dispname: - conn->host.dispname; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - - /* Verify that connection server matches info in X509 certificate at - `beg'..`end'. */ - - if(!SSL_CONN_CONFIG(verifyhost)) - return CURLE_OK; - - if(Curl_parseX509(&cert, beg, end)) - return CURLE_PEER_FAILED_VERIFICATION; - - /* Get the server IP address. */ -#ifdef ENABLE_IPV6 - if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr)) - addrlen = sizeof(struct in6_addr); - else -#endif - if(Curl_inet_pton(AF_INET, hostname, &addr)) - addrlen = sizeof(struct in_addr); - - /* Process extensions. */ - for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) { - p = Curl_getASN1Element(&ext, p, cert.extensions.end); - /* Check if extension is a subjectAlternativeName. */ - ext.beg = checkOID(ext.beg, ext.end, sanOID); - if(ext.beg) { - ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end); - /* Skip critical if present. */ - if(elem.tag == CURL_ASN1_BOOLEAN) - ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end); - /* Parse the octet string contents: is a single sequence. */ - Curl_getASN1Element(&elem, elem.beg, elem.end); - /* Check all GeneralNames. */ - for(q = elem.beg; matched != 1 && q < elem.end;) { - q = Curl_getASN1Element(&name, q, elem.end); - switch(name.tag) { - case 2: /* DNS name. */ - len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, - name.beg, name.end); - if(len > 0 && (size_t)len == strlen(dnsname)) - matched = Curl_cert_hostcheck(dnsname, hostname); - else - matched = 0; - free(dnsname); - break; - - case 7: /* IP address. */ - matched = (size_t) (name.end - q) == addrlen && - !memcmp(&addr, q, addrlen); - break; - } - } - } - } - - switch(matched) { - case 1: - /* an alternative name matched the server hostname */ - infof(data, "\t subjectAltName: %s matched\n", dispname); - return CURLE_OK; - case 0: - /* an alternative name field existed, but didn't match and then - we MUST fail */ - infof(data, "\t subjectAltName does not match %s\n", dispname); - return CURLE_PEER_FAILED_VERIFICATION; - } - - /* Process subject. */ - name.header = NULL; - name.beg = name.end = ""; - q = cert.subject.beg; - /* we have to look to the last occurrence of a commonName in the - distinguished one to get the most significant one. */ - while(q < cert.subject.end) { - q = Curl_getASN1Element(&dn, q, cert.subject.end); - for(p = dn.beg; p < dn.end;) { - p = Curl_getASN1Element(&elem, p, dn.end); - /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */ - elem.beg = checkOID(elem.beg, elem.end, cnOID); - if(elem.beg) - name = elem; /* Latch CN. */ - } - } - - /* Check the CN if found. */ - if(!Curl_getASN1Element(&elem, name.beg, name.end)) - failf(data, "SSL: unable to obtain common name from peer certificate"); - else { - len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end); - if(len < 0) { - free(dnsname); - return CURLE_OUT_OF_MEMORY; - } - if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ - failf(data, "SSL: illegal cert name field"); - else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) { - infof(data, "\t common name: %s (matched)\n", dnsname); - free(dnsname); - return CURLE_OK; - } - else - failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", dnsname, dispname); - free(dnsname); - } - - return CURLE_PEER_FAILED_VERIFICATION; -} - -#endif /* USE_GSKIT */ diff --git a/dep/cpr/opt/curl/lib/x509asn1.h b/dep/cpr/opt/curl/lib/x509asn1.h deleted file mode 100644 index ce40297927a..00000000000 --- a/dep/cpr/opt/curl/lib/x509asn1.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef HEADER_CURL_X509ASN1_H -#define HEADER_CURL_X509ASN1_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_CYASSL) || defined(USE_SCHANNEL) - -#include "urldata.h" - -/* - * Constants. - */ - -/* Largest supported ASN.1 structure. */ -#define CURL_ASN1_MAX ((size_t) 0x40000) /* 256K */ - -/* ASN.1 classes. */ -#define CURL_ASN1_UNIVERSAL 0 -#define CURL_ASN1_APPLICATION 1 -#define CURL_ASN1_CONTEXT_SPECIFIC 2 -#define CURL_ASN1_PRIVATE 3 - -/* ASN.1 types. */ -#define CURL_ASN1_BOOLEAN 1 -#define CURL_ASN1_INTEGER 2 -#define CURL_ASN1_BIT_STRING 3 -#define CURL_ASN1_OCTET_STRING 4 -#define CURL_ASN1_NULL 5 -#define CURL_ASN1_OBJECT_IDENTIFIER 6 -#define CURL_ASN1_OBJECT_DESCRIPTOR 7 -#define CURL_ASN1_INSTANCE_OF 8 -#define CURL_ASN1_REAL 9 -#define CURL_ASN1_ENUMERATED 10 -#define CURL_ASN1_EMBEDDED 11 -#define CURL_ASN1_UTF8_STRING 12 -#define CURL_ASN1_RELATIVE_OID 13 -#define CURL_ASN1_SEQUENCE 16 -#define CURL_ASN1_SET 17 -#define CURL_ASN1_NUMERIC_STRING 18 -#define CURL_ASN1_PRINTABLE_STRING 19 -#define CURL_ASN1_TELETEX_STRING 20 -#define CURL_ASN1_VIDEOTEX_STRING 21 -#define CURL_ASN1_IA5_STRING 22 -#define CURL_ASN1_UTC_TIME 23 -#define CURL_ASN1_GENERALIZED_TIME 24 -#define CURL_ASN1_GRAPHIC_STRING 25 -#define CURL_ASN1_VISIBLE_STRING 26 -#define CURL_ASN1_GENERAL_STRING 27 -#define CURL_ASN1_UNIVERSAL_STRING 28 -#define CURL_ASN1_CHARACTER_STRING 29 -#define CURL_ASN1_BMP_STRING 30 - - -/* - * Types. - */ - -/* ASN.1 parsed element. */ -typedef struct { - const char * header; /* Pointer to header byte. */ - const char * beg; /* Pointer to element data. */ - const char * end; /* Pointer to 1st byte after element. */ - unsigned char class; /* ASN.1 element class. */ - unsigned char tag; /* ASN.1 element tag. */ - bool constructed; /* Element is constructed. */ -} curl_asn1Element; - - -/* ASN.1 OID table entry. */ -typedef struct { - const char * numoid; /* Dotted-numeric OID. */ - const char * textoid; /* OID name. */ -} curl_OID; - - -/* X509 certificate: RFC 5280. */ -typedef struct { - curl_asn1Element certificate; - curl_asn1Element version; - curl_asn1Element serialNumber; - curl_asn1Element signatureAlgorithm; - curl_asn1Element signature; - curl_asn1Element issuer; - curl_asn1Element notBefore; - curl_asn1Element notAfter; - curl_asn1Element subject; - curl_asn1Element subjectPublicKeyInfo; - curl_asn1Element subjectPublicKeyAlgorithm; - curl_asn1Element subjectPublicKey; - curl_asn1Element issuerUniqueID; - curl_asn1Element subjectUniqueID; - curl_asn1Element extensions; -} curl_X509certificate; - - -/* - * Prototypes. - */ - -const char *Curl_getASN1Element(curl_asn1Element *elem, - const char *beg, const char *end); -const char *Curl_ASN1tostr(curl_asn1Element *elem, int type); -const char *Curl_DNtostr(curl_asn1Element *dn); -int Curl_parseX509(curl_X509certificate *cert, - const char *beg, const char *end); -CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum, - const char *beg, const char *end); -CURLcode Curl_verifyhost(struct connectdata *conn, - const char *beg, const char *end); -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ -#endif /* HEADER_CURL_X509ASN1_H */ diff --git a/dep/cpr/opt/curl/libcurl.pc.in b/dep/cpr/opt/curl/libcurl.pc.in deleted file mode 100644 index feea1cd91a5..00000000000 --- a/dep/cpr/opt/curl/libcurl.pc.in +++ /dev/null @@ -1,39 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### - -# This should most probably benefit from getting a "Requires:" field added -# dynamically by configure. -# -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -supported_protocols="@SUPPORT_PROTOCOLS@" -supported_features="@SUPPORT_FEATURES@" - -Name: libcurl -URL: https://curl.haxx.se/ -Description: Library to transfer files with ftp, http, etc. -Version: @CURLVERSION@ -Libs: -L${libdir} -lcurl -Libs.private: @LIBCURL_LIBS@ -Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@ diff --git a/dep/cpr/opt/curl/src/.gitignore b/dep/cpr/opt/curl/src/.gitignore deleted file mode 100644 index 0f6fcd47c96..00000000000 --- a/dep/cpr/opt/curl/src/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -*.a -*.nlm -*.res -config-win32.h -curl -curl_config.h -curl_config.h.in -stamp-h2 -tool_hugehelp.c -tool_version.h.dist diff --git a/dep/cpr/opt/curl/src/CMakeLists.txt b/dep/cpr/opt/curl/src/CMakeLists.txt deleted file mode 100644 index de188be663f..00000000000 --- a/dep/cpr/opt/curl/src/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -set(EXE_NAME curl) - -if(USE_MANUAL) - # Use the C locale to ensure that only ASCII characters appear in the - # embedded text. NROFF and MANOPT are set in the parent CMakeLists.txt - add_custom_command( - OUTPUT tool_hugehelp.c - COMMAND ${CMAKE_COMMAND} -E echo "#include \"tool_setup.h\"" > tool_hugehelp.c - COMMAND ${CMAKE_COMMAND} -E echo "#ifndef HAVE_LIBZ" >> tool_hugehelp.c - COMMAND env LC_ALL=C "${NROFF}" ${NROFF_MANOPT} - "${CURL_BINARY_DIR}/docs/curl.1" | - "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" - "${CURL_SOURCE_DIR}/docs/MANUAL" >> tool_hugehelp.c - COMMAND ${CMAKE_COMMAND} -E echo "#else" >> tool_hugehelp.c - COMMAND env LC_ALL=C "${NROFF}" ${NROFF_MANOPT} - "${CURL_BINARY_DIR}/docs/curl.1" | - "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" -c - "${CURL_SOURCE_DIR}/docs/MANUAL" >> tool_hugehelp.c - COMMAND ${CMAKE_COMMAND} -E echo "#endif /* HAVE_LIBZ */" >> tool_hugehelp.c - DEPENDS - "${CURL_SOURCE_DIR}/docs/MANUAL" - generate-curl.1 - "${CURL_BINARY_DIR}/docs/curl.1" - "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" - "${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.h" - VERBATIM) -else() - add_custom_command( - OUTPUT tool_hugehelp.c - COMMAND ${CMAKE_COMMAND} -E echo "/* built-in manual is disabled, blank function */" > tool_hugehelp.c - COMMAND ${CMAKE_COMMAND} -E echo "#include \"tool_hugehelp.h\"" >> tool_hugehelp.c - COMMAND ${CMAKE_COMMAND} -E echo "void hugehelp(void) {}" >> tool_hugehelp.c - DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.h" - VERBATIM) - -endif() - -transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) - -if(MSVC) - list(APPEND CURL_SOURCE curl.rc) -endif() - -# CURL_FILES comes from Makefile.inc -add_executable( - ${EXE_NAME} - ${CURL_FILES} - ) - -source_group("curlX source files" FILES ${CURLX_CFILES}) -source_group("curl source files" FILES ${CURL_CFILES}) -source_group("curl header files" FILES ${CURL_HFILES}) - -include_directories( - ${CURL_SOURCE_DIR}/lib # To be able to reach "curl_setup_once.h" - ${CURL_BINARY_DIR}/lib # To be able to reach "curl_config.h" - ${CURL_BINARY_DIR}/include # To be able to reach "curl/curl.h" - # This is needed as tool_hugehelp.c is generated in the binary dir - ${CURL_SOURCE_DIR}/src # To be able to reach "tool_hugehelp.h" - ) - -#Build curl executable -target_link_libraries( ${EXE_NAME} libcurl ${CURL_LIBS}) - -################################################################################ - -#SET_TARGET_PROPERTIES(${EXE_NAME} ARCHIVE_OUTPUT_DIRECTORY "blah blah blah") -#SET_TARGET_PROPERTIES(${EXE_NAME} RUNTIME_OUTPUT_DIRECTORY "blah blah blah") -#SET_TARGET_PROPERTIES(${EXE_NAME} LIBRARY_OUTPUT_DIRECTORY "blah blah blah") - -# Add the postfix to the executable since it is not added automatically as for modules and shared libraries -set_target_properties(${EXE_NAME} PROPERTIES - DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}") - -#INCLUDE(ModuleInstall OPTIONAL) - -install(TARGETS ${EXE_NAME} DESTINATION bin) diff --git a/dep/cpr/opt/curl/src/Makefile.Watcom b/dep/cpr/opt/curl/src/Makefile.Watcom deleted file mode 100644 index 25cd3bf8806..00000000000 --- a/dep/cpr/opt/curl/src/Makefile.Watcom +++ /dev/null @@ -1,234 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2005 - 2008, Gisle Vanem . -# Copyright (C) 2005 - 2015, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -# -# Watcom / OpenWatcom / Win32 makefile for curl. -# - -.ERASE - -!if $(__VERSION__) < 1280 -!message !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!message ! This Open Watcom version is too old and is no longer supported ! -!message ! Please download latest version from www.openwatcom.org ! -!message !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!error Unsupported version of Open Watcom -!endif - -!ifndef %watcom -!error WATCOM environment variable not set! -!endif - -# In order to process Makefile.inc wmake must be called with -u switch! -!ifndef %MAKEFLAGS -!error You MUST call wmake with the -u switch! -!endif - -!ifdef %libname -LIBNAME = $(%libname) -!else -LIBNAME = libcurl -!endif - -TARGETS = curl.exe - -CC = wcc386 -LD = wlink -AR = wlib -RC = wrc - -!ifdef __LOADDLL__ -! loaddll wcc386 wccd386 -! loaddll wpp386 wppd386 -! loaddll wlib wlibd -! loaddll wlink wlinkd -!endif - -!ifdef __UNIX__ -CP = cp -MD = mkdir -p -!else -CP = copy 2>NUL -MD = mkdir -!endif -!if $(__VERSION__) > 1290 -RD = rm -rf -!else ifdef __UNIX__ -RD = rm -rf -!else -RD = rmdir /q /s 2>NUL -!endif - -SYS_INCL = -I"$(%watcom)/h/nt" -I"$(%watcom)/h" - -CFLAGS = -3r -mf -hc -zff -zgf -zq -zm -s -fr=con -w2 -fpi -oilrtfm & - -wcd=201 -bt=nt -bc -d+ -dWIN32 -dHAVE_STRTOLL & - -I"../include" -I"../lib" $(SYS_INCL) - -!ifdef %debug -DEBUG = -dDEBUG=1 -dDEBUGBUILD -CFLAGS += -d3 $(DEBUG) -!else -CFLAGS += -d0 -!endif - -!ifdef %use_ipv6 -CFLAGS += -d_WIN32_WINNT=0x0501 -dENABLE_IPV6 -!endif - -!ifdef %use_ssl -CFLAGS += -wcd=138 -dUSE_OPENSSL -dUSE_OPENSSL -I"$(OPENSSL_ROOT)/inc32" -!endif - -!ifdef %curl_static -CFLAGS += -DCURL_STATICLIB -!else -CFLAGS += -br -!endif - -# -# Change to suite. -# -!ifdef %zlib_root -ZLIB_ROOT = $(%zlib_root) -!else -ZLIB_ROOT = ../../zlib-1.2.8 -!endif - -!ifdef %libssh2_root -LIBSSH2_ROOT = $(%libssh2_root) -!else -LIBSSH2_ROOT = ../../libssh2-1.5.0 -!endif - -!ifdef %librtmp_root -LIBRTMP_ROOT = $(%librtmp_root) -!else -LIBRTMP_ROOT = ../../rtmpdump-2.3 -!endif - -!ifdef %openssl_root -OPENSSL_ROOT = $(%openssl_root) -!else -OPENSSL_ROOT = ../../openssl-1.0.2a -!endif - -!ifdef %ares_root -ARES_ROOT = $(%ares_root) -!else -ARES_ROOT = ../ares -!endif - -OBJ_DIR = WC_Win32.obj -LINK_ARG = $(OBJ_DIR)/wlink.arg - -!include Makefile.inc - -OBJS1 = $(OBJ_DIR)/$(CURL_CFILES) -!ifndef %curl_static -OBJS1 += $(CURLX_CFILES:../lib/=) -!endif -OBJS2 = $(OBJS1: = $(OBJ_DIR)/) -OBJS = $(OBJS2:.c=.obj) - -RESOURCE = $(OBJ_DIR)/curl.res - -DIRS = $(OBJ_DIR) - -all: tool_hugehelp.c $(DIRS) $(TARGETS) .SYMBOLIC - @echo Welcome to curl - -clean: .SYMBOLIC - -rm -f $(OBJS) - -rm -f $(RESOURCE) $(LINK_ARG) - -vclean distclean: clean .SYMBOLIC - -$(RD) $(OBJ_DIR) - -rm -f curl.exe curl.sym tool_hugehelp.c - -tool_hugehelp.c: tool_hugehelp.c.cvs - $(CP) $[@ $^@ - -tool_hugehelp.c.cvs: .EXISTSONLY - $(CP) tool_hugehelp.c $^@ - -$(DIRS): - -$(MD) $^@ - -curl.exe: $(OBJS) $(RESOURCE) - %create $(LINK_ARG) - @%append $(LINK_ARG) system nt -!ifdef %debug - @%append $(LINK_ARG) debug all - @%append $(LINK_ARG) option symfile -!endif - @%append $(LINK_ARG) option quiet, caseexact, eliminate - @%append $(LINK_ARG) option map=$(OBJ_DIR)/$^&.map - @%append $(LINK_ARG) option res=$(RESOURCE) - @%append $(LINK_ARG) file { $(OBJS) } -!ifndef %curl_static - @%append $(LINK_ARG) library ../lib/$(LIBNAME)_imp.lib -!else - @%append $(LINK_ARG) library ../lib/$(LIBNAME).lib - @%append $(LINK_ARG) library wldap32.lib -! ifdef %use_zlib - @%append $(LINK_ARG) library '$(ZLIB_ROOT)/zlib.lib' -! endif -! ifdef %use_rtmp - @%append $(LINK_ARG) library '$(LIBRTMP_ROOT)/librtmp/librtmp.lib' - @%append $(LINK_ARG) library winmm.lib -! endif -! ifdef %use_ssh2 - @%append $(LINK_ARG) library '$(LIBSSH2_ROOT)/win32/libssh2.lib' -! endif -! ifdef %use_ssl - @%append $(LINK_ARG) library '$(OPENSSL_ROOT)/out32/libeay32.lib' - @%append $(LINK_ARG) library '$(OPENSSL_ROOT)/out32/ssleay32.lib' -! endif -! ifdef %use_ares - @%append $(LINK_ARG) library '$(ARES_ROOT)/cares.lib' -! endif -! ifdef %use_winidn -! if $(__VERSION__) > 1290 - @%append $(LINK_ARG) library normaliz.lib -! else - @%append $(LINK_ARG) import '_IdnToAscii@20' 'NORMALIZ.DLL'.'IdnToAscii' - @%append $(LINK_ARG) import '_IdnToUnicode@20' 'NORMALIZ.DLL'.'IdnToUnicode' -! endif -! endif -!endif -!ifeq USE_WATT32 1 - @%append $(LINK_ARG) library '$(%watt_root)/lib/wattcpw_imp.lib' -!else - @%append $(LINK_ARG) library ws2_32.lib -!endif - $(LD) name $^@ @$(LINK_ARG) - -$(RESOURCE): curl.rc - $(RC) $(DEBUG) -q -r -zm -bt=nt -I"../include" $(SYS_INCL) $[@ -fo=$^@ - -# suffix search path - vpath-like hack -.c: ../lib - -.c{$(OBJ_DIR)}.obj: - $(CC) $(CFLAGS) $[@ -fo=$^@ diff --git a/dep/cpr/opt/curl/src/Makefile.am b/dep/cpr/opt/curl/src/Makefile.am deleted file mode 100644 index bfcd877fc1f..00000000000 --- a/dep/cpr/opt/curl/src/Makefile.am +++ /dev/null @@ -1,142 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### -AUTOMAKE_OPTIONS = foreign nostdinc - -# remove targets if the command fails -.DELETE_ON_ERROR: - -# Specify our include paths here, and do it relative to $(top_srcdir) and -# $(top_builddir), to ensure that these paths which belong to the library -# being currently built and tested are searched before the library which -# might possibly already be installed in the system. -# -# $(top_srcdir)/include is for libcurl's external include files -# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file -# $(top_builddir)/src is for curl's generated src/curl_config.h file -# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files -# $(top_srcdir)/src is for curl's src/tool_setup.h and "curl-private" files - -AM_CPPFLAGS = -I$(top_srcdir)/include \ - -I$(top_builddir)/lib \ - -I$(top_builddir)/src \ - -I$(top_srcdir)/lib \ - -I$(top_srcdir)/src - -bin_PROGRAMS = curl - -SUBDIRS = ../docs - -if USE_CPPFLAG_CURL_STATICLIB -AM_CPPFLAGS += -DCURL_STATICLIB -endif - -include Makefile.inc - -# CURL_FILES comes from Makefile.inc -curl_SOURCES = $(CURL_FILES) - -# This might hold -Werror -CFLAGS += @CURL_CFLAG_EXTRAS@ - -# Prevent LIBS from being used for all link targets -LIBS = $(BLANK_AT_MAKETIME) - -if USE_EXPLICIT_LIB_DEPS -curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ -else -curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ -endif - -curl_LDFLAGS = @LIBMETALINK_LDFLAGS@ -curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBMETALINK_CPPFLAGS) - -@CODE_COVERAGE_RULES@ -curl_LDFLAGS += $(CODE_COVERAGE_LDFLAGS) -CFLAGS += $(CODE_COVERAGE_CFLAGS) - -# if unit tests are enabled, build a static library to link them with -if BUILD_UNITTESTS -noinst_LTLIBRARIES = libcurltool.la -libcurltool_la_CPPFLAGS = $(LIBMETALINK_CPPFLAGS) $(AM_CPPFLAGS) \ - -DCURL_STATICLIB -DUNITTESTS -libcurltool_la_CFLAGS = -libcurltool_la_LDFLAGS = -static $(LINKFLAGS) -libcurltool_la_SOURCES = $(curl_SOURCES) -endif - -CLEANFILES = tool_hugehelp.c -# Use the C locale to ensure that only ASCII characters appear in the -# embedded text. -NROFF=env LC_ALL=C @NROFF@ @MANOPT@ # figured out by the configure script - -EXTRA_DIST = mkhelp.pl makefile.dj Makefile.b32 \ - Makefile.m32 macos/curl.mcp.xml.sit.hqx macos/MACINSTALL.TXT \ - macos/src/curl_GUSIConfig.cpp macos/src/macos_main.cpp makefile.amiga \ - curl.rc Makefile.netware Makefile.inc Makefile.Watcom CMakeLists.txt - -# Use absolute directory to disable VPATH -MANPAGE=$(abs_top_builddir)/docs/curl.1 -README=$(top_srcdir)/docs/MANUAL -MKHELP=$(top_srcdir)/src/mkhelp.pl -HUGE=tool_hugehelp.c - -if USE_MANUAL -# Here are the stuff to create a built-in manual - -$(MANPAGE): - cd $(top_builddir)/docs && $(MAKE) - -if HAVE_LIBZ -# This generates the tool_hugehelp.c file in both uncompressed and -# compressed formats. -$(HUGE): $(MANPAGE) $(README) $(MKHELP) - echo '#include "tool_setup.h"' > $(HUGE) - echo '#ifndef HAVE_LIBZ' >> $(HUGE) - $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) $(README) >> $(HUGE) - echo '#else' >> $(HUGE) - $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) -c $(README) >> $(HUGE) - echo '#endif /* HAVE_LIBZ */' >> $(HUGE) -else # HAVE_LIBZ -# This generates the tool_hugehelp.c file uncompressed only -$(HUGE): $(MANPAGE) $(README) $(MKHELP) - echo '#include "tool_setup.h"' > $(HUGE) - $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) $(README) >> $(HUGE) -endif - -else # USE_MANUAL -# built-in manual has been disabled, make a blank file -$(HUGE): - echo "/* built-in manual is disabled, blank function */" > $(HUGE) - echo '#include "tool_hugehelp.h"' >> $(HUGE) - echo "void hugehelp(void) {}" >>$(HUGE) -endif - -# ignore tool_hugehelp.c since it is generated source code and it plays -# by slightly different rules! -checksrc: - @PERL@ $(top_srcdir)/lib/checksrc.pl -D$(srcdir) \ - -W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch] - -if CURLDEBUG -# for debug builds, we scan the sources on all regular make invokes -all-local: checksrc -endif diff --git a/dep/cpr/opt/curl/src/Makefile.b32 b/dep/cpr/opt/curl/src/Makefile.b32 deleted file mode 100644 index a60b3db74b4..00000000000 --- a/dep/cpr/opt/curl/src/Makefile.b32 +++ /dev/null @@ -1,154 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2000, Jaepil Kim, . -# Copyright (C) 2001 - 2015, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -############################################################ -# -# Makefile.b32 - Borland's C++ Compiler 5.X -# -# 'BCCDIR' has to be set up to point to the base directory -# of the compiler, i.e. SET BCCDIR = c:\Borland\BCC55 -# -############################################################ - -!if "$(__MAKE__)" == "" -!error __MAKE__ not defined. Use Borlands's MAKE to process this makefile. -!endif - -# Borland's $(MAKEDIR) expands to the path where make.exe is located, -# use this feature to define BCCDIR when user has not defined BCCDIR. -!ifndef BCCDIR -BCCDIR = $(MAKEDIR)\.. -!endif - -# Edit the path below to point to the base of your Zlib sources. -!ifndef ZLIB_PATH -ZLIB_PATH = ..\..\zlib-1.2.8 -!endif - -# Edit the path below to point to the base of your OpenSSL package. -!ifndef OPENSSL_PATH -OPENSSL_PATH = ..\..\openssl-1.0.2a -!endif - -# Set program's name -PROGNAME = curl.exe - -# Setup environment -PP_CMD = cpp32 -q -P- -CC_CMD = bcc32 -q -c -LD = bcc32 -RM = del 2>NUL -MKDIR = md -RMDIR = rd /q 2>NUL -COPY = $(COMSPEC) /c copy /y - -CC_FLAGS = -5 -O2 -tWM -w -w-aus -w-ccc -w-dup -w-prc -w-pro -w-rch -w-sig -w-spa -w-inl -w-pia -w-pin -Dinline=__inline -LDFLAGS = -q -lq -lap - -SRCDIRS = .;..\lib -OBJDIR = .\BCC_objs -INCDIRS = -I.;..\include;..\lib -LINKLIB = $(BCCDIR)\lib\cw32mt.lib $(BCCDIR)\lib\ws2_32.lib -DEFINES = -DNDEBUG -DWIN32 - -!ifdef DYNAMIC -LIBCURL_LIB = ..\lib\libcurl_imp.lib -!else -LIBCURL_LIB = ..\lib\libcurl.lib -DEFINES = $(DEFINES) -DCURL_STATICLIB -!endif - -# ZLIB support is enabled setting WITH_ZLIB=1 -!ifdef WITH_ZLIB -DEFINES = $(DEFINES) -DHAVE_LIBZ -DHAVE_ZLIB_H -INCDIRS = $(INCDIRS);$(ZLIB_PATH) -LINKLIB = $(LINKLIB) $(ZLIB_PATH)\zlib.lib -!endif - -# SSL support is enabled setting WITH_SSL=1 -!ifdef WITH_SSL -DEFINES = $(DEFINES) -DUSE_OPENSSL -INCDIRS = $(INCDIRS);$(OPENSSL_PATH)\inc32;$(OPENSSL_PATH)\inc32\openssl -LINKLIB = $(LINKLIB) $(OPENSSL_PATH)\out32\ssleay32.lib $(OPENSSL_PATH)\out32\libeay32.lib -!endif - -.autodepend - -.path.c = $(SRCDIRS) -.path.obj = $(OBJDIR) -.path.int = $(OBJDIR) - -# Makefile.inc provides the CSOURCES and HHEADERS defines -!include Makefile.inc - -CSOURCES = $(CURL_CFILES) $(CURLX_CFILES:../lib/=) -OBJECTS = $(CSOURCES:.c=.obj) -PREPROCESSED = $(CSOURCES:.c=.int) - -# Borland's command line compiler (BCC32) version 5.5.1 integrated -# preprocessor has a bug which results in silently generating wrong -# definitions for libcurl macros such as CURL_OFF_T_C, on the other -# hand Borland's command line preprocessor (CPP32) version 5.5.1 does -# not have the bug and achieves proper results. In order to avoid the -# silent bug we first preprocess source files and later compile the -# preprocessed result. - -.c.obj: - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(<) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -all: $(OBJDIR) tool_hugehelp $(PROGNAME) - -clean: - cd $(OBJDIR) - @-$(RM) $(OBJECTS) - @-$(RM) $(PREPROCESSED) - cd .. - @-$(RMDIR) $(OBJDIR) - @-$(RM) $(PROGNAME) - @-$(RM) curl.tds - -$(OBJDIR): - @-$(RMDIR) $(OBJDIR) - @-$(MKDIR) $(OBJDIR) - -!ifdef WITH_ZLIB -tool_hugehelp: ..\docs\MANUAL ..\docs\curl.1 mkhelp.pl - groff -Tascii -man -P -c ../docs/curl.1 > tool_hugehelp.tmp - perl -w mkhelp.pl -c ../docs/MANUAL < tool_hugehelp.tmp > tool_hugehelp.c - @-$(RM) tool_hugehelp.tmp -!else -tool_hugehelp: - if exist ..\GIT-INFO $(COPY) tool_hugehelp.c.cvs tool_hugehelp.c -!endif - -$(PROGNAME): $(OBJECTS) $(LIBCURL_LIB) $(LINKLIB) - @-$(RM) $(PROGNAME) - $(LD) $(LDFLAGS) -e$@ @&&! -$(**: = ^ -) -! - - -# End of Makefile.b32 diff --git a/dep/cpr/opt/curl/src/Makefile.inc b/dep/cpr/opt/curl/src/Makefile.inc deleted file mode 100644 index 45b4967f647..00000000000 --- a/dep/cpr/opt/curl/src/Makefile.inc +++ /dev/null @@ -1,109 +0,0 @@ -# ./src/Makefile.inc -# Using the backslash as line continuation character might be problematic -# with some make flavours, as Watcom's wmake showed us already. If we -# ever want to change this in a portable manner then we should consider -# this idea (posted to the libcurl list by Adam Kellas): -# CSRC1 = file1.c file2.c file3.c -# CSRC2 = file4.c file5.c file6.c -# CSOURCES = $(CSRC1) $(CSRC2) - -# libcurl has sources that provide functions named curlx_* that aren't part of -# the official API, but we re-use the code here to avoid duplication. -CURLX_CFILES = \ - ../lib/strtoofft.c \ - ../lib/nonblock.c \ - ../lib/warnless.c - -CURLX_HFILES = \ - ../lib/curl_setup.h \ - ../lib/strtoofft.h \ - ../lib/nonblock.h \ - ../lib/warnless.h - -CURL_CFILES = \ - slist_wc.c \ - tool_binmode.c \ - tool_bname.c \ - tool_cb_dbg.c \ - tool_cb_hdr.c \ - tool_cb_prg.c \ - tool_cb_rea.c \ - tool_cb_see.c \ - tool_cb_wrt.c \ - tool_cfgable.c \ - tool_convert.c \ - tool_dirhie.c \ - tool_doswin.c \ - tool_easysrc.c \ - tool_formparse.c \ - tool_getparam.c \ - tool_getpass.c \ - tool_help.c \ - tool_helpers.c \ - tool_homedir.c \ - tool_hugehelp.c \ - tool_libinfo.c \ - tool_main.c \ - tool_metalink.c \ - tool_msgs.c \ - tool_operate.c \ - tool_operhlp.c \ - tool_panykey.c \ - tool_paramhlp.c \ - tool_parsecfg.c \ - tool_strdup.c \ - tool_setopt.c \ - tool_sleep.c \ - tool_urlglob.c \ - tool_util.c \ - tool_vms.c \ - tool_writeout.c \ - tool_xattr.c - -CURL_HFILES = \ - slist_wc.h \ - tool_binmode.h \ - tool_bname.h \ - tool_cb_dbg.h \ - tool_cb_hdr.h \ - tool_cb_prg.h \ - tool_cb_rea.h \ - tool_cb_see.h \ - tool_cb_wrt.h \ - tool_cfgable.h \ - tool_convert.h \ - tool_dirhie.h \ - tool_doswin.h \ - tool_easysrc.h \ - tool_formparse.h \ - tool_getparam.h \ - tool_getpass.h \ - tool_help.h \ - tool_helpers.h \ - tool_homedir.h \ - tool_hugehelp.h \ - tool_libinfo.h \ - tool_main.h \ - tool_metalink.h \ - tool_msgs.h \ - tool_operate.h \ - tool_operhlp.h \ - tool_panykey.h \ - tool_paramhlp.h \ - tool_parsecfg.h \ - tool_sdecls.h \ - tool_setopt.h \ - tool_setup.h \ - tool_sleep.h \ - tool_strdup.h \ - tool_urlglob.h \ - tool_util.h \ - tool_version.h \ - tool_vms.h \ - tool_writeout.h \ - tool_xattr.h - -CURL_RCFILES = curl.rc - -# curl_SOURCES is special and gets assigned in src/Makefile.am -CURL_FILES = $(CURL_CFILES) $(CURLX_CFILES) $(CURL_HFILES) diff --git a/dep/cpr/opt/curl/src/Makefile.m32 b/dep/cpr/opt/curl/src/Makefile.m32 deleted file mode 100644 index e55427a5e0c..00000000000 --- a/dep/cpr/opt/curl/src/Makefile.m32 +++ /dev/null @@ -1,377 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1999 - 2017, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -########################################################################### -# -## Makefile for building curl.exe with MingW (GCC-3.2 or later) -## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4) -## -## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...] -## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn -## -## Hint: you can also set environment vars to control the build, f.e.: -## set ZLIB_PATH=c:/zlib-1.2.8 -## set ZLIB=1 -# -########################################################################### - -# Edit the path below to point to the base of your Zlib sources. -ifndef ZLIB_PATH -ZLIB_PATH = ../../zlib-1.2.8 -endif -# Edit the path below to point to the base of your OpenSSL package. -ifndef OPENSSL_PATH -OPENSSL_PATH = ../../openssl-1.0.2a -endif -# Edit the path below to point to the base of your LibSSH2 package. -ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.5.0 -endif -# Edit the path below to point to the base of your librtmp package. -ifndef LIBRTMP_PATH -LIBRTMP_PATH = ../../librtmp-2.4 -endif -# Edit the path below to point to the base of your libmetalink package. -ifndef LIBMETALINK_PATH -LIBMETALINK_PATH = ../../libmetalink-0.1.3 -endif -# Edit the path below to point to the base of your libexpat package. -ifndef LIBEXPAT_PATH -LIBEXPAT_PATH = ../../expat-2.1.0 -endif -# Edit the path below to point to the base of your libxml2 package. -ifndef LIBXML2_PATH -LIBXML2_PATH = ../../libxml2-2.9.2 -endif -# Edit the path below to point to the base of your libidn2 package. -ifndef LIBIDN2_PATH -LIBIDN2_PATH = ../../libidn2-2.0.3 -endif -# Edit the path below to point to the base of your MS IDN package. -# Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1 -# https://www.microsoft.com/en-us/download/details.aspx?id=734 -ifndef WINIDN_PATH -WINIDN_PATH = ../../Microsoft IDN Mitigation APIs -endif -# Edit the path below to point to the base of your Novell LDAP NDK. -ifndef LDAP_SDK -LDAP_SDK = c:/novell/ndk/cldapsdk/win32 -endif -# Edit the path below to point to the base of your nghttp2 package. -ifndef NGHTTP2_PATH -NGHTTP2_PATH = ../../nghttp2-1.0.0 -endif - -PROOT = .. - -# Edit the path below to point to the base of your c-ares package. -ifndef LIBCARES_PATH -LIBCARES_PATH = $(PROOT)/ares -endif - -CC = $(CROSSPREFIX)gcc -CFLAGS = $(CURL_CFLAG_EXTRAS) -g -O2 -Wall -W -CFLAGS += -fno-strict-aliasing -# comment LDFLAGS below to keep debug info -LDFLAGS = $(CURL_LDFLAG_EXTRAS) $(CURL_LDFLAG_EXTRAS_EXE) -s -AR = $(CROSSPREFIX)ar -RC = $(CROSSPREFIX)windres -RCFLAGS = --include-dir=$(PROOT)/include -O COFF -STRIP = $(CROSSPREFIX)strip -g - -# We may need these someday -# PERL = perl -# NROFF = nroff - -# Set environment var ARCH to your architecture to override autodetection. -ifndef ARCH -ifeq ($(findstring x86_64,$(shell $(CC) -dumpmachine)),x86_64) -ARCH = w64 -else -ARCH = w32 -endif -endif - -ifeq ($(ARCH),w64) -CFLAGS += -m64 -D_AMD64_ -LDFLAGS += -m64 -RCFLAGS += -F pe-x86-64 -else -CFLAGS += -m32 -LDFLAGS += -m32 -RCFLAGS += -F pe-i386 -endif - -# Platform-dependent helper tool macros -ifeq ($(findstring /sh,$(SHELL)),/sh) -DEL = rm -f $1 -RMDIR = rm -fr $1 -MKDIR = mkdir -p $1 -COPY = -cp -afv $1 $2 -#COPYR = -cp -afr $1/* $2 -COPYR = -rsync -aC $1/* $2 -TOUCH = touch $1 -CAT = cat -ECHONL = echo "" -DL = ' -else -ifeq "$(OS)" "Windows_NT" -DEL = -del 2>NUL /q /f $(subst /,\,$1) -RMDIR = -rd 2>NUL /q /s $(subst /,\,$1) -else -DEL = -del 2>NUL $(subst /,\,$1) -RMDIR = -deltree 2>NUL /y $(subst /,\,$1) -endif -MKDIR = -md 2>NUL $(subst /,\,$1) -COPY = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2) -COPYR = -xcopy 2>NUL /q /y /e $(subst /,\,$1) $(subst /,\,$2) -TOUCH = copy 2>&1>NUL /b $(subst /,\,$1) +,, -CAT = type -ECHONL = $(ComSpec) /c echo. -endif - -######################################################## -## Nothing more to do below this line! - -ifeq ($(findstring -dyn,$(CFG)),-dyn) -DYN = 1 -endif -ifeq ($(findstring -ares,$(CFG)),-ares) -ARES = 1 -endif -ifeq ($(findstring -sync,$(CFG)),-sync) -SYNC = 1 -endif -ifeq ($(findstring -rtmp,$(CFG)),-rtmp) -RTMP = 1 -SSL = 1 -ZLIB = 1 -endif -ifeq ($(findstring -ssh2,$(CFG)),-ssh2) -SSH2 = 1 -SSL = 1 -ZLIB = 1 -endif -ifeq ($(findstring -ssl,$(CFG)),-ssl) -SSL = 1 -endif -ifeq ($(findstring -zlib,$(CFG)),-zlib) -ZLIB = 1 -endif -ifeq ($(findstring -idn2,$(CFG)),-idn2) -IDN2 = 1 -endif -ifeq ($(findstring -winidn,$(CFG)),-winidn) -WINIDN = 1 -endif -ifeq ($(findstring -sspi,$(CFG)),-sspi) -SSPI = 1 -endif -ifeq ($(findstring -ldaps,$(CFG)),-ldaps) -LDAPS = 1 -endif -ifeq ($(findstring -ipv6,$(CFG)),-ipv6) -IPV6 = 1 -endif -ifeq ($(findstring -metalink,$(CFG)),-metalink) -METALINK = 1 -endif -ifeq ($(findstring -winssl,$(CFG)),-winssl) -WINSSL = 1 -SSPI = 1 -endif -ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) -NGHTTP2 = 1 -endif - -INCLUDES = -I. -I../include -I../lib -ifdef SSL - ifdef WINSSL - CFLAGS += -DCURL_WITH_MULTI_SSL - endif -endif - -ifdef DYN - curl_DEPENDENCIES = $(PROOT)/lib/libcurldll.a $(PROOT)/lib/libcurl.dll - curl_LDADD = -L$(PROOT)/lib -lcurldll -else - curl_DEPENDENCIES = $(PROOT)/lib/libcurl.a - curl_LDADD = -L$(PROOT)/lib -lcurl - CFLAGS += -DCURL_STATICLIB - LDFLAGS += -static -endif -ifdef SYNC - CFLAGS += -DUSE_SYNC_DNS -else - ifdef ARES - ifndef DYN - curl_DEPENDENCIES += $(LIBCARES_PATH)/libcares.a - endif - CFLAGS += -DUSE_ARES -DCARES_STATICLIB - curl_LDADD += -L"$(LIBCARES_PATH)" -lcares - endif -endif -ifdef RTMP - CFLAGS += -DUSE_LIBRTMP - curl_LDADD += -L"$(LIBRTMP_PATH)/librtmp" -lrtmp -lwinmm -endif -ifdef NGHTTP2 - CFLAGS += -DUSE_NGHTTP2 - curl_LDADD += -L"$(NGHTTP2_PATH)/lib" -lnghttp2 -endif -ifdef SSH2 - CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H - curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2 - ifdef WINSSL - ifndef DYN - curl_LDADD += -lbcrypt -lcrypt32 - endif - endif -endif -ifdef SSL - ifndef OPENSSL_INCLUDE - ifeq "$(wildcard $(OPENSSL_PATH)/outinc)" "$(OPENSSL_PATH)/outinc" - OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc - endif - ifeq "$(wildcard $(OPENSSL_PATH)/include)" "$(OPENSSL_PATH)/include" - OPENSSL_INCLUDE = $(OPENSSL_PATH)/include - endif - endif - ifneq "$(wildcard $(OPENSSL_INCLUDE)/openssl/opensslv.h)" "$(OPENSSL_INCLUDE)/openssl/opensslv.h" - $(error Invalid path to OpenSSL package: $(OPENSSL_PATH)) - endif - ifndef OPENSSL_LIBPATH - OPENSSL_LIBS = -lssl -lcrypto - ifeq "$(wildcard $(OPENSSL_PATH)/out)" "$(OPENSSL_PATH)/out" - OPENSSL_LIBPATH = $(OPENSSL_PATH)/out - ifdef DYN - OPENSSL_LIBS = -lssl32 -leay32 - endif - endif - ifeq "$(wildcard $(OPENSSL_PATH)/lib)" "$(OPENSSL_PATH)/lib" - OPENSSL_LIBPATH = $(OPENSSL_PATH)/lib - endif - endif - ifndef DYN - OPENSSL_LIBS += -lgdi32 -lcrypt32 - endif - INCLUDES += -I"$(OPENSSL_INCLUDE)" - CFLAGS += -DUSE_OPENSSL - curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) -endif -ifdef WINSSL - CFLAGS += -DUSE_SCHANNEL - curl_LDADD += -lcrypt32 -endif -ifdef ZLIB - INCLUDES += -I"$(ZLIB_PATH)" - CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H - curl_LDADD += -L"$(ZLIB_PATH)" -lz -endif -ifdef IDN2 - CFLAGS += -DUSE_LIBIDN2 - curl_LDADD += -L"$(LIBIDN2_PATH)/lib" -lidn2 -else -ifdef WINIDN - CFLAGS += -DUSE_WIN32_IDN - curl_LDADD += -L"$(WINIDN_PATH)" -lnormaliz -endif -endif -ifdef METALINK - INCLUDES += -I"$(LIBMETALINK_PATH)/include" - CFLAGS += -DUSE_METALINK - curl_LDADD += -L"$(LIBMETALINK_PATH)/lib" -lmetalink - ifndef DYN - ifeq ($(findstring libexpat_metalink_parser.o,$(shell $(AR) t "$(LIBMETALINK_PATH)/lib/libmetalink.a")),libexpat_metalink_parser.o) - curl_LDADD += -L"$(LIBEXPAT_PATH)/lib" -lexpat - else - curl_LDADD += -L"$(LIBXML2_PATH)/lib" -lxml2 - endif - endif -endif -ifdef SSPI - CFLAGS += -DUSE_WINDOWS_SSPI -endif -ifdef IPV6 - CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501 -endif -ifdef LDAPS - CFLAGS += -DHAVE_LDAP_SSL -endif -ifdef USE_LDAP_NOVELL - CFLAGS += -DCURL_HAS_NOVELL_LDAPSDK - curl_LDADD += -L"$(LDAP_SDK)/lib/mscvc" -lldapsdk -lldapssl -lldapx -endif -ifdef USE_LDAP_OPENLDAP - CFLAGS += -DCURL_HAS_OPENLDAP_LDAPSDK - curl_LDADD += -L"$(LDAP_SDK)/lib" -lldap -llber -endif -ifndef USE_LDAP_NOVELL -ifndef USE_LDAP_OPENLDAP -curl_LDADD += -lwldap32 -endif -endif -curl_LDADD += -lws2_32 - -# Makefile.inc provides the CSOURCES and HHEADERS defines -include Makefile.inc - -curl_PROGRAMS = curl.exe -curl_OBJECTS := $(patsubst %.c,%.o,$(strip $(CURL_CFILES))) -curlx_OBJECTS := $(patsubst %.c,%.o,$(notdir $(strip $(CURLX_CFILES)))) -ifdef DYN -curl_OBJECTS += $(curlx_OBJECTS) -vpath %.c $(PROOT)/lib -endif - -RESOURCE = curl.res - - -all: $(curl_PROGRAMS) - -curl.exe: $(RESOURCE) $(curl_OBJECTS) $(curl_DEPENDENCIES) - $(call DEL, $@) - $(CC) $(LDFLAGS) -o $@ $< $(curl_OBJECTS) $(curl_LDADD) - -# We don't have nroff normally under win32 -# tool_hugehelp.c: $(PROOT)/docs/MANUAL $(PROOT)/docs/curl.1 mkhelp.pl -# @$(call DEL, tool_hugehelp.c) -# $(NROFF) -man $(PROOT)/docs/curl.1 | $(PERL) mkhelp.pl $(PROOT)/docs/MANUAL > tool_hugehelp.c - -tool_hugehelp.c: - @echo Creating $@ - @$(call COPY, $@.cvs, $@) - -%.o: %.c - $(CC) $(INCLUDES) $(CFLAGS) -c $< - -%.res: %.rc - $(RC) $(RCFLAGS) -i $< -o $@ - -clean: -ifeq "$(wildcard tool_hugehelp.c.cvs)" "tool_hugehelp.c.cvs" - @$(call DEL, tool_hugehelp.c) -endif - @$(call DEL, $(curl_OBJECTS) $(curlx_OBJECTS) $(RESOURCE)) - -distclean vclean: clean - @$(call DEL, $(curl_PROGRAMS)) diff --git a/dep/cpr/opt/curl/src/Makefile.netware b/dep/cpr/opt/curl/src/Makefile.netware deleted file mode 100644 index a927da592ae..00000000000 --- a/dep/cpr/opt/curl/src/Makefile.netware +++ /dev/null @@ -1,524 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2004 - 2014, Guenter Knauf, . -# Copyright (C) 2001 - 2015, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -################################################################# -# -## Makefile for building curl.nlm (NetWare version - gnu make) -## -## Use: make -f Makefile.netware -# -################################################################# - -# Edit the path below to point to the base of your Novell NDK. -ifndef NDKBASE -NDKBASE = c:/novell -endif - -# Edit the path below to point to the base of your Zlib sources. -ifndef ZLIB_PATH -ZLIB_PATH = ../../zlib-1.2.8 -endif - -# Edit the path below to point to the base of your OpenSSL package. -ifndef OPENSSL_PATH -OPENSSL_PATH = ../../openssl-1.0.2a -endif - -# Edit the path below to point to the base of your LibSSH2 package. -ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.5.0 -endif - -# Edit the path below to point to the base of your axTLS package. -ifndef AXTLS_PATH -AXTLS_PATH = ../../axTLS-1.2.7 -endif - -# Edit the path below to point to the base of your libidn package. -ifndef LIBIDN_PATH -LIBIDN_PATH = ../../libidn-1.18 -endif - -# Edit the path below to point to the base of your librtmp package. -ifndef LIBRTMP_PATH -LIBRTMP_PATH = ../../librtmp-2.3 -endif - -# Edit the path below to point to the base of your nghttp2 package. -ifndef NGHTTP2_PATH -NGHTTP2_PATH = ../../nghttp2-0.6.7 -endif - -# Edit the path below to point to the base of your fbopenssl package. -ifndef FBOPENSSL_PATH -FBOPENSSL_PATH = ../../fbopenssl-0.4 -endif - -# Edit the path below to point to the base of your libmetalink package. -ifndef LIBMETALINK_PATH -LIBMETALINK_PATH = ../../libmetalink-0.1.2 -endif - -# Edit the path below to point to the base of your libexpat package. -ifndef LIBEXPAT_PATH -LIBEXPAT_PATH = ../../expat-2.1.0 -endif - -# Edit the path below to point to the base of your libXML2 package. -ifndef LIBXML2_PATH -LIBXML2_PATH = ../../libxml2-2.8.0 -endif - -# Edit the path below to point to the base of your c-ares package. -ifndef LIBCARES_PATH -LIBCARES_PATH = ../ares -endif - -ifndef INSTDIR -INSTDIR = ..$(DS)curl-$(LIBCURL_VERSION_STR)-bin-nw -endif - -# Edit the vars below to change NLM target settings. -TARGET = curl -VERSION = $(LIBCURL_VERSION) -COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR) -DESCR = curl $(LIBCURL_VERSION_STR) ($(LIBARCH)) - https://curl.haxx.se -MTSAFE = YES -STACK = 64000 -SCREEN = $(TARGET) commandline utility -# Comment the line below if you dont want to load protected automatically. -# LDRING = 3 - -# Uncomment the next line to enable linking with POSIX semantics. -# POSIXFL = 1 - -# Edit the var below to point to your lib architecture. -ifndef LIBARCH -LIBARCH = LIBC -endif - -# must be equal to NDEBUG or DEBUG, CURLDEBUG -ifndef DB -DB = NDEBUG -endif -# Optimization: -O or debugging: -g -ifeq ($(DB),NDEBUG) - OPT = -O2 - OBJDIR = release -else - OPT = -g - OBJDIR = debug -endif - -# The following lines defines your compiler. -ifdef CWFolder - METROWERKS = $(CWFolder) -endif -ifdef METROWERKS - # MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support - MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support/Metrowerks Support - CC = mwccnlm -else - CC = gcc -endif -PERL = perl -# Here you can find a native Win32 binary of the original awk: -# http://www.gknw.net/development/prgtools/awk-20100523.zip -AWK = awk -CP = cp -afv -MKDIR = mkdir -# RM = rm -f -# If you want to mark the target as MTSAFE you will need a tool for -# generating the xdc data for the linker; here's a minimal tool: -# http://www.gknw.net/development/prgtools/mkxdc.zip -MPKXDC = mkxdc - -# LIBARCH_U = $(shell $(AWK) 'BEGIN {print toupper(ARGV[1])}' $(LIBARCH)) -LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH)) - -# Include the version info retrieved from curlver.h --include $(OBJDIR)/version.inc - -# Global flags for all compilers -CFLAGS += $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc - -ifeq ($(CC),mwccnlm) -LD = mwldnlm -LDFLAGS = -nostdlib $(OBJS) $(PRELUDE) $(LDLIBS) -o $@ -commandfile -LIBEXT = lib -CFLAGS += -gccinc -inline off -opt nointrinsics -proc 586 -CFLAGS += -relax_pointers -#CFLAGS += -w on -ifeq ($(LIBARCH),LIBC) -ifeq ($(POSIXFL),1) - PRELUDE = $(NDK_LIBC)/imports/posixpre.o -else - PRELUDE = $(NDK_LIBC)/imports/libcpre.o -endif - CFLAGS += -align 4 -else - # PRELUDE = $(NDK_CLIB)/imports/clibpre.o - # to avoid the __init_* / __deinit_* whoes dont use prelude from NDK - PRELUDE = "$(MWCW_PATH)/libraries/runtime/prelude.obj" - # CFLAGS += -include "$(MWCW_PATH)/headers/nlm_clib_prefix.h" - CFLAGS += -align 1 -endif -else -LD = nlmconv -LDFLAGS = -T -LIBEXT = a -CFLAGS += -m32 -CFLAGS += -fno-builtin -fno-strict-aliasing -ifeq ($(findstring gcc,$(CC)),gcc) -CFLAGS += -fpcc-struct-return -endif -CFLAGS += -Wall # -pedantic -ifeq ($(LIBARCH),LIBC) -ifeq ($(POSIXFL),1) - PRELUDE = $(NDK_LIBC)/imports/posixpre.gcc.o -else - PRELUDE = $(NDK_LIBC)/imports/libcpre.gcc.o -endif -else - # PRELUDE = $(NDK_CLIB)/imports/clibpre.gcc.o - # to avoid the __init_* / __deinit_* whoes dont use prelude from NDK - # http://www.gknw.net/development/mk_nlm/gcc_pre.zip - PRELUDE = $(NDK_ROOT)/pre/prelude.o - CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h -endif -endif - -NDK_ROOT = $(NDKBASE)/ndk -ifndef NDK_CLIB -NDK_CLIB = $(NDK_ROOT)/nwsdk -endif -ifndef NDK_LIBC -NDK_LIBC = $(NDK_ROOT)/libc -endif -ifndef NDK_LDAP -NDK_LDAP = $(NDK_ROOT)/cldapsdk/netware -endif -CURL_INC = ../include -CURL_LIB = ../lib - -INCLUDES = -I$(CURL_INC) -I$(CURL_LIB) - -ifeq ($(findstring -static,$(CFG)),-static) -LINK_STATIC = 1 -endif -ifeq ($(findstring -ares,$(CFG)),-ares) -WITH_ARES = 1 -endif -ifeq ($(findstring -rtmp,$(CFG)),-rtmp) -WITH_RTMP = 1 -WITH_SSL = 1 -WITH_ZLIB = 1 -endif -ifeq ($(findstring -ssh2,$(CFG)),-ssh2) -WITH_SSH2 = 1 -WITH_SSL = 1 -WITH_ZLIB = 1 -endif -ifeq ($(findstring -axtls,$(CFG)),-axtls) -WITH_AXTLS = 1 -WITH_SSL = -else -ifeq ($(findstring -ssl,$(CFG)),-ssl) -WITH_SSL = 1 -endif -endif -ifeq ($(findstring -zlib,$(CFG)),-zlib) -WITH_ZLIB = 1 -endif -ifeq ($(findstring -idn,$(CFG)),-idn) -WITH_IDN = 1 -endif -ifeq ($(findstring -metalink,$(CFG)),-metalink) -WITH_METALINK = 1 -WITH_SSL = 1 -endif -ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) -WITH_NGHTTP2 = 1 -endif -ifeq ($(findstring -ipv6,$(CFG)),-ipv6) -ENABLE_IPV6 = 1 -endif - -ifdef LINK_STATIC - LDLIBS = $(CURL_LIB)/libcurl.$(LIBEXT) -ifdef WITH_ARES - LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT) -endif -else - MODULES = libcurl.nlm - IMPORTS = @$(CURL_LIB)/libcurl.imp -endif -ifdef WITH_SSH2 - # INCLUDES += -I$(LIBSSH2_PATH)/include -ifdef LINK_STATIC - LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT) -else - MODULES += libssh2.nlm - IMPORTS += @$(LIBSSH2_PATH)/nw/libssh2.imp -endif -endif -ifdef WITH_RTMP - # INCLUDES += -I$(LIBRTMP_PATH) -ifdef LINK_STATIC - LDLIBS += $(LIBRTMP_PATH)/librtmp/librtmp.$(LIBEXT) -endif -endif -ifdef WITH_SSL - # INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) - LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT) - LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT) - IMPORTS += GetProcessSwitchCount RunningProcess -else -ifdef WITH_AXTLS - # INCLUDES += -I$(AXTLS_PATH)/inc -ifdef LINK_STATIC - LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT) -else - MODULES += libaxtls.nlm - IMPORTS += $(AXTLS_PATH)/lib/libaxtls.imp -endif -endif -endif -ifdef WITH_ZLIB - INCLUDES += -I$(ZLIB_PATH) -ifdef LINK_STATIC - LDLIBS += $(ZLIB_PATH)/nw/$(LIBARCH)/libz.$(LIBEXT) -else - MODULES += libz.nlm - IMPORTS += @$(ZLIB_PATH)/nw/$(LIBARCH)/libz.imp -endif -endif -ifdef WITH_IDN - # INCLUDES += -I$(LIBIDN_PATH)/include - LDLIBS += $(LIBIDN_PATH)/lib/libidn.$(LIBEXT) -endif -ifdef WITH_NGHTTP2 - INCLUDES += -I$(NGHTTP2_PATH)/include - LDLIBS += $(NGHTTP2_PATH)/lib/libnghttp2.$(LIBEXT) -endif -ifdef WITH_METALINK - CFLAGS += -DUSE_METALINK - INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) - INCLUDES += -I$(LIBMETALINK_PATH)/include - LDLIBS += $(LIBMETALINK_PATH)/lib/libmetalink.$(LIBEXT) -ifdef WITH_LIBEXPAT - ifeq ($(LIBARCH),LIBC) - IMPORTS += @$(LIBEXPAT_PATH)/imports/expatlbc.imp - MODULES += expatlbc - else - IMPORTS += @$(LIBEXPAT_PATH)/imports/expatlib.imp - MODULES += expatlib - endif -else -ifdef WITH_LIBXML2 - IMPORTS += @$(LIBXML2_PATH)/lib/libxml2.imp - MODULES += libxml2 -endif -endif -endif - -ifeq ($(LIBARCH),LIBC) - INCLUDES += -I$(NDK_LIBC)/include - # INCLUDES += -I$(NDK_LIBC)/include/nks - # INCLUDES += -I$(NDK_LIBC)/include/winsock - CFLAGS += -D_POSIX_SOURCE -else - INCLUDES += -I$(NDK_CLIB)/include/nlm - # INCLUDES += -I$(NDK_CLIB)/include -endif -ifndef DISABLE_LDAP - # INCLUDES += -I$(NDK_LDAP)/$(LIBARCH_L)/inc -endif -CFLAGS += $(INCLUDES) - -ifeq ($(MTSAFE),YES) - XDCOPT = -n -endif -ifeq ($(MTSAFE),NO) - XDCOPT = -u -endif -ifdef XDCOPT - XDCDATA = $(OBJDIR)/$(TARGET).xdc -endif - -ifeq ($(findstring /sh,$(SHELL)),/sh) -DL = ' -DS = / -PCT = % -#-include $(NDKBASE)/nlmconv/ncpfs.inc -else -DS = \\ -PCT = %% -endif - -# Makefile.inc provides the CSOURCES and HHEADERS defines -include Makefile.inc - -OBJX := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(strip $(CURLX_CFILES)))) -OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(strip $(CURL_CFILES))) -ifndef LINK_STATIC -OBJS += $(OBJX) -endif - -vpath %.c $(CURL_LIB) - -all: prebuild $(TARGET).nlm - -prebuild: $(OBJDIR) $(OBJDIR)/version.inc - -$(OBJDIR)/%.o: %.c -# @echo Compiling $< - $(CC) $(CFLAGS) -c $< -o $@ - -$(OBJDIR)/version.inc: $(CURL_INC)/curl/curlver.h $(OBJDIR) - @echo Creating $@ - @$(AWK) -f ../packages/NetWare/get_ver.awk $< > $@ - -install: $(INSTDIR) all - @-$(CP) ../docs/$(TARGET).pdf $(INSTDIR) - @-$(CP) ../docs/$(TARGET).html $(INSTDIR) - @$(CP) $(TARGET).nlm $(INSTDIR) - -clean: -ifeq "$(wildcard tool_hugehelp.c.cvs)" "tool_hugehelp.c.cvs" - -$(RM) tool_hugehelp.c -endif - -$(RM) -r $(OBJDIR) - -distclean vclean: clean - -$(RM) $(TARGET).nlm - -$(OBJDIR) $(INSTDIR): - @$(MKDIR) $@ - -$(TARGET).nlm: $(OBJS) $(OBJDIR)/$(TARGET).def $(XDCDATA) - @echo Linking $@ - @-$(RM) $@ - @$(LD) $(LDFLAGS) $(OBJDIR)/$(TARGET).def - -$(OBJDIR)/%.xdc: Makefile.netware - @echo Creating $@ - @$(MPKXDC) $(XDCOPT) $@ - -$(OBJDIR)/%.def: Makefile.netware - @echo $(DL)# DEF file for linking with $(LD)$(DL) > $@ - @echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@ - @echo $(DL)# All your changes will be lost!!$(DL) >> $@ - @echo $(DL)#$(DL) >> $@ - @echo $(DL)copyright "$(COPYR)"$(DL) >> $@ - @echo $(DL)description "$(DESCR)"$(DL) >> $@ - @echo $(DL)version $(VERSION)$(DL) >> $@ -ifdef NLMTYPE - @echo $(DL)type $(NLMTYPE)$(DL) >> $@ -endif -ifdef STACK - @echo $(DL)stack $(STACK)$(DL) >> $@ -endif -ifdef SCREEN - @echo $(DL)screenname "$(SCREEN)"$(DL) >> $@ -else - @echo $(DL)screenname "DEFAULT"$(DL) >> $@ -endif -ifneq ($(DB),NDEBUG) - @echo $(DL)debug$(DL) >> $@ -endif - @echo $(DL)threadname "$(TARGET)"$(DL) >> $@ -ifdef XDCDATA - @echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@ -endif -ifeq ($(LDRING),0) - @echo $(DL)flag_on 16$(DL) >> $@ -endif -ifeq ($(LDRING),3) - @echo $(DL)flag_on 512$(DL) >> $@ -endif -ifeq ($(LIBARCH),CLIB) - @echo $(DL)start _Prelude$(DL) >> $@ - @echo $(DL)exit _Stop$(DL) >> $@ - @echo $(DL)import @$(NDK_CLIB)/imports/clib.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_CLIB)/imports/threads.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_CLIB)/imports/nlmlib.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_CLIB)/imports/socklib.imp$(DL) >> $@ - @echo $(DL)module clib$(DL) >> $@ -ifndef DISABLE_LDAP - @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapsdk.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapssl.imp$(DL) >> $@ -# @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapx.imp$(DL) >> $@ - @echo $(DL)module ldapsdk ldapssl$(DL) >> $@ -endif -else -ifeq ($(POSIXFL),1) - @echo $(DL)flag_on 4194304$(DL) >> $@ -endif - @echo $(DL)flag_on 64$(DL) >> $@ - @echo $(DL)pseudopreemption$(DL) >> $@ -ifeq ($(findstring posixpre,$(PRELUDE)),posixpre) - @echo $(DL)start POSIX_Start$(DL) >> $@ - @echo $(DL)exit POSIX_Stop$(DL) >> $@ - @echo $(DL)check POSIX_CheckUnload$(DL) >> $@ -else - @echo $(DL)start _LibCPrelude$(DL) >> $@ - @echo $(DL)exit _LibCPostlude$(DL) >> $@ - @echo $(DL)check _LibCCheckUnload$(DL) >> $@ -endif - @echo $(DL)import @$(NDK_LIBC)/imports/libc.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_LIBC)/imports/netware.imp$(DL) >> $@ - @echo $(DL)module libc$(DL) >> $@ -ifndef DISABLE_LDAP - @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapsdk.imp$(DL) >> $@ - @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapssl.imp$(DL) >> $@ -# @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapx.imp$(DL) >> $@ - @echo $(DL)module lldapsdk lldapssl$(DL) >> $@ -endif -endif -ifdef MODULES - @echo $(DL)module $(MODULES)$(DL) >> $@ -endif -ifdef EXPORTS - @echo $(DL)export $(EXPORTS)$(DL) >> $@ -endif -ifdef IMPORTS - @echo $(DL)import $(IMPORTS)$(DL) >> $@ -endif -ifeq ($(findstring nlmconv,$(LD)),nlmconv) - @echo $(DL)input $(PRELUDE)$(DL) >> $@ - @echo $(DL)input $(OBJS)$(DL) >> $@ -ifdef LDLIBS - @echo $(DL)input $(LDLIBS)$(DL) >> $@ -endif - @echo $(DL)output $(TARGET).nlm$(DL) >> $@ -endif - -tool_hugehelp.c: - @echo Creating $@ - @$(CP) tool_hugehelp.c.cvs $@ - -$(LIBCARES_PATH)/libcares.$(LIBEXT): - $(MAKE) -C $(LIBCARES_PATH) -f Makefile.netware lib - - diff --git a/dep/cpr/opt/curl/src/curl.rc b/dep/cpr/opt/curl/src/curl.rc deleted file mode 100644 index 5f49d223697..00000000000 --- a/dep/cpr/opt/curl/src/curl.rc +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include -#include "tool_version.h" - -LANGUAGE 0x09,0x01 - -#define RC_VERSION CURL_VERSION_MAJOR, CURL_VERSION_MINOR, CURL_VERSION_PATCH, 0 - -VS_VERSION_INFO VERSIONINFO - FILEVERSION RC_VERSION - PRODUCTVERSION RC_VERSION - FILEFLAGSMASK 0x3fL -#if defined(DEBUGBUILD) || defined(_DEBUG) - FILEFLAGS 1 -#else - FILEFLAGS 0 -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L - -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "curl, https://curl.haxx.se/\0" - VALUE "FileDescription", "The curl executable\0" - VALUE "FileVersion", CURL_VERSION "\0" - VALUE "InternalName", "curl\0" - VALUE "OriginalFilename", "curl.exe\0" - VALUE "ProductName", "The curl executable\0" - VALUE "ProductVersion", CURL_VERSION "\0" - VALUE "LegalCopyright", "\xa9 " CURL_COPYRIGHT "\0" /* a9: Copyright symbol */ - VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" - END - END - - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END diff --git a/dep/cpr/opt/curl/src/macos/MACINSTALL.TXT b/dep/cpr/opt/curl/src/macos/MACINSTALL.TXT deleted file mode 100644 index 2bab9fd3dd7..00000000000 --- a/dep/cpr/opt/curl/src/macos/MACINSTALL.TXT +++ /dev/null @@ -1 +0,0 @@ -MACOS (not MACOS X) =================== This is the first attempt at porting curl to MacOS. http, ftp, dict and telnet seems to work fine, other protocols and advanced features have not been all tested. This port is heavily based on the GUSI library from Matthias Neeracher. GUSI (Grand Unified Socket Interface) is a POSIX/Pthreads/Sockets library bringing some of the comforts of UNIX 98 to traditional MacOS. The latest GUSI release can be downloaded from sourceforge at I have also written a few functions to help port Unix applications to MacOS. These functions are part of the GUSI Extra library that can be downloaded at OpenSSL support is still experimental but I hope to deliver a version including SSL soon. curl for MacOS requires using the CodeWarrior compiler from Metrowerks. First download GUSI, GUSI Extra and curl. Access paths have been setup so that GUSI, GUSI Extra and curl directories should have the same parent directory. Follow the instructions in GUSI Extra "readme.txt" mainly the ones related to SIOUX and GUSI patches. If you do not apply these patches curl will not behave correctly. In the 'curl/src/macos' directory, decode "curl.mcp.xml.sit.hqx" (This is a stuffit binhexed file) From the CodeWarrior IDE, import 'curl/src/macos/curl.xml', adjust the access paths if required. Then you should be able to build: - the libcurl libraries for PPC and 68K. - the curl application (also available for PPC and 68K) which is the command line version of curl. If the file "tool_hugehelp.c" is missing rename "curl/src/tool_hugehelp.c.cvs" to "tool_hugehelp.c" and make sure its file type is 'TEXT' diff --git a/dep/cpr/opt/curl/src/macos/curl.mcp.xml.sit.hqx b/dep/cpr/opt/curl/src/macos/curl.mcp.xml.sit.hqx deleted file mode 100644 index 01650b9a148..00000000000 --- a/dep/cpr/opt/curl/src/macos/curl.mcp.xml.sit.hqx +++ /dev/null @@ -1 +0,0 @@ -(This file must be converted with BinHex 4.0) :%'0eFQ`ZE@0`,RKYE#jcDA3!8dP8090*9#%!N!3F@`#3")EF8h4eCQC*G#!SBbN a16Nh,6)`-$%J3@aKC'4TEL"6HA0dC@ec,#"*EQ-Z,#"SG(4`1Lm[Gj!$,Q&XB@4 ND@jcHA-ZBfpY,e0dG@CQ5A3[$3SD!!83!!!F@`#3!h)!!3#3!h)0,`fPT9*PFf9 bGQ9NTD8!TC!%!3!!2!!3Z$+T+EJbU5N!N!d-['F!"*UP!!!E'J#3"!m!Bh9bE#j YBh!ZH'eX!!%`!P4&@&4$9dP&!3$rN!3!N!U!!*!*!CS!N!0K!*!%$`"#`G6)[bB "`A,RBHAV3f@ZJUhAq'5,9!EjE+@0l9R9ECKR4kTRRh2Tr@@VMJ"@0,FaU4R&FMa LBT)4LbVeb+BC%jqHQQI4[fPBGXP3'T4BeHdDm#H-`9$4'EUJEJ186cE)3X(8K-U 1KiJ4+5-HVi0DI[@5XBTQHb300K2--ZQmjPHEfdA)NhXMSJc'A+@kemq4P`'SeCB TD8QEYXMK8Kk4YZRkc1,G%m39"[dp8Zmc'[eKd,jpTVh555HQXd2`S9"KrGB`laE (r+!)8r8DP'9kbYVQeY-aSjVQRA2k-`'2pqTr9EP6Z&H-%4eK4@qp1Z(fDAd1&`A H1IYG&T86QUHmp*%cdr$@G4fJrQ[9'8p)f"FPKmMQH6!kGBGeTA5Im1Pp*(P69-* b8ld+I'KQIH`@CNfcIEGE&Zbb`3f,4IkZ#4Ve"2%R-a#MLYefeG"*FSMj,RD`aaE DHh6$h8hF"r`SK84RjI*$KFfI&J3ZTk"r!J2$Nr#%K(IA803e(bAG645j1231E'$ C5$(Nr9Z2LZbqJPSH&9[h1(,+e"8!I$4XKrIeH6Y"")PlSQG2V4#-hZAbb2jBT25 (IUG-bFQ+0[bbfAlrpIDlpCradaS5G(*4d%[i*ISQ&5*3e$NVT#A+!Y3P%V*@HX9 6AGI"h1N`D@lj56PX8fB95NekUL&lk'15a*Z(38rC`Ii%$Y$E-A"!QfHG(Ed)Uhd $e&Ckrm4jfVikK&j$D[%H)*lGX!FUK'&[Ck*%#lJUT9qiT13X#T4mK2)e"`%-JFe )*)Sa9b+92'@Gb8N6d9E+kJ#VEA(c6+d`%E82FXcNKJYM'a,FD@Jf-Bhe0i+B2b' 4,T!!lq1IYLpFITlMfGiYPc0f$6,+MDV5TI9#X-SpJhU%)Fb8cp2EjaJ6Y-)DC*f e'FGC5B'BdQV'H!@cS`XJID*-@m3!EFmNq*Ve20Pc0%pLrF4I`MH*iE!bAI`TJ6f fIkZ$4)P"bTla%@'ZL"8pmd(L(R3XEa8KPe@FkheL$l%E1UF89BS&afbE`RN#pXJ IUFD+"e#6RG6PSV[,G0B8l,Ipa2UU$4a@eA6jr+8Y,jkA1f9)d0!)UcD8pc1PCaS $4e#PcC8bCKD'Ar-2Yr"-%XLQh@AF!9p6rj`FhAk@,R*F(2h!LB#ca(F'im+pi,L Bf4LJV+icK26r2XR2)q9fr#K3PQ3PU)3V#9KqDVJL&pEb*`f)lAAq9FdpFU[$8N6 H43&)*h$BNrd0,c(!ICCA2Nh-i-b#,A9)Dq6b0QXcb4Cb)HG0c,H"E8"bQ0V82+K (6bpND%LUfp6S(mNAhkhHBJTdab-6GA&I%2cqe4`NjKlSpKDmI6m!h0,h!`LC-2j pCCGeT6#1Y62eS"hVZBAlj!YPi8DS1XV14b!3d)r5Z1C(*KTB'Df3!+cZN!#aJMU am2DQK54epTl55RJcT[d$'Q5Me1@)lDI#N6S,Rb-#2%BpdZePl2&DZb9GH)-0FR` 3N!!5&mlD,Sp)"5ZC2f@E-bpUflPTaUfFJ4mZUlcp#`iNNNl#eBaVI1&m0!dP'F[ lT`UUYVZpKX&HPmBMVf"+'fS0*6pRfA+HccXLd0PXk",eKDrh`@MYIGqm(MRcMcP UCb#C$m'[dhBrb438Hbh4+bDe&0"BSF1P+PPP4@i`%iP22P9ibJHTcBXRN5!leUL LkN%bVNT!r-qGI('DMAp8jc1e[eH9VBp1+DSk0V(-aMaJD(6FHQ+T'%'h8"e3LeY *2ldFPa@Tem)!l+PBLXN#idPfFC0i-V-9Ed2X@hEhCC!!e2J+JDccb1@@XE`Ch+V @!I1YF"Jf&8Kc*-A[5BT"cFJ3I8rP#Vb#NHYS+"%q25(pP2,aD$5KBV4"&PiN--c f!&h'b,[%ZDE0!j&ZY32dZD3h)p'VEr2p@kU8c8kU,K'lh$A8,)`efrhRPmImIpI YXG)SXje6-1Z$'lrlYNl#ECVlA2V[1h9Ej6X"Q-(LA%P65$-Ka92rah%dQmeF#KH (%CE56(aEpX$BKjEHj(6mN!"l3iEi(2#eJXU2$BHK`913!#8U6q3!&-VfilRY05# +CbP+)RJR0D'943,GI+$+0I0+'SNaNUMBZ[q4'kLpb*c)iGMP,'c'hFQc1B6@@J6 fXPPfGrc`"VaZDc5@lD1*@AIr'1UT5C'NI$HV@!e*U##m)62YSNd$`'p*J1[@ZVM 5D'GRTkrhF6"1D9-DV'2YVR*$RV,I`+QmTjICq92DT-f+SL1lD&kp)C8`64h*aY* AaJiFNQBGVU!$p6A1-m-e*1L9Iic!B!lQ,rZIkda"cB%TJ`U*0QP,'JVEhkFUFU& (X5K4`r3eG5!0T0`KfYQ6-I-E-mUbb&1TIGYrd"X"EXL$@U!J)EB+%q8mMd,dFeJ fLGJA5!N*4MXRSYfk8"8Vp9RY*4rXaR0dQ"3d!1R%CAQZRaPE1*MZ&DHdelBBaaA (CTA1k$H!##ZMT'i$kB0JJPc9Y"5Em&M)DRM*#SIahMpP`2T[3F,Sr2JX9E@,U5L 10Sdd1Y(qAG#,G'hX$PibcN@!,X`qX*,'eM#B)#S*k1PLLI*REMpB"UmhHT-j!0& TG)jc$@3BLI"em*jDf-B%qLmRR$,BQ1q)YN!*Q1ZNVH,YL#f$!C3-1#@Lch3a2+D 1S3dIq-1a[1C*E$*P+KPQG`THP&p'TQ$JJ-*$cK9F03c3F-aJGGic8i,3hd[fAQ( X2Zr!KU)Rlj!!cer8P'[-pmXiEG4ETUADfi2e!+XIM"@%f)[i)Ikd3c!4jR!-4ar q1T6*aH(Xp6eP)1"JRKV00!kq!BaZa-p*GA93QrN2e@l5U!bDcH)QqRTh9BT04b$ 5Yml1!p$+q9ILbSc)r+'IfN,jLH0'9S)Z+ji4P'1GBK9MHCmrhF8AVC(Xmm"IHl# QFBJ"3PC,19FjeHrVT3AV%qCIqAh1VJm(G,#b$Gh-aRS@jXNFTGXV8@2Eq&L#U%L bf**dKC),j0c9*P0&V!XPRpA0'`jEQG1PDJ+Zdb`[PpRLe34(EcHI-CPm54(VIbE 2J3S%q'`"i`+,HjI3D&@MmVRC5ffqFSVlc[1eQP`@)$eHGrSTSGA@,fc&Yd%c#-[ c`N5)bZ%5b!`+QA-C%YBp[NpG`fMrU'VklXR-he$9jRbE5pBEJR2GeER[mN'1,[` *5HDBYJFl#DN&kKi#mVHiL2@'H4Lb-%(#jb5!e"`RQeJJPfD*L#l$'($NZ1*53#4 P"Z19[8kVVN86PN0#LLPpq&`6QI1)ZR-h3b"[H'qCf&q%J1$CRiFD6AhC'iAdA!5 &9qaeYeVcr,1k'F2P%TlIY-mjXqRIMK+"1cJjQ1[ad0mTG53!aa[IQhlKS@)N-(a pUJ$DahNB2HZ[!!fJ,p(-ACep@IGH86&XYZf#UZd`6HTD`e66bA,VjkUkQpeq)%J hajLPmXp(SipKb*'k%k1f[e'0!D&Sh80Q"$BH&jiJb+SEbpTbQBkE2Qp,5[hLS@1 1pUZ(*&)`(+D+RH8$Z0,+br4iTZJ2rZVP,UC!FP8[XHa#3+"aHC!!DMcpKpFDeIe D%2`@$YX20DB&iIcJUS-R%eCPc4&MSE2f3qfA9IJK5I@,R4403FVlTR'JKYF'NBr eC`jcaFi8Bl$9bp,K,TCp"cJ33fq@Z6`!DldUA,C8J[(2MaI2,p!`$5YT12Mei`2 kEK")F$6(J8GAiLMFaTiMqpE8KiZGrrk"D3Fi#8(4*fVmGK4GIb9Pb9N,%Qh2V&b G`4BR#1B@ZrmSF@DdRU#!!i64LJXc9abPYpjfa+I*FSZ(&IkqF2,@5XqlSfe(pJ5 @FBNcIm6`B$SBQ19pA0k8'bmMac8kRP[Q#l4qV9P3ibU$dmlE'[@*Dj1JGRJe4[Z 5M#`*0UYGpeTAFQV4)hc"Frq0Qe88T#fG+YrEd%GD5VaN8ee69)@GJLMaCTYZJ$h Y`PmD[A8fB#4GP0TV(G5&@%i-DBILl&5HUC*fk#qhfiL-VdMPEK`@*G5aB'3@1DI `Gmq!%mJhD-m-E@ei1#pf)H!Y)#hdYf5,Kre61KKr6-k+iC&[6#!,*8aC4V,dBda *G-Ea,kcp`EQYmI)q(TSXdpT[&6NmmVela*&ZrNk#!a*Ek1U9e(A-C#MTiFrU*8# GRIPS(IG0NC0@D@C,ef!3$-V,f1MmeU$hMNGflfPjdA1l$m'dhT6mE$5k,&09Rk* 35$B&A8hc`Q,f[MCL'()&ZSp9"F43Y6Gp$d@GQ1*-IFE)fQ`!Gl+4bY!)4&ME!i1 S(e$jM(!B0$aPZUklAZC&R6Q$q(JE0b`QVJ8l2ELL'2i"i$m4hNQq3$S*@r,KlPV @0aB$#$cij*NFIiA[#P'Hmk'D%mJh*T,r&0T!Sj!!I%QRN!"4J!C25i'JdhRAG4# +iPZ,'C)pS[%JqMbf%5Z@HYTRpTjm`P9K-jj6!9j,5+E8[jbd,$Qb,rLerVlm'a" EJ,NAIG%b0S`!KTfSi1,Hlm6&Tl86i@XA-SjmDCVVm2JR[U[ZUaabTc`"ZLc''*T MA06`8"HaVhrb,12m0TYp8$49BH,J(bC-qMij8S3`iIJLm!&DUAX,NDT4j(cCZq` Sjr#YLPbe+8AqUc@cBNPJ0I"'D`jmfZPUpmQhXQ'2G"i,XrX6PZh5*UdATE`QBJT 2*-NNJ'H03hDLq3NLl8V#BcH(SN53!&)l)I#5DJXfUc)pbK*kKMMdhlkIbRYcdU* -kaTcDabVQGjqY*`D1++%&&hPjA0$mc46dA5Pa&+%QbaXIY(9*40iKhGhE(!d(Zj TU%6JfY"(KHR"&-pfT-D8AB"c'iDKcqH'9"0#TcflZJ5YE#(YDU4QTYFS*`lY2+' HUH+"N6hThTfY$V%@bmP3RrZVqj*lIM!qQ&'(*R8#YUX0ViVa-8c1cLi5mSh423Y c"ZTZ&UCCXZeRVUh#+(cU-p`4R%4,2aCl@ZeXXYH'f1j5r6'Fdp6k&d9CITqHK#@ jRIp9LG#d$jCXIJ9ZTRb1X1r#JCA&JjmSEMUfVbL!D[6I$5#JScE6Na9lmKfF0EH V"15k'@bDdk%miP"ThZ@A0I0@V`65l5S9deFHd#$hUXR5GDT"DMik$YJL+GmY#CB f%KC+a"&%)ihiBfR+0I#@&ENYGGfGh1ZaX"RlLlZ$l-9X9H*LaaQqEZ6LZ'rpIM* GCa`prJ+&V"j-rb!(B[h8XVQbRfQhYc,GJ(J65aIbPCVha(mX8UAS2e@%VYZYMF( $UMM#pf[eK66(Dj1)d*GNK+[I"ZK52ijfp01Pj098q,AA1GUbRR,5Z)jBdJMD1LZ Y8$2iKCVB!R2!PiF*N!$Ycb2#1Nh6&f-fSDEc2YH1jp9GM@!XI'*ilG-Qc4qT0fe dIZdlC9qP)X!!&@4T9A$EaNq-AZKQ6%R$$a54DScX[R*,M*!!k)K4LrB9Ma0[+II jcUfa44M*R18DLAMSp36ELf),#2#qPidNRI[QVFj%D95q)Xa`RS6EjCd+5BN6MeV %!,Q1a$r!B1`Bp3FM8IpLD)S+$G#+BR1)d#!hB9'5GRjMXFLAC-06*FkSLrBpG6X ,q$JVU-a-"TBp@F)+T`$8S[Dj!EIek6Ei!CIBUAGZpERj!eKb9(,X'RqjiBH5bbP -M*hrM9L`Xhl"GqM#U-f9*jXA"IQeZ[b#&`DqGehATT!!(S$6dqLGCl@A-NeefUB CPHNb!6cQp-!L[%Qal$RBVE9ZN!#qrF#!'d&V@ceTH8bbU3`DV0!06TamU$%('FZ l0N`a41a+-&6)Jcjl2XS1jHBp[HE"-PTaj6*#rZXdIX8%X8XRqJXc(FN5iG%bELS +b,60YmQf"J65!j!!D%+B#Ik0&-B3B@*GM[jJlJBU$RkG93B`&-#!h+HerJ8PT,@ b4!M[IeX(5fA%bFZLUp@K6(mkd@BTHhBcDkGaJh0`$CA2N!#3!%G1-Ne!SYh%drH F,BQM`')#DqM&#U(*Y-1lG45[6@GDN!#,bMKZRMG8"D$T2Kc192P!mSK@0AC8#3E D5,p-B+X2ZcmCQAIc,2AEdK5!+1N5*`cl9qJ@N!")h+G,fYaRJrRN`dd1NQ"E$VL ki6&AIilJU6[Z6pR5B*U9Rm1S[dr`a6mp3Fd`ArhVJQ!TR9T#ZhI+MpjYcFC*Tpf JP)[hkrKT5D`IVBCl"QA0TS2!TdYN8%E#epb&4PA9Q-hQ50A5SA@GjUa`kE-X-HM +d28*r*JYMjd!ICRc,(ZrmcU5e(4KNd[IAR$U[Tm*rdK"&(P&HE,U5c&(#0[`'-D 5f6@Qdr3dIB[VAlQbBHEiXrVYae)ZjkP@,'U[dE)NKfe95B9"Jk0'I$A8b$VC&CI hj0TB-$9m0"N8$CIaHe"M2@3-GQ$(12rHGfTrFM[EP9BMH3B`fcFE2PM'VNZ+fSm R[kIC&VabE@DX[9ZChF-R3*X*[Gmakl`@[!XBM"Iq3#d4e2`)6dE"fe2&5r'*3)D fB!kY""qf-#Xh!5DUNqDYG(&`URfpc*RAAS-#r+D@!A[j8r[eAi!S-rimJJ'!JGb %*BZ5$!f,GjJjLa5D")q,RL4XR[Ppi(r8RNiP$2e@ALL+bU&lUIljbU5MXf56RSK #8KbRX8C@f&kmYX-V,K+TmASNfml4&HPfSV$Y(&Y&J8ER)M[,N!"VmB&c'$a2h'h c`MAp!+rpRY(4Qe8@Z#el[0+YYH#ZYd3EMkbHRechUKDqX5k8m)cfAKj'mJ*[h6' 6)pLEDAqcBBi5[CE[rpIkcC%LIUe3f4@8TFUBfZ9B6FYY-F)N[fBV'h3@(m&iB,a )d1HkSQUS"C91!eHTUrHa9J[FLDk'K8-H9XmKc$L*'V5H'-5[*p)TC'El!$b2J"k T0Ul!A)(4ZlVY!Te#X5V)+@[J"r1e-BdkRFe`N!#r0DcM"VUBekGkJe,*5cpX0PS T(d3588LNcfA!1-TB8GQ`K0eIIl0N96)Nd!Rb%&4LIRETS'P3+jA+Bi9SY#qCmGI 5Ai,[V-NK#La5439PX&LDc8hTl$aLj359-bqmDJZ)GiaX1k1[k)bMZ2r(U*c[Gej %D)m*@@+eGqbF249V)fRpkp)6e0JrHiB*[K8*9fGR-AU+jTcpi#f0+U0+L@Yc'U2 dc04kb961J1JdC5PLEV30PJSYZXJ#jfdlb$,0UrY"jX[RkUY8JLY)-L`Gj6ieH'6 %C*LCT`)3ZS@[X2!%!-SJKp1jEL2Cml64,qZhPa)'AidDL1Ybp@6`iI80l+RfHpd Y1XF"[0[r!$B*PqDdHB95)l8[1I%*Nr,#e&Y3CCiNFC[8dj9TDKdh)Q6,,fCk(S# pQbBT0TY@PD(I@lDhBV%Pk9GrD%IY,YpIM-V9cE(UBbG2&Xck6c5I1BcMA-YcJFA 0,Q"*[F1C16*jHTMMPV0@6HYDU5V0`dPbD&X+MPSlR&+hbi36I8(5pBhrN!$Nj*a Z#!akZ&EGD+M,95XdGQGpfB`RY9BjCa9"Jp0EhH,EFY$Xp0#fq5DI#KVJBj,10hZ `Bq#LBCm2%H@E,+X9!b92Xb3iDFh4MVPIpfIVl"rkr%Eie%$X)MHS6PM!XTB'1$H kR%(U%"b&pq)aqe3a9TkCmFDMGk2qq%"HEh*XqVLk9-A,*pAd(dpZSG2Q#&qCJP2 X5cRMX'hX$'L5*+0!i`51"Yaj''JmqAJA#qUqe!P,MR-!NDje18N(qV3@5C1&B`D IqHRl9X2i2T6ZJH'e!jK,MY#3!+TSYiGI*AaPcjIbGE,pQ5[0Bk@%Ahrf#aQ$NkU d!GNU@XiVQ!T6'EHGZC4@(Qf-icF'*X1,1elXp1L)jmi`Y"F,'Fll%A@'$Mp1IT% 4pZjYGj%b,8rhMFlIh1-NN!#MD$'mrpeRD+18mX9YJ+9kiQE-B&U''*jE1*6raUl $40TV"8Aj2`cF3YHakZ6%05+TZ8&#e4HlCpJjL2$)l&2RNVNKBEAbL2UqijV4C,4 !9bq*`lQDp-&$iV8-!)S2)(el3Gp5lfekXY%TkcB%-PkqfD`DRD,R`APCTf%SkYi YkMk9pc01i''-FlHj6bF6QU%PJ+-@4DbAp91&Q,4`0mc1'1(,P6j)j1fMGbAf%BG ,M8&e!2R'Uk,%Rcm9JkL53'"eTe@IXaCCY!0!33RNL)DY5CYmjN%VhK,U8GXFG+[ 8jmX*Z2'(9BE)F'c"[r"4(UF4E*Qa[Nk-j&"MM!B6UZ*0YpL'!+9)G*&k,&2l@&& AbpQL&q)IrbB+ED(J8lRM"*Ii6%VUADiNE'dVU'q%[LHeia*6Y%89acHSZLZH(mq I[jRmr6$mVc-RTPb8+)ZMjI@hNG(F0VT&bU@(Hq1!F"2j881[Z$Nm5SC@1$41qHC Z*B%dX0kZFfcHDPjCH`GJrbU5DkEdIaTUI+NaK"PdSmI[LPTLJ9IJ8KA#kV"2Uia KdERdQFN93d"lqUqXj@Mr+*qi6&"UECZ-#,*iEC&C`bZqlMfYpM(epQ)*%&C![LJ hPR8L[G0#*-Pj,5P*C$cF+BTi2&i!bX+hlrFri`8+M'SNkXcMM(Q3!%%A2MlD*28 VCqT[JjMIq0PTUq0qPSAf4a0$XLC)-48j(c*)V1K5Pc(m%SGL+($j+p8S%dQ3!&Z lQ%+#S[eP8p$5$[$Vq)R)6HaCkZT5CT&*Rb,2I'PA"EVrJTPJKBE@Xi$J%rQAiUE $fqc2ald8l1R&r%FZ(Gq*VR(@l'M!MiUBId*-Kd&S!pP"YBNkYP[B[Z%YlT5SmY! 2rJF43CSX-e@Gp1FDa-d'!JQ@al9raL0r$[fkG0#D5VmHClHGEqhD`fmVA[jC+rM (&qL@f"N"(1DT-#2bD)j)N3!`Tr&$Rep"LN@aR!Rl(5lcE1UYTUmcVKrX(f1)40K Y4RQl"CKXF9C08YC(*$aR5a@QalMZGITR05QRZ"+h`52GmMN4pj6iXh*6MZFb8ke arcTIYkJ%@!F4TNFBfCKU#I3SZViZSKC0e*!!"cFIrhEC%XbSMX6jaS5&9#h@!`d [Y&`V)j*NiURXkhF0DP5e2dAG*Z,9N!$*D[l1$KF5SNi[b"J@Z2Di),1E93CDGmd Gb1)8,k@iE`R'kNHkLYb%dGd34Y,C013(''CiPAT2BRL[dYPHEY6ZE'`i0f-mp)a X&[HT"f3K+8rfE`T!,%MI)YZKJqZ#ZDTfGRYe'+5[Ke+2E%ecBS3pPC!!rU*,drD &884$ZmbC%Y-Iea(IUfjblN-*cX2hB`Mr+aG#AhMaaJfKPbd5P[+H$9A'(jGqcQ- 2pAc0'J[b`hF4+N1dYV[8#-aHm&FiqHbK`R8PpZ*be,`-[a"P"q1lcb$Z8I%0RA2 X8bcClk*cpGU1Q5c6VI%#`63X"PYE,*Hi3bF21r2JTij#%Q3J'cij@e+-99)rZqB $DdVZbrG[S8$eBj!!@$Z3!%C,DD1H[Dr+iFXKGGD&**8$2mqBZG+M+&`P%``#e8Y 13020cm&rj9ND(4q*S+D%eYGi'X(IT1lA+fV1,T!!6(fcKe2S6"!X-C-F-TqlSTB BJTb$,U'!bY8!!!: \ No newline at end of file diff --git a/dep/cpr/opt/curl/src/macos/src/curl_GUSIConfig.cpp b/dep/cpr/opt/curl/src/macos/src/curl_GUSIConfig.cpp deleted file mode 100644 index fc9378ae25c..00000000000 --- a/dep/cpr/opt/curl/src/macos/src/curl_GUSIConfig.cpp +++ /dev/null @@ -1 +0,0 @@ -/**************** BEGIN GUSI CONFIGURATION **************************** * * GUSI Configuration section generated by GUSI Configurator * last modified: Mon Oct 29 15:41:51 2001 * * This section will be overwritten by the next run of Configurator. */ #define GUSI_SOURCE #include #include /* Declarations of Socket Factories */ __BEGIN_DECLS void GUSIwithInetSockets(); void GUSIwithLocalSockets(); void GUSIwithMTInetSockets(); void GUSIwithMTTcpSockets(); void GUSIwithMTUdpSockets(); void GUSIwithOTInetSockets(); void GUSIwithOTTcpSockets(); void GUSIwithOTUdpSockets(); void GUSIwithPPCSockets(); void GUSISetupFactories(); __END_DECLS /* Configure Socket Factories */ void GUSISetupFactories() { #ifdef GUSISetupFactories_BeginHook GUSISetupFactories_BeginHook #endif GUSIwithInetSockets(); #ifdef GUSISetupFactories_EndHook GUSISetupFactories_EndHook #endif } /* Declarations of File Devices */ __BEGIN_DECLS void GUSIwithNullSockets(); void GUSISetupDevices(); __END_DECLS /* Configure File Devices */ void GUSISetupDevices() { #ifdef GUSISetupDevices_BeginHook GUSISetupDevices_BeginHook #endif GUSIwithNullSockets(); #ifdef GUSISetupDevices_EndHook GUSISetupDevices_EndHook #endif } #ifndef __cplusplus #error GUSISetupConfig() needs to be written in C++ #endif GUSIConfiguration::FileSuffix sSuffices[] = { "", '????', '????' }; extern "C" void GUSISetupConfig() { GUSIConfiguration * config = GUSIConfiguration::CreateInstance(GUSIConfiguration::kNoResource); config->ConfigureDefaultTypeCreator('TEXT', 'CWIE'); config->ConfigureSuffices( sizeof(sSuffices)/sizeof(GUSIConfiguration::FileSuffix)-1, sSuffices); } /**************** END GUSI CONFIGURATION *************************/ \ No newline at end of file diff --git a/dep/cpr/opt/curl/src/macos/src/macos_main.cpp b/dep/cpr/opt/curl/src/macos/src/macos_main.cpp deleted file mode 100644 index cf3075ffcca..00000000000 --- a/dep/cpr/opt/curl/src/macos/src/macos_main.cpp +++ /dev/null @@ -1 +0,0 @@ -/* ========================================================================= Copyright (C) 2001 Eric Lavigne Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: - The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from defects in it. - The origin of this software must not be misrepresented, either by explicit claim or by omission. - You are allowed to distributed modified copies of the software, in source and binary form, provided they are marked plainly as altered versions, and are not misrepresented as being the original software. ========================================================================= */ #include #include #include #include #include #include /* ========================================================================= */ DECLARE_MAIN(curl) REGISTER_MAIN_START REGISTER_MAIN(curl) REGISTER_MAIN_END /* ========================================================================= */ int main() { ::MaxApplZone(); for (int i = 1; i <= 10; i++) ::MoreMasters(); (void) exec_commands(); return 0; } \ No newline at end of file diff --git a/dep/cpr/opt/curl/src/makefile.amiga b/dep/cpr/opt/curl/src/makefile.amiga deleted file mode 100644 index 9f3748b1aa4..00000000000 --- a/dep/cpr/opt/curl/src/makefile.amiga +++ /dev/null @@ -1,30 +0,0 @@ -# -# $VER: curl Makefile for AmigaOS ... -# - -# change the follow to where you have the AmiTCP SDK v4.3 includes: - -ATCPSDKI= /GG/netinclude - - -CC = m68k-amigaos-gcc -CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall -LIBS = ../lib/libcurl.a -lssl -lcrypto -lz -MANPAGE = ../docs/curl.1 -README = ../docs/MANUAL -MKHELP = ../src/mkhelp.pl - -include Makefile.inc - -OBJS = $(CURL_CFILES:.c=.o) $(CURLX_CFILES:.c=.o) - -all: tool_hugehelp.c $(OBJS) - $(CC) $(CFLAGS) -o curl $(OBJS) $(LIBS) -Wl,-Map,curl.map,--cref - -tool_hugehelp.c: $(README) $(MANPAGE) mkhelp.pl - rm -f tool_hugehelp.c - /bin/nroff -man $(MANPAGE) | /bin/perl $(MKHELP) -c $(README) > tool_hugehelp.c - -install: - $(INSTALL) -c curl /c/curl - diff --git a/dep/cpr/opt/curl/src/makefile.dj b/dep/cpr/opt/curl/src/makefile.dj deleted file mode 100644 index fbd2d3738c3..00000000000 --- a/dep/cpr/opt/curl/src/makefile.dj +++ /dev/null @@ -1,94 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2003 - 2007, Gisle Vanem . -# Copyright (C) 2003 - 2015, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -# -# Adapted for djgpp2 / Watt-32 / DOS -# - -DEPEND_PREREQ = # tool_hugehelp.c - -TOPDIR = .. - -include ../packages/DOS/common.dj -include Makefile.inc - -CSOURCES = $(CURL_CFILES) - -ifeq ($(USE_SSL),1) - EX_LIBS += $(OPENSSL_ROOT)/lib/libssl.a $(OPENSSL_ROOT)/lib/libcrypt.a -endif - -ifeq ($(USE_ARES),1) - EX_LIBS += $(ARES_ROOT)/libcares.a -endif - -ifeq ($(USE_ZLIB),1) - EX_LIBS += $(ZLIB_ROOT)/libz.a - CFLAGS += -DUSE_MANUAL -endif - -ifeq ($(USE_IDNA),1) - EX_LIBS += $(LIBIDN_ROOT)/lib/dj_obj/libidn.a -liconv -endif - -EX_LIBS += $(WATT32_ROOT)/lib/libwatt.a - -PROGRAM = curl.exe -OBJECTS += $(addprefix $(OBJ_DIR)/, $(CSOURCES:.c=.o)) - -all: $(OBJ_DIR) $(PROGRAM) - @echo Welcome to curl - -$(PROGRAM): $(OBJECTS) ../lib/libcurl.a - $(CC) -o $@ $^ $(LDFLAGS) $(EX_LIBS) - -# -# groff 1.18+ requires "-P -c" -# -tool_hugehelp.c: ../docs/MANUAL ../docs/curl.1 mkhelp.pl - groff -Tascii -man ../docs/curl.1 | \ - perl -w mkhelp.pl ../docs/MANUAL > $@ - -# clean generated files -# -genclean: - - $(DELETE) tool_hugehelp.c - -# clean object files and subdir -# -objclean: genclean - - $(DELETE) $(OBJ_DIR)$(DS)*.o - - $(RMDIR) $(OBJ_DIR) - -# clean without removing built program -# -clean: objclean - - $(DELETE) depend.dj - -# clean everything -# -realclean vclean: clean - - $(DELETE) $(PROGRAM) - --include depend.dj - diff --git a/dep/cpr/opt/curl/src/mkhelp.pl b/dep/cpr/opt/curl/src/mkhelp.pl deleted file mode 100644 index 270daa20a31..00000000000 --- a/dep/cpr/opt/curl/src/mkhelp.pl +++ /dev/null @@ -1,258 +0,0 @@ -#!/usr/bin/env perl -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# 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, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -########################################################################### - -# Yeah, I know, probably 1000 other persons already wrote a script like -# this, but I'll tell ya: - -# THEY DON'T FIT ME :-) - -# Get readme file as parameter: - -if($ARGV[0] eq "-c") { - $c=1; - shift @ARGV; -} - -my $README = $ARGV[0]; - -if($README eq "") { - print "usage: mkhelp.pl [-c] < manpage\n"; - exit; -} - - -push @out, " _ _ ____ _\n"; -push @out, " Project ___| | | | _ \\| |\n"; -push @out, " / __| | | | |_) | |\n"; -push @out, " | (__| |_| | _ <| |___\n"; -push @out, " \\___|\\___/|_| \\_\\_____|\n"; - -my $olen=0; -while () { - my $line = $_; - - # this should be removed: - $line =~ s/(.|_)//g; - - # remove trailing CR from line. msysgit checks out files as line+CRLF - $line =~ s/\r$//; - - if($line =~ /^([ \t]*\n|curl)/i) { - # cut off headers and empty lines - $wline++; # count number of cut off lines - next; - } - - my $text = $line; - $text =~ s/^\s+//g; # cut off preceding... - $text =~ s/\s+$//g; # and trailing whitespaces - - $tlen = length($text); - - if($wline && ($olen == $tlen)) { - # if the previous line with contents was exactly as long as - # this line, then we ignore the newlines! - - # We do this magic because a header may abort a paragraph at - # any line, but we don't want that to be noticed in the output - # here - $wline=0; - } - $olen = $tlen; - - if($wline) { - # we only make one empty line max - $wline = 0; - push @out, "\n"; - } - push @out, $line; -} -push @out, "\n"; # just an extra newline - -open(READ, "<$README") || - die "couldn't read the README infile $README"; - -while() { - my $line = $_; - - # remove trailing CR from line. msysgit checks out files as line+CRLF - $line =~ s/\r$//; - - push @out, $line; -} -close(READ); - -$now = localtime; -print <import(); - 1; - }; - print STDERR "Warning: compression requested but Gzip is not available\n" if (!$c) -} - -if($c) -{ - my $content = join("", @out); - my $gzippedContent; - IO::Compress::Gzip::gzip( - \$content, \$gzippedContent, Level => 9, TextFlag => 1, Time=>0) or die "gzip failed:"; - $gzip = length($content); - $gzipped = length($gzippedContent); - - print < -#include "memdebug.h" /* keep this as LAST include */ -static const unsigned char hugehelpgz[] = { - /* This mumbo-jumbo is the huge help text compressed with gzip. - Thanks to this operation, the size of this data shrank from $gzip - to $gzipped bytes. You can disable the use of compressed help - texts by NOT passing -c to the mkhelp.pl tool. */ -HEAD -; - - my $c=0; - print " "; - for(split(//, $gzippedContent)) { - my $num=ord($_); - printf(" 0x%02x,", 0+$num); - if(!(++$c % 12)) { - print "\n "; - } - } - print "\n};\n"; - - print < 500) { - # terminate and make another fputs() call here - print ", stdout);\n fputs(\n"; - $outsize=length($new)+1; - } - printf("\"%s\\n\"\n", $new); - -} - -print ", stdout) ;\n}\n"; - -foot(); - -sub foot { - print <, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "tool_setup.h" - -#ifndef CURL_DISABLE_LIBCURL_OPTION - -#include "slist_wc.h" - -/* The last #include files should be: */ -#include "memdebug.h" - -/* - * slist_wc_append() appends a string to the linked list. This function can be - * used as an initialization function as well as an append function. - */ -struct slist_wc *slist_wc_append(struct slist_wc *list, - const char *data) -{ - struct curl_slist *new_item = curl_slist_append(NULL, data); - - if(!new_item) - return NULL; - - if(!list) { - list = malloc(sizeof(struct slist_wc)); - - if(!list) { - curl_slist_free_all(new_item); - return NULL; - } - - list->first = new_item; - list->last = new_item; - return list; - } - - list->last->next = new_item; - list->last = list->last->next; - return list; -} - -/* be nice and clean up resources */ -void slist_wc_free_all(struct slist_wc *list) -{ - if(!list) - return; - - curl_slist_free_all(list->first); - free(list); -} - -#endif /* CURL_DISABLE_LIBCURL_OPTION */ diff --git a/dep/cpr/opt/curl/src/slist_wc.h b/dep/cpr/opt/curl/src/slist_wc.h deleted file mode 100644 index d8943122c1d..00000000000 --- a/dep/cpr/opt/curl/src/slist_wc.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef HEADER_CURL_SLIST_WC_H -#define HEADER_CURL_SLIST_WC_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "tool_setup.h" -#ifndef CURL_DISABLE_LIBCURL_OPTION - -/* linked-list structure with last node cache for easysrc */ -struct slist_wc { - struct curl_slist *first; - struct curl_slist *last; -}; - -/* - * NAME curl_slist_wc_append() - * - * DESCRIPTION - * - * Appends a string to a linked list. If no list exists, it will be created - * first. Returns the new list, after appending. - */ -struct slist_wc *slist_wc_append(struct slist_wc *, const char *); - -/* - * NAME curl_slist_free_all() - * - * DESCRIPTION - * - * free a previously built curl_slist_wc. - */ -void slist_wc_free_all(struct slist_wc *); - -#endif /* CURL_DISABLE_LIBCURL_OPTION */ - -#endif /* HEADER_CURL_SLIST_WC_H */ - diff --git a/dep/cpr/opt/curl/src/tool_binmode.c b/dep/cpr/opt/curl/src/tool_binmode.c deleted file mode 100644 index 5ca64cd58c2..00000000000 --- a/dep/cpr/opt/curl/src/tool_binmode.c +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#ifdef HAVE_SETMODE - -#ifdef HAVE_IO_H -# include -#endif - -#ifdef HAVE_FCNTL_H -# include -#endif - -#include "tool_binmode.h" - -#include "memdebug.h" /* keep this as LAST include */ - -void set_binmode(FILE *stream) -{ -#ifdef O_BINARY -# ifdef __HIGHC__ - _setmode(stream, O_BINARY); -# else - (void)setmode(fileno(stream), O_BINARY); -# endif -#else - (void)stream; -#endif -} - -#endif /* HAVE_SETMODE */ - diff --git a/dep/cpr/opt/curl/src/tool_binmode.h b/dep/cpr/opt/curl/src/tool_binmode.h deleted file mode 100644 index 8b445ae669b..00000000000 --- a/dep/cpr/opt/curl/src/tool_binmode.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HEADER_CURL_TOOL_BINMODE_H -#define HEADER_CURL_TOOL_BINMODE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#ifdef HAVE_SETMODE - -void set_binmode(FILE *stream); - -#else - -#define set_binmode(x) Curl_nop_stmt - -#endif /* HAVE_SETMODE */ - -#endif /* HEADER_CURL_TOOL_BINMODE_H */ - diff --git a/dep/cpr/opt/curl/src/tool_bname.c b/dep/cpr/opt/curl/src/tool_bname.c deleted file mode 100644 index 5cc5c15dfec..00000000000 --- a/dep/cpr/opt/curl/src/tool_bname.c +++ /dev/null @@ -1,50 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include "tool_bname.h" - -#include "memdebug.h" /* keep this as LAST include */ - -#ifndef HAVE_BASENAME - -char *tool_basename(char *path) -{ - char *s1; - char *s2; - - s1 = strrchr(path, '/'); - s2 = strrchr(path, '\\'); - - if(s1 && s2) { - path = (s1 > s2) ? s1 + 1 : s2 + 1; - } - else if(s1) - path = s1 + 1; - else if(s2) - path = s2 + 1; - - return path; -} - -#endif /* HAVE_BASENAME */ - diff --git a/dep/cpr/opt/curl/src/tool_bname.h b/dep/cpr/opt/curl/src/tool_bname.h deleted file mode 100644 index 61b97b49251..00000000000 --- a/dep/cpr/opt/curl/src/tool_bname.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef HEADER_CURL_TOOL_BNAME_H -#define HEADER_CURL_TOOL_BNAME_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#ifndef HAVE_BASENAME - -char *tool_basename(char *path); - -#define basename(x) tool_basename((x)) - -#endif /* HAVE_BASENAME */ - -#endif /* HEADER_CURL_TOOL_BNAME_H */ - diff --git a/dep/cpr/opt/curl/src/tool_cb_dbg.c b/dep/cpr/opt/curl/src/tool_cb_dbg.c deleted file mode 100644 index aa1ef857c19..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_dbg.c +++ /dev/null @@ -1,282 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_convert.h" -#include "tool_msgs.h" -#include "tool_cb_dbg.h" -#include "tool_util.h" - -#include "memdebug.h" /* keep this as LAST include */ - -static void dump(const char *timebuf, const char *text, - FILE *stream, const unsigned char *ptr, size_t size, - trace tracetype, curl_infotype infotype); - -/* -** callback for CURLOPT_DEBUGFUNCTION -*/ - -int tool_debug_cb(CURL *handle, curl_infotype type, - char *data, size_t size, - void *userdata) -{ - struct OperationConfig *operation = userdata; - struct GlobalConfig *config = operation->global; - FILE *output = config->errors; - const char *text; - struct timeval tv; - struct tm *now; - char timebuf[20]; - time_t secs; - static time_t epoch_offset; - static int known_offset; - - (void)handle; /* not used */ - - if(config->tracetime) { - tv = tvnow(); - if(!known_offset) { - epoch_offset = time(NULL) - tv.tv_sec; - known_offset = 1; - } - secs = epoch_offset + tv.tv_sec; - now = localtime(&secs); /* not thread safe but we don't care */ - snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ", - now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); - } - else - timebuf[0] = 0; - - if(!config->trace_stream) { - /* open for append */ - if(!strcmp("-", config->trace_dump)) - config->trace_stream = stdout; - else if(!strcmp("%", config->trace_dump)) - /* Ok, this is somewhat hackish but we do it undocumented for now */ - config->trace_stream = config->errors; /* aka stderr */ - else { - config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT); - config->trace_fopened = TRUE; - } - } - - if(config->trace_stream) - output = config->trace_stream; - - if(!output) { - warnf(config, "Failed to create/open output"); - return 0; - } - - if(config->tracetype == TRACE_PLAIN) { - /* - * This is the trace look that is similar to what libcurl makes on its - * own. - */ - static const char * const s_infotype[] = { - "*", "<", ">", "{", "}", "{", "}" - }; - size_t i; - size_t st = 0; - static bool newl = FALSE; - static bool traced_data = FALSE; - - switch(type) { - case CURLINFO_HEADER_OUT: - if(size > 0) { - for(i = 0; i < size - 1; i++) { - if(data[i] == '\n') { /* LF */ - if(!newl) { - fprintf(output, "%s%s ", timebuf, s_infotype[type]); - } - (void)fwrite(data + st, i - st + 1, 1, output); - st = i + 1; - newl = FALSE; - } - } - if(!newl) - fprintf(output, "%s%s ", timebuf, s_infotype[type]); - (void)fwrite(data + st, i - st + 1, 1, output); - } - newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; - traced_data = FALSE; - break; - case CURLINFO_TEXT: - case CURLINFO_HEADER_IN: - if(!newl) - fprintf(output, "%s%s ", timebuf, s_infotype[type]); - (void)fwrite(data, size, 1, output); - newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; - traced_data = FALSE; - break; - case CURLINFO_DATA_OUT: - case CURLINFO_DATA_IN: - case CURLINFO_SSL_DATA_IN: - case CURLINFO_SSL_DATA_OUT: - if(!traced_data) { - /* if the data is output to a tty and we're sending this debug trace - to stderr or stdout, we don't display the alert about the data not - being shown as the data _is_ shown then just not via this - function */ - if(!config->isatty || ((output != stderr) && (output != stdout))) { - if(!newl) - fprintf(output, "%s%s ", timebuf, s_infotype[type]); - fprintf(output, "[%zd bytes data]\n", size); - newl = FALSE; - traced_data = TRUE; - } - } - break; - default: /* nada */ - newl = FALSE; - traced_data = FALSE; - break; - } - - return 0; - } - -#ifdef CURL_DOES_CONVERSIONS - /* Special processing is needed for CURLINFO_HEADER_OUT blocks - * if they contain both headers and data (separated by CRLFCRLF). - * We dump the header text and then switch type to CURLINFO_DATA_OUT. - */ - if((type == CURLINFO_HEADER_OUT) && (size > 4)) { - size_t i; - for(i = 0; i < size - 4; i++) { - if(memcmp(&data[i], "\r\n\r\n", 4) == 0) { - /* dump everything through the CRLFCRLF as a sent header */ - text = "=> Send header"; - dump(timebuf, text, output, (unsigned char *)data, i + 4, - config->tracetype, type); - data += i + 3; - size -= i + 4; - type = CURLINFO_DATA_OUT; - data += 1; - break; - } - } - } -#endif /* CURL_DOES_CONVERSIONS */ - - switch(type) { - case CURLINFO_TEXT: - fprintf(output, "%s== Info: %s", timebuf, data); - /* FALLTHROUGH */ - default: /* in case a new one is introduced to shock us */ - return 0; - - case CURLINFO_HEADER_OUT: - text = "=> Send header"; - break; - case CURLINFO_DATA_OUT: - text = "=> Send data"; - break; - case CURLINFO_HEADER_IN: - text = "<= Recv header"; - break; - case CURLINFO_DATA_IN: - text = "<= Recv data"; - break; - case CURLINFO_SSL_DATA_IN: - text = "<= Recv SSL data"; - break; - case CURLINFO_SSL_DATA_OUT: - text = "=> Send SSL data"; - break; - } - - dump(timebuf, text, output, (unsigned char *) data, size, config->tracetype, - type); - return 0; -} - -static void dump(const char *timebuf, const char *text, - FILE *stream, const unsigned char *ptr, size_t size, - trace tracetype, curl_infotype infotype) -{ - size_t i; - size_t c; - - unsigned int width = 0x10; - - if(tracetype == TRACE_ASCII) - /* without the hex output, we can fit more on screen */ - width = 0x40; - - fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size); - - for(i = 0; i < size; i += width) { - - fprintf(stream, "%04zx: ", i); - - if(tracetype == TRACE_BIN) { - /* hex not disabled, show it */ - for(c = 0; c < width; c++) - if(i + c < size) - fprintf(stream, "%02x ", ptr[i + c]); - else - fputs(" ", stream); - } - - for(c = 0; (c < width) && (i + c < size); c++) { - /* check for 0D0A; if found, skip past and start a new line of output */ - if((tracetype == TRACE_ASCII) && - (i + c + 1 < size) && (ptr[i + c] == 0x0D) && - (ptr[i + c + 1] == 0x0A)) { - i += (c + 2 - width); - break; - } -#ifdef CURL_DOES_CONVERSIONS - /* repeat the 0D0A check above but use the host encoding for CRLF */ - if((tracetype == TRACE_ASCII) && - (i + c + 1 < size) && (ptr[i + c] == '\r') && - (ptr[i + c + 1] == '\n')) { - i += (c + 2 - width); - break; - } - /* convert to host encoding and print this character */ - fprintf(stream, "%c", convert_char(infotype, ptr[i + c])); -#else - (void)infotype; - fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80)) ? - ptr[i + c] : UNPRINTABLE_CHAR); -#endif /* CURL_DOES_CONVERSIONS */ - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if((tracetype == TRACE_ASCII) && - (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) && - (ptr[i + c + 2] == 0x0A)) { - i += (c + 3 - width); - break; - } - } - fputc('\n', stream); /* newline */ - } - fflush(stream); -} - diff --git a/dep/cpr/opt/curl/src/tool_cb_dbg.h b/dep/cpr/opt/curl/src/tool_cb_dbg.h deleted file mode 100644 index c1cbc807389..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_dbg.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CB_DBG_H -#define HEADER_CURL_TOOL_CB_DBG_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -/* -** callback for CURLOPT_DEBUGFUNCTION -*/ - -int tool_debug_cb(CURL *handle, curl_infotype type, - char *data, size_t size, - void *userdata); - -#endif /* HEADER_CURL_TOOL_CB_DBG_H */ - diff --git a/dep/cpr/opt/curl/src/tool_cb_hdr.c b/dep/cpr/opt/curl/src/tool_cb_hdr.c deleted file mode 100644 index bb982d2e4f9..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_hdr.c +++ /dev/null @@ -1,239 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include "strcase.h" - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_doswin.h" -#include "tool_msgs.h" -#include "tool_cb_hdr.h" - -#include "memdebug.h" /* keep this as LAST include */ - -static char *parse_filename(const char *ptr, size_t len); - -/* -** callback for CURLOPT_HEADERFUNCTION -*/ - -size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) -{ - struct HdrCbData *hdrcbdata = userdata; - struct OutStruct *outs = hdrcbdata->outs; - struct OutStruct *heads = hdrcbdata->heads; - const char *str = ptr; - const size_t cb = size * nmemb; - const char *end = (char *)ptr + cb; - char *url = NULL; - - /* - * Once that libcurl has called back tool_header_cb() the returned value - * is checked against the amount that was intended to be written, if - * it does not match then it fails with CURLE_WRITE_ERROR. So at this - * point returning a value different from sz*nmemb indicates failure. - */ - size_t failure = (size && nmemb) ? 0 : 1; - - if(!heads->config) - return failure; - -#ifdef DEBUGBUILD - if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { - warnf(heads->config->global, "Header data exceeds single call write " - "limit!\n"); - return failure; - } -#endif - - /* - * Write header data when curl option --dump-header (-D) is given. - */ - - if(heads->config->headerfile && heads->stream) { - size_t rc = fwrite(ptr, size, nmemb, heads->stream); - if(rc != cb) - return rc; - /* flush the stream to send off what we got earlier */ - (void)fflush(heads->stream); - } - - /* - * This callback sets the filename where output shall be written when - * curl options --remote-name (-O) and --remote-header-name (-J) have - * been simultaneously given and additionally server returns an HTTP - * Content-Disposition header specifying a filename property. - */ - - if(hdrcbdata->honor_cd_filename && - (cb > 20) && checkprefix("Content-disposition:", str) && - !curl_easy_getinfo(outs->config->easy, CURLINFO_EFFECTIVE_URL, &url) && - url && (checkprefix("http://", url) || checkprefix("https://", url))) { - const char *p = str + 20; - - /* look for the 'filename=' parameter - (encoded filenames (*=) are not supported) */ - for(;;) { - char *filename; - size_t len; - - while(*p && (p < end) && !ISALPHA(*p)) - p++; - if(p > end - 9) - break; - - if(memcmp(p, "filename=", 9)) { - /* no match, find next parameter */ - while((p < end) && (*p != ';')) - p++; - continue; - } - p += 9; - - /* this expression below typecasts 'cb' only to avoid - warning: signed and unsigned type in conditional expression - */ - len = (ssize_t)cb - (p - str); - filename = parse_filename(p, len); - if(filename) { - outs->filename = filename; - outs->alloc_filename = TRUE; - outs->is_cd_filename = TRUE; - outs->s_isreg = TRUE; - outs->fopened = FALSE; - outs->stream = NULL; - hdrcbdata->honor_cd_filename = FALSE; - break; - } - return failure; - } - } - - return cb; -} - -/* - * Copies a file name part and returns an ALLOCATED data buffer. - */ -static char *parse_filename(const char *ptr, size_t len) -{ - char *copy; - char *p; - char *q; - char stop = '\0'; - - /* simple implementation of strndup() */ - copy = malloc(len + 1); - if(!copy) - return NULL; - memcpy(copy, ptr, len); - copy[len] = '\0'; - - p = copy; - if(*p == '\'' || *p == '"') { - /* store the starting quote */ - stop = *p; - p++; - } - else - stop = ';'; - - /* if the filename contains a path, only use filename portion */ - q = strrchr(copy, '/'); - if(q) { - p = q + 1; - if(!*p) { - Curl_safefree(copy); - return NULL; - } - } - - /* If the filename contains a backslash, only use filename portion. The idea - is that even systems that don't handle backslashes as path separators - probably want the path removed for convenience. */ - q = strrchr(p, '\\'); - if(q) { - p = q + 1; - if(!*p) { - Curl_safefree(copy); - return NULL; - } - } - - /* scan for the end letter and stop there */ - for(q = p; *q; ++q) { - if(*q == stop) { - *q = '\0'; - break; - } - } - - /* make sure the file name doesn't end in \r or \n */ - q = strchr(p, '\r'); - if(q) - *q = '\0'; - - q = strchr(p, '\n'); - if(q) - *q = '\0'; - - if(copy != p) - memmove(copy, p, strlen(p) + 1); - -#if defined(MSDOS) || defined(WIN32) - { - char *sanitized; - SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0); - Curl_safefree(copy); - if(sc) - return NULL; - copy = sanitized; - } -#endif /* MSDOS || WIN32 */ - - /* in case we built debug enabled, we allow an environment variable - * named CURL_TESTDIR to prefix the given file name to put it into a - * specific directory - */ -#ifdef DEBUGBUILD - { - char *tdir = curlx_getenv("CURL_TESTDIR"); - if(tdir) { - char buffer[512]; /* suitably large */ - snprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy); - Curl_safefree(copy); - copy = strdup(buffer); /* clone the buffer, we don't use the libcurl - aprintf() or similar since we want to use the - same memory code as the "real" parse_filename - function */ - curl_free(tdir); - } - } -#endif - - return copy; -} - diff --git a/dep/cpr/opt/curl/src/tool_cb_hdr.h b/dep/cpr/opt/curl/src/tool_cb_hdr.h deleted file mode 100644 index 32032e98098..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_hdr.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CB_HDR_H -#define HEADER_CURL_TOOL_CB_HDR_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -/* - * curl operates using a single HdrCbData struct variable, a - * pointer to this is passed as userdata pointer to tool_header_cb. - * - * 'outs' member is a pointer to the OutStruct variable used to keep - * track of information relative to curl's output writing. - * - * 'heads' member is a pointer to the OutStruct variable used to keep - * track of information relative to header response writing. - * - * 'honor_cd_filename' member is TRUE when tool_header_cb is allowed - * to honor Content-Disposition filename property and accordingly - * set 'outs' filename, otherwise FALSE; - */ - -struct HdrCbData { - struct OutStruct *outs; - struct OutStruct *heads; - bool honor_cd_filename; -}; - -/* -** callback for CURLOPT_HEADERFUNCTION -*/ - -size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata); - -#endif /* HEADER_CURL_TOOL_CB_HDR_H */ - diff --git a/dep/cpr/opt/curl/src/tool_cb_prg.c b/dep/cpr/opt/curl/src/tool_cb_prg.c deleted file mode 100644 index 992b96d97a6..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_prg.c +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_cb_prg.h" -#include "tool_util.h" - -#include "memdebug.h" /* keep this as LAST include */ - -/* -** callback for CURLOPT_XFERINFOFUNCTION -*/ - -#define MAX_BARLENGTH 256 - -int tool_progress_cb(void *clientp, - curl_off_t dltotal, curl_off_t dlnow, - curl_off_t ultotal, curl_off_t ulnow) -{ - /* The original progress-bar source code was written for curl by Lars Aas, - and this new edition inherits some of his concepts. */ - - char line[MAX_BARLENGTH + 1]; - char format[40]; - double frac; - double percent; - int barwidth; - int num; - struct timeval now = tvnow(); - struct ProgressData *bar = (struct ProgressData *)clientp; - curl_off_t total; - curl_off_t point; - - /* expected transfer size */ - total = dltotal + ultotal + bar->initial_size; - - /* we've come this far */ - point = dlnow + ulnow + bar->initial_size; - - if(bar->calls && (tvdiff(now, bar->prevtime) < 100L) && point < total) - /* after first call, limit progress-bar updating to 10 Hz */ - /* update when we're at 100% even if last update is less than 200ms ago */ - return 0; - - if(point > total) - /* we have got more than the expected total! */ - total = point; - - /* simply count invokes */ - bar->calls++; - - if(total < 1) { - curl_off_t prevblock = bar->prev / 1024; - curl_off_t thisblock = point / 1024; - while(thisblock > prevblock) { - fprintf(bar->out, "#"); - prevblock++; - } - } - else if(point != bar->prev) { - frac = (double)point / (double)total; - percent = frac * 100.0; - barwidth = bar->width - 7; - num = (int) (((double)barwidth) * frac); - if(num > MAX_BARLENGTH) - num = MAX_BARLENGTH; - memset(line, '#', num); - line[num] = '\0'; - snprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth); - fprintf(bar->out, format, line, percent); - } - fflush(bar->out); - bar->prev = point; - bar->prevtime = now; - - return 0; -} - -void progressbarinit(struct ProgressData *bar, - struct OperationConfig *config) -{ -#ifdef __EMX__ - /* 20000318 mgs */ - int scr_size[2]; -#endif - char *colp; - - memset(bar, 0, sizeof(struct ProgressData)); - - /* pass this through to progress function so - * it can display progress towards total file - * not just the part that's left. (21-may-03, dbyron) */ - if(config->use_resume) - bar->initial_size = config->resume_from; - -/* TODO: get terminal width through ansi escapes or something similar. - try to update width when xterm is resized... - 19990617 larsa */ -#ifndef __EMX__ - /* 20000318 mgs - * OS/2 users most likely won't have this env var set, and besides that - * we're using our own way to determine screen width */ - colp = curlx_getenv("COLUMNS"); - if(colp) { - char *endptr; - long num = strtol(colp, &endptr, 10); - if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 0)) - bar->width = (int)num; - else - bar->width = 79; - curl_free(colp); - } - else - bar->width = 79; -#else - /* 20000318 mgs - * We use this emx library call to get the screen width, and subtract - * one from what we got in order to avoid a problem with the cursor - * advancing to the next line if we print a string that is as long as - * the screen is wide. */ - - _scrsize(scr_size); - bar->width = scr_size[0] - 1; -#endif - - bar->out = config->global->errors; -} diff --git a/dep/cpr/opt/curl/src/tool_cb_prg.h b/dep/cpr/opt/curl/src/tool_cb_prg.h deleted file mode 100644 index d62b4a073c2..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_prg.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CB_PRG_H -#define HEADER_CURL_TOOL_CB_PRG_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#define CURL_PROGRESS_STATS 0 /* default progress display */ -#define CURL_PROGRESS_BAR 1 - -struct ProgressData { - int calls; - curl_off_t prev; - struct timeval prevtime; - int width; - FILE *out; /* where to write everything to */ - curl_off_t initial_size; -}; - -void progressbarinit(struct ProgressData *bar, - struct OperationConfig *config); - -/* -** callback for CURLOPT_PROGRESSFUNCTION -*/ - -int tool_progress_cb(void *clientp, - curl_off_t dltotal, curl_off_t dlnow, - curl_off_t ultotal, curl_off_t ulnow); - -#endif /* HEADER_CURL_TOOL_CB_PRG_H */ - diff --git a/dep/cpr/opt/curl/src/tool_cb_rea.c b/dep/cpr/opt/curl/src/tool_cb_rea.c deleted file mode 100644 index 88137ae74ae..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_rea.c +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_cb_rea.h" - -#include "memdebug.h" /* keep this as LAST include */ - -/* -** callback for CURLOPT_READFUNCTION -*/ - -size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata) -{ - ssize_t rc; - struct InStruct *in = userdata; - - rc = read(in->fd, buffer, sz*nmemb); - if(rc < 0) { - if(errno == EAGAIN) { - errno = 0; - in->config->readbusy = TRUE; - return CURL_READFUNC_PAUSE; - } - /* since size_t is unsigned we can't return negative values fine */ - rc = 0; - } - in->config->readbusy = FALSE; - return (size_t)rc; -} - diff --git a/dep/cpr/opt/curl/src/tool_cb_rea.h b/dep/cpr/opt/curl/src/tool_cb_rea.h deleted file mode 100644 index 5fbc793f6ca..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_rea.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CB_REA_H -#define HEADER_CURL_TOOL_CB_REA_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -/* -** callback for CURLOPT_READFUNCTION -*/ - -size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata); - -#endif /* HEADER_CURL_TOOL_CB_REA_H */ - diff --git a/dep/cpr/opt/curl/src/tool_cb_see.c b/dep/cpr/opt/curl/src/tool_cb_see.c deleted file mode 100644 index 621d440f4f9..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_see.c +++ /dev/null @@ -1,131 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_cb_see.h" - -#include "memdebug.h" /* keep this as LAST include */ - -/* OUR_MAX_SEEK_L has 'long' data type, OUR_MAX_SEEK_O has 'curl_off_t, - both represent the same value. Maximum offset used here when we lseek - using a 'long' data type offset */ - -#define OUR_MAX_SEEK_L 2147483647L - 1L -#define OUR_MAX_SEEK_O CURL_OFF_T_C(0x7FFFFFFF) - CURL_OFF_T_C(0x1) - -/* -** callback for CURLOPT_SEEKFUNCTION -** -** Notice that this is not supposed to return the resulting offset. This -** shall only return CURL_SEEKFUNC_* return codes. -*/ - -int tool_seek_cb(void *userdata, curl_off_t offset, int whence) -{ - struct InStruct *in = userdata; - -#if(CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES) - - /* The offset check following here is only interesting if curl_off_t is - larger than off_t and we are not using the WIN32 large file support - macros that provide the support to do 64bit seeks correctly */ - - if(offset > OUR_MAX_SEEK_O) { - /* Some precaution code to work around problems with different data sizes - to allow seeking >32bit even if off_t is 32bit. Should be very rare and - is really valid on weirdo-systems. */ - curl_off_t left = offset; - - if(whence != SEEK_SET) - /* this code path doesn't support other types */ - return CURL_SEEKFUNC_FAIL; - - if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET)) - /* couldn't rewind to beginning */ - return CURL_SEEKFUNC_FAIL; - - while(left) { - long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left; - if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR)) - /* couldn't seek forwards the desired amount */ - return CURL_SEEKFUNC_FAIL; - left -= step; - } - return CURL_SEEKFUNC_OK; - } -#endif - - if(LSEEK_ERROR == lseek(in->fd, offset, whence)) - /* couldn't rewind, the reason is in errno but errno is just not portable - enough and we don't actually care that much why we failed. We'll let - libcurl know that it may try other means if it wants to. */ - return CURL_SEEKFUNC_CANTSEEK; - - return CURL_SEEKFUNC_OK; -} - -#if defined(WIN32) && !defined(__MINGW64__) - -#ifdef __BORLANDC__ -/* 64-bit lseek-like function unavailable */ -# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) -#endif - -#ifdef __POCC__ -# if(__POCC__ < 450) -/* 64-bit lseek-like function unavailable */ -# define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence) -# else -# define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence) -# endif -#endif - -#ifdef _WIN32_WCE -/* 64-bit lseek-like function unavailable */ -# undef _lseeki64 -# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) -# undef _get_osfhandle -# define _get_osfhandle(fd) (fd) -#endif - -/* - * Truncate a file handle at a 64-bit position 'where'. - */ - -int tool_ftruncate64(int fd, curl_off_t where) -{ - if(_lseeki64(fd, where, SEEK_SET) < 0) - return -1; - - if(!SetEndOfFile((HANDLE)_get_osfhandle(fd))) - return -1; - - return 0; -} - -#endif /* WIN32 && ! __MINGW64__ */ - diff --git a/dep/cpr/opt/curl/src/tool_cb_see.h b/dep/cpr/opt/curl/src/tool_cb_see.h deleted file mode 100644 index b07741da694..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_see.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CB_SEE_H -#define HEADER_CURL_TOOL_CB_SEE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#if defined(WIN32) && !defined(__MINGW64__) - -int tool_ftruncate64(int fd, curl_off_t where); - -#undef ftruncate -#define ftruncate(fd,where) tool_ftruncate64(fd,where) - -#ifndef HAVE_FTRUNCATE -# define HAVE_FTRUNCATE 1 -#endif - -#endif /* WIN32 && ! __MINGW64__ */ - -/* -** callback for CURLOPT_SEEKFUNCTION -*/ - -int tool_seek_cb(void *userdata, curl_off_t offset, int whence); - -#endif /* HEADER_CURL_TOOL_CB_SEE_H */ - diff --git a/dep/cpr/opt/curl/src/tool_cb_wrt.c b/dep/cpr/opt/curl/src/tool_cb_wrt.c deleted file mode 100644 index 6716ba5cdba..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_wrt.c +++ /dev/null @@ -1,177 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_msgs.h" -#include "tool_cb_wrt.h" - -#include "memdebug.h" /* keep this as LAST include */ - -/* create a local file for writing, return TRUE on success */ -bool tool_create_output_file(struct OutStruct *outs) -{ - struct GlobalConfig *global = outs->config->global; - FILE *file; - - if(!outs->filename || !*outs->filename) { - warnf(global, "Remote filename has no length!\n"); - return FALSE; - } - - if(outs->is_cd_filename) { - /* don't overwrite existing files */ - file = fopen(outs->filename, "rb"); - if(file) { - fclose(file); - warnf(global, "Refusing to overwrite %s: %s\n", outs->filename, - strerror(EEXIST)); - return FALSE; - } - } - - /* open file for writing */ - file = fopen(outs->filename, "wb"); - if(!file) { - warnf(global, "Failed to create the file %s: %s\n", outs->filename, - strerror(errno)); - return FALSE; - } - outs->s_isreg = TRUE; - outs->fopened = TRUE; - outs->stream = file; - outs->bytes = 0; - outs->init = 0; - return TRUE; -} - -/* -** callback for CURLOPT_WRITEFUNCTION -*/ - -size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) -{ - size_t rc; - struct OutStruct *outs = userdata; - struct OperationConfig *config = outs->config; - size_t bytes = sz * nmemb; - bool is_tty = config->global->isatty; - - /* - * Once that libcurl has called back tool_write_cb() the returned value - * is checked against the amount that was intended to be written, if - * it does not match then it fails with CURLE_WRITE_ERROR. So at this - * point returning a value different from sz*nmemb indicates failure. - */ - const size_t failure = bytes ? 0 : 1; - -#ifdef DEBUGBUILD - { - char *tty = curlx_getenv("CURL_ISATTY"); - if(tty) { - is_tty = TRUE; - curl_free(tty); - } - } - - if(config->include_headers) { - if(bytes > (size_t)CURL_MAX_HTTP_HEADER) { - warnf(config->global, "Header data size exceeds single call write " - "limit!\n"); - return failure; - } - } - else { - if(bytes > (size_t)CURL_MAX_WRITE_SIZE) { - warnf(config->global, "Data size exceeds single call write limit!\n"); - return failure; - } - } - - { - /* Some internal congruency checks on received OutStruct */ - bool check_fails = FALSE; - if(outs->filename) { - /* regular file */ - if(!*outs->filename) - check_fails = TRUE; - if(!outs->s_isreg) - check_fails = TRUE; - if(outs->fopened && !outs->stream) - check_fails = TRUE; - if(!outs->fopened && outs->stream) - check_fails = TRUE; - if(!outs->fopened && outs->bytes) - check_fails = TRUE; - } - else { - /* standard stream */ - if(!outs->stream || outs->s_isreg || outs->fopened) - check_fails = TRUE; - if(outs->alloc_filename || outs->is_cd_filename || outs->init) - check_fails = TRUE; - } - if(check_fails) { - warnf(config->global, "Invalid output struct data for write callback\n"); - return failure; - } - } -#endif - - if(!outs->stream && !tool_create_output_file(outs)) - return failure; - - if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) { - /* binary output to terminal? */ - if(memchr(buffer, 0, bytes)) { - warnf(config->global, "Binary output can mess up your terminal. " - "Use \"--output -\" to tell curl to output it to your terminal " - "anyway, or consider \"--output \" to save to a file.\n"); - config->synthetic_error = ERR_BINARY_TERMINAL; - return failure; - } - } - - rc = fwrite(buffer, sz, nmemb, outs->stream); - - if(bytes == rc) - /* we added this amount of data to the output */ - outs->bytes += bytes; - - if(config->readbusy) { - config->readbusy = FALSE; - curl_easy_pause(config->easy, CURLPAUSE_CONT); - } - - if(config->nobuffer) { - /* output buffering disabled */ - int res = fflush(outs->stream); - if(res) - return failure; - } - - return rc; -} diff --git a/dep/cpr/opt/curl/src/tool_cb_wrt.h b/dep/cpr/opt/curl/src/tool_cb_wrt.h deleted file mode 100644 index 4ccbf3a5f19..00000000000 --- a/dep/cpr/opt/curl/src/tool_cb_wrt.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CB_WRT_H -#define HEADER_CURL_TOOL_CB_WRT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -/* -** callback for CURLOPT_WRITEFUNCTION -*/ - -size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata); - -/* create a local file for writing, return TRUE on success */ -bool tool_create_output_file(struct OutStruct *outs); - -#endif /* HEADER_CURL_TOOL_CB_WRT_H */ - diff --git a/dep/cpr/opt/curl/src/tool_cfgable.c b/dep/cpr/opt/curl/src/tool_cfgable.c deleted file mode 100644 index 755195cedfb..00000000000 --- a/dep/cpr/opt/curl/src/tool_cfgable.c +++ /dev/null @@ -1,174 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include "tool_cfgable.h" -#include "tool_main.h" - -#include "memdebug.h" /* keep this as LAST include */ - -void config_init(struct OperationConfig* config) -{ - memset(config, 0, sizeof(struct OperationConfig)); - - config->postfieldsize = -1; - config->use_httpget = FALSE; - config->create_dirs = FALSE; - config->maxredirs = DEFAULT_MAXREDIRS; - config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */ - config->proto_present = FALSE; - config->proto_redir = CURLPROTO_ALL & /* All except FILE, SCP and SMB */ - ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB | - CURLPROTO_SMBS); - config->proto_redir_present = FALSE; - config->proto_default = NULL; - config->tcp_nodelay = TRUE; /* enabled by default */ -} - -static void free_config_fields(struct OperationConfig *config) -{ - struct getout *urlnode; - - Curl_safefree(config->random_file); - Curl_safefree(config->egd_file); - Curl_safefree(config->useragent); - Curl_safefree(config->cookie); - Curl_safefree(config->cookiejar); - Curl_safefree(config->cookiefile); - - Curl_safefree(config->postfields); - Curl_safefree(config->referer); - - Curl_safefree(config->headerfile); - Curl_safefree(config->ftpport); - Curl_safefree(config->iface); - - Curl_safefree(config->range); - - Curl_safefree(config->userpwd); - Curl_safefree(config->tls_username); - Curl_safefree(config->tls_password); - Curl_safefree(config->tls_authtype); - Curl_safefree(config->proxy_tls_username); - Curl_safefree(config->proxy_tls_password); - Curl_safefree(config->proxy_tls_authtype); - Curl_safefree(config->proxyuserpwd); - Curl_safefree(config->proxy); - - Curl_safefree(config->dns_ipv6_addr); - Curl_safefree(config->dns_ipv4_addr); - Curl_safefree(config->dns_interface); - Curl_safefree(config->dns_servers); - - Curl_safefree(config->noproxy); - - Curl_safefree(config->mail_from); - curl_slist_free_all(config->mail_rcpt); - Curl_safefree(config->mail_auth); - - Curl_safefree(config->netrc_file); - - urlnode = config->url_list; - while(urlnode) { - struct getout *next = urlnode->next; - Curl_safefree(urlnode->url); - Curl_safefree(urlnode->outfile); - Curl_safefree(urlnode->infile); - Curl_safefree(urlnode); - urlnode = next; - } - config->url_list = NULL; - config->url_last = NULL; - config->url_get = NULL; - config->url_out = NULL; - - Curl_safefree(config->cipher_list); - Curl_safefree(config->proxy_cipher_list); - Curl_safefree(config->cert); - Curl_safefree(config->proxy_cert); - Curl_safefree(config->cert_type); - Curl_safefree(config->proxy_cert_type); - Curl_safefree(config->cacert); - Curl_safefree(config->proxy_cacert); - Curl_safefree(config->capath); - Curl_safefree(config->proxy_capath); - Curl_safefree(config->crlfile); - Curl_safefree(config->pinnedpubkey); - Curl_safefree(config->proxy_crlfile); - Curl_safefree(config->key); - Curl_safefree(config->proxy_key); - Curl_safefree(config->key_type); - Curl_safefree(config->proxy_key_type); - Curl_safefree(config->key_passwd); - Curl_safefree(config->proxy_key_passwd); - Curl_safefree(config->pubkey); - Curl_safefree(config->hostpubmd5); - Curl_safefree(config->engine); - Curl_safefree(config->request_target); - Curl_safefree(config->customrequest); - Curl_safefree(config->krblevel); - - Curl_safefree(config->oauth_bearer); - - Curl_safefree(config->unix_socket_path); - Curl_safefree(config->writeout); - Curl_safefree(config->proto_default); - - curl_slist_free_all(config->quote); - curl_slist_free_all(config->postquote); - curl_slist_free_all(config->prequote); - - curl_slist_free_all(config->headers); - curl_slist_free_all(config->proxyheaders); - - if(config->mimepost) { - curl_mime_free(config->mimepost); - config->mimepost = NULL; - } - config->mimecurrent = NULL; - - curl_slist_free_all(config->telnet_options); - curl_slist_free_all(config->resolve); - curl_slist_free_all(config->connect_to); - - Curl_safefree(config->preproxy); - Curl_safefree(config->proxy_service_name); - Curl_safefree(config->service_name); - - Curl_safefree(config->ftp_account); - Curl_safefree(config->ftp_alternative_to_user); -} - -void config_free(struct OperationConfig *config) -{ - struct OperationConfig *last = config; - - /* Free each of the structures in reverse order */ - while(last) { - struct OperationConfig *prev = last->prev; - - free_config_fields(last); - free(last); - - last = prev; - } -} diff --git a/dep/cpr/opt/curl/src/tool_cfgable.h b/dep/cpr/opt/curl/src/tool_cfgable.h deleted file mode 100644 index 23943fe7b63..00000000000 --- a/dep/cpr/opt/curl/src/tool_cfgable.h +++ /dev/null @@ -1,282 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CFGABLE_H -#define HEADER_CURL_TOOL_CFGABLE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include "tool_sdecls.h" - -#include "tool_metalink.h" - -typedef enum { - ERR_NONE, - ERR_BINARY_TERMINAL = 1, /* binary to terminal detected */ - ERR_LAST -} curl_error; - -struct GlobalConfig; - -struct OperationConfig { - CURL *easy; /* A copy of the handle from GlobalConfig */ - bool remote_time; - char *random_file; - char *egd_file; - char *useragent; - char *cookie; /* single line with specified cookies */ - char *cookiejar; /* write to this file */ - char *cookiefile; /* read from this file */ - bool cookiesession; /* new session? */ - bool encoding; /* Accept-Encoding please */ - bool tr_encoding; /* Transfer-Encoding please */ - unsigned long authtype; /* auth bitmask */ - bool use_resume; - bool resume_from_current; - bool disable_epsv; - bool disable_eprt; - bool ftp_pret; - long proto; - bool proto_present; - long proto_redir; - bool proto_redir_present; - char *proto_default; - curl_off_t resume_from; - char *postfields; - curl_off_t postfieldsize; - char *referer; - double timeout; - double connecttimeout; - long maxredirs; - curl_off_t max_filesize; - char *headerfile; - char *ftpport; - char *iface; - int localport; - int localportrange; - unsigned short porttouse; - char *range; - long low_speed_limit; - long low_speed_time; - char *dns_servers; /* dot notation: 1.1.1.1;2.2.2.2 */ - char *dns_interface; /* interface name */ - char *dns_ipv4_addr; /* dot notation */ - char *dns_ipv6_addr; /* dot notation */ - char *userpwd; - char *login_options; - char *tls_username; - char *tls_password; - char *tls_authtype; - char *proxy_tls_username; - char *proxy_tls_password; - char *proxy_tls_authtype; - char *proxyuserpwd; - char *proxy; - int proxyver; /* set to CURLPROXY_HTTP* define */ - char *noproxy; - char *mail_from; - struct curl_slist *mail_rcpt; - char *mail_auth; - bool sasl_ir; /* Enable/disable SASL initial response */ - bool proxytunnel; - bool ftp_append; /* APPE on ftp */ - bool use_ascii; /* select ascii or text transfer */ - bool autoreferer; /* automatically set referer */ - bool failonerror; /* fail on (HTTP) errors */ - bool include_headers; /* send headers to data output */ - bool no_body; /* don't get the body */ - bool dirlistonly; /* only get the FTP dir list */ - bool followlocation; /* follow http redirects */ - bool unrestricted_auth; /* Continue to send authentication (user+password) - when following ocations, even when hostname - changed */ - bool netrc_opt; - bool netrc; - char *netrc_file; - struct getout *url_list; /* point to the first node */ - struct getout *url_last; /* point to the last/current node */ - struct getout *url_get; /* point to the node to fill in URL */ - struct getout *url_out; /* point to the node to fill in outfile */ - char *cipher_list; - char *proxy_cipher_list; - char *cert; - char *proxy_cert; - char *cert_type; - char *proxy_cert_type; - char *cacert; - char *proxy_cacert; - char *capath; - char *proxy_capath; - char *crlfile; - char *proxy_crlfile; - char *pinnedpubkey; - char *key; - char *proxy_key; - char *key_type; - char *proxy_key_type; - char *key_passwd; - char *proxy_key_passwd; - char *pubkey; - char *hostpubmd5; - char *engine; - bool crlf; - char *customrequest; - char *krblevel; - char *request_target; - long httpversion; - bool nobuffer; - bool readbusy; /* set when reading input returns EAGAIN */ - bool globoff; - bool use_httpget; - bool insecure_ok; /* set TRUE to allow insecure SSL connects */ - bool proxy_insecure_ok; /* set TRUE to allow insecure SSL connects - for proxy */ - bool terminal_binary_ok; - bool verifystatus; - bool create_dirs; - bool ftp_create_dirs; - bool ftp_skip_ip; - bool proxynegotiate; - bool proxyntlm; - bool proxydigest; - bool proxybasic; - bool proxyanyauth; - char *writeout; /* %-styled format string to output */ - struct curl_slist *quote; - struct curl_slist *postquote; - struct curl_slist *prequote; - long ssl_version; - long ssl_version_max; - long proxy_ssl_version; - long ip_version; - curl_TimeCond timecond; - time_t condtime; - struct curl_slist *headers; - struct curl_slist *proxyheaders; - curl_mime *mimepost; - curl_mime *mimecurrent; - struct curl_slist *telnet_options; - struct curl_slist *resolve; - struct curl_slist *connect_to; - HttpReq httpreq; - - /* for bandwidth limiting features: */ - curl_off_t sendpersecond; /* send to peer */ - curl_off_t recvpersecond; /* receive from peer */ - - bool ftp_ssl; - bool ftp_ssl_reqd; - bool ftp_ssl_control; - bool ftp_ssl_ccc; - int ftp_ssl_ccc_mode; - char *preproxy; - int socks5_gssapi_nec; /* The NEC reference server does not protect the - encryption type exchange */ - unsigned long socks5_auth;/* auth bitmask for socks5 proxies */ - char *proxy_service_name; /* set authentication service name for HTTP and - SOCKS5 proxies */ - char *service_name; /* set authentication service name for DIGEST-MD5, - Kerberos 5 and SPNEGO */ - - bool tcp_nodelay; - bool tcp_fastopen; - long req_retry; /* number of retries */ - bool retry_connrefused; /* set connection refused as a transient error */ - long retry_delay; /* delay between retries (in seconds) */ - long retry_maxtime; /* maximum time to keep retrying */ - - char *ftp_account; /* for ACCT */ - char *ftp_alternative_to_user; /* send command if USER/PASS fails */ - int ftp_filemethod; - long tftp_blksize; /* TFTP BLKSIZE option */ - bool tftp_no_options; /* do not send TFTP options requests */ - bool ignorecl; /* --ignore-content-length */ - bool disable_sessionid; - - bool raw; - bool post301; - bool post302; - bool post303; - bool nokeepalive; /* for keepalive needs */ - long alivetime; - bool content_disposition; /* use Content-disposition filename */ - - int default_node_flags; /* default flags to search for each 'node', which - is basically each given URL to transfer */ - - bool xattr; /* store metadata in extended attributes */ - long gssapi_delegation; - bool ssl_allow_beast; /* allow this SSL vulnerability */ - bool proxy_ssl_allow_beast; /* allow this SSL vulnerability for proxy*/ - - bool ssl_no_revoke; /* disable SSL certificate revocation checks */ - /*bool proxy_ssl_no_revoke; */ - - bool use_metalink; /* process given URLs as metalink XML file */ - metalinkfile *metalinkfile_list; /* point to the first node */ - metalinkfile *metalinkfile_last; /* point to the last/current node */ -#ifdef CURLDEBUG - bool test_event_based; -#endif - char *oauth_bearer; /* OAuth 2.0 bearer token */ - bool nonpn; /* enable/disable TLS NPN extension */ - bool noalpn; /* enable/disable TLS ALPN extension */ - char *unix_socket_path; /* path to Unix domain socket */ - bool abstract_unix_socket; /* path to an abstract Unix domain socket */ - bool falsestart; - bool path_as_is; - double expect100timeout; - bool suppress_connect_headers; /* suppress proxy CONNECT response headers - from user callbacks */ - curl_error synthetic_error; /* if non-zero, it overrides any libcurl - error */ - bool ssh_compression; /* enable/disable SSH compression */ - struct GlobalConfig *global; - struct OperationConfig *prev; - struct OperationConfig *next; /* Always last in the struct */ -}; - -struct GlobalConfig { - CURL *easy; /* Once we have one, we keep it here */ - int showerror; /* -1 == unset, default => show errors - 0 => -s is used to NOT show errors - 1 => -S has been used to show errors */ - bool mute; /* don't show messages, --silent given */ - bool noprogress; /* don't show progress bar --silent given */ - bool isatty; /* Updated internally if output is a tty */ - FILE *errors; /* Error stream, defaults to stderr */ - bool errors_fopened; /* Whether error stream isn't stderr */ - char *trace_dump; /* file to dump the network trace to */ - FILE *trace_stream; - bool trace_fopened; - trace tracetype; - bool tracetime; /* include timestamp? */ - int progressmode; /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */ - char *libcurl; /* Output libcurl code to this file name */ - bool fail_early; /* exit on first transfer error */ - struct OperationConfig *first; - struct OperationConfig *current; - struct OperationConfig *last; /* Always last in the struct */ -}; - -void config_init(struct OperationConfig *config); -void config_free(struct OperationConfig *config); - -#endif /* HEADER_CURL_TOOL_CFGABLE_H */ diff --git a/dep/cpr/opt/curl/src/tool_convert.c b/dep/cpr/opt/curl/src/tool_convert.c deleted file mode 100644 index d0f5dcb0044..00000000000 --- a/dep/cpr/opt/curl/src/tool_convert.c +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#ifdef CURL_DOES_CONVERSIONS - -#ifdef HAVE_ICONV -# include -#endif - -#include "tool_convert.h" - -#include "memdebug.h" /* keep this as LAST include */ - -#ifdef HAVE_ICONV - -/* curl tool iconv conversion descriptors */ -static iconv_t inbound_cd = (iconv_t)-1; -static iconv_t outbound_cd = (iconv_t)-1; - -/* set default codesets for iconv */ -#ifndef CURL_ICONV_CODESET_OF_NETWORK -# define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" -#endif - -/* - * convert_to_network() is a curl tool function to convert - * from the host encoding to ASCII on non-ASCII platforms. - */ -CURLcode convert_to_network(char *buffer, size_t length) -{ - /* translate from the host encoding to the network encoding */ - char *input_ptr, *output_ptr; - size_t res, in_bytes, out_bytes; - - /* open an iconv conversion descriptor if necessary */ - if(outbound_cd == (iconv_t)-1) { - outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - if(outbound_cd == (iconv_t)-1) { - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - res = iconv(outbound_cd, &input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if((res == (size_t)-1) || (in_bytes != 0)) { - return CURLE_CONV_FAILED; - } - - return CURLE_OK; -} - -/* - * convert_from_network() is a curl tool function - * for performing ASCII conversions on non-ASCII platforms. - */ -CURLcode convert_from_network(char *buffer, size_t length) -{ - /* translate from the network encoding to the host encoding */ - char *input_ptr, *output_ptr; - size_t res, in_bytes, out_bytes; - - /* open an iconv conversion descriptor if necessary */ - if(inbound_cd == (iconv_t)-1) { - inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - if(inbound_cd == (iconv_t)-1) { - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - res = iconv(inbound_cd, &input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if((res == (size_t)-1) || (in_bytes != 0)) { - return CURLE_CONV_FAILED; - } - - return CURLE_OK; -} - -void convert_cleanup(void) -{ - /* close iconv conversion descriptors */ - if(inbound_cd != (iconv_t)-1) - (void)iconv_close(inbound_cd); - if(outbound_cd != (iconv_t)-1) - (void)iconv_close(outbound_cd); -} - -#endif /* HAVE_ICONV */ - -char convert_char(curl_infotype infotype, char this_char) -{ -/* determine how this specific character should be displayed */ - switch(infotype) { - case CURLINFO_DATA_IN: - case CURLINFO_DATA_OUT: - case CURLINFO_SSL_DATA_IN: - case CURLINFO_SSL_DATA_OUT: - /* data, treat as ASCII */ - if((this_char >= 0x20) && (this_char < 0x7f)) { - /* printable ASCII hex value: convert to host encoding */ - (void)convert_from_network(&this_char, 1); - } - else { - /* non-printable ASCII, use a replacement character */ - return UNPRINTABLE_CHAR; - } - /* fall through to default */ - default: - /* treat as host encoding */ - if(ISPRINT(this_char) - && (this_char != '\t') - && (this_char != '\r') - && (this_char != '\n')) { - /* printable characters excluding tabs and line end characters */ - return this_char; - } - break; - } - /* non-printable, use a replacement character */ - return UNPRINTABLE_CHAR; -} - -#endif /* CURL_DOES_CONVERSIONS */ - diff --git a/dep/cpr/opt/curl/src/tool_convert.h b/dep/cpr/opt/curl/src/tool_convert.h deleted file mode 100644 index d1b1d23273b..00000000000 --- a/dep/cpr/opt/curl/src/tool_convert.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CONVERT_H -#define HEADER_CURL_TOOL_CONVERT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#ifdef CURL_DOES_CONVERSIONS - -#ifdef HAVE_ICONV - -CURLcode convert_to_network(char *buffer, size_t length); -CURLcode convert_from_network(char *buffer, size_t length); -void convert_cleanup(void); - -#endif /* HAVE_ICONV */ - -char convert_char(curl_infotype infotype, char this_char); - -#endif /* CURL_DOES_CONVERSIONS */ - -#if !defined(CURL_DOES_CONVERSIONS) || !defined(HAVE_ICONV) -#define convert_cleanup() Curl_nop_stmt -#endif - -#endif /* HEADER_CURL_TOOL_CONVERT_H */ - diff --git a/dep/cpr/opt/curl/src/tool_dirhie.c b/dep/cpr/opt/curl/src/tool_dirhie.c deleted file mode 100644 index 1d735920502..00000000000 --- a/dep/cpr/opt/curl/src/tool_dirhie.c +++ /dev/null @@ -1,158 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include - -#ifdef WIN32 -# include -#endif - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_dirhie.h" - -#include "memdebug.h" /* keep this as LAST include */ - -#ifdef NETWARE -# ifndef __NOVELL_LIBC__ -# define mkdir mkdir_510 -# endif -#endif - -#ifdef WIN32 -# define mkdir(x,y) (mkdir)((x)) -# ifndef __POCC__ -# define F_OK 0 -# endif -#endif - -static void show_dir_errno(FILE *errors, const char *name) -{ - switch(errno) { -#ifdef EACCES - case EACCES: - fprintf(errors, "You don't have permission to create %s.\n", name); - break; -#endif -#ifdef ENAMETOOLONG - case ENAMETOOLONG: - fprintf(errors, "The directory name %s is too long.\n", name); - break; -#endif -#ifdef EROFS - case EROFS: - fprintf(errors, "%s resides on a read-only file system.\n", name); - break; -#endif -#ifdef ENOSPC - case ENOSPC: - fprintf(errors, "No space left on the file system that will " - "contain the directory %s.\n", name); - break; -#endif -#ifdef EDQUOT - case EDQUOT: - fprintf(errors, "Cannot create directory %s because you " - "exceeded your quota.\n", name); - break; -#endif - default : - fprintf(errors, "Error creating directory %s.\n", name); - break; - } -} - -/* - * Create the needed directory hierarchy recursively in order to save - * multi-GETs in file output, ie: - * curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt" - * should create all the dir* automagically - */ - -#ifdef WIN32 -/* systems that may use either or when specifying a path */ -#define PATH_DELIMITERS "\\/" -#else -#define PATH_DELIMITERS DIR_CHAR -#endif - - -CURLcode create_dir_hierarchy(const char *outfile, FILE *errors) -{ - char *tempdir; - char *tempdir2; - char *outdup; - char *dirbuildup; - CURLcode result = CURLE_OK; - size_t outlen; - - outlen = strlen(outfile); - outdup = strdup(outfile); - if(!outdup) - return CURLE_OUT_OF_MEMORY; - - dirbuildup = malloc(outlen + 1); - if(!dirbuildup) { - Curl_safefree(outdup); - return CURLE_OUT_OF_MEMORY; - } - dirbuildup[0] = '\0'; - - /* Allow strtok() here since this isn't used threaded */ - /* !checksrc! disable BANNEDFUNC 2 */ - tempdir = strtok(outdup, PATH_DELIMITERS); - - while(tempdir != NULL) { - tempdir2 = strtok(NULL, PATH_DELIMITERS); - /* since strtok returns a token for the last word even - if not ending with DIR_CHAR, we need to prune it */ - if(tempdir2 != NULL) { - size_t dlen = strlen(dirbuildup); - if(dlen) - snprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir); - else { - if(outdup == tempdir) - /* the output string doesn't start with a separator */ - strcpy(dirbuildup, tempdir); - else - snprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir); - } - if(access(dirbuildup, F_OK) == -1) { - if(-1 == mkdir(dirbuildup, (mode_t)0000750)) { - show_dir_errno(errors, dirbuildup); - result = CURLE_WRITE_ERROR; - break; /* get out of loop */ - } - } - } - tempdir = tempdir2; - } - - Curl_safefree(dirbuildup); - Curl_safefree(outdup); - - return result; -} - diff --git a/dep/cpr/opt/curl/src/tool_dirhie.h b/dep/cpr/opt/curl/src/tool_dirhie.h deleted file mode 100644 index cc67687de27..00000000000 --- a/dep/cpr/opt/curl/src/tool_dirhie.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef HEADER_CURL_TOOL_DIRHIE_H -#define HEADER_CURL_TOOL_DIRHIE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -CURLcode create_dir_hierarchy(const char *outfile, FILE *errors); - -#endif /* HEADER_CURL_TOOL_DIRHIE_H */ - diff --git a/dep/cpr/opt/curl/src/tool_doswin.c b/dep/cpr/opt/curl/src/tool_doswin.c deleted file mode 100644 index 91299986afd..00000000000 --- a/dep/cpr/opt/curl/src/tool_doswin.c +++ /dev/null @@ -1,668 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#if defined(MSDOS) || defined(WIN32) - -#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) -# include -#endif - -#ifdef WIN32 -# include "tool_cfgable.h" -# include "tool_libinfo.h" -#endif - -#include "tool_bname.h" -#include "tool_doswin.h" - -#include "memdebug.h" /* keep this as LAST include */ - -/* - * Macros ALWAYS_TRUE and ALWAYS_FALSE are used to avoid compiler warnings. - */ - -#define ALWAYS_TRUE (1) -#define ALWAYS_FALSE (0) - -#if defined(_MSC_VER) && !defined(__POCC__) -# undef ALWAYS_TRUE -# undef ALWAYS_FALSE -# if (_MSC_VER < 1500) -# define ALWAYS_TRUE (0, 1) -# define ALWAYS_FALSE (1, 0) -# else -# define ALWAYS_TRUE \ -__pragma(warning(push)) \ -__pragma(warning(disable:4127)) \ -(1) \ -__pragma(warning(pop)) -# define ALWAYS_FALSE \ -__pragma(warning(push)) \ -__pragma(warning(disable:4127)) \ -(0) \ -__pragma(warning(pop)) -# endif -#endif - -#ifdef WIN32 -# undef PATH_MAX -# define PATH_MAX MAX_PATH -#endif - -#ifndef S_ISCHR -# ifdef S_IFCHR -# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -# else -# define S_ISCHR(m) (0) /* cannot tell if file is a device */ -# endif -#endif - -#ifdef WIN32 -# define _use_lfn(f) ALWAYS_TRUE /* long file names always available */ -#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */ -# define _use_lfn(f) ALWAYS_FALSE /* long file names never available */ -#elif defined(__DJGPP__) -# include /* _use_lfn(f) prototype */ -#endif - -#ifndef UNITTESTS -static SANITIZEcode truncate_dryrun(const char *path, - const size_t truncate_pos); -#ifdef MSDOS -static SANITIZEcode msdosify(char **const sanitized, const char *file_name, - int flags); -#endif -static SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, - const char *file_name, - int flags); -#endif /* !UNITTESTS (static declarations used if no unit tests) */ - - -/* -Sanitize a file or path name. - -All banned characters are replaced by underscores, for example: -f?*foo => f__foo -f:foo::$DATA => f_foo__$DATA -f:\foo:bar => f__foo_bar -f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH) - -This function was implemented according to the guidelines in 'Naming Files, -Paths, and Namespaces' section 'Naming Conventions'. -https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx - -Flags ------ -SANITIZE_ALLOW_COLONS: Allow colons. -Without this flag colons are sanitized. - -SANITIZE_ALLOW_PATH: Allow path separators and colons. -Without this flag path separators and colons are sanitized. - -SANITIZE_ALLOW_RESERVED: Allow reserved device names. -Without this flag a reserved device name is renamed (COM1 => _COM1) unless it's -in a UNC prefixed path. - -SANITIZE_ALLOW_TRUNCATE: Allow truncating a long filename. -Without this flag if the sanitized filename or path will be too long an error -occurs. With this flag the filename --and not any other parts of the path-- may -be truncated to at least a single character. A filename followed by an -alternate data stream (ADS) cannot be truncated in any case. - -Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. -Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. -*/ -SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name, - int flags) -{ - char *p, *target; - size_t len; - SANITIZEcode sc; - size_t max_sanitized_len; - - if(!sanitized) - return SANITIZE_ERR_BAD_ARGUMENT; - - *sanitized = NULL; - - if(!file_name) - return SANITIZE_ERR_BAD_ARGUMENT; - - if((flags & SANITIZE_ALLOW_PATH)) { -#ifndef MSDOS - if(file_name[0] == '\\' && file_name[1] == '\\') - /* UNC prefixed path \\ (eg \\?\C:\foo) */ - max_sanitized_len = 32767-1; - else -#endif - max_sanitized_len = PATH_MAX-1; - } - else - /* The maximum length of a filename. - FILENAME_MAX is often the same as PATH_MAX, in other words it is 260 and - does not discount the path information therefore we shouldn't use it. */ - max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1; - - len = strlen(file_name); - if(len > max_sanitized_len) { - if(!(flags & SANITIZE_ALLOW_TRUNCATE) || - truncate_dryrun(file_name, max_sanitized_len)) - return SANITIZE_ERR_INVALID_PATH; - - len = max_sanitized_len; - } - - target = malloc(len + 1); - if(!target) - return SANITIZE_ERR_OUT_OF_MEMORY; - - strncpy(target, file_name, len); - target[len] = '\0'; - -#ifndef MSDOS - if((flags & SANITIZE_ALLOW_PATH) && !strncmp(target, "\\\\?\\", 4)) - /* Skip the literal path prefix \\?\ */ - p = target + 4; - else -#endif - p = target; - - /* replace control characters and other banned characters */ - for(; *p; ++p) { - const char *banned; - - if((1 <= *p && *p <= 31) || - (!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *p == ':') || - (!(flags & SANITIZE_ALLOW_PATH) && (*p == '/' || *p == '\\'))) { - *p = '_'; - continue; - } - - for(banned = "|<>\"?*"; *banned; ++banned) { - if(*p == *banned) { - *p = '_'; - break; - } - } - } - - /* remove trailing spaces and periods if not allowing paths */ - if(!(flags & SANITIZE_ALLOW_PATH) && len) { - char *clip = NULL; - - p = &target[len]; - do { - --p; - if(*p != ' ' && *p != '.') - break; - clip = p; - } while(p != target); - - if(clip) { - *clip = '\0'; - len = clip - target; - } - } - -#ifdef MSDOS - sc = msdosify(&p, target, flags); - free(target); - if(sc) - return sc; - target = p; - len = strlen(target); - - if(len > max_sanitized_len) { - free(target); - return SANITIZE_ERR_INVALID_PATH; - } -#endif - - if(!(flags & SANITIZE_ALLOW_RESERVED)) { - sc = rename_if_reserved_dos_device_name(&p, target, flags); - free(target); - if(sc) - return sc; - target = p; - len = strlen(target); - - if(len > max_sanitized_len) { - free(target); - return SANITIZE_ERR_INVALID_PATH; - } - } - - *sanitized = target; - return SANITIZE_ERR_OK; -} - - -/* -Test if truncating a path to a file will leave at least a single character in -the filename. Filenames suffixed by an alternate data stream can't be -truncated. This performs a dry run, nothing is modified. - -Good truncate_pos 9: C:\foo\bar => C:\foo\ba -Good truncate_pos 6: C:\foo => C:\foo -Good truncate_pos 5: C:\foo => C:\fo -Bad* truncate_pos 5: C:foo => C:foo -Bad truncate_pos 5: C:\foo:ads => C:\fo -Bad truncate_pos 9: C:\foo:ads => C:\foo:ad -Bad truncate_pos 5: C:\foo\bar => C:\fo -Bad truncate_pos 5: C:\foo\ => C:\fo -Bad truncate_pos 7: C:\foo\ => C:\foo\ -Error truncate_pos 7: C:\foo => (pos out of range) -Bad truncate_pos 1: C:\foo\ => C - -* C:foo is ambiguous, C could end up being a drive or file therefore something - like C:superlongfilename can't be truncated. - -Returns -SANITIZE_ERR_OK: Good -- 'path' can be truncated -SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated -!= SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error -*/ -SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos) -{ - size_t len; - - if(!path) - return SANITIZE_ERR_BAD_ARGUMENT; - - len = strlen(path); - - if(truncate_pos > len) - return SANITIZE_ERR_BAD_ARGUMENT; - - if(!len || !truncate_pos) - return SANITIZE_ERR_INVALID_PATH; - - if(strpbrk(&path[truncate_pos - 1], "\\/:")) - return SANITIZE_ERR_INVALID_PATH; - - /* C:\foo can be truncated but C:\foo:ads can't */ - if(truncate_pos > 1) { - const char *p = &path[truncate_pos - 1]; - do { - --p; - if(*p == ':') - return SANITIZE_ERR_INVALID_PATH; - } while(p != path && *p != '\\' && *p != '/'); - } - - return SANITIZE_ERR_OK; -} - -/* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function - * were taken with modification from the DJGPP port of tar 1.12. They use - * algorithms originally from DJTAR. - */ - -/* -Extra sanitization MSDOS for file_name. - -This is a supporting function for sanitize_file_name. - -Warning: This is an MSDOS legacy function and was purposely written in a way -that some path information may pass through. For example drive letter names -(C:, D:, etc) are allowed to pass through. For sanitizing a filename use -sanitize_file_name. - -Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. -Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. -*/ -#if defined(MSDOS) || defined(UNITTESTS) -SANITIZEcode msdosify(char **const sanitized, const char *file_name, - int flags) -{ - char dos_name[PATH_MAX]; - static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */ - "|<>/\\\":?*"; /* illegal in DOS & W95 */ - static const char *illegal_chars_w95 = &illegal_chars_dos[8]; - int idx, dot_idx; - const char *s = file_name; - char *d = dos_name; - const char *const dlimit = dos_name + sizeof(dos_name) - 1; - const char *illegal_aliens = illegal_chars_dos; - size_t len = sizeof(illegal_chars_dos) - 1; - - if(!sanitized) - return SANITIZE_ERR_BAD_ARGUMENT; - - *sanitized = NULL; - - if(!file_name) - return SANITIZE_ERR_BAD_ARGUMENT; - - if(strlen(file_name) > PATH_MAX-1 && - (!(flags & SANITIZE_ALLOW_TRUNCATE) || - truncate_dryrun(file_name, PATH_MAX-1))) - return SANITIZE_ERR_INVALID_PATH; - - /* Support for Windows 9X VFAT systems, when available. */ - if(_use_lfn(file_name)) { - illegal_aliens = illegal_chars_w95; - len -= (illegal_chars_w95 - illegal_chars_dos); - } - - /* Get past the drive letter, if any. */ - if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') { - *d++ = *s++; - *d = ((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) ? ':' : '_'; - ++d, ++s; - } - - for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) { - if(memchr(illegal_aliens, *s, len)) { - - if((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *s == ':') - *d = ':'; - else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\')) - *d = *s; - /* Dots are special: DOS doesn't allow them as the leading character, - and a file name cannot have more than a single dot. We leave the - first non-leading dot alone, unless it comes too close to the - beginning of the name: we want sh.lex.c to become sh_lex.c, not - sh.lex-c. */ - else if(*s == '.') { - if((flags & SANITIZE_ALLOW_PATH) && idx == 0 && - (s[1] == '/' || s[1] == '\\' || - (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) { - /* Copy "./" and "../" verbatim. */ - *d++ = *s++; - if(d == dlimit) - break; - if(*s == '.') { - *d++ = *s++; - if(d == dlimit) - break; - } - *d = *s; - } - else if(idx == 0) - *d = '_'; - else if(dot_idx >= 0) { - if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */ - d[dot_idx - idx] = '_'; /* replace previous dot */ - *d = '.'; - } - else - *d = '-'; - } - else - *d = '.'; - - if(*s == '.') - dot_idx = idx; - } - else if(*s == '+' && s[1] == '+') { - if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */ - *d++ = 'x'; - if(d == dlimit) - break; - *d = 'x'; - } - else { - /* libg++ etc. */ - if(dlimit - d < 4) { - *d++ = 'x'; - if(d == dlimit) - break; - *d = 'x'; - } - else { - memcpy(d, "plus", 4); - d += 3; - } - } - s++; - idx++; - } - else - *d = '_'; - } - else - *d = *s; - if(*s == '/' || *s == '\\') { - idx = 0; - dot_idx = -1; - } - else - idx++; - } - *d = '\0'; - - if(*s) { - /* dos_name is truncated, check that truncation requirements are met, - specifically truncating a filename suffixed by an alternate data stream - or truncating the entire filename is not allowed. */ - if(!(flags & SANITIZE_ALLOW_TRUNCATE) || strpbrk(s, "\\/:") || - truncate_dryrun(dos_name, d - dos_name)) - return SANITIZE_ERR_INVALID_PATH; - } - - *sanitized = strdup(dos_name); - return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY); -} -#endif /* MSDOS || UNITTESTS */ - -/* -Rename file_name if it's a reserved dos device name. - -This is a supporting function for sanitize_file_name. - -Warning: This is an MSDOS legacy function and was purposely written in a way -that some path information may pass through. For example drive letter names -(C:, D:, etc) are allowed to pass through. For sanitizing a filename use -sanitize_file_name. - -Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. -Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. -*/ -SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, - const char *file_name, - int flags) -{ - /* We could have a file whose name is a device on MS-DOS. Trying to - * retrieve such a file would fail at best and wedge us at worst. We need - * to rename such files. */ - char *p, *base; - char fname[PATH_MAX]; -#ifdef MSDOS - struct_stat st_buf; -#endif - - if(!sanitized) - return SANITIZE_ERR_BAD_ARGUMENT; - - *sanitized = NULL; - - if(!file_name) - return SANITIZE_ERR_BAD_ARGUMENT; - - /* Ignore UNC prefixed paths, they are allowed to contain a reserved name. */ -#ifndef MSDOS - if((flags & SANITIZE_ALLOW_PATH) && - file_name[0] == '\\' && file_name[1] == '\\') { - size_t len = strlen(file_name); - *sanitized = malloc(len + 1); - if(!*sanitized) - return SANITIZE_ERR_OUT_OF_MEMORY; - strncpy(*sanitized, file_name, len + 1); - return SANITIZE_ERR_OK; - } -#endif - - if(strlen(file_name) > PATH_MAX-1 && - (!(flags & SANITIZE_ALLOW_TRUNCATE) || - truncate_dryrun(file_name, PATH_MAX-1))) - return SANITIZE_ERR_INVALID_PATH; - - strncpy(fname, file_name, PATH_MAX-1); - fname[PATH_MAX-1] = '\0'; - base = basename(fname); - - /* Rename reserved device names that are known to be accessible without \\.\ - Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS - https://support.microsoft.com/en-us/kb/74496 - https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx - */ - for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) { - size_t p_len; - int x = (curl_strnequal(p, "CON", 3) || - curl_strnequal(p, "PRN", 3) || - curl_strnequal(p, "AUX", 3) || - curl_strnequal(p, "NUL", 3)) ? 3 : - (curl_strnequal(p, "CLOCK$", 6)) ? 6 : - (curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ? - (('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0; - - if(!x) - continue; - - /* the devices may be accessible with an extension or ADS, for - example CON.AIR and 'CON . AIR' and CON:AIR access console */ - - for(; p[x] == ' '; ++x) - ; - - if(p[x] == '.') { - p[x] = '_'; - continue; - } - else if(p[x] == ':') { - if(!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) { - p[x] = '_'; - continue; - } - ++x; - } - else if(p[x]) /* no match */ - continue; - - /* p points to 'CON' or 'CON ' or 'CON:', etc */ - p_len = strlen(p); - - /* Prepend a '_' */ - if(strlen(fname) == PATH_MAX-1) { - --p_len; - if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(p, p_len)) - return SANITIZE_ERR_INVALID_PATH; - p[p_len] = '\0'; - } - memmove(p + 1, p, p_len + 1); - p[0] = '_'; - ++p_len; - - /* if fname was just modified then the basename pointer must be updated */ - if(p == fname) - base = basename(fname); - } - - /* This is the legacy portion from rename_if_dos_device_name that checks for - reserved device names. It only works on MSDOS. On Windows XP the stat - check errors with EINVAL if the device name is reserved. On Windows - Vista/7/8 it sets mode S_IFREG (regular file or device). According to MSDN - stat doc the latter behavior is correct, but that doesn't help us identify - whether it's a reserved device name and not a regular file name. */ -#ifdef MSDOS - if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { - /* Prepend a '_' */ - size_t blen = strlen(base); - if(blen) { - if(strlen(fname) == PATH_MAX-1) { - --blen; - if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(base, blen)) - return SANITIZE_ERR_INVALID_PATH; - base[blen] = '\0'; - } - memmove(base + 1, base, blen + 1); - base[0] = '_'; - ++blen; - } - } -#endif - - *sanitized = strdup(fname); - return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY); -} - -#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) - -/* - * Disable program default argument globbing. We do it on our own. - */ -char **__crt0_glob_function(char *arg) -{ - (void)arg; - return (char **)0; -} - -#endif /* MSDOS && (__DJGPP__ || __GO32__) */ - -#ifdef WIN32 - -/* - * Function to find CACert bundle on a Win32 platform using SearchPath. - * (SearchPath is already declared via inclusions done in setup header file) - * (Use the ASCII version instead of the unicode one!) - * The order of the directories it searches is: - * 1. application's directory - * 2. current working directory - * 3. Windows System directory (e.g. C:\windows\system32) - * 4. Windows Directory (e.g. C:\windows) - * 5. all directories along %PATH% - * - * For WinXP and later search order actually depends on registry value: - * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode - */ - -CURLcode FindWin32CACert(struct OperationConfig *config, - const char *bundle_file) -{ - CURLcode result = CURLE_OK; - - /* search and set cert file only if libcurl supports SSL */ - if(curlinfo->features & CURL_VERSION_SSL) { - - DWORD res_len; - char buf[PATH_MAX]; - char *ptr = NULL; - - buf[0] = '\0'; - - res_len = SearchPathA(NULL, bundle_file, NULL, PATH_MAX, buf, &ptr); - if(res_len > 0) { - Curl_safefree(config->cacert); - config->cacert = strdup(buf); - if(!config->cacert) - result = CURLE_OUT_OF_MEMORY; - } - } - - return result; -} - -#endif /* WIN32 */ - -#endif /* MSDOS || WIN32 */ diff --git a/dep/cpr/opt/curl/src/tool_doswin.h b/dep/cpr/opt/curl/src/tool_doswin.h deleted file mode 100644 index f649ef02351..00000000000 --- a/dep/cpr/opt/curl/src/tool_doswin.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef HEADER_CURL_TOOL_DOSWIN_H -#define HEADER_CURL_TOOL_DOSWIN_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#if defined(MSDOS) || defined(WIN32) - -#define SANITIZE_ALLOW_COLONS (1<<0) /* Allow colons */ -#define SANITIZE_ALLOW_PATH (1<<1) /* Allow path separators and colons */ -#define SANITIZE_ALLOW_RESERVED (1<<2) /* Allow reserved device names */ -#define SANITIZE_ALLOW_TRUNCATE (1<<3) /* Allow truncating a long filename */ - -typedef enum { - SANITIZE_ERR_OK = 0, /* 0 - OK */ - SANITIZE_ERR_INVALID_PATH, /* 1 - the path is invalid */ - SANITIZE_ERR_BAD_ARGUMENT, /* 2 - bad function parameter */ - SANITIZE_ERR_OUT_OF_MEMORY, /* 3 - out of memory */ - SANITIZE_ERR_LAST /* never use! */ -} SANITIZEcode; - -SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name, - int flags); -#ifdef UNITTESTS -SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos); -SANITIZEcode msdosify(char **const sanitized, const char *file_name, - int flags); -SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, - const char *file_name, - int flags); -#endif /* UNITTESTS */ - -#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) - -char **__crt0_glob_function(char *arg); - -#endif /* MSDOS && (__DJGPP__ || __GO32__) */ - -#ifdef WIN32 - -CURLcode FindWin32CACert(struct OperationConfig *config, - const char *bundle_file); - -#endif /* WIN32 */ - -#endif /* MSDOS || WIN32 */ - -#endif /* HEADER_CURL_TOOL_DOSWIN_H */ - diff --git a/dep/cpr/opt/curl/src/tool_easysrc.c b/dep/cpr/opt/curl/src/tool_easysrc.c deleted file mode 100644 index cb30e404bb6..00000000000 --- a/dep/cpr/opt/curl/src/tool_easysrc.c +++ /dev/null @@ -1,236 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include "slist_wc.h" - -#ifndef CURL_DISABLE_LIBCURL_OPTION - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_easysrc.h" -#include "tool_msgs.h" - -#include "memdebug.h" /* keep this as LAST include */ - -/* global variable definitions, for easy-interface source code generation */ - -struct slist_wc *easysrc_decl = NULL; /* Variable declarations */ -struct slist_wc *easysrc_data = NULL; /* Build slists, forms etc. */ -struct slist_wc *easysrc_code = NULL; /* Setopt calls */ -struct slist_wc *easysrc_toohard = NULL; /* Unconvertible setopt */ -struct slist_wc *easysrc_clean = NULL; /* Clean up allocated data */ -int easysrc_mime_count = 0; -int easysrc_slist_count = 0; - -static const char *const srchead[]={ - "/********* Sample code generated by the curl command line tool **********", - " * All curl_easy_setopt() options are documented at:", - " * https://curl.haxx.se/libcurl/c/curl_easy_setopt.html", - " ************************************************************************/", - "#include ", - "", - "int main(int argc, char *argv[])", - "{", - " CURLcode ret;", - " CURL *hnd;", - NULL -}; -/* easysrc_decl declarations come here */ -/* easysrc_data initialisations come here */ -/* easysrc_code statements come here */ -static const char *const srchard[]={ - "/* Here is a list of options the curl code used that cannot get generated", - " as source easily. You may select to either not use them or implement", - " them yourself.", - "", - NULL -}; -static const char *const srcend[]={ - "", - " return (int)ret;", - "}", - "/**** End of sample code ****/", - NULL -}; - -/* Clean up all source code if we run out of memory */ -static void easysrc_free(void) -{ - slist_wc_free_all(easysrc_decl); - easysrc_decl = NULL; - slist_wc_free_all(easysrc_data); - easysrc_data = NULL; - slist_wc_free_all(easysrc_code); - easysrc_code = NULL; - slist_wc_free_all(easysrc_toohard); - easysrc_toohard = NULL; - slist_wc_free_all(easysrc_clean); - easysrc_clean = NULL; -} - -/* Add a source line to the main code or remarks */ -CURLcode easysrc_add(struct slist_wc **plist, const char *line) -{ - CURLcode ret = CURLE_OK; - struct slist_wc *list = slist_wc_append(*plist, line); - if(!list) { - easysrc_free(); - ret = CURLE_OUT_OF_MEMORY; - } - else - *plist = list; - return ret; -} - -CURLcode easysrc_addf(struct slist_wc **plist, const char *fmt, ...) -{ - CURLcode ret; - char *bufp; - va_list ap; - va_start(ap, fmt); - bufp = curlx_mvaprintf(fmt, ap); - va_end(ap); - if(! bufp) { - ret = CURLE_OUT_OF_MEMORY; - } - else { - ret = easysrc_add(plist, bufp); - curl_free(bufp); - } - return ret; -} - -#define CHKRET(v) do {CURLcode ret = (v); if(ret) return ret;} WHILE_FALSE - -CURLcode easysrc_init(void) -{ - CHKRET(easysrc_add(&easysrc_code, - "hnd = curl_easy_init();")); - return CURLE_OK; -} - -CURLcode easysrc_perform(void) -{ - /* Note any setopt calls which we could not convert */ - if(easysrc_toohard) { - int i; - struct curl_slist *ptr; - const char *c; - CHKRET(easysrc_add(&easysrc_code, "")); - /* Preamble comment */ - for(i = 0; ((c = srchard[i]) != NULL); i++) - CHKRET(easysrc_add(&easysrc_code, c)); - /* Each unconverted option */ - if(easysrc_toohard) { - for(ptr = easysrc_toohard->first; ptr; ptr = ptr->next) - CHKRET(easysrc_add(&easysrc_code, ptr->data)); - } - CHKRET(easysrc_add(&easysrc_code, "")); - CHKRET(easysrc_add(&easysrc_code, "*/")); - - slist_wc_free_all(easysrc_toohard); - easysrc_toohard = NULL; - } - - CHKRET(easysrc_add(&easysrc_code, "")); - CHKRET(easysrc_add(&easysrc_code, "ret = curl_easy_perform(hnd);")); - CHKRET(easysrc_add(&easysrc_code, "")); - - return CURLE_OK; -} - -CURLcode easysrc_cleanup(void) -{ - CHKRET(easysrc_add(&easysrc_code, "curl_easy_cleanup(hnd);")); - CHKRET(easysrc_add(&easysrc_code, "hnd = NULL;")); - - return CURLE_OK; -} - -void dumpeasysrc(struct GlobalConfig *config) -{ - struct curl_slist *ptr; - char *o = config->libcurl; - - FILE *out; - bool fopened = FALSE; - if(strcmp(o, "-")) { - out = fopen(o, FOPEN_WRITETEXT); - fopened = TRUE; - } - else - out = stdout; - if(!out) - warnf(config, "Failed to open %s to write libcurl code!\n", o); - else { - int i; - const char *c; - - for(i = 0; ((c = srchead[i]) != NULL); i++) - fprintf(out, "%s\n", c); - - /* Declare variables used for complex setopt values */ - if(easysrc_decl) { - for(ptr = easysrc_decl->first; ptr; ptr = ptr->next) - fprintf(out, " %s\n", ptr->data); - } - - /* Set up complex values for setopt calls */ - if(easysrc_data) { - fprintf(out, "\n"); - - for(ptr = easysrc_data->first; ptr; ptr = ptr->next) - fprintf(out, " %s\n", ptr->data); - } - - fprintf(out, "\n"); - if(easysrc_code) { - for(ptr = easysrc_code->first; ptr; ptr = ptr->next) { - if(ptr->data[0]) { - fprintf(out, " %s\n", ptr->data); - } - else { - fprintf(out, "\n"); - } - } - } - - if(easysrc_clean) { - for(ptr = easysrc_clean->first; ptr; ptr = ptr->next) - fprintf(out, " %s\n", ptr->data); - } - - for(i = 0; ((c = srcend[i]) != NULL); i++) - fprintf(out, "%s\n", c); - - if(fopened) - fclose(out); - } - - easysrc_free(); -} - -#endif /* CURL_DISABLE_LIBCURL_OPTION */ diff --git a/dep/cpr/opt/curl/src/tool_easysrc.h b/dep/cpr/opt/curl/src/tool_easysrc.h deleted file mode 100644 index fd799ab84d3..00000000000 --- a/dep/cpr/opt/curl/src/tool_easysrc.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef HEADER_CURL_TOOL_EASYSRC_H -#define HEADER_CURL_TOOL_EASYSRC_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" -#ifndef CURL_DISABLE_LIBCURL_OPTION - -/* global variable declarations, for easy-interface source code generation */ - -extern struct slist_wc *easysrc_decl; /* Variable declarations */ -extern struct slist_wc *easysrc_data; /* Build slists, forms etc. */ -extern struct slist_wc *easysrc_code; /* Setopt calls etc. */ -extern struct slist_wc *easysrc_toohard; /* Unconvertible setopt */ -extern struct slist_wc *easysrc_clean; /* Clean up (reverse order) */ - -extern int easysrc_mime_count; /* Number of curl_mime variables */ -extern int easysrc_slist_count; /* Number of curl_slist variables */ - -extern CURLcode easysrc_init(void); -extern CURLcode easysrc_add(struct slist_wc **plist, const char *bupf); -extern CURLcode easysrc_addf(struct slist_wc **plist, - const char *fmt, ...); -extern CURLcode easysrc_perform(void); -extern CURLcode easysrc_cleanup(void); - -void dumpeasysrc(struct GlobalConfig *config); - -#endif /* CURL_DISABLE_LIBCURL_OPTION */ - -#endif /* HEADER_CURL_TOOL_EASYSRC_H */ diff --git a/dep/cpr/opt/curl/src/tool_formparse.c b/dep/cpr/opt/curl/src/tool_formparse.c deleted file mode 100644 index 4645a761e38..00000000000 --- a/dep/cpr/opt/curl/src/tool_formparse.c +++ /dev/null @@ -1,749 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include "mime.h" -#include "strcase.h" - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_convert.h" -#include "tool_msgs.h" -#include "tool_formparse.h" - -#include "memdebug.h" /* keep this as LAST include */ - - -/* - * helper function to get a word from form param - * after call get_parm_word, str either point to string end - * or point to any of end chars. - */ -static char *get_param_word(char **str, char **end_pos) -{ - char *ptr = *str; - char *word_begin = NULL; - char *ptr2; - char *escape = NULL; - const char *end_chars = ";,"; - - /* the first non-space char is here */ - word_begin = ptr; - if(*ptr == '"') { - ++ptr; - while(*ptr) { - if(*ptr == '\\') { - if(ptr[1] == '\\' || ptr[1] == '"') { - /* remember the first escape position */ - if(!escape) - escape = ptr; - /* skip escape of back-slash or double-quote */ - ptr += 2; - continue; - } - } - if(*ptr == '"') { - *end_pos = ptr; - if(escape) { - /* has escape, we restore the unescaped string here */ - ptr = ptr2 = escape; - do { - if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"')) - ++ptr; - *ptr2++ = *ptr++; - } - while(ptr < *end_pos); - *end_pos = ptr2; - } - while(*ptr && NULL == strchr(end_chars, *ptr)) - ++ptr; - *str = ptr; - return word_begin + 1; - } - ++ptr; - } - /* end quote is missing, treat it as non-quoted. */ - ptr = word_begin; - } - - while(*ptr && NULL == strchr(end_chars, *ptr)) - ++ptr; - *str = *end_pos = ptr; - return word_begin; -} - -/* Append slist item and return -1 if failed. */ -static int slist_append(struct curl_slist **plist, const char *data) -{ - struct curl_slist *s = curl_slist_append(*plist, data); - - if(!s) - return -1; - - *plist = s; - return 0; -} - -/* Read headers from a file and append to list. */ -static int read_field_headers(struct OperationConfig *config, - const char *filename, FILE *fp, - struct curl_slist **pheaders) -{ - size_t hdrlen = 0; - size_t pos = 0; - int c; - bool incomment = FALSE; - int lineno = 1; - char hdrbuf[999]; /* Max. header length + 1. */ - - for(;;) { - c = getc(fp); - if(c == EOF || (!pos && !ISSPACE(c))) { - /* Strip and flush the current header. */ - while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1])) - hdrlen--; - if(hdrlen) { - hdrbuf[hdrlen] = '\0'; - if(slist_append(pheaders, hdrbuf)) { - fprintf(config->global->errors, - "Out of memory for field headers!\n"); - return -1; - } - hdrlen = 0; - } - } - - switch(c) { - case EOF: - if(ferror(fp)) { - fprintf(config->global->errors, - "Header file %s read error: %s\n", filename, strerror(errno)); - return -1; - } - return 0; /* Done. */ - case '\r': - continue; /* Ignore. */ - case '\n': - pos = 0; - incomment = FALSE; - lineno++; - continue; - case '#': - if(!pos) - incomment = TRUE; - break; - } - - pos++; - if(!incomment) { - if(hdrlen == sizeof hdrbuf - 1) { - warnf(config->global, "File %s line %d: header too long (truncated)\n", - filename, lineno); - c = ' '; - } - if(hdrlen <= sizeof hdrbuf - 1) - hdrbuf[hdrlen++] = (char) c; - } - } - /* NOTREACHED */ -} - -static int get_param_part(struct OperationConfig *config, char **str, - char **pdata, char **ptype, char **pfilename, - char **pencoder, struct curl_slist **pheaders) -{ - char *p = *str; - char *type = NULL; - char *filename = NULL; - char *encoder = NULL; - char *endpos; - char *tp; - char sep; - char type_major[128] = ""; - char type_minor[128] = ""; - char *endct = NULL; - struct curl_slist *headers = NULL; - - if(ptype) - *ptype = NULL; - if(pfilename) - *pfilename = NULL; - if(pheaders) - *pheaders = NULL; - if(pencoder) - *pencoder = NULL; - while(ISSPACE(*p)) - p++; - tp = p; - *pdata = get_param_word(&p, &endpos); - /* If not quoted, strip trailing spaces. */ - if(*pdata == tp) - while(endpos > *pdata && ISSPACE(endpos[-1])) - endpos--; - sep = *p; - *endpos = '\0'; - while(sep == ';') { - while(ISSPACE(*++p)) - ; - - if(!endct && checkprefix("type=", p)) { - for(p += 5; ISSPACE(*p); p++) - ; - /* set type pointer */ - type = p; - - /* verify that this is a fine type specifier */ - if(2 != sscanf(type, "%127[^/ ]/%127[^;, \n]", type_major, type_minor)) { - warnf(config->global, "Illegally formatted content-type field!\n"); - curl_slist_free_all(headers); - return -1; /* illegal content-type syntax! */ - } - - /* now point beyond the content-type specifier */ - endpos = type + strlen(type_major) + strlen(type_minor) + 1; - for(p = endpos; ISSPACE(*p); p++) - ; - while(*p && *p != ';' && *p != ',') - p++; - endct = p; - sep = *p; - } - else if(checkprefix("filename=", p)) { - if(endct) { - *endct = '\0'; - endct = NULL; - } - for(p += 9; ISSPACE(*p); p++) - ; - tp = p; - filename = get_param_word(&p, &endpos); - /* If not quoted, strip trailing spaces. */ - if(filename == tp) - while(endpos > filename && ISSPACE(endpos[-1])) - endpos--; - sep = *p; - *endpos = '\0'; - } - else if(checkprefix("headers=", p)) { - if(endct) { - *endct = '\0'; - endct = NULL; - } - p += 8; - if(*p == '@' || *p == '<') { - char *hdrfile; - FILE *fp; - /* Read headers from a file. */ - - do { - p++; - } while(ISSPACE(*p)); - tp = p; - hdrfile = get_param_word(&p, &endpos); - /* If not quoted, strip trailing spaces. */ - if(hdrfile == tp) - while(endpos > hdrfile && ISSPACE(endpos[-1])) - endpos--; - sep = *p; - *endpos = '\0'; - /* TODO: maybe special fopen for VMS? */ - fp = fopen(hdrfile, FOPEN_READTEXT); - if(!fp) - warnf(config->global, "Cannot read from %s: %s\n", hdrfile, - strerror(errno)); - else { - int i = read_field_headers(config, hdrfile, fp, &headers); - - fclose(fp); - if(i) { - curl_slist_free_all(headers); - return -1; - } - } - } - else { - char *hdr; - - while(ISSPACE(*p)) - p++; - tp = p; - hdr = get_param_word(&p, &endpos); - /* If not quoted, strip trailing spaces. */ - if(hdr == tp) - while(endpos > hdr && ISSPACE(endpos[-1])) - endpos--; - sep = *p; - *endpos = '\0'; - if(slist_append(&headers, hdr)) { - fprintf(config->global->errors, "Out of memory for field header!\n"); - curl_slist_free_all(headers); - return -1; - } - } - } - else if(checkprefix("encoder=", p)) { - if(endct) { - *endct = '\0'; - endct = NULL; - } - for(p += 8; ISSPACE(*p); p++) - ; - tp = p; - encoder = get_param_word(&p, &endpos); - /* If not quoted, strip trailing spaces. */ - if(encoder == tp) - while(endpos > encoder && ISSPACE(endpos[-1])) - endpos--; - sep = *p; - *endpos = '\0'; - } - else { - /* unknown prefix, skip to next block */ - char *unknown = get_param_word(&p, &endpos); - - sep = *p; - if(endct) - endct = p; - else { - *endpos = '\0'; - if(*unknown) - warnf(config->global, "skip unknown form field: %s\n", unknown); - } - } - } - - /* Terminate and strip content type. */ - if(type) { - if(!endct) - endct = type + strlen(type); - while(endct > type && ISSPACE(endct[-1])) - endct--; - *endct = '\0'; - } - - if(ptype) - *ptype = type; - else if(type) - warnf(config->global, "Field content type not allowed here: %s\n", type); - - if(pfilename) - *pfilename = filename; - else if(filename) - warnf(config->global, - "Field file name not allowed here: %s\n", filename); - - if(pencoder) - *pencoder = encoder; - else if(encoder) - warnf(config->global, - "Field encoder not allowed here: %s\n", encoder); - - if(pheaders) - *pheaders = headers; - else if(headers) { - warnf(config->global, - "Field headers not allowed here: %s\n", headers->data); - curl_slist_free_all(headers); - } - - *str = p; - return sep & 0xFF; -} - -/* Check if file is "-". If so, use a callback to read OUR stdin (to - * workaround Windows DLL file handle caveat). - * Else use curl_mime_filedata(). */ -static CURLcode file_or_stdin(curl_mimepart *part, const char *file) -{ - if(strcmp(file, "-")) - return curl_mime_filedata(part, file); - - return curl_mime_data_cb(part, -1, (curl_read_callback) fread, - (curl_seek_callback) fseek, NULL, stdin); -} - - -/*************************************************************************** - * - * formparse() - * - * Reads a 'name=value' parameter and builds the appropriate linked list. - * - * Specify files to upload with 'name=@filename', or 'name=@"filename"' - * in case the filename contain ',' or ';'. Supports specified - * given Content-Type of the files. Such as ';type='. - * - * If literal_value is set, any initial '@' or '<' in the value string - * loses its special meaning, as does any embedded ';type='. - * - * You may specify more than one file for a single name (field). Specify - * multiple files by writing it like: - * - * 'name=@filename,filename2,filename3' - * - * or use double-quotes quote the filename: - * - * 'name=@"filename","filename2","filename3"' - * - * If you want content-types specified for each too, write them like: - * - * 'name=@filename;type=image/gif,filename2,filename3' - * - * If you want custom headers added for a single part, write them in a separate - * file and do like this: - * - * 'name=foo;headers=@headerfile' or why not - * 'name=@filemame;headers=@headerfile' - * - * To upload a file, but to fake the file name that will be included in the - * formpost, do like this: - * - * 'name=@filename;filename=/dev/null' or quote the faked filename like: - * 'name=@filename;filename="play, play, and play.txt"' - * - * If filename/path contains ',' or ';', it must be quoted by double-quotes, - * else curl will fail to figure out the correct filename. if the filename - * tobe quoted contains '"' or '\', '"' and '\' must be escaped by backslash. - * - * This function uses curl_formadd to fulfill it's job. Is heavily based on - * the old curl_formparse code. - * - ***************************************************************************/ - -int formparse(struct OperationConfig *config, - const char *input, - curl_mime **mimepost, - curl_mime **mimecurrent, - bool literal_value) -{ - /* input MUST be a string in the format 'name=contents' and we'll - build a linked list with the info */ - char *name = NULL; - char *contents = NULL; - char *contp; - char *data; - char *type = NULL; - char *filename = NULL; - char *encoder = NULL; - struct curl_slist *headers = NULL; - curl_mimepart *part = NULL; - CURLcode res; - int sep = '\0'; - - /* Allocate the main mime structure if needed. */ - if(!*mimepost) { - *mimepost = curl_mime_init(config->easy); - if(!*mimepost) { - warnf(config->global, "curl_mime_init failed!\n"); - return 1; - } - *mimecurrent = *mimepost; - } - - /* Make a copy we can overwrite. */ - contents = strdup(input); - if(!contents) { - fprintf(config->global->errors, "out of memory\n"); - return 2; - } - - /* Scan for the end of the name. */ - contp = strchr(contents, '='); - if(contp) { - if(contp > contents) - name = contents; - *contp++ = '\0'; - - if(*contp == '(' && !literal_value) { - curl_mime *subparts; - - /* Starting a multipart. */ - sep = get_param_part(config, &contp, &data, &type, NULL, NULL, &headers); - if(sep < 0) { - Curl_safefree(contents); - return 3; - } - subparts = curl_mime_init(config->easy); - if(!subparts) { - warnf(config->global, "curl_mime_init failed!\n"); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 4; - } - part = curl_mime_addpart(*mimecurrent); - if(!part) { - warnf(config->global, "curl_mime_addpart failed!\n"); - curl_mime_free(subparts); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 5; - } - if(curl_mime_subparts(part, subparts)) { - warnf(config->global, "curl_mime_subparts failed!\n"); - curl_mime_free(subparts); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 6; - } - *mimecurrent = subparts; - if(curl_mime_headers(part, headers, 1)) { - warnf(config->global, "curl_mime_headers failed!\n"); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 7; - } - if(curl_mime_type(part, type)) { - warnf(config->global, "curl_mime_type failed!\n"); - Curl_safefree(contents); - return 8; - } - } - else if(!name && !strcmp(contp, ")") && !literal_value) { - /* Ending a mutipart. */ - if(*mimecurrent == *mimepost) { - warnf(config->global, "no multipart to terminate!\n"); - Curl_safefree(contents); - return 9; - } - *mimecurrent = (*mimecurrent)->parent->parent; - } - else if('@' == contp[0] && !literal_value) { - - /* we use the @-letter to indicate file name(s) */ - - curl_mime *subparts = NULL; - - do { - /* since this was a file, it may have a content-type specifier - at the end too, or a filename. Or both. */ - ++contp; - sep = get_param_part(config, &contp, - &data, &type, &filename, &encoder, &headers); - if(sep < 0) { - if(subparts != *mimecurrent) - curl_mime_free(subparts); - Curl_safefree(contents); - return 10; - } - - /* now contp point to comma or string end. - If more files to come, make sure we have multiparts. */ - if(!subparts) { - if(sep != ',') /* If there is a single file. */ - subparts = *mimecurrent; - else { - subparts = curl_mime_init(config->easy); - if(!subparts) { - warnf(config->global, "curl_mime_init failed!\n"); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 11; - } - } - } - - /* Allocate a part for that file. */ - part = curl_mime_addpart(subparts); - if(!part) { - warnf(config->global, "curl_mime_addpart failed!\n"); - if(subparts != *mimecurrent) - curl_mime_free(subparts); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 12; - } - - /* Set part headers. */ - if(curl_mime_headers(part, headers, 1)) { - warnf(config->global, "curl_mime_headers failed!\n"); - if(subparts != *mimecurrent) - curl_mime_free(subparts); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 13; - } - - /* Setup file in part. */ - res = file_or_stdin(part, data); - if(res) { - warnf(config->global, "setting file %s failed!\n", data); - if(res != CURLE_READ_ERROR) { - if(subparts != *mimecurrent) - curl_mime_free(subparts); - Curl_safefree(contents); - return 14; - } - } - if(filename && curl_mime_filename(part, filename)) { - warnf(config->global, "curl_mime_filename failed!\n"); - if(subparts != *mimecurrent) - curl_mime_free(subparts); - Curl_safefree(contents); - return 15; - } - if(curl_mime_type(part, type)) { - warnf(config->global, "curl_mime_type failed!\n"); - if(subparts != *mimecurrent) - curl_mime_free(subparts); - Curl_safefree(contents); - return 16; - } - if(curl_mime_encoder(part, encoder)) { - warnf(config->global, "curl_mime_encoder failed!\n"); - if(subparts != *mimecurrent) - curl_mime_free(subparts); - Curl_safefree(contents); - return 17; - } - - /* *contp could be '\0', so we just check with the delimiter */ - } while(sep); /* loop if there's another file name */ - - /* now we add the multiple files section */ - if(subparts != *mimecurrent) { - part = curl_mime_addpart(*mimecurrent); - if(!part) { - warnf(config->global, "curl_mime_addpart failed!\n"); - curl_mime_free(subparts); - Curl_safefree(contents); - return 18; - } - if(curl_mime_subparts(part, subparts)) { - warnf(config->global, "curl_mime_subparts failed!\n"); - curl_mime_free(subparts); - Curl_safefree(contents); - return 19; - } - } - } - else { - /* Allocate a mime part. */ - part = curl_mime_addpart(*mimecurrent); - if(!part) { - warnf(config->global, "curl_mime_addpart failed!\n"); - Curl_safefree(contents); - return 20; - } - - if(*contp == '<' && !literal_value) { - ++contp; - sep = get_param_part(config, &contp, - &data, &type, &filename, &encoder, &headers); - if(sep < 0) { - Curl_safefree(contents); - return 21; - } - - /* Set part headers. */ - if(curl_mime_headers(part, headers, 1)) { - warnf(config->global, "curl_mime_headers failed!\n"); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 22; - } - - /* Setup file in part. */ - res = file_or_stdin(part, data); - if(res) { - warnf(config->global, "setting file %s failed!\n", data); - if(res != CURLE_READ_ERROR) { - Curl_safefree(contents); - return 23; - } - } - } - else { - if(literal_value) - data = contp; - else { - sep = get_param_part(config, &contp, - &data, &type, &filename, &encoder, &headers); - if(sep < 0) { - Curl_safefree(contents); - return 24; - } - } - - /* Set part headers. */ - if(curl_mime_headers(part, headers, 1)) { - warnf(config->global, "curl_mime_headers failed!\n"); - curl_slist_free_all(headers); - Curl_safefree(contents); - return 25; - } - -#ifdef CURL_DOES_CONVERSIONS - if(convert_to_network(data, strlen(data))) { - warnf(config->global, "curl_formadd failed!\n"); - Curl_safefree(contents); - return 26; - } -#endif - - if(curl_mime_data(part, data, CURL_ZERO_TERMINATED)) { - warnf(config->global, "curl_mime_data failed!\n"); - Curl_safefree(contents); - return 27; - } - } - - if(curl_mime_filename(part, filename)) { - warnf(config->global, "curl_mime_filename failed!\n"); - Curl_safefree(contents); - return 28; - } - if(curl_mime_type(part, type)) { - warnf(config->global, "curl_mime_type failed!\n"); - Curl_safefree(contents); - return 29; - } - if(curl_mime_encoder(part, encoder)) { - warnf(config->global, "curl_mime_encoder failed!\n"); - Curl_safefree(contents); - return 30; - } - - if(sep) { - *contp = (char) sep; - warnf(config->global, - "garbage at end of field specification: %s\n", contp); - } - } - - /* Set part name. */ - if(name && curl_mime_name(part, name)) { - warnf(config->global, "curl_mime_name failed!\n"); - Curl_safefree(contents); - return 31; - } - } - else { - warnf(config->global, "Illegally formatted input field!\n"); - Curl_safefree(contents); - return 32; - } - Curl_safefree(contents); - return 0; -} diff --git a/dep/cpr/opt/curl/src/tool_formparse.h b/dep/cpr/opt/curl/src/tool_formparse.h deleted file mode 100644 index a52b98d393f..00000000000 --- a/dep/cpr/opt/curl/src/tool_formparse.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef HEADER_CURL_TOOL_FORMPARSE_H -#define HEADER_CURL_TOOL_FORMPARSE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -int formparse(struct OperationConfig *config, - const char *input, - curl_mime **mimepost, - curl_mime **mimecurrent, - bool literal_value); - -#endif /* HEADER_CURL_TOOL_FORMPARSE_H */ - diff --git a/dep/cpr/opt/curl/src/tool_getparam.c b/dep/cpr/opt/curl/src/tool_getparam.c deleted file mode 100644 index b65c45732db..00000000000 --- a/dep/cpr/opt/curl/src/tool_getparam.c +++ /dev/null @@ -1,2164 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include "strcase.h" - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_binmode.h" -#include "tool_cfgable.h" -#include "tool_cb_prg.h" -#include "tool_convert.h" -#include "tool_formparse.h" -#include "tool_getparam.h" -#include "tool_helpers.h" -#include "tool_libinfo.h" -#include "tool_metalink.h" -#include "tool_msgs.h" -#include "tool_paramhlp.h" -#include "tool_parsecfg.h" - -#include "memdebug.h" /* keep this as LAST include */ - -#ifdef MSDOS -# define USE_WATT32 -#endif - -#define GetStr(str,val) do { \ - if(*(str)) { \ - free(*(str)); \ - *(str) = NULL; \ - } \ - if((val)) { \ - *(str) = strdup((val)); \ - if(!(*(str))) \ - return PARAM_NO_MEM; \ - } \ -} WHILE_FALSE - -struct LongShort { - const char *letter; /* short name option */ - const char *lname; /* long name option */ - enum { - ARG_NONE, /* stand-alone but not a boolean */ - ARG_BOOL, /* accepts a --no-[name] prefix */ - ARG_STRING /* requires an argument */ - } desc; -}; - -static const struct LongShort aliases[]= { - /* 'letter' strings with more than one character have *no* short option to - mention. */ - {"*@", "url", ARG_STRING}, - {"*4", "dns-ipv4-addr", ARG_STRING}, - {"*6", "dns-ipv6-addr", ARG_STRING}, - {"*a", "random-file", ARG_STRING}, - {"*b", "egd-file", ARG_STRING}, - {"*B", "oauth2-bearer", ARG_STRING}, - {"*c", "connect-timeout", ARG_STRING}, - {"*d", "ciphers", ARG_STRING}, - {"*D", "dns-interface", ARG_STRING}, - {"*e", "disable-epsv", ARG_BOOL}, - {"*E", "epsv", ARG_BOOL}, - /* 'epsv' made like this to make --no-epsv and --epsv to work - although --disable-epsv is the documented option */ - {"*F", "dns-servers", ARG_STRING}, - {"*g", "trace", ARG_STRING}, - {"*G", "npn", ARG_BOOL}, - {"*h", "trace-ascii", ARG_STRING}, - {"*H", "alpn", ARG_BOOL}, - {"*i", "limit-rate", ARG_STRING}, - {"*j", "compressed", ARG_BOOL}, - {"*J", "tr-encoding", ARG_BOOL}, - {"*k", "digest", ARG_BOOL}, - {"*l", "negotiate", ARG_BOOL}, - {"*m", "ntlm", ARG_BOOL}, - {"*M", "ntlm-wb", ARG_BOOL}, - {"*n", "basic", ARG_BOOL}, - {"*o", "anyauth", ARG_BOOL}, -#ifdef USE_WATT32 - {"*p", "wdebug", ARG_BOOL}, -#endif - {"*q", "ftp-create-dirs", ARG_BOOL}, - {"*r", "create-dirs", ARG_BOOL}, - {"*s", "max-redirs", ARG_STRING}, - {"*t", "proxy-ntlm", ARG_BOOL}, - {"*u", "crlf", ARG_BOOL}, - {"*v", "stderr", ARG_STRING}, - {"*w", "interface", ARG_STRING}, - {"*x", "krb", ARG_STRING}, - {"*x", "krb4", ARG_STRING}, - /* 'krb4' is the previous name */ - {"*y", "max-filesize", ARG_STRING}, - {"*z", "disable-eprt", ARG_BOOL}, - {"*Z", "eprt", ARG_BOOL}, - /* 'eprt' made like this to make --no-eprt and --eprt to work - although --disable-eprt is the documented option */ - {"*~", "xattr", ARG_BOOL}, - {"$a", "ftp-ssl", ARG_BOOL}, - /* 'ftp-ssl' deprecated name since 7.20.0 */ - {"$a", "ssl", ARG_BOOL}, - /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */ - {"$b", "ftp-pasv", ARG_BOOL}, - {"$c", "socks5", ARG_STRING}, - {"$d", "tcp-nodelay", ARG_BOOL}, - {"$e", "proxy-digest", ARG_BOOL}, - {"$f", "proxy-basic", ARG_BOOL}, - {"$g", "retry", ARG_STRING}, - {"$V", "retry-connrefused", ARG_BOOL}, - {"$h", "retry-delay", ARG_STRING}, - {"$i", "retry-max-time", ARG_STRING}, - {"$k", "proxy-negotiate", ARG_BOOL}, - {"$m", "ftp-account", ARG_STRING}, - {"$n", "proxy-anyauth", ARG_BOOL}, - {"$o", "trace-time", ARG_BOOL}, - {"$p", "ignore-content-length", ARG_BOOL}, - {"$q", "ftp-skip-pasv-ip", ARG_BOOL}, - {"$r", "ftp-method", ARG_STRING}, - {"$s", "local-port", ARG_STRING}, - {"$t", "socks4", ARG_STRING}, - {"$T", "socks4a", ARG_STRING}, - {"$u", "ftp-alternative-to-user", ARG_STRING}, - {"$v", "ftp-ssl-reqd", ARG_BOOL}, - /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */ - {"$v", "ssl-reqd", ARG_BOOL}, - /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */ - {"$w", "sessionid", ARG_BOOL}, - /* 'sessionid' listed as --no-sessionid in the help */ - {"$x", "ftp-ssl-control", ARG_BOOL}, - {"$y", "ftp-ssl-ccc", ARG_BOOL}, - {"$j", "ftp-ssl-ccc-mode", ARG_STRING}, - {"$z", "libcurl", ARG_STRING}, - {"$#", "raw", ARG_BOOL}, - {"$0", "post301", ARG_BOOL}, - {"$1", "keepalive", ARG_BOOL}, - /* 'keepalive' listed as --no-keepalive in the help */ - {"$2", "socks5-hostname", ARG_STRING}, - {"$3", "keepalive-time", ARG_STRING}, - {"$4", "post302", ARG_BOOL}, - {"$5", "noproxy", ARG_STRING}, - {"$7", "socks5-gssapi-nec", ARG_BOOL}, - {"$8", "proxy1.0", ARG_STRING}, - {"$9", "tftp-blksize", ARG_STRING}, - {"$A", "mail-from", ARG_STRING}, - {"$B", "mail-rcpt", ARG_STRING}, - {"$C", "ftp-pret", ARG_BOOL}, - {"$D", "proto", ARG_STRING}, - {"$E", "proto-redir", ARG_STRING}, - {"$F", "resolve", ARG_STRING}, - {"$G", "delegation", ARG_STRING}, - {"$H", "mail-auth", ARG_STRING}, - {"$I", "post303", ARG_BOOL}, - {"$J", "metalink", ARG_BOOL}, - {"$K", "sasl-ir", ARG_BOOL}, - {"$L", "test-event", ARG_BOOL}, - {"$M", "unix-socket", ARG_STRING}, - {"$N", "path-as-is", ARG_BOOL}, - {"$O", "socks5-gssapi-service", ARG_STRING}, - /* 'socks5-gssapi-service' merged with'proxy-service-name' and - deprecated since 7.49.0 */ - {"$O", "proxy-service-name", ARG_STRING}, - {"$P", "service-name", ARG_STRING}, - {"$Q", "proto-default", ARG_STRING}, - {"$R", "expect100-timeout", ARG_STRING}, - {"$S", "tftp-no-options", ARG_BOOL}, - {"$U", "connect-to", ARG_STRING}, - {"$W", "abstract-unix-socket", ARG_STRING}, - {"$X", "tls-max", ARG_STRING}, - {"$Y", "suppress-connect-headers", ARG_BOOL}, - {"$Z", "compressed-ssh", ARG_BOOL}, - {"0", "http1.0", ARG_NONE}, - {"01", "http1.1", ARG_NONE}, - {"02", "http2", ARG_NONE}, - {"03", "http2-prior-knowledge", ARG_NONE}, - {"1", "tlsv1", ARG_NONE}, - {"10", "tlsv1.0", ARG_NONE}, - {"11", "tlsv1.1", ARG_NONE}, - {"12", "tlsv1.2", ARG_NONE}, - {"13", "tlsv1.3", ARG_NONE}, - {"2", "sslv2", ARG_NONE}, - {"3", "sslv3", ARG_NONE}, - {"4", "ipv4", ARG_NONE}, - {"6", "ipv6", ARG_NONE}, - {"a", "append", ARG_BOOL}, - {"A", "user-agent", ARG_STRING}, - {"b", "cookie", ARG_STRING}, - {"B", "use-ascii", ARG_BOOL}, - {"c", "cookie-jar", ARG_STRING}, - {"C", "continue-at", ARG_STRING}, - {"d", "data", ARG_STRING}, - {"dr", "data-raw", ARG_STRING}, - {"da", "data-ascii", ARG_STRING}, - {"db", "data-binary", ARG_STRING}, - {"de", "data-urlencode", ARG_STRING}, - {"D", "dump-header", ARG_STRING}, - {"e", "referer", ARG_STRING}, - {"E", "cert", ARG_STRING}, - {"Ea", "cacert", ARG_STRING}, - {"Eb", "cert-type", ARG_STRING}, - {"Ec", "key", ARG_STRING}, - {"Ed", "key-type", ARG_STRING}, - {"Ee", "pass", ARG_STRING}, - {"Ef", "engine", ARG_STRING}, - {"Eg", "capath", ARG_STRING}, - {"Eh", "pubkey", ARG_STRING}, - {"Ei", "hostpubmd5", ARG_STRING}, - {"Ej", "crlfile", ARG_STRING}, - {"Ek", "tlsuser", ARG_STRING}, - {"El", "tlspassword", ARG_STRING}, - {"Em", "tlsauthtype", ARG_STRING}, - {"En", "ssl-allow-beast", ARG_BOOL}, - {"Eo", "login-options", ARG_STRING}, - {"Ep", "pinnedpubkey", ARG_STRING}, - {"Eq", "cert-status", ARG_BOOL}, - {"Er", "false-start", ARG_BOOL}, - {"Es", "ssl-no-revoke", ARG_BOOL}, - {"Et", "tcp-fastopen", ARG_BOOL}, - {"Eu", "proxy-tlsuser", ARG_STRING}, - {"Ev", "proxy-tlspassword", ARG_STRING}, - {"Ew", "proxy-tlsauthtype", ARG_STRING}, - {"Ex", "proxy-cert", ARG_STRING}, - {"Ey", "proxy-cert-type", ARG_STRING}, - {"Ez", "proxy-key", ARG_STRING}, - {"E0", "proxy-key-type", ARG_STRING}, - {"E1", "proxy-pass", ARG_STRING}, - {"E2", "proxy-ciphers", ARG_STRING}, - {"E3", "proxy-crlfile", ARG_STRING}, - {"E4", "proxy-ssl-allow-beast", ARG_BOOL}, - {"E5", "login-options", ARG_STRING}, - {"E6", "proxy-cacert", ARG_STRING}, - {"E7", "proxy-capath", ARG_STRING}, - {"E8", "proxy-insecure", ARG_BOOL}, - {"E9", "proxy-tlsv1", ARG_NONE}, - {"EA", "socks5-basic", ARG_BOOL}, - {"EB", "socks5-gssapi", ARG_BOOL}, - {"f", "fail", ARG_BOOL}, - {"fa", "fail-early", ARG_BOOL}, - {"F", "form", ARG_STRING}, - {"Fs", "form-string", ARG_STRING}, - {"g", "globoff", ARG_BOOL}, - {"G", "get", ARG_NONE}, - {"Ga", "request-target", ARG_STRING}, - {"h", "help", ARG_BOOL}, - {"H", "header", ARG_STRING}, - {"Hp", "proxy-header", ARG_STRING}, - {"i", "include", ARG_BOOL}, - {"I", "head", ARG_BOOL}, - {"j", "junk-session-cookies", ARG_BOOL}, - {"J", "remote-header-name", ARG_BOOL}, - {"k", "insecure", ARG_BOOL}, - {"K", "config", ARG_STRING}, - {"l", "list-only", ARG_BOOL}, - {"L", "location", ARG_BOOL}, - {"Lt", "location-trusted", ARG_BOOL}, - {"m", "max-time", ARG_STRING}, - {"M", "manual", ARG_BOOL}, - {"n", "netrc", ARG_BOOL}, - {"no", "netrc-optional", ARG_BOOL}, - {"ne", "netrc-file", ARG_STRING}, - {"N", "buffer", ARG_BOOL}, - /* 'buffer' listed as --no-buffer in the help */ - {"o", "output", ARG_STRING}, - {"O", "remote-name", ARG_NONE}, - {"Oa", "remote-name-all", ARG_BOOL}, - {"p", "proxytunnel", ARG_BOOL}, - {"P", "ftp-port", ARG_STRING}, - {"q", "disable", ARG_BOOL}, - {"Q", "quote", ARG_STRING}, - {"r", "range", ARG_STRING}, - {"R", "remote-time", ARG_BOOL}, - {"s", "silent", ARG_BOOL}, - {"S", "show-error", ARG_BOOL}, - {"t", "telnet-option", ARG_STRING}, - {"T", "upload-file", ARG_STRING}, - {"u", "user", ARG_STRING}, - {"U", "proxy-user", ARG_STRING}, - {"v", "verbose", ARG_BOOL}, - {"V", "version", ARG_BOOL}, - {"w", "write-out", ARG_STRING}, - {"x", "proxy", ARG_STRING}, - {"xa", "preproxy", ARG_STRING}, - {"X", "request", ARG_STRING}, - {"Y", "speed-limit", ARG_STRING}, - {"y", "speed-time", ARG_STRING}, - {"z", "time-cond", ARG_STRING}, - {"#", "progress-bar", ARG_BOOL}, - {":", "next", ARG_NONE}, -}; - -/* Split the argument of -E to 'certname' and 'passphrase' separated by colon. - * We allow ':' and '\' to be escaped by '\' so that we can use certificate - * nicknames containing ':'. See - * for details. */ -#ifndef UNITTESTS -static -#endif -void parse_cert_parameter(const char *cert_parameter, - char **certname, - char **passphrase) -{ - size_t param_length = strlen(cert_parameter); - size_t span; - const char *param_place = NULL; - char *certname_place = NULL; - *certname = NULL; - *passphrase = NULL; - - /* most trivial assumption: cert_parameter is empty */ - if(param_length == 0) - return; - - /* next less trivial: cert_parameter starts 'pkcs11:' and thus - * looks like a RFC7512 PKCS#11 URI which can be used as-is. - * Also if cert_parameter contains no colon nor backslash, this - * means no passphrase was given and no characters escaped */ - if(!strncmp(cert_parameter, "pkcs11:", 7) || - !strpbrk(cert_parameter, ":\\")) { - *certname = strdup(cert_parameter); - return; - } - /* deal with escaped chars; find unescaped colon if it exists */ - certname_place = malloc(param_length + 1); - if(!certname_place) - return; - - *certname = certname_place; - param_place = cert_parameter; - while(*param_place) { - span = strcspn(param_place, ":\\"); - strncpy(certname_place, param_place, span); - param_place += span; - certname_place += span; - /* we just ate all the non-special chars. now we're on either a special - * char or the end of the string. */ - switch(*param_place) { - case '\0': - break; - case '\\': - param_place++; - switch(*param_place) { - case '\0': - *certname_place++ = '\\'; - break; - case '\\': - *certname_place++ = '\\'; - param_place++; - break; - case ':': - *certname_place++ = ':'; - param_place++; - break; - default: - *certname_place++ = '\\'; - *certname_place++ = *param_place; - param_place++; - break; - } - break; - case ':': - /* Since we live in a world of weirdness and confusion, the win32 - dudes can use : when using drive letters and thus c:\file:password - needs to work. In order not to break compatibility, we still use : as - separator, but we try to detect when it is used for a file name! On - windows. */ -#ifdef WIN32 - if(param_place && - (param_place == &cert_parameter[1]) && - (cert_parameter[2] == '\\' || cert_parameter[2] == '/') && - (ISALPHA(cert_parameter[0])) ) { - /* colon in the second column, followed by a backslash, and the - first character is an alphabetic letter: - - this is a drive letter colon */ - *certname_place++ = ':'; - param_place++; - break; - } -#endif - /* escaped colons and Windows drive letter colons were handled - * above; if we're still here, this is a separating colon */ - param_place++; - if(strlen(param_place) > 0) { - *passphrase = strdup(param_place); - } - goto done; - } - } -done: - *certname_place = '\0'; -} - -static void -GetFileAndPassword(char *nextarg, char **file, char **password) -{ - char *certname, *passphrase; - parse_cert_parameter(nextarg, &certname, &passphrase); - Curl_safefree(*file); - *file = certname; - if(passphrase) { - Curl_safefree(*password); - *password = passphrase; - } - cleanarg(nextarg); -} - -ParameterError getparameter(const char *flag, /* f or -long-flag */ - char *nextarg, /* NULL if unset */ - bool *usedarg, /* set to TRUE if the arg - has been used */ - struct GlobalConfig *global, - struct OperationConfig *config) -{ - char letter; - char subletter = '\0'; /* subletters can only occur on long options */ - int rc; - const char *parse = NULL; - unsigned int j; - time_t now; - int hit = -1; - bool longopt = FALSE; - bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ - ParameterError err; - bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled - by using --OPTION or --no-OPTION */ - - *usedarg = FALSE; /* default is that we don't use the arg */ - - if(('-' != flag[0]) || - (('-' == flag[0]) && ('-' == flag[1]))) { - /* this should be a long name */ - const char *word = ('-' == flag[0]) ? flag + 2 : flag; - size_t fnam = strlen(word); - int numhits = 0; - - if(!strncmp(word, "no-", 3)) { - /* disable this option but ignore the "no-" part when looking for it */ - word += 3; - toggle = FALSE; - } - - for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { - if(curl_strnequal(aliases[j].lname, word, fnam)) { - longopt = TRUE; - numhits++; - if(curl_strequal(aliases[j].lname, word)) { - parse = aliases[j].letter; - hit = j; - numhits = 1; /* a single unique hit */ - break; - } - parse = aliases[j].letter; - hit = j; - } - } - if(numhits > 1) { - /* this is at least the second match! */ - return PARAM_OPTION_AMBIGUOUS; - } - if(hit < 0) { - return PARAM_OPTION_UNKNOWN; - } - } - else { - flag++; /* prefixed with one dash, pass it */ - hit = -1; - parse = flag; - } - - do { - /* we can loop here if we have multiple single-letters */ - - if(!longopt) { - letter = (char)*parse; - subletter = '\0'; - } - else { - letter = parse[0]; - subletter = parse[1]; - } - - if(hit < 0) { - for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { - if(letter == aliases[j].letter[0]) { - hit = j; - break; - } - } - if(hit < 0) { - return PARAM_OPTION_UNKNOWN; - } - } - - if(aliases[hit].desc == ARG_STRING) { - /* this option requires an extra parameter */ - if(!longopt && parse[1]) { - nextarg = (char *)&parse[1]; /* this is the actual extra parameter */ - singleopt = TRUE; /* don't loop anymore after this */ - } - else if(!nextarg) - return PARAM_REQUIRES_PARAMETER; - else - *usedarg = TRUE; /* mark it as used */ - } - else if((aliases[hit].desc == ARG_NONE) && !toggle) - return PARAM_NO_PREFIX; - - switch(letter) { - case '*': /* options without a short option */ - switch(subletter) { - case '4': /* --dns-ipv4-addr */ - /* addr in dot notation */ - GetStr(&config->dns_ipv4_addr, nextarg); - break; - case '6': /* --dns-ipv6-addr */ - /* addr in dot notation */ - GetStr(&config->dns_ipv6_addr, nextarg); - break; - case 'a': /* random-file */ - GetStr(&config->random_file, nextarg); - break; - case 'b': /* egd-file */ - GetStr(&config->egd_file, nextarg); - break; - case 'B': /* OAuth 2.0 bearer token */ - GetStr(&config->oauth_bearer, nextarg); - break; - case 'c': /* connect-timeout */ - err = str2udouble(&config->connecttimeout, nextarg, - LONG_MAX/1000); - if(err) - return err; - break; - case 'd': /* ciphers */ - GetStr(&config->cipher_list, nextarg); - break; - case 'D': /* --dns-interface */ - /* interface name */ - GetStr(&config->dns_interface, nextarg); - break; - case 'e': /* --disable-epsv */ - config->disable_epsv = toggle; - break; - case 'E': /* --epsv */ - config->disable_epsv = (!toggle)?TRUE:FALSE; - break; - case 'F': /* --dns-servers */ - /* IP addrs of DNS servers */ - GetStr(&config->dns_servers, nextarg); - break; - case 'g': /* --trace */ - GetStr(&global->trace_dump, nextarg); - if(global->tracetype && (global->tracetype != TRACE_BIN)) - warnf(global, "--trace overrides an earlier trace/verbose option\n"); - global->tracetype = TRACE_BIN; - break; - case 'G': /* --npn */ - config->nonpn = (!toggle)?TRUE:FALSE; - break; - case 'h': /* --trace-ascii */ - GetStr(&global->trace_dump, nextarg); - if(global->tracetype && (global->tracetype != TRACE_ASCII)) - warnf(global, - "--trace-ascii overrides an earlier trace/verbose option\n"); - global->tracetype = TRACE_ASCII; - break; - case 'H': /* --alpn */ - config->noalpn = (!toggle)?TRUE:FALSE; - break; - case 'i': /* --limit-rate */ - { - /* We support G, M, K too */ - char *unit; - curl_off_t value; - if(curlx_strtoofft(nextarg, &unit, 0, &value)) { - warnf(global, "unsupported rate\n"); - return PARAM_BAD_USE; - } - - if(!*unit) - unit = (char *)"b"; - else if(strlen(unit) > 1) - unit = (char *)"w"; /* unsupported */ - - switch(*unit) { - case 'G': - case 'g': - value *= 1024*1024*1024; - break; - case 'M': - case 'm': - value *= 1024*1024; - break; - case 'K': - case 'k': - value *= 1024; - break; - case 'b': - case 'B': - /* for plain bytes, leave as-is */ - break; - default: - warnf(global, "unsupported rate unit. Use G, M, K or B!\n"); - return PARAM_BAD_USE; - } - config->recvpersecond = value; - config->sendpersecond = value; - } - break; - - case 'j': /* --compressed */ - if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ)) - return PARAM_LIBCURL_DOESNT_SUPPORT; - config->encoding = toggle; - break; - - case 'J': /* --tr-encoding */ - config->tr_encoding = toggle; - break; - - case 'k': /* --digest */ - if(toggle) - config->authtype |= CURLAUTH_DIGEST; - else - config->authtype &= ~CURLAUTH_DIGEST; - break; - - case 'l': /* --negotiate */ - if(toggle) { - if(curlinfo->features & CURL_VERSION_SPNEGO) - config->authtype |= CURLAUTH_NEGOTIATE; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - } - else - config->authtype &= ~CURLAUTH_NEGOTIATE; - break; - - case 'm': /* --ntlm */ - if(toggle) { - if(curlinfo->features & CURL_VERSION_NTLM) - config->authtype |= CURLAUTH_NTLM; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - } - else - config->authtype &= ~CURLAUTH_NTLM; - break; - - case 'M': /* --ntlm-wb */ - if(toggle) { - if(curlinfo->features & CURL_VERSION_NTLM_WB) - config->authtype |= CURLAUTH_NTLM_WB; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - } - else - config->authtype &= ~CURLAUTH_NTLM_WB; - break; - - case 'n': /* --basic for completeness */ - if(toggle) - config->authtype |= CURLAUTH_BASIC; - else - config->authtype &= ~CURLAUTH_BASIC; - break; - - case 'o': /* --anyauth, let libcurl pick it */ - if(toggle) - config->authtype = CURLAUTH_ANY; - /* --no-anyauth simply doesn't touch it */ - break; - -#ifdef USE_WATT32 - case 'p': /* --wdebug */ - dbug_init(); - break; -#endif - case 'q': /* --ftp-create-dirs */ - config->ftp_create_dirs = toggle; - break; - - case 'r': /* --create-dirs */ - config->create_dirs = toggle; - break; - - case 's': /* --max-redirs */ - /* specified max no of redirects (http(s)), this accepts -1 as a - special condition */ - err = str2num(&config->maxredirs, nextarg); - if(err) - return err; - if(config->maxredirs < -1) - return PARAM_BAD_NUMERIC; - break; - - case 't': /* --proxy-ntlm */ - if(curlinfo->features & CURL_VERSION_NTLM) - config->proxyntlm = toggle; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - - case 'u': /* --crlf */ - /* LF -> CRLF conversion? */ - config->crlf = toggle; - break; - - case 'v': /* --stderr */ - if(strcmp(nextarg, "-")) { - FILE *newfile = fopen(nextarg, FOPEN_WRITETEXT); - if(!newfile) - warnf(global, "Failed to open %s!\n", nextarg); - else { - if(global->errors_fopened) - fclose(global->errors); - global->errors = newfile; - global->errors_fopened = TRUE; - } - } - else - global->errors = stdout; - break; - case 'w': /* --interface */ - /* interface */ - GetStr(&config->iface, nextarg); - break; - case 'x': /* --krb */ - /* kerberos level string */ - if(curlinfo->features & CURL_VERSION_KERBEROS4) - GetStr(&config->krblevel, nextarg); - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - case 'y': /* --max-filesize */ - err = str2offset(&config->max_filesize, nextarg); - if(err) - return err; - break; - case 'z': /* --disable-eprt */ - config->disable_eprt = toggle; - break; - case 'Z': /* --eprt */ - config->disable_eprt = (!toggle)?TRUE:FALSE; - break; - case '~': /* --xattr */ - config->xattr = toggle; - break; - case '@': /* the URL! */ - { - struct getout *url; - - if(!config->url_get) - config->url_get = config->url_list; - - if(config->url_get) { - /* there's a node here, if it already is filled-in continue to find - an "empty" node */ - while(config->url_get && (config->url_get->flags & GETOUT_URL)) - config->url_get = config->url_get->next; - } - - /* now there might or might not be an available node to fill in! */ - - if(config->url_get) - /* existing node */ - url = config->url_get; - else - /* there was no free node, create one! */ - url = new_getout(config); - - if(!url) - return PARAM_NO_MEM; - - /* fill in the URL */ - GetStr(&url->url, nextarg); - url->flags |= GETOUT_URL; - } - } - break; - case '$': /* more options without a short option */ - switch(subletter) { - case 'a': /* --ssl */ - if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) - return PARAM_LIBCURL_DOESNT_SUPPORT; - config->ftp_ssl = toggle; - break; - case 'b': /* --ftp-pasv */ - Curl_safefree(config->ftpport); - break; - case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves - the name locally and passes on the resolved address */ - GetStr(&config->proxy, nextarg); - config->proxyver = CURLPROXY_SOCKS5; - break; - case 't': /* --socks4 specifies a socks4 proxy to use */ - GetStr(&config->proxy, nextarg); - config->proxyver = CURLPROXY_SOCKS4; - break; - case 'T': /* --socks4a specifies a socks4a proxy to use */ - GetStr(&config->proxy, nextarg); - config->proxyver = CURLPROXY_SOCKS4A; - break; - case '2': /* --socks5-hostname specifies a socks5 proxy and enables name - resolving with the proxy */ - GetStr(&config->proxy, nextarg); - config->proxyver = CURLPROXY_SOCKS5_HOSTNAME; - break; - case 'd': /* --tcp-nodelay option */ - config->tcp_nodelay = toggle; - break; - case 'e': /* --proxy-digest */ - config->proxydigest = toggle; - break; - case 'f': /* --proxy-basic */ - config->proxybasic = toggle; - break; - case 'g': /* --retry */ - err = str2unum(&config->req_retry, nextarg); - if(err) - return err; - break; - case 'V': /* --retry-connrefused */ - config->retry_connrefused = toggle; - break; - case 'h': /* --retry-delay */ - err = str2unum(&config->retry_delay, nextarg); - if(err) - return err; - break; - case 'i': /* --retry-max-time */ - err = str2unum(&config->retry_maxtime, nextarg); - if(err) - return err; - break; - - case 'k': /* --proxy-negotiate */ - if(curlinfo->features & CURL_VERSION_SPNEGO) - config->proxynegotiate = toggle; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - - case 'm': /* --ftp-account */ - GetStr(&config->ftp_account, nextarg); - break; - case 'n': /* --proxy-anyauth */ - config->proxyanyauth = toggle; - break; - case 'o': /* --trace-time */ - global->tracetime = toggle; - break; - case 'p': /* --ignore-content-length */ - config->ignorecl = toggle; - break; - case 'q': /* --ftp-skip-pasv-ip */ - config->ftp_skip_ip = toggle; - break; - case 'r': /* --ftp-method (undocumented at this point) */ - config->ftp_filemethod = ftpfilemethod(config, nextarg); - break; - case 's': /* --local-port */ - rc = sscanf(nextarg, "%d - %d", - &config->localport, - &config->localportrange); - if(!rc) - return PARAM_BAD_USE; - if(rc == 1) - config->localportrange = 1; /* default number of ports to try */ - else { - config->localportrange -= config->localport; - if(config->localportrange < 1) { - warnf(global, "bad range input\n"); - return PARAM_BAD_USE; - } - } - break; - case 'u': /* --ftp-alternative-to-user */ - GetStr(&config->ftp_alternative_to_user, nextarg); - break; - case 'v': /* --ssl-reqd */ - if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) - return PARAM_LIBCURL_DOESNT_SUPPORT; - config->ftp_ssl_reqd = toggle; - break; - case 'w': /* --no-sessionid */ - config->disable_sessionid = (!toggle)?TRUE:FALSE; - break; - case 'x': /* --ftp-ssl-control */ - if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) - return PARAM_LIBCURL_DOESNT_SUPPORT; - config->ftp_ssl_control = toggle; - break; - case 'y': /* --ftp-ssl-ccc */ - config->ftp_ssl_ccc = toggle; - if(!config->ftp_ssl_ccc_mode) - config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; - break; - case 'j': /* --ftp-ssl-ccc-mode */ - config->ftp_ssl_ccc = TRUE; - config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); - break; - case 'z': /* --libcurl */ -#ifdef CURL_DISABLE_LIBCURL_OPTION - warnf(global, - "--libcurl option was disabled at build-time!\n"); - return PARAM_OPTION_UNKNOWN; -#else - GetStr(&global->libcurl, nextarg); - break; -#endif - case '#': /* --raw */ - config->raw = toggle; - break; - case '0': /* --post301 */ - config->post301 = toggle; - break; - case '1': /* --no-keepalive */ - config->nokeepalive = (!toggle)?TRUE:FALSE; - break; - case '3': /* --keepalive-time */ - err = str2unum(&config->alivetime, nextarg); - if(err) - return err; - break; - case '4': /* --post302 */ - config->post302 = toggle; - break; - case 'I': /* --post303 */ - config->post303 = toggle; - break; - case '5': /* --noproxy */ - /* This specifies the noproxy list */ - GetStr(&config->noproxy, nextarg); - break; - case '7': /* --socks5-gssapi-nec*/ - config->socks5_gssapi_nec = toggle; - break; - case '8': /* --proxy1.0 */ - /* http 1.0 proxy */ - GetStr(&config->proxy, nextarg); - config->proxyver = CURLPROXY_HTTP_1_0; - break; - case '9': /* --tftp-blksize */ - err = str2unum(&config->tftp_blksize, nextarg); - if(err) - return err; - break; - case 'A': /* --mail-from */ - GetStr(&config->mail_from, nextarg); - break; - case 'B': /* --mail-rcpt */ - /* append receiver to a list */ - err = add2list(&config->mail_rcpt, nextarg); - if(err) - return err; - break; - case 'C': /* --ftp-pret */ - config->ftp_pret = toggle; - break; - case 'D': /* --proto */ - config->proto_present = TRUE; - if(proto2num(config, &config->proto, nextarg)) - return PARAM_BAD_USE; - break; - case 'E': /* --proto-redir */ - config->proto_redir_present = TRUE; - if(proto2num(config, &config->proto_redir, nextarg)) - return PARAM_BAD_USE; - break; - case 'F': /* --resolve */ - err = add2list(&config->resolve, nextarg); - if(err) - return err; - break; - case 'G': /* --delegation LEVEL */ - config->gssapi_delegation = delegation(config, nextarg); - break; - case 'H': /* --mail-auth */ - GetStr(&config->mail_auth, nextarg); - break; - case 'J': /* --metalink */ - { -#ifdef USE_METALINK - int mlmaj, mlmin, mlpatch; - metalink_get_version(&mlmaj, &mlmin, &mlpatch); - if((mlmaj*10000)+(mlmin*100) + mlpatch < CURL_REQ_LIBMETALINK_VERS) { - warnf(global, - "--metalink option cannot be used because the version of " - "the linked libmetalink library is too old. " - "Required: %d.%d.%d, found %d.%d.%d\n", - CURL_REQ_LIBMETALINK_MAJOR, - CURL_REQ_LIBMETALINK_MINOR, - CURL_REQ_LIBMETALINK_PATCH, - mlmaj, mlmin, mlpatch); - return PARAM_BAD_USE; - } - else - config->use_metalink = toggle; -#else - warnf(global, "--metalink option is ignored because the binary is " - "built without the Metalink support.\n"); -#endif - break; - } - case 'K': /* --sasl-ir */ - config->sasl_ir = toggle; - break; - case 'L': /* --test-event */ -#ifdef CURLDEBUG - config->test_event_based = toggle; -#else - warnf(global, "--test-event is ignored unless a debug build!\n"); -#endif - break; - case 'M': /* --unix-socket */ - config->abstract_unix_socket = FALSE; - GetStr(&config->unix_socket_path, nextarg); - break; - case 'N': /* --path-as-is */ - config->path_as_is = toggle; - break; - case 'O': /* --proxy-service-name */ - GetStr(&config->proxy_service_name, nextarg); - break; - case 'P': /* --service-name */ - GetStr(&config->service_name, nextarg); - break; - case 'Q': /* --proto-default */ - GetStr(&config->proto_default, nextarg); - err = check_protocol(config->proto_default); - if(err) - return err; - break; - case 'R': /* --expect100-timeout */ - err = str2udouble(&config->expect100timeout, nextarg, LONG_MAX/1000); - if(err) - return err; - break; - case 'S': /* --tftp-no-options */ - config->tftp_no_options = toggle; - break; - case 'U': /* --connect-to */ - err = add2list(&config->connect_to, nextarg); - if(err) - return err; - break; - case 'W': /* --abstract-unix-socket */ - config->abstract_unix_socket = TRUE; - GetStr(&config->unix_socket_path, nextarg); - break; - case 'X': /* --tls-max */ - err = str2tls_max(&config->ssl_version_max, nextarg); - if(err) - return err; - break; - case 'Y': /* --suppress-connect-headers */ - config->suppress_connect_headers = toggle; - break; - case 'Z': /* --compressed-ssh */ - config->ssh_compression = toggle; - break; - } - break; - case '#': /* --progress-bar */ - if(toggle) - global->progressmode = CURL_PROGRESS_BAR; - else - global->progressmode = CURL_PROGRESS_STATS; - break; - case ':': /* --next */ - return PARAM_NEXT_OPERATION; - case '0': /* --http* options */ - switch(subletter) { - case '\0': - /* HTTP version 1.0 */ - config->httpversion = CURL_HTTP_VERSION_1_0; - break; - case '1': - /* HTTP version 1.1 */ - config->httpversion = CURL_HTTP_VERSION_1_1; - break; - case '2': - /* HTTP version 2.0 */ - config->httpversion = CURL_HTTP_VERSION_2_0; - break; - case '3': - /* HTTP version 2.0 over clean TCP*/ - config->httpversion = CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE; - break; - } - break; - case '1': /* --tlsv1* options */ - switch(subletter) { - case '\0': - /* TLS version 1.x */ - config->ssl_version = CURL_SSLVERSION_TLSv1; - break; - case '0': - /* TLS version 1.0 */ - config->ssl_version = CURL_SSLVERSION_TLSv1_0; - break; - case '1': - /* TLS version 1.1 */ - config->ssl_version = CURL_SSLVERSION_TLSv1_1; - break; - case '2': - /* TLS version 1.2 */ - config->ssl_version = CURL_SSLVERSION_TLSv1_2; - break; - case '3': - /* TLS version 1.3 */ - config->ssl_version = CURL_SSLVERSION_TLSv1_3; - break; - } - break; - case '2': - /* SSL version 2 */ - config->ssl_version = CURL_SSLVERSION_SSLv2; - break; - case '3': - /* SSL version 3 */ - config->ssl_version = CURL_SSLVERSION_SSLv3; - break; - case '4': - /* IPv4 */ - config->ip_version = 4; - break; - case '6': - /* IPv6 */ - config->ip_version = 6; - break; - case 'a': - /* This makes the FTP sessions use APPE instead of STOR */ - config->ftp_append = toggle; - break; - case 'A': - /* This specifies the User-Agent name */ - GetStr(&config->useragent, nextarg); - break; - case 'b': /* cookie string coming up: */ - if(nextarg[0] == '@') { - nextarg++; - } - else if(strchr(nextarg, '=')) { - /* A cookie string must have a =-letter */ - GetStr(&config->cookie, nextarg); - break; - } - /* We have a cookie file to read from! */ - GetStr(&config->cookiefile, nextarg); - break; - case 'B': - /* use ASCII/text when transferring */ - config->use_ascii = toggle; - break; - case 'c': - /* get the file name to dump all cookies in */ - GetStr(&config->cookiejar, nextarg); - break; - case 'C': - /* This makes us continue an ftp transfer at given position */ - if(strcmp(nextarg, "-")) { - err = str2offset(&config->resume_from, nextarg); - if(err) - return err; - config->resume_from_current = FALSE; - } - else { - config->resume_from_current = TRUE; - config->resume_from = 0; - } - config->use_resume = TRUE; - break; - case 'd': - /* postfield data */ - { - char *postdata = NULL; - FILE *file; - size_t size = 0; - bool raw_mode = (subletter == 'r'); - - if(subletter == 'e') { /* --data-urlencode*/ - /* [name]=[content], we encode the content part only - * [name]@[file name] - * - * Case 2: we first load the file using that name and then encode - * the content. - */ - const char *p = strchr(nextarg, '='); - size_t nlen; - char is_file; - if(!p) - /* there was no '=' letter, check for a '@' instead */ - p = strchr(nextarg, '@'); - if(p) { - nlen = p - nextarg; /* length of the name part */ - is_file = *p++; /* pass the separator */ - } - else { - /* neither @ nor =, so no name and it isn't a file */ - nlen = is_file = 0; - p = nextarg; - } - if('@' == is_file) { - /* a '@' letter, it means that a file name or - (stdin) follows */ - if(!strcmp("-", p)) { - file = stdin; - set_binmode(stdin); - } - else { - file = fopen(p, "rb"); - if(!file) - warnf(global, - "Couldn't read data from file \"%s\", this makes " - "an empty POST.\n", nextarg); - } - - err = file2memory(&postdata, &size, file); - - if(file && (file != stdin)) - fclose(file); - if(err) - return err; - } - else { - GetStr(&postdata, p); - if(postdata) - size = strlen(postdata); - } - - if(!postdata) { - /* no data from the file, point to a zero byte string to make this - get sent as a POST anyway */ - postdata = strdup(""); - if(!postdata) - return PARAM_NO_MEM; - size = 0; - } - else { - char *enc = curl_easy_escape(config->easy, postdata, (int)size); - Curl_safefree(postdata); /* no matter if it worked or not */ - if(enc) { - /* now make a string with the name from above and append the - encoded string */ - size_t outlen = nlen + strlen(enc) + 2; - char *n = malloc(outlen); - if(!n) { - curl_free(enc); - return PARAM_NO_MEM; - } - if(nlen > 0) { /* only append '=' if we have a name */ - snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc); - size = outlen-1; - } - else { - strcpy(n, enc); - size = outlen-2; /* since no '=' was inserted */ - } - curl_free(enc); - postdata = n; - } - else - return PARAM_NO_MEM; - } - } - else if('@' == *nextarg && !raw_mode) { - /* the data begins with a '@' letter, it means that a file name - or - (stdin) follows */ - nextarg++; /* pass the @ */ - - if(!strcmp("-", nextarg)) { - file = stdin; - if(subletter == 'b') /* forced data-binary */ - set_binmode(stdin); - } - else { - file = fopen(nextarg, "rb"); - if(!file) - warnf(global, "Couldn't read data from file \"%s\", this makes " - "an empty POST.\n", nextarg); - } - - if(subletter == 'b') - /* forced binary */ - err = file2memory(&postdata, &size, file); - else { - err = file2string(&postdata, file); - if(postdata) - size = strlen(postdata); - } - - if(file && (file != stdin)) - fclose(file); - if(err) - return err; - - if(!postdata) { - /* no data from the file, point to a zero byte string to make this - get sent as a POST anyway */ - postdata = strdup(""); - if(!postdata) - return PARAM_NO_MEM; - } - } - else { - GetStr(&postdata, nextarg); - if(postdata) - size = strlen(postdata); - } - -#ifdef CURL_DOES_CONVERSIONS - if(subletter != 'b') { - /* NOT forced binary, convert to ASCII */ - if(convert_to_network(postdata, strlen(postdata))) { - Curl_safefree(postdata); - return PARAM_NO_MEM; - } - } -#endif - - if(config->postfields) { - /* we already have a string, we append this one with a separating - &-letter */ - char *oldpost = config->postfields; - curl_off_t oldlen = config->postfieldsize; - curl_off_t newlen = oldlen + curlx_uztoso(size) + 2; - config->postfields = malloc((size_t)newlen); - if(!config->postfields) { - Curl_safefree(oldpost); - Curl_safefree(postdata); - return PARAM_NO_MEM; - } - memcpy(config->postfields, oldpost, (size_t)oldlen); - /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */ - config->postfields[oldlen] = '\x26'; - memcpy(&config->postfields[oldlen + 1], postdata, size); - config->postfields[oldlen + 1 + size] = '\0'; - Curl_safefree(oldpost); - Curl_safefree(postdata); - config->postfieldsize += size + 1; - } - else { - config->postfields = postdata; - config->postfieldsize = curlx_uztoso(size); - } - } - /* - We can't set the request type here, as this data might be used in - a simple GET if -G is used. Already or soon. - - if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) { - Curl_safefree(postdata); - return PARAM_BAD_USE; - } - */ - break; - case 'D': - /* dump-header to given file name */ - GetStr(&config->headerfile, nextarg); - break; - case 'e': - { - char *ptr = strstr(nextarg, ";auto"); - if(ptr) { - /* Automatic referer requested, this may be combined with a - set initial one */ - config->autoreferer = TRUE; - *ptr = 0; /* zero terminate here */ - } - else - config->autoreferer = FALSE; - GetStr(&config->referer, nextarg); - } - break; - case 'E': - switch(subletter) { - case '\0': /* certificate file */ - GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); - break; - case 'a': /* CA info PEM file */ - /* CA info PEM file */ - GetStr(&config->cacert, nextarg); - break; - case 'b': /* cert file type */ - GetStr(&config->cert_type, nextarg); - break; - case 'c': /* private key file */ - GetStr(&config->key, nextarg); - break; - case 'd': /* private key file type */ - GetStr(&config->key_type, nextarg); - break; - case 'e': /* private key passphrase */ - GetStr(&config->key_passwd, nextarg); - cleanarg(nextarg); - break; - case 'f': /* crypto engine */ - GetStr(&config->engine, nextarg); - if(config->engine && curl_strequal(config->engine, "list")) - return PARAM_ENGINES_REQUESTED; - break; - case 'g': /* CA info PEM file */ - /* CA cert directory */ - GetStr(&config->capath, nextarg); - break; - case 'h': /* --pubkey public key file */ - GetStr(&config->pubkey, nextarg); - break; - case 'i': /* --hostpubmd5 md5 of the host public key */ - GetStr(&config->hostpubmd5, nextarg); - if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) - return PARAM_BAD_USE; - break; - case 'j': /* CRL info PEM file */ - /* CRL file */ - GetStr(&config->crlfile, nextarg); - break; - case 'k': /* TLS username */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) - GetStr(&config->tls_username, nextarg); - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - case 'l': /* TLS password */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) - GetStr(&config->tls_password, nextarg); - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - case 'm': /* TLS authentication type */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { - GetStr(&config->tls_authtype, nextarg); - if(!curl_strequal(config->tls_authtype, "SRP")) - return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ - } - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - case 'n': /* no empty SSL fragments, --ssl-allow-beast */ - if(curlinfo->features & CURL_VERSION_SSL) - config->ssl_allow_beast = toggle; - break; - - case 'o': /* --login-options */ - GetStr(&config->login_options, nextarg); - break; - - case 'p': /* Pinned public key DER file */ - /* Pinned public key DER file */ - GetStr(&config->pinnedpubkey, nextarg); - break; - - case 'q': /* --cert-status */ - config->verifystatus = TRUE; - break; - - case 'r': /* --false-start */ - config->falsestart = TRUE; - break; - - case 's': /* --ssl-no-revoke */ - if(curlinfo->features & CURL_VERSION_SSL) - config->ssl_no_revoke = TRUE; - break; - - case 't': /* --tcp-fastopen */ - config->tcp_fastopen = TRUE; - break; - - case 'u': /* TLS username for proxy */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) - GetStr(&config->proxy_tls_username, nextarg); - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - - case 'v': /* TLS password for proxy */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) - GetStr(&config->proxy_tls_password, nextarg); - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - - case 'w': /* TLS authentication type for proxy */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { - GetStr(&config->proxy_tls_authtype, nextarg); - if(!curl_strequal(config->proxy_tls_authtype, "SRP")) - return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ - } - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - - case 'x': /* certificate file for proxy */ - GetFileAndPassword(nextarg, &config->proxy_cert, - &config->proxy_key_passwd); - break; - - case 'y': /* cert file type for proxy */ - GetStr(&config->proxy_cert_type, nextarg); - break; - - case 'z': /* private key file for proxy */ - GetStr(&config->proxy_key, nextarg); - break; - - case '0': /* private key file type for proxy */ - GetStr(&config->proxy_key_type, nextarg); - break; - - case '1': /* private key passphrase for proxy */ - GetStr(&config->proxy_key_passwd, nextarg); - cleanarg(nextarg); - break; - - case '2': /* ciphers for proxy */ - GetStr(&config->proxy_cipher_list, nextarg); - break; - - case '3': /* CRL info PEM file for proxy */ - /* CRL file */ - GetStr(&config->proxy_crlfile, nextarg); - break; - - case '4': /* no empty SSL fragments for proxy */ - if(curlinfo->features & CURL_VERSION_SSL) - config->proxy_ssl_allow_beast = toggle; - break; - - case '5': /* --login-options */ - GetStr(&config->login_options, nextarg); - break; - - case '6': /* CA info PEM file for proxy */ - /* CA info PEM file */ - GetStr(&config->proxy_cacert, nextarg); - break; - - case '7': /* CA info PEM file for proxy */ - /* CA cert directory */ - GetStr(&config->proxy_capath, nextarg); - break; - - case '8': /* allow insecure SSL connects for proxy */ - config->proxy_insecure_ok = toggle; - break; - - case '9': /* --proxy-tlsv1 */ - /* TLS version 1 for proxy */ - config->proxy_ssl_version = CURL_SSLVERSION_TLSv1; - break; - - case 'A': - /* --socks5-basic */ - if(toggle) - config->socks5_auth |= CURLAUTH_BASIC; - else - config->socks5_auth &= ~CURLAUTH_BASIC; - break; - - case 'B': - /* --socks5-gssapi */ - if(toggle) - config->socks5_auth |= CURLAUTH_GSSAPI; - else - config->socks5_auth &= ~CURLAUTH_GSSAPI; - break; - - default: /* unknown flag */ - return PARAM_OPTION_UNKNOWN; - } - break; - case 'f': - switch(subletter) { - case 'a': /* --fail-early */ - global->fail_early = toggle; - break; - default: - /* fail hard on errors */ - config->failonerror = toggle; - } - break; - case 'F': - /* "form data" simulation, this is a little advanced so lets do our best - to sort this out slowly and carefully */ - if(formparse(config, - nextarg, - &config->mimepost, - &config->mimecurrent, - (subletter == 's')?TRUE:FALSE)) /* 's' is literal string */ - return PARAM_BAD_USE; - if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq)) - return PARAM_BAD_USE; - break; - - case 'g': /* g disables URLglobbing */ - config->globoff = toggle; - break; - - case 'G': /* HTTP GET */ - if(subletter == 'a') { /* --request-target */ - GetStr(&config->request_target, nextarg); - } - else - config->use_httpget = TRUE; - break; - - case 'h': /* h for help */ - if(toggle) { - return PARAM_HELP_REQUESTED; - } - /* we now actually support --no-help too! */ - break; - case 'H': - /* A custom header to append to a list */ - if(nextarg[0] == '@') { - /* read many headers from a file or stdin */ - char *string; - size_t len; - bool use_stdin = !strcmp(&nextarg[1], "-"); - FILE *file = use_stdin?stdin:fopen(&nextarg[1], FOPEN_READTEXT); - if(!file) - warnf(global, "Failed to open %s!\n", &nextarg[1]); - else { - err = file2memory(&string, &len, file); - if(!err) { - /* Allow strtok() here since this isn't used threaded */ - /* !checksrc! disable BANNEDFUNC 2 */ - char *h = strtok(string, "\r\n"); - while(h) { - if(subletter == 'p') /* --proxy-header */ - err = add2list(&config->proxyheaders, h); - else - err = add2list(&config->headers, h); - if(err) - break; - h = strtok(NULL, "\r\n"); - } - free(string); - } - if(!use_stdin) - fclose(file); - if(err) - return err; - } - } - else { - if(subletter == 'p') /* --proxy-header */ - err = add2list(&config->proxyheaders, nextarg); - else - err = add2list(&config->headers, nextarg); - if(err) - return err; - } - break; - case 'i': - config->include_headers = toggle; /* include the headers as well in the - general output stream */ - break; - case 'j': - config->cookiesession = toggle; - break; - case 'I': - /* - * no_body will imply include_headers later on - */ - config->no_body = toggle; - if(SetHTTPrequest(config, - (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET, - &config->httpreq)) - return PARAM_BAD_USE; - break; - case 'J': /* --remote-header-name */ - if(config->include_headers) { - warnf(global, - "--include and --remote-header-name cannot be combined.\n"); - return PARAM_BAD_USE; - } - config->content_disposition = toggle; - break; - case 'k': /* allow insecure SSL connects */ - config->insecure_ok = toggle; - break; - case 'K': /* parse config file */ - if(parseconfig(nextarg, global)) - warnf(global, "error trying read config from the '%s' file\n", - nextarg); - break; - case 'l': - config->dirlistonly = toggle; /* only list the names of the FTP dir */ - break; - case 'L': - config->followlocation = toggle; /* Follow Location: HTTP headers */ - switch(subletter) { - case 't': - /* Continue to send authentication (user+password) when following - * locations, even when hostname changed */ - config->unrestricted_auth = toggle; - break; - } - break; - case 'm': - /* specified max time */ - err = str2udouble(&config->timeout, nextarg, LONG_MAX/1000); - if(err) - return err; - break; - case 'M': /* M for manual, huge help */ - if(toggle) { /* --no-manual shows no manual... */ -#ifdef USE_MANUAL - return PARAM_MANUAL_REQUESTED; -#else - warnf(global, - "built-in manual was disabled at build-time!\n"); - return PARAM_OPTION_UNKNOWN; -#endif - } - break; - case 'n': - switch(subletter) { - case 'o': /* CA info PEM file */ - /* use .netrc or URL */ - config->netrc_opt = toggle; - break; - case 'e': /* netrc-file */ - GetStr(&config->netrc_file, nextarg); - break; - default: - /* pick info from .netrc, if this is used for http, curl will - automatically enfore user+password with the request */ - config->netrc = toggle; - break; - } - break; - case 'N': - /* disable the output I/O buffering. note that the option is called - --buffer but is mostly used in the negative form: --no-buffer */ - if(longopt) - config->nobuffer = (!toggle)?TRUE:FALSE; - else - config->nobuffer = toggle; - break; - case 'O': /* --remote-name */ - if(subletter == 'a') { /* --remote-name-all */ - config->default_node_flags = toggle?GETOUT_USEREMOTE:0; - break; - } - /* fall-through! */ - case 'o': /* --output */ - /* output file */ - { - struct getout *url; - if(!config->url_out) - config->url_out = config->url_list; - if(config->url_out) { - /* there's a node here, if it already is filled-in continue to find - an "empty" node */ - while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE)) - config->url_out = config->url_out->next; - } - - /* now there might or might not be an available node to fill in! */ - - if(config->url_out) - /* existing node */ - url = config->url_out; - else - /* there was no free node, create one! */ - url = new_getout(config); - - if(!url) - return PARAM_NO_MEM; - - /* fill in the outfile */ - if('o' == letter) { - GetStr(&url->outfile, nextarg); - url->flags &= ~GETOUT_USEREMOTE; /* switch off */ - } - else { - url->outfile = NULL; /* leave it */ - if(toggle) - url->flags |= GETOUT_USEREMOTE; /* switch on */ - else - url->flags &= ~GETOUT_USEREMOTE; /* switch off */ - } - url->flags |= GETOUT_OUTFILE; - } - break; - case 'P': - /* This makes the FTP sessions use PORT instead of PASV */ - /* use or <192.168.10.10> style addresses. Anything except - this will make us try to get the "default" address. - NOTE: this is a changed behaviour since the released 4.1! - */ - GetStr(&config->ftpport, nextarg); - break; - case 'p': - /* proxy tunnel for non-http protocols */ - config->proxytunnel = toggle; - break; - - case 'q': /* if used first, already taken care of, we do it like - this so we don't cause an error! */ - break; - case 'Q': - /* QUOTE command to send to FTP server */ - switch(nextarg[0]) { - case '-': - /* prefixed with a dash makes it a POST TRANSFER one */ - nextarg++; - err = add2list(&config->postquote, nextarg); - break; - case '+': - /* prefixed with a plus makes it a just-before-transfer one */ - nextarg++; - err = add2list(&config->prequote, nextarg); - break; - default: - err = add2list(&config->quote, nextarg); - break; - } - if(err) - return err; - break; - case 'r': - /* Specifying a range WITHOUT A DASH will create an illegal HTTP range - (and won't actually be range by definition). The man page previously - claimed that to be a good way, why this code is added to work-around - it. */ - if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) { - char buffer[32]; - curl_off_t off; - if(curlx_strtoofft(nextarg, NULL, 10, &off)) { - warnf(global, "unsupported range point\n"); - return PARAM_BAD_USE; - } - warnf(global, - "A specified range MUST include at least one dash (-). " - "Appending one for you!\n"); - snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off); - Curl_safefree(config->range); - config->range = strdup(buffer); - if(!config->range) - return PARAM_NO_MEM; - } - { - /* byte range requested */ - char *tmp_range; - tmp_range = nextarg; - while(*tmp_range != '\0') { - if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') { - warnf(global, "Invalid character is found in given range. " - "A specified range MUST have only digits in " - "\'start\'-\'stop\'. The server's response to this " - "request is uncertain.\n"); - break; - } - tmp_range++; - } - /* byte range requested */ - GetStr(&config->range, nextarg); - } - break; - case 'R': - /* use remote file's time */ - config->remote_time = toggle; - break; - case 's': - /* don't show progress meter, don't show errors : */ - if(toggle) - global->mute = global->noprogress = TRUE; - else - global->mute = global->noprogress = FALSE; - if(global->showerror < 0) - /* if still on the default value, set showerror to the reverse of - toggle. This is to allow -S and -s to be used in an independent - order but still have the same effect. */ - global->showerror = (!toggle)?TRUE:FALSE; /* toggle off */ - break; - case 'S': - /* show errors */ - global->showerror = toggle?1:0; /* toggle on if used with -s */ - break; - case 't': - /* Telnet options */ - err = add2list(&config->telnet_options, nextarg); - if(err) - return err; - break; - case 'T': - /* we are uploading */ - { - struct getout *url; - if(!config->url_out) - config->url_out = config->url_list; - if(config->url_out) { - /* there's a node here, if it already is filled-in continue to find - an "empty" node */ - while(config->url_out && (config->url_out->flags & GETOUT_UPLOAD)) - config->url_out = config->url_out->next; - } - - /* now there might or might not be an available node to fill in! */ - - if(config->url_out) - /* existing node */ - url = config->url_out; - else - /* there was no free node, create one! */ - url = new_getout(config); - - if(!url) - return PARAM_NO_MEM; - - url->flags |= GETOUT_UPLOAD; /* mark -T used */ - if(!*nextarg) - url->flags |= GETOUT_NOUPLOAD; - else { - /* "-" equals stdin, but keep the string around for now */ - GetStr(&url->infile, nextarg); - } - } - break; - case 'u': - /* user:password */ - GetStr(&config->userpwd, nextarg); - cleanarg(nextarg); - break; - case 'U': - /* Proxy user:password */ - GetStr(&config->proxyuserpwd, nextarg); - cleanarg(nextarg); - break; - case 'v': - if(toggle) { - /* the '%' thing here will cause the trace get sent to stderr */ - Curl_safefree(global->trace_dump); - global->trace_dump = strdup("%"); - if(!global->trace_dump) - return PARAM_NO_MEM; - if(global->tracetype && (global->tracetype != TRACE_PLAIN)) - warnf(global, - "-v, --verbose overrides an earlier trace/verbose option\n"); - global->tracetype = TRACE_PLAIN; - } - else - /* verbose is disabled here */ - global->tracetype = TRACE_NONE; - break; - case 'V': - if(toggle) /* --no-version yields no output! */ - return PARAM_VERSION_INFO_REQUESTED; - break; - - case 'w': - /* get the output string */ - if('@' == *nextarg) { - /* the data begins with a '@' letter, it means that a file name - or - (stdin) follows */ - FILE *file; - const char *fname; - nextarg++; /* pass the @ */ - if(!strcmp("-", nextarg)) { - fname = ""; - file = stdin; - } - else { - fname = nextarg; - file = fopen(nextarg, FOPEN_READTEXT); - } - err = file2string(&config->writeout, file); - if(file && (file != stdin)) - fclose(file); - if(err) - return err; - if(!config->writeout) - warnf(global, "Failed to read %s", fname); - } - else - GetStr(&config->writeout, nextarg); - break; - case 'x': - switch(subletter) { - case 'a': /* --preproxy */ - GetStr(&config->preproxy, nextarg); - break; - default: - /* --proxy */ - GetStr(&config->proxy, nextarg); - config->proxyver = CURLPROXY_HTTP; - break; - } - break; - case 'X': - /* set custom request */ - GetStr(&config->customrequest, nextarg); - break; - case 'y': - /* low speed time */ - err = str2unum(&config->low_speed_time, nextarg); - if(err) - return err; - if(!config->low_speed_limit) - config->low_speed_limit = 1; - break; - case 'Y': - /* low speed limit */ - err = str2unum(&config->low_speed_limit, nextarg); - if(err) - return err; - if(!config->low_speed_time) - config->low_speed_time = 30; - break; - case 'z': /* time condition coming up */ - switch(*nextarg) { - case '+': - nextarg++; - /* FALLTHROUGH */ - default: - /* If-Modified-Since: (section 14.28 in RFC2068) */ - config->timecond = CURL_TIMECOND_IFMODSINCE; - break; - case '-': - /* If-Unmodified-Since: (section 14.24 in RFC2068) */ - config->timecond = CURL_TIMECOND_IFUNMODSINCE; - nextarg++; - break; - case '=': - /* Last-Modified: (section 14.29 in RFC2068) */ - config->timecond = CURL_TIMECOND_LASTMOD; - nextarg++; - break; - } - now = time(NULL); - config->condtime = curl_getdate(nextarg, &now); - if(-1 == (int)config->condtime) { - /* now let's see if it is a file name to get the time from instead! */ - struct_stat statbuf; - if(-1 == stat(nextarg, &statbuf)) { - /* failed, remove time condition */ - config->timecond = CURL_TIMECOND_NONE; - warnf(global, - "Illegal date format for -z, --time-cond (and not " - "a file name). Disabling time condition. " - "See curl_getdate(3) for valid date syntax.\n"); - } - else { - /* pull the time out from the file */ - config->condtime = statbuf.st_mtime; - } - } - break; - default: /* unknown flag */ - return PARAM_OPTION_UNKNOWN; - } - hit = -1; - - } while(!longopt && !singleopt && *++parse && !*usedarg); - - return PARAM_OK; -} - -ParameterError parse_args(struct GlobalConfig *config, int argc, - argv_item_t argv[]) -{ - int i; - bool stillflags; - char *orig_opt = NULL; - ParameterError result = PARAM_OK; - struct OperationConfig *operation = config->first; - - for(i = 1, stillflags = TRUE; i < argc && !result; i++) { - orig_opt = argv[i]; - - if(stillflags && ('-' == argv[i][0])) { - char *nextarg; - bool passarg; - char *flag = argv[i]; - - if(!strcmp("--", argv[i])) - /* This indicates the end of the flags and thus enables the - following (URL) argument to start with -. */ - stillflags = FALSE; - else { - nextarg = (i < (argc - 1)) ? argv[i + 1] : NULL; - - result = getparameter(flag, nextarg, &passarg, config, operation); - if(result == PARAM_NEXT_OPERATION) { - /* Reset result as PARAM_NEXT_OPERATION is only used here and not - returned from this function */ - result = PARAM_OK; - - if(operation->url_list && operation->url_list->url) { - /* Allocate the next config */ - operation->next = malloc(sizeof(struct OperationConfig)); - if(operation->next) { - /* Initialise the newly created config */ - config_init(operation->next); - - /* Copy the easy handle */ - operation->next->easy = config->easy; - - /* Set the global config pointer */ - operation->next->global = config; - - /* Update the last operation pointer */ - config->last = operation->next; - - /* Move onto the new config */ - operation->next->prev = operation; - operation = operation->next; - } - else - result = PARAM_NO_MEM; - } - } - else if(!result && passarg) - i++; /* we're supposed to skip this */ - } - } - else { - bool used; - - /* Just add the URL please */ - result = getparameter((char *)"--url", argv[i], &used, config, - operation); - } - } - - if(result && result != PARAM_HELP_REQUESTED && - result != PARAM_MANUAL_REQUESTED && - result != PARAM_VERSION_INFO_REQUESTED && - result != PARAM_ENGINES_REQUESTED) { - const char *reason = param2text(result); - - if(orig_opt && strcmp(":", orig_opt)) - helpf(config->errors, "option %s: %s\n", orig_opt, reason); - else - helpf(config->errors, "%s\n", reason); - } - - return result; -} diff --git a/dep/cpr/opt/curl/src/tool_getparam.h b/dep/cpr/opt/curl/src/tool_getparam.h deleted file mode 100644 index 2148e409184..00000000000 --- a/dep/cpr/opt/curl/src/tool_getparam.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef HEADER_CURL_TOOL_GETPARAM_H -#define HEADER_CURL_TOOL_GETPARAM_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -typedef enum { - PARAM_OK = 0, - PARAM_OPTION_AMBIGUOUS, - PARAM_OPTION_UNKNOWN, - PARAM_REQUIRES_PARAMETER, - PARAM_BAD_USE, - PARAM_HELP_REQUESTED, - PARAM_MANUAL_REQUESTED, - PARAM_VERSION_INFO_REQUESTED, - PARAM_ENGINES_REQUESTED, - PARAM_GOT_EXTRA_PARAMETER, - PARAM_BAD_NUMERIC, - PARAM_NEGATIVE_NUMERIC, - PARAM_LIBCURL_DOESNT_SUPPORT, - PARAM_LIBCURL_UNSUPPORTED_PROTOCOL, - PARAM_NO_MEM, - PARAM_NEXT_OPERATION, - PARAM_NO_PREFIX, - PARAM_NUMBER_TOO_LARGE, - PARAM_LAST -} ParameterError; - -struct GlobalConfig; -struct OperationConfig; - -ParameterError getparameter(const char *flag, char *nextarg, bool *usedarg, - struct GlobalConfig *global, - struct OperationConfig *operation); - -#ifdef UNITTESTS -void parse_cert_parameter(const char *cert_parameter, - char **certname, - char **passphrase); -#endif - -ParameterError parse_args(struct GlobalConfig *config, int argc, - argv_item_t argv[]); - -#endif /* HEADER_CURL_TOOL_GETPARAM_H */ - diff --git a/dep/cpr/opt/curl/src/tool_getpass.c b/dep/cpr/opt/curl/src/tool_getpass.c deleted file mode 100644 index e5e2d6dc1e5..00000000000 --- a/dep/cpr/opt/curl/src/tool_getpass.c +++ /dev/null @@ -1,254 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#ifndef HAVE_GETPASS_R -/* this file is only for systems without getpass_r() */ - -#ifdef HAVE_FCNTL_H -# include -#endif - -#ifdef HAVE_TERMIOS_H -# include -#elif defined(HAVE_TERMIO_H) -# include -#endif - -#ifdef __VMS -# include descrip -# include starlet -# include iodef -#endif - -#ifdef WIN32 -# include -#endif - -#ifdef NETWARE -# ifdef __NOVELL_LIBC__ -# include -# else -# include -# endif -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif -#include "tool_getpass.h" - -#include "memdebug.h" /* keep this as LAST include */ - -#ifdef __VMS -/* VMS implementation */ -char *getpass_r(const char *prompt, char *buffer, size_t buflen) -{ - long sts; - short chan; - - /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4 */ - /* distribution so I created this. May revert back later to */ - /* struct _iosb iosb; */ - struct _iosb - { - short int iosb$w_status; /* status */ - short int iosb$w_bcnt; /* byte count */ - int unused; /* unused */ - } iosb; - - $DESCRIPTOR(ttdesc, "TT"); - - buffer[0] = '\0'; - sts = sys$assign(&ttdesc, &chan, 0, 0); - if(sts & 1) { - sts = sys$qiow(0, chan, - IO$_READPROMPT | IO$M_NOECHO, - &iosb, 0, 0, buffer, buflen, 0, 0, - prompt, strlen(prompt)); - - if((sts & 1) && (iosb.iosb$w_status & 1)) - buffer[iosb.iosb$w_bcnt] = '\0'; - - sts = sys$dassgn(chan); - } - return buffer; /* we always return success */ -} -#define DONE -#endif /* __VMS */ - -#ifdef __SYMBIAN32__ -# define getch() getchar() -#endif - -#if defined(WIN32) || defined(__SYMBIAN32__) - -char *getpass_r(const char *prompt, char *buffer, size_t buflen) -{ - size_t i; - fputs(prompt, stderr); - - for(i = 0; i < buflen; i++) { - buffer[i] = (char)getch(); - if(buffer[i] == '\r' || buffer[i] == '\n') { - buffer[i] = '\0'; - break; - } - else - if(buffer[i] == '\b') - /* remove this letter and if this is not the first key, remove the - previous one as well */ - i = i - (i >= 1 ? 2 : 1); - } -#ifndef __SYMBIAN32__ - /* since echo is disabled, print a newline */ - fputs("\n", stderr); -#endif - /* if user didn't hit ENTER, terminate buffer */ - if(i == buflen) - buffer[buflen-1] = '\0'; - - return buffer; /* we always return success */ -} -#define DONE -#endif /* WIN32 || __SYMBIAN32__ */ - -#ifdef NETWARE -/* NetWare implementation */ -#ifdef __NOVELL_LIBC__ -char *getpass_r(const char *prompt, char *buffer, size_t buflen) -{ - return getpassword(prompt, buffer, buflen); -} -#else -char *getpass_r(const char *prompt, char *buffer, size_t buflen) -{ - size_t i = 0; - - printf("%s", prompt); - do { - buffer[i++] = getch(); - if(buffer[i-1] == '\b') { - /* remove this letter and if this is not the first key, - remove the previous one as well */ - if(i > 1) { - printf("\b \b"); - i = i - 2; - } - else { - RingTheBell(); - i = i - 1; - } - } - else if(buffer[i-1] != 13) - putchar('*'); - - } while((buffer[i-1] != 13) && (i < buflen)); - buffer[i-1] = '\0'; - printf("\r\n"); - return buffer; -} -#endif /* __NOVELL_LIBC__ */ -#define DONE -#endif /* NETWARE */ - -#ifndef DONE /* not previously provided */ - -#ifdef HAVE_TERMIOS_H -# define struct_term struct termios -#elif defined(HAVE_TERMIO_H) -# define struct_term struct termio -#else -# undef struct_term -#endif - -static bool ttyecho(bool enable, int fd) -{ -#ifdef struct_term - static struct_term withecho; - static struct_term noecho; -#endif - if(!enable) { - /* disable echo by extracting the current 'withecho' mode and remove the - ECHO bit and set back the struct */ -#ifdef HAVE_TERMIOS_H - tcgetattr(fd, &withecho); - noecho = withecho; - noecho.c_lflag &= ~ECHO; - tcsetattr(fd, TCSANOW, &noecho); -#elif defined(HAVE_TERMIO_H) - ioctl(fd, TCGETA, &withecho); - noecho = withecho; - noecho.c_lflag &= ~ECHO; - ioctl(fd, TCSETA, &noecho); -#else - /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */ - (void)fd; - return FALSE; /* not disabled */ -#endif - return TRUE; /* disabled */ - } - /* re-enable echo, assumes we disabled it before (and set the structs we - now use to reset the terminal status) */ -#ifdef HAVE_TERMIOS_H - tcsetattr(fd, TCSAFLUSH, &withecho); -#elif defined(HAVE_TERMIO_H) - ioctl(fd, TCSETA, &withecho); -#else - return FALSE; /* not enabled */ -#endif - return TRUE; /* enabled */ -} - -char *getpass_r(const char *prompt, /* prompt to display */ - char *password, /* buffer to store password in */ - size_t buflen) /* size of buffer to store password in */ -{ - ssize_t nread; - bool disabled; - int fd = open("/dev/tty", O_RDONLY); - if(-1 == fd) - fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */ - - disabled = ttyecho(FALSE, fd); /* disable terminal echo */ - - fputs(prompt, stderr); - nread = read(fd, password, buflen); - if(nread > 0) - password[--nread] = '\0'; /* zero terminate where enter is stored */ - else - password[0] = '\0'; /* got nothing */ - - if(disabled) { - /* if echo actually was disabled, add a newline */ - fputs("\n", stderr); - (void)ttyecho(TRUE, fd); /* enable echo */ - } - - if(STDIN_FILENO != fd) - close(fd); - - return password; /* return pointer to buffer */ -} - -#endif /* DONE */ -#endif /* HAVE_GETPASS_R */ diff --git a/dep/cpr/opt/curl/src/tool_getpass.h b/dep/cpr/opt/curl/src/tool_getpass.h deleted file mode 100644 index f639596fc74..00000000000 --- a/dep/cpr/opt/curl/src/tool_getpass.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef HEADER_CURL_TOOL_GETPASS_H -#define HEADER_CURL_TOOL_GETPASS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#ifndef HAVE_GETPASS_R -/* If there's a system-provided function named like this, we trust it is - also found in one of the standard headers. */ - -/* - * Returning NULL will abort the continued operation! - */ -char *getpass_r(const char *prompt, char *buffer, size_t buflen); -#endif - -#endif /* HEADER_CURL_TOOL_GETPASS_H */ diff --git a/dep/cpr/opt/curl/src/tool_help.c b/dep/cpr/opt/curl/src/tool_help.c deleted file mode 100644 index 486f65dc8ef..00000000000 --- a/dep/cpr/opt/curl/src/tool_help.c +++ /dev/null @@ -1,576 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "tool_setup.h" - -#include "tool_panykey.h" -#include "tool_help.h" -#include "tool_libinfo.h" -#include "tool_version.h" - -#include "memdebug.h" /* keep this as LAST include */ - -#ifdef MSDOS -# define USE_WATT32 -#endif - -/* - * The help output is generated with the following command - --------------------------------------------------------- - - cd $srcroot/docs/cmdline-opts - ./gen.pl listhelp - */ - -struct helptxt { - const char *opt; - const char *desc; -}; - -static const struct helptxt helptext[] = { - {" --abstract-unix-socket ", - "Connect via abstract Unix domain socket"}, - {" --anyauth", - "Pick any authentication method"}, - {"-a, --append", - "Append to target file when uploading"}, - {" --basic", - "Use HTTP Basic Authentication"}, - {" --cacert ", - "CA certificate to verify peer against"}, - {" --capath ", - "CA directory to verify peer against"}, - {"-E, --cert ", - "Client certificate file and password"}, - {" --cert-status", - "Verify the status of the server certificate"}, - {" --cert-type ", - "Certificate file type (DER/PEM/ENG)"}, - {" --ciphers ", - "SSL ciphers to use"}, - {" --compressed", - "Request compressed response"}, - {" --compressed-ssh", - "Enable SSH compression"}, - {"-K, --config ", - "Read config from a file"}, - {" --connect-timeout ", - "Maximum time allowed for connection"}, - {" --connect-to ", - "Connect to host"}, - {"-C, --continue-at ", - "Resumed transfer offset"}, - {"-b, --cookie ", - "Send cookies from string/file"}, - {"-c, --cookie-jar ", - "Write cookies to after operation"}, - {" --create-dirs", - "Create necessary local directory hierarchy"}, - {" --crlf", - "Convert LF to CRLF in upload"}, - {" --crlfile ", - "Get a CRL list in PEM format from the given file"}, - {"-d, --data ", - "HTTP POST data"}, - {" --data-ascii ", - "HTTP POST ASCII data"}, - {" --data-binary ", - "HTTP POST binary data"}, - {" --data-raw ", - "HTTP POST data, '@' allowed"}, - {" --data-urlencode ", - "HTTP POST data url encoded"}, - {" --delegation ", - "GSS-API delegation permission"}, - {" --digest", - "Use HTTP Digest Authentication"}, - {"-q, --disable", - "Disable .curlrc"}, - {" --disable-eprt", - "Inhibit using EPRT or LPRT"}, - {" --disable-epsv", - "Inhibit using EPSV"}, - {" --dns-interface ", - "Interface to use for DNS requests"}, - {" --dns-ipv4-addr
", - "IPv4 address to use for DNS requests"}, - {" --dns-ipv6-addr
", - "IPv6 address to use for DNS requests"}, - {" --dns-servers ", - "DNS server addrs to use"}, - {"-D, --dump-header ", - "Write the received headers to "}, - {" --egd-file ", - "EGD socket path for random data"}, - {" --engine ", - "Crypto engine to use"}, - {" --expect100-timeout ", - "How long to wait for 100-continue"}, - {"-f, --fail", - "Fail silently (no output at all) on HTTP errors"}, - {" --fail-early", - "Fail on first transfer error, do not continue"}, - {" --false-start", - "Enable TLS False Start"}, - {"-F, --form ", - "Specify multipart MIME data"}, - {" --form-string ", - "Specify multipart MIME data"}, - {" --ftp-account ", - "Account data string"}, - {" --ftp-alternative-to-user ", - "String to replace USER [name]"}, - {" --ftp-create-dirs", - "Create the remote dirs if not present"}, - {" --ftp-method ", - "Control CWD usage"}, - {" --ftp-pasv", - "Use PASV/EPSV instead of PORT"}, - {"-P, --ftp-port
", - "Use PORT instead of PASV"}, - {" --ftp-pret", - "Send PRET before PASV"}, - {" --ftp-skip-pasv-ip", - "Skip the IP address for PASV"}, - {" --ftp-ssl-ccc", - "Send CCC after authenticating"}, - {" --ftp-ssl-ccc-mode ", - "Set CCC mode"}, - {" --ftp-ssl-control", - "Require SSL/TLS for FTP login, clear for transfer"}, - {"-G, --get", - "Put the post data in the URL and use GET"}, - {"-g, --globoff", - "Disable URL sequences and ranges using {} and []"}, - {"-I, --head", - "Show document info only"}, - {"-H, --header
", - "Pass custom header(s) to server"}, - {"-h, --help", - "This help text"}, - {" --hostpubmd5 ", - "Acceptable MD5 hash of the host public key"}, - {"-0, --http1.0", - "Use HTTP 1.0"}, - {" --http1.1", - "Use HTTP 1.1"}, - {" --http2", - "Use HTTP 2"}, - {" --http2-prior-knowledge", - "Use HTTP 2 without HTTP/1.1 Upgrade"}, - {" --ignore-content-length", - "Ignore the size of the remote resource"}, - {"-i, --include", - "Include protocol response headers in the output"}, - {"-k, --insecure", - "Allow insecure server connections when using SSL"}, - {" --interface ", - "Use network INTERFACE (or address)"}, - {"-4, --ipv4", - "Resolve names to IPv4 addresses"}, - {"-6, --ipv6", - "Resolve names to IPv6 addresses"}, - {"-j, --junk-session-cookies", - "Ignore session cookies read from file"}, - {" --keepalive-time ", - "Interval time for keepalive probes"}, - {" --key ", - "Private key file name"}, - {" --key-type ", - "Private key file type (DER/PEM/ENG)"}, - {" --krb ", - "Enable Kerberos with security "}, - {" --libcurl ", - "Dump libcurl equivalent code of this command line"}, - {" --limit-rate ", - "Limit transfer speed to RATE"}, - {"-l, --list-only", - "List only mode"}, - {" --local-port ", - "Force use of RANGE for local port numbers"}, - {"-L, --location", - "Follow redirects"}, - {" --location-trusted", - "Like --location, and send auth to other hosts"}, - {" --login-options ", - "Server login options"}, - {" --mail-auth
", - "Originator address of the original email"}, - {" --mail-from
", - "Mail from this address"}, - {" --mail-rcpt
", - "Mail from this address"}, - {"-M, --manual", - "Display the full manual"}, - {" --max-filesize ", - "Maximum file size to download"}, - {" --max-redirs ", - "Maximum number of redirects allowed"}, - {"-m, --max-time